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