]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/beri/virtio/virtio_mmio_platform.c
Update nvi to 2.1.3 which fixes the data corruption when locale conversion
[FreeBSD/FreeBSD.git] / sys / dev / beri / virtio / virtio_mmio_platform.c
1 /*-
2  * Copyright (c) 2014 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         bus_space_tag_t         bst;
74         bus_space_handle_t      bsh;
75         device_t                dev;
76         void                    (*intr_handler)(void *);
77         void                    *ih_user;
78         device_t                pio_recv;
79         device_t                pio_send;
80 };
81
82 static int
83 setup_pio(struct virtio_mmio_platform_softc *sc, char *name, device_t *dev)
84 {
85         phandle_t pio_node;
86         struct fdt_ic *ic;
87         phandle_t xref;
88         phandle_t node;
89
90         if ((node = ofw_bus_get_node(sc->dev)) == -1)
91                 return (ENXIO);
92
93         if (OF_searchencprop(node, name, &xref,
94                 sizeof(xref)) == -1) {
95                 return (ENXIO);
96         }
97
98         pio_node = OF_node_from_xref(xref);
99         SLIST_FOREACH(ic, &fdt_ic_list_head, fdt_ics) {
100                 if (ic->iph == pio_node) {
101                         *dev = ic->dev;
102                         PIO_CONFIGURE(*dev, PIO_OUT_ALL,
103                                         PIO_UNMASK_ALL);
104                         return (0);
105                 }
106         }
107
108         return (ENXIO);
109 }
110
111 static int
112 virtio_mmio_platform_probe(device_t dev)
113 {
114
115         if (!ofw_bus_status_okay(dev))
116                 return (ENXIO);
117
118         if (!ofw_bus_is_compatible(dev, "beri,virtio_mmio_platform"))
119                 return (ENXIO);
120
121         device_set_desc(dev, "Virtio MMIO platform");
122         return (BUS_PROBE_DEFAULT);
123 }
124
125 static int
126 virtio_mmio_platform_attach(device_t dev)
127 {
128         struct virtio_mmio_platform_softc *sc;
129         struct fdt_ic *fic;
130         phandle_t node;
131
132         sc = device_get_softc(dev);
133         sc->dev = dev;
134
135         if (setup_pio(sc, "pio-send", &sc->pio_send) != 0)
136                 return (ENXIO);
137         if (setup_pio(sc, "pio-recv", &sc->pio_recv) != 0)
138                 return (ENXIO);
139
140         if ((node = ofw_bus_get_node(sc->dev)) == -1)
141                 return (ENXIO);
142
143         fic = malloc(sizeof(*fic), M_DEVBUF, M_WAITOK|M_ZERO);
144         fic->iph = node;
145         fic->dev = dev;
146         SLIST_INSERT_HEAD(&fdt_ic_list_head, fic, fdt_ics);
147
148         return (0);
149 }
150
151 static int
152 platform_note(device_t dev, size_t offset, int val)
153 {
154         struct virtio_mmio_platform_softc *sc;
155         int note;
156         int i;
157
158         sc = device_get_softc(dev);
159
160         switch (offset) {
161                 case (VIRTIO_MMIO_QUEUE_NOTIFY):
162                         if (val == 0)
163                                 note = Q_NOTIFY;
164                         else if (val == 1)
165                                 note = Q_NOTIFY1;
166                         break;
167                 case (VIRTIO_MMIO_QUEUE_PFN):
168                         note = Q_PFN;
169                         break;
170                 case (VIRTIO_MMIO_QUEUE_SEL):
171                         note = Q_SEL;
172                         break;
173                 default:
174                         note = 0;
175         }
176
177         if (note) {
178                 mips_dcache_wbinv_all();
179
180                 PIO_SET(sc->pio_send, note, 1);
181
182                 /* 
183                  * Wait until host ack the request.
184                  * Usually done within few cycles.
185                  * TODO: bad
186                  */
187
188                 for (i = 100; i > 0; i--) {
189                         if (PIO_READ(sc->pio_send) == 0)
190                                 break;
191                 }
192
193                 if (i == 0)
194                         device_printf(sc->dev, "Warning: host busy\n");
195         }
196
197         return (0);
198 }
199
200 static void
201 platform_intr(void *arg)
202 {
203         struct virtio_mmio_platform_softc *sc;
204         int reg;
205
206         sc = arg;
207
208         /* Read pending */
209         reg = PIO_READ(sc->pio_recv);
210
211         /* Ack */
212         PIO_SET(sc->pio_recv, reg, 0);
213
214         /* Writeback, invalidate cache */
215         mips_dcache_wbinv_all();
216
217         if (sc->intr_handler != NULL)
218                 sc->intr_handler(sc->ih_user);
219 }
220
221 static int
222 platform_setup_intr(device_t dev, device_t mmio_dev,
223                         void *intr_handler, void *ih_user)
224 {
225         struct virtio_mmio_platform_softc *sc;
226
227         sc = device_get_softc(dev);
228
229         sc->intr_handler = intr_handler;
230         sc->ih_user = ih_user;
231
232         PIO_SETUP_IRQ(sc->pio_recv, platform_intr, sc);
233
234         return (0);
235 }
236
237 static int
238 platform_poll(device_t dev)
239 {
240
241         mips_dcache_wbinv_all();
242
243         return (0);
244 }
245
246 static device_method_t virtio_mmio_platform_methods[] = {
247         DEVMETHOD(device_probe,         virtio_mmio_platform_probe),
248         DEVMETHOD(device_attach,        virtio_mmio_platform_attach),
249
250         /* virtio_mmio_if.h */
251         DEVMETHOD(virtio_mmio_note,             platform_note),
252         DEVMETHOD(virtio_mmio_poll,             platform_poll),
253         DEVMETHOD(virtio_mmio_setup_intr,       platform_setup_intr),
254         DEVMETHOD_END
255 };
256
257 static driver_t virtio_mmio_platform_driver = {
258         "virtio_mmio_platform",
259         virtio_mmio_platform_methods,
260         sizeof(struct virtio_mmio_platform_softc),
261 };
262
263 static devclass_t virtio_mmio_platform_devclass;
264
265 DRIVER_MODULE(virtio_mmio_platform, simplebus, virtio_mmio_platform_driver,
266         virtio_mmio_platform_devclass, 0, 0);