1 /**
2 * \file
3 * \brief APIC for X86
4 */
5 /*
6 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
7 * Frank Mehnert <fm3@os.inf.tu-dresden.de>
8 * economic rights: Technische Universität Dresden (Germany)
9 * This file is part of TUD:OS and distributed under the terms of the
10 * GNU Lesser General Public License 2.1.
11 * Please see the COPYING-LGPL-2.1 file for details.
12 */
13 #ifndef __L4_UTIL_APIC_H
14 #define __L4_UTIL_APIC_H
15
16 /*
17 * Local APIC programming library
18 *
19 * For documentation, see
20 *
21 * "Intel Architecture Software Developer's Manual", Volume 3, chapter 7.5:
22 * "Advanced Programmable Interrupt Controller (APIC)"
23 *
24 * Local APIC is present since
25 * - INTEL P6 (PPro)
26 * - AMD K7 (Athlon), Model 2
27 *
28 * In non-SMP-boards, local APIC is disabled, but
29 * can be activated by writing to a MSR register.
30 * For using APIC see packets cpufreq and l4rtl.
31 *
32 * See linux/include/asm-i386/i82489.h for further details.
33 */
34
35 #define APIC_PHYS_BASE 0xFEE00000
36 #define APIC_MAP_BASE 0xA0200000
37 #define APIC_BASE_MSR 0x1b
38
39 #define APIC_ID 0x20
40 #define GET_APIC_ID(x) (((x)>>24)&0x0F)
41 #define APIC_LVR 0x30
42 #define GET_APIC_VERSION(x) ((x)&0xFF)
43 #define APIC_TASKPRI 0x80
44 #define APIC_TPRI_MASK 0xFF
45 #define APIC_EOI 0xB0
46 #define APIC_LDR 0xD0
47 #define APIC_LDR_MASK (0xFF<<24)
48 #define APIC_DFR 0xE0
49 #define SET_APIC_DFR(x) ((x)<<28)
50 #define APIC_SPIV 0xF0
51 #define APIC_LVTT 0x320
52 #define APIC_LVTPC 0x340
53 #define APIC_LVT0 0x350
54 #define SET_APIC_TIMER_BASE(x) (((x)<<18))
55 #define APIC_TIMER_BASE_DIV 0x2
56 #define APIC_LVT1 0x360
57 #define APIC_LVTERR 0x370
58 #define APIC_TMICT 0x380
59 #define APIC_TMCCT 0x390
60 #define APIC_TDCR 0x3E0
61
62 #define APIC_LVT_MASKED (1<<16)
63 #define APIC_LVT_TIMER_PERIODIC (1<<17)
64 #define APIC_TDR_DIV_1 0xB
65 #define APIC_TDR_DIV_2 0x0
66 #define APIC_TDR_DIV_4 0x1
67 #define APIC_TDR_DIV_8 0x2
68 #define APIC_TDR_DIV_16 0x3
69 #define APIC_TDR_DIV_32 0x8
70 #define APIC_TDR_DIV_64 0x9
71 #define APIC_TDR_DIV_128 0xA
72
73 #include <l4/sys/compiler.h>
74 #include <l4/sys/types.h>
75
76 EXTERN_C_BEGIN
77
78 /* prototypes */
79 extern unsigned long apic_map_base;
80 extern unsigned long apic_timer_divisor;
81
82 extern unsigned long l4_scaler_apic_to_ms;
83
84 L4_CV void apic_show_registers(void);
85 L4_CV int apic_check_working(void);
86 L4_CV void apic_activate_by_io(void);
87 L4_CV void apic_timer_set_divisor(int divisor);
88
89 L4_CV unsigned long l4_calibrate_apic(void);
90
91 EXTERN_C_END
92
93 L4_INLINE void apic_write(unsigned long reg, unsigned long v);
94 L4_INLINE unsigned long apic_read(unsigned long reg);
95 L4_INLINE void apic_activate_by_msr(void);
96 L4_INLINE void apic_deactivate_by_msr(void);
97 L4_INLINE unsigned long apic_read_phys_address(void);
98 L4_INLINE int apic_test_present(void);
99 L4_INLINE void apic_soft_enable(void);
100 L4_INLINE void apic_init(unsigned long map_addr);
101 L4_INLINE void apic_done(void);
102 L4_INLINE void apic_irq_ack(void);
103
104 L4_INLINE void apic_lvt0_disable_irq(void);
105 L4_INLINE void apic_lvt0_enable_irq(void);
106 L4_INLINE void apic_lvt1_disable_irq(void);
107 L4_INLINE void apic_lvt1_enable_irq(void);
108
109 L4_INLINE void apic_timer_write(unsigned long value);
110 L4_INLINE unsigned long apic_timer_read(void);
111 L4_INLINE void apic_timer_disable_irq(void);
112 L4_INLINE void apic_timer_enable_irq(void);
113 L4_INLINE void apic_timer_assign_irq(unsigned long vector);
114 L4_INLINE void apic_timer_set_periodic(void);
115 L4_INLINE void apic_timer_set_one_shot(void);
116
117 L4_INLINE void apic_perf_disable_irq(void);
118 L4_INLINE void apic_perf_enable_irq(void);
119 L4_INLINE void apic_perf_assign_irq(unsigned long vector);
120
121
122 /* write APIC register */
123 L4_INLINE void
apic_write(unsigned long reg,unsigned long v)124 apic_write(unsigned long reg, unsigned long v)
125 {
126 *((volatile unsigned long *)(apic_map_base+reg))=v;
127 }
128
129
130 /* read APIC register */
131 L4_INLINE unsigned long
apic_read(unsigned long reg)132 apic_read(unsigned long reg)
133 {
134 return *((volatile unsigned long *)(apic_map_base+reg));
135 }
136
137
138 /* disable LINT0 */
139 L4_INLINE void
apic_lvt0_disable_irq(void)140 apic_lvt0_disable_irq(void)
141 {
142 unsigned long tmp_val;
143 tmp_val = apic_read(APIC_LVT0);
144 tmp_val |= APIC_LVT_MASKED;
145 apic_write(APIC_LVT0, tmp_val);
146 }
147
148
149 /* enable LINT0 */
150 L4_INLINE void
apic_lvt0_enable_irq(void)151 apic_lvt0_enable_irq(void)
152 {
153 unsigned long tmp_val;
154 tmp_val = apic_read(APIC_LVT0);
155 tmp_val &= ~(APIC_LVT_MASKED);
156 apic_write(APIC_LVT0, tmp_val);
157 }
158
159
160 /* disable LINT1 */
161 L4_INLINE void
apic_lvt1_disable_irq(void)162 apic_lvt1_disable_irq(void)
163 {
164 unsigned long tmp_val;
165 tmp_val = apic_read(APIC_LVT1);
166 tmp_val |= APIC_LVT_MASKED;
167 apic_write(APIC_LVT1, tmp_val);
168 }
169
170
171 /* enable LINT1 */
172 L4_INLINE void
apic_lvt1_enable_irq(void)173 apic_lvt1_enable_irq(void)
174 {
175 unsigned long tmp_val;
176 tmp_val = apic_read(APIC_LVT1);
177 tmp_val &= ~(APIC_LVT_MASKED);
178 apic_write(APIC_LVT1, tmp_val);
179 }
180
181
182 /* write APIC timer register */
183 L4_INLINE void
apic_timer_write(unsigned long value)184 apic_timer_write(unsigned long value)
185 {
186 apic_read(APIC_TMICT);
187 apic_write(APIC_TMICT,value);
188 }
189
190
191 /* read APIC timer register */
192 L4_INLINE unsigned long
apic_timer_read(void)193 apic_timer_read(void)
194 {
195 return apic_read(APIC_TMCCT);
196 }
197
198
199 /* disable IRQ when APIC timer passes 0 */
200 L4_INLINE void
apic_timer_disable_irq(void)201 apic_timer_disable_irq(void)
202 {
203 unsigned long tmp_val;
204 tmp_val = apic_read(APIC_LVTT);
205 tmp_val |= APIC_LVT_MASKED;
206 apic_write(APIC_LVTT, tmp_val);
207 }
208
209
210 /* enable IRQ when APIC timer passes 0 */
211 L4_INLINE void
apic_timer_enable_irq(void)212 apic_timer_enable_irq(void)
213 {
214 unsigned long tmp_val;
215 tmp_val = apic_read(APIC_LVTT);
216 tmp_val &= ~(APIC_LVT_MASKED);
217 apic_write(APIC_LVTT, tmp_val);
218 }
219
220
221 L4_INLINE void
apic_timer_set_periodic(void)222 apic_timer_set_periodic(void)
223 {
224 unsigned long tmp_val;
225 tmp_val = apic_read(APIC_LVTT);
226 tmp_val |= APIC_LVT_TIMER_PERIODIC;
227 tmp_val |= APIC_LVT_MASKED;
228 apic_write(APIC_LVTT, tmp_val);
229 }
230
231
232 L4_INLINE void
apic_timer_set_one_shot(void)233 apic_timer_set_one_shot(void)
234 {
235 unsigned long tmp_val;
236 tmp_val = apic_read(APIC_LVTT);
237 tmp_val &= ~APIC_LVT_TIMER_PERIODIC;
238 tmp_val |= APIC_LVT_MASKED;
239 apic_write(APIC_LVTT, tmp_val);
240 }
241
242
243 /* set vector of APIC timer irq */
244 L4_INLINE void
apic_timer_assign_irq(unsigned long vector)245 apic_timer_assign_irq(unsigned long vector)
246 {
247 unsigned long tmp_val;
248 tmp_val = apic_read(APIC_LVTT);
249 tmp_val &= 0xffffff00;
250 tmp_val |= vector;
251 tmp_val |= APIC_LVT_MASKED;
252 apic_write(APIC_LVTT, tmp_val);
253 }
254
255
256 /* disable IRQ when performance counter passes 0 */
257 L4_INLINE void
apic_perf_disable_irq(void)258 apic_perf_disable_irq(void)
259 {
260 unsigned long tmp_val;
261 tmp_val = apic_read(APIC_LVTPC);
262 tmp_val |= APIC_LVT_MASKED;
263 apic_write(APIC_LVTPC, tmp_val);
264 }
265
266
267 /* enable IRQ when performance counter passes 0 */
268 L4_INLINE void
apic_perf_enable_irq(void)269 apic_perf_enable_irq(void)
270 {
271 unsigned long tmp_val;
272 tmp_val = apic_read(APIC_LVTPC);
273 tmp_val &= ~(APIC_LVT_MASKED);
274 apic_write(APIC_LVTPC, tmp_val);
275 }
276
277
278 /* set vector of performance counter irq */
279 L4_INLINE void
apic_perf_assign_irq(unsigned long vector)280 apic_perf_assign_irq(unsigned long vector)
281 {
282 unsigned long tmp_val;
283 tmp_val = apic_read(APIC_LVTPC);
284 tmp_val &= 0xffffff00;
285 tmp_val |= vector;
286 tmp_val |= APIC_LVT_MASKED;
287 apic_write(APIC_LVTPC, tmp_val);
288 }
289
290
291 /* activate APIC by writing to appropriate MSR */
292 L4_INLINE void
apic_activate_by_msr(void)293 apic_activate_by_msr(void)
294 {
295 unsigned long low;
296 unsigned long high;
297
298 /* rdmsr */
299 asm volatile(".byte 0xf; .byte 0x32\n"
300 :"=a" (low),
301 "=d" (high)
302 :"c" (APIC_BASE_MSR)
303 );
304
305 low |= 0x800; /* activate APIC */
306 low &= 0x00000fff;
307 low |= (APIC_PHYS_BASE & 0xfffff000); /* set address */
308
309 /* wrmsr */
310 asm volatile(".byte 0xf; .byte 0x30\n"
311 :
312 :"c" (APIC_BASE_MSR),
313 "a" (low),
314 "d" (high)
315 );
316 }
317
318
319 /* deactivate APIC by writing to appropriate MSR */
320 L4_INLINE void
apic_deactivate_by_msr(void)321 apic_deactivate_by_msr(void)
322 {
323 unsigned long low;
324 unsigned long high;
325
326 /* rdmsr */
327 asm volatile(".byte 0xf; .byte 0x32\n"
328 :"=a" (low),
329 "=d" (high)
330 :"c" (APIC_BASE_MSR)
331 );
332
333 low &= 0xfffff7ff; /* deactivate APIC */
334
335 /* wrmsr */
336 asm volatile(".byte 0xf; .byte 0x30\n"
337 :
338 :"c" (APIC_BASE_MSR),
339 "a" (low),
340 "d" (high)
341 );
342 }
343
344
345 /* read memory mapped address of apic */
346 L4_INLINE unsigned long
apic_read_phys_address(void)347 apic_read_phys_address(void)
348 {
349 unsigned long low;
350 unsigned long high;
351
352 /* rdmsr */
353 asm volatile(".byte 0xf; .byte 0x32\n"
354 :"=a" (low),
355 "=d" (high)
356 :"c" (APIC_BASE_MSR)
357 );
358
359 return (low &= 0xfffff000);
360 }
361
362
363 /* test if APIC present */
364 L4_INLINE int
apic_test_present(void)365 apic_test_present(void)
366 {
367 unsigned int dummy;
368 unsigned int capability;
369
370 asm volatile("pushl %%ebx ; cpuid ; popl %%ebx"
371 : "=a" (dummy),
372 "=c" (dummy),
373 "=d" (capability)
374 : "a" (0x00000001)
375 : "cc");
376
377 return ((capability & 1<<9) !=0);
378 }
379
380
381 L4_INLINE void
apic_soft_enable(void)382 apic_soft_enable(void)
383 {
384 unsigned long tmp_val;
385 tmp_val = apic_read(APIC_SPIV);
386 tmp_val |= (1<<8); /* enable APIC */
387 tmp_val &= ~(1<<9); /* enable Focus Processor Checking */
388 tmp_val |= 0xff; /* Set spurious IRQ vector to 0xff */
389 apic_write(APIC_SPIV, tmp_val);
390 }
391
392
393 L4_INLINE void
apic_init(unsigned long base_addr)394 apic_init(unsigned long base_addr)
395 {
396 apic_map_base = base_addr;
397 }
398
399
400 L4_INLINE void
apic_done(void)401 apic_done(void)
402 {
403 apic_map_base = 0;
404 }
405
406
407 L4_INLINE void
apic_irq_ack(void)408 apic_irq_ack(void)
409 {
410 apic_read(APIC_SPIV);
411 apic_write(APIC_EOI, 0);
412 }
413
414
415 #endif /* __L4_UTIL_APIC_H */
416