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