Home | History | Annotate | Line # | Download | only in x86
      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
    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
    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
    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
    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
    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
    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 *
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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