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/dev/beri/virtio/virtio_mmio_platform.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) 2014-2015 Ruslan Bukin <br@bsdpad.com>
    3  * All rights reserved.
    4  *
    5  * This software was developed by SRI International and the University of
    6  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
    7  * ("CTSRD"), as part of the DARPA CRASH research programme.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   26  * LIABILITY, 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 
   31 /*
   32  * BERI interface for Virtio MMIO bus.
   33  *
   34  * This driver provides interrupt-engine for software-implemented
   35  * Virtio MMIO backend.
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __FBSDID("$FreeBSD$");
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/bus.h>
   44 #include <sys/kernel.h>
   45 #include <sys/module.h>
   46 #include <sys/malloc.h>
   47 #include <sys/rman.h>
   48 #include <sys/timeet.h>
   49 #include <sys/timetc.h>
   50 #include <sys/watchdog.h>
   51 
   52 #include <machine/bus.h>
   53 #include <machine/fdt.h>
   54 #include <machine/cpu.h>
   55 #include <machine/cache.h>
   56 
   57 #include <dev/fdt/fdt_common.h>
   58 #include <dev/ofw/openfirm.h>
   59 #include <dev/ofw/ofw_bus.h>
   60 #include <dev/ofw/ofw_bus_subr.h>
   61 
   62 #include <dev/beri/virtio/virtio_mmio_platform.h>
   63 #include <dev/virtio/mmio/virtio_mmio.h>
   64 #include <dev/altera/pio/pio.h>
   65 
   66 #include "virtio_mmio_if.h"
   67 #include "pio_if.h"
   68 
   69 static void platform_intr(void *arg);
   70 
   71 struct virtio_mmio_platform_softc {
   72         struct resource         *res[1];
   73         void                    *ih;
   74         bus_space_tag_t         bst;
   75         bus_space_handle_t      bsh;
   76         device_t                dev;
   77         void                    (*intr_handler)(void *);
   78         void                    *ih_user;
   79         device_t                pio_recv;
   80         device_t                pio_send;
   81         int                     use_pio;
   82 };
   83 
   84 static int
   85 setup_pio(struct virtio_mmio_platform_softc *sc, char *name, device_t *dev)
   86 {
   87         phandle_t pio_node;
   88         struct fdt_ic *ic;
   89         phandle_t xref;
   90         phandle_t node;
   91 
   92         if ((node = ofw_bus_get_node(sc->dev)) == -1)
   93                 return (ENXIO);
   94 
   95         if (OF_searchencprop(node, name, &xref,
   96                 sizeof(xref)) == -1) {
   97                 return (ENXIO);
   98         }
   99 
  100         pio_node = OF_node_from_xref(xref);
  101         SLIST_FOREACH(ic, &fdt_ic_list_head, fdt_ics) {
  102                 if (ic->iph == pio_node) {
  103                         *dev = ic->dev;
  104                         PIO_CONFIGURE(*dev, PIO_OUT_ALL,
  105                                         PIO_UNMASK_ALL);
  106                         return (0);
  107                 }
  108         }
  109 
  110         return (ENXIO);
  111 }
  112 
  113 static int
  114 virtio_mmio_platform_probe(device_t dev)
  115 {
  116 
  117         if (!ofw_bus_status_okay(dev))
  118                 return (ENXIO);
  119 
  120         if (!ofw_bus_is_compatible(dev, "beri,virtio_mmio_platform"))
  121                 return (ENXIO);
  122 
  123         device_set_desc(dev, "Virtio MMIO platform");
  124         return (BUS_PROBE_DEFAULT);
  125 }
  126 
  127 static int
  128 virtio_mmio_platform_attach(device_t dev)
  129 {
  130         struct virtio_mmio_platform_softc *sc;
  131         struct fdt_ic *fic;
  132         phandle_t node;
  133 
  134         sc = device_get_softc(dev);
  135         sc->dev = dev;
  136         sc->use_pio = 1;
  137 
  138         if ((setup_pio(sc, "pio-send", &sc->pio_send) != 0) ||
  139             (setup_pio(sc, "pio-recv", &sc->pio_recv) != 0))
  140                 sc->use_pio = 0;
  141 
  142         if ((node = ofw_bus_get_node(sc->dev)) == -1)
  143                 return (ENXIO);
  144 
  145         fic = malloc(sizeof(*fic), M_DEVBUF, M_WAITOK|M_ZERO);
  146         fic->iph = node;
  147         fic->dev = dev;
  148         SLIST_INSERT_HEAD(&fdt_ic_list_head, fic, fdt_ics);
  149 
  150         return (0);
  151 }
  152 
  153 static int
  154 platform_prewrite(device_t dev, size_t offset, int val)
  155 {
  156         struct virtio_mmio_platform_softc *sc;
  157 
  158         sc = device_get_softc(dev);
  159 
  160         switch (offset) {
  161         case (VIRTIO_MMIO_QUEUE_NOTIFY):
  162                 mips_dcache_wbinv_all();
  163                 break;
  164         default:
  165                 break;
  166         }
  167 
  168         return (0);
  169 }
  170 
  171 static int
  172 platform_note(device_t dev, size_t offset, int val)
  173 {
  174         struct virtio_mmio_platform_softc *sc;
  175         int note;
  176         int i;
  177 
  178         sc = device_get_softc(dev);
  179 
  180         switch (offset) {
  181         case (VIRTIO_MMIO_QUEUE_NOTIFY):
  182                 if (val == 0)
  183                         note = Q_NOTIFY;
  184                 else if (val == 1)
  185                         note = Q_NOTIFY1;
  186                 else
  187                         note = 0;
  188                 break;
  189         case (VIRTIO_MMIO_QUEUE_PFN):
  190                 note = Q_PFN;
  191                 break;
  192         case (VIRTIO_MMIO_QUEUE_SEL):
  193                 note = Q_SEL;
  194                 break;
  195         default:
  196                 note = 0;
  197         }
  198 
  199         if (note) {
  200                 mips_dcache_wbinv_all();
  201 
  202                 if (!sc->use_pio)
  203                         return (0);
  204 
  205                 PIO_SET(sc->pio_send, note, 1);
  206 
  207                 /* 
  208                  * Wait until host ack the request.
  209                  * Usually done within few cycles.
  210                  * TODO: bad
  211                  */
  212 
  213                 for (i = 100; i > 0; i--) {
  214                         if (PIO_READ(sc->pio_send) == 0)
  215                                 break;
  216                 }
  217 
  218                 if (i == 0)
  219                         device_printf(sc->dev, "Warning: host busy\n");
  220         }
  221 
  222         return (0);
  223 }
  224 
  225 static void
  226 platform_intr(void *arg)
  227 {
  228         struct virtio_mmio_platform_softc *sc;
  229         int reg;
  230 
  231         sc = arg;
  232 
  233         if (sc->use_pio) {
  234                 /* Read pending */
  235                 reg = PIO_READ(sc->pio_recv);
  236 
  237                 /* Ack */
  238                 PIO_SET(sc->pio_recv, reg, 0);
  239         }
  240 
  241         /* Writeback, invalidate cache */
  242         mips_dcache_wbinv_all();
  243 
  244         if (sc->intr_handler != NULL)
  245                 sc->intr_handler(sc->ih_user);
  246 }
  247 
  248 static int
  249 platform_setup_intr(device_t dev, device_t mmio_dev,
  250                         void *intr_handler, void *ih_user)
  251 {
  252         struct virtio_mmio_platform_softc *sc;
  253         int rid;
  254 
  255         sc = device_get_softc(dev);
  256 
  257         sc->intr_handler = intr_handler;
  258         sc->ih_user = ih_user;
  259 
  260         if (sc->use_pio) {
  261                 PIO_SETUP_IRQ(sc->pio_recv, platform_intr, sc);
  262                 return (0);
  263         }
  264 
  265         rid = 0;
  266         sc->res[0] = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  267                 RF_ACTIVE);
  268         if (!sc->res[0]) {
  269                 device_printf(dev, "Can't allocate interrupt\n");
  270                 return (ENXIO);
  271         }
  272 
  273         if (bus_setup_intr(dev, sc->res[0], INTR_TYPE_MISC | INTR_MPSAFE,
  274                 NULL, platform_intr, sc, &sc->ih)) {
  275                 device_printf(dev, "Can't setup the interrupt\n");
  276                 return (ENXIO);
  277         }
  278 
  279         return (0);
  280 }
  281 
  282 static int
  283 platform_poll(device_t dev)
  284 {
  285 
  286         mips_dcache_wbinv_all();
  287 
  288         return (0);
  289 }
  290 
  291 static device_method_t virtio_mmio_platform_methods[] = {
  292         DEVMETHOD(device_probe,         virtio_mmio_platform_probe),
  293         DEVMETHOD(device_attach,        virtio_mmio_platform_attach),
  294 
  295         /* virtio_mmio_if.h */
  296         DEVMETHOD(virtio_mmio_prewrite,         platform_prewrite),
  297         DEVMETHOD(virtio_mmio_note,             platform_note),
  298         DEVMETHOD(virtio_mmio_poll,             platform_poll),
  299         DEVMETHOD(virtio_mmio_setup_intr,       platform_setup_intr),
  300         DEVMETHOD_END
  301 };
  302 
  303 static driver_t virtio_mmio_platform_driver = {
  304         "virtio_mmio_platform",
  305         virtio_mmio_platform_methods,
  306         sizeof(struct virtio_mmio_platform_softc),
  307 };
  308 
  309 DRIVER_MODULE(virtio_mmio_platform, simplebus, virtio_mmio_platform_driver,
  310     0, 0);

Cache object: f47bdd44ccae2ef9b732b295cab3b05b


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