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

Cache object: c6892e75562a29aad28f6c1020e10918


[ 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.