| /* |
| * @file architecture specific interfaces |
| * @remark Copyright 2008 Intel Corporation |
| * @remark Read the file COPYING |
| * @author Andi Kleen |
| */ |
| |
| #if defined(__i386__) || defined(__x86_64__) |
| |
| /* Assume we run on the same host as the profilee */ |
| |
| #define num_to_mask(x) ((1U << (x)) - 1) |
| |
| static inline int cpuid_vendor(char *vnd) |
| { |
| union { |
| struct { |
| unsigned b,d,c; |
| }; |
| char v[12]; |
| } v; |
| unsigned eax; |
| asm volatile( "pushl %%ebx; cpuid; movl %%ebx, %1; popl %%ebx" |
| : "=a" (eax), "=S" (v.b), "=c" (v.c), "=d" (v.d) : "0" (0)); |
| return !strncmp(v.v, vnd, 12); |
| } |
| |
| /* Work around Nehalem spec update AAJ79: CPUID incorrectly indicates |
| unhalted reference cycle architectural event is supported. We assume |
| steppings after C0 report correct data in CPUID. */ |
| static inline void workaround_nehalem_aaj79(unsigned *ebx) |
| { |
| union { |
| unsigned eax; |
| struct { |
| unsigned stepping : 4; |
| unsigned model : 4; |
| unsigned family : 4; |
| unsigned type : 2; |
| unsigned res : 2; |
| unsigned ext_model : 4; |
| unsigned ext_family : 8; |
| unsigned res2 : 4; |
| }; |
| } v; |
| unsigned model; |
| |
| if (!cpuid_vendor("GenuineIntel")) |
| return; |
| asm volatile( "pushl %%ebx; cpuid; movl %%ebx, %1; popl %%ebx" |
| : "=a" (v.eax) : "0" (1) : "ecx","edx"); |
| model = (v.ext_model << 4) + v.model; |
| if (v.family != 6 || model != 26 || v.stepping > 4) |
| return; |
| *ebx |= (1 << 2); /* disable unsupported event */ |
| } |
| |
| static inline unsigned arch_get_filter(op_cpu cpu_type) |
| { |
| if (cpu_type == CPU_ARCH_PERFMON) { |
| unsigned ebx, eax; |
| asm volatile( "pushl %%ebx; cpuid; movl %%ebx, %1; popl %%ebx" |
| : "=a" (eax), "=S" (ebx) : "0" (0xa) : "ecx","edx"); |
| workaround_nehalem_aaj79(&ebx); |
| return ebx & num_to_mask(eax >> 24); |
| } |
| return -1U; |
| } |
| |
| static inline int arch_num_counters(op_cpu cpu_type) |
| { |
| if (cpu_type == CPU_ARCH_PERFMON) { |
| unsigned v; |
| asm volatile( "pushl %%ebx; cpuid; movl %%eax, %1; popl %%ebx" |
| : "=a" (v) : "0" (0xa) : "ecx","edx"); |
| return (v >> 8) & 0xff; |
| } |
| return -1; |
| } |
| |
| static inline unsigned arch_get_counter_mask(void) |
| { |
| unsigned v; |
| asm volatile( "pushl %%ebx; cpuid; movl %%ebx, %1; popl %%ebx" |
| : "=a" (v) : "0" (0xa) : "ecx","edx"); |
| return num_to_mask((v >> 8) & 0xff); |
| } |
| |
| #else |
| |
| static inline unsigned arch_get_filter(op_cpu cpu_type) |
| { |
| /* Do something with passed arg to shut up the compiler warning */ |
| if (cpu_type != CPU_NO_GOOD) |
| return 0; |
| return 0; |
| } |
| |
| static inline int arch_num_counters(op_cpu cpu_type) |
| { |
| /* Do something with passed arg to shut up the compiler warning */ |
| if (cpu_type != CPU_NO_GOOD) |
| return -1; |
| return -1; |
| } |
| |
| static inline unsigned arch_get_counter_mask(void) |
| { |
| return 0; |
| } |
| |
| #endif |