1 /*- 2 * Copyright (C) 2008-2010 Nathan Whitehorn 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/module.h> 32 #include <sys/bus.h> 33 #include <sys/conf.h> 34 #include <sys/kernel.h> 35 #include <sys/pciio.h> 36 #include <sys/rman.h> 37 38 #include <dev/ofw/openfirm.h> 39 #include <dev/ofw/ofw_pci.h> 40 41 #include <dev/pci/pcivar.h> 42 #include <dev/pci/pcireg.h> 43 44 #include <machine/bus.h> 45 #include <machine/intr_machdep.h> 46 #include <machine/md_var.h> 47 #include <machine/openpicvar.h> 48 #include <machine/pio.h> 49 #include <machine/resource.h> 50 51 #include <dev/ofw/ofw_bus.h> 52 #include <dev/ofw/ofw_bus_subr.h> 53 #include <powerpc/ofw/ofw_pci.h> 54 55 #include <vm/vm.h> 56 #include <vm/pmap.h> 57 58 #include "pcib_if.h" 59 #include "pic_if.h" 60 61 /* 62 * IBM CPC9X5 Hypertransport Device interface. 63 */ 64 static int cpcht_probe(device_t); 65 static int cpcht_attach(device_t); 66 67 static void cpcht_configure_htbridge(device_t, phandle_t); 68 69 /* 70 * pcib interface. 71 */ 72 static u_int32_t cpcht_read_config(device_t, u_int, u_int, u_int, 73 u_int, int); 74 static void cpcht_write_config(device_t, u_int, u_int, u_int, 75 u_int, u_int32_t, int); 76 static int cpcht_route_interrupt(device_t, device_t, int); 77 static int cpcht_alloc_msi(device_t dev, device_t child, 78 int count, int maxcount, int *irqs); 79 static int cpcht_release_msi(device_t dev, device_t child, 80 int count, int *irqs); 81 static int cpcht_alloc_msix(device_t dev, device_t child, 82 int *irq); 83 static int cpcht_release_msix(device_t dev, device_t child, 84 int irq); 85 static int cpcht_map_msi(device_t dev, device_t child, 86 int irq, uint64_t *addr, uint32_t *data); 87 88 /* 89 * Driver methods. 90 */ 91 static device_method_t cpcht_methods[] = { 92 /* Device interface */ 93 DEVMETHOD(device_probe, cpcht_probe), 94 DEVMETHOD(device_attach, cpcht_attach), 95 96 /* pcib interface */ 97 DEVMETHOD(pcib_read_config, cpcht_read_config), 98 DEVMETHOD(pcib_write_config, cpcht_write_config), 99 DEVMETHOD(pcib_route_interrupt, cpcht_route_interrupt), 100 DEVMETHOD(pcib_alloc_msi, cpcht_alloc_msi), 101 DEVMETHOD(pcib_release_msi, cpcht_release_msi), 102 DEVMETHOD(pcib_alloc_msix, cpcht_alloc_msix), 103 DEVMETHOD(pcib_release_msix, cpcht_release_msix), 104 DEVMETHOD(pcib_map_msi, cpcht_map_msi), 105 106 DEVMETHOD_END 107 }; 108 109 struct cpcht_irq { 110 enum { 111 IRQ_NONE, IRQ_HT, IRQ_MSI, IRQ_INTERNAL 112 } irq_type; 113 114 int ht_source; 115 116 vm_offset_t ht_base; 117 vm_offset_t apple_eoi; 118 uint32_t eoi_data; 119 int edge; 120 }; 121 122 static struct cpcht_irq *cpcht_irqmap = NULL; 123 uint32_t cpcht_msipic = 0; 124 125 struct cpcht_softc { 126 struct ofw_pci_softc pci_sc; 127 vm_offset_t sc_data; 128 uint64_t sc_populated_slots; 129 130 struct cpcht_irq htirq_map[128]; 131 struct mtx htirq_mtx; 132 }; 133 134 static devclass_t cpcht_devclass; 135 DEFINE_CLASS_1(pcib, cpcht_driver, cpcht_methods, sizeof(struct cpcht_softc), 136 ofw_pci_driver); 137 DRIVER_MODULE(cpcht, nexus, cpcht_driver, cpcht_devclass, 0, 0); 138 139 #define CPCHT_IOPORT_BASE 0xf4000000UL /* Hardwired */ 140 #define CPCHT_IOPORT_SIZE 0x00400000UL 141 142 #define HTAPIC_REQUEST_EOI 0x20 143 #define HTAPIC_TRIGGER_LEVEL 0x02 144 #define HTAPIC_MASK 0x01 145 146 static int 147 cpcht_probe(device_t dev) 148 { 149 const char *type, *compatible; 150 151 type = ofw_bus_get_type(dev); 152 compatible = ofw_bus_get_compat(dev); 153 154 if (type == NULL || compatible == NULL) 155 return (ENXIO); 156 157 if (strcmp(type, "ht") != 0) 158 return (ENXIO); 159 160 if (strcmp(compatible, "u3-ht") != 0) 161 return (ENXIO); 162 163 device_set_desc(dev, "IBM CPC9X5 HyperTransport Tunnel"); 164 return (0); 165 } 166 167 static int 168 cpcht_attach(device_t dev) 169 { 170 struct cpcht_softc *sc; 171 phandle_t node, child; 172 u_int32_t reg[3]; 173 int i; 174 175 node = ofw_bus_get_node(dev); 176 sc = device_get_softc(dev); 177 178 if (OF_getprop(node, "reg", reg, sizeof(reg)) < 12) 179 return (ENXIO); 180 181 if (OF_getproplen(node, "ranges") <= 0) 182 sc->pci_sc.sc_quirks = OFW_PCI_QUIRK_RANGES_ON_CHILDREN; 183 sc->sc_populated_slots = 0; 184 sc->sc_data = (vm_offset_t)pmap_mapdev(reg[1], reg[2]); 185 186 /* 187 * Set up the resource manager and the HT->MPIC mapping. For cpcht, 188 * the ranges are properties of the child bridges, and this is also 189 * where we get the HT interrupts properties. 190 */ 191 192 #if 0 193 /* I/O port mappings are usually not in the device tree */ 194 rman_manage_region(&sc->pci_sc.sc_io_rman, 0, CPCHT_IOPORT_SIZE - 1); 195 #endif 196 197 bzero(sc->htirq_map, sizeof(sc->htirq_map)); 198 mtx_init(&sc->htirq_mtx, "cpcht irq", NULL, MTX_DEF); 199 for (i = 0; i < 8; i++) 200 sc->htirq_map[i].irq_type = IRQ_INTERNAL; 201 for (child = OF_child(node); child != 0; child = OF_peer(child)) 202 cpcht_configure_htbridge(dev, child); 203 204 /* Now make the mapping table available to the MPIC */ 205 cpcht_irqmap = sc->htirq_map; 206 207 return (ofw_pci_attach(dev)); 208 } 209 210 static void 211 cpcht_configure_htbridge(device_t dev, phandle_t child) 212 { 213 struct cpcht_softc *sc; 214 struct ofw_pci_register pcir; 215 int ptr, nextptr; 216 uint32_t vend, val; 217 int i, nirq, irq; 218 u_int b, f, s; 219 220 sc = device_get_softc(dev); 221 if (OF_getprop(child, "reg", &pcir, sizeof(pcir)) == -1) 222 return; 223 224 b = OFW_PCI_PHYS_HI_BUS(pcir.phys_hi); 225 s = OFW_PCI_PHYS_HI_DEVICE(pcir.phys_hi); 226 f = OFW_PCI_PHYS_HI_FUNCTION(pcir.phys_hi); 227 228 /* 229 * Mark this slot is populated. The remote south bridge does 230 * not like us talking to unpopulated slots on the root bus. 231 */ 232 sc->sc_populated_slots |= (1 << s); 233 234 /* 235 * Next build up any HT->MPIC mappings for this sub-bus. One would 236 * naively hope that enabling, disabling, and EOIing interrupts would 237 * cause the appropriate HT bus transactions to that effect. This is 238 * not the case. 239 * 240 * Instead, we have to muck about on the HT peer's root PCI bridges, 241 * figure out what interrupts they send, enable them, and cache 242 * the location of their WaitForEOI registers so that we can 243 * send EOIs later. 244 */ 245 246 /* All the devices we are interested in have caps */ 247 if (!(PCIB_READ_CONFIG(dev, b, s, f, PCIR_STATUS, 2) 248 & PCIM_STATUS_CAPPRESENT)) 249 return; 250 251 nextptr = PCIB_READ_CONFIG(dev, b, s, f, PCIR_CAP_PTR, 1); 252 while (nextptr != 0) { 253 ptr = nextptr; 254 nextptr = PCIB_READ_CONFIG(dev, b, s, f, 255 ptr + PCICAP_NEXTPTR, 1); 256 257 /* Find the HT IRQ capabilities */ 258 if (PCIB_READ_CONFIG(dev, b, s, f, 259 ptr + PCICAP_ID, 1) != PCIY_HT) 260 continue; 261 262 val = PCIB_READ_CONFIG(dev, b, s, f, ptr + PCIR_HT_COMMAND, 2); 263 if ((val & PCIM_HTCMD_CAP_MASK) != PCIM_HTCAP_INTERRUPT) 264 continue; 265 266 /* Ask for the IRQ count */ 267 PCIB_WRITE_CONFIG(dev, b, s, f, ptr + PCIR_HT_COMMAND, 0x1, 1); 268 nirq = PCIB_READ_CONFIG(dev, b, s, f, ptr + 4, 4); 269 nirq = ((nirq >> 16) & 0xff) + 1; 270 271 device_printf(dev, "%d HT IRQs on device %d.%d\n", nirq, s, f); 272 273 for (i = 0; i < nirq; i++) { 274 PCIB_WRITE_CONFIG(dev, b, s, f, 275 ptr + PCIR_HT_COMMAND, 0x10 + (i << 1), 1); 276 irq = PCIB_READ_CONFIG(dev, b, s, f, ptr + 4, 4); 277 278 /* 279 * Mask this interrupt for now. 280 */ 281 PCIB_WRITE_CONFIG(dev, b, s, f, ptr + 4, 282 irq | HTAPIC_MASK, 4); 283 irq = (irq >> 16) & 0xff; 284 285 sc->htirq_map[irq].irq_type = IRQ_HT; 286 sc->htirq_map[irq].ht_source = i; 287 sc->htirq_map[irq].ht_base = sc->sc_data + 288 (((((s & 0x1f) << 3) | (f & 0x07)) << 8) | (ptr)); 289 290 PCIB_WRITE_CONFIG(dev, b, s, f, 291 ptr + PCIR_HT_COMMAND, 0x11 + (i << 1), 1); 292 sc->htirq_map[irq].eoi_data = 293 PCIB_READ_CONFIG(dev, b, s, f, ptr + 4, 4) | 294 0x80000000; 295 296 /* 297 * Apple uses a non-compliant IO/APIC that differs 298 * in how we signal EOIs. Check if this device was 299 * made by Apple, and act accordingly. 300 */ 301 vend = PCIB_READ_CONFIG(dev, b, s, f, 302 PCIR_DEVVENDOR, 4); 303 if ((vend & 0xffff) == 0x106b) 304 sc->htirq_map[irq].apple_eoi = 305 (sc->htirq_map[irq].ht_base - ptr) + 0x60; 306 } 307 } 308 } 309 310 static u_int32_t 311 cpcht_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, 312 int width) 313 { 314 struct cpcht_softc *sc; 315 vm_offset_t caoff; 316 317 sc = device_get_softc(dev); 318 caoff = sc->sc_data + 319 (((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg); 320 321 if (bus == 0 && (!(sc->sc_populated_slots & (1 << slot)) || func > 0)) 322 return (0xffffffff); 323 324 if (bus > 0) 325 caoff += 0x01000000UL + (bus << 16); 326 327 switch (width) { 328 case 1: 329 return (in8rb(caoff)); 330 break; 331 case 2: 332 return (in16rb(caoff)); 333 break; 334 case 4: 335 return (in32rb(caoff)); 336 break; 337 } 338 339 return (0xffffffff); 340 } 341 342 static void 343 cpcht_write_config(device_t dev, u_int bus, u_int slot, u_int func, 344 u_int reg, u_int32_t val, int width) 345 { 346 struct cpcht_softc *sc; 347 vm_offset_t caoff; 348 349 sc = device_get_softc(dev); 350 caoff = sc->sc_data + 351 (((((slot & 0x1f) << 3) | (func & 0x07)) << 8) | reg); 352 353 if (bus == 0 && (!(sc->sc_populated_slots & (1 << slot)) || func > 0)) 354 return; 355 356 if (bus > 0) 357 caoff += 0x01000000UL + (bus << 16); 358 359 switch (width) { 360 case 1: 361 out8rb(caoff, val); 362 break; 363 case 2: 364 out16rb(caoff, val); 365 break; 366 case 4: 367 out32rb(caoff, val); 368 break; 369 } 370 } 371 372 static int 373 cpcht_route_interrupt(device_t bus, device_t dev, int pin) 374 { 375 return (pin); 376 } 377 378 static int 379 cpcht_alloc_msi(device_t dev, device_t child, int count, int maxcount, 380 int *irqs) 381 { 382 struct cpcht_softc *sc; 383 int i, j; 384 385 sc = device_get_softc(dev); 386 j = 0; 387 388 /* Bail if no MSI PIC yet */ 389 if (cpcht_msipic == 0) 390 return (ENXIO); 391 392 mtx_lock(&sc->htirq_mtx); 393 for (i = 8; i < 124 - count; i++) { 394 for (j = 0; j < count; j++) { 395 if (sc->htirq_map[i+j].irq_type != IRQ_NONE) 396 break; 397 } 398 if (j == count) 399 break; 400 401 i += j; /* We know there isn't a large enough run */ 402 } 403 404 if (j != count) { 405 mtx_unlock(&sc->htirq_mtx); 406 return (ENXIO); 407 } 408 409 for (j = 0; j < count; j++) { 410 irqs[j] = MAP_IRQ(cpcht_msipic, i+j); 411 sc->htirq_map[i+j].irq_type = IRQ_MSI; 412 } 413 mtx_unlock(&sc->htirq_mtx); 414 415 return (0); 416 } 417 418 static int 419 cpcht_release_msi(device_t dev, device_t child, int count, int *irqs) 420 { 421 struct cpcht_softc *sc; 422 int i; 423 424 sc = device_get_softc(dev); 425 426 mtx_lock(&sc->htirq_mtx); 427 for (i = 0; i < count; i++) 428 sc->htirq_map[irqs[i] & 0xff].irq_type = IRQ_NONE; 429 mtx_unlock(&sc->htirq_mtx); 430 431 return (0); 432 } 433 434 static int 435 cpcht_alloc_msix(device_t dev, device_t child, int *irq) 436 { 437 struct cpcht_softc *sc; 438 int i; 439 440 sc = device_get_softc(dev); 441 442 /* Bail if no MSI PIC yet */ 443 if (cpcht_msipic == 0) 444 return (ENXIO); 445 446 mtx_lock(&sc->htirq_mtx); 447 for (i = 8; i < 124; i++) { 448 if (sc->htirq_map[i].irq_type == IRQ_NONE) { 449 sc->htirq_map[i].irq_type = IRQ_MSI; 450 *irq = MAP_IRQ(cpcht_msipic, i); 451 452 mtx_unlock(&sc->htirq_mtx); 453 return (0); 454 } 455 } 456 mtx_unlock(&sc->htirq_mtx); 457 458 return (ENXIO); 459 } 460 461 static int 462 cpcht_release_msix(device_t dev, device_t child, int irq) 463 { 464 struct cpcht_softc *sc; 465 466 sc = device_get_softc(dev); 467 468 mtx_lock(&sc->htirq_mtx); 469 sc->htirq_map[irq & 0xff].irq_type = IRQ_NONE; 470 mtx_unlock(&sc->htirq_mtx); 471 472 return (0); 473 } 474 475 static int 476 cpcht_map_msi(device_t dev, device_t child, int irq, uint64_t *addr, 477 uint32_t *data) 478 { 479 device_t pcib; 480 struct pci_devinfo *dinfo; 481 struct pcicfg_ht *ht = NULL; 482 483 for (pcib = child; pcib != dev; pcib = 484 device_get_parent(device_get_parent(pcib))) { 485 dinfo = device_get_ivars(pcib); 486 ht = &dinfo->cfg.ht; 487 488 if (ht == NULL) 489 continue; 490 } 491 492 if (ht == NULL) 493 return (ENXIO); 494 495 *addr = ht->ht_msiaddr; 496 *data = irq & 0xff; 497 498 return (0); 499 } 500 501 /* 502 * Driver for the integrated MPIC on U3/U4 (CPC925/CPC945) 503 */ 504 505 static int openpic_cpcht_probe(device_t); 506 static int openpic_cpcht_attach(device_t); 507 static void openpic_cpcht_config(device_t, u_int irq, 508 enum intr_trigger trig, enum intr_polarity pol); 509 static void openpic_cpcht_enable(device_t, u_int irq, u_int vector); 510 static void openpic_cpcht_unmask(device_t, u_int irq); 511 static void openpic_cpcht_eoi(device_t, u_int irq); 512 513 static device_method_t openpic_cpcht_methods[] = { 514 /* Device interface */ 515 DEVMETHOD(device_probe, openpic_cpcht_probe), 516 DEVMETHOD(device_attach, openpic_cpcht_attach), 517 518 /* PIC interface */ 519 DEVMETHOD(pic_bind, openpic_bind), 520 DEVMETHOD(pic_config, openpic_cpcht_config), 521 DEVMETHOD(pic_dispatch, openpic_dispatch), 522 DEVMETHOD(pic_enable, openpic_cpcht_enable), 523 DEVMETHOD(pic_eoi, openpic_cpcht_eoi), 524 DEVMETHOD(pic_ipi, openpic_ipi), 525 DEVMETHOD(pic_mask, openpic_mask), 526 DEVMETHOD(pic_unmask, openpic_cpcht_unmask), 527 528 { 0, 0 }, 529 }; 530 531 struct openpic_cpcht_softc { 532 struct openpic_softc sc_openpic; 533 534 struct mtx sc_ht_mtx; 535 }; 536 537 static driver_t openpic_cpcht_driver = { 538 "htpic", 539 openpic_cpcht_methods, 540 sizeof(struct openpic_cpcht_softc), 541 }; 542 543 DRIVER_MODULE(openpic, unin, openpic_cpcht_driver, openpic_devclass, 0, 0); 544 545 static int 546 openpic_cpcht_probe(device_t dev) 547 { 548 const char *type = ofw_bus_get_type(dev); 549 550 if (strcmp(type, "open-pic") != 0) 551 return (ENXIO); 552 553 device_set_desc(dev, OPENPIC_DEVSTR); 554 return (0); 555 } 556 557 static int 558 openpic_cpcht_attach(device_t dev) 559 { 560 struct openpic_cpcht_softc *sc; 561 phandle_t node; 562 int err, irq; 563 564 node = ofw_bus_get_node(dev); 565 err = openpic_common_attach(dev, node); 566 if (err != 0) 567 return (err); 568 569 /* 570 * The HT APIC stuff is not thread-safe, so we need a mutex to 571 * protect it. 572 */ 573 sc = device_get_softc(dev); 574 mtx_init(&sc->sc_ht_mtx, "htpic", NULL, MTX_SPIN); 575 576 /* 577 * Interrupts 0-3 are internally sourced and are level triggered 578 * active low. Interrupts 4-123 are connected to a pulse generator 579 * and should be programmed as edge triggered low-to-high. 580 * 581 * IBM CPC945 Manual, Section 9.3. 582 */ 583 584 for (irq = 0; irq < 4; irq++) 585 openpic_config(dev, irq, INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW); 586 for (irq = 4; irq < 124; irq++) 587 openpic_config(dev, irq, INTR_TRIGGER_EDGE, INTR_POLARITY_LOW); 588 589 /* 590 * Use this PIC for MSI only if it is the root PIC. This may not 591 * be necessary, but Linux does it, and I cannot find any U3 machines 592 * with MSI devices to test. 593 */ 594 if (dev == root_pic) 595 cpcht_msipic = node; 596 597 return (0); 598 } 599 600 static void 601 openpic_cpcht_config(device_t dev, u_int irq, enum intr_trigger trig, 602 enum intr_polarity pol) 603 { 604 struct openpic_cpcht_softc *sc; 605 uint32_t ht_irq; 606 607 /* 608 * The interrupt settings for the MPIC are completely determined 609 * by the internal wiring in the northbridge. Real changes to these 610 * settings need to be negotiated with the remote IO-APIC on the HT 611 * link. 612 */ 613 614 sc = device_get_softc(dev); 615 616 if (cpcht_irqmap != NULL && irq < 128 && 617 cpcht_irqmap[irq].ht_base > 0 && !cpcht_irqmap[irq].edge) { 618 mtx_lock_spin(&sc->sc_ht_mtx); 619 620 /* Program the data port */ 621 out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND, 622 0x10 + (cpcht_irqmap[irq].ht_source << 1)); 623 624 /* Grab the IRQ config register */ 625 ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4); 626 627 /* Mask the IRQ while we fiddle settings */ 628 out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq | HTAPIC_MASK); 629 630 /* Program the interrupt sense */ 631 ht_irq &= ~(HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI); 632 if (trig == INTR_TRIGGER_EDGE) { 633 cpcht_irqmap[irq].edge = 1; 634 } else { 635 cpcht_irqmap[irq].edge = 0; 636 ht_irq |= HTAPIC_TRIGGER_LEVEL | HTAPIC_REQUEST_EOI; 637 } 638 out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq); 639 640 mtx_unlock_spin(&sc->sc_ht_mtx); 641 } 642 } 643 644 static void 645 openpic_cpcht_enable(device_t dev, u_int irq, u_int vec) 646 { 647 struct openpic_cpcht_softc *sc; 648 uint32_t ht_irq; 649 650 openpic_enable(dev, irq, vec); 651 652 sc = device_get_softc(dev); 653 654 if (cpcht_irqmap != NULL && irq < 128 && 655 cpcht_irqmap[irq].ht_base > 0) { 656 mtx_lock_spin(&sc->sc_ht_mtx); 657 658 /* Program the data port */ 659 out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND, 660 0x10 + (cpcht_irqmap[irq].ht_source << 1)); 661 662 /* Unmask the interrupt */ 663 ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4); 664 ht_irq &= ~HTAPIC_MASK; 665 out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq); 666 667 mtx_unlock_spin(&sc->sc_ht_mtx); 668 } 669 670 openpic_cpcht_eoi(dev, irq); 671 } 672 673 static void 674 openpic_cpcht_unmask(device_t dev, u_int irq) 675 { 676 struct openpic_cpcht_softc *sc; 677 uint32_t ht_irq; 678 679 openpic_unmask(dev, irq); 680 681 sc = device_get_softc(dev); 682 683 if (cpcht_irqmap != NULL && irq < 128 && 684 cpcht_irqmap[irq].ht_base > 0) { 685 mtx_lock_spin(&sc->sc_ht_mtx); 686 687 /* Program the data port */ 688 out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND, 689 0x10 + (cpcht_irqmap[irq].ht_source << 1)); 690 691 /* Unmask the interrupt */ 692 ht_irq = in32rb(cpcht_irqmap[irq].ht_base + 4); 693 ht_irq &= ~HTAPIC_MASK; 694 out32rb(cpcht_irqmap[irq].ht_base + 4, ht_irq); 695 696 mtx_unlock_spin(&sc->sc_ht_mtx); 697 } 698 699 openpic_cpcht_eoi(dev, irq); 700 } 701 702 static void 703 openpic_cpcht_eoi(device_t dev, u_int irq) 704 { 705 struct openpic_cpcht_softc *sc; 706 uint32_t off, mask; 707 708 if (irq == 255) 709 return; 710 711 sc = device_get_softc(dev); 712 713 if (cpcht_irqmap != NULL && irq < 128 && 714 cpcht_irqmap[irq].ht_base > 0 && !cpcht_irqmap[irq].edge) { 715 /* If this is an HT IRQ, acknowledge it at the remote APIC */ 716 717 if (cpcht_irqmap[irq].apple_eoi) { 718 off = (cpcht_irqmap[irq].ht_source >> 3) & ~3; 719 mask = 1 << (cpcht_irqmap[irq].ht_source & 0x1f); 720 out32rb(cpcht_irqmap[irq].apple_eoi + off, mask); 721 } else { 722 mtx_lock_spin(&sc->sc_ht_mtx); 723 724 out8rb(cpcht_irqmap[irq].ht_base + PCIR_HT_COMMAND, 725 0x11 + (cpcht_irqmap[irq].ht_source << 1)); 726 out32rb(cpcht_irqmap[irq].ht_base + 4, 727 cpcht_irqmap[irq].eoi_data); 728 729 mtx_unlock_spin(&sc->sc_ht_mtx); 730 } 731 } 732 733 openpic_eoi(dev, irq); 734 } 735