Commit 1d6e32e9 authored by Oliver Horst's avatar Oliver Horst
Browse files

Merge branch 'split/freertos-portable-src-perfmon' into split/freertos-portable-src

parents 09e8e3e8 f5d1f101
Pipeline #19569 failed with stages
in 3 minutes and 50 seconds
# SPDX-License-Identifier: MIT
cmake_minimum_required(VERSION 3.7 FATAL_ERROR)
target_sources(
freertos
#
PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/perfmon_arch.c"
)
/*******************************************************************************
* Created by Dorel Coman on 21.10.17.
*
* This API provides functionalities for accessing the Performance Monitor
* Counters (PMU) registers of the ARM64 architectures
******************************************************************************/
#include "freertos/FreeRTOS.h"
#include "freertos/extra/perfmon.h"
#include "xil/xpseudo_asm.h"
/* Macros used for accessing and setting up the PMU registers */
#define PMCR_MASK 0x3Fu
#define PMCR_E (1u << 0u) /* Enable all counters */
#define PMCR_P (1u << 1u) /* Reset all counters */
#define PMCR_C (1u << 2u) /* Cycle counter reset */
#define PMCR_D (1u << 3u) /* CCNT counts every 64th CPU cycle */
#define PMCR_N_SHIFT 11u /* Mask used for getting Number of counters supported */
#define PMCR_N_MASK 0x1Fu
#define PMU_USERENR_MASK 0xFu /* Mask for writable bits */
#define PMUSERENR_EN_EL0 (1u << 0u) /* EL0 access enable */
#define PMUSERENR_CR (1u << 2u) /* Cycle counter read enable */
#define PMUSERENR_ER (1u << 3u) /* Event counter read enable */
#define PMUSERENR_ENABLE_ALL 0xDu
/*********************************************************
* Registers of the Performance Monitor Unit (PMU)
*********************************************************/
/* Performance Monitors Event Counter Selection Register */
#define PMSELR_EL0 "PMSELR_EL0"
/* Performance Monitors User Enable Register */
#define PMUSERENR_EL0 "PMUSERENR_EL0"
/* Performance Monitors Count Enable Set register */
#define PMCNTENSET_EL0 "PMCNTENSET_EL0"
/* Performance Monitors Control Register */
#define PMCR_EL0 "PMCR_EL0"
/* Performance Monitors Cycle Count Register - 64-bit register */
#define PMCCNTR_EL0 "PMCCNTR_EL0"
/* Performance Monitors Selected Event Count Register */
#define PMXEVCNTR_EL0 "PMXEVCNTR_EL0"
/* Performance Monitors Selected Event Type Register */
#define PMXEVTYPER_EL0 "PMXEVTYPER_EL0"
/* Performance Monitors Interrupt Enable Clear register */
#define PMINTENCLR_EL1 "PMINTENCLR_EL1"
/* Performance Monitors Interrupt Enable Set register */
#define PMINTENSET_EL1 "PMINTENSET_EL1"
/* Performance Monitors Overflow Flag Status Clear Register */
#define PMOVSCLR_EL0 "PMOVSCLR_EL0"
/* Performance Monitors Overflow Flag Status Set register */
#define PMOVSSET_EL0 "PMOVSSET_EL0"
/*******************************************************************************
* Function definitions
******************************************************************************/
#if( INCLUDE_vPerfmonEnableUserAccess == 1 )
/**
* It enables user-mode access (EL0: applications) to counters. It is
* important in order to be able to use the counters in FreeRTOS.
*/
static inline void vPerfmonEnableUserAccess()
{
uint32_t reg_val;
reg_val = mfcp( PMUSERENR_EL0 );
reg_val = reg_val | PMUSERENR_ENABLE_ALL;
mtcp( PMUSERENR_EL0, reg_val );
}
#endif
/**
* This function enables the selected counter in order to make it count. If
* the counter is not enabled, it will not count the occurencies of its
* selected event type
* @idx: The counter n index
*/
static inline void vPerfmonEnableCounter( uint32_t idx )
{
mtcp( PMCNTENSET_EL0, (1u << idx) );
}
/**
* This function disables the selected counter.
* @idx: The counter n index
*/
static inline void vPerfmonDisableCounter( uint32_t idx )
{
mtcp( PMCNTENSET_EL0, (0u << idx) );
}
/**
* This function writes the PMCR register of the PMU
* @param val to be written inside the PMCR register
*/
static inline void prvPerfmonWriteControlRegister( UBaseType_t val )
{
val &= PMCR_MASK;
isb();
mtcp( PMCR_EL0, val );
}
/**
* This function returns the value of the PMCR_EL0 register
* @return PMCR_EL0 value
*/
static inline uint32_t prvPerfmonReadControlRegister( void )
{
return (uint32_t)mfcp( PMCR_EL0 );
}
/**
* This function reads the PMCR_EL0 register and writes it back with the value
* needed in order to activate the PMU counters. The PMCR_E mask enables all
* the counters
*/
static inline void set_pmcr_el0()
{
uint32_t val;
val = prvPerfmonReadControlRegister();
prvPerfmonWriteControlRegister( val | PMCR_E );
}
/**
* This function selects the counter on which it is wanted to executed some
* PMU operations
* @param idx of the counter to be selecte
*/
static inline void prvPerfmonSelectCounter( uint32_t idx )
{
mtcp( PMSELR_EL0, idx );
isb();
}
/**
* This function sets, for the given counter, the type of event to be
* monitored and counted
* @param idx of the counter of which it is being selected the event
* @param type of the event to be monitored. Events that can be monitored are
* contained in the file events.h
*/
static inline void prvPerfmonSetCounterEventType( uint32_t idx, uint32_t type )
{
prvPerfmonSelectCounter(idx);
mtcp( PMXEVTYPER_EL0, type );
}
void vPerfmonInitCounters()
{
uint32_t number_of_counters;
#if( INCLUDE_vPerfmonEnableUserAccess == 1 )
{
vPerfmonEnableUserAccess();
}
#endif
set_pmcr_el0();
number_of_counters = uxPerfmonGetNumberOfCounters();
for( uint32_t i = 0; i < number_of_counters; ++i )
{
vPerfmonClearInterruptForCounter( i );
}
}
void vPerfmonEnableCounterForEvent( uint32_t idx, uint32_t event_type )
{
vPerfmonDisableCounter(idx);
prvPerfmonSetCounterEventType(idx, event_type);
vPerfmonEnableCounter(idx);
}
UBaseType_t uxPerfmonHasCounterOverflowed( uint32_t idx )
{
UBaseType_t value;
value = mfcp( PMOVSSET_EL0 );
return ( (value) & (1u << idx) );
}
void vPerfmonEnableInterruptForCounter( uint32_t idx )
{
mtcp( PMINTENSET_EL1, (1u << idx) );
}
void vPerfmonDisableInterruptForCounter( uint32_t idx )
{
/* Disabling the interrupt for the selected counter */
mtcp( PMINTENCLR_EL1, (1u << idx) );
isb();
/* Clearing the interrupt line */
mtcp( PMOVSCLR_EL0, (1u << idx) );
isb();
}
void vPerfmonClearInterruptForCounter( uint32_t idx )
{
mtcp( PMOVSCLR_EL0, (1u << idx) );
isb();
}
void vPerfmonStartCounter(uint32_t idx, UBaseType_t count_val )
{
/* Writing the value on the selected counter */
vPerfmonWriteCounter( idx, count_val );
/* Clear the interrupt register before enabling it again to be sure it
wasn't already triggered */
vPerfmonClearInterruptForCounter( idx );
vPerfmonEnableInterruptForCounter(idx);
}
uint32_t mask_value( uint32_t value )
{
uint32_t MAX = 0xFFFFFFFFu;
uint32_t val = MAX - value;
return val;
}
UBaseType_t uxPerfmonReadCounter( uint32_t idx )
{
UBaseType_t ulReturn = 0u;
if ( idx < uxPerfmonGetNumberOfCounters() )
{
prvPerfmonSelectCounter( idx );
ulReturn = mfcp( PMXEVCNTR_EL0 );
}
return ulReturn;
}
void vPerfmonWriteCounter( uint32_t idx, UBaseType_t value )
{
if ( idx < uxPerfmonGetNumberOfCounters() )
{
prvPerfmonSelectCounter(idx);
mtcp( PMXEVCNTR_EL0, value );
}
}
UBaseType_t uxPerfmonReadCycleCounter( void )
{
return (UBaseType_t)mfcp( PMCCNTR_EL0 );
}
UBaseType_t uxPerfmonGetNumberOfCounters( void )
{
UBaseType_t count;
count = prvPerfmonReadControlRegister();
/* Extracting the bits[15:11] - These bits store the number of counters
available for the respective CPU. The description of the register can be
found in the A53 CPU Technical Reference Manual at the chapter 12.4.1
Performance Monitors Control Register */
count = ( (count >> PMCR_N_SHIFT) & PMCR_N_MASK );
return count;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment