1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (C) 2010 Nathan Whitehorn 5 * Copyright (C) 2011 glevand (geoffrey.levand@mail.ru) 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/kernel.h> 32 #include <sys/module.h> 33 #include <sys/malloc.h> 34 #include <sys/bus.h> 35 #include <sys/clock.h> 36 #include <sys/cpu.h> 37 #include <sys/lock.h> 38 #include <sys/mutex.h> 39 #include <sys/resource.h> 40 #include <sys/rman.h> 41 42 #include <vm/vm.h> 43 #include <vm/pmap.h> 44 45 #include <machine/bus.h> 46 #include <machine/platform.h> 47 #include <machine/resource.h> 48 49 #include "ps3bus.h" 50 #include "ps3-hvcall.h" 51 #include "iommu_if.h" 52 #include "clock_if.h" 53 54 static void ps3bus_identify(driver_t *, device_t); 55 static int ps3bus_probe(device_t); 56 static int ps3bus_attach(device_t); 57 static int ps3bus_print_child(device_t dev, device_t child); 58 static int ps3bus_read_ivar(device_t bus, device_t child, int which, 59 uintptr_t *result); 60 static struct rman *ps3bus_get_rman(device_t bus, int type, u_int flags); 61 static struct resource *ps3bus_alloc_resource(device_t bus, device_t child, 62 int type, int *rid, rman_res_t start, rman_res_t end, 63 rman_res_t count, u_int flags); 64 static int ps3bus_map_resource(device_t bus, device_t child, 65 struct resource *r, struct resource_map_request *argsp, 66 struct resource_map *map); 67 static int ps3bus_unmap_resource(device_t bus, device_t child, 68 struct resource *r, struct resource_map *map); 69 static bus_dma_tag_t ps3bus_get_dma_tag(device_t dev, device_t child); 70 static int ps3_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs, 71 bus_addr_t min, bus_addr_t max, bus_size_t alignment, 72 bus_addr_t boundary, void *cookie); 73 static int ps3_iommu_unmap(device_t dev, bus_dma_segment_t *segs, 74 int nsegs, void *cookie); 75 static int ps3_gettime(device_t dev, struct timespec *ts); 76 static int ps3_settime(device_t dev, struct timespec *ts); 77 78 struct ps3bus_devinfo { 79 int bus; 80 int dev; 81 uint64_t bustype; 82 uint64_t devtype; 83 int busidx; 84 int devidx; 85 86 struct resource_list resources; 87 bus_dma_tag_t dma_tag; 88 89 struct mtx iommu_mtx; 90 bus_addr_t dma_base[4]; 91 }; 92 93 static MALLOC_DEFINE(M_PS3BUS, "ps3bus", "PS3 system bus device information"); 94 95 enum ps3bus_irq_type { 96 SB_IRQ = 2, 97 OHCI_IRQ = 3, 98 EHCI_IRQ = 4, 99 }; 100 101 enum ps3bus_reg_type { 102 OHCI_REG = 3, 103 EHCI_REG = 4, 104 }; 105 106 static device_method_t ps3bus_methods[] = { 107 /* Device interface */ 108 DEVMETHOD(device_identify, ps3bus_identify), 109 DEVMETHOD(device_probe, ps3bus_probe), 110 DEVMETHOD(device_attach, ps3bus_attach), 111 112 /* Bus interface */ 113 DEVMETHOD(bus_add_child, bus_generic_add_child), 114 DEVMETHOD(bus_get_dma_tag, ps3bus_get_dma_tag), 115 DEVMETHOD(bus_print_child, ps3bus_print_child), 116 DEVMETHOD(bus_read_ivar, ps3bus_read_ivar), 117 DEVMETHOD(bus_get_rman, ps3bus_get_rman), 118 DEVMETHOD(bus_alloc_resource, ps3bus_alloc_resource), 119 DEVMETHOD(bus_adjust_resource, bus_generic_rman_adjust_resource), 120 DEVMETHOD(bus_activate_resource, bus_generic_rman_activate_resource), 121 DEVMETHOD(bus_deactivate_resource, bus_generic_rman_deactivate_resource), 122 DEVMETHOD(bus_map_resource, ps3bus_map_resource), 123 DEVMETHOD(bus_unmap_resource, ps3bus_unmap_resource), 124 DEVMETHOD(bus_release_resource, bus_generic_rman_release_resource), 125 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 126 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 127 128 /* IOMMU interface */ 129 DEVMETHOD(iommu_map, ps3_iommu_map), 130 DEVMETHOD(iommu_unmap, ps3_iommu_unmap), 131 132 /* Clock interface */ 133 DEVMETHOD(clock_gettime, ps3_gettime), 134 DEVMETHOD(clock_settime, ps3_settime), 135 136 DEVMETHOD_END 137 }; 138 139 struct ps3bus_softc { 140 struct rman sc_mem_rman; 141 struct rman sc_intr_rman; 142 struct mem_region *regions; 143 int rcount; 144 }; 145 146 static driver_t ps3bus_driver = { 147 "ps3bus", 148 ps3bus_methods, 149 sizeof(struct ps3bus_softc) 150 }; 151 152 DRIVER_MODULE(ps3bus, nexus, ps3bus_driver, 0, 0); 153 154 static void 155 ps3bus_identify(driver_t *driver, device_t parent) 156 { 157 if (strcmp(installed_platform(), "ps3") != 0) 158 return; 159 160 if (device_find_child(parent, "ps3bus", -1) == NULL) 161 BUS_ADD_CHILD(parent, 0, "ps3bus", 0); 162 } 163 164 static int 165 ps3bus_probe(device_t dev) 166 { 167 /* Do not attach to any OF nodes that may be present */ 168 169 device_set_desc(dev, "Playstation 3 System Bus"); 170 171 return (BUS_PROBE_NOWILDCARD); 172 } 173 174 static void 175 ps3bus_resources_init(struct rman *rm, int bus_index, int dev_index, 176 struct ps3bus_devinfo *dinfo) 177 { 178 uint64_t irq_type, irq, outlet; 179 uint64_t reg_type, paddr, len; 180 uint64_t ppe, junk; 181 int i, result; 182 int thread; 183 184 resource_list_init(&dinfo->resources); 185 186 lv1_get_logical_ppe_id(&ppe); 187 thread = 32 - fls(mfctrl()); 188 189 /* Scan for interrupts */ 190 for (i = 0; i < 10; i++) { 191 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 192 (lv1_repository_string("bus") >> 32) | bus_index, 193 lv1_repository_string("dev") | dev_index, 194 lv1_repository_string("intr") | i, 0, &irq_type, &irq); 195 196 if (result != 0) 197 break; 198 199 switch (irq_type) { 200 case SB_IRQ: 201 lv1_construct_event_receive_port(&outlet); 202 lv1_connect_irq_plug_ext(ppe, thread, outlet, outlet, 203 0); 204 lv1_connect_interrupt_event_receive_port(dinfo->bus, 205 dinfo->dev, outlet, irq); 206 break; 207 case OHCI_IRQ: 208 case EHCI_IRQ: 209 lv1_construct_io_irq_outlet(irq, &outlet); 210 lv1_connect_irq_plug_ext(ppe, thread, outlet, outlet, 211 0); 212 break; 213 default: 214 printf("Unknown IRQ type %ld for device %d.%d\n", 215 irq_type, dinfo->bus, dinfo->dev); 216 break; 217 } 218 219 resource_list_add(&dinfo->resources, SYS_RES_IRQ, i, 220 outlet, outlet, 1); 221 } 222 223 /* Scan for registers */ 224 for (i = 0; i < 10; i++) { 225 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 226 (lv1_repository_string("bus") >> 32) | bus_index, 227 lv1_repository_string("dev") | dev_index, 228 lv1_repository_string("reg") | i, 229 lv1_repository_string("type"), ®_type, &junk); 230 231 if (result != 0) 232 break; 233 234 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 235 (lv1_repository_string("bus") >> 32) | bus_index, 236 lv1_repository_string("dev") | dev_index, 237 lv1_repository_string("reg") | i, 238 lv1_repository_string("data"), &paddr, &len); 239 240 result = lv1_map_device_mmio_region(dinfo->bus, dinfo->dev, 241 paddr, len, 12 /* log_2(4 KB) */, &paddr); 242 243 if (result != 0) { 244 printf("Mapping registers failed for device " 245 "%d.%d (%ld.%ld): %d\n", dinfo->bus, dinfo->dev, 246 dinfo->bustype, dinfo->devtype, result); 247 continue; 248 } 249 250 rman_manage_region(rm, paddr, paddr + len - 1); 251 resource_list_add(&dinfo->resources, SYS_RES_MEMORY, i, 252 paddr, paddr + len, len); 253 } 254 } 255 256 static void 257 ps3bus_resources_init_by_type(struct rman *rm, int bus_index, int dev_index, 258 uint64_t irq_type, uint64_t reg_type, struct ps3bus_devinfo *dinfo) 259 { 260 uint64_t _irq_type, irq, outlet; 261 uint64_t _reg_type, paddr, len; 262 uint64_t ppe, junk; 263 int i, result; 264 int thread; 265 266 resource_list_init(&dinfo->resources); 267 268 lv1_get_logical_ppe_id(&ppe); 269 thread = 32 - fls(mfctrl()); 270 271 /* Scan for interrupts */ 272 for (i = 0; i < 10; i++) { 273 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 274 (lv1_repository_string("bus") >> 32) | bus_index, 275 lv1_repository_string("dev") | dev_index, 276 lv1_repository_string("intr") | i, 0, &_irq_type, &irq); 277 278 if (result != 0) 279 break; 280 281 if (_irq_type != irq_type) 282 continue; 283 284 lv1_construct_io_irq_outlet(irq, &outlet); 285 lv1_connect_irq_plug_ext(ppe, thread, outlet, outlet, 286 0); 287 resource_list_add(&dinfo->resources, SYS_RES_IRQ, i, 288 outlet, outlet, 1); 289 } 290 291 /* Scan for registers */ 292 for (i = 0; i < 10; i++) { 293 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 294 (lv1_repository_string("bus") >> 32) | bus_index, 295 lv1_repository_string("dev") | dev_index, 296 lv1_repository_string("reg") | i, 297 lv1_repository_string("type"), &_reg_type, &junk); 298 299 if (result != 0) 300 break; 301 302 if (_reg_type != reg_type) 303 continue; 304 305 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 306 (lv1_repository_string("bus") >> 32) | bus_index, 307 lv1_repository_string("dev") | dev_index, 308 lv1_repository_string("reg") | i, 309 lv1_repository_string("data"), &paddr, &len); 310 311 result = lv1_map_device_mmio_region(dinfo->bus, dinfo->dev, 312 paddr, len, 12 /* log_2(4 KB) */, &paddr); 313 314 if (result != 0) { 315 printf("Mapping registers failed for device " 316 "%d.%d (%ld.%ld): %d\n", dinfo->bus, dinfo->dev, 317 dinfo->bustype, dinfo->devtype, result); 318 break; 319 } 320 321 rman_manage_region(rm, paddr, paddr + len - 1); 322 resource_list_add(&dinfo->resources, SYS_RES_MEMORY, i, 323 paddr, paddr + len, len); 324 } 325 } 326 327 static int 328 ps3bus_attach(device_t self) 329 { 330 struct ps3bus_softc *sc; 331 struct ps3bus_devinfo *dinfo; 332 int bus_index, dev_index, result; 333 uint64_t bustype, bus, devs; 334 uint64_t dev, devtype; 335 uint64_t junk; 336 device_t cdev; 337 338 sc = device_get_softc(self); 339 sc->sc_mem_rman.rm_type = RMAN_ARRAY; 340 sc->sc_mem_rman.rm_descr = "PS3Bus Memory Mapped I/O"; 341 sc->sc_intr_rman.rm_type = RMAN_ARRAY; 342 sc->sc_intr_rman.rm_descr = "PS3Bus Interrupts"; 343 rman_init(&sc->sc_mem_rman); 344 rman_init(&sc->sc_intr_rman); 345 rman_manage_region(&sc->sc_intr_rman, 0, ~0); 346 347 /* Get memory regions for DMA */ 348 mem_regions(&sc->regions, &sc->rcount, NULL, NULL); 349 350 /* 351 * Probe all the PS3's buses. 352 */ 353 354 for (bus_index = 0; bus_index < 5; bus_index++) { 355 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 356 (lv1_repository_string("bus") >> 32) | bus_index, 357 lv1_repository_string("type"), 0, 0, &bustype, &junk); 358 359 if (result != 0) 360 continue; 361 362 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 363 (lv1_repository_string("bus") >> 32) | bus_index, 364 lv1_repository_string("id"), 0, 0, &bus, &junk); 365 366 if (result != 0) 367 continue; 368 369 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 370 (lv1_repository_string("bus") >> 32) | bus_index, 371 lv1_repository_string("num_dev"), 0, 0, &devs, &junk); 372 373 for (dev_index = 0; dev_index < devs; dev_index++) { 374 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 375 (lv1_repository_string("bus") >> 32) | bus_index, 376 lv1_repository_string("dev") | dev_index, 377 lv1_repository_string("type"), 0, &devtype, &junk); 378 379 if (result != 0) 380 continue; 381 382 result = lv1_get_repository_node_value(PS3_LPAR_ID_PME, 383 (lv1_repository_string("bus") >> 32) | bus_index, 384 lv1_repository_string("dev") | dev_index, 385 lv1_repository_string("id"), 0, &dev, &junk); 386 387 if (result != 0) 388 continue; 389 390 switch (devtype) { 391 case PS3_DEVTYPE_USB: 392 /* USB device has OHCI and EHCI USB host controllers */ 393 394 lv1_open_device(bus, dev, 0); 395 396 /* OHCI host controller */ 397 398 dinfo = malloc(sizeof(*dinfo), M_PS3BUS, 399 M_WAITOK | M_ZERO); 400 401 dinfo->bus = bus; 402 dinfo->dev = dev; 403 dinfo->bustype = bustype; 404 dinfo->devtype = devtype; 405 dinfo->busidx = bus_index; 406 dinfo->devidx = dev_index; 407 408 ps3bus_resources_init_by_type(&sc->sc_mem_rman, bus_index, 409 dev_index, OHCI_IRQ, OHCI_REG, dinfo); 410 411 cdev = device_add_child(self, "ohci", DEVICE_UNIT_ANY); 412 if (cdev == NULL) { 413 device_printf(self, 414 "device_add_child failed\n"); 415 free(dinfo, M_PS3BUS); 416 continue; 417 } 418 419 mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF); 420 device_set_ivars(cdev, dinfo); 421 422 /* EHCI host controller */ 423 424 dinfo = malloc(sizeof(*dinfo), M_PS3BUS, 425 M_WAITOK | M_ZERO); 426 427 dinfo->bus = bus; 428 dinfo->dev = dev; 429 dinfo->bustype = bustype; 430 dinfo->devtype = devtype; 431 dinfo->busidx = bus_index; 432 dinfo->devidx = dev_index; 433 434 ps3bus_resources_init_by_type(&sc->sc_mem_rman, bus_index, 435 dev_index, EHCI_IRQ, EHCI_REG, dinfo); 436 437 cdev = device_add_child(self, "ehci", DEVICE_UNIT_ANY); 438 if (cdev == NULL) { 439 device_printf(self, 440 "device_add_child failed\n"); 441 free(dinfo, M_PS3BUS); 442 continue; 443 } 444 445 mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF); 446 device_set_ivars(cdev, dinfo); 447 break; 448 default: 449 dinfo = malloc(sizeof(*dinfo), M_PS3BUS, 450 M_WAITOK | M_ZERO); 451 452 dinfo->bus = bus; 453 dinfo->dev = dev; 454 dinfo->bustype = bustype; 455 dinfo->devtype = devtype; 456 dinfo->busidx = bus_index; 457 dinfo->devidx = dev_index; 458 459 if (dinfo->bustype == PS3_BUSTYPE_SYSBUS || 460 dinfo->bustype == PS3_BUSTYPE_STORAGE) 461 lv1_open_device(bus, dev, 0); 462 463 ps3bus_resources_init(&sc->sc_mem_rman, bus_index, 464 dev_index, dinfo); 465 466 cdev = device_add_child(self, NULL, DEVICE_UNIT_ANY); 467 if (cdev == NULL) { 468 device_printf(self, 469 "device_add_child failed\n"); 470 free(dinfo, M_PS3BUS); 471 continue; 472 } 473 474 mtx_init(&dinfo->iommu_mtx, "iommu", NULL, MTX_DEF); 475 device_set_ivars(cdev, dinfo); 476 } 477 } 478 } 479 480 clock_register(self, 1000); 481 482 return (bus_generic_attach(self)); 483 } 484 485 static int 486 ps3bus_print_child(device_t dev, device_t child) 487 { 488 struct ps3bus_devinfo *dinfo = device_get_ivars(child); 489 int retval = 0; 490 491 retval += bus_print_child_header(dev, child); 492 retval += resource_list_print_type(&dinfo->resources, "mem", 493 SYS_RES_MEMORY, "%#jx"); 494 retval += resource_list_print_type(&dinfo->resources, "irq", 495 SYS_RES_IRQ, "%jd"); 496 497 retval += bus_print_child_footer(dev, child); 498 499 return (retval); 500 } 501 502 static int 503 ps3bus_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) 504 { 505 struct ps3bus_devinfo *dinfo = device_get_ivars(child); 506 507 switch (which) { 508 case PS3BUS_IVAR_BUS: 509 *result = dinfo->bus; 510 break; 511 case PS3BUS_IVAR_DEVICE: 512 *result = dinfo->dev; 513 break; 514 case PS3BUS_IVAR_BUSTYPE: 515 *result = dinfo->bustype; 516 break; 517 case PS3BUS_IVAR_DEVTYPE: 518 *result = dinfo->devtype; 519 break; 520 case PS3BUS_IVAR_BUSIDX: 521 *result = dinfo->busidx; 522 break; 523 case PS3BUS_IVAR_DEVIDX: 524 *result = dinfo->devidx; 525 break; 526 default: 527 return (EINVAL); 528 } 529 530 return (0); 531 } 532 533 static struct rman * 534 ps3bus_get_rman(device_t bus, int type, u_int flags) 535 { 536 struct ps3bus_softc *sc; 537 538 sc = device_get_softc(bus); 539 switch (type) { 540 case SYS_RES_MEMORY: 541 return (&sc->sc_mem_rman); 542 case SYS_RES_IRQ: 543 return (&sc->sc_intr_rman); 544 default: 545 return (NULL); 546 } 547 } 548 549 static struct resource * 550 ps3bus_alloc_resource(device_t bus, device_t child, int type, int *rid, 551 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 552 { 553 struct ps3bus_devinfo *dinfo; 554 rman_res_t adjstart, adjend, adjcount; 555 struct resource_list_entry *rle; 556 557 dinfo = device_get_ivars(child); 558 559 switch (type) { 560 case SYS_RES_MEMORY: 561 rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY, 562 *rid); 563 if (rle == NULL) { 564 device_printf(bus, "no rle for %s memory %d\n", 565 device_get_nameunit(child), *rid); 566 return (NULL); 567 } 568 569 if (start < rle->start) 570 adjstart = rle->start; 571 else if (start > rle->end) 572 adjstart = rle->end; 573 else 574 adjstart = start; 575 576 if (end < rle->start) 577 adjend = rle->start; 578 else if (end > rle->end) 579 adjend = rle->end; 580 else 581 adjend = end; 582 583 adjcount = adjend - adjstart; 584 break; 585 case SYS_RES_IRQ: 586 rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 587 *rid); 588 adjstart = rle->start; 589 adjcount = ulmax(count, rle->count); 590 adjend = ulmax(rle->end, rle->start + adjcount - 1); 591 break; 592 default: 593 device_printf(bus, "unknown resource request from %s\n", 594 device_get_nameunit(child)); 595 return (NULL); 596 } 597 598 return (bus_generic_rman_alloc_resource(bus, child, type, rid, adjstart, 599 adjend, adjcount, flags)); 600 } 601 602 static int 603 ps3bus_map_resource(device_t bus, device_t child, struct resource *r, 604 struct resource_map_request *argsp, struct resource_map *map) 605 { 606 struct resource_map_request args; 607 rman_res_t length, start; 608 int error; 609 610 /* Resources must be active to be mapped. */ 611 if (!(rman_get_flags(r) & RF_ACTIVE)) 612 return (ENXIO); 613 614 /* Mappings are only supported on memory resources. */ 615 switch (rman_get_type(r)) { 616 case SYS_RES_MEMORY: 617 break; 618 default: 619 return (EINVAL); 620 } 621 622 resource_init_map_request(&args); 623 error = resource_validate_map_request(r, argsp, &args, &start, &length); 624 if (error) 625 return (error); 626 627 if (bootverbose) 628 printf("ps3 mapdev: start %jx, len %jd\n", start, length); 629 630 map->r_vaddr = pmap_mapdev_attr(start, length, args.memattr); 631 if (map->r_vaddr == NULL) 632 return (ENOMEM); 633 map->r_bustag = &bs_be_tag; 634 map->r_bushandle = (vm_offset_t)map->r_vaddr; 635 map->r_size = length; 636 return (0); 637 } 638 639 static int 640 ps3bus_unmap_resource(device_t bus, device_t child, struct resource *r, 641 struct resource_map *map) 642 { 643 644 switch (rman_get_type(r)) { 645 case SYS_RES_MEMORY: 646 pmap_unmapdev(map->r_vaddr, map->r_size); 647 return (0); 648 default: 649 return (EINVAL); 650 } 651 } 652 653 static bus_dma_tag_t 654 ps3bus_get_dma_tag(device_t dev, device_t child) 655 { 656 struct ps3bus_devinfo *dinfo = device_get_ivars(child); 657 struct ps3bus_softc *sc = device_get_softc(dev); 658 int i, err, flags, pagesize; 659 660 if (dinfo->bustype != PS3_BUSTYPE_SYSBUS && 661 dinfo->bustype != PS3_BUSTYPE_STORAGE) 662 return (bus_get_dma_tag(dev)); 663 664 mtx_lock(&dinfo->iommu_mtx); 665 if (dinfo->dma_tag != NULL) { 666 mtx_unlock(&dinfo->iommu_mtx); 667 return (dinfo->dma_tag); 668 } 669 670 flags = 0; /* 32-bit mode */ 671 if (dinfo->bustype == PS3_BUSTYPE_SYSBUS && 672 dinfo->devtype == PS3_DEVTYPE_USB) 673 flags = 2; /* 8-bit mode */ 674 675 pagesize = 24; /* log_2(16 MB) */ 676 if (dinfo->bustype == PS3_BUSTYPE_STORAGE) 677 pagesize = 12; /* 4 KB */ 678 679 for (i = 0; i < sc->rcount; i++) { 680 err = lv1_allocate_device_dma_region(dinfo->bus, dinfo->dev, 681 sc->regions[i].mr_size, pagesize, flags, 682 &dinfo->dma_base[i]); 683 if (err != 0) { 684 device_printf(child, 685 "could not allocate DMA region %d: %d\n", i, err); 686 goto fail; 687 } 688 689 err = lv1_map_device_dma_region(dinfo->bus, dinfo->dev, 690 sc->regions[i].mr_start, dinfo->dma_base[i], 691 sc->regions[i].mr_size, 692 0xf800000000000800UL /* Cell Handbook Figure 7.3.4.1 */); 693 if (err != 0) { 694 device_printf(child, 695 "could not map DMA region %d: %d\n", i, err); 696 goto fail; 697 } 698 } 699 700 err = bus_dma_tag_create(bus_get_dma_tag(dev), 701 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, 702 NULL, NULL, BUS_SPACE_MAXSIZE, 0, BUS_SPACE_MAXSIZE, 703 0, NULL, NULL, &dinfo->dma_tag); 704 705 /* 706 * Note: storage devices have IOMMU mappings set up by the hypervisor, 707 * but use physical, non-translated addresses. The above IOMMU 708 * initialization is necessary for the hypervisor to be able to set up 709 * the mappings, but actual DMA mappings should not use the IOMMU 710 * routines. 711 */ 712 if (dinfo->bustype != PS3_BUSTYPE_STORAGE) 713 bus_dma_tag_set_iommu(dinfo->dma_tag, dev, dinfo); 714 715 fail: 716 mtx_unlock(&dinfo->iommu_mtx); 717 718 if (err) 719 return (NULL); 720 721 return (dinfo->dma_tag); 722 } 723 724 static int 725 ps3_iommu_map(device_t dev, bus_dma_segment_t *segs, int *nsegs, 726 bus_addr_t min, bus_addr_t max, bus_size_t alignment, bus_addr_t boundary, 727 void *cookie) 728 { 729 struct ps3bus_devinfo *dinfo = cookie; 730 struct ps3bus_softc *sc = device_get_softc(dev); 731 int i, j; 732 733 for (i = 0; i < *nsegs; i++) { 734 for (j = 0; j < sc->rcount; j++) { 735 if (segs[i].ds_addr >= sc->regions[j].mr_start && 736 segs[i].ds_addr < sc->regions[j].mr_start + 737 sc->regions[j].mr_size) 738 break; 739 } 740 KASSERT(j < sc->rcount, 741 ("Trying to map address %#lx not in physical memory", 742 segs[i].ds_addr)); 743 744 segs[i].ds_addr = dinfo->dma_base[j] + 745 (segs[i].ds_addr - sc->regions[j].mr_start); 746 } 747 748 return (0); 749 } 750 751 static int 752 ps3_iommu_unmap(device_t dev, bus_dma_segment_t *segs, int nsegs, void *cookie) 753 { 754 755 return (0); 756 } 757 758 #define Y2K 946684800 759 760 static int 761 ps3_gettime(device_t dev, struct timespec *ts) 762 { 763 uint64_t rtc, tb; 764 int result; 765 766 result = lv1_get_rtc(&rtc, &tb); 767 if (result) 768 return (result); 769 770 ts->tv_sec = rtc + Y2K; 771 ts->tv_nsec = 0; 772 return (0); 773 } 774 775 static int 776 ps3_settime(device_t dev, struct timespec *ts) 777 { 778 return (-1); 779 } 780