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/dev/ofw/ofw_pcib.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) 2011 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 AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 #include <sys/module.h>
   32 #include <sys/bus.h>
   33 #include <sys/conf.h>
   34 #include <sys/kernel.h>
   35 #include <sys/rman.h>
   36 
   37 #include <dev/ofw/openfirm.h>
   38 #include <dev/ofw/ofw_pci.h>
   39 #include <dev/ofw/ofw_bus.h>
   40 #include <dev/ofw/ofw_bus_subr.h>
   41 #include <dev/ofw/ofwpci.h>
   42 
   43 #include <dev/pci/pcivar.h>
   44 #include <dev/pci/pcireg.h>
   45 #include <dev/pci/pcib_private.h>
   46 
   47 #include <machine/bus.h>
   48 #include <machine/md_var.h>
   49 #include <machine/resource.h>
   50 
   51 #include <vm/vm.h>
   52 #include <vm/pmap.h>
   53 
   54 #include "pcib_if.h"
   55 
   56 /*
   57  * If it is necessary to set another value of this for
   58  * some platforms it should be set at fdt.h file
   59  */
   60 #ifndef PCI_MAP_INTR
   61 #define PCI_MAP_INTR    4
   62 #endif
   63 
   64 #define PCI_INTR_PINS   4
   65 
   66 /*
   67  * bus interface.
   68  */
   69 static struct resource * ofw_pcib_alloc_resource(device_t, device_t,
   70     int, int *, rman_res_t, rman_res_t, rman_res_t, u_int);
   71 static int ofw_pcib_release_resource(device_t, device_t, int, int,
   72     struct resource *);
   73 static int ofw_pcib_activate_resource(device_t, device_t, int, int,
   74     struct resource *);
   75 static int ofw_pcib_deactivate_resource(device_t, device_t, int, int,
   76     struct resource *);
   77 static int ofw_pcib_adjust_resource(device_t, device_t, int,
   78     struct resource *, rman_res_t, rman_res_t);
   79 static int ofw_pcib_translate_resource(device_t bus, int type,
   80         rman_res_t start, rman_res_t *newstart);
   81 
   82 #ifdef __powerpc__
   83 static bus_space_tag_t ofw_pcib_bus_get_bus_tag(device_t, device_t);
   84 #endif
   85 
   86 /*
   87  * pcib interface
   88  */
   89 static int ofw_pcib_maxslots(device_t);
   90 
   91 /*
   92  * ofw_bus interface
   93  */
   94 static phandle_t ofw_pcib_get_node(device_t, device_t);
   95 
   96 /*
   97  * local methods
   98  */
   99 static int ofw_pcib_fill_ranges(phandle_t, struct ofw_pci_range *);
  100 static struct rman *ofw_pcib_get_rman(struct ofw_pci_softc *, int, u_int);
  101 
  102 /*
  103  * Driver methods.
  104  */
  105 static device_method_t  ofw_pcib_methods[] = {
  106         /* Device interface */
  107         DEVMETHOD(device_attach,        ofw_pcib_attach),
  108 
  109         /* Bus interface */
  110         DEVMETHOD(bus_print_child,      bus_generic_print_child),
  111         DEVMETHOD(bus_read_ivar,        ofw_pcib_read_ivar),
  112         DEVMETHOD(bus_write_ivar,       ofw_pcib_write_ivar),
  113         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
  114         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
  115         DEVMETHOD(bus_alloc_resource,   ofw_pcib_alloc_resource),
  116         DEVMETHOD(bus_release_resource, ofw_pcib_release_resource),
  117         DEVMETHOD(bus_activate_resource,        ofw_pcib_activate_resource),
  118         DEVMETHOD(bus_deactivate_resource,      ofw_pcib_deactivate_resource),
  119         DEVMETHOD(bus_adjust_resource,  ofw_pcib_adjust_resource),
  120         DEVMETHOD(bus_translate_resource,       ofw_pcib_translate_resource),
  121 #ifdef __powerpc__
  122         DEVMETHOD(bus_get_bus_tag,      ofw_pcib_bus_get_bus_tag),
  123 #endif
  124 
  125         /* pcib interface */
  126         DEVMETHOD(pcib_maxslots,        ofw_pcib_maxslots),
  127         DEVMETHOD(pcib_route_interrupt, ofw_pcib_route_interrupt),
  128         DEVMETHOD(pcib_request_feature, pcib_request_feature_allow),
  129 
  130         /* ofw_bus interface */
  131         DEVMETHOD(ofw_bus_get_node,     ofw_pcib_get_node),
  132 
  133         DEVMETHOD_END
  134 };
  135 
  136 DEFINE_CLASS_0(ofw_pcib, ofw_pcib_driver, ofw_pcib_methods, 0);
  137 
  138 int
  139 ofw_pcib_init(device_t dev)
  140 {
  141         struct ofw_pci_softc *sc;
  142         phandle_t node;
  143         u_int32_t busrange[2];
  144         struct ofw_pci_range *rp;
  145         int i, error;
  146         struct ofw_pci_cell_info *cell_info;
  147 
  148         node = ofw_bus_get_node(dev);
  149         sc = device_get_softc(dev);
  150         sc->sc_initialized = 1;
  151         sc->sc_range = NULL;
  152         sc->sc_pci_domain = device_get_unit(dev);
  153 
  154         cell_info = (struct ofw_pci_cell_info *)malloc(sizeof(*cell_info),
  155             M_DEVBUF, M_WAITOK | M_ZERO);
  156 
  157         sc->sc_cell_info = cell_info;
  158 
  159         if (OF_getencprop(node, "bus-range", busrange, sizeof(busrange)) != 8)
  160                 busrange[0] = 0;
  161 
  162         sc->sc_dev = dev;
  163         sc->sc_node = node;
  164         sc->sc_bus = busrange[0];
  165 
  166         if (sc->sc_quirks & OFW_PCI_QUIRK_RANGES_ON_CHILDREN) {
  167                 phandle_t c;
  168                 int n, i;
  169 
  170                 sc->sc_nrange = 0;
  171                 for (c = OF_child(node); c != 0; c = OF_peer(c)) {
  172                         n = ofw_pcib_nranges(c, cell_info);
  173                         if (n > 0)
  174                                 sc->sc_nrange += n;
  175                 }
  176                 if (sc->sc_nrange == 0) {
  177                         error = ENXIO;
  178                         goto out;
  179                 }
  180                 sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
  181                     M_DEVBUF, M_WAITOK);
  182                 i = 0;
  183                 for (c = OF_child(node); c != 0; c = OF_peer(c)) {
  184                         n = ofw_pcib_fill_ranges(c, &sc->sc_range[i]);
  185                         if (n > 0)
  186                                 i += n;
  187                 }
  188                 KASSERT(i == sc->sc_nrange, ("range count mismatch"));
  189         } else {
  190                 sc->sc_nrange = ofw_pcib_nranges(node, cell_info);
  191                 if (sc->sc_nrange <= 0) {
  192                         device_printf(dev, "could not getranges\n");
  193                         error = ENXIO;
  194                         goto out;
  195                 }
  196                 sc->sc_range = malloc(sc->sc_nrange * sizeof(sc->sc_range[0]),
  197                     M_DEVBUF, M_WAITOK);
  198                 ofw_pcib_fill_ranges(node, sc->sc_range);
  199         }
  200 
  201         sc->sc_io_rman.rm_type = RMAN_ARRAY;
  202         sc->sc_io_rman.rm_descr = "PCI I/O Ports";
  203         error = rman_init(&sc->sc_io_rman);
  204         if (error != 0) {
  205                 device_printf(dev, "rman_init() failed. error = %d\n", error);
  206                 goto out;
  207         }
  208 
  209         sc->sc_mem_rman.rm_type = RMAN_ARRAY;
  210         sc->sc_mem_rman.rm_descr = "PCI Non Prefetchable Memory";
  211         error = rman_init(&sc->sc_mem_rman);
  212         if (error != 0) {
  213                 device_printf(dev, "rman_init() failed. error = %d\n", error);
  214                 goto out_mem_rman;
  215         }
  216 
  217         sc->sc_pmem_rman.rm_type = RMAN_ARRAY;
  218         sc->sc_pmem_rman.rm_descr = "PCI Prefetchable Memory";
  219         error = rman_init(&sc->sc_pmem_rman);
  220         if (error != 0) {
  221                 device_printf(dev, "rman_init() failed. error = %d\n", error);
  222                 goto out_pmem_rman;
  223         }
  224 
  225         for (i = 0; i < sc->sc_nrange; i++) {
  226                 error = 0;
  227                 rp = sc->sc_range + i;
  228 
  229                 if (sc->sc_range_mask & ((uint64_t)1 << i))
  230                         continue;
  231                 switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
  232                 case OFW_PCI_PHYS_HI_SPACE_CONFIG:
  233                         break;
  234                 case OFW_PCI_PHYS_HI_SPACE_IO:
  235                         error = rman_manage_region(&sc->sc_io_rman, rp->pci,
  236                             rp->pci + rp->size - 1);
  237                         break;
  238                 case OFW_PCI_PHYS_HI_SPACE_MEM32:
  239                 case OFW_PCI_PHYS_HI_SPACE_MEM64:
  240                         if (rp->pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) {
  241                                 sc->sc_have_pmem = 1;
  242                                 error = rman_manage_region(&sc->sc_pmem_rman,
  243                                     rp->pci, rp->pci + rp->size - 1);
  244                         } else {
  245                                 error = rman_manage_region(&sc->sc_mem_rman,
  246                                     rp->pci, rp->pci + rp->size - 1);
  247                         }
  248                         break;
  249                 }
  250 
  251                 if (error != 0) {
  252                         device_printf(dev,
  253                             "rman_manage_region(%x, %#jx, %#jx) failed. "
  254                             "error = %d\n", rp->pci_hi &
  255                             OFW_PCI_PHYS_HI_SPACEMASK, rp->pci,
  256                             rp->pci + rp->size - 1, error);
  257                         goto out_full;
  258                 }
  259         }
  260 
  261         ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t));
  262         return (0);
  263 
  264 out_full:
  265         rman_fini(&sc->sc_pmem_rman);
  266 out_pmem_rman:
  267         rman_fini(&sc->sc_mem_rman);
  268 out_mem_rman:
  269         rman_fini(&sc->sc_io_rman);
  270 out:
  271         free(sc->sc_cell_info, M_DEVBUF);
  272         free(sc->sc_range, M_DEVBUF);
  273 
  274         return (error);
  275 }
  276 
  277 void
  278 ofw_pcib_fini(device_t dev)
  279 {
  280         struct ofw_pci_softc *sc;
  281 
  282         sc = device_get_softc(dev);
  283         free(sc->sc_cell_info, M_DEVBUF);
  284         free(sc->sc_range, M_DEVBUF);
  285         rman_fini(&sc->sc_io_rman);
  286         rman_fini(&sc->sc_mem_rman);
  287         rman_fini(&sc->sc_pmem_rman);
  288 }
  289 
  290 int
  291 ofw_pcib_attach(device_t dev)
  292 {
  293         struct ofw_pci_softc *sc;
  294         int error;
  295 
  296         sc = device_get_softc(dev);
  297         if (!sc->sc_initialized) {
  298                 error = ofw_pcib_init(dev);
  299                 if (error != 0)
  300                         return (error);
  301         }
  302 
  303         device_add_child(dev, "pci", -1);
  304         return (bus_generic_attach(dev));
  305 }
  306 
  307 static int
  308 ofw_pcib_maxslots(device_t dev)
  309 {
  310 
  311         return (PCI_SLOTMAX);
  312 }
  313 
  314 int
  315 ofw_pcib_route_interrupt(device_t bus, device_t dev, int pin)
  316 {
  317         struct ofw_pci_softc *sc;
  318         struct ofw_pci_register reg;
  319         uint32_t pintr, mintr[PCI_MAP_INTR];
  320         int intrcells;
  321         phandle_t iparent;
  322 
  323         sc = device_get_softc(bus);
  324         pintr = pin;
  325 
  326         /* Fabricate imap information in case this isn't an OFW device */
  327         bzero(&reg, sizeof(reg));
  328         reg.phys_hi = (pci_get_bus(dev) << OFW_PCI_PHYS_HI_BUSSHIFT) |
  329             (pci_get_slot(dev) << OFW_PCI_PHYS_HI_DEVICESHIFT) |
  330             (pci_get_function(dev) << OFW_PCI_PHYS_HI_FUNCTIONSHIFT);
  331 
  332         intrcells = ofw_bus_lookup_imap(ofw_bus_get_node(dev),
  333             &sc->sc_pci_iinfo, &reg, sizeof(reg), &pintr, sizeof(pintr),
  334             mintr, sizeof(mintr), &iparent);
  335         if (intrcells != 0) {
  336                 pintr = ofw_bus_map_intr(dev, iparent, intrcells, mintr);
  337                 return (pintr);
  338         }
  339 
  340         /*
  341          * Maybe it's a real interrupt, not an intpin
  342          */
  343         if (pin > PCI_INTR_PINS)
  344                 return (pin);
  345 
  346         device_printf(bus, "could not route pin %d for device %d.%d\n",
  347             pin, pci_get_slot(dev), pci_get_function(dev));
  348         return (PCI_INVALID_IRQ);
  349 }
  350 
  351 int
  352 ofw_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
  353 {
  354         struct ofw_pci_softc *sc;
  355 
  356         sc = device_get_softc(dev);
  357 
  358         switch (which) {
  359         case PCIB_IVAR_DOMAIN:
  360                 *result = sc->sc_pci_domain;
  361                 return (0);
  362         case PCIB_IVAR_BUS:
  363                 *result = sc->sc_bus;
  364                 return (0);
  365         default:
  366                 break;
  367         }
  368 
  369         return (ENOENT);
  370 }
  371 
  372 int
  373 ofw_pcib_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
  374 {
  375         struct ofw_pci_softc *sc;
  376 
  377         sc = device_get_softc(dev);
  378 
  379         switch (which) {
  380         case PCIB_IVAR_BUS:
  381                 sc->sc_bus = value;
  382                 return (0);
  383         default:
  384                 break;
  385         }
  386 
  387         return (ENOENT);
  388 }
  389 
  390 int
  391 ofw_pcib_nranges(phandle_t node, struct ofw_pci_cell_info *info)
  392 {
  393         ssize_t nbase_ranges;
  394 
  395         if (info == NULL)
  396                 return (-1);
  397 
  398         info->host_address_cells = 1;
  399         info->size_cells = 2;
  400         info->pci_address_cell = 3;
  401 
  402         OF_getencprop(OF_parent(node), "#address-cells",
  403             &(info->host_address_cells), sizeof(info->host_address_cells));
  404         OF_getencprop(node, "#address-cells",
  405             &(info->pci_address_cell), sizeof(info->pci_address_cell));
  406         OF_getencprop(node, "#size-cells", &(info->size_cells),
  407             sizeof(info->size_cells));
  408 
  409         nbase_ranges = OF_getproplen(node, "ranges");
  410         if (nbase_ranges <= 0)
  411                 return (-1);
  412 
  413         return (nbase_ranges / sizeof(cell_t) /
  414             (info->pci_address_cell + info->host_address_cells +
  415             info->size_cells));
  416 }
  417 
  418 static struct resource *
  419 ofw_pcib_alloc_resource(device_t bus, device_t child, int type, int *rid,
  420     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
  421 {
  422         struct ofw_pci_softc *sc;
  423         struct resource *rv;
  424         struct rman *rm;
  425         int needactivate;
  426 
  427         needactivate = flags & RF_ACTIVE;
  428         flags &= ~RF_ACTIVE;
  429 
  430         sc = device_get_softc(bus);
  431 
  432 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
  433         if (type ==  PCI_RES_BUS) {
  434                   return (pci_domain_alloc_bus(sc->sc_pci_domain, child, rid,
  435                       start, end, count, flags | needactivate));
  436         }
  437 #endif
  438 
  439         rm = ofw_pcib_get_rman(sc, type, flags);
  440         if (rm == NULL)  {
  441                 return (bus_generic_alloc_resource(bus, child, type, rid,
  442                     start, end, count, flags | needactivate));
  443         }
  444 
  445         rv = rman_reserve_resource(rm, start, end, count, flags, child);
  446         if (rv == NULL) {
  447                 device_printf(bus, "failed to reserve resource for %s\n",
  448                     device_get_nameunit(child));
  449                 return (NULL);
  450         }
  451 
  452         rman_set_rid(rv, *rid);
  453 
  454         if (needactivate) {
  455                 if (bus_activate_resource(child, type, *rid, rv) != 0) {
  456                         device_printf(bus,
  457                             "failed to activate resource for %s\n",
  458                             device_get_nameunit(child));
  459                         rman_release_resource(rv);
  460                         return (NULL);
  461                 }
  462         }
  463 
  464         return (rv);
  465 }
  466 
  467 static int
  468 ofw_pcib_release_resource(device_t bus, device_t child, int type, int rid,
  469     struct resource *res)
  470 {
  471         struct ofw_pci_softc *sc;
  472         struct rman *rm;
  473         int error;
  474 
  475         sc = device_get_softc(bus);
  476 
  477 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
  478         if (type == PCI_RES_BUS)
  479                 return (pci_domain_release_bus(sc->sc_pci_domain, child, rid,
  480                     res));
  481 #endif
  482 
  483         rm = ofw_pcib_get_rman(sc, type, rman_get_flags(res));
  484         if (rm == NULL) {
  485                 return (bus_generic_release_resource(bus, child, type, rid,
  486                     res));
  487         }
  488         KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
  489 
  490         if (rman_get_flags(res) & RF_ACTIVE) {
  491                 error = bus_deactivate_resource(child, type, rid, res);
  492                 if (error != 0)
  493                         return (error);
  494         }
  495         return (rman_release_resource(res));
  496 }
  497 
  498 static int
  499 ofw_pcib_translate_resource(device_t bus, int type, rman_res_t start,
  500         rman_res_t *newstart)
  501 {
  502         struct ofw_pci_softc *sc;
  503         struct ofw_pci_range *rp;
  504         int space;
  505 
  506         sc = device_get_softc(bus);
  507 
  508         /*
  509          * Map this through the ranges list
  510          */
  511         for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
  512             rp->pci_hi != 0; rp++) {
  513                 if (start < rp->pci || start >= rp->pci + rp->size)
  514                         continue;
  515 
  516                 switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
  517                 case OFW_PCI_PHYS_HI_SPACE_IO:
  518                         space = SYS_RES_IOPORT;
  519                         break;
  520                 case OFW_PCI_PHYS_HI_SPACE_MEM32:
  521                 case OFW_PCI_PHYS_HI_SPACE_MEM64:
  522                         space = SYS_RES_MEMORY;
  523                         break;
  524                 default:
  525                         space = -1;
  526                 }
  527 
  528                 if (type == space) {
  529                         start += (rp->host - rp->pci);
  530                         *newstart = start;
  531                         return (0);
  532                 }
  533         }
  534         return (ENOENT);
  535 }
  536 
  537 static int
  538 ofw_pcib_activate_resource(device_t bus, device_t child, int type, int rid,
  539     struct resource *res)
  540 {
  541         struct ofw_pci_softc *sc;
  542         bus_space_handle_t handle;
  543         bus_space_tag_t tag;
  544         struct ofw_pci_range *rp;
  545         vm_paddr_t start;
  546         int space;
  547         int rv;
  548 
  549         sc = device_get_softc(bus);
  550 
  551         if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) {
  552                 return (bus_generic_activate_resource(bus, child, type, rid,
  553                     res));
  554         }
  555 
  556         start = (vm_paddr_t)rman_get_start(res);
  557 
  558         /*
  559          * Map this through the ranges list
  560          */
  561         for (rp = sc->sc_range; rp < sc->sc_range + sc->sc_nrange &&
  562             rp->pci_hi != 0; rp++) {
  563                 if (start < rp->pci || start >= rp->pci + rp->size)
  564                         continue;
  565 
  566                 switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) {
  567                 case OFW_PCI_PHYS_HI_SPACE_IO:
  568                         space = SYS_RES_IOPORT;
  569                         break;
  570                 case OFW_PCI_PHYS_HI_SPACE_MEM32:
  571                 case OFW_PCI_PHYS_HI_SPACE_MEM64:
  572                         space = SYS_RES_MEMORY;
  573                         break;
  574                 default:
  575                         space = -1;
  576                         }
  577 
  578                 if (type == space) {
  579                         start += (rp->host - rp->pci);
  580                         break;
  581                 }
  582         }
  583 
  584         if (bootverbose)
  585                 printf("ofw_pci mapdev: start %jx, len %jd\n",
  586                     (rman_res_t)start, rman_get_size(res));
  587 
  588         tag = BUS_GET_BUS_TAG(child, child);
  589         if (tag == NULL)
  590                 return (ENOMEM);
  591 
  592         rman_set_bustag(res, tag);
  593         rv = bus_space_map(tag, start,
  594             rman_get_size(res), 0, &handle);
  595         if (rv != 0)
  596                 return (ENOMEM);
  597 
  598         rman_set_bushandle(res, handle);
  599         rman_set_virtual(res, (void *)handle); /* XXX  for powerpc only ? */
  600 
  601         return (rman_activate_resource(res));
  602 }
  603 
  604 #ifdef __powerpc__
  605 static bus_space_tag_t
  606 ofw_pcib_bus_get_bus_tag(device_t bus, device_t child)
  607 {
  608 
  609         return (&bs_le_tag);
  610 }
  611 #endif
  612 
  613 static int
  614 ofw_pcib_deactivate_resource(device_t bus, device_t child, int type, int rid,
  615     struct resource *res)
  616 {
  617         vm_size_t psize;
  618 
  619         if (type != SYS_RES_IOPORT && type != SYS_RES_MEMORY) {
  620                 return (bus_generic_deactivate_resource(bus, child, type, rid,
  621                     res));
  622         }
  623 
  624         psize = rman_get_size(res);
  625         pmap_unmapdev(rman_get_virtual(res), psize);
  626 
  627         return (rman_deactivate_resource(res));
  628 }
  629 
  630 static int
  631 ofw_pcib_adjust_resource(device_t bus, device_t child, int type,
  632     struct resource *res, rman_res_t start, rman_res_t end)
  633 {
  634         struct rman *rm;
  635         struct ofw_pci_softc *sc;
  636 
  637         sc = device_get_softc(bus);
  638 #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
  639         if (type == PCI_RES_BUS)
  640                 return (pci_domain_adjust_bus(sc->sc_pci_domain, child, res,
  641                     start, end));
  642 #endif
  643 
  644         rm = ofw_pcib_get_rman(sc, type, rman_get_flags(res));
  645         if (rm == NULL) {
  646                 return (bus_generic_adjust_resource(bus, child, type, res,
  647                     start, end));
  648         }
  649         KASSERT(rman_is_region_manager(res, rm), ("rman mismatch"));
  650         KASSERT(!(rman_get_flags(res) & RF_ACTIVE),
  651             ("active resources cannot be adjusted"));
  652 
  653         return (rman_adjust_resource(res, start, end));
  654 }
  655 
  656 static phandle_t
  657 ofw_pcib_get_node(device_t bus, device_t dev)
  658 {
  659         struct ofw_pci_softc *sc;
  660 
  661         sc = device_get_softc(bus);
  662         /* We only have one child, the PCI bus, which needs our own node. */
  663 
  664         return (sc->sc_node);
  665 }
  666 
  667 static int
  668 ofw_pcib_fill_ranges(phandle_t node, struct ofw_pci_range *ranges)
  669 {
  670         int host_address_cells = 1, pci_address_cells = 3, size_cells = 2;
  671         cell_t *base_ranges;
  672         ssize_t nbase_ranges;
  673         int nranges;
  674         int i, j, k;
  675 
  676         OF_getencprop(OF_parent(node), "#address-cells", &host_address_cells,
  677             sizeof(host_address_cells));
  678         OF_getencprop(node, "#address-cells", &pci_address_cells,
  679             sizeof(pci_address_cells));
  680         OF_getencprop(node, "#size-cells", &size_cells, sizeof(size_cells));
  681 
  682         nbase_ranges = OF_getproplen(node, "ranges");
  683         if (nbase_ranges <= 0)
  684                 return (-1);
  685         nranges = nbase_ranges / sizeof(cell_t) /
  686             (pci_address_cells + host_address_cells + size_cells);
  687 
  688         base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
  689         OF_getencprop(node, "ranges", base_ranges, nbase_ranges);
  690 
  691         for (i = 0, j = 0; i < nranges; i++) {
  692                 ranges[i].pci_hi = base_ranges[j++];
  693                 ranges[i].pci = 0;
  694                 for (k = 0; k < pci_address_cells - 1; k++) {
  695                         ranges[i].pci <<= 32;
  696                         ranges[i].pci |= base_ranges[j++];
  697                 }
  698                 ranges[i].host = 0;
  699                 for (k = 0; k < host_address_cells; k++) {
  700                         ranges[i].host <<= 32;
  701                         ranges[i].host |= base_ranges[j++];
  702                 }
  703                 ranges[i].size = 0;
  704                 for (k = 0; k < size_cells; k++) {
  705                         ranges[i].size <<= 32;
  706                         ranges[i].size |= base_ranges[j++];
  707                 }
  708         }
  709 
  710         free(base_ranges, M_DEVBUF);
  711         return (nranges);
  712 }
  713 
  714 static struct rman *
  715 ofw_pcib_get_rman(struct ofw_pci_softc *sc, int type, u_int flags)
  716 {
  717 
  718         switch (type) {
  719         case SYS_RES_IOPORT:
  720                 return (&sc->sc_io_rman);
  721         case SYS_RES_MEMORY:
  722                 if (sc->sc_have_pmem  && (flags & RF_PREFETCHABLE))
  723                         return (&sc->sc_pmem_rman);
  724                 else
  725                         return (&sc->sc_mem_rman);
  726         default:
  727                 break;
  728         }
  729 
  730         return (NULL);
  731 }

Cache object: a89f87d10a58bdb1662cadb5da51b68f


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