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