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