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