The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/powerpc/ps3/ps3bus.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: ed4713fd097a9d9d497f31707db02801


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.