1 /* $OpenBSD: ppb.c,v 1.29 2009/04/01 19:51:10 kettenis Exp $ */ 2 /* $NetBSD: ppb.c,v 1.16 1997/06/06 23:48:05 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1996 Christopher G. Demetriou. 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christopher G. Demetriou 18 * for the NetBSD Project. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/device.h> 38 #include <sys/proc.h> 39 #include <sys/workq.h> 40 41 #include <dev/pci/pcireg.h> 42 #include <dev/pci/pcivar.h> 43 #include <dev/pci/pcidevs.h> 44 #include <dev/pci/ppbreg.h> 45 46 struct ppb_softc { 47 struct device sc_dev; /* generic device glue */ 48 pci_chipset_tag_t sc_pc; /* our PCI chipset... */ 49 pcitag_t sc_tag; /* ...and tag. */ 50 pci_intr_handle_t sc_ih[4]; 51 void *sc_intrhand; 52 struct device *sc_psc; 53 int sc_cap_off; 54 struct timeout sc_to; 55 }; 56 57 int ppbmatch(struct device *, void *, void *); 58 void ppbattach(struct device *, struct device *, void *); 59 int ppbdetach(struct device *self, int flags); 60 61 struct cfattach ppb_ca = { 62 sizeof(struct ppb_softc), ppbmatch, ppbattach, ppbdetach 63 }; 64 65 struct cfdriver ppb_cd = { 66 NULL, "ppb", DV_DULL 67 }; 68 69 int ppb_intr(void *); 70 void ppb_hotplug_insert(void *, void *); 71 void ppb_hotplug_insert_finish(void *); 72 int ppb_hotplug_fixup(struct pci_attach_args *); 73 int ppb_hotplug_fixup_type0(pci_chipset_tag_t, pcitag_t, pcitag_t); 74 int ppb_hotplug_fixup_type1(pci_chipset_tag_t, pcitag_t, pcitag_t); 75 void ppb_hotplug_rescan(void *, void *); 76 void ppb_hotplug_remove(void *, void *); 77 int ppbprint(void *, const char *pnp); 78 79 int 80 ppbmatch(struct device *parent, void *match, void *aux) 81 { 82 struct pci_attach_args *pa = aux; 83 84 /* 85 * This device is mislabeled. It is not a PCI bridge. 86 */ 87 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_VIATECH && 88 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT82C586_PWR) 89 return (0); 90 /* 91 * Check the ID register to see that it's a PCI bridge. 92 * If it is, we assume that we can deal with it; it _should_ 93 * work in a standardized way... 94 */ 95 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE && 96 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_PCI) 97 return (1); 98 99 return (0); 100 } 101 102 void 103 ppbattach(struct device *parent, struct device *self, void *aux) 104 { 105 struct ppb_softc *sc = (struct ppb_softc *)self; 106 struct pci_attach_args *pa = aux; 107 pci_chipset_tag_t pc = pa->pa_pc; 108 struct pcibus_attach_args pba; 109 pci_intr_handle_t ih; 110 pcireg_t busdata, reg; 111 int pin; 112 113 sc->sc_pc = pc; 114 sc->sc_tag = pa->pa_tag; 115 116 busdata = pci_conf_read(pc, pa->pa_tag, PPB_REG_BUSINFO); 117 118 if (PPB_BUSINFO_SECONDARY(busdata) == 0) { 119 printf(": not configured by system firmware\n"); 120 return; 121 } 122 123 #if 0 124 /* 125 * XXX can't do this, because we're not given our bus number 126 * (we shouldn't need it), and because we've no way to 127 * decompose our tag. 128 */ 129 /* sanity check. */ 130 if (pa->pa_bus != PPB_BUSINFO_PRIMARY(busdata)) 131 panic("ppbattach: bus in tag (%d) != bus in reg (%d)", 132 pa->pa_bus, PPB_BUSINFO_PRIMARY(busdata)); 133 #endif 134 135 /* Check for PCI Express capabilities and setup hotplug support. */ 136 if (pci_get_capability(pc, pa->pa_tag, PCI_CAP_PCIEXPRESS, 137 &sc->sc_cap_off, ®) && (reg & PCI_PCIE_XCAP_SI)) { 138 if (pci_intr_map(pa, &ih) == 0) 139 sc->sc_intrhand = pci_intr_establish(pc, ih, IPL_TTY, 140 ppb_intr, sc, self->dv_xname); 141 142 if (sc->sc_intrhand) { 143 printf(": %s", pci_intr_string(pc, ih)); 144 145 /* Enable hotplug interrupt. */ 146 reg = pci_conf_read(pc, pa->pa_tag, 147 sc->sc_cap_off + PCI_PCIE_SLCSR); 148 reg |= (PCI_PCIE_SLCSR_HPE | PCI_PCIE_SLCSR_PDE); 149 pci_conf_write(pc, pa->pa_tag, 150 sc->sc_cap_off + PCI_PCIE_SLCSR, reg); 151 152 timeout_set(&sc->sc_to, ppb_hotplug_insert_finish, sc); 153 } 154 } 155 156 printf("\n"); 157 158 for (pin = PCI_INTERRUPT_PIN_A; pin <= PCI_INTERRUPT_PIN_D; pin++) { 159 pa->pa_intrpin = pa->pa_rawintrpin = pin; 160 pa->pa_intrline = 0; 161 pci_intr_map(pa, &sc->sc_ih[pin - PCI_INTERRUPT_PIN_A]); 162 } 163 164 /* 165 * Attach the PCI bus that hangs off of it. 166 * 167 * XXX Don't pass-through Memory Read Multiple. Should we? 168 * XXX Consult the spec... 169 */ 170 bzero(&pba, sizeof(pba)); 171 pba.pba_busname = "pci"; 172 pba.pba_iot = pa->pa_iot; 173 pba.pba_memt = pa->pa_memt; 174 pba.pba_dmat = pa->pa_dmat; 175 pba.pba_pc = pc; 176 #if 0 177 pba.pba_flags = pa->pa_flags & ~PCI_FLAGS_MRM_OKAY; 178 #endif 179 pba.pba_domain = pa->pa_domain; 180 pba.pba_bus = PPB_BUSINFO_SECONDARY(busdata); 181 pba.pba_bridgeih = sc->sc_ih; 182 pba.pba_bridgetag = &sc->sc_tag; 183 pba.pba_intrswiz = pa->pa_intrswiz; 184 pba.pba_intrtag = pa->pa_intrtag; 185 186 sc->sc_psc = config_found(self, &pba, ppbprint); 187 } 188 189 int 190 ppbdetach(struct device *self, int flags) 191 { 192 struct ppb_softc *sc = (struct ppb_softc *)self; 193 194 if (sc->sc_intrhand) 195 pci_intr_disestablish(sc->sc_pc, sc->sc_intrhand); 196 197 return config_detach_children(self, flags); 198 } 199 200 int 201 ppb_intr(void *arg) 202 { 203 struct ppb_softc *sc = arg; 204 pcireg_t reg; 205 206 /* 207 * XXX ignore hotplug events while in autoconf. On some 208 * machines with onboard re(4), we gat a bogus hotplug remove 209 * event when we reset that device. Ignoring that event makes 210 * sure we will not try to forcibly detach re(4) when it isn't 211 * ready to deal with that. 212 */ 213 if (cold) 214 return (0); 215 216 reg = pci_conf_read(sc->sc_pc, sc->sc_tag, 217 sc->sc_cap_off + PCI_PCIE_SLCSR); 218 if (reg & PCI_PCIE_SLCSR_PDC) { 219 if (reg & PCI_PCIE_SLCSR_PDS) 220 workq_add_task(NULL, 0, ppb_hotplug_insert, sc, NULL); 221 else 222 workq_add_task(NULL, 0, ppb_hotplug_remove, sc, NULL); 223 224 /* Clear interrupts. */ 225 pci_conf_write(sc->sc_pc, sc->sc_tag, 226 sc->sc_cap_off + PCI_PCIE_SLCSR, reg); 227 return (1); 228 } 229 230 return (0); 231 } 232 233 #ifdef PCI_MACHDEP_ENUMERATE_BUS 234 #define pci_enumerate_bus PCI_MACHDEP_ENUMERATE_BUS 235 #else 236 extern int pci_enumerate_bus(struct pci_softc *, 237 int (*)(struct pci_attach_args *), struct pci_attach_args *); 238 #endif 239 240 void 241 ppb_hotplug_insert(void *arg1, void *arg2) 242 { 243 struct ppb_softc *sc = arg1; 244 struct pci_softc *psc = (struct pci_softc *)sc->sc_psc; 245 246 if (!LIST_EMPTY(&psc->sc_devs)) 247 return; 248 249 /* XXX Powerup the card. */ 250 251 /* XXX Turn on LEDs. */ 252 253 /* Wait a second for things to settle. */ 254 timeout_add_sec(&sc->sc_to, 1); 255 } 256 257 void 258 ppb_hotplug_insert_finish(void *arg) 259 { 260 workq_add_task(NULL, 0, ppb_hotplug_rescan, arg, NULL); 261 } 262 263 int 264 ppb_hotplug_fixup(struct pci_attach_args *pa) 265 { 266 pcireg_t bhlcr; 267 268 bhlcr = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG); 269 switch (PCI_HDRTYPE_TYPE(bhlcr)) { 270 case 0: 271 return ppb_hotplug_fixup_type0(pa->pa_pc, 272 pa->pa_tag, *pa->pa_bridgetag); 273 case 1: 274 return ppb_hotplug_fixup_type1(pa->pa_pc, 275 pa->pa_tag, *pa->pa_bridgetag); 276 default: 277 return (0); 278 } 279 } 280 281 int 282 ppb_hotplug_fixup_type0(pci_chipset_tag_t pc, pcitag_t tag, pcitag_t bridgetag) 283 { 284 pcireg_t blr, type, intr; 285 int reg, line; 286 bus_addr_t base, io_base, io_limit, mem_base, mem_limit; 287 bus_size_t size, io_size, mem_size; 288 289 /* 290 * The code below assumes that the address ranges on our 291 * parent PCI Express bridge are really available and don't 292 * overlap with other devices in the system. 293 */ 294 295 /* Figure out the I/O address range of the bridge. */ 296 blr = pci_conf_read(pc, bridgetag, PPB_REG_IOSTATUS); 297 io_base = (blr & 0x000000f0) << 8; 298 io_limit = (blr & 0x000f000) | 0x00000fff; 299 if (io_limit > io_base) 300 io_size = (io_limit - io_base + 1); 301 else 302 io_size = 0; 303 304 /* Figure out the memory mapped I/O address range of the bridge. */ 305 blr = pci_conf_read(pc, bridgetag, PPB_REG_MEM); 306 mem_base = (blr & 0x0000fff0) << 16; 307 mem_limit = (blr & 0xffff0000) | 0x000fffff; 308 if (mem_limit > mem_base) 309 mem_size = (mem_limit - mem_base + 1); 310 else 311 mem_size = 0; 312 313 /* Assign resources to the Base Address Registers. */ 314 for (reg = PCI_MAPREG_START; reg < PCI_MAPREG_END; reg += 4) { 315 if (!pci_mapreg_probe(pc, tag, reg, &type)) 316 continue; 317 318 if (pci_mapreg_info(pc, tag, reg, type, &base, &size, NULL)) 319 continue; 320 321 if (base != 0) 322 continue; 323 324 switch (type) { 325 case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: 326 case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: 327 base = roundup(mem_base, size); 328 size += base - mem_base; 329 if (size > mem_size) 330 continue; 331 pci_conf_write(pc, tag, reg, base); 332 mem_base += size; 333 mem_size -= size; 334 break; 335 case PCI_MAPREG_TYPE_IO: 336 base = roundup(io_base, size); 337 size += base - io_base; 338 if (size > io_size) 339 continue; 340 pci_conf_write(pc, tag, reg, base); 341 io_base += size; 342 io_size -= size; 343 break; 344 default: 345 break; 346 } 347 348 if (type & PCI_MAPREG_MEM_TYPE_64BIT) 349 reg += 4; 350 } 351 352 /* 353 * Fill in the interrupt line for platforms that need it. 354 * 355 * XXX We assume that the interrupt line matches the line used 356 * by the PCI Express bridge. This may not be true. 357 */ 358 intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); 359 if (PCI_INTERRUPT_PIN(intr) != PCI_INTERRUPT_PIN_NONE && 360 PCI_INTERRUPT_LINE(intr) == 0) { 361 /* Get the interrupt line from our parent. */ 362 intr = pci_conf_read(pc, bridgetag, PCI_INTERRUPT_REG); 363 line = PCI_INTERRUPT_LINE(intr); 364 365 intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); 366 intr &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT); 367 intr |= line << PCI_INTERRUPT_LINE_SHIFT; 368 pci_conf_write(pc, tag, PCI_INTERRUPT_REG, intr); 369 } 370 371 return (0); 372 } 373 374 int 375 ppb_hotplug_fixup_type1(pci_chipset_tag_t pc, pcitag_t tag, pcitag_t bridgetag) 376 { 377 pcireg_t bhlcr, bir, csr, val; 378 int bus, dev, reg; 379 380 bir = pci_conf_read(pc, bridgetag, PPB_REG_BUSINFO); 381 if (PPB_BUSINFO_SUBORDINATE(bir) <= PPB_BUSINFO_SECONDARY(bir)) 382 return (0); 383 384 bus = PPB_BUSINFO_SECONDARY(bir); 385 bir = pci_conf_read(pc, tag, PPB_REG_BUSINFO); 386 bir &= (0xff << 24); 387 bir |= bus++; 388 bir |= (bus << 8); 389 bir |= (bus << 16); 390 pci_conf_write(pc, tag, PPB_REG_BUSINFO, bir); 391 392 for (reg = PPB_REG_IOSTATUS; reg < PPB_REG_BRIDGECONTROL; reg += 4) { 393 val = pci_conf_read(pc, bridgetag, reg); 394 pci_conf_write(pc, tag, reg, val); 395 } 396 397 csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 398 csr |= PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE; 399 csr |= PCI_COMMAND_MASTER_ENABLE; 400 csr |= PCI_COMMAND_INVALIDATE_ENABLE; 401 csr |= PCI_COMMAND_SERR_ENABLE; 402 pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr); 403 404 for (dev = 0; dev < pci_bus_maxdevs(pc, bus); dev++) { 405 tag = pci_make_tag(pc, bus, dev, 0); 406 407 bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); 408 if (PCI_HDRTYPE_TYPE(bhlcr) != 0) 409 continue; 410 411 ppb_hotplug_fixup_type0(pc, tag, bridgetag); 412 } 413 414 return (0); 415 } 416 417 void 418 ppb_hotplug_rescan(void *arg1, void *arg2) 419 { 420 struct ppb_softc *sc = arg1; 421 struct pci_softc *psc = (struct pci_softc *)sc->sc_psc; 422 423 if (psc) { 424 /* Assign resources. */ 425 pci_enumerate_bus(psc, ppb_hotplug_fixup, NULL); 426 427 /* Attach devices. */ 428 pci_enumerate_bus(psc, NULL, NULL); 429 } 430 } 431 432 void 433 ppb_hotplug_remove(void *arg1, void *arg2) 434 { 435 struct ppb_softc *sc = arg1; 436 struct pci_softc *psc = (struct pci_softc *)sc->sc_psc; 437 438 if (psc) 439 pci_detach_devices(psc, DETACH_FORCE); 440 } 441 442 int 443 ppbprint(void *aux, const char *pnp) 444 { 445 struct pcibus_attach_args *pba = aux; 446 447 /* only PCIs can attach to PPBs; easy. */ 448 if (pnp) 449 printf("pci at %s", pnp); 450 printf(" bus %d", pba->pba_bus); 451 return (UNCONF); 452 } 453