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
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;
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
41static 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
59static 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
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. */
87static 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
100static 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
123static 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
132static 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
138static 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
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
185static inline op_cpu op_cpu_specific_type(op_cpu cpu_type)
186{
187	return cpu_type;
188}
189#endif
190