• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * @file op_apic.c
3  *
4  * APIC setup etc. routines
5  *
6  * @remark Copyright 2002 OProfile authors
7  * @remark Read the file COPYING
8  *
9  * @author John Levon
10  * @author Philippe Elie
11  * @author Dave Jones
12  * @author Graydon Hoare
13  */
14 
15 #include <linux/mm.h>
16 #include <linux/init.h>
17 #include <linux/config.h>
18 #include <asm/io.h>
19 
20 #include "oprofile.h"
21 #include "op_msr.h"
22 #include "op_apic.h"
23 
24 /* used to save/restore original kernel nmi */
25 static struct gate_struct kernel_nmi;
26 static ulong lvtpc_masked;
27 
28 /* this masking code is unsafe and nasty but might deal with the small
29  * race when installing the NMI entry into the IDT.
30  */
mask_lvtpc(void * e)31 static void mask_lvtpc(void * e)
32 {
33 	u32 v = apic_read(APIC_LVTPC);
34 	lvtpc_masked = v & APIC_LVT_MASKED;
35 	apic_write(APIC_LVTPC, v | APIC_LVT_MASKED);
36 }
37 
unmask_lvtpc(void * e)38 static void unmask_lvtpc(void * e)
39 {
40 	if (!lvtpc_masked)
41 		apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
42 }
43 
44 
install_nmi(void)45 void install_nmi(void)
46 {
47 	struct _descr descr;
48 
49 	/* NMI handler is at idt_table[IDT_VECTOR_NUMBER]            */
50 	/* see Intel Vol.3 Figure 5-2, interrupt gate                */
51 
52 	smp_call_function(mask_lvtpc, NULL, 0, 1);
53 	mask_lvtpc(NULL);
54 
55 	store_idt(descr);
56 	kernel_nmi = descr.base[NMI_VECTOR_NUM];
57 	SET_NMI_GATE;
58 
59 	smp_call_function(unmask_lvtpc, NULL, 0, 1);
60 	unmask_lvtpc(NULL);
61 }
62 
restore_nmi(void)63 void restore_nmi(void)
64 {
65 	struct _descr descr;
66 
67 	smp_call_function(mask_lvtpc, NULL, 0, 1);
68 	mask_lvtpc(NULL);
69 
70 	store_idt(descr);
71 	descr.base[NMI_VECTOR_NUM] = kernel_nmi;
72 
73 	smp_call_function(unmask_lvtpc, NULL, 0, 1);
74 	unmask_lvtpc(NULL);
75 }
76 
77 
78 /* ---------------- APIC setup ------------------ */
79 static uint saved_lvtpc[NR_CPUS];
80 
lvtpc_apic_setup(void * dummy)81 void __init lvtpc_apic_setup(void * dummy)
82 {
83 	uint val;
84 
85 	/* set up LVTPC as we need it */
86 	/* IA32 V3, Figure 7.8 */
87 	val = apic_read(APIC_LVTPC);
88 	saved_lvtpc[op_cpu_id()] = val;
89 	/* allow PC overflow interrupts */
90 	val &= ~APIC_LVT_MASKED;
91 	/* set delivery to NMI */
92 	val = SET_APIC_DELIVERY_MODE(val, APIC_MODE_NMI);
93 	apic_write(APIC_LVTPC, val);
94 }
95 
96 /* not safe to mark as __exit since used from __init code */
lvtpc_apic_restore(void * dummy)97 void lvtpc_apic_restore(void * dummy)
98 {
99 	/* restoring APIC_LVTPC can trigger an apic error because the delivery
100 	 * mode and vector nr combination can be illegal. That's by design: on
101 	 * power on apic lvt contain a zero vector nr which are legal only for
102 	 * NMI delivrey mode. So inhibit apic err before restoring lvtpc
103 	 */
104 	uint v = apic_read(APIC_LVTERR);
105 	apic_write(APIC_LVTERR, v | APIC_LVT_MASKED);
106 	apic_write(APIC_LVTPC, saved_lvtpc[op_cpu_id()]);
107 	apic_write(APIC_LVTERR, v);
108 }
109 
enable_apic(void)110 static int __init enable_apic(void)
111 {
112 	uint msr_low, msr_high;
113 	uint val;
114 
115 	/* enable local APIC via MSR. Forgetting this is a fun way to
116 	 * lock the box. But we have to hope this is allowed if the APIC
117 	 * has already been enabled.
118 	 *
119 	 * IA32 V3, 7.4.2 */
120 	rdmsr(MSR_IA32_APICBASE, msr_low, msr_high);
121 	if ((msr_low & (1 << 11)) == 0)
122 		wrmsr(MSR_IA32_APICBASE, msr_low | (1 << 11), msr_high);
123 
124 	/* even if the apic is up we must check for a good APIC */
125 
126 	/* IA32 V3, 7.4.15 */
127 	val = apic_read(APIC_LVR);
128 	if (!APIC_INTEGRATED(GET_APIC_VERSION(val)))
129 		goto not_local_apic;
130 
131 	/* LVT0,LVT1,LVTT,LVTPC */
132 	if (GET_APIC_MAXLVT(apic_read(APIC_LVR)) < 4)
133 		goto not_local_apic;
134 
135 	/* IA32 V3, 7.4.14.1 */
136 	val = apic_read(APIC_SPIV);
137 	if (!(val & APIC_SPIV_APIC_ENABLED))
138 		apic_write(APIC_SPIV, val | APIC_SPIV_APIC_ENABLED);
139 
140 	return !!(val & APIC_SPIV_APIC_ENABLED);
141 
142 not_local_apic:
143 	/* disable the apic only if it was disabled */
144 	if ((msr_low & (1 << 11)) == 0)
145 		wrmsr(MSR_IA32_APICBASE, msr_low & ~(1 << 11), msr_high);
146 
147 	printk(KERN_ERR "oprofile: no suitable local APIC. Falling back to RTC mode.\n");
148 	return -ENODEV;
149 }
150 
do_apic_setup(void)151 static void __init do_apic_setup(void)
152 {
153 	uint val;
154 
155 	local_irq_disable();
156 
157 	val = APIC_LVT_LEVEL_TRIGGER;
158 	val = SET_APIC_DELIVERY_MODE(val, APIC_MODE_EXINT);
159 	apic_write(APIC_LVT0, val);
160 
161 	/* edge triggered, IA 7.4.11 */
162 	val = SET_APIC_DELIVERY_MODE(0, APIC_MODE_NMI);
163 	apic_write(APIC_LVT1, val);
164 
165 	/* clear error register */
166 	/* IA32 V3, 7.4.17 */
167 	/* PHE must be cleared after unmasking by a back-to-back write,
168 	 * but it is probably ok because we mask only, the ESR is not
169 	 * updated is this a real problem ? */
170 	apic_write(APIC_ESR, 0);
171 
172 	/* mask error interrupt */
173 	/* IA32 V3, Figure 7.8 */
174 	val = apic_read(APIC_LVTERR);
175 	val |= APIC_LVT_MASKED;
176 	apic_write(APIC_LVTERR, val);
177 
178 	/* setup timer vector */
179 	/* IA32 V3, 7.4.8 */
180 	apic_write(APIC_LVTT, APIC_SEND_PENDING | 0x31);
181 
182 	/* Divide configuration register */
183 	/* PHE the apic clock is based on the FSB. This should only
184 	 * changed with a calibration method.  */
185 	val = APIC_TDR_DIV_1;
186 	apic_write(APIC_TDCR, val);
187 
188 	local_irq_enable();
189 }
190 
191 /* does the CPU have a local APIC ? */
check_cpu_ok(void)192 static int __init check_cpu_ok(void)
193 {
194 	if (sysctl.cpu_type != CPU_PPRO &&
195 		sysctl.cpu_type != CPU_PII &&
196 		sysctl.cpu_type != CPU_PIII &&
197 		sysctl.cpu_type != CPU_ATHLON &&
198 		sysctl.cpu_type != CPU_HAMMER &&
199 		sysctl.cpu_type != CPU_P4 &&
200 		sysctl.cpu_type != CPU_P4_HT2)
201 		return 0;
202 
203 	return 1;
204 }
205 
apic_setup(void)206 int __init apic_setup(void)
207 {
208 	u32 val;
209 
210 	if (!check_cpu_ok())
211 		goto nodev;
212 
213 	fixmap_setup();
214 
215 	switch (enable_apic()) {
216 		case 0:
217 			do_apic_setup();
218 			val = apic_read(APIC_ESR);
219 			printk(KERN_INFO "oprofile: enabled local APIC. Err code %.08x\n", val);
220 			break;
221 		case 1:
222 			printk(KERN_INFO "oprofile: APIC was already enabled\n");
223 			break;
224 		default:
225 			goto nodev;
226 	}
227 
228 	lvtpc_apic_setup(NULL);
229 	return 0;
230 nodev:
231 	printk(KERN_WARNING "Your CPU does not have a local APIC, e.g. "
232 	       "mobile P6. Falling back to RTC mode.\n");
233 	return -ENODEV;
234 }
235 
apic_restore(void)236 void apic_restore(void)
237 {
238 	fixmap_restore();
239 }
240