xref: /netbsd/sys/arch/x86/x86/ioapic.c (revision 5aec2ac1)
1 /*	$NetBSD: ioapic.c,v 1.66 2022/10/06 06:42:46 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.66 2022/10/06 06:42:46 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 struct ioapic_softc *ioapics;	/* head of linked list */
116 int nioapics = 0;		/* number attached */
117 static int ioapic_vecbase;
118 
119 static inline u_long
ioapic_lock(struct ioapic_softc * sc)120 ioapic_lock(struct ioapic_softc *sc)
121 {
122 	u_long flags;
123 
124 	flags = x86_read_psl();
125 	x86_disable_intr();
126 	__cpu_simple_lock(&sc->sc_pic.pic_lock);
127 	return flags;
128 }
129 
130 static inline void
ioapic_unlock(struct ioapic_softc * sc,u_long flags)131 ioapic_unlock(struct ioapic_softc *sc, u_long flags)
132 {
133 	__cpu_simple_unlock(&sc->sc_pic.pic_lock);
134 	x86_write_psl(flags);
135 }
136 
137 #ifndef _IOAPIC_CUSTOM_RW
138 /*
139  * Register read/write routines.
140  */
141 static inline  uint32_t
ioapic_read_ul(struct ioapic_softc * sc,int regid)142 ioapic_read_ul(struct ioapic_softc *sc, int regid)
143 {
144 	uint32_t val;
145 
146 	*(sc->sc_reg) = regid;
147 	val = *sc->sc_data;
148 
149 	return val;
150 }
151 
152 static inline  void
ioapic_write_ul(struct ioapic_softc * sc,int regid,uint32_t val)153 ioapic_write_ul(struct ioapic_softc *sc, int regid, uint32_t val)
154 {
155 	*(sc->sc_reg) = regid;
156 	*(sc->sc_data) = val;
157 }
158 #endif /* !_IOAPIC_CUSTOM_RW */
159 
160 static inline uint32_t
ioapic_read(struct ioapic_softc * sc,int regid)161 ioapic_read(struct ioapic_softc *sc, int regid)
162 {
163 	uint32_t val;
164 	u_long flags;
165 
166 	flags = ioapic_lock(sc);
167 	val = ioapic_read_ul(sc, regid);
168 	ioapic_unlock(sc, flags);
169 	return val;
170 }
171 
172 static inline  void
ioapic_write(struct ioapic_softc * sc,int regid,int val)173 ioapic_write(struct ioapic_softc *sc, int regid, int val)
174 {
175 	u_long flags;
176 
177 	flags = ioapic_lock(sc);
178 	ioapic_write_ul(sc, regid, val);
179 	ioapic_unlock(sc, flags);
180 }
181 
182 struct ioapic_softc *
ioapic_find(int apicid)183 ioapic_find(int apicid)
184 {
185 	struct ioapic_softc *sc;
186 
187 	if (apicid == MPS_ALL_APICS) {	/* XXX mpbios-specific */
188 		/*
189 		 * XXX kludge for all-ioapics interrupt support
190 		 * on single ioapic systems
191 		 */
192 		if (nioapics <= 1)
193 			return ioapics;
194 		panic("unsupported: all-ioapics interrupt with >1 ioapic");
195 	}
196 
197 	for (sc = ioapics; sc != NULL; sc = sc->sc_next)
198 		if (sc->sc_pic.pic_apicid == apicid)
199 			return sc;
200 
201 	return NULL;
202 }
203 
204 /*
205  * For the case the I/O APICs were configured using ACPI, there must
206  * be an option to match global ACPI interrupts with APICs.
207  */
208 struct ioapic_softc *
ioapic_find_bybase(int vec)209 ioapic_find_bybase(int vec)
210 {
211 	struct ioapic_softc *sc;
212 
213 	for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
214 		if (vec >= sc->sc_pic.pic_vecbase &&
215 		    vec < (sc->sc_pic.pic_vecbase + sc->sc_apic_sz))
216 			return sc;
217 	}
218 
219 	return NULL;
220 }
221 
222 static inline void
ioapic_add(struct ioapic_softc * sc)223 ioapic_add(struct ioapic_softc *sc)
224 {
225 	struct ioapic_softc **scp;
226 
227 	sc->sc_next = NULL;
228 
229 	for (scp = &ioapics; *scp != NULL; scp = &(*scp)->sc_next)
230 		;
231 	*scp = sc;
232 	nioapics++;
233 }
234 
235 void
ioapic_print_redir(struct ioapic_softc * sc,const char * why,int pin)236 ioapic_print_redir(struct ioapic_softc *sc, const char *why, int pin)
237 {
238 	uint32_t redirlo = ioapic_read(sc, IOAPIC_REDLO(pin));
239 	uint32_t redirhi = ioapic_read(sc, IOAPIC_REDHI(pin));
240 
241 	apic_format_redir(device_xname(sc->sc_dev), why, pin,
242 	    APIC_VECTYPE_IOAPIC, redirhi, redirlo);
243 }
244 
245 CFATTACH_DECL_NEW(ioapic, sizeof(struct ioapic_softc),
246     ioapic_match, ioapic_attach, NULL, NULL);
247 
248 int
ioapic_match(device_t parent,cfdata_t match,void * aux)249 ioapic_match(device_t parent, cfdata_t match, void *aux)
250 {
251 
252 	return 1;
253 }
254 
255 /*
256  * can't use bus_space_xxx as we don't have a bus handle ...
257  */
258 void
ioapic_attach(device_t parent,device_t self,void * aux)259 ioapic_attach(device_t parent, device_t self, void *aux)
260 {
261 	struct ioapic_softc *sc = device_private(self);
262 	struct apic_attach_args *aaa = (struct apic_attach_args *)aux;
263 	int apic_id;
264 	uint32_t ver_sz;
265 	int i;
266 
267 	sc->sc_dev = self;
268 	sc->sc_flags = aaa->flags;
269 	sc->sc_pic.pic_apicid = aaa->apic_id;
270 	sc->sc_pic.pic_name = device_xname(self);
271 	sc->sc_pic.pic_ioapic = sc;
272 
273 	aprint_naive("\n");
274 
275 	if (ioapic_find(aaa->apic_id) != NULL) {
276 		aprint_error(": duplicate apic id (ignored)\n");
277 		return;
278 	}
279 
280 	aprint_verbose(": pa 0x%jx", (uintmax_t)aaa->apic_address);
281 #ifndef _IOAPIC_CUSTOM_RW
282 	{
283 	bus_space_handle_t bh;
284 
285 	if (x86_mem_add_mapping(aaa->apic_address, PAGE_SIZE, 0, &bh) != 0) {
286 		aprint_error(": map failed\n");
287 		return;
288 	}
289 	sc->sc_reg = (volatile uint32_t *)(bh + IOAPIC_REG);
290 	sc->sc_data = (volatile uint32_t *)(bh + IOAPIC_DATA);
291 	}
292 #endif
293 	sc->sc_pa = aaa->apic_address;
294 
295 	sc->sc_pic.pic_type = PIC_IOAPIC;
296 	__cpu_simple_lock_init(&sc->sc_pic.pic_lock);
297 	sc->sc_pic.pic_hwmask = ioapic_hwmask;
298 	sc->sc_pic.pic_hwunmask = ioapic_hwunmask;
299 	sc->sc_pic.pic_addroute = ioapic_addroute;
300 	sc->sc_pic.pic_delroute = ioapic_delroute;
301 	sc->sc_pic.pic_trymask = ioapic_trymask;
302 	sc->sc_pic.pic_edge_stubs = ioapic_edge_stubs;
303 	sc->sc_pic.pic_level_stubs = ioapic_level_stubs;
304 	sc->sc_pic.pic_intr_get_devname = x86_intr_get_devname;
305 	sc->sc_pic.pic_intr_get_assigned = x86_intr_get_assigned;
306 	sc->sc_pic.pic_intr_get_count = x86_intr_get_count;
307 
308 	apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK)
309 	    >> IOAPIC_ID_SHIFT;
310 	ver_sz = ioapic_read(sc, IOAPIC_VER);
311 
312 	if (ver_sz == 0xffffffff) {
313 		aprint_error(": failed to read version/size\n");
314 		goto out;
315 	}
316 
317 	ioapic_add(sc);
318 
319 	sc->sc_apic_vers = (ver_sz & IOAPIC_VER_MASK) >> IOAPIC_VER_SHIFT;
320 	sc->sc_apic_sz = (ver_sz & IOAPIC_MAX_MASK) >> IOAPIC_MAX_SHIFT;
321 	sc->sc_apic_sz++;
322 
323 	if (aaa->apic_vecbase != -1)
324 		sc->sc_pic.pic_vecbase = aaa->apic_vecbase;
325 	else {
326 		/*
327 		 * XXX this assumes ordering of ioapics in the table.
328 		 * Only needed for broken BIOS workaround (see mpbios.c)
329 		 */
330 		sc->sc_pic.pic_vecbase = ioapic_vecbase;
331 		ioapic_vecbase += sc->sc_apic_sz;
332 	}
333 
334 	if (mp_verbose) {
335 		printf(", %s mode",
336 		    aaa->flags & IOAPIC_PICMODE ? "PIC" : "virtual wire");
337 	}
338 
339 	aprint_verbose(", version 0x%x, %d pins", sc->sc_apic_vers,
340 	    sc->sc_apic_sz);
341 	aprint_normal("\n");
342 
343 	sc->sc_pins = malloc(sizeof(struct ioapic_pin) * sc->sc_apic_sz,
344 	    M_DEVBUF, M_WAITOK);
345 
346 	for (i = 0; i < sc->sc_apic_sz; i++) {
347 		uint32_t redlo, redhi;
348 
349 		sc->sc_pins[i].ip_next = NULL;
350 		sc->sc_pins[i].ip_map = NULL;
351 		sc->sc_pins[i].ip_vector = 0;
352 		sc->sc_pins[i].ip_type = IST_NONE;
353 
354 		/* Mask all pins by default. */
355 		redlo = IOAPIC_REDLO_MASK;
356 		/*
357 		 * ISA interrupts are connect to pin 0-15 and
358 		 * edge triggered on high, which is the default.
359 		 *
360 		 * Expect all other interrupts to be PCI-like
361 		 * level triggered on low.
362 		 */
363 		if (i >= 16)
364 			redlo |= IOAPIC_REDLO_LEVEL | IOAPIC_REDLO_ACTLO;
365 		redhi = (cpu_info_primary.ci_cpuid << IOAPIC_REDHI_DEST_SHIFT);
366 		ioapic_write(sc, IOAPIC_REDHI(i), redhi);
367 		ioapic_write(sc, IOAPIC_REDLO(i), redlo);
368 	}
369 
370 	/*
371 	 * In case the APIC is not initialized to the correct ID
372 	 * do it now.
373 	 * Maybe we should record the original ID for interrupt
374 	 * mapping later ...
375 	 */
376 	if (apic_id != sc->sc_pic.pic_apicid) {
377 		aprint_debug_dev(sc->sc_dev,
378 		    "apid is misconfigured (%d != %d)\n",
379 		    apic_id, sc->sc_pic.pic_apicid);
380 
381 		ioapic_write(sc, IOAPIC_ID,
382 		    (ioapic_read(sc, IOAPIC_ID) & ~IOAPIC_ID_MASK)
383 		    | (sc->sc_pic.pic_apicid << IOAPIC_ID_SHIFT));
384 
385 		apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK)
386 		    >> IOAPIC_ID_SHIFT;
387 
388 		if (apic_id != sc->sc_pic.pic_apicid)
389 			aprint_error_dev(sc->sc_dev,
390 			    "can't remap apid from %d to %d\n",
391 			    apic_id, sc->sc_pic.pic_apicid);
392 		else
393 			aprint_debug_dev(sc->sc_dev, "remapped to apic %d\n",
394 			    sc->sc_pic.pic_apicid);
395 	}
396 
397  out:
398 	if (!pmf_device_register(self, NULL, NULL))
399 		aprint_error_dev(self, "couldn't establish power handler\n");
400 
401 #if 0
402 	/* output of this was boring. */
403 	if (mp_verbose)
404 		for (i = 0; i < sc->sc_apic_sz; i++)
405 			ioapic_print_redir(sc, "boot", i);
406 #endif
407 }
408 
409 static void
apic_set_redir(struct ioapic_softc * sc,int pin,int idt_vec,struct cpu_info * ci)410 apic_set_redir(struct ioapic_softc *sc, int pin, int idt_vec,
411 	       struct cpu_info *ci)
412 {
413 	uint32_t redlo;
414 	uint32_t redhi;
415 	int delmode;
416 	struct ioapic_pin *pp;
417 	struct mp_intr_map *map;
418 
419 	pp = &sc->sc_pins[pin];
420 	map = pp->ip_map;
421 	redlo = map == NULL ? IOAPIC_REDLO_MASK : map->redir;
422 	redhi = 0;
423 	delmode = (redlo & IOAPIC_REDLO_DEL_MASK) >> IOAPIC_REDLO_DEL_SHIFT;
424 
425 	if (delmode == IOAPIC_REDLO_DEL_FIXED ||
426 	    delmode == IOAPIC_REDLO_DEL_LOPRI) {
427 		if (pp->ip_type == IST_NONE) {
428 			redlo |= IOAPIC_REDLO_MASK;
429 		} else {
430 			redhi = (ci->ci_cpuid << IOAPIC_REDHI_DEST_SHIFT);
431 			redlo |= (idt_vec & 0xff);
432 			redlo |= IOAPIC_REDLO_DEL_FIXED
433 			    << IOAPIC_REDLO_DEL_SHIFT;
434 			redlo &= ~IOAPIC_REDLO_DSTMOD;
435 
436 			/* XXX derive this bit from BIOS info */
437 			if (pp->ip_type == IST_LEVEL)
438 				redlo |= IOAPIC_REDLO_LEVEL;
439 			else
440 				redlo &= ~IOAPIC_REDLO_LEVEL;
441 			if ((map != NULL)
442 			    && ((map->flags & 3) == MPS_INTPO_DEF)) {
443 				if (pp->ip_type == IST_LEVEL)
444 					redlo |= IOAPIC_REDLO_ACTLO;
445 				else
446 					redlo &= ~IOAPIC_REDLO_ACTLO;
447 			}
448 		}
449 	}
450 	ioapic_write(sc, IOAPIC_REDHI(pin), redhi);
451 	ioapic_write(sc, IOAPIC_REDLO(pin), redlo);
452 	if (mp_verbose)
453 		ioapic_print_redir(sc, "int", pin);
454 }
455 
456 /*
457  * Throw the switch and enable interrupts..
458  */
459 
460 void
ioapic_enable(void)461 ioapic_enable(void)
462 {
463 	if (ioapics == NULL)
464 		return;
465 
466 	i8259_setmask(0xffff);
467 
468 	if (ioapics->sc_flags & IOAPIC_PICMODE) {
469 		aprint_debug_dev(ioapics->sc_dev,
470 				 "writing to IMCR to disable pics\n");
471 		outb(IMCR_ADDR, IMCR_REGISTER);
472 		outb(IMCR_DATA, IMCR_APIC);
473 	}
474 }
475 
476 void
ioapic_reenable(void)477 ioapic_reenable(void)
478 {
479 	int p, apic_id;
480 	struct ioapic_softc *sc;
481 
482 	if (ioapics == NULL)
483 		return;
484 
485 	aprint_normal("%s reenabling\n", device_xname(ioapics->sc_dev));
486 
487 	for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
488 		apic_id = (ioapic_read(sc, IOAPIC_ID) & IOAPIC_ID_MASK)
489 		    >> IOAPIC_ID_SHIFT;
490 		if (apic_id != sc->sc_pic.pic_apicid) {
491 			ioapic_write(sc, IOAPIC_ID,
492 			    (ioapic_read(sc, IOAPIC_ID) & ~IOAPIC_ID_MASK)
493 			    | (sc->sc_pic.pic_apicid << IOAPIC_ID_SHIFT));
494 		}
495 
496 		for (p = 0; p < sc->sc_apic_sz; p++)
497 			apic_set_redir(sc, p, sc->sc_pins[p].ip_vector,
498 				    sc->sc_pins[p].ip_cpu);
499 	}
500 
501 	ioapic_enable();
502 }
503 
504 void
ioapic_hwmask(struct pic * pic,int pin)505 ioapic_hwmask(struct pic *pic, int pin)
506 {
507 	uint32_t redlo;
508 	struct ioapic_softc *sc = pic->pic_ioapic;
509 	u_long flags;
510 
511 	flags = ioapic_lock(sc);
512 	redlo = ioapic_read_ul(sc, IOAPIC_REDLO(pin));
513 	redlo |= IOAPIC_REDLO_MASK;
514 	redlo &= ~IOAPIC_REDLO_RIRR;
515 	ioapic_write_ul(sc, IOAPIC_REDLO(pin), redlo);
516 	ioapic_unlock(sc, flags);
517 }
518 
519 bool
ioapic_trymask(struct pic * pic,int pin)520 ioapic_trymask(struct pic *pic, int pin)
521 {
522 	uint32_t redlo;
523 	struct ioapic_softc *sc = pic->pic_ioapic;
524 	u_long flags;
525 	bool rv;
526 
527 	/* Mask it. */
528 	flags = ioapic_lock(sc);
529 	redlo = ioapic_read_ul(sc, IOAPIC_REDLO(pin));
530 	redlo |= IOAPIC_REDLO_MASK;
531 	ioapic_write_ul(sc, IOAPIC_REDLO(pin), redlo);
532 
533 	/* If pending, unmask and abort. */
534 	redlo = ioapic_read_ul(sc, IOAPIC_REDLO(pin));
535 	if ((redlo & (IOAPIC_REDLO_RIRR | IOAPIC_REDLO_DELSTS)) != 0) {
536 		redlo &= ~IOAPIC_REDLO_MASK;
537 		ioapic_write_ul(sc, IOAPIC_REDLO(pin), redlo);
538 		rv = false;
539 	} else {
540 		rv = true;
541 	}
542 	ioapic_unlock(sc, flags);
543 	return rv;
544 }
545 
546 void
ioapic_hwunmask(struct pic * pic,int pin)547 ioapic_hwunmask(struct pic *pic, int pin)
548 {
549 	uint32_t redlo;
550 	struct ioapic_softc *sc = pic->pic_ioapic;
551 	u_long flags;
552 
553 	flags = ioapic_lock(sc);
554 	redlo = ioapic_read_ul(sc, IOAPIC_REDLO(pin));
555 	redlo &= ~(IOAPIC_REDLO_MASK | IOAPIC_REDLO_RIRR);
556 	ioapic_write_ul(sc, IOAPIC_REDLO(pin), redlo);
557 	ioapic_unlock(sc, flags);
558 }
559 
560 static void
ioapic_addroute(struct pic * pic,struct cpu_info * ci,int pin,int idtvec,int type)561 ioapic_addroute(struct pic *pic, struct cpu_info *ci, int pin,
562 		int idtvec, int type)
563 {
564 	struct ioapic_softc *sc = pic->pic_ioapic;
565 	struct ioapic_pin *pp;
566 
567 	pp = &sc->sc_pins[pin];
568 	pp->ip_type = type;
569 	pp->ip_vector = idtvec;
570 	pp->ip_cpu = ci;
571 	apic_set_redir(sc, pin, idtvec, ci);
572 }
573 
574 static void
ioapic_delroute(struct pic * pic,struct cpu_info * ci,int pin,int idtvec,int type)575 ioapic_delroute(struct pic *pic, struct cpu_info *ci, int pin,
576     int idtvec, int type)
577 {
578 
579 	ioapic_hwmask(pic, pin);
580 }
581 
582 #ifdef DDB
583 void ioapic_dump(void);
584 void ioapic_dump_raw(void);
585 
586 void
ioapic_dump(void)587 ioapic_dump(void)
588 {
589 	struct ioapic_softc *sc;
590 	struct ioapic_pin *ip;
591 	int p;
592 
593 	for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
594 		for (p = 0; p < sc->sc_apic_sz; p++) {
595 			ip = &sc->sc_pins[p];
596 			if (ip->ip_type != IST_NONE)
597 				ioapic_print_redir(sc, "dump", p);
598 		}
599 	}
600 }
601 
602 void
ioapic_dump_raw(void)603 ioapic_dump_raw(void)
604 {
605 	struct ioapic_softc *sc;
606 	int i;
607 	uint32_t reg;
608 
609 	for (sc = ioapics; sc != NULL; sc = sc->sc_next) {
610 		printf("Register dump of %s\n", device_xname(sc->sc_dev));
611 		i = 0;
612 		do {
613 			if (i % 0x08 == 0)
614 				printf("%02x", i);
615 			reg = ioapic_read(sc, i);
616 			printf(" %08x", (u_int)reg);
617 			if (++i % 0x08 == 0)
618 				printf("\n");
619 		} while (i < IOAPIC_REDTBL + (sc->sc_apic_sz * 2));
620 	}
621 }
622 #endif
623