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

Cache object: f3a2adab249b3616d7b19afdab4c3bc9


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