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 Virtio Networking Frontend
33 */
34
35 #include <sys/cdefs.h>
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/malloc.h>
42 #include <sys/rman.h>
43 #include <sys/timeet.h>
44 #include <sys/timetc.h>
45 #include <sys/endian.h>
46 #include <sys/lock.h>
47 #include <sys/mbuf.h>
48 #include <sys/mutex.h>
49 #include <sys/socket.h>
50 #include <sys/sockio.h>
51 #include <sys/sysctl.h>
52 #include <sys/mdioctl.h>
53 #include <sys/conf.h>
54 #include <sys/stat.h>
55 #include <sys/uio.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 <net/bpf.h>
63 #include <net/if.h>
64 #include <net/ethernet.h>
65 #include <net/if_dl.h>
66 #include <net/if_media.h>
67 #include <net/if_types.h>
68 #include <net/if_var.h>
69 #include <net/if_vlan_var.h>
70
71 #include <netinet/in.h>
72 #include <netinet/udp.h>
73 #include <netinet/tcp.h>
74
75 #include <machine/bus.h>
76 #include <machine/fdt.h>
77 #include <machine/cpu.h>
78 #include <machine/intr.h>
79
80 #include <dev/beri/virtio/virtio.h>
81 #include <dev/beri/virtio/virtio_mmio_platform.h>
82
83 #include <dev/altera/pio/pio.h>
84
85 #include <dev/virtio/mmio/virtio_mmio.h>
86 #include <dev/virtio/network/virtio_net.h>
87 #include <dev/virtio/virtio_ids.h>
88 #include <dev/virtio/virtio_config.h>
89 #include <dev/virtio/virtio_ring.h>
90
91 #include "pio_if.h"
92
93 #define DPRINTF(fmt, args...) printf(fmt, ##args)
94
95 #define READ4(_sc, _reg) \
96 bus_read_4((_sc)->res[0], _reg)
97 #define WRITE4(_sc, _reg, _val) \
98 bus_write_4((_sc)->res[0], _reg, _val)
99
100 #define VTBE_LOCK(sc) mtx_lock(&(sc)->mtx)
101 #define VTBE_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
102 #define VTBE_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED);
103 #define VTBE_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED);
104
105 /*
106 * Driver data and defines.
107 */
108 #define DESC_COUNT 256
109
110 struct vtbe_softc {
111 struct resource *res[2];
112 bus_space_tag_t bst;
113 bus_space_handle_t bsh;
114 device_t dev;
115 struct ifnet *ifp;
116 int if_flags;
117 struct mtx mtx;
118 boolean_t is_attached;
119
120 int beri_mem_offset;
121 device_t pio_send;
122 device_t pio_recv;
123 int opened;
124
125 struct vqueue_info vs_queues[2];
126 int vs_curq;
127 int hdrsize;
128 };
129
130 static struct resource_spec vtbe_spec[] = {
131 { SYS_RES_MEMORY, 0, RF_ACTIVE },
132 { -1, 0 }
133 };
134
135 static void vtbe_txfinish_locked(struct vtbe_softc *sc);
136 static void vtbe_rxfinish_locked(struct vtbe_softc *sc);
137 static void vtbe_stop_locked(struct vtbe_softc *sc);
138 static int pio_enable_irq(struct vtbe_softc *sc, int enable);
139
140 static void
vtbe_txstart_locked(struct vtbe_softc * sc)141 vtbe_txstart_locked(struct vtbe_softc *sc)
142 {
143 struct iovec iov[DESC_COUNT];
144 struct virtio_net_hdr *vnh;
145 struct vqueue_info *vq;
146 struct iovec *tiov;
147 struct ifnet *ifp;
148 struct mbuf *m;
149 struct uio uio;
150 int enqueued;
151 int iolen;
152 int error;
153 int reg;
154 int len;
155 int n;
156
157 VTBE_ASSERT_LOCKED(sc);
158
159 /* RX queue */
160 vq = &sc->vs_queues[0];
161 if (!vq_has_descs(vq)) {
162 return;
163 }
164
165 ifp = sc->ifp;
166 if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
167 return;
168 }
169
170 enqueued = 0;
171
172 if (!vq_ring_ready(vq))
173 return;
174
175 vq->vq_save_used = be16toh(vq->vq_used->idx);
176
177 for (;;) {
178 if (!vq_has_descs(vq)) {
179 ifp->if_drv_flags |= IFF_DRV_OACTIVE;
180 break;
181 }
182
183 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
184 if (m == NULL) {
185 break;
186 }
187
188 n = vq_getchain(sc->beri_mem_offset, vq, iov,
189 DESC_COUNT, NULL);
190 KASSERT(n == 2,
191 ("Unexpected amount of descriptors (%d)", n));
192
193 tiov = getcopy(iov, n);
194 vnh = iov[0].iov_base;
195 memset(vnh, 0, sc->hdrsize);
196
197 len = iov[1].iov_len;
198 uio.uio_resid = len;
199 uio.uio_iov = &tiov[1];
200 uio.uio_segflg = UIO_SYSSPACE;
201 uio.uio_iovcnt = 1;
202 uio.uio_offset = 0;
203 uio.uio_rw = UIO_READ;
204
205 error = m_mbuftouio(&uio, m, 0);
206 if (error)
207 panic("m_mbuftouio failed\n");
208
209 iolen = (len - uio.uio_resid + sc->hdrsize);
210
211 free(tiov, M_DEVBUF);
212 vq_relchain(vq, iov, n, iolen);
213
214 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
215
216 BPF_MTAP(ifp, m);
217 m_freem(m);
218
219 ++enqueued;
220 }
221
222 if (enqueued != 0) {
223 reg = htobe32(VIRTIO_MMIO_INT_VRING);
224 WRITE4(sc, VIRTIO_MMIO_INTERRUPT_STATUS, reg);
225
226 PIO_SET(sc->pio_send, Q_INTR, 1);
227 }
228 }
229
230 static void
vtbe_txstart(struct ifnet * ifp)231 vtbe_txstart(struct ifnet *ifp)
232 {
233 struct vtbe_softc *sc = ifp->if_softc;
234
235 VTBE_LOCK(sc);
236 vtbe_txstart_locked(sc);
237 VTBE_UNLOCK(sc);
238 }
239
240 static void
vtbe_stop_locked(struct vtbe_softc * sc)241 vtbe_stop_locked(struct vtbe_softc *sc)
242 {
243 struct ifnet *ifp;
244
245 VTBE_ASSERT_LOCKED(sc);
246
247 ifp = sc->ifp;
248 ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
249 }
250
251 static void
vtbe_init_locked(struct vtbe_softc * sc)252 vtbe_init_locked(struct vtbe_softc *sc)
253 {
254 struct ifnet *ifp = sc->ifp;
255
256 VTBE_ASSERT_LOCKED(sc);
257
258 if (ifp->if_drv_flags & IFF_DRV_RUNNING)
259 return;
260
261 ifp->if_drv_flags |= IFF_DRV_RUNNING;
262 }
263
264 static void
vtbe_init(void * if_softc)265 vtbe_init(void *if_softc)
266 {
267 struct vtbe_softc *sc = if_softc;
268
269 VTBE_LOCK(sc);
270 vtbe_init_locked(sc);
271 VTBE_UNLOCK(sc);
272 }
273
274 static int
vtbe_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)275 vtbe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
276 {
277 struct ifmediareq *ifmr;
278 struct vtbe_softc *sc;
279 struct ifreq *ifr;
280 int mask, error;
281
282 sc = ifp->if_softc;
283 ifr = (struct ifreq *)data;
284
285 error = 0;
286 switch (cmd) {
287 case SIOCSIFFLAGS:
288 VTBE_LOCK(sc);
289 if (ifp->if_flags & IFF_UP) {
290 pio_enable_irq(sc, 1);
291
292 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
293 vtbe_init_locked(sc);
294 }
295 } else {
296 pio_enable_irq(sc, 0);
297
298 if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
299 vtbe_stop_locked(sc);
300 }
301 }
302 sc->if_flags = ifp->if_flags;
303 VTBE_UNLOCK(sc);
304 break;
305 case SIOCADDMULTI:
306 case SIOCDELMULTI:
307 break;
308 case SIOCSIFMEDIA:
309 case SIOCGIFMEDIA:
310 ifmr = (struct ifmediareq *)data;
311 ifmr->ifm_count = 1;
312 ifmr->ifm_status = (IFM_AVALID | IFM_ACTIVE);
313 ifmr->ifm_active = (IFM_ETHER | IFM_10G_T | IFM_FDX);
314 ifmr->ifm_current = ifmr->ifm_active;
315 break;
316 case SIOCSIFCAP:
317 mask = ifp->if_capenable ^ ifr->ifr_reqcap;
318 if (mask & IFCAP_VLAN_MTU) {
319 ifp->if_capenable ^= IFCAP_VLAN_MTU;
320 }
321 break;
322
323 case SIOCSIFADDR:
324 pio_enable_irq(sc, 1);
325 default:
326 error = ether_ioctl(ifp, cmd, data);
327 break;
328 }
329
330 return (error);
331 }
332
333 static void
vtbe_txfinish_locked(struct vtbe_softc * sc)334 vtbe_txfinish_locked(struct vtbe_softc *sc)
335 {
336 struct ifnet *ifp;
337
338 VTBE_ASSERT_LOCKED(sc);
339
340 ifp = sc->ifp;
341 }
342
343 static int
vq_init(struct vtbe_softc * sc)344 vq_init(struct vtbe_softc *sc)
345 {
346 struct vqueue_info *vq;
347 uint8_t *base;
348 int size;
349 int reg;
350 int pfn;
351
352 vq = &sc->vs_queues[sc->vs_curq];
353 vq->vq_qsize = DESC_COUNT;
354
355 reg = READ4(sc, VIRTIO_MMIO_QUEUE_PFN);
356 pfn = be32toh(reg);
357 vq->vq_pfn = pfn;
358
359 size = vring_size(vq->vq_qsize, VRING_ALIGN);
360 base = paddr_map(sc->beri_mem_offset,
361 (pfn << PAGE_SHIFT), size);
362
363 /* First pages are descriptors */
364 vq->vq_desc = (struct vring_desc *)base;
365 base += vq->vq_qsize * sizeof(struct vring_desc);
366
367 /* Then avail ring */
368 vq->vq_avail = (struct vring_avail *)base;
369 base += (2 + vq->vq_qsize + 1) * sizeof(uint16_t);
370
371 /* Then it's rounded up to the next page */
372 base = (uint8_t *)roundup2((uintptr_t)base, VRING_ALIGN);
373
374 /* And the last pages are the used ring */
375 vq->vq_used = (struct vring_used *)base;
376
377 /* Mark queue as allocated, and start at 0 when we use it. */
378 vq->vq_flags = VQ_ALLOC;
379 vq->vq_last_avail = 0;
380
381 return (0);
382 }
383
384 static void
vtbe_proc_rx(struct vtbe_softc * sc,struct vqueue_info * vq)385 vtbe_proc_rx(struct vtbe_softc *sc, struct vqueue_info *vq)
386 {
387 struct iovec iov[DESC_COUNT];
388 struct iovec *tiov;
389 struct ifnet *ifp;
390 struct uio uio;
391 struct mbuf *m;
392 int iolen;
393 int i;
394 int n;
395
396 ifp = sc->ifp;
397
398 n = vq_getchain(sc->beri_mem_offset, vq, iov,
399 DESC_COUNT, NULL);
400
401 KASSERT(n >= 1 && n <= DESC_COUNT,
402 ("wrong n %d", n));
403
404 tiov = getcopy(iov, n);
405
406 iolen = 0;
407 for (i = 1; i < n; i++) {
408 iolen += iov[i].iov_len;
409 }
410
411 uio.uio_resid = iolen;
412 uio.uio_iov = &tiov[1];
413 uio.uio_segflg = UIO_SYSSPACE;
414 uio.uio_iovcnt = (n - 1);
415 uio.uio_rw = UIO_WRITE;
416
417 if ((m = m_uiotombuf(&uio, M_NOWAIT, 0, ETHER_ALIGN,
418 M_PKTHDR)) == NULL) {
419 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
420 goto done;
421 }
422
423 m->m_pkthdr.rcvif = ifp;
424
425 if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
426
427 CURVNET_SET(ifp->if_vnet);
428 VTBE_UNLOCK(sc);
429 (*ifp->if_input)(ifp, m);
430 VTBE_LOCK(sc);
431 CURVNET_RESTORE();
432
433 done:
434 free(tiov, M_DEVBUF);
435 vq_relchain(vq, iov, n, iolen + sc->hdrsize);
436 }
437
438 static void
vtbe_rxfinish_locked(struct vtbe_softc * sc)439 vtbe_rxfinish_locked(struct vtbe_softc *sc)
440 {
441 struct vqueue_info *vq;
442 int reg;
443
444 /* TX queue */
445 vq = &sc->vs_queues[1];
446 if (!vq_ring_ready(vq))
447 return;
448
449 /* Process new descriptors */
450 vq->vq_save_used = be16toh(vq->vq_used->idx);
451
452 while (vq_has_descs(vq)) {
453 vtbe_proc_rx(sc, vq);
454 }
455
456 /* Interrupt the other side */
457 reg = htobe32(VIRTIO_MMIO_INT_VRING);
458 WRITE4(sc, VIRTIO_MMIO_INTERRUPT_STATUS, reg);
459
460 PIO_SET(sc->pio_send, Q_INTR, 1);
461 }
462
463 static void
vtbe_intr(void * arg)464 vtbe_intr(void *arg)
465 {
466 struct vtbe_softc *sc;
467 int pending;
468 uint32_t reg;
469
470 sc = arg;
471
472 VTBE_LOCK(sc);
473
474 reg = PIO_READ(sc->pio_recv);
475
476 /* Ack */
477 PIO_SET(sc->pio_recv, reg, 0);
478
479 pending = htobe32(reg);
480 if (pending & Q_SEL) {
481 reg = READ4(sc, VIRTIO_MMIO_QUEUE_SEL);
482 sc->vs_curq = be32toh(reg);
483 }
484
485 if (pending & Q_PFN) {
486 vq_init(sc);
487 }
488
489 if (pending & Q_NOTIFY) {
490 /* beri rx / arm tx notify */
491 vtbe_txfinish_locked(sc);
492 }
493
494 if (pending & Q_NOTIFY1) {
495 vtbe_rxfinish_locked(sc);
496 }
497
498 VTBE_UNLOCK(sc);
499 }
500
501 static int
vtbe_get_hwaddr(struct vtbe_softc * sc,uint8_t * hwaddr)502 vtbe_get_hwaddr(struct vtbe_softc *sc, uint8_t *hwaddr)
503 {
504 int rnd;
505
506 /*
507 * Generate MAC address, use 'bsd' + random 24 low-order bits.
508 */
509
510 rnd = arc4random() & 0x00ffffff;
511
512 hwaddr[0] = 'b';
513 hwaddr[1] = 's';
514 hwaddr[2] = 'd';
515 hwaddr[3] = rnd >> 16;
516 hwaddr[4] = rnd >> 8;
517 hwaddr[5] = rnd >> 0;
518
519 return (0);
520 }
521
522 static int
pio_enable_irq(struct vtbe_softc * sc,int enable)523 pio_enable_irq(struct vtbe_softc *sc, int enable)
524 {
525
526 /*
527 * IRQ lines should be disabled while reprogram FPGA core.
528 */
529
530 if (enable) {
531 if (sc->opened == 0) {
532 sc->opened = 1;
533 PIO_SETUP_IRQ(sc->pio_recv, vtbe_intr, sc);
534 }
535 } else {
536 if (sc->opened == 1) {
537 PIO_TEARDOWN_IRQ(sc->pio_recv);
538 sc->opened = 0;
539 }
540 }
541
542 return (0);
543 }
544
545 static int
vtbe_probe(device_t dev)546 vtbe_probe(device_t dev)
547 {
548
549 if (!ofw_bus_status_okay(dev))
550 return (ENXIO);
551
552 if (!ofw_bus_is_compatible(dev, "sri-cambridge,beri-vtnet"))
553 return (ENXIO);
554
555 device_set_desc(dev, "Virtio BERI Ethernet Controller");
556 return (BUS_PROBE_DEFAULT);
557 }
558
559 static int
vtbe_attach(device_t dev)560 vtbe_attach(device_t dev)
561 {
562 uint8_t macaddr[ETHER_ADDR_LEN];
563 struct vtbe_softc *sc;
564 struct ifnet *ifp;
565 int reg;
566
567 sc = device_get_softc(dev);
568 sc->dev = dev;
569
570 sc->hdrsize = sizeof(struct virtio_net_hdr);
571
572 if (bus_alloc_resources(dev, vtbe_spec, sc->res)) {
573 device_printf(dev, "could not allocate resources\n");
574 return (ENXIO);
575 }
576
577 /* Memory interface */
578 sc->bst = rman_get_bustag(sc->res[0]);
579 sc->bsh = rman_get_bushandle(sc->res[0]);
580
581 mtx_init(&sc->mtx, device_get_nameunit(sc->dev),
582 MTX_NETWORK_LOCK, MTX_DEF);
583
584 if (setup_offset(dev, &sc->beri_mem_offset) != 0)
585 return (ENXIO);
586 if (setup_pio(dev, "pio-send", &sc->pio_send) != 0)
587 return (ENXIO);
588 if (setup_pio(dev, "pio-recv", &sc->pio_recv) != 0)
589 return (ENXIO);
590
591 /* Setup MMIO */
592
593 /* Specify that we provide network device */
594 reg = htobe32(VIRTIO_ID_NETWORK);
595 WRITE4(sc, VIRTIO_MMIO_DEVICE_ID, reg);
596
597 /* The number of desc we support */
598 reg = htobe32(DESC_COUNT);
599 WRITE4(sc, VIRTIO_MMIO_QUEUE_NUM_MAX, reg);
600
601 /* Our features */
602 reg = htobe32(VIRTIO_NET_F_MAC |
603 VIRTIO_F_NOTIFY_ON_EMPTY);
604 WRITE4(sc, VIRTIO_MMIO_HOST_FEATURES, reg);
605
606 /* Get MAC */
607 if (vtbe_get_hwaddr(sc, macaddr)) {
608 device_printf(sc->dev, "can't get mac\n");
609 return (ENXIO);
610 }
611
612 /* Set up the ethernet interface. */
613 sc->ifp = ifp = if_alloc(IFT_ETHER);
614 ifp->if_baudrate = IF_Gbps(10);
615 ifp->if_softc = sc;
616 if_initname(ifp, device_get_name(dev), device_get_unit(dev));
617 ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX |
618 IFF_MULTICAST | IFF_PROMISC);
619 ifp->if_capabilities = IFCAP_VLAN_MTU;
620 ifp->if_capenable = ifp->if_capabilities;
621 ifp->if_start = vtbe_txstart;
622 ifp->if_ioctl = vtbe_ioctl;
623 ifp->if_init = vtbe_init;
624 IFQ_SET_MAXLEN(&ifp->if_snd, DESC_COUNT - 1);
625 ifp->if_snd.ifq_drv_maxlen = DESC_COUNT - 1;
626 IFQ_SET_READY(&ifp->if_snd);
627 ifp->if_hdrlen = sizeof(struct ether_vlan_header);
628
629 /* All ready to run, attach the ethernet interface. */
630 ether_ifattach(ifp, macaddr);
631
632 sc->is_attached = true;
633
634 return (0);
635 }
636
637 static device_method_t vtbe_methods[] = {
638 DEVMETHOD(device_probe, vtbe_probe),
639 DEVMETHOD(device_attach, vtbe_attach),
640 { 0, 0 }
641 };
642
643 static driver_t vtbe_driver = {
644 "vtbe",
645 vtbe_methods,
646 sizeof(struct vtbe_softc),
647 };
648
649 static devclass_t vtbe_devclass;
650
651 DRIVER_MODULE(vtbe, simplebus, vtbe_driver, vtbe_devclass, 0, 0);
652 MODULE_DEPEND(vtbe, ether, 1, 1, 1);
653