1 /* $OpenBSD: mpcpcibus.c,v 1.46 2013/08/07 07:29:19 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 {"legacy", 0x00000cf8, 0x00000cfc, 0 }, 107 {"IBM,27-82660", 0x00000cf8, 0x00000cfc, 0 }, 108 {NULL, 0x00000000, 0x00000000, 0 }, 109 }; 110 111 int 112 mpcpcibrmatch(struct device *parent, void *match, void *aux) 113 { 114 struct confargs *ca = aux; 115 int found = 0; 116 117 if (strcmp(ca->ca_name, mpcpcibr_cd.cd_name) != 0) 118 return (found); 119 120 found = 1; 121 122 return found; 123 } 124 125 struct ranges_32 { 126 u_int32_t cspace; 127 u_int32_t child_hi; 128 u_int32_t child_lo; 129 u_int32_t phys; 130 u_int32_t size_hi; 131 u_int32_t size_lo; 132 }; 133 134 void 135 mpcpcibus_find_ranges_32(struct pcibr_softc *sc, u_int32_t *range_store, 136 int rangesize) 137 { 138 int i, found; 139 unsigned int base = 0; 140 unsigned int size = 0; 141 struct ranges_32 *prange = (void *)range_store; 142 int rangelen; 143 144 rangelen = rangesize / sizeof(struct ranges_32); 145 146 /* mac configs */ 147 sc->sc_membus_space.bus_base = 0; 148 sc->sc_membus_space.bus_io = 0; 149 sc->sc_iobus_space.bus_base = 0; 150 sc->sc_iobus_space.bus_io = 1; 151 152 /* find io(config) base, flag == 0x01000000 */ 153 found = 0; 154 for (i = 0; i < rangelen; i++) { 155 if (prange[i].cspace == 0x01000000) { 156 /* find last? */ 157 found = i; 158 159 if (sc->sc_ioex) 160 extent_free(sc->sc_ioex, prange[i].child_lo, 161 prange[i].size_lo, EX_NOWAIT); 162 } 163 } 164 /* found the io space ranges */ 165 if (prange[found].cspace == 0x01000000) { 166 sc->sc_iobus_space.bus_base = prange[found].phys; 167 sc->sc_iobus_space.bus_size = prange[found].size_lo; 168 } 169 170 /* the mem space ranges 171 * apple openfirmware always puts full 172 * addresses in config information, 173 * it is not necessary to have correct bus 174 * base address, but since 0 is reserved 175 * and all IO and device memory will be in 176 * upper 2G of address space, set to 177 * 0x80000000 178 */ 179 for (i = 0; i < rangelen; i++) { 180 if (prange[i].cspace == 0x02000000) { 181 #ifdef DEBUG_PCI 182 printf("\nfound mem %x %x", 183 prange[i].phys, 184 prange[i].size_lo); 185 #endif 186 if (base != 0) { 187 if ((base + size) == prange[i].phys) 188 size += prange[i].size_lo; 189 else { 190 base = prange[i].phys; 191 size = prange[i].size_lo; 192 } 193 } else { 194 base = prange[i].phys; 195 size = prange[i].size_lo; 196 } 197 198 if (sc->sc_memex) 199 extent_free(sc->sc_memex, prange[i].child_lo, 200 prange[i].size_lo, EX_NOWAIT); 201 } 202 } 203 sc->sc_membus_space.bus_base = base; 204 sc->sc_membus_space.bus_size = size; 205 } 206 207 struct ranges_64 { 208 u_int32_t cspace; 209 u_int32_t child_hi; 210 u_int32_t child_lo; 211 u_int32_t phys_hi; 212 u_int32_t phys_lo; 213 u_int32_t size_hi; 214 u_int32_t size_lo; 215 }; 216 217 void 218 mpcpcibus_find_ranges_64(struct pcibr_softc *sc, u_int32_t *range_store, 219 int rangesize) 220 { 221 int i, found; 222 unsigned int base = 0; 223 unsigned int size = 0; 224 struct ranges_64 *prange = (void *)range_store; 225 int rangelen; 226 227 rangelen = rangesize / sizeof(struct ranges_64); 228 229 /* mac configs */ 230 sc->sc_membus_space.bus_base = 0; 231 sc->sc_membus_space.bus_io = 0; 232 sc->sc_iobus_space.bus_base = 0; 233 sc->sc_iobus_space.bus_io = 1; 234 235 if (prange[0].cspace == 0xabb10113) { /* appl U3; */ 236 prange[0].cspace = 0x01000000; 237 prange[0].child_lo = 0x00000000; 238 prange[0].phys_lo = 0xf8070000; 239 prange[0].size_lo = 0x00001000; 240 prange[1].cspace = 0x02000000; 241 prange[1].child_lo = 0xf2000000; 242 prange[1].phys_lo = 0xf2000000; 243 prange[1].size_lo = 0x02800000; 244 rangelen = 2; 245 } 246 247 /* find io(config) base, flag == 0x01000000 */ 248 found = 0; 249 for (i = 0; i < rangelen; i++) { 250 if (prange[i].cspace == 0x01000000) { 251 /* find last? */ 252 found = i; 253 254 if (sc->sc_ioex) 255 extent_free(sc->sc_ioex, prange[i].child_lo, 256 prange[i].size_lo, EX_NOWAIT); 257 } 258 } 259 /* found the io space ranges */ 260 if (prange[found].cspace == 0x01000000) { 261 sc->sc_iobus_space.bus_base = prange[found].phys_lo; 262 sc->sc_iobus_space.bus_size = prange[found].size_lo; 263 } 264 265 /* the mem space ranges 266 * apple openfirmware always puts full 267 * addresses in config information, 268 * it is not necessary to have correct bus 269 * base address, but since 0 is reserved 270 * and all IO and device memory will be in 271 * upper 2G of address space, set to 272 * 0x80000000 273 */ 274 for (i = 0; i < rangelen; i++) { 275 if (prange[i].cspace == 0x02000000) { 276 #ifdef DEBUG_PCI 277 printf("\nfound mem %x %x", 278 prange[i].phys_lo, 279 prange[i].size_lo); 280 #endif 281 if (base != 0) { 282 if ((base + size) == prange[i].phys_lo) { 283 size += prange[i].size_lo; 284 } else { 285 base = prange[i].phys_lo; 286 size = prange[i].size_lo; 287 } 288 } else { 289 base = prange[i].phys_lo; 290 size = prange[i].size_lo; 291 } 292 293 if (sc->sc_memex) 294 extent_free(sc->sc_memex, prange[i].child_lo, 295 prange[i].size_lo, EX_NOWAIT); 296 } 297 } 298 sc->sc_membus_space.bus_base = base; 299 sc->sc_membus_space.bus_size = size; 300 } 301 302 void 303 mpcpcibrattach(struct device *parent, struct device *self, void *aux) 304 { 305 struct pcibr_softc *sc = (struct pcibr_softc *)self; 306 struct confargs *ca = aux; 307 struct pcibr_config *lcp; 308 struct pcibus_attach_args pba; 309 int of_node = 0; 310 char compat[32]; 311 u_int32_t addr_offset; 312 u_int32_t data_offset; 313 int i; 314 int len; 315 int rangesize; 316 u_int32_t range_store[32]; 317 318 if (ca->ca_node == 0) { 319 printf("invalid node on mpcpcibr config\n"); 320 return; 321 } 322 len=OF_getprop(ca->ca_node, "name", compat, sizeof (compat)); 323 compat[len] = '\0'; 324 if (len > 0) 325 printf(" %s", compat); 326 327 len=OF_getprop(ca->ca_node, "compatible", compat, 328 sizeof (compat)); 329 if (len <= 0 ) { 330 len=OF_getprop(ca->ca_node, "name", compat, 331 sizeof (compat)); 332 if (len <= 0) { 333 printf(" compatible and name not found\n"); 334 return; 335 } 336 compat[len] = 0; 337 if (strcmp (compat, "bandit") != 0) { 338 printf(" compatible not found and name %s found\n", 339 compat); 340 return; 341 } 342 } 343 compat[len] = 0; 344 if ((rangesize = OF_getprop(ca->ca_node, "ranges", 345 range_store, sizeof (range_store))) <= 0) { 346 if (strcmp(compat, "u3-ht") == 0) { 347 range_store[0] = 0xabb10113; /* appl U3; */ 348 } else 349 printf("range lookup failed, node %x\n", ca->ca_node); 350 } 351 /* translate byte(s) into item count*/ 352 353 lcp = &sc->pcibr_config; 354 355 snprintf(sc->sc_ioex_name, sizeof(sc->sc_ioex_name), 356 "%s pciio", sc->sc_dev.dv_xname); 357 sc->sc_ioex = extent_create(sc->sc_ioex_name, 0x00000000, 0xffffffff, 358 M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED); 359 snprintf(sc->sc_memex_name, sizeof(sc->sc_memex_name), 360 "%s pcimem", sc->sc_dev.dv_xname); 361 sc->sc_memex = extent_create(sc->sc_memex_name, 0x00000000, 0xffffffff, 362 M_DEVBUF, NULL, 0, EX_NOWAIT | EX_FILLED); 363 364 if (ppc_proc_is_64b) 365 mpcpcibus_find_ranges_64 (sc, range_store, rangesize); 366 else 367 mpcpcibus_find_ranges_32 (sc, range_store, rangesize); 368 369 addr_offset = 0; 370 for (i = 0; config_offsets[i].compat != NULL; i++) { 371 struct config_type *co = &config_offsets[i]; 372 if (strcmp(co->compat, compat) == 0) { 373 addr_offset = co->addr; 374 data_offset = co->data; 375 lcp->config_type = co->config_type; 376 break; 377 } 378 } 379 if (addr_offset == 0) { 380 printf("unable to find match for" 381 " compatible %s\n", compat); 382 return; 383 } 384 #ifdef DEBUG_FIXUP 385 printf(" mem base %x sz %x io base %x sz %x\n" 386 " config addr %x config data %x\n", 387 sc->sc_membus_space.bus_base, 388 sc->sc_membus_space.bus_size, 389 sc->sc_iobus_space.bus_base, 390 sc->sc_iobus_space.bus_size, 391 addr_offset, data_offset); 392 #endif 393 394 if ( bus_space_map(&(sc->sc_iobus_space), addr_offset, 395 NBPG, 0, &lcp->ioh_cf8) != 0 ) 396 panic("mpcpcibus: unable to map self"); 397 398 if ( bus_space_map(&(sc->sc_iobus_space), data_offset, 399 NBPG, 0, &lcp->ioh_cfc) != 0 ) 400 panic("mpcpcibus: unable to map self"); 401 402 of_node = ca->ca_node; 403 404 lcp->lc_pc.pc_conf_v = lcp; 405 lcp->lc_pc.pc_node = ca->ca_node; 406 lcp->lc_pc.pc_conf_read = mpc_conf_read; 407 lcp->lc_pc.pc_conf_write = mpc_conf_write; 408 lcp->lc_iot = &sc->sc_iobus_space; 409 lcp->lc_memt = &sc->sc_membus_space; 410 411 printf(": %s\n", compat); 412 413 bzero(&pba, sizeof(pba)); 414 pba.pba_dmat = &pci_bus_dma_tag; 415 416 pba.pba_busname = "pci"; 417 pba.pba_iot = &sc->sc_iobus_space; 418 pba.pba_memt = &sc->sc_membus_space; 419 pba.pba_ioex = sc->sc_ioex; 420 pba.pba_memex = sc->sc_memex; 421 pba.pba_pc = &lcp->lc_pc; 422 pba.pba_domain = pci_ndomains++; 423 pba.pba_bus = 0; 424 425 config_found(self, &pba, mpcpcibrprint); 426 } 427 428 static int 429 mpcpcibrprint(void *aux, const char *pnp) 430 { 431 struct pcibus_attach_args *pba = aux; 432 433 if (pnp) 434 printf("%s at %s", pba->pba_busname, pnp); 435 printf(" bus %d", pba->pba_bus); 436 return(UNCONF); 437 } 438 439 u_int32_t 440 mpc_gen_config_reg(void *cpv, pcitag_t tag, int offset) 441 { 442 struct pcibr_config *cp = cpv; 443 unsigned int bus, dev, fcn; 444 u_int32_t reg, val = PCITAG_OFFSET(tag); 445 446 pci_decompose_tag(cpv, tag, &bus, &dev, &fcn); 447 448 if (cp->config_type & 1) { 449 /* Config Mechanism #2 */ 450 if (bus == 0) { 451 if (dev < 11) 452 return 0xffffffff; 453 /* 454 * Need to do config type 0 operation 455 * 1 << (11?+dev) | fcn << 8 | reg 456 * 11? is because pci spec states 457 * that 11-15 is reserved. 458 */ 459 reg = 1 << (dev) | fcn << 8 | offset; 460 } else { 461 if (dev > 15) 462 return 0xffffffff; 463 /* 464 * config type 1 465 */ 466 reg = val | offset | 1; 467 } 468 } else { 469 /* config mechanism #2, type 0 470 * standard cf8/cfc config 471 */ 472 reg = 0x80000000 | val | offset; 473 } 474 475 return reg; 476 } 477 478 /* #define DEBUG_CONFIG */ 479 pcireg_t 480 mpc_conf_read(void *cpv, pcitag_t tag, int offset) 481 { 482 struct pcibr_config *cp = cpv; 483 pcireg_t data; 484 u_int32_t reg; 485 int s; 486 int daddr = 0; 487 faultbuf env; 488 void *oldh; 489 490 if (offset & 3 || 491 offset < 0 || offset >= PCI_CONFIG_SPACE_SIZE) { 492 #ifdef DEBUG_CONFIG 493 printf ("pci_conf_read: bad reg %x\n", offset); 494 #endif /* DEBUG_CONFIG */ 495 return(~0); 496 } 497 498 reg = mpc_gen_config_reg(cpv, tag, offset); 499 /* if invalid tag, return -1 */ 500 if (reg == 0xffffffff) 501 return(~0); 502 503 if ((cp->config_type & 2) && (offset & 0x04)) 504 daddr += 4; 505 506 s = splhigh(); 507 508 oldh = curpcb->pcb_onfault; 509 if (setfault(&env)) { 510 /* we faulted during the read? */ 511 curpcb->pcb_onfault = oldh; 512 splx(s); 513 return 0xffffffff; 514 } 515 516 bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg); 517 bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */ 518 data = bus_space_read_4(cp->lc_iot, cp->ioh_cfc, daddr); 519 bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */ 520 bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */ 521 522 curpcb->pcb_onfault = oldh; 523 524 splx(s); 525 #ifdef DEBUG_CONFIG 526 if (!((offset == 0) && (data == 0xffffffff))) { 527 unsigned int bus, dev, fcn; 528 pci_decompose_tag(cpv, tag, &bus, &dev, &fcn); 529 printf("mpc_conf_read bus %x dev %x fcn %x offset %x", bus, dev, fcn, 530 offset); 531 printf(" daddr %x reg %x",daddr, reg); 532 printf(" data %x\n", data); 533 } 534 #endif 535 536 return(data); 537 } 538 539 void 540 mpc_conf_write(void *cpv, pcitag_t tag, int offset, pcireg_t data) 541 { 542 struct pcibr_config *cp = cpv; 543 u_int32_t reg; 544 int s; 545 int daddr = 0; 546 547 reg = mpc_gen_config_reg(cpv, tag, offset); 548 549 /* if invalid tag, return ??? */ 550 if (reg == 0xffffffff) 551 return; 552 553 if ((cp->config_type & 2) && (offset & 0x04)) 554 daddr += 4; 555 556 #ifdef DEBUG_CONFIG 557 { 558 unsigned int bus, dev, fcn; 559 pci_decompose_tag(cpv, tag, &bus, &dev, &fcn); 560 printf("mpc_conf_write bus %x dev %x fcn %x offset %x", bus, 561 dev, fcn, offset); 562 printf(" daddr %x reg %x",daddr, reg); 563 printf(" data %x\n", data); 564 } 565 #endif 566 567 s = splhigh(); 568 569 bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, reg); 570 bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */ 571 bus_space_write_4(cp->lc_iot, cp->ioh_cfc, daddr, data); 572 bus_space_write_4(cp->lc_iot, cp->ioh_cf8, 0, 0); /* disable */ 573 bus_space_read_4(cp->lc_iot, cp->ioh_cf8, 0); /* XXX */ 574 575 splx(s); 576 } 577