• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * @file architecture specific interfaces
3  * @remark Copyright 2008 Intel Corporation
4  * @remark Read the file COPYING
5  * @author Andi Kleen
6  */
7 
8 #if (defined(__i386__) || defined(__x86_64__)) && !defined(ANDROID_HOST)
9 
10 /* Assume we run on the same host as the profilee */
11 
12 #define num_to_mask(x) ((1U << (x)) - 1)
13 
cpuid_vendor(char * vnd)14 static 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;
23 #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
36 	asm("cpuid" : "=a" (eax), "=b" (v.b), "=c" (v.c), "=d" (v.d) : "0" (0));
37 #endif
38 	return !strncmp(v.v, vnd, 12);
39 }
40 
arch_cpuid_1(int code)41 static 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 
cpuid_signature()59 static inline unsigned int cpuid_signature()
60 {
61 	return arch_cpuid_1(1);
62 }
63 
cpu_model(unsigned int eax)64 static 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 
cpu_family(unsigned int eax)71 static 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 
cpu_stepping(unsigned int eax)78 static inline unsigned int cpu_stepping(unsigned int eax)
79 {
80 	return (eax & 0xf);
81 }
82 
83 
84 /* 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. */
workaround_nehalem_aaj79(unsigned * ebx)87 static inline void workaround_nehalem_aaj79(unsigned *ebx)
88 {
89 	unsigned eax;
90 
91 	if (!cpuid_vendor("GenuineIntel"))
92 		return;
93 	eax = cpuid_signature();
94 	if (cpu_family(eax) != 6 || cpu_model(eax) != 26
95 		|| cpu_stepping(eax) > 4)
96 		return;
97 	*ebx |= (1 << 2);	/* disable unsupported event */
98 }
99 
arch_get_filter(op_cpu cpu_type)100 static inline unsigned arch_get_filter(op_cpu cpu_type)
101 {
102 	if (op_cpu_base_type(cpu_type) == CPU_ARCH_PERFMON) {
103 		unsigned ebx, eax;
104 #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
115 		asm("cpuid" : "=a" (eax), "=b" (ebx) : "0" (0xa) : "ecx","edx");
116 #endif
117 		workaround_nehalem_aaj79(&ebx);
118 		return ebx & num_to_mask(eax >> 24);
119 	}
120 	return -1U;
121 }
122 
arch_num_counters(op_cpu cpu_type)123 static inline int arch_num_counters(op_cpu cpu_type)
124 {
125 	if (op_cpu_base_type(cpu_type) == CPU_ARCH_PERFMON) {
126 		unsigned v = arch_cpuid_1(0xa);
127 		return (v >> 8) & 0xff;
128 	}
129 	return -1;
130 }
131 
arch_get_counter_mask(void)132 static inline unsigned arch_get_counter_mask(void)
133 {
134 	unsigned v = arch_cpuid_1(0xa);
135 	return num_to_mask((v >> 8) & 0xff);
136 }
137 
op_cpu_specific_type(op_cpu cpu_type)138 static 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 
162 #else
163 
arch_get_filter(op_cpu cpu_type)164 static 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 
arch_num_counters(op_cpu cpu_type)172 static 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 
arch_get_counter_mask(void)180 static inline unsigned arch_get_counter_mask(void)
181 {
182 	return 0;
183 }
184 
op_cpu_specific_type(op_cpu cpu_type)185 static inline op_cpu op_cpu_specific_type(op_cpu cpu_type)
186 {
187 	return cpu_type;
188 }
189 #endif
190