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/pci/ofw_pci.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 - 2003 by Thomas Moestl <tmm@FreeBSD.org>
    4  * Copyright (c) 2005 - 2015 by Marius Strobl <marius@FreeBSD.org>
    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  * 3. The name of the author may not be used to endorse or promote products
   16  *    derived from this software without specific prior written permission.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  *
   30  *      from: NetBSD: psycho.c,v 1.35 2001/09/10 16:17:06 eeh Exp
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD: releng/11.2/sys/sparc64/pci/ofw_pci.c 300173 2016-05-18 23:39:31Z gonzo $");
   35 
   36 #include "opt_ofw_pci.h"
   37 
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/bus.h>
   41 #include <sys/kernel.h>
   42 #include <sys/rman.h>
   43 
   44 #include <dev/ofw/ofw_bus.h>
   45 #include <dev/ofw/ofw_pci.h>
   46 #include <dev/ofw/openfirm.h>
   47 
   48 #include <dev/pci/pcireg.h>
   49 #include <dev/pci/pcivar.h>
   50 
   51 #include <machine/asi.h>
   52 #include <machine/bus.h>
   53 #include <machine/bus_private.h>
   54 #include <machine/cpufunc.h>
   55 #include <machine/fsr.h>
   56 #include <machine/resource.h>
   57 
   58 #include <sparc64/pci/ofw_pci.h>
   59 
   60 int
   61 ofw_pci_attach_common(device_t dev, bus_dma_tag_t dmat, u_long iosize,
   62     u_long memsize)
   63 {
   64         struct ofw_pci_softc *sc;
   65         struct ofw_pci_ranges *range;
   66         phandle_t node;
   67         uint32_t prop_array[2];
   68         u_int i, j, nrange;
   69 
   70         sc = device_get_softc(dev);
   71         node = ofw_bus_get_node(dev);
   72         sc->sc_node = node;
   73         sc->sc_pci_dmat = dmat;
   74 
   75         /* Initialize memory and I/O rmans. */
   76         sc->sc_pci_io_rman.rm_type = RMAN_ARRAY;
   77         sc->sc_pci_io_rman.rm_descr = "PCI I/O Ports";
   78         if (rman_init(&sc->sc_pci_io_rman) != 0 ||
   79             rman_manage_region(&sc->sc_pci_io_rman, 0, iosize) != 0) {
   80                 device_printf(dev, "failed to set up I/O rman\n");
   81                 return (ENXIO);
   82         }
   83         sc->sc_pci_mem_rman.rm_type = RMAN_ARRAY;
   84         sc->sc_pci_mem_rman.rm_descr = "PCI Memory";
   85         if (rman_init(&sc->sc_pci_mem_rman) != 0 ||
   86             rman_manage_region(&sc->sc_pci_mem_rman, 0, memsize) != 0) {
   87                 device_printf(dev, "failed to set up memory rman\n");
   88                 return (ENXIO);
   89         }
   90 
   91         /*
   92          * Find the addresses of the various bus spaces.  The physical
   93          * start addresses of the ranges are the configuration, I/O and
   94          * memory handles.  There should not be multiple ones of one kind.
   95          */
   96         nrange = OF_getprop_alloc(node, "ranges", sizeof(*range),
   97             (void **)&range);
   98         for (i = 0; i < nrange; i++) {
   99                 j = OFW_PCI_RANGE_CS(&range[i]);
  100                 if (sc->sc_pci_bh[j] != 0) {
  101                         device_printf(dev, "duplicate range for space %d\n",
  102                             j);
  103                         OF_prop_free(range);
  104                         return (EINVAL);
  105                 }
  106                 sc->sc_pci_bh[j] = OFW_PCI_RANGE_PHYS(&range[i]);
  107         }
  108         OF_prop_free(range);
  109 
  110         /*
  111          * Make sure that the expected ranges are actually present.
  112          * The OFW_PCI_CS_MEM64 one is not currently used.
  113          */
  114         if (sc->sc_pci_bh[OFW_PCI_CS_CONFIG] == 0) {
  115                 device_printf(dev, "missing CONFIG range\n");
  116                 return (ENXIO);
  117         }
  118         if (sc->sc_pci_bh[OFW_PCI_CS_IO] == 0) {
  119                 device_printf(dev, "missing IO range\n");
  120                 return (ENXIO);
  121         }
  122         if (sc->sc_pci_bh[OFW_PCI_CS_MEM32] == 0) {
  123                 device_printf(dev, "missing MEM32 range\n");
  124                 return (ENXIO);
  125         }
  126 
  127         /* Allocate our tags. */
  128         sc->sc_pci_iot = sparc64_alloc_bus_tag(NULL, PCI_IO_BUS_SPACE);
  129         if (sc->sc_pci_iot == NULL) {
  130                 device_printf(dev, "could not allocate PCI I/O tag\n");
  131                 return (ENXIO);
  132         }
  133         sc->sc_pci_cfgt = sparc64_alloc_bus_tag(NULL, PCI_CONFIG_BUS_SPACE);
  134         if (sc->sc_pci_cfgt == NULL) {
  135                 device_printf(dev,
  136                     "could not allocate PCI configuration space tag\n");
  137                 return (ENXIO);
  138         }
  139 
  140         /*
  141          * Get the bus range from the firmware.
  142          */
  143         i = OF_getprop(node, "bus-range", (void *)prop_array,
  144             sizeof(prop_array));
  145         if (i == -1) {
  146                 device_printf(dev, "could not get bus-range\n");
  147                 return (ENXIO);
  148         }
  149         if (i != sizeof(prop_array)) {
  150                 device_printf(dev, "broken bus-range (%d)", i);
  151                 return (EINVAL);
  152         }
  153         sc->sc_pci_secbus = prop_array[0];
  154         sc->sc_pci_subbus = prop_array[1];
  155         if (bootverbose != 0)
  156                 device_printf(dev, "bus range %u to %u; PCI bus %d\n",
  157                     sc->sc_pci_secbus, sc->sc_pci_subbus, sc->sc_pci_secbus);
  158 
  159         ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(ofw_pci_intr_t));
  160 
  161         return (0);
  162 }
  163 
  164 uint32_t
  165 ofw_pci_read_config_common(device_t dev, u_int regmax, u_long offset,
  166     u_int bus, u_int slot, u_int func, u_int reg, int width)
  167 {
  168         struct ofw_pci_softc *sc;
  169         bus_space_handle_t bh;
  170         uint32_t r, wrd;
  171         int i;
  172         uint16_t shrt;
  173         uint8_t byte;
  174 
  175         sc = device_get_softc(dev);
  176         if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
  177             slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax)
  178                 return (-1);
  179 
  180         bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
  181         switch (width) {
  182         case 1:
  183                 i = bus_space_peek_1(sc->sc_pci_cfgt, bh, offset, &byte);
  184                 r = byte;
  185                 break;
  186         case 2:
  187                 i = bus_space_peek_2(sc->sc_pci_cfgt, bh, offset, &shrt);
  188                 r = shrt;
  189                 break;
  190         case 4:
  191                 i = bus_space_peek_4(sc->sc_pci_cfgt, bh, offset, &wrd);
  192                 r = wrd;
  193                 break;
  194         default:
  195                 panic("%s: bad width %d", __func__, width);
  196                 /* NOTREACHED */
  197         }
  198 
  199         if (i) {
  200 #ifdef OFW_PCI_DEBUG
  201                 printf("%s: read data error reading: %d.%d.%d: 0x%x\n",
  202                     __func__, bus, slot, func, reg);
  203 #endif
  204                 r = -1;
  205         }
  206         return (r);
  207 }
  208 
  209 void
  210 ofw_pci_write_config_common(device_t dev, u_int regmax, u_long offset,
  211     u_int bus, u_int slot, u_int func, u_int reg, uint32_t val, int width)
  212 {
  213         struct ofw_pci_softc *sc;
  214         bus_space_handle_t bh;
  215 
  216         sc = device_get_softc(dev);
  217         if (bus < sc->sc_pci_secbus || bus > sc->sc_pci_subbus ||
  218             slot > PCI_SLOTMAX || func > PCI_FUNCMAX || reg > regmax)
  219                 return;
  220 
  221         bh = sc->sc_pci_bh[OFW_PCI_CS_CONFIG];
  222         switch (width) {
  223         case 1:
  224                 bus_space_write_1(sc->sc_pci_cfgt, bh, offset, val);
  225                 break;
  226         case 2:
  227                 bus_space_write_2(sc->sc_pci_cfgt, bh, offset, val);
  228                 break;
  229         case 4:
  230                 bus_space_write_4(sc->sc_pci_cfgt, bh, offset, val);
  231                 break;
  232         default:
  233                 panic("%s: bad width %d", __func__, width);
  234                 /* NOTREACHED */
  235         }
  236 }
  237 
  238 ofw_pci_intr_t
  239 ofw_pci_route_interrupt_common(device_t bridge, device_t dev, int pin)
  240 {
  241         struct ofw_pci_softc *sc;
  242         struct ofw_pci_register reg;
  243         ofw_pci_intr_t pintr, mintr;
  244 
  245         sc = device_get_softc(bridge);
  246         pintr = pin;
  247         if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo,
  248             &reg, sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr),
  249             NULL) != 0)
  250                 return (mintr);
  251         return (PCI_INVALID_IRQ);
  252 }
  253 
  254 void
  255 ofw_pci_dmamap_sync_stst_order_common(void)
  256 {
  257         static u_char buf[VIS_BLOCKSIZE] __aligned(VIS_BLOCKSIZE);
  258         register_t reg, s;
  259 
  260         s = intr_disable();
  261         reg = rd(fprs);
  262         wr(fprs, reg | FPRS_FEF, 0);
  263         __asm __volatile("stda %%f0, [%0] %1"
  264             : : "r" (buf), "n" (ASI_BLK_COMMIT_S));
  265         membar(Sync);
  266         wr(fprs, reg, 0);
  267         intr_restore(s);
  268 }
  269 
  270 int
  271 ofw_pci_read_ivar(device_t dev, device_t child __unused, int which,
  272     uintptr_t *result)
  273 {
  274         struct ofw_pci_softc *sc;
  275 
  276         switch (which) {
  277         case PCIB_IVAR_DOMAIN:
  278                 *result = device_get_unit(dev);
  279                 return (0);
  280         case PCIB_IVAR_BUS:
  281                 sc = device_get_softc(dev);
  282                 *result = sc->sc_pci_secbus;
  283                 return (0);
  284         }
  285         return (ENOENT);
  286 }
  287 
  288 struct resource *
  289 ofw_pci_alloc_resource(device_t bus, device_t child, int type, int *rid,
  290     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
  291 {
  292         struct ofw_pci_softc *sc;
  293         struct resource *rv;
  294         struct rman *rm;
  295 
  296         sc = device_get_softc(bus);
  297         switch (type) {
  298         case SYS_RES_IRQ:
  299                 /*
  300                  * XXX: Don't accept blank ranges for now, only single
  301                  * interrupts.  The other case should not happen with
  302                  * the MI PCI code ...
  303                  * XXX: This may return a resource that is out of the
  304                  * range that was specified.  Is this correct ...?
  305                  */
  306                 if (start != end)
  307                         panic("%s: XXX: interrupt range", __func__);
  308                 return (bus_generic_alloc_resource(bus, child, type, rid,
  309                     start, end, count, flags));
  310         case SYS_RES_MEMORY:
  311                 rm = &sc->sc_pci_mem_rman;
  312                 break;
  313         case SYS_RES_IOPORT:
  314                 rm = &sc->sc_pci_io_rman;
  315                 break;
  316         default:
  317                 return (NULL);
  318         }
  319 
  320         rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
  321             child);
  322         if (rv == NULL)
  323                 return (NULL);
  324         rman_set_rid(rv, *rid);
  325 
  326         if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type,
  327             *rid, rv) != 0) {
  328                 rman_release_resource(rv);
  329                 return (NULL);
  330         }
  331         return (rv);
  332 }
  333 
  334 int
  335 ofw_pci_activate_resource(device_t bus, device_t child, int type, int rid,
  336     struct resource *r)
  337 {
  338         struct ofw_pci_softc *sc;
  339         struct bus_space_tag *tag;
  340 
  341         sc = device_get_softc(bus);
  342         switch (type) {
  343         case SYS_RES_IRQ:
  344                 return (bus_generic_activate_resource(bus, child, type, rid,
  345                     r));
  346         case SYS_RES_MEMORY:
  347                 tag = sparc64_alloc_bus_tag(r, PCI_MEMORY_BUS_SPACE);
  348                 if (tag == NULL)
  349                         return (ENOMEM);
  350                 rman_set_bustag(r, tag);
  351                 rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_MEM32] +
  352                     rman_get_start(r));
  353                 break;
  354         case SYS_RES_IOPORT:
  355                 rman_set_bustag(r, sc->sc_pci_iot);
  356                 rman_set_bushandle(r, sc->sc_pci_bh[OFW_PCI_CS_IO] +
  357                     rman_get_start(r));
  358                 break;
  359         }
  360         return (rman_activate_resource(r));
  361 }
  362 
  363 int
  364 ofw_pci_adjust_resource(device_t bus, device_t child, int type,
  365     struct resource *r, rman_res_t start, rman_res_t end)
  366 {
  367         struct ofw_pci_softc *sc;
  368         struct rman *rm;
  369 
  370         sc = device_get_softc(bus);
  371         switch (type) {
  372         case SYS_RES_IRQ:
  373                 return (bus_generic_adjust_resource(bus, child, type, r,
  374                     start, end));
  375         case SYS_RES_MEMORY:
  376                 rm = &sc->sc_pci_mem_rman;
  377                 break;
  378         case SYS_RES_IOPORT:
  379                 rm = &sc->sc_pci_io_rman;
  380                 break;
  381         default:
  382                 return (EINVAL);
  383         }
  384         if (rman_is_region_manager(r, rm) == 0)
  385                 return (EINVAL);
  386         return (rman_adjust_resource(r, start, end));
  387 }
  388 
  389 bus_dma_tag_t
  390 ofw_pci_get_dma_tag(device_t bus, device_t child __unused)
  391 {
  392         struct ofw_pci_softc *sc;
  393 
  394         sc = device_get_softc(bus);
  395         return (sc->sc_pci_dmat);
  396 }
  397 
  398 phandle_t
  399 ofw_pci_get_node(device_t bus, device_t child __unused)
  400 {
  401         struct ofw_pci_softc *sc;
  402 
  403         sc = device_get_softc(bus);
  404         /* We only have one child, the PCI bus, which needs our own node. */
  405         return (sc->sc_node);
  406 }

Cache object: df925ce846fb2973bf2c9a7f9046a4cc


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