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) 2001 Thomas Moestl <tmm@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.26 2001/09/10 16:27:53 eeh Exp
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 /*
   36  * UltraSPARC 5 and beyond EBus support
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/systm.h>
   41 #include <sys/bus.h>
   42 #include <sys/kernel.h>
   43 #include <sys/malloc.h>
   44 #include <sys/module.h>
   45 
   46 #include <machine/bus.h>
   47 
   48 #include <sys/rman.h>
   49 
   50 #include <dev/ofw/ofw_bus.h>
   51 #include <dev/ofw/openfirm.h>
   52 
   53 #include <machine/ofw_bus.h>
   54 #include <machine/resource.h>
   55 
   56 #include <dev/pci/pcireg.h>
   57 #include <dev/pci/pcivar.h>
   58 
   59 #include <sparc64/pci/ofw_pci.h>
   60 
   61 /*
   62  * The register, ranges and interrupt map properties are identical to the ISA
   63  * ones.
   64  */
   65 #include <sparc64/isa/ofw_isa.h>
   66 
   67 struct ebus_devinfo {
   68         char                    *edi_compat;    /* PROM compatible */
   69         char                    *edi_model;     /* PROM model */
   70         char                    *edi_name;      /* PROM name */
   71         char                    *edi_type;      /* PROM device_type */
   72         phandle_t               edi_node;       /* PROM node */
   73 
   74         struct resource_list    edi_rl;
   75 };
   76 
   77 struct ebus_rinfo {
   78         int                     eri_rtype;
   79         struct rman             eri_rman;
   80         struct resource         *eri_res;
   81 };
   82 
   83 struct ebus_softc {
   84         struct isa_ranges       *sc_range;
   85         struct ebus_rinfo       *sc_rinfo;
   86 
   87         int                     sc_nrange;
   88         int                     sc_nimap;
   89 
   90         struct ofw_bus_iinfo    sc_iinfo;
   91 };
   92 
   93 static device_probe_t ebus_probe;
   94 static device_attach_t ebus_attach;
   95 static bus_print_child_t ebus_print_child;
   96 static bus_probe_nomatch_t ebus_probe_nomatch;
   97 static bus_alloc_resource_t ebus_alloc_resource;
   98 static bus_release_resource_t ebus_release_resource;
   99 static bus_get_resource_list_t ebus_get_resource_list;
  100 static ofw_bus_get_compat_t ebus_get_compat;
  101 static ofw_bus_get_model_t ebus_get_model;
  102 static ofw_bus_get_name_t ebus_get_name;
  103 static ofw_bus_get_node_t ebus_get_node;
  104 static ofw_bus_get_type_t ebus_get_type;
  105 
  106 static struct ebus_devinfo *ebus_setup_dinfo(device_t, struct ebus_softc *,
  107     phandle_t, char *);
  108 static void ebus_destroy_dinfo(struct ebus_devinfo *);
  109 static int ebus_print_res(struct ebus_devinfo *);
  110 
  111 static device_method_t ebus_methods[] = {
  112         /* Device interface */
  113         DEVMETHOD(device_probe,         ebus_probe),
  114         DEVMETHOD(device_attach,        ebus_attach),
  115         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  116         DEVMETHOD(device_suspend,       bus_generic_suspend),
  117         DEVMETHOD(device_resume,        bus_generic_resume),
  118 
  119         /* Bus interface */
  120         DEVMETHOD(bus_print_child,      ebus_print_child),
  121         DEVMETHOD(bus_probe_nomatch,    ebus_probe_nomatch),
  122         DEVMETHOD(bus_setup_intr,       bus_generic_setup_intr),
  123         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
  124         DEVMETHOD(bus_alloc_resource,   ebus_alloc_resource),
  125         DEVMETHOD(bus_get_resource_list, ebus_get_resource_list),
  126         DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
  127         DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
  128         DEVMETHOD(bus_release_resource, ebus_release_resource),
  129         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
  130 
  131         /* ofw_bus interface */
  132         DEVMETHOD(ofw_bus_get_compat,   ebus_get_compat),
  133         DEVMETHOD(ofw_bus_get_model,    ebus_get_model),
  134         DEVMETHOD(ofw_bus_get_name,     ebus_get_name),
  135         DEVMETHOD(ofw_bus_get_node,     ebus_get_node),
  136         DEVMETHOD(ofw_bus_get_type,     ebus_get_type),
  137 
  138         { 0, 0 }
  139 };
  140 
  141 static driver_t ebus_driver = {
  142         "ebus",
  143         ebus_methods,
  144         sizeof(struct ebus_softc),
  145 };
  146 
  147 static devclass_t ebus_devclass;
  148 
  149 DRIVER_MODULE(ebus, pci, ebus_driver, ebus_devclass, 0, 0);
  150 MODULE_DEPEND(ebus, pci, 1, 1, 1);
  151 MODULE_VERSION(ebus, 1);
  152 
  153 static int
  154 ebus_probe(device_t dev)
  155 {
  156 
  157         if (pci_get_class(dev) != PCIC_BRIDGE ||
  158             pci_get_vendor(dev) != 0x108e ||
  159             strcmp(ofw_bus_get_name(dev), "ebus") != 0)
  160                 return (ENXIO);
  161 
  162         if (pci_get_device(dev) == 0x1000)
  163                 device_set_desc(dev, "PCI-EBus2 bridge");
  164         else if (pci_get_device(dev) == 0x1100)
  165                 device_set_desc(dev, "PCI-EBus3 bridge");
  166         else
  167                 return (ENXIO);
  168         return (0);
  169 }
  170 
  171 static int
  172 ebus_attach(device_t dev)
  173 {
  174         struct ebus_softc *sc;
  175         struct ebus_devinfo *edi;
  176         struct ebus_rinfo *eri;
  177         struct resource *res;
  178         device_t cdev;
  179         phandle_t node;
  180         char *cname;
  181         int i, rnum, rid;
  182 
  183         sc = device_get_softc(dev);
  184 
  185         node = ofw_bus_get_node(dev);
  186         sc->sc_nrange = OF_getprop_alloc(node, "ranges",
  187             sizeof(*sc->sc_range), (void **)&sc->sc_range);
  188         if (sc->sc_nrange == -1) {
  189                 printf("ebus_attach: could not get ranges property\n");
  190                 return (ENXIO);
  191         }
  192 
  193         sc->sc_rinfo = malloc(sizeof(*sc->sc_rinfo) * sc->sc_nrange, M_DEVBUF,
  194             M_WAITOK | M_ZERO);
  195 
  196         /* For every range, there must be a matching resource. */
  197         for (rnum = 0; rnum < sc->sc_nrange; rnum++) {
  198                 eri = &sc->sc_rinfo[rnum];
  199                 eri->eri_rtype = ofw_isa_range_restype(&sc->sc_range[rnum]);
  200                 rid = PCIR_BAR(rnum);
  201                 res = bus_alloc_resource_any(dev, eri->eri_rtype, &rid,
  202                     RF_ACTIVE);
  203                 if (res == NULL) {
  204                         printf("ebus_attach: failed to allocate range "
  205                             "resource!\n");
  206                         goto fail;
  207                 }
  208                 eri->eri_res = res;
  209                 eri->eri_rman.rm_type = RMAN_ARRAY;
  210                 eri->eri_rman.rm_descr = "EBus range";
  211                 if (rman_init(&eri->eri_rman) != 0) {
  212                         printf("ebus_attach: failed to initialize rman!");
  213                         goto fail;
  214                 }
  215                 if (rman_manage_region(&eri->eri_rman, rman_get_start(res),
  216                     rman_get_end(res)) != 0) {
  217                         printf("ebus_attach: failed to register region!");
  218                         rman_fini(&eri->eri_rman);
  219                         goto fail;
  220                 }
  221         }
  222 
  223         ofw_bus_setup_iinfo(node, &sc->sc_iinfo, sizeof(ofw_isa_intr_t));
  224 
  225         /*
  226          * Now attach our children.
  227          */
  228         for (node = OF_child(node); node > 0; node = OF_peer(node)) {
  229                 if ((OF_getprop_alloc(node, "name", 1, (void **)&cname)) == -1)
  230                         continue;
  231 
  232                 if ((edi = ebus_setup_dinfo(dev, sc, node, cname)) == NULL) {
  233                         device_printf(dev, "<%s>: incomplete\n", cname);
  234                         free(cname, M_OFWPROP);
  235                         continue;
  236                 }
  237                 if ((cdev = device_add_child(dev, NULL, -1)) == NULL)
  238                         panic("ebus_attach: device_add_child failed");
  239                 device_set_ivars(cdev, edi);
  240         }
  241         return (bus_generic_attach(dev));
  242 
  243 fail:
  244         for (i = rnum; i >= 0; i--) {
  245                 eri = &sc->sc_rinfo[i];
  246                 if (i < rnum)
  247                         rman_fini(&eri->eri_rman);
  248                 if (eri->eri_res != 0) {
  249                         bus_release_resource(dev, eri->eri_rtype,
  250                             PCIR_BAR(rnum), eri->eri_res);
  251                 }
  252         }
  253         free(sc->sc_range, M_OFWPROP);
  254         return (ENXIO);
  255 }
  256 
  257 static int
  258 ebus_print_child(device_t dev, device_t child)
  259 {
  260         struct ebus_devinfo *edi;
  261         int retval;
  262 
  263         edi = device_get_ivars(child);
  264         retval = bus_print_child_header(dev, child);
  265         retval += ebus_print_res(edi);
  266         retval += bus_print_child_footer(dev, child);
  267         return (retval);
  268 }
  269 
  270 static void
  271 ebus_probe_nomatch(device_t dev, device_t child)
  272 {
  273         struct ebus_devinfo *edi;
  274 
  275         edi = device_get_ivars(child);
  276         device_printf(dev, "<%s>", edi->edi_name);
  277         ebus_print_res(edi);
  278         printf(" (no driver attached)\n");
  279 }
  280 
  281 static struct resource *
  282 ebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
  283     u_long start, u_long end, u_long count, u_int flags)
  284 {
  285         struct ebus_softc *sc;
  286         struct resource_list *rl;
  287         struct resource_list_entry *rle = NULL;
  288         struct resource *res;
  289         struct ebus_rinfo *ri;
  290         bus_space_tag_t bt;
  291         bus_space_handle_t bh;
  292         int passthrough = (device_get_parent(child) != bus);
  293         int isdefault = (start == 0UL && end == ~0UL);
  294         int ridx, rv;
  295 
  296         sc = (struct ebus_softc *)device_get_softc(bus);
  297         rl = BUS_GET_RESOURCE_LIST(bus, child);
  298         /*
  299          * Map EBus ranges to PCI ranges.  This may include changing the
  300          * allocation type.
  301          */
  302         switch (type) {
  303         case SYS_RES_MEMORY:
  304                 KASSERT(!(isdefault && passthrough),
  305                     ("ebus_alloc_resource: passthrough of default alloc"));
  306                 if (!passthrough) {
  307                         rle = resource_list_find(rl, type, *rid);
  308                         if (rle == NULL)
  309                                 return (NULL);
  310                         KASSERT(rle->res == NULL,
  311                             ("ebus_alloc_resource: resource entry is busy"));
  312                         if (isdefault) {
  313                                 start = rle->start;
  314                                 count = ulmax(count, rle->count);
  315                                 end = ulmax(rle->end, start + count - 1);
  316                         }
  317                 }
  318 
  319                 (void)ofw_isa_range_map(sc->sc_range, sc->sc_nrange,
  320                     &start, &end, &ridx);
  321 
  322                 ri = &sc->sc_rinfo[ridx];
  323                 res = rman_reserve_resource(&ri->eri_rman, start, end, count,
  324                     flags, child);
  325                 if (res == NULL)
  326                         return (NULL);
  327                 rman_set_rid(res, *rid);
  328                 bt = rman_get_bustag(ri->eri_res);
  329                 rman_set_bustag(res, bt);
  330                 rv = bus_space_subregion(bt, rman_get_bushandle(ri->eri_res),
  331                     rman_get_start(res) - rman_get_start(ri->eri_res), count,
  332                     &bh);
  333                 if (rv != 0) {
  334                         rman_release_resource(res);
  335                         return (NULL);
  336                 }
  337                 rman_set_bushandle(res, bh);
  338                 if (!passthrough)
  339                         rle->res = res;
  340                 return (res);
  341         case SYS_RES_IRQ:
  342                 return (resource_list_alloc(rl, bus, child, type, rid, start,
  343                     end, count, flags));
  344         }
  345         return (NULL);
  346 }
  347 
  348 static int
  349 ebus_release_resource(device_t bus, device_t child, int type, int rid,
  350     struct resource *res)
  351 {
  352         struct resource_list *rl;
  353         struct resource_list_entry *rle;
  354         int passthrough = (device_get_parent(child) != bus);
  355         int rv;
  356 
  357         rl = BUS_GET_RESOURCE_LIST(bus, child);
  358         switch (type) {
  359         case SYS_RES_MEMORY:
  360                 if ((rv = rman_release_resource(res)) != 0)
  361                         return (rv);
  362                 if (!passthrough) {
  363                         rle = resource_list_find(rl, type, rid);
  364                         KASSERT(rle != NULL, ("ebus_release_resource: "
  365                             "resource entry not found!"));
  366                         KASSERT(rle->res != NULL, ("ebus_alloc_resource: "
  367                             "resource entry is not busy"));
  368                         rle->res = NULL;
  369                 }
  370                 break;
  371         case SYS_RES_IRQ:
  372                 return (resource_list_release(rl, bus, child, type, rid, res));
  373         default:
  374                 panic("ebus_release_resource: unsupported resource type %d",
  375                     type);
  376         }
  377         return (0);
  378 }
  379 
  380 static struct resource_list *
  381 ebus_get_resource_list(device_t dev, device_t child)
  382 {
  383         struct ebus_devinfo *edi;
  384 
  385         edi = device_get_ivars(child);
  386         return (&edi->edi_rl);
  387 }
  388 
  389 static struct ebus_devinfo *
  390 ebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node,
  391     char *name)
  392 {
  393         struct ebus_devinfo *edi;
  394         struct isa_regs *reg;
  395         ofw_isa_intr_t *intrs;
  396         ofw_pci_intr_t rintr;
  397         u_int64_t start;
  398         int nreg, nintr, i;
  399 
  400         edi = malloc(sizeof(*edi), M_DEVBUF, M_ZERO | M_WAITOK);
  401         if (edi == NULL)
  402                 return (NULL);
  403         resource_list_init(&edi->edi_rl);
  404         edi->edi_name = name;
  405         edi->edi_node = node;
  406 
  407         OF_getprop_alloc(node, "compatible", 1, (void **)&edi->edi_compat);
  408         OF_getprop_alloc(node, "device_type", 1, (void **)&edi->edi_type);
  409         OF_getprop_alloc(node, "model", 1, (void **)&edi->edi_model);
  410         nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)&reg);
  411         if (nreg == -1) {
  412                 ebus_destroy_dinfo(edi);
  413                 return (NULL);
  414         }
  415         for (i = 0; i < nreg; i++) {
  416                 start = ISA_REG_PHYS(reg + i);
  417                 resource_list_add(&edi->edi_rl, SYS_RES_MEMORY, i,
  418                     start, start + reg[i].size - 1, reg[i].size);
  419         }
  420         free(reg, M_OFWPROP);
  421 
  422         nintr = OF_getprop_alloc(node, "interrupts",  sizeof(*intrs),
  423             (void **)&intrs);
  424         for (i = 0; i < nintr; i++) {
  425                 rintr = ofw_isa_route_intr(dev, node, &sc->sc_iinfo, intrs[i]);
  426                 if (rintr == PCI_INVALID_IRQ)
  427                         panic("ebus_setup_dinfo: could not map ebus "
  428                             "interrupt %d", intrs[i]);
  429                 resource_list_add(&edi->edi_rl, SYS_RES_IRQ, i,
  430                     rintr, rintr, 1);
  431         }
  432         free(intrs, M_OFWPROP);
  433 
  434         return (edi);
  435 }
  436 
  437 /*
  438  * NOTE: This does not free the name member (it is needed afterwards in some
  439  * cases).
  440  */
  441 static void
  442 ebus_destroy_dinfo(struct ebus_devinfo *edi)
  443 {
  444 
  445         if (edi->edi_compat != NULL)
  446                 free(edi->edi_compat, M_OFWPROP);
  447         if (edi->edi_type != NULL)
  448                 free(edi->edi_type, M_OFWPROP);
  449         if (edi->edi_model != NULL)
  450                 free(edi->edi_model, M_OFWPROP);
  451         resource_list_free(&edi->edi_rl);
  452         free(edi, M_DEVBUF);
  453 }
  454 
  455 static int
  456 ebus_print_res(struct ebus_devinfo *edi)
  457 {
  458         int retval;
  459 
  460         retval = 0;
  461         retval += resource_list_print_type(&edi->edi_rl, "addr", SYS_RES_MEMORY,
  462             "%#lx");
  463         retval += resource_list_print_type(&edi->edi_rl, "irq", SYS_RES_IRQ,
  464             "%ld");
  465         return (retval);
  466 }
  467 
  468 static const char *
  469 ebus_get_compat(device_t bus, device_t dev)
  470 {
  471         struct ebus_devinfo *dinfo;
  472 
  473         dinfo = device_get_ivars(dev);
  474         return (dinfo->edi_compat);
  475 }
  476 
  477 static const char *
  478 ebus_get_model(device_t bus, device_t dev)
  479 {
  480         struct ebus_devinfo *dinfo;
  481 
  482         dinfo = device_get_ivars(dev);
  483         return (dinfo->edi_model);
  484 }
  485 
  486 static const char *
  487 ebus_get_name(device_t bus, device_t dev)
  488 {
  489         struct ebus_devinfo *dinfo;
  490 
  491         dinfo = device_get_ivars(dev);
  492         return (dinfo->edi_name);
  493 }
  494 
  495 static phandle_t
  496 ebus_get_node(device_t bus, device_t dev)
  497 {
  498         struct ebus_devinfo *dinfo;
  499 
  500         dinfo = device_get_ivars(dev);
  501         return (dinfo->edi_node);
  502 }
  503 
  504 static const char *
  505 ebus_get_type(device_t bus, device_t dev)
  506 {
  507         struct ebus_devinfo *dinfo;
  508 
  509         dinfo = device_get_ivars(dev);
  510         return (dinfo->edi_type);
  511 }

Cache object: 40e26e5299afe6ce0466d4708a012fa4


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