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/sparc64/ebus/ebus.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) 1999, 2000 Matthew R. Green
    3  * Copyright (c) 2009 by Marius Strobl <marius@FreeBSD.org>
    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  * 3. The name of the author may not be used to endorse or promote products
   15  *    derived from this software without specific prior written permission.
   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 THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  *      from: NetBSD: ebus.c,v 1.52 2008/05/29 14:51:26 mrg Exp
   30  */
   31 /*-
   32  * Copyright (c) 2001 Thomas Moestl <tmm@FreeBSD.org>
   33  * All rights reserved.
   34  *
   35  * Redistribution and use in source and binary forms, with or without
   36  * modification, are permitted provided that the following conditions
   37  * are met:
   38  * 1. Redistributions of source code must retain the above copyright
   39  *    notice, this list of conditions and the following disclaimer.
   40  * 2. Redistributions in binary form must reproduce the above copyright
   41  *    notice, this list of conditions and the following disclaimer in the
   42  *    documentation and/or other materials provided with the distribution.
   43  * 3. The name of the author may not be used to endorse or promote products
   44  *    derived from this software without specific prior written permission.
   45  *
   46  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   47  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   48  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   49  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   50  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   51  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   52  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   53  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   54  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   56  * SUCH DAMAGE.
   57  */
   58 
   59 #include <sys/cdefs.h>
   60 __FBSDID("$FreeBSD: releng/11.0/sys/sparc64/ebus/ebus.c 300173 2016-05-18 23:39:31Z gonzo $");
   61 
   62 /*
   63  * Driver for JBus to EBus and PCI to EBus bridges
   64  */
   65 
   66 #include <sys/param.h>
   67 #include <sys/systm.h>
   68 #include <sys/bus.h>
   69 #include <sys/kernel.h>
   70 #include <sys/malloc.h>
   71 #include <sys/module.h>
   72 #include <sys/rman.h>
   73 
   74 #include <dev/ofw/ofw_bus.h>
   75 #include <dev/ofw/ofw_bus_subr.h>
   76 #include <dev/ofw/openfirm.h>
   77 
   78 #include <machine/bus.h>
   79 #ifndef SUN4V
   80 #include <machine/bus_common.h>
   81 #endif
   82 #include <machine/intr_machdep.h>
   83 #include <machine/resource.h>
   84 
   85 #include <dev/pci/pcireg.h>
   86 #include <dev/pci/pcivar.h>
   87 
   88 #include <sparc64/pci/ofw_pci.h>
   89 
   90 /*
   91  * The register, interrupt map and for the PCI variant also the ranges
   92  * properties are identical to the ISA ones.
   93  */
   94 #include <sparc64/isa/ofw_isa.h>
   95 
   96 struct ebus_nexus_ranges {
   97         uint32_t        child_hi;
   98         uint32_t        child_lo;
   99         uint32_t        phys_hi;
  100         uint32_t        phys_lo;
  101         uint32_t        size;
  102 };
  103 
  104 struct ebus_devinfo {
  105         struct ofw_bus_devinfo  edi_obdinfo;
  106         struct resource_list    edi_rl;
  107 };
  108 
  109 struct ebus_rinfo {
  110         int                     eri_rtype;
  111         struct rman             eri_rman;
  112         struct resource         *eri_res;
  113 };
  114 
  115 struct ebus_softc {
  116         void                    *sc_range;
  117         struct ebus_rinfo       *sc_rinfo;
  118 
  119         u_int                   sc_flags;
  120 #define EBUS_PCI                (1 << 0)
  121 
  122         int                     sc_nrange;
  123 
  124         struct ofw_bus_iinfo    sc_iinfo;
  125 
  126 #ifndef SUN4V
  127         uint32_t                sc_ign;
  128 #endif
  129 };
  130 
  131 static device_probe_t ebus_nexus_probe;
  132 static device_attach_t ebus_nexus_attach;
  133 static device_probe_t ebus_pci_probe;
  134 static device_attach_t ebus_pci_attach;
  135 static bus_print_child_t ebus_print_child;
  136 static bus_probe_nomatch_t ebus_probe_nomatch;
  137 static bus_alloc_resource_t ebus_alloc_resource;
  138 static bus_activate_resource_t ebus_activate_resource;
  139 static bus_adjust_resource_t ebus_adjust_resource;
  140 static bus_release_resource_t ebus_release_resource;
  141 static bus_setup_intr_t ebus_setup_intr;
  142 static bus_get_resource_list_t ebus_get_resource_list;
  143 static ofw_bus_get_devinfo_t ebus_get_devinfo;
  144 
  145 static int ebus_attach(device_t dev, struct ebus_softc *sc, phandle_t node);
  146 static struct ebus_devinfo *ebus_setup_dinfo(device_t dev,
  147     struct ebus_softc *sc, phandle_t node);
  148 static void ebus_destroy_dinfo(struct ebus_devinfo *edi);
  149 static int ebus_print_res(struct ebus_devinfo *edi);
  150 
  151 static devclass_t ebus_devclass;
  152 
  153 static device_method_t ebus_nexus_methods[] = {
  154         /* Device interface */
  155         DEVMETHOD(device_probe,         ebus_nexus_probe),
  156         DEVMETHOD(device_attach,        ebus_nexus_attach),
  157         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  158         DEVMETHOD(device_suspend,       bus_generic_suspend),
  159         DEVMETHOD(device_resume,        bus_generic_resume),
  160 
  161         /* Bus interface */
  162         DEVMETHOD(bus_print_child,      ebus_print_child),
  163         DEVMETHOD(bus_probe_nomatch,    ebus_probe_nomatch),
  164         DEVMETHOD(bus_alloc_resource,   ebus_alloc_resource),
  165         DEVMETHOD(bus_activate_resource, ebus_activate_resource),
  166         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
  167         DEVMETHOD(bus_adjust_resource,  ebus_adjust_resource),
  168         DEVMETHOD(bus_release_resource, ebus_release_resource),
  169         DEVMETHOD(bus_setup_intr,       ebus_setup_intr),
  170         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
  171         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
  172         DEVMETHOD(bus_get_resource_list, ebus_get_resource_list),
  173         DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
  174 
  175         /* ofw_bus interface */
  176         DEVMETHOD(ofw_bus_get_devinfo,  ebus_get_devinfo),
  177         DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
  178         DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
  179         DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
  180         DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
  181         DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
  182 
  183         DEVMETHOD_END
  184 };
  185 
  186 static driver_t ebus_nexus_driver = {
  187         "ebus",
  188         ebus_nexus_methods,
  189         sizeof(struct ebus_softc),
  190 };
  191 
  192 /*
  193  * NB: we rely on the interrupt controllers of the accompanying PCI-Express
  194  * bridge to be registered as the nexus variant of the EBus bridges doesn't
  195  * employ its own one.
  196  */
  197 EARLY_DRIVER_MODULE(ebus, nexus, ebus_nexus_driver, ebus_devclass, 0, 0,
  198     BUS_PASS_BUS + 1);
  199 MODULE_DEPEND(ebus, nexus, 1, 1, 1);
  200 
  201 static device_method_t ebus_pci_methods[] = {
  202         /* Device interface */
  203         DEVMETHOD(device_probe,         ebus_pci_probe),
  204         DEVMETHOD(device_attach,        ebus_pci_attach),
  205         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  206         DEVMETHOD(device_suspend,       bus_generic_suspend),
  207         DEVMETHOD(device_resume,        bus_generic_resume),
  208 
  209         /* Bus interface */
  210         DEVMETHOD(bus_print_child,      ebus_print_child),
  211         DEVMETHOD(bus_probe_nomatch,    ebus_probe_nomatch),
  212         DEVMETHOD(bus_alloc_resource,   ebus_alloc_resource),
  213         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
  214         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
  215         DEVMETHOD(bus_release_resource, ebus_release_resource),
  216         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
  217         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
  218         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
  219         DEVMETHOD(bus_get_resource_list, ebus_get_resource_list),
  220         DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
  221 
  222         /* ofw_bus interface */
  223         DEVMETHOD(ofw_bus_get_devinfo,  ebus_get_devinfo),
  224         DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
  225         DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
  226         DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
  227         DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
  228         DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
  229 
  230         DEVMETHOD_END
  231 };
  232 
  233 static driver_t ebus_pci_driver = {
  234         "ebus",
  235         ebus_pci_methods,
  236         sizeof(struct ebus_softc),
  237 };
  238 
  239 EARLY_DRIVER_MODULE(ebus, pci, ebus_pci_driver, ebus_devclass, 0, 0,
  240     BUS_PASS_BUS);
  241 MODULE_DEPEND(ebus, pci, 1, 1, 1);
  242 MODULE_VERSION(ebus, 1);
  243 
  244 static int
  245 ebus_nexus_probe(device_t dev)
  246 {
  247         const char* compat;
  248 
  249         compat = ofw_bus_get_compat(dev);
  250         if (compat != NULL && strcmp(ofw_bus_get_name(dev), "ebus") == 0 &&
  251             strcmp(compat, "jbus-ebus") == 0) {
  252                 device_set_desc(dev, "JBus-EBus bridge");
  253                 return (BUS_PROBE_GENERIC);
  254         }
  255         return (ENXIO);
  256 }
  257 
  258 static int
  259 ebus_pci_probe(device_t dev)
  260 {
  261 
  262         if (pci_get_class(dev) != PCIC_BRIDGE ||
  263             pci_get_vendor(dev) != 0x108e ||
  264             strcmp(ofw_bus_get_name(dev), "ebus") != 0)
  265                 return (ENXIO);
  266 
  267         if (pci_get_device(dev) == 0x1000)
  268                 device_set_desc(dev, "PCI-EBus2 bridge");
  269         else if (pci_get_device(dev) == 0x1100)
  270                 device_set_desc(dev, "PCI-EBus3 bridge");
  271         else
  272                 return (ENXIO);
  273         return (BUS_PROBE_GENERIC);
  274 }
  275 
  276 static int
  277 ebus_nexus_attach(device_t dev)
  278 {
  279         struct ebus_softc *sc;
  280         phandle_t node;
  281 
  282         sc = device_get_softc(dev);
  283         node = ofw_bus_get_node(dev);
  284 
  285 #ifndef SUN4V
  286         if (OF_getprop(node, "portid", &sc->sc_ign,
  287             sizeof(sc->sc_ign)) == -1) {
  288                 device_printf(dev, "could not determine IGN");
  289                 return (ENXIO);
  290         }
  291 #endif
  292 
  293         sc->sc_nrange = OF_getprop_alloc(node, "ranges",
  294             sizeof(struct ebus_nexus_ranges), &sc->sc_range);
  295         if (sc->sc_nrange == -1) {
  296                 device_printf(dev, "could not get ranges property\n");
  297                 return (ENXIO);
  298         }
  299         return (ebus_attach(dev, sc, node));
  300 }
  301 
  302 static int
  303 ebus_pci_attach(device_t dev)
  304 {
  305         struct ebus_softc *sc;
  306         struct ebus_rinfo *eri;
  307         struct resource *res;
  308         struct isa_ranges *range;
  309         phandle_t node;
  310         int i, rnum, rid;
  311 
  312         sc = device_get_softc(dev);
  313         sc->sc_flags |= EBUS_PCI;
  314 
  315         pci_write_config(dev, PCIR_COMMAND,
  316             pci_read_config(dev, PCIR_COMMAND, 2) | PCIM_CMD_SERRESPEN |
  317             PCIM_CMD_PERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN, 2);
  318         pci_write_config(dev, PCIR_CACHELNSZ, 16 /* 64 bytes */, 1);
  319         pci_write_config(dev, PCIR_LATTIMER, 64 /* 64 PCI cycles */, 1);
  320 
  321         node = ofw_bus_get_node(dev);
  322         sc->sc_nrange = OF_getprop_alloc(node, "ranges",
  323             sizeof(struct isa_ranges), &sc->sc_range);
  324         if (sc->sc_nrange == -1) {
  325                 device_printf(dev, "could not get ranges property\n");
  326                 return (ENXIO);
  327         }
  328 
  329         sc->sc_rinfo = malloc(sizeof(*sc->sc_rinfo) * sc->sc_nrange, M_DEVBUF,
  330             M_WAITOK | M_ZERO);
  331 
  332         /* For every range, there must be a matching resource. */
  333         for (rnum = 0; rnum < sc->sc_nrange; rnum++) {
  334                 eri = &sc->sc_rinfo[rnum];
  335                 range = &((struct isa_ranges *)sc->sc_range)[rnum];
  336                 eri->eri_rtype = ofw_isa_range_restype(range);
  337                 rid = PCIR_BAR(rnum);
  338                 res = bus_alloc_resource_any(dev, eri->eri_rtype, &rid,
  339                     RF_ACTIVE);
  340                 if (res == NULL) {
  341                         device_printf(dev,
  342                             "could not allocate range resource %d\n", rnum);
  343                         goto fail;
  344                 }
  345                 if (rman_get_start(res) != ISA_RANGE_PHYS(range)) {
  346                         device_printf(dev,
  347                             "mismatch in start of range %d (0x%lx/0x%lx)\n",
  348                             rnum, rman_get_start(res), ISA_RANGE_PHYS(range));
  349                         goto fail;
  350                 }
  351                 if (rman_get_size(res) != range->size) {
  352                         device_printf(dev,
  353                             "mismatch in size of range %d (0x%lx/0x%x)\n",
  354                             rnum, rman_get_size(res), range->size);
  355                         goto fail;
  356                 }
  357                 eri->eri_res = res;
  358                 eri->eri_rman.rm_type = RMAN_ARRAY;
  359                 eri->eri_rman.rm_descr = "EBus range";
  360                 if (rman_init_from_resource(&eri->eri_rman, res) != 0) {
  361                         device_printf(dev,
  362                             "could not initialize rman for range %d", rnum);
  363                         goto fail;
  364                 }
  365         }
  366         return (ebus_attach(dev, sc, node));
  367 
  368  fail:
  369         for (i = rnum; i >= 0; i--) {
  370                 eri = &sc->sc_rinfo[i];
  371                 if (i < rnum)
  372                         rman_fini(&eri->eri_rman);
  373                 if (eri->eri_res != NULL) {
  374                         bus_release_resource(dev, eri->eri_rtype,
  375                             PCIR_BAR(rnum), eri->eri_res);
  376                 }
  377         }
  378         free(sc->sc_rinfo, M_DEVBUF);
  379         OF_prop_free(sc->sc_range);
  380         return (ENXIO);
  381 }
  382 
  383 static int
  384 ebus_attach(device_t dev, struct ebus_softc *sc, phandle_t node)
  385 {
  386         struct ebus_devinfo *edi;
  387         device_t cdev;
  388 
  389         ofw_bus_setup_iinfo(node, &sc->sc_iinfo, sizeof(ofw_isa_intr_t));
  390 
  391         /*
  392          * Now attach our children.
  393          */
  394         for (node = OF_child(node); node > 0; node = OF_peer(node)) {
  395                 if ((edi = ebus_setup_dinfo(dev, sc, node)) == NULL)
  396                         continue;
  397                 if ((cdev = device_add_child(dev, NULL, -1)) == NULL) {
  398                         device_printf(dev, "<%s>: device_add_child failed\n",
  399                             edi->edi_obdinfo.obd_name);
  400                         ebus_destroy_dinfo(edi);
  401                         continue;
  402                 }
  403                 device_set_ivars(cdev, edi);
  404         }
  405         return (bus_generic_attach(dev));
  406 }
  407 
  408 static int
  409 ebus_print_child(device_t dev, device_t child)
  410 {
  411         int retval;
  412 
  413         retval = bus_print_child_header(dev, child);
  414         retval += ebus_print_res(device_get_ivars(child));
  415         retval += bus_print_child_footer(dev, child);
  416         return (retval);
  417 }
  418 
  419 static void
  420 ebus_probe_nomatch(device_t dev, device_t child)
  421 {
  422 
  423         device_printf(dev, "<%s>", ofw_bus_get_name(child));
  424         ebus_print_res(device_get_ivars(child));
  425         printf(" (no driver attached)\n");
  426 }
  427 
  428 static struct resource *
  429 ebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
  430     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
  431 {
  432         struct ebus_softc *sc;
  433         struct resource_list *rl;
  434         struct resource_list_entry *rle = NULL;
  435         struct resource *res;
  436         struct ebus_rinfo *eri;
  437         struct ebus_nexus_ranges *enr;
  438         uint64_t cend, cstart, offset;
  439         int i, isdefault, passthrough, ridx;
  440 
  441         isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
  442         passthrough = (device_get_parent(child) != bus);
  443         sc = device_get_softc(bus);
  444         rl = BUS_GET_RESOURCE_LIST(bus, child);
  445         switch (type) {
  446         case SYS_RES_MEMORY:
  447                 KASSERT(!(isdefault && passthrough),
  448                     ("%s: passthrough of default allocation", __func__));
  449                 if (!passthrough) {
  450                         rle = resource_list_find(rl, type, *rid);
  451                         if (rle == NULL)
  452                                 return (NULL);
  453                         KASSERT(rle->res == NULL,
  454                             ("%s: resource entry is busy", __func__));
  455                         if (isdefault) {
  456                                 start = rle->start;
  457                                 count = ulmax(count, rle->count);
  458                                 end = ulmax(rle->end, start + count - 1);
  459                         }
  460                 }
  461 
  462                 res = NULL;
  463                 if ((sc->sc_flags & EBUS_PCI) != 0) {
  464                         /*
  465                          * Map EBus ranges to PCI ranges.  This may include
  466                          * changing the allocation type.
  467                          */
  468                         type = ofw_isa_range_map(sc->sc_range, sc->sc_nrange,
  469                             &start, &end, &ridx);
  470                         eri = &sc->sc_rinfo[ridx];
  471                         res = rman_reserve_resource(&eri->eri_rman, start,
  472                             end, count, flags & ~RF_ACTIVE, child);
  473                         if (res == NULL)
  474                                 return (NULL);
  475                         rman_set_rid(res, *rid);
  476                         if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(
  477                             child, type, *rid, res) != 0) {
  478                                 rman_release_resource(res);
  479                                 return (NULL);
  480                         }
  481                 } else {
  482                         /* Map EBus ranges to nexus ranges. */
  483                         for (i = 0; i < sc->sc_nrange; i++) {
  484                                 enr = &((struct ebus_nexus_ranges *)
  485                                     sc->sc_range)[i];
  486                                 cstart = (((uint64_t)enr->child_hi) << 32) |
  487                                     enr->child_lo;
  488                                 cend = cstart + enr->size - 1;
  489                                 if (start >= cstart && end <= cend) {
  490                                         offset =
  491                                             (((uint64_t)enr->phys_hi) << 32) |
  492                                             enr->phys_lo;
  493                                         start += offset - cstart;
  494                                         end += offset - cstart;
  495                                         res = bus_generic_alloc_resource(bus,
  496                                             child, type, rid, start, end,
  497                                             count, flags);
  498                                         break;
  499                                 }
  500                         }
  501                 }
  502                 if (!passthrough)
  503                         rle->res = res;
  504                 return (res);
  505         case SYS_RES_IRQ:
  506                 return (resource_list_alloc(rl, bus, child, type, rid, start,
  507                     end, count, flags));
  508         }
  509         return (NULL);
  510 }
  511 
  512 static int
  513 ebus_activate_resource(device_t bus, device_t child, int type, int rid,
  514     struct resource *res)
  515 {
  516         struct ebus_softc *sc;
  517         struct ebus_rinfo *eri;
  518         bus_space_tag_t bt;
  519         bus_space_handle_t bh;
  520         int i, rv;
  521 
  522         sc = device_get_softc(bus);
  523         if ((sc->sc_flags & EBUS_PCI) != 0 && type != SYS_RES_IRQ) {
  524                 for (i = 0; i < sc->sc_nrange; i++) {
  525                         eri = &sc->sc_rinfo[i];
  526                         if (rman_is_region_manager(res, &eri->eri_rman) != 0) {
  527                                 bt = rman_get_bustag(eri->eri_res);
  528                                 rv = bus_space_subregion(bt,
  529                                     rman_get_bushandle(eri->eri_res),
  530                                     rman_get_start(res) -
  531                                     rman_get_start(eri->eri_res),
  532                                     rman_get_size(res), &bh);
  533                                 if (rv != 0)
  534                                         return (rv);
  535                                 rman_set_bustag(res, bt);
  536                                 rman_set_bushandle(res, bh);
  537                                 return (rman_activate_resource(res));
  538                         }
  539                 }
  540                 return (EINVAL);
  541         }
  542         return (bus_generic_activate_resource(bus, child, type, rid, res));
  543 }
  544 
  545 static int
  546 ebus_adjust_resource(device_t bus __unused, device_t child __unused,
  547     int type __unused, struct resource *res __unused, rman_res_t start __unused,
  548     rman_res_t end __unused)
  549 {
  550 
  551         return (ENXIO);
  552 }
  553 
  554 static int
  555 ebus_release_resource(device_t bus, device_t child, int type, int rid,
  556     struct resource *res)
  557 {
  558         struct ebus_softc *sc;
  559         struct resource_list *rl;
  560         struct resource_list_entry *rle;
  561         int passthrough, rv;
  562 
  563         passthrough = (device_get_parent(child) != bus);
  564         rl = BUS_GET_RESOURCE_LIST(bus, child);
  565         sc = device_get_softc(bus);
  566         if ((sc->sc_flags & EBUS_PCI) != 0 && type != SYS_RES_IRQ) {
  567                 if ((rman_get_flags(res) & RF_ACTIVE) != 0 ){
  568                         rv = bus_deactivate_resource(child, type, rid, res);
  569                         if (rv != 0)
  570                                 return (rv);
  571                 }
  572                 rv = rman_release_resource(res);
  573                 if (rv != 0)
  574                         return (rv);
  575                 if (!passthrough) {
  576                         rle = resource_list_find(rl, type, rid);
  577                         KASSERT(rle != NULL,
  578                             ("%s: resource entry not found!", __func__));
  579                         KASSERT(rle->res != NULL,
  580                            ("%s: resource entry is not busy", __func__));
  581                         rle->res = NULL;
  582                 }
  583                 return (0);
  584         }
  585         return (resource_list_release(rl, bus, child, type, rid, res));
  586 }
  587 
  588 static int
  589 ebus_setup_intr(device_t dev, device_t child, struct resource *ires,
  590     int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg,
  591     void **cookiep)
  592 {
  593 #ifndef SUN4V
  594         struct ebus_softc *sc;
  595         u_long vec;
  596 
  597         sc = device_get_softc(dev);
  598         if ((sc->sc_flags & EBUS_PCI) == 0) {
  599                 /*
  600                  * Make sure the vector is fully specified.  This isn't
  601                  * necessarily the case with the PCI variant.
  602                  */
  603                 vec = rman_get_start(ires);
  604                 if (INTIGN(vec) != sc->sc_ign) {
  605                         device_printf(dev,
  606                             "invalid interrupt vector 0x%lx\n", vec);
  607                         return (EINVAL);
  608                 }
  609 
  610                 /*
  611                  * As we rely on the interrupt controllers of the
  612                  * accompanying PCI-Express bridge ensure at least
  613                  * something is registered for this vector.
  614                  */
  615                 if (intr_vectors[vec].iv_ic == NULL) {
  616                         device_printf(dev,
  617                             "invalid interrupt controller for vector 0x%lx\n",
  618                             vec);
  619                         return (EINVAL);
  620                 }
  621         }
  622 #endif
  623         return (bus_generic_setup_intr(dev, child, ires, flags, filt, intr,
  624             arg, cookiep));
  625 }
  626 
  627 static struct resource_list *
  628 ebus_get_resource_list(device_t dev, device_t child)
  629 {
  630         struct ebus_devinfo *edi;
  631 
  632         edi = device_get_ivars(child);
  633         return (&edi->edi_rl);
  634 }
  635 
  636 static const struct ofw_bus_devinfo *
  637 ebus_get_devinfo(device_t bus, device_t dev)
  638 {
  639         struct ebus_devinfo *edi;
  640 
  641         edi = device_get_ivars(dev);
  642         return (&edi->edi_obdinfo);
  643 }
  644 
  645 static struct ebus_devinfo *
  646 ebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node)
  647 {
  648         struct isa_regs reg, *regs;
  649         ofw_isa_intr_t intr, *intrs;
  650         struct ebus_devinfo *edi;
  651         uint64_t start;
  652         uint32_t rintr;
  653         int i, nintr, nreg, rv;
  654 
  655         edi = malloc(sizeof(*edi), M_DEVBUF, M_ZERO | M_WAITOK);
  656         if (ofw_bus_gen_setup_devinfo(&edi->edi_obdinfo, node) != 0) {
  657                 free(edi, M_DEVBUF);
  658                 return (NULL);
  659         }
  660         resource_list_init(&edi->edi_rl);
  661         nreg = OF_getprop_alloc(node, "reg", sizeof(*regs), (void **)&regs);
  662         if (nreg == -1) {
  663                 device_printf(dev, "<%s>: incomplete\n",
  664                     edi->edi_obdinfo.obd_name);
  665                 ebus_destroy_dinfo(edi);
  666                 return (NULL);
  667         }
  668         for (i = 0; i < nreg; i++) {
  669                 start = ISA_REG_PHYS(regs + i);
  670                 (void)resource_list_add(&edi->edi_rl, SYS_RES_MEMORY, i,
  671                     start, start + regs[i].size - 1, regs[i].size);
  672         }
  673         OF_prop_free(regs);
  674 
  675         nintr = OF_getprop_alloc(node, "interrupts",  sizeof(*intrs),
  676             (void **)&intrs);
  677         if (nintr == -1)
  678                 return (edi);
  679         for (i = 0; i < nintr; i++) {
  680                 rv = 0;
  681                 if ((sc->sc_flags & EBUS_PCI) != 0) {
  682                         rintr = ofw_isa_route_intr(dev, node, &sc->sc_iinfo,
  683                             intrs[i]);
  684                 } else {
  685                         intr = intrs[i];
  686                         rv = ofw_bus_lookup_imap(node, &sc->sc_iinfo, &reg,
  687                             sizeof(reg), &intr, sizeof(intr), &rintr,
  688                             sizeof(rintr), NULL);
  689 #ifndef SUN4V
  690                         if (rv != 0)
  691                                 rintr = INTMAP_VEC(sc->sc_ign, rintr);
  692 #endif
  693                 }
  694                 if ((sc->sc_flags & EBUS_PCI) == 0 ? rv == 0 :
  695                     rintr == PCI_INVALID_IRQ) {
  696                         device_printf(dev,
  697                             "<%s>: could not map EBus interrupt %d\n",
  698                             edi->edi_obdinfo.obd_name, intrs[i]);
  699                         continue;
  700                 }
  701                 (void)resource_list_add(&edi->edi_rl, SYS_RES_IRQ, i, rintr,
  702                     rintr, 1);
  703         }
  704         OF_prop_free(intrs);
  705         return (edi);
  706 }
  707 
  708 static void
  709 ebus_destroy_dinfo(struct ebus_devinfo *edi)
  710 {
  711 
  712         resource_list_free(&edi->edi_rl);
  713         ofw_bus_gen_destroy_devinfo(&edi->edi_obdinfo);
  714         free(edi, M_DEVBUF);
  715 }
  716 
  717 static int
  718 ebus_print_res(struct ebus_devinfo *edi)
  719 {
  720         int retval;
  721 
  722         retval = 0;
  723         retval += resource_list_print_type(&edi->edi_rl, "addr", SYS_RES_MEMORY,
  724             "%#jx");
  725         retval += resource_list_print_type(&edi->edi_rl, "irq", SYS_RES_IRQ,
  726             "%jd");
  727         return (retval);
  728 }

Cache object: 0d339876f05ac59fa74212e2d47840a7


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