1 | /* $NetBSD: ioapic.c,v 1.52 2015/07/27 15:45:20 msaitoh Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2000, 2009 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by RedBack Networks Inc, and by Andrew Doran. |
9 | * |
10 | * Author: Bill Sommerfeld |
11 | * |
12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions |
14 | * are met: |
15 | * 1. Redistributions of source code must retain the above copyright |
16 | * notice, this list of conditions and the following disclaimer. |
17 | * 2. Redistributions in binary form must reproduce the above copyright |
18 | * notice, this list of conditions and the following disclaimer in the |
19 | * documentation and/or other materials provided with the distribution. |
20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 | * POSSIBILITY OF SUCH DAMAGE. |
32 | */ |
33 | |
34 | /* |
35 | * Copyright (c) 1999 Stefan Grefen |
36 | * |
37 | * Redistribution and use in source and binary forms, with or without |
38 | * modification, are permitted provided that the following conditions |
39 | * are met: |
40 | * 1. Redistributions of source code must retain the above copyright |
41 | * notice, this list of conditions and the following disclaimer. |
42 | * 2. Redistributions in binary form must reproduce the above copyright |
43 | * notice, this list of conditions and the following disclaimer in the |
44 | * documentation and/or other materials provided with the distribution. |
45 | * 3. All advertising materials mentioning features or use of this software |
46 | * must display the following acknowledgement: |
47 | * This product includes software developed by the NetBSD |
48 | * Foundation, Inc. and its contributors. |
49 | * 4. Neither the name of The NetBSD Foundation nor the names of its |
50 | * contributors may be used to endorse or promote products derived |
51 | * from this software without specific prior written permission. |
52 | * |
53 | * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY |
54 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
55 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
56 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE |
57 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
58 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
59 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
60 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
61 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
62 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
63 | * SUCH DAMAGE. |
64 | */ |
65 | |
66 | #include <sys/cdefs.h> |
67 | __KERNEL_RCSID(0, "$NetBSD: ioapic.c,v 1.52 2015/07/27 15:45:20 msaitoh Exp $" ); |
68 | |
69 | #include "opt_ddb.h" |
70 | |
71 | #include <sys/param.h> |
72 | #include <sys/systm.h> |
73 | #include <sys/device.h> |
74 | #include <sys/malloc.h> |
75 | #include <sys/kernel.h> |
76 | #include <sys/bus.h> |
77 | |
78 | #include <uvm/uvm_extern.h> |
79 | |
80 | #include <machine/isa_machdep.h> /* XXX intrhand */ |
81 | #include <machine/i82093reg.h> |
82 | #include <machine/i82093var.h> |
83 | #include <machine/i82489reg.h> |
84 | #include <machine/i82489var.h> |
85 | #include <machine/i8259.h> |
86 | #include <machine/mpbiosvar.h> |
87 | #include <machine/pio.h> |
88 | #include <machine/pmap.h> |
89 | #include <machine/lock.h> |
90 | |
91 | #include "acpica.h" |
92 | #include "opt_mpbios.h" |
93 | #include "opt_acpi.h" |
94 | |
95 | #if !defined(MPBIOS) && NACPICA == 0 |
96 | #error "ioapic needs at least one of the MPBIOS or ACPI options" |
97 | #endif |
98 | |
99 | /* |
100 | * XXX locking |
101 | */ |
102 | |
103 | int ioapic_match(device_t, cfdata_t, void *); |
104 | void ioapic_attach(device_t, device_t, void *); |
105 | |
106 | extern int x86_mem_add_mapping(bus_addr_t, bus_size_t, |
107 | int, bus_space_handle_t *); /* XXX XXX */ |
108 | |
109 | void ioapic_hwmask(struct pic *, int); |
110 | void ioapic_hwunmask(struct pic *, int); |
111 | bool ioapic_trymask(struct pic *, int); |
112 | static void ioapic_addroute(struct pic *, struct cpu_info *, int, int, int); |
113 | static void ioapic_delroute(struct pic *, struct cpu_info *, int, int, int); |
114 | |
115 | int apic_verbose = 0; |
116 | |
117 | struct ioapic_softc *ioapics; /* head of linked list */ |
118 | int nioapics = 0; /* number attached */ |
119 | static int ioapic_vecbase; |
120 | |
121 | static inline u_long |
122 | ioapic_lock(struct ioapic_softc *sc) |
123 | { |
124 | u_long flags; |
125 | |
126 | flags = x86_read_psl(); |
127 | x86_disable_intr(); |
128 | __cpu_simple_lock(&sc->sc_pic.pic_lock); |
129 | return flags; |
130 | } |
131 | |
132 | static inline void |
133 | ioapic_unlock(struct ioapic_softc *sc, u_long flags) |
134 | { |
135 | __cpu_simple_unlock(&sc->sc_pic.pic_lock); |
136 | x86_write_psl(flags); |
137 | } |
138 | |
139 | #ifndef _IOAPIC_CUSTOM_RW |
140 | /* |
141 | * Register read/write routines. |
142 | */ |
143 | static inline uint32_t |
144 | ioapic_read_ul(struct ioapic_softc *sc,int regid) |
145 | { |
146 | uint32_t val; |
147 | |
148 | *(sc->sc_reg) = regid; |
149 | val = *sc->sc_data; |
150 | |
151 | return val; |
152 | } |
153 | |
154 | static inline void |
155 | ioapic_write_ul(struct ioapic_softc *sc,int regid, uint32_t val) |
156 | { |
157 | *(sc->sc_reg) = regid; |
158 | *(sc->sc_data) = val; |
159 | } |
160 | #endif /* !_IOAPIC_CUSTOM_RW */ |
161 | |
162 | static inline uint32_t |
163 | ioapic_read(struct ioapic_softc *sc, int regid) |
164 | { |
165 | uint32_t val; |
166 | u_long flags; |
167 | |
168 | flags = ioapic_lock(sc); |
169 | val = ioapic_read_ul(sc, regid); |
170 | ioapic_unlock(sc, flags); |
171 | return val; |
172 | } |
173 | |
174 | static inline void |
175 | ioapic_write(struct ioapic_softc *sc,int regid, int val) |
176 | { |
177 | u_long flags; |
178 | |
179 | flags = ioapic_lock(sc); |
180 | ioapic_write_ul(sc, regid, val); |
181 | ioapic_unlock(sc, flags); |
182 | } |
183 | |
184 | struct ioapic_softc * |
185 | ioapic_find(int apicid) |
186 | { |
187 | struct ioapic_softc *sc; |
188 | |
189 | if (apicid == MPS_ALL_APICS) { /* XXX mpbios-specific */ |
190 | /* |
191 | * XXX kludge for all-ioapics interrupt support |
192 | * on single ioapic systems |
193 | */ |
194 | if (nioapics <= 1) |
195 | return ioapics; |
196 | panic("unsupported: all-ioapics interrupt with >1 ioapic" ); |
197 | } |
198 | |
199 | for (sc = ioapics; sc != NULL; sc = sc->sc_next) |
200 | if (sc->sc_pic.pic_apicid == apicid) |
201 | return sc; |
202 | |
203 | return NULL; |
204 | } |
205 | |
206 | /* |
207 | * For the case the I/O APICs were configured using ACPI, there must |
208 | * be an option to match global ACPI interrupts with APICs. |
209 | */ |
210 | struct ioapic_softc * |
211 | ioapic_find_bybase(int vec) |
212 | { |
213 | struct ioapic_softc *sc; |
214 | |
215 | for (sc = ioapics; sc != NULL; sc = sc->sc_next) { |
216 | if (vec >= sc->sc_pic.pic_vecbase && |
217 | vec < (sc->sc_pic.pic_vecbase + sc->sc_apic_sz)) |
218 | return sc; |
219 | } |
220 | |
221 | return NULL; |
222 | } |
223 | |
224 | static inline void |
225 | ioapic_add(struct ioapic_softc *sc) |
226 | { |
227 | struct ioapic_softc **scp; |
228 | |
229 | sc->sc_next = NULL; |
230 | |
231 | for (scp = &ioapics; *scp != NULL; scp = &(*scp)->sc_next) |
232 | ; |
233 | *scp = sc; |
234 | nioapics++; |
235 | } |
236 | |
237 | void |
238 | ioapic_print_redir (struct ioapic_softc *sc, const char *why, int pin) |
239 | { |
240 | uint32_t redirlo = ioapic_read(sc, IOAPIC_REDLO(pin)); |
241 | uint32_t redirhi = ioapic_read(sc, IOAPIC_REDHI(pin)); |
242 | |
243 | apic_format_redir(device_xname(sc->sc_dev), why, pin, redirhi, |
244 | redirlo); |
245 | } |
246 | |
247 | CFATTACH_DECL_NEW(ioapic, sizeof(struct ioapic_softc), |
248 | ioapic_match, ioapic_attach, NULL, NULL); |
249 | |
250 | int |
251 | ioapic_match(device_t parent, cfdata_t match, void *aux) |
252 | { |
253 | |
254 | return 1; |
255 | } |
256 | |
257 | /* |
258 | * can't use bus_space_xxx as we don't have a bus handle ... |
259 | */ |
260 | void |
261 | ioapic_attach(device_t parent, device_t self, void *aux) |
262 | { |
263 | struct ioapic_softc *sc = device_private(self); |
264 | struct apic_attach_args *aaa = (struct apic_attach_args *)aux; |
265 | int apic_id; |
266 | uint32_t ver_sz; |
267 | int i; |
268 | |
269 | sc->sc_dev = self; |
270 | sc->sc_flags = aaa->flags; |
271 | sc->sc_pic.pic_apicid = aaa->apic_id; |
272 | sc->sc_pic.pic_name = device_xname(self); |
273 | sc->sc_pic.pic_ioapic = sc; |
274 | |
275 | aprint_naive("\n" ); |
276 | |
277 | if (ioapic_find(aaa->apic_id) != NULL) { |
278 | aprint_error(": duplicate apic id (ignored)\n" ); |
279 | return; |
280 | } |
281 | |
282 | aprint_verbose(": pa 0x%jx" , (uintmax_t)aaa->apic_address); |
283 | #ifndef _IOAPIC_CUSTOM_RW |
284 | { |
285 | bus_space_handle_t bh; |
286 | |
287 | if (x86_mem_add_mapping(aaa->apic_address, PAGE_SIZE, 0, &bh) != 0) { |
288 | aprint_error(": map failed\n" ); |
289 | return; |
290 | } |
291 | sc->sc_reg = (volatile uint32_t *)(bh + IOAPIC_REG); |
292 | sc->sc_data = (volatile uint32_t *)(bh + IOAPIC_DATA); |
293 | } |
294 | #endif |
295 | sc->sc_pa = aaa->apic_address; |
296 | |
297 | sc->sc_pic.pic_type = PIC_IOAPIC; |
298 | __cpu_simple_lock_init(&sc->sc_pic.pic_lock); |
299 | sc->sc_pic.pic_hwmask = ioapic_hwmask; |
300 | sc->sc_pic.pic_hwunmask = ioapic_hwunmask; |
301 | sc->sc_pic.pic_addroute = ioapic_addroute; |
302 | sc->sc_pic.pic_delroute = ioapic_delroute; |
303 | sc->sc_pic.pic_trymask = ioapic_trymask; |
304 | sc->sc_pic.pic_edge_stubs = ioapic_edge_stubs; |
305 | sc->sc_pic.pic_level_stubs = ioapic_level_stubs; |
306 | |
307 | apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK) |
308 | >> IOAPIC_ID_SHIFT; |
309 | ver_sz = ioapic_read(sc, IOAPIC_VER); |
310 | |
311 | if (ver_sz == 0xffffffff) { |
312 | aprint_error(": failed to read version/size\n" ); |
313 | goto out; |
314 | } |
315 | |
316 | ioapic_add(sc); |
317 | |
318 | sc->sc_apic_vers = (ver_sz & IOAPIC_VER_MASK) >> IOAPIC_VER_SHIFT; |
319 | sc->sc_apic_sz = (ver_sz & IOAPIC_MAX_MASK) >> IOAPIC_MAX_SHIFT; |
320 | sc->sc_apic_sz++; |
321 | |
322 | if (aaa->apic_vecbase != -1) |
323 | sc->sc_pic.pic_vecbase = aaa->apic_vecbase; |
324 | else { |
325 | /* |
326 | * XXX this assumes ordering of ioapics in the table. |
327 | * Only needed for broken BIOS workaround (see mpbios.c) |
328 | */ |
329 | sc->sc_pic.pic_vecbase = ioapic_vecbase; |
330 | ioapic_vecbase += sc->sc_apic_sz; |
331 | } |
332 | |
333 | if (mp_verbose) { |
334 | printf(", %s mode" , |
335 | aaa->flags & IOAPIC_PICMODE ? "PIC" : "virtual wire" ); |
336 | } |
337 | |
338 | aprint_verbose(", version 0x%x, %d pins" , sc->sc_apic_vers, |
339 | sc->sc_apic_sz); |
340 | aprint_normal("\n" ); |
341 | |
342 | sc->sc_pins = malloc(sizeof(struct ioapic_pin) * sc->sc_apic_sz, |
343 | M_DEVBUF, M_WAITOK); |
344 | |
345 | for (i=0; i<sc->sc_apic_sz; i++) { |
346 | uint32_t redlo, redhi; |
347 | |
348 | sc->sc_pins[i].ip_next = NULL; |
349 | sc->sc_pins[i].ip_map = NULL; |
350 | sc->sc_pins[i].ip_vector = 0; |
351 | sc->sc_pins[i].ip_type = IST_NONE; |
352 | |
353 | /* Mask all pins by default. */ |
354 | redlo = IOAPIC_REDLO_MASK; |
355 | /* |
356 | * ISA interrupts are connect to pin 0-15 and |
357 | * edge triggered on high, which is the default. |
358 | * |
359 | * Expect all other interrupts to be PCI-like |
360 | * level triggered on low. |
361 | */ |
362 | if (i >= 16) |
363 | redlo |= IOAPIC_REDLO_LEVEL | IOAPIC_REDLO_ACTLO; |
364 | redhi = (cpu_info_primary.ci_cpuid << IOAPIC_REDHI_DEST_SHIFT); |
365 | ioapic_write(sc, IOAPIC_REDHI(i), redhi); |
366 | ioapic_write(sc, IOAPIC_REDLO(i), redlo); |
367 | } |
368 | |
369 | /* |
370 | * In case the APIC is not initialized to the correct ID |
371 | * do it now. |
372 | * Maybe we should record the original ID for interrupt |
373 | * mapping later ... |
374 | */ |
375 | if (apic_id != sc->sc_pic.pic_apicid) { |
376 | aprint_debug_dev(sc->sc_dev, "misconfigured as apic %d\n" , |
377 | apic_id); |
378 | |
379 | ioapic_write(sc, IOAPIC_ID, |
380 | (ioapic_read(sc, IOAPIC_ID) & ~IOAPIC_ID_MASK) |
381 | | (sc->sc_pic.pic_apicid << IOAPIC_ID_SHIFT)); |
382 | |
383 | apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK) |
384 | >> IOAPIC_ID_SHIFT; |
385 | |
386 | if (apic_id != sc->sc_pic.pic_apicid) |
387 | aprint_error_dev(sc->sc_dev, |
388 | "can't remap to apid %d\n" , sc->sc_pic.pic_apicid); |
389 | else |
390 | aprint_debug_dev(sc->sc_dev, "remapped to apic %d\n" , |
391 | sc->sc_pic.pic_apicid); |
392 | } |
393 | |
394 | out: |
395 | if (!pmf_device_register(self, NULL, NULL)) |
396 | aprint_error_dev(self, "couldn't establish power handler\n" ); |
397 | |
398 | #if 0 |
399 | /* output of this was boring. */ |
400 | if (mp_verbose) |
401 | for (i=0; i<sc->sc_apic_sz; i++) |
402 | ioapic_print_redir(sc, "boot" , i); |
403 | #endif |
404 | } |
405 | |
406 | static void |
407 | apic_set_redir(struct ioapic_softc *sc, int pin, int idt_vec, |
408 | struct cpu_info *ci) |
409 | { |
410 | uint32_t redlo; |
411 | uint32_t redhi; |
412 | int delmode; |
413 | struct ioapic_pin *pp; |
414 | struct mp_intr_map *map; |
415 | |
416 | pp = &sc->sc_pins[pin]; |
417 | map = pp->ip_map; |
418 | redlo = map == NULL ? IOAPIC_REDLO_MASK : map->redir; |
419 | redhi = 0; |
420 | delmode = (redlo & IOAPIC_REDLO_DEL_MASK) >> IOAPIC_REDLO_DEL_SHIFT; |
421 | |
422 | if (delmode == IOAPIC_REDLO_DEL_FIXED || |
423 | delmode == IOAPIC_REDLO_DEL_LOPRI) { |
424 | if (pp->ip_type == IST_NONE) { |
425 | redlo |= IOAPIC_REDLO_MASK; |
426 | } else { |
427 | redhi = (ci->ci_cpuid << IOAPIC_REDHI_DEST_SHIFT); |
428 | redlo |= (idt_vec & 0xff); |
429 | redlo |= IOAPIC_REDLO_DEL_FIXED |
430 | << IOAPIC_REDLO_DEL_SHIFT; |
431 | redlo &= ~IOAPIC_REDLO_DSTMOD; |
432 | |
433 | /* XXX derive this bit from BIOS info */ |
434 | if (pp->ip_type == IST_LEVEL) |
435 | redlo |= IOAPIC_REDLO_LEVEL; |
436 | else |
437 | redlo &= ~IOAPIC_REDLO_LEVEL; |
438 | if ((map != NULL) |
439 | && ((map->flags & 3) == MPS_INTPO_DEF)) { |
440 | if (pp->ip_type == IST_LEVEL) |
441 | redlo |= IOAPIC_REDLO_ACTLO; |
442 | else |
443 | redlo &= ~IOAPIC_REDLO_ACTLO; |
444 | } |
445 | } |
446 | } |
447 | ioapic_write(sc, IOAPIC_REDHI(pin), redhi); |
448 | ioapic_write(sc, IOAPIC_REDLO(pin), redlo); |
449 | if (mp_verbose) |
450 | ioapic_print_redir(sc, "int" , pin); |
451 | } |
452 | |
453 | /* |
454 | * Throw the switch and enable interrupts.. |
455 | */ |
456 | |
457 | void |
458 | ioapic_enable(void) |
459 | { |
460 | if (ioapics == NULL) |
461 | return; |
462 | |
463 | i8259_setmask(0xffff); |
464 | |
465 | if (ioapics->sc_flags & IOAPIC_PICMODE) { |
466 | aprint_debug_dev(ioapics->sc_dev, |
467 | "writing to IMCR to disable pics\n" ); |
468 | outb(IMCR_ADDR, IMCR_REGISTER); |
469 | outb(IMCR_DATA, IMCR_APIC); |
470 | } |
471 | } |
472 | |
473 | void |
474 | ioapic_reenable(void) |
475 | { |
476 | int p, apic_id; |
477 | struct ioapic_softc *sc; |
478 | |
479 | if (ioapics == NULL) |
480 | return; |
481 | |
482 | aprint_normal("%s reenabling\n" , device_xname(ioapics->sc_dev)); |
483 | |
484 | for (sc = ioapics; sc != NULL; sc = sc->sc_next) { |
485 | apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK) |
486 | >> IOAPIC_ID_SHIFT; |
487 | if (apic_id != sc->sc_pic.pic_apicid) { |
488 | ioapic_write(sc, IOAPIC_ID, |
489 | (ioapic_read(sc, IOAPIC_ID) & ~IOAPIC_ID_MASK) |
490 | | (sc->sc_pic.pic_apicid << IOAPIC_ID_SHIFT)); |
491 | } |
492 | |
493 | for (p = 0; p < sc->sc_apic_sz; p++) |
494 | apic_set_redir(sc, p, sc->sc_pins[p].ip_vector, |
495 | sc->sc_pins[p].ip_cpu); |
496 | } |
497 | |
498 | ioapic_enable(); |
499 | } |
500 | |
501 | void |
502 | ioapic_hwmask(struct pic *pic, int pin) |
503 | { |
504 | uint32_t redlo; |
505 | struct ioapic_softc *sc = pic->pic_ioapic; |
506 | u_long flags; |
507 | |
508 | flags = ioapic_lock(sc); |
509 | redlo = ioapic_read_ul(sc, IOAPIC_REDLO(pin)); |
510 | redlo |= IOAPIC_REDLO_MASK; |
511 | ioapic_write_ul(sc, IOAPIC_REDLO(pin), redlo); |
512 | ioapic_unlock(sc, flags); |
513 | } |
514 | |
515 | bool |
516 | ioapic_trymask(struct pic *pic, int pin) |
517 | { |
518 | uint32_t redlo; |
519 | struct ioapic_softc *sc = pic->pic_ioapic; |
520 | u_long flags; |
521 | bool rv; |
522 | |
523 | /* Mask it. */ |
524 | flags = ioapic_lock(sc); |
525 | redlo = ioapic_read_ul(sc, IOAPIC_REDLO(pin)); |
526 | redlo |= IOAPIC_REDLO_MASK; |
527 | ioapic_write_ul(sc, IOAPIC_REDLO(pin), redlo); |
528 | |
529 | /* If pending, unmask and abort. */ |
530 | redlo = ioapic_read_ul(sc, IOAPIC_REDLO(pin)); |
531 | if ((redlo & (IOAPIC_REDLO_RIRR|IOAPIC_REDLO_DELSTS)) != 0) { |
532 | redlo &= ~IOAPIC_REDLO_MASK; |
533 | ioapic_write_ul(sc, IOAPIC_REDLO(pin), redlo); |
534 | rv = false; |
535 | } else { |
536 | rv = true; |
537 | } |
538 | ioapic_unlock(sc, flags); |
539 | return rv; |
540 | } |
541 | |
542 | void |
543 | ioapic_hwunmask(struct pic *pic, int pin) |
544 | { |
545 | uint32_t redlo; |
546 | struct ioapic_softc *sc = pic->pic_ioapic; |
547 | u_long flags; |
548 | |
549 | flags = ioapic_lock(sc); |
550 | redlo = ioapic_read_ul(sc, IOAPIC_REDLO(pin)); |
551 | redlo &= ~IOAPIC_REDLO_MASK; |
552 | ioapic_write_ul(sc, IOAPIC_REDLO(pin), redlo); |
553 | ioapic_unlock(sc, flags); |
554 | } |
555 | |
556 | static void |
557 | ioapic_addroute(struct pic *pic, struct cpu_info *ci, int pin, |
558 | int idtvec, int type) |
559 | { |
560 | struct ioapic_softc *sc = pic->pic_ioapic; |
561 | struct ioapic_pin *pp; |
562 | |
563 | pp = &sc->sc_pins[pin]; |
564 | pp->ip_type = type; |
565 | pp->ip_vector = idtvec; |
566 | pp->ip_cpu = ci; |
567 | apic_set_redir(sc, pin, idtvec, ci); |
568 | } |
569 | |
570 | static void |
571 | ioapic_delroute(struct pic *pic, struct cpu_info *ci, int pin, |
572 | int idtvec, int type) |
573 | { |
574 | |
575 | ioapic_hwmask(pic, pin); |
576 | } |
577 | |
578 | #ifdef DDB |
579 | void ioapic_dump(void); |
580 | void ioapic_dump_raw(void); |
581 | |
582 | void |
583 | ioapic_dump(void) |
584 | { |
585 | struct ioapic_softc *sc; |
586 | struct ioapic_pin *ip; |
587 | int p; |
588 | |
589 | for (sc = ioapics; sc != NULL; sc = sc->sc_next) { |
590 | for (p = 0; p < sc->sc_apic_sz; p++) { |
591 | ip = &sc->sc_pins[p]; |
592 | if (ip->ip_type != IST_NONE) |
593 | ioapic_print_redir(sc, "dump" , p); |
594 | } |
595 | } |
596 | } |
597 | |
598 | void |
599 | ioapic_dump_raw(void) |
600 | { |
601 | struct ioapic_softc *sc; |
602 | int i; |
603 | uint32_t reg; |
604 | |
605 | for (sc = ioapics; sc != NULL; sc = sc->sc_next) { |
606 | printf("Register dump of %s\n" , device_xname(sc->sc_dev)); |
607 | i = 0; |
608 | do { |
609 | if (i % 0x08 == 0) |
610 | printf("%02x" , i); |
611 | reg = ioapic_read(sc, i); |
612 | printf(" %08x" , (u_int)reg); |
613 | if (++i % 0x08 == 0) |
614 | printf("\n" ); |
615 | } while (i < 0x40); |
616 | } |
617 | } |
618 | #endif |
619 | |