1 /*- 2 * Copyright (C) 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/kernel.h> 31 #include <sys/module.h> 32 #include <sys/malloc.h> 33 #include <sys/bus.h> 34 #include <sys/clock.h> 35 #include <sys/cpu.h> 36 #include <sys/resource.h> 37 #include <sys/rman.h> 38 39 #include <vm/vm.h> 40 #include <vm/pmap.h> 41 42 #include <machine/bus.h> 43 #include <machine/platform.h> 44 #include <machine/pmap.h> 45 #include <machine/resource.h> 46 47 #include "ps3bus.h" 48 #include "ps3-hvcall.h" 49 #include "iommu_if.h" 50 #include "clock_if.h" 51 52 static void ps3bus_identify(driver_t *, device_t); 53 static int ps3bus_probe(device_t); 54 static int ps3bus_attach(device_t); 55 static int ps3bus_print_child(device_t dev, device_t child); 56 static int ps3bus_read_ivar(device_t bus, device_t child, int which, 57 uintptr_t *result); 58 static struct resource *ps3bus_alloc_resource(device_t bus, device_t child, 59 int type, int *rid, u_long start, u_long end, 60 u_long count, u_int flags); 61 static int ps3bus_activate_resource(device_t bus, device_t child, int type, 62 int rid, struct resource *res); 63 static bus_dma_tag_t ps3bus_get_dma_tag(device_t dev, device_t child); 64 static int ps3_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs, bus_addr_t min, bus_addr_t max, bus_size_t alignment, 65 bus_size_t boundary, void *cookie); 66 static int ps3_iommu_unmap(device_t dev, bus_dma_segment_t *segs, 67 int nsegs, void *cookie); 68 static int ps3_gettime(device_t dev, struct timespec *ts); 69 static int ps3_settime(device_t dev, struct timespec *ts); 70 71 struct ps3bus_devinfo { 72 int bus; 73 int dev; 74 uint64_t bustype; 75 uint64_t devtype; 76 77 struct resource_list resources; 78 bus_dma_tag_t dma_tag; 79 80 struct mtx iommu_mtx; 81 bus_addr_t dma_base[4]; 82 }; 83 84 static MALLOC_DEFINE(M_PS3BUS, "ps3bus", "PS3 system bus device information"); 85 86 enum ps3bus_irq_type { 87 SB_IRQ = 2, 88 OHCI_IRQ = 3, 89 EHCI_IRQ = 4, 90 }; 91 92 static device_method_t ps3bus_methods[] = { 93 /* Device interface */ 94 DEVMETHOD(device_identify, ps3bus_identify), 95 DEVMETHOD(device_probe, ps3bus_probe), 96 DEVMETHOD(device_attach, ps3bus_attach), 97 98 /* Bus interface */ 99 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 100 DEVMETHOD(bus_add_child, bus_generic_add_child), 101 DEVMETHOD(bus_get_dma_tag, ps3bus_get_dma_tag), 102 DEVMETHOD(bus_print_child, ps3bus_print_child), 103 DEVMETHOD(bus_read_ivar, ps3bus_read_ivar), 104 DEVMETHOD(bus_alloc_resource, ps3bus_alloc_resource), 105 DEVMETHOD(bus_activate_resource, ps3bus_activate_resource), 106 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 107 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 108 109 /* IOMMU interface */ 110 DEVMETHOD(iommu_map, ps3_iommu_map), 111 DEVMETHOD(iommu_unmap, ps3_iommu_unmap), 112 113 /* Clock interface */ 114 DEVMETHOD(clock_gettime, ps3_gettime), 115 DEVMETHOD(clock_settime, ps3_settime), 116 117 { 0, 0 } 118 }; 119 120 struct ps3bus_softc { 121 struct rman sc_mem_rman; 122 struct mem_region *regions; 123 int rcount; 124 }; 125 126 static driver_t ps3bus_driver = { 127 "ps3bus", 128 ps3bus_methods, 129 sizeof(struct ps3bus_softc) 130 }; 131 132 static devclass_t ps3bus_devclass; 133 134 DRIVER_MODULE(ps3bus, nexus, ps3bus_driver, ps3bus_devclass, 0, 0); 135 136 static void 137 ps3bus_identify(driver_t *driver, device_t parent) 138 { 139 if (strcmp(installed_platform(), "ps3") != 0) 140 return; 141 142 if (device_find_child(parent, "ps3bus", -1) == NULL) 143 BUS_ADD_CHILD(parent, 0, "ps3bus", 0); 144 } 145 146 static int 147 ps3bus_probe(device_t dev) 148 { 149 /* Do not attach to any OF nodes that may be present */ 150 151 device_set_desc(dev, "Playstation 3 System Bus"); 152 153 return (BUS_PROBE_NOWILDCARD); 154 } 155 156 static void 157 ps3bus_resources_init(struct rman *rm, int bus_index, int dev_index, 158 struct ps3bus_devinfo *dinfo) 159 { 160 uint64_t irq_type, irq, outlet; 161 uint64_t reg_type, paddr, len; 162 uint64_t ppe, junk; 163 int i, result; 164 int thread; 165 166 resource_list_init(&dinfo->resources); 167 168 lv1_get_logical_ppe_id(&ppe); 169 thread = 32 - fls(mfctrl()); 170 171 /* Scan for interrupts */ 172 for (i = 0; i < 10; i++) { 173 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 174 (lv1_repository_string("bus") >> 32) | bus_index, 175 lv1_repository_string("dev") | dev_index, 176 lv1_repository_string("intr") | i, 0, &irq_type, &irq); 177 178 if (result != 0) 179 break; 180 181 switch (irq_type) { 182 case SB_IRQ: 183 lv1_construct_event_receive_port(&outlet); 184 lv1_connect_irq_plug_ext(ppe, thread, outlet, outlet, 185 0); 186 lv1_connect_interrupt_event_receive_port(dinfo->bus, 187 dinfo->dev, outlet, irq); 188 break; 189 case OHCI_IRQ: 190 case EHCI_IRQ: 191 lv1_construct_io_irq_outlet(irq, &outlet); 192 lv1_connect_irq_plug_ext(ppe, thread, outlet, outlet, 193 0); 194 break; 195 default: 196 printf("Unknown IRQ type %ld for device %d.%d\n", 197 irq_type, dinfo->bus, dinfo->dev); 198 break; 199 } 200 201 resource_list_add(&dinfo->resources, SYS_RES_IRQ, i, 202 outlet, outlet, 1); 203 } 204 205 /* Scan for registers */ 206 for (i = 0; i < 10; i++) { 207 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 208 (lv1_repository_string("bus") >> 32) | bus_index, 209 lv1_repository_string("dev") | dev_index, 210 lv1_repository_string("reg") | i, 211 lv1_repository_string("type"), ®_type, &junk); 212 213 if (result != 0) 214 break; 215 216 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 217 (lv1_repository_string("bus") >> 32) | bus_index, 218 lv1_repository_string("dev") | dev_index, 219 lv1_repository_string("reg") | i, 220 lv1_repository_string("data"), &paddr, &len); 221 222 result = lv1_map_device_mmio_region(dinfo->bus, dinfo->dev, 223 paddr, len, 12 /* log_2(4 KB) */, &paddr); 224 225 if (result != 0) { 226 printf("Mapping registers failed for device " 227 "%d.%d (%ld.%ld): %d\n", dinfo->bus, dinfo->dev, 228 dinfo->bustype, dinfo->devtype, result); 229 continue; 230 } 231 232 rman_manage_region(rm, paddr, paddr + len - 1); 233 resource_list_add(&dinfo->resources, SYS_RES_MEMORY, i, 234 paddr, paddr + len, len); 235 } 236 } 237 238 static int 239 ps3bus_attach(device_t self) 240 { 241 struct ps3bus_softc *sc; 242 struct ps3bus_devinfo *dinfo; 243 int bus_index, dev_index, result; 244 uint64_t bustype, bus, devs; 245 uint64_t dev, devtype; 246 uint64_t junk; 247 device_t cdev; 248 249 sc = device_get_softc(self); 250 sc->sc_mem_rman.rm_type = RMAN_ARRAY; 251 sc->sc_mem_rman.rm_descr = "PS3Bus Memory Mapped I/O"; 252 rman_init(&sc->sc_mem_rman); 253 254 /* Get memory regions for DMA */ 255 mem_regions(&sc->regions, &sc->rcount, &sc->regions, &sc->rcount); 256 257 /* 258 * Probe all the PS3's buses. 259 */ 260 261 for (bus_index = 0; bus_index < 5; bus_index++) { 262 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 263 (lv1_repository_string("bus") >> 32) | bus_index, 264 lv1_repository_string("type"), 0, 0, &bustype, &junk); 265 266 if (result != 0) 267 continue; 268 269 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 270 (lv1_repository_string("bus") >> 32) | bus_index, 271 lv1_repository_string("id"), 0, 0, &bus, &junk); 272 273 if (result != 0) 274 continue; 275 276 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 277 (lv1_repository_string("bus") >> 32) | bus_index, 278 lv1_repository_string("num_dev"), 0, 0, &devs, &junk); 279 280 for (dev_index = 0; dev_index < devs; dev_index++) { 281 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 282 (lv1_repository_string("bus") >> 32) | bus_index, 283 lv1_repository_string("dev") | dev_index, 284 lv1_repository_string("type"), 0, &devtype, &junk); 285 286 if (result != 0) 287 continue; 288 289 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 290 (lv1_repository_string("bus") >> 32) | bus_index, 291 lv1_repository_string("dev") | dev_index, 292 lv1_repository_string("id"), 0, &dev, &junk); 293 294 if (result != 0) 295 continue; 296 297 dinfo = malloc(sizeof(*dinfo), M_PS3BUS, 298 M_WAITOK | M_ZERO); 299 300 dinfo->bus = bus; 301 dinfo->dev = dev; 302 dinfo->bustype = bustype; 303 dinfo->devtype = devtype; 304 305 if (dinfo->bustype == PS3_BUSTYPE_SYSBUS) 306 lv1_open_device(bus, dev, 0); 307 308 ps3bus_resources_init(&sc->sc_mem_rman, bus_index, 309 dev_index, dinfo); 310 311 cdev = device_add_child(self, NULL, -1); 312 if (cdev == NULL) { 313 device_printf(self, 314 "device_add_child failed\n"); 315 free(dinfo, M_PS3BUS); 316 continue; 317 } 318 319 mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF); 320 device_set_ivars(cdev, dinfo); 321 } 322 } 323 324 clock_register(self, 1000); 325 326 return (bus_generic_attach(self)); 327 } 328 329 static int 330 ps3bus_print_child(device_t dev, device_t child) 331 { 332 struct ps3bus_devinfo *dinfo = device_get_ivars(child); 333 int retval = 0; 334 335 retval += bus_print_child_header(dev, child); 336 retval += resource_list_print_type(&dinfo->resources, "mem", 337 SYS_RES_MEMORY, "%#lx"); 338 retval += resource_list_print_type(&dinfo->resources, "irq", 339 SYS_RES_IRQ, "%ld"); 340 341 retval += bus_print_child_footer(dev, child); 342 343 return (retval); 344 } 345 346 static int 347 ps3bus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) 348 { 349 struct ps3bus_devinfo *dinfo = device_get_ivars(child); 350 351 switch (which) { 352 case PS3BUS_IVAR_BUS: 353 *result = dinfo->bus; 354 break; 355 case PS3BUS_IVAR_DEVICE: 356 *result = dinfo->dev; 357 break; 358 case PS3BUS_IVAR_BUSTYPE: 359 *result = dinfo->bustype; 360 break; 361 case PS3BUS_IVAR_DEVTYPE: 362 *result = dinfo->devtype; 363 break; 364 default: 365 return (EINVAL); 366 } 367 368 return (0); 369 } 370 371 static struct resource * 372 ps3bus_alloc_resource(device_t bus, device_t child, int type, int *rid, 373 u_long start, u_long end, u_long count, u_int flags) 374 { 375 struct ps3bus_devinfo *dinfo; 376 struct ps3bus_softc *sc; 377 int needactivate; 378 struct resource *rv; 379 struct rman *rm; 380 u_long adjstart, adjend, adjcount; 381 struct resource_list_entry *rle; 382 383 sc = device_get_softc(bus); 384 dinfo = device_get_ivars(child); 385 needactivate = flags & RF_ACTIVE; 386 flags &= ~RF_ACTIVE; 387 388 switch (type) { 389 case SYS_RES_MEMORY: 390 rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY, 391 *rid); 392 if (rle == NULL) { 393 device_printf(bus, "no rle for %s memory %d\n", 394 device_get_nameunit(child), *rid); 395 return (NULL); 396 } 397 398 if (start < rle->start) 399 adjstart = rle->start; 400 else if (start > rle->end) 401 adjstart = rle->end; 402 else 403 adjstart = start; 404 405 if (end < rle->start) 406 adjend = rle->start; 407 else if (end > rle->end) 408 adjend = rle->end; 409 else 410 adjend = end; 411 412 adjcount = adjend - adjstart; 413 414 rm = &sc->sc_mem_rman; 415 break; 416 case SYS_RES_IRQ: 417 return (resource_list_alloc(&dinfo->resources, bus, child, 418 type, rid, start, end, count, flags)); 419 default: 420 device_printf(bus, "unknown resource request from %s\n", 421 device_get_nameunit(child)); 422 return (NULL); 423 } 424 425 rv = rman_reserve_resource(rm, adjstart, adjend, adjcount, flags, 426 child); 427 if (rv == NULL) { 428 device_printf(bus, 429 "failed to reserve resource %#lx - %#lx (%#lx)" 430 " for %s\n", adjstart, adjend, adjcount, 431 device_get_nameunit(child)); 432 return (NULL); 433 } 434 435 rman_set_rid(rv, *rid); 436 437 if (needactivate) { 438 if (bus_activate_resource(child, type, *rid, rv) != 0) { 439 device_printf(bus, 440 "failed to activate resource for %s\n", 441 device_get_nameunit(child)); 442 rman_release_resource(rv); 443 return (NULL); 444 } 445 } 446 447 return (rv); 448 } 449 450 static int 451 ps3bus_activate_resource(device_t bus, device_t child, int type, int rid, 452 struct resource *res) 453 { 454 void *p; 455 456 if (type == SYS_RES_IRQ) 457 return (bus_activate_resource(bus, type, rid, res)); 458 459 if (type == SYS_RES_MEMORY) { 460 vm_offset_t start; 461 462 start = (vm_offset_t) rman_get_start(res); 463 464 if (bootverbose) 465 printf("ps3 mapdev: start %zx, len %ld\n", start, 466 rman_get_size(res)); 467 468 p = pmap_mapdev(start, (vm_size_t) rman_get_size(res)); 469 if (p == NULL) 470 return (ENOMEM); 471 rman_set_virtual(res, p); 472 rman_set_bustag(res, &bs_be_tag); 473 rman_set_bushandle(res, (u_long)p); 474 } 475 476 return (rman_activate_resource(res)); 477 } 478 479 static bus_dma_tag_t 480 ps3bus_get_dma_tag(device_t dev, device_t child) 481 { 482 struct ps3bus_devinfo *dinfo = device_get_ivars(child); 483 struct ps3bus_softc *sc = device_get_softc(dev); 484 int i, err, flags; 485 486 if (dinfo->bustype != PS3_BUSTYPE_SYSBUS) 487 return (bus_get_dma_tag(dev)); 488 489 mtx_lock(&dinfo->iommu_mtx); 490 if (dinfo->dma_tag != NULL) { 491 mtx_unlock(&dinfo->iommu_mtx); 492 return (dinfo->dma_tag); 493 } 494 495 flags = 0; /* 32-bit mode */ 496 if (dinfo->bustype == PS3_BUSTYPE_SYSBUS && 497 dinfo->devtype == PS3_DEVTYPE_USB) 498 flags = 2; /* 8-bit mode */ 499 500 for (i = 0; i < sc->rcount; i++) { 501 err = lv1_allocate_device_dma_region(dinfo->bus, dinfo->dev, 502 sc->regions[i].mr_size, 24 /* log_2(16 MB) */, flags, 503 &dinfo->dma_base[i]); 504 if (err != 0) { 505 device_printf(child, 506 "could not allocate DMA region %d: %d\n", i, err); 507 goto fail; 508 } 509 510 err = lv1_map_device_dma_region(dinfo->bus, dinfo->dev, 511 sc->regions[i].mr_start, dinfo->dma_base[i], 512 sc->regions[i].mr_size, 513 0xf800000000000800UL /* Cell Handbook Figure 7.3.4.1 */); 514 if (err != 0) { 515 device_printf(child, 516 "could not map DMA region %d: %d\n", i, err); 517 goto fail; 518 } 519 } 520 521 err = bus_dma_tag_create(bus_get_dma_tag(dev), 522 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 523 NULL, NULL, BUS_SPACE_MAXSIZE, 0, BUS_SPACE_MAXSIZE, 524 0, NULL, NULL, &dinfo->dma_tag); 525 526 bus_dma_tag_set_iommu(dinfo->dma_tag, dev, dinfo); 527 528 fail: 529 mtx_unlock(&dinfo->iommu_mtx); 530 531 if (err) 532 return (NULL); 533 534 return (dinfo->dma_tag); 535 } 536 537 static int 538 ps3_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs, 539 bus_addr_t min, bus_addr_t max, bus_size_t alignment, bus_size_t boundary, 540 void *cookie) 541 { 542 struct ps3bus_devinfo *dinfo = cookie; 543 struct ps3bus_softc *sc = device_get_softc(dev); 544 int i, j; 545 546 for (i = 0; i < *nsegs; i++) { 547 for (j = 0; j < sc->rcount; j++) { 548 if (segs[i].ds_addr >= sc->regions[j].mr_start && 549 segs[i].ds_addr < sc->regions[j].mr_start + 550 sc->regions[j].mr_size) 551 break; 552 } 553 KASSERT(j < sc->rcount, 554 ("Trying to map address %#lx not in physical memory", 555 segs[i].ds_addr)); 556 557 segs[i].ds_addr = dinfo->dma_base[j] + 558 (segs[i].ds_addr - sc->regions[j].mr_start); 559 } 560 561 return (0); 562 } 563 564 static int 565 ps3_iommu_unmap(device_t dev, bus_dma_segment_t *segs, int nsegs, void *cookie) 566 { 567 568 return (0); 569 } 570 571 #define Y2K 946684800 572 573 static int 574 ps3_gettime(device_t dev, struct timespec *ts) 575 { 576 uint64_t rtc, tb; 577 int result; 578 579 result = lv1_get_rtc(&rtc, &tb); 580 if (result) 581 return (result); 582 583 ts->tv_sec = rtc + Y2K; 584 ts->tv_nsec = 0; 585 return (0); 586 } 587 588 static int 589 ps3_settime(device_t dev, struct timespec *ts) 590 { 591 return (-1); 592 } 593 594