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