I don't seem to be able to enable the performance counters on my
beagleboard, and I'm certain that there's an obvious step that I'm
missing. The cycle counter works just fine, but the 4 performance
counter registers only ever return 0. When I read from any of the
setup registers like the PMNC etc they seem to have the right values,
or at least the values that I'm putting in them.
I'm running a fairly recent build of Angstrom (2.6.32 kernel) on my C4
board. Here's the code that I'm using to set things up:
<blockquote>
inline void _setCounting( int enable )
{
unsigned bits;
asm ("MRC p15, 0, %0, C9, C12, 0\n\t" : "=r" (bits));
bits |= enable; // counting enable
asm ("MCR p15, 0, %0, C9, C12, 0\n\t" :: "r" (bits));
}
inline void _resetClockCounter()
{
unsigned bits;
asm ("MRC p15, 0, %0, C9, C12, 0\n\t" : "=r" (bits));
bits |= (1<<2);
asm ("MCR p15, 0, %0, C9, C12, 0\n\t" :: "r" (bits));
}
inline void _resetEventCounters()
{
unsigned bits;
asm ("MRC p15, 0, %0, C9, C12, 0\n\t" : "=r" (bits));
bits |= (1<<1);
asm ("MCR p15, 0, %0, C9, C12, 0\n\t" :: "r" (bits));
}
inline void _enableCounters( int cycleCounter
, int counter0
, int counter1
, int counter2
, int counter3 )
{
unsigned bits = cycleCounter << 31
> counter0 << 0
> counter1 << 1
> counter2 << 2
> counter3 << 3;
asm ("MCR p15, 0, %0, C9, C12, 1\n\t" :: "r" (bits));
}
inline void _disableCounters()
{
asm ("MCR p15, 0, %0, C9, C12, 2\n\t" :: "r" (1<<31 | 1<<3 | 1<<2
1<<1 | 1<<0));
}
inline void _incPerfCounter( int counter )
{
asm ("MCR p15, 0, %0, C9, C12, 4\n\t" :: "r" (1<<counter));
}
inline void _selectPerfCounter( int counter )
{
asm ("MCR p15, 0, %0, C9, C12, 5\n\t" :: "r" (counter));
}
inline void _setPerfCounterFunction( int function )
{
asm ("MCR p15, 0, %0, C9, C13, 1\n\t" :: "r" (function));
}
inline void _writeToPerfCounter( unsigned val )
{
asm ("MCR p15, 0, %0, C9, C13, 2\n\t" :: "r" (val));
}
inline void _writeToCycleCounter( unsigned val )
{
asm ("MCR p15, 0, %0, C9, C13, 0\n\t" :: "r" (val));
}
inline unsigned _readFromCycleCounter()
{
unsigned retval;
asm ("MRC p15, 0, %0, C9, C13, 0\n\t" : "=r" (retval));
return retval;
}
inline unsigned _readFromPerfCounter()
{
unsigned retval;
asm ("MRC p15, 0, %0, C9, C13, 2\n\t" : "=r" (retval));
return retval;
}
inline void startCounters( int count0func
, int count1func
, int count2func
, int count3func )
{
_setCounting(1);
_resetClockCounter();
_resetEventCounters();
_selectPerfCounter(0);
_setPerfCounterFunction( count0func );
_selectPerfCounter(1);
_setPerfCounterFunction( count1func );
_selectPerfCounter(2);
_setPerfCounterFunction( count2func );
_selectPerfCounter(3);
_setPerfCounterFunction( count3func );
_enableCounters(1, 1, 1, 1, 1);
}
inline void stopCounters( unsigned * cycles
, unsigned * counter0
, unsigned * counter1
, unsigned * counter2
, unsigned * counter3 )
{
_disableCounters();
_selectPerfCounter(0);
*counter0 = _readFromPerfCounter();
_selectPerfCounter(1);
*counter1 = _readFromPerfCounter();
_selectPerfCounter(2);
*counter2 = _readFromPerfCounter();
_selectPerfCounter(3);
*counter3 = _readFromPerfCounter();
*cycles = _readFromCycleCounter();
_setCounting(0);
}
</blockquote>
... and then I'm using it around a bit of code that I want to test:
<blockquote>
startCounters( 0x8, 0xf, 0x11, 0x40 );
printf( "Hello PMU\n" );
stopCounters( &cycles, &count0, &count1, &count2, &count3 );
</blockquote>
Can anyone see what I'm doing wrong here?