1 /* $OpenBSD: mpcpcibus.c,v 1.47 2015/06/03 08:41:43 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Per Fogelstrom 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/device.h> 32 #include <sys/malloc.h> 33 #include <sys/extent.h> 34 35 #include <machine/autoconf.h> 36 #include <machine/pcb.h> 37 38 #include <dev/pci/pcireg.h> 39 #include <dev/pci/pcivar.h> 40 #include <dev/pci/pcidevs.h> 41 42 #include <dev/ofw/openfirm.h> 43 44 int mpcpcibrmatch(struct device *, void *, void *); 45 void mpcpcibrattach(struct device *, struct device *, void *); 46 47 pcireg_t mpc_conf_read(void *, pcitag_t, int); 48 void mpc_conf_write(void *, pcitag_t, int, pcireg_t); 49 50 u_int32_t mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset); 51 52 struct pcibr_config { 53 bus_space_tag_t lc_memt; 54 bus_space_tag_t lc_iot; 55 bus_space_handle_t ioh_cf8; 56 bus_space_handle_t ioh_cfc; 57 struct ppc_pci_chipset lc_pc; 58 int config_type; 59 }; 60 61 struct pcibr_softc { 62 struct device sc_dev; 63 struct ppc_bus_space sc_membus_space; 64 struct ppc_bus_space sc_iobus_space; 65 struct pcibr_config pcibr_config; 66 struct extent *sc_ioex; 67 struct extent *sc_memex; 68 char sc_ioex_name[32]; 69 char sc_memex_name[32]; 70 }; 71 72 struct cfattach mpcpcibr_ca = { 73 sizeof(struct pcibr_softc), mpcpcibrmatch, mpcpcibrattach, 74 }; 75 76 struct cfdriver mpcpcibr_cd = { 77 NULL, "mpcpcibr", DV_DULL, 78 }; 79 80 static int mpcpcibrprint(void *, const char *pnp); 81 82 void mpcpcibus_find_ranges_32(struct pcibr_softc *, u_int32_t *, int); 83 void mpcpcibus_find_ranges_64(struct pcibr_softc *, u_int32_t *, int); 84 85 /* 86 * config types 87 * bit meanings 88 * 0 - standard cf8/cfc type configurations, 89 * sometimes the base addresses for these are different 90 * 1 - Config Method #2 configuration - uni-north 91 * 92 * 2 - 64 bit config bus, data for accesses &4 is at daddr+4; 93 */ 94 struct config_type{ 95 char * compat; 96 u_int32_t addr; /* offset */ 97 u_int32_t data; /* offset */ 98 int config_type; 99 }; 100 struct config_type config_offsets[] = { 101 {"grackle", 0x00c00cf8, 0x00e00cfc, 0 }, 102 {"bandit", 0x00800000, 0x00c00000, 1 }, 103 {"uni-north", 0x00800000, 0x00c00000, 3 }, 104 {"u3-agp", 0x00800000, 0x00c00000, 3 }, 105 {"u3-ht", 0x00000cf8, 0x00000cfc, 3 }, 106 {"u4-pcie", 0x00800000, 0x00c00000, 7 }, 107 {"legacy", 0x00000cf8, 0x00000cfc, 0 }, 108 {"IBM,27-82660", 0x00000cf8, 0x00000cfc, 0 }, 109 {NULL, 0x00000000, 0x00000000, 0 }, 110 }; 111 112 int 113 mpcpcibrmatch(struct device *parent, void *match, void *aux) 114 { 115 struct confargs *ca = aux; 116 int found = 0; 117 118 if (strcmp(ca->ca_name, mpcpcibr_cd.cd_name) != 0) 119 return (found); 120 121 found = 1; 122 123 return found; 124 } 125 126 struct ranges_32 { 127 u_int32_t cspace; 128 u_int32_t child_hi; 129 u_int32_t child_lo; 130 u_int32_t phys; 131 u_int32_t size_hi; 132 u_int32_t size_lo; 133 }; 134 135 void 136 mpcpcibus_find_ranges_32(struct pcibr_softc *sc, u_int32_t *range_store, 137 int rangesize) 138 { 139 int i, found; 140 unsigned int base = 0; 141 unsigned int size = 0; 142 struct ranges_32 *prange = (void *)range_store; 143 int rangelen; 144 145 rangelen = rangesize / sizeof(struct ranges_32); 146 147 /* mac configs */ 148 sc->sc_membus_space.bus_base = 0; 149 sc->sc_membus_space.bus_io = 0; 150 sc->sc_iobus_space.bus_base = 0; 151 sc->sc_iobus_space.bus_io = 1; 152 153 /* find io(config) base, flag == 0x01000000 */ 154 found = 0; 155 for (i = 0; i < rangelen; i++) { 156 if (prange[i].cspace == 0x01000000) { 157 /* find last? */ 158 found = i; 159 160 if (sc->sc_ioex) 161 extent_free(sc->sc_ioex, prange[i].child_lo, 162 prange[i].size_lo, EX_NOWAIT); 163 } 164 } 165 /* found the io space ranges */ 166 if (prange[found].cspace == 0x01000000) { 167 sc->sc_iobus_space.bus_base = prange[found].phys; 168 sc->sc_iobus_space.bus_size = prange[found].size_lo; 169 } 170 171 /* the mem space ranges 172 * apple openfirmware always puts full 173 * addresses in config information, 174 * it is not necessary to have correct bus 175 * base address, but since 0 is reserved 176 * and all IO and device memory will be in 177 * upper 2G of address space, set to 178 * 0x80000000 179 */ 180 for (i = 0; i < rangelen; i++) { 181 if (prange[i].cspace == 0x02000000) { 182 #ifdef DEBUG_PCI 183 printf("\nfound mem %x %x", 184 prange[i].phys, 185 prange[i].size_lo); 186 #endif 187 if (base != 0) { 188 if ((base + size) == prange[i].phys) 189 size += prange[i].size_lo; 190 else { 191 base = prange[i].phys; 192 size = prange[i].size_lo; 193 } 194 } else { 195 base = prange[i].phys; 196 size = prange[i].size_lo; 197 } 198 199 if (sc->sc_memex) 200 extent_free(sc->sc_memex, prange[i].child_lo, 201 prange[i].size_lo, EX_NOWAIT); 202 } 203 } 204 sc->sc_membus_space.bus_base = base; 205 sc->sc_membus_space.bus_size = size; 206 } 207 208 struct ranges_64 { 209 u_int32_t cspace; 210 u_int32_t child_hi; 211 u_int32_t child_lo; 212 u_int32_t phys_hi; 213 u_int32_t phys_lo; 214 u_int32_t size_hi; 215 u_int32_t size_lo; 216 }; 217 218 void 219 mpcpcibus_find_ranges_64(struct pcibr_softc *sc, u_int32_t *range_store, 220 int rangesize) 221 { 222 int i, found; 223 unsigned int base = 0; 224 unsigned int size = 0; 225 struct ranges_64 *prange = (void *)range_store; 226 int rangelen; 227 228 rangelen = rangesize / sizeof(struct ranges_64); 229 230 /* mac configs */ 231 sc->sc_membus_space.bus_base = 0; 232 sc->sc_membus_space.bus_io = 0; 233 sc->sc_iobus_space.bus_base = 0; 234 sc->sc_iobus_space.bus_io = 1; 235 236 if (prange[0].cspace == 0xabb10113) { /* appl U3; */ 237 prange[0].cspace = 0x01000000; 238 prange[0].child_lo = 0x00000000; 239 prange[0].phys_lo = 0xf8070000; 240 prange[0].size_lo = 0x00001000; 241 prange[1].cspace = 0x02000000; 242 prange[1].child_lo = 0xf2000000; 243 prange[1].phys_lo = 0xf2000000; 244 prange[1].size_lo = 0x02800000; 245 rangelen = 2; 246 } 247 248 /* find io(config) base, flag == 0x01000000 */ 249 found = 0; 250 for (i = 0; i < rangelen; i++) { 251 if (prange[i].cspace == 0x01000000) { 252 /* find last? */ 253 found = i; 254 255 if (sc->sc_ioex) 256 extent_free(sc->sc_ioex, prange[i].child_lo, 257 prange[i].size_lo, EX_NOWAIT); 258 } 259 } 260 /* found the io space ranges */ 261 if (prange[found].cspace == 0x01000000) { 262 sc->sc_iobus_space.bus_base = prange[found].phys_lo; 263 sc->sc_iobus_space.bus_size = prange[found].size_lo; 264 } 265 266 /* the mem space ranges 267 * apple openfirmware always puts full 268 * addresses in config information, 269 * it is not necessary to have correct bus 270 * base address, but since 0 is reserved 271 * and all IO and device memory will be in 272 * upper 2G of address space, set to 273 * 0x80000000 274 */ 275 for (i = 0; i < rangelen; i++) { 276 if (prange[i].cspace == 0x02000000) { 277 #ifdef DEBUG_PCI 278 printf("\nfound mem %x %x", 279 prange[i].phys_lo, 280 prange[i].size_lo); 281 #endif 282 if (base != 0) { 283 if ((base + size) == prange[i].phys_lo) { 284 size += prange[i].size_lo; 285 } else { 286 base = prange[i].phys_lo; 287 size = prange[i].size_lo; 288 } 289 } else { 290 base = prange[i].phys_lo; 291 size = prange[i].size_lo; 292 } 293 294 if (sc->sc_memex) 295 extent_free(sc->sc_memex, prange[i].child_lo, 296 prange[i].size_lo, EX_NOWAIT); 297 } 298 } 299 sc->sc_membus_space.bus_base = base; 300 sc->sc_membus_space.bus_size = size; 301 } 302 303 void 304 mpcpcibrattach(struct device *parent, struct device *self, void *aux) 305 { 306 struct pcibr_softc *sc = (struct pcibr_softc *)self; 307 struct confargs *ca = aux; 308 struct pcibr_config *lcp; 309 struct pcibus_attach_args pba; 310 int of_node = 0; 311 char compat[32]; 312 u_int32_t addr_offset; 313 u_int32_t data_offset; 314 int i; 315 int len; 316 int rangesize; 317 u_int32_t range_store[32]; 318 319 if (ca->ca_node == 0) { 320 printf("invalid node on mpcpcibr config\n"); 321 return; 322 } 323 len=OF_getprop(ca->ca_node, "name", compat, sizeof (compat)); 324 compat[len] = '\0'; 325 if (len > 0) 326 printf(" %s", compat); 327 328 len=OF_getprop(ca->ca_node, "compatible", compat, 329 sizeof (compat)); 330 if (len <= 0 ) { 331 len=OF_getprop(ca->ca_node, "name", compat, 332 sizeof (compat)); 333 if (len <= 0) { 334 printf(" compatible and name not found\n"); 335 return; 336 } 337 compat[len] = 0; 338 if (strcmp (compat, "bandit") != 0) { 339 printf(" compatible not found and name %s found\n", 340 compat); 341 return; 342 } 343 } 344 compat[len] = 0; 345 if ((rangesize = OF_getprop(ca->ca_node, "ranges", 346 range_store, sizeof (range_store))) <= 0) { 347 if (strcmp(compat, "u3-ht") == 0) { 348 range_store[0] = 0xabb10113; /* appl U3; */ 349 } else 350 printf("range lookup failed, node %x\n", ca->ca_node); 351 } 352 /* translate byte(s) into item count*/ 353 354 lcp = &sc->pcibr_config; 355 356 snprintf(sc->sc_ioex_name, sizeof(sc->sc_ioex_name), 357 "%s pciio", sc->sc_dev.dv_xname); 358 sc->sc_ioex = extent_create(sc->sc_ioex_name, 0x00000000, 0xffffffff, 359 M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED); 360 snprintf(sc->sc_memex_name, sizeof(sc->sc_memex_name), 361 "%s pcimem", sc->sc_dev.dv_xname); 362 sc->sc_memex = extent_create(sc->sc_memex_name, 0x00000000, 0xffffffff, 363 M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED); 364 365 if (ppc_proc_is_64b) 366 mpcpcibus_find_ranges_64 (sc, range_store, rangesize); 367 else 368 mpcpcibus_find_ranges_32 (sc, range_store, rangesize); 369 370 addr_offset = 0; 371 for (i = 0; config_offsets[i].compat != NULL; i++) { 372 struct config_type *co = &config_offsets[i]; 373 if (strcmp(co->compat, compat) == 0) { 374 addr_offset = co->addr; 375 data_offset = co->data; 376 lcp->config_type = co->config_type; 377 break; 378 } 379 } 380 if (addr_offset == 0) { 381 printf("unable to find match for" 382 " compatible %s\n", compat); 383 return; 384 } 385 #ifdef DEBUG_FIXUP 386 printf(" mem base %x sz %x io base %x sz %x\n" 387 " config addr %x config data %x\n", 388 sc->sc_membus_space.bus_base, 389 sc->sc_membus_space.bus_size, 390 sc->sc_iobus_space.bus_base, 391 sc->sc_iobus_space.bus_size, 392 addr_offset, data_offset); 393 #endif 394 395 if ( bus_space_map(&(sc->sc_iobus_space), addr_offset, 396 NBPG, 0, &lcp->ioh_cf8) != 0 ) 397 panic("mpcpcibus: unable to map self"); 398 399 if ( bus_space_map(&(sc->sc_iobus_space), data_offset, 400 NBPG, 0, &lcp->ioh_cfc) != 0 ) 401 panic("mpcpcibus: unable to map self"); 402 403 of_node = ca->ca_node; 404 405 lcp->lc_pc.pc_conf_v = lcp; 406 lcp->lc_pc.pc_node = ca->ca_node; 407 lcp->lc_pc.pc_conf_read = mpc_conf_read; 408 lcp->lc_pc.pc_conf_write = mpc_conf_write; 409 lcp->lc_iot = &sc->sc_iobus_space; 410 lcp->lc_memt = &sc->sc_membus_space; 411 412 printf(": %s\n", compat); 413 414 bzero(&pba, sizeof(pba)); 415 pba.pba_dmat = &pci_bus_dma_tag; 416 417 pba.pba_busname = "pci"; 418 pba.pba_iot = &sc->sc_iobus_space; 419 pba.pba_memt = &sc->sc_membus_space; 420 pba.pba_ioex = sc->sc_ioex; 421 pba.pba_memex = sc->sc_memex; 422 pba.pba_pc = &lcp->lc_pc; 423 pba.pba_domain = pci_ndomains++; 424 pba.pba_bus = 0; 425 426 config_found(self, &pba, mpcpcibrprint); 427 } 428 429 static int 430 mpcpcibrprint(void *aux, const char *pnp) 431 { 432 struct pcibus_attach_args *pba = aux; 433 434 if (pnp) 435 printf("%s at %s", pba->pba_busname, pnp); 436 printf(" bus %d", pba->pba_bus); 437 return(UNCONF); 438 } 439 440 u_int32_t 441 mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset) 442 { 443 struct pcibr_config *cp = cpv; 444 unsigned int bus, dev, fcn; 445 u_int32_t reg, val = PCITAG_OFFSET(tag); 446 447 pci_decompose_tag(cpv, tag, &bus, &dev, &fcn); 448 449 if (cp->config_type & 4) { 450 reg = val | offset | 1; 451 reg |= (offset >> 8) << 28; 452 } else if (cp->config_type & 1) { 453 /* Config Mechanism #2 */ 454 if (bus == 0) { 455 if (dev < 11) 456 return 0xffffffff; 457 /* 458 * Need to do config type 0 operation 459 * 1 << (11?+dev) | fcn << 8 | reg 460 * 11? is because pci spec states 461 * that 11-15 is reserved. 462 */ 463 reg = 1 << (dev) | fcn << 8 | offset; 464 } else { 465 if (dev > 15) 466 return 0xffffffff; 467 /* 468 * config type 1 469 */ 470 reg = val | offset | 1; 471 } 472 } else { 473 /* config mechanism #2, type 0 474 * standard cf8/cfc config 475 */ 476 reg = 0x80000000 | val | offset; 477 } 478 479 return reg; 480 } 481 482 /* #define DEBUG_CONFIG */ 483 pcireg_t 484 mpc_conf_read(void *cpv, pcitag_t tag, int offset) 485 { 486 struct pcibr_config *cp = cpv; 487 pcireg_t data; 488 u_int32_t reg; 489 int s; 490 int daddr = 0; 491 faultbuf env; 492 void *oldh; 493 494 if (offset & 3 || 495 offset < 0 || offset >= PCI_CONFIG_SPACE_SIZE) { 496 #ifdef DEBUG_CONFIG 497 printf ("pci_conf_read: bad reg %x\n", offset); 498 #endif /* DEBUG_CONFIG */ 499 return(~0); 500 } 501 502 reg = mpc_gen_config_reg(cpv, tag, offset); 503 /* if invalid tag, return -1 */ 504 if (reg == 0xffffffff) 505 return(~0); 506 507 if ((cp->config_type & 2) && (offset & 0x04)) 508 daddr += 4; 509 510 s = splhigh(); 511 512 oldh = curpcb->pcb_onfault; 513 if (setfault(&env)) { 514 /* we faulted during the read? */ 515 curpcb->pcb_onfault = oldh; 516 splx(s); 517 return 0xffffffff; 518 } 519 520 bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg); 521 bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */ 522 data = bus_space_read_4(cp->lc_iot, cp->ioh_cfc, daddr); 523 bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */ 524 bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */ 525 526 curpcb->pcb_onfault = oldh; 527 528 splx(s); 529 #ifdef DEBUG_CONFIG 530 if (!((offset == 0) && (data == 0xffffffff))) { 531 unsigned int bus, dev, fcn; 532 pci_decompose_tag(cpv, tag, &bus, &dev, &fcn); 533 printf("mpc_conf_read bus %x dev %x fcn %x offset %x", bus, dev, fcn, 534 offset); 535 printf(" daddr %x reg %x",daddr, reg); 536 printf(" data %x\n", data); 537 } 538 #endif 539 540 return(data); 541 } 542 543 void 544 mpc_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data) 545 { 546 struct pcibr_config *cp = cpv; 547 u_int32_t reg; 548 int s; 549 int daddr = 0; 550 551 reg = mpc_gen_config_reg(cpv, tag, offset); 552 553 /* if invalid tag, return ??? */ 554 if (reg == 0xffffffff) 555 return; 556 557 if ((cp->config_type & 2) && (offset & 0x04)) 558 daddr += 4; 559 560 #ifdef DEBUG_CONFIG 561 { 562 unsigned int bus, dev, fcn; 563 pci_decompose_tag(cpv, tag, &bus, &dev, &fcn); 564 printf("mpc_conf_write bus %x dev %x fcn %x offset %x", bus, 565 dev, fcn, offset); 566 printf(" daddr %x reg %x",daddr, reg); 567 printf(" data %x\n", data); 568 } 569 #endif 570 571 s = splhigh(); 572 573 bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg); 574 bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */ 575 bus_space_write_4(cp->lc_iot, cp->ioh_cfc, daddr, data); 576 bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */ 577 bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */ 578 579 splx(s); 580 } 581