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

Cache object: f31155ce5b77d1ca6908303fba6644db


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