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/mips/nlm/xlp_simplebus.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) 2015 Broadcom Corporation
    3  * (based on sys/dev/fdt/simplebus.c)
    4  * Copyright (c) 2013 Nathan Whitehorn
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD$");
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/module.h>
   34 #include <sys/bus.h>
   35 #include <sys/conf.h>
   36 #include <sys/kernel.h>
   37 #include <sys/rman.h>
   38 
   39 #include <vm/vm.h>
   40 #include <vm/vm_param.h>
   41 #include <vm/pmap.h>
   42 
   43 #include <machine/bus.h>
   44 #include <machine/intr_machdep.h>
   45 
   46 #include <mips/nlm/hal/haldefs.h>
   47 #include <mips/nlm/interrupt.h>
   48 #include <mips/nlm/hal/iomap.h>
   49 #include <mips/nlm/hal/mips-extns.h>
   50 #include <mips/nlm/hal/pcibus.h>
   51 #include <mips/nlm/xlp.h>
   52 
   53 #include <dev/ofw/openfirm.h>
   54 #include <dev/ofw/ofw_bus.h>
   55 #include <dev/ofw/ofw_bus_subr.h>
   56 
   57 #include <dev/fdt/simplebus.h>
   58 
   59 /* flash memory region for chipselects */
   60 #define GBU_MEM_BASE    0x16000000UL
   61 #define GBU_MEM_LIMIT   0x17ffffffUL
   62 
   63 /*
   64  * Device registers in pci ecfg memory region for devices without regular PCI BARs
   65  */
   66 #define PCI_ECFG_BASE   XLP_DEFAULT_IO_BASE
   67 #define PCI_ECFG_LIMIT  (XLP_DEFAULT_IO_BASE + 0x0fffffff)
   68 
   69 /*
   70  * Bus interface.
   71  */
   72 static int              xlp_simplebus_probe(device_t dev);
   73 static struct resource *xlp_simplebus_alloc_resource(device_t, device_t, int,
   74     int *, rman_res_t, rman_res_t, rman_res_t, u_int);
   75 static int              xlp_simplebus_activate_resource(device_t, device_t, int,
   76     int, struct resource *);
   77 static int              xlp_simplebus_setup_intr(device_t, device_t,
   78     struct resource *, int, driver_filter_t *, driver_intr_t *, void *, void **);
   79 
   80 /*
   81  * ofw_bus interface
   82  */
   83 static int              xlp_simplebus_ofw_map_intr(device_t, device_t, phandle_t,
   84     int, pcell_t *);
   85 
   86 static devclass_t simplebus_devclass;
   87 static device_method_t xlp_simplebus_methods[] = {
   88         /* Device interface */
   89         DEVMETHOD(device_probe,         xlp_simplebus_probe),
   90 
   91         DEVMETHOD(bus_alloc_resource,   xlp_simplebus_alloc_resource),
   92         DEVMETHOD(bus_activate_resource, xlp_simplebus_activate_resource),
   93         DEVMETHOD(bus_setup_intr,       xlp_simplebus_setup_intr),
   94 
   95         DEVMETHOD(ofw_bus_map_intr,     xlp_simplebus_ofw_map_intr),
   96         DEVMETHOD_END
   97 };
   98 
   99 DEFINE_CLASS_1(simplebus, xlp_simplebus_driver, xlp_simplebus_methods,
  100     sizeof(struct simplebus_softc), simplebus_driver);
  101 DRIVER_MODULE(xlp_simplebus, ofwbus, xlp_simplebus_driver, simplebus_devclass,
  102     0, 0);
  103 
  104 static struct rman irq_rman, port_rman, mem_rman, pci_ecfg_rman, gbu_rman;
  105 
  106 static void
  107 xlp_simplebus_init_resources(void)
  108 {
  109         irq_rman.rm_start = 0;
  110         irq_rman.rm_end = 255;
  111         irq_rman.rm_type = RMAN_ARRAY;
  112         irq_rman.rm_descr = "PCI Mapped Interrupts";
  113         if (rman_init(&irq_rman)
  114             || rman_manage_region(&irq_rman, 0, 255))
  115                 panic("xlp_simplebus_init_resources irq_rman");
  116 
  117         port_rman.rm_type = RMAN_ARRAY;
  118         port_rman.rm_descr = "I/O ports";
  119         if (rman_init(&port_rman)
  120             || rman_manage_region(&port_rman, PCIE_IO_BASE, PCIE_IO_LIMIT))
  121                 panic("xlp_simplebus_init_resources port_rman");
  122 
  123         mem_rman.rm_type = RMAN_ARRAY;
  124         mem_rman.rm_descr = "I/O memory";
  125         if (rman_init(&mem_rman)
  126             || rman_manage_region(&mem_rman, PCIE_MEM_BASE, PCIE_MEM_LIMIT))
  127                 panic("xlp_simplebus_init_resources mem_rman");
  128 
  129         pci_ecfg_rman.rm_type = RMAN_ARRAY;
  130         pci_ecfg_rman.rm_descr = "PCI ECFG IO";
  131         if (rman_init(&pci_ecfg_rman) || rman_manage_region(&pci_ecfg_rman,
  132             PCI_ECFG_BASE, PCI_ECFG_LIMIT))
  133                 panic("xlp_simplebus_init_resources pci_ecfg_rman");
  134 
  135         gbu_rman.rm_type = RMAN_ARRAY;
  136         gbu_rman.rm_descr = "Flash region";
  137         if (rman_init(&gbu_rman)
  138             || rman_manage_region(&gbu_rman, GBU_MEM_BASE, GBU_MEM_LIMIT))
  139                 panic("xlp_simplebus_init_resources gbu_rman");
  140 }
  141 
  142 static int
  143 xlp_simplebus_probe(device_t dev)
  144 {
  145 
  146         if (!ofw_bus_status_okay(dev))
  147                 return (ENXIO);
  148 
  149         /*
  150          * FDT data puts a "simple-bus" compatible string on many things that
  151          * have children but aren't really busses in our world.  Without a
  152          * ranges property we will fail to attach, so just fail to probe too.
  153          */
  154         if (!(ofw_bus_is_compatible(dev, "simple-bus") &&
  155             ofw_bus_has_prop(dev, "ranges")) &&
  156             (ofw_bus_get_type(dev) == NULL || strcmp(ofw_bus_get_type(dev),
  157              "soc") != 0))
  158                 return (ENXIO);
  159 
  160         xlp_simplebus_init_resources();
  161         device_set_desc(dev, "XLP SoC bus");
  162 
  163         return (BUS_PROBE_SPECIFIC);
  164 }
  165 
  166 static struct resource *
  167 xlp_simplebus_alloc_resource(device_t bus, device_t child, int type, int *rid,
  168     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
  169 {
  170         struct rman                     *rm;
  171         struct resource                 *rv;
  172         struct resource_list_entry      *rle;
  173         struct simplebus_softc          *sc;
  174         struct simplebus_devinfo        *di;
  175         bus_space_tag_t                 bustag;
  176         int j, isdefault, passthrough, needsactivate;
  177 
  178         passthrough = (device_get_parent(child) != bus);
  179         needsactivate = flags & RF_ACTIVE;
  180         sc = device_get_softc(bus);
  181         di = device_get_ivars(child);
  182         rle = NULL;
  183         bustag = NULL;
  184 
  185         if (!passthrough) {
  186                 isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
  187                 if (isdefault) {
  188                         rle = resource_list_find(&di->rl, type, *rid);
  189                         if (rle == NULL)
  190                                 return (NULL);
  191                         if (rle->res != NULL)
  192                                 panic("%s: resource entry is busy", __func__);
  193                         start = rle->start;
  194                         count = ulmax(count, rle->count);
  195                         end = ulmax(rle->end, start + count - 1);
  196                 }
  197                 if (type == SYS_RES_MEMORY) {
  198                         /* Remap through ranges property */
  199                         for (j = 0; j < sc->nranges; j++) {
  200                                 if (start >= sc->ranges[j].bus && end <
  201                                     sc->ranges[j].bus + sc->ranges[j].size) {
  202                                         start -= sc->ranges[j].bus;
  203                                         start += sc->ranges[j].host;
  204                                         end -= sc->ranges[j].bus;
  205                                         end += sc->ranges[j].host;
  206                                         break;
  207                                 }
  208                         }
  209                         if (j == sc->nranges && sc->nranges != 0) {
  210                                 if (bootverbose)
  211                                         device_printf(bus, "Could not map resource "
  212                                             "%#jx-%#jx\n", start, end);
  213                                 return (NULL);
  214                         }
  215                 }
  216         }
  217         switch (type) {
  218         case SYS_RES_IRQ:
  219                 rm = &irq_rman;
  220                 break;
  221         case SYS_RES_IOPORT:
  222                 rm = &port_rman;
  223                 bustag = rmi_bus_space;
  224                 break;
  225         case SYS_RES_MEMORY:
  226                 if (start >= GBU_MEM_BASE && end <= GBU_MEM_LIMIT) {
  227                         rm = &gbu_rman;
  228                         bustag = rmi_bus_space;
  229                 } else if (start >= PCI_ECFG_BASE && end <= PCI_ECFG_LIMIT) {
  230                         rm = &pci_ecfg_rman;
  231                         bustag = rmi_uart_bus_space;
  232                 } else if (start >= PCIE_MEM_BASE && end <= PCIE_MEM_LIMIT) {
  233                         rm = &mem_rman;
  234                         bustag = rmi_bus_space;
  235                 } else {
  236                         if (bootverbose)
  237                                 device_printf(bus, "Invalid MEM range"
  238                                             "%#jx-%#jx\n", start, end);
  239                         return (NULL);
  240                 }
  241                 break;
  242         default:
  243                 return (NULL);
  244         }
  245 
  246         rv = rman_reserve_resource(rm, start, end, count, flags, child);
  247         if (rv == NULL) {
  248                 device_printf(bus, "%s: could not reserve resource for %s\n",
  249                     __func__, device_get_nameunit(child));
  250                 return (NULL);
  251         }
  252 
  253         rman_set_rid(rv, *rid);
  254         if (bustag != NULL)
  255                 rman_set_bustag(rv, bustag);
  256 
  257         if (needsactivate) {
  258                 if (bus_activate_resource(child, type, *rid, rv)) {
  259                         device_printf(bus, "%s: could not activate resource\n",
  260                             __func__);
  261                         rman_release_resource(rv);
  262                         return (NULL);
  263                 }
  264         }
  265 
  266         return (rv);
  267 }
  268 
  269 static int
  270 xlp_simplebus_activate_resource(device_t bus, device_t child, int type, int rid,
  271     struct resource *r)
  272 {
  273         void *vaddr;
  274         vm_paddr_t paddr;
  275         vm_size_t psize;
  276 
  277         /*
  278          * If this is a memory resource, use pmap_mapdev to map it.
  279          */
  280         if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
  281                 paddr = rman_get_start(r);
  282                 psize = rman_get_size(r);
  283                 vaddr = pmap_mapdev(paddr, psize);
  284 
  285                 rman_set_virtual(r, vaddr);
  286                 rman_set_bushandle(r, (bus_space_handle_t)(uintptr_t)vaddr);
  287         }
  288 
  289         return (rman_activate_resource(r));
  290 }
  291 
  292 static int
  293 xlp_simplebus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
  294     driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
  295 {
  296         register_t s;
  297         int irq;
  298 
  299         /* setup irq */
  300         s = intr_disable();
  301         irq = rman_get_start(res);
  302         cpu_establish_hardintr(device_get_nameunit(child), filt, intr, arg,
  303             irq, flags, cookiep);
  304         intr_restore(s);
  305         return (0);
  306 }
  307 
  308 static int
  309 xlp_simplebus_ofw_map_intr(device_t dev, device_t child, phandle_t iparent, int icells,
  310     pcell_t *irq)
  311 {
  312 
  313         return ((int)irq[0]);
  314 }

Cache object: a9c05e5800c87c176a35bad0305eda96


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