blob: 36c06b377de79ea220ce350f42bd6125ac133a0e [file] [log] [blame]
Ben Cheng5a4eb4e2009-09-14 16:00:41 -07001/*
2 * @file architecture specific interfaces
3 * @remark Copyright 2008 Intel Corporation
4 * @remark Read the file COPYING
5 * @author Andi Kleen
6 */
7
Jeff Brownb415fab2011-01-11 12:38:32 -08008#if (defined(__i386__) || defined(__x86_64__)) && !defined(ANDROID_HOST)
Ben Cheng5a4eb4e2009-09-14 16:00:41 -07009
10/* Assume we run on the same host as the profilee */
11
12#define num_to_mask(x) ((1U << (x)) - 1)
13
14static inline int cpuid_vendor(char *vnd)
15{
16 union {
17 struct {
18 unsigned b,d,c;
19 };
20 char v[12];
21 } v;
22 unsigned eax;
David 'Digit' Turner02636c62011-02-01 23:09:00 +010023#ifdef __PIC__
24 __asm__ __volatile__(
25 "pushl %%ebx\n" /* must be preserved due to PIC code */
26 "cpuid\n"
27 "mov %%ebx, 0(%%edi)\n"
28 "mov %%ecx, 4(%%edi)\n"
29 "mov %%edx, 8(%%edi)\n"
30 "popl %%ebx\n"
31 : "=a" (eax)
32 : "a"(0), "D"(v.v)
33 : "%ecx", "%edx"
34 );
35#else
Ben Cheng5bbbe462010-09-02 21:48:01 -070036 asm("cpuid" : "=a" (eax), "=b" (v.b), "=c" (v.c), "=d" (v.d) : "0" (0));
David 'Digit' Turner02636c62011-02-01 23:09:00 +010037#endif
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070038 return !strncmp(v.v, vnd, 12);
39}
40
David 'Digit' Turner02636c62011-02-01 23:09:00 +010041static inline unsigned arch_cpuid_1(int code)
42{
43 unsigned val;
44#ifdef __PIC__
45 __asm__ __volatile__ (
46 "pushl %%ebx\n"
47 "cpuid\n"
48 "popl %%ebx\n"
49 : "=a" (val)
50 : "a" (code)
51 : "ecx", "edx"
52 );
53#else
54 asm("cpuid" : "=a" (v.eax) : "a" (code) : "ecx","ebx","edx");
55#endif
56 return val;
57}
58
Jeff Brown7a33c862011-02-02 14:00:44 -080059static inline unsigned int cpuid_signature()
60{
61 return arch_cpuid_1(1);
62}
63
64static inline unsigned int cpu_model(unsigned int eax)
65{
66 unsigned model = (eax & 0xf0) >> 4;
67 unsigned ext_model = (eax & 0xf0000) >> 12;
68 return ext_model + model;
69}
70
71static inline unsigned int cpu_family(unsigned int eax)
72{
73 unsigned family = (eax & 0xf00) >> 8;
74 unsigned ext_family = (eax & 0xff00000) >> 20;
75 return ext_family + family;
76}
77
78static inline unsigned int cpu_stepping(unsigned int eax)
79{
80 return (eax & 0xf);
81}
82
David 'Digit' Turner02636c62011-02-01 23:09:00 +010083
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070084/* Work around Nehalem spec update AAJ79: CPUID incorrectly indicates
85 unhalted reference cycle architectural event is supported. We assume
86 steppings after C0 report correct data in CPUID. */
87static inline void workaround_nehalem_aaj79(unsigned *ebx)
88{
Jeff Brown7a33c862011-02-02 14:00:44 -080089 unsigned eax;
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070090
91 if (!cpuid_vendor("GenuineIntel"))
92 return;
Jeff Brown7a33c862011-02-02 14:00:44 -080093 eax = cpuid_signature();
94 if (cpu_family(eax) != 6 || cpu_model(eax) != 26
95 || cpu_stepping(eax) > 4)
Ben Cheng5a4eb4e2009-09-14 16:00:41 -070096 return;
97 *ebx |= (1 << 2); /* disable unsupported event */
98}
99
100static inline unsigned arch_get_filter(op_cpu cpu_type)
101{
Jeff Brown7a33c862011-02-02 14:00:44 -0800102 if (op_cpu_base_type(cpu_type) == CPU_ARCH_PERFMON) {
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700103 unsigned ebx, eax;
David 'Digit' Turner02636c62011-02-01 23:09:00 +0100104#ifdef __PIC__
105 __asm__ __volatile__ (
106 "pushl %%ebx\n"
107 "cpuid\n"
108 "mov %%ebx, %%ecx\n"
109 "popl %%ebx"
110 : "=a" (eax), "=c" (ebx)
111 : "a" (0xa)
112 : "edx"
113 );
114#else
Ben Cheng5bbbe462010-09-02 21:48:01 -0700115 asm("cpuid" : "=a" (eax), "=b" (ebx) : "0" (0xa) : "ecx","edx");
David 'Digit' Turner02636c62011-02-01 23:09:00 +0100116#endif
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700117 workaround_nehalem_aaj79(&ebx);
118 return ebx & num_to_mask(eax >> 24);
119 }
120 return -1U;
121}
122
123static inline int arch_num_counters(op_cpu cpu_type)
124{
Jeff Brown7a33c862011-02-02 14:00:44 -0800125 if (op_cpu_base_type(cpu_type) == CPU_ARCH_PERFMON) {
David 'Digit' Turner02636c62011-02-01 23:09:00 +0100126 unsigned v = arch_cpuid_1(0xa);
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700127 return (v >> 8) & 0xff;
128 }
129 return -1;
130}
131
132static inline unsigned arch_get_counter_mask(void)
133{
David 'Digit' Turner02636c62011-02-01 23:09:00 +0100134 unsigned v = arch_cpuid_1(0xa);
135 return num_to_mask((v >> 8) & 0xff);
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700136}
137
Jeff Brown7a33c862011-02-02 14:00:44 -0800138static inline op_cpu op_cpu_specific_type(op_cpu cpu_type)
139{
140 if (cpu_type == CPU_ARCH_PERFMON) {
141 /* Already know is Intel family 6, so just check the model. */
142 int model = cpu_model(cpuid_signature());
143 switch(model) {
144 case 0x0f:
145 case 0x16:
146 case 0x17:
147 case 0x1d:
148 return CPU_CORE_2;
149 case 0x1a:
150 case 0x1e:
151 case 0x2e:
152 return CPU_CORE_I7;
153 case 0x1c:
154 return CPU_ATOM;
155 case 0x25:
156 return CPU_WESTMERE;
157 }
158 }
159 return cpu_type;
160}
161
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700162#else
163
164static inline unsigned arch_get_filter(op_cpu cpu_type)
165{
166 /* Do something with passed arg to shut up the compiler warning */
167 if (cpu_type != CPU_NO_GOOD)
168 return 0;
169 return 0;
170}
171
172static inline int arch_num_counters(op_cpu cpu_type)
173{
174 /* Do something with passed arg to shut up the compiler warning */
175 if (cpu_type != CPU_NO_GOOD)
176 return -1;
177 return -1;
178}
179
180static inline unsigned arch_get_counter_mask(void)
181{
182 return 0;
183}
184
Jeff Brown7a33c862011-02-02 14:00:44 -0800185static inline op_cpu op_cpu_specific_type(op_cpu cpu_type)
186{
187 return cpu_type;
188}
Ben Cheng5a4eb4e2009-09-14 16:00:41 -0700189#endif