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