2 * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
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.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
32 * BERI Virtio Networking Frontend
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
38 #include <sys/param.h>
39 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/module.h>
43 #include <sys/malloc.h>
45 #include <sys/timeet.h>
46 #include <sys/timetc.h>
47 #include <sys/endian.h>
50 #include <sys/mutex.h>
51 #include <sys/socket.h>
52 #include <sys/sockio.h>
53 #include <sys/sysctl.h>
54 #include <sys/mdioctl.h>
59 #include <dev/fdt/fdt_common.h>
60 #include <dev/ofw/openfirm.h>
61 #include <dev/ofw/ofw_bus.h>
62 #include <dev/ofw/ofw_bus_subr.h>
66 #include <net/ethernet.h>
67 #include <net/if_dl.h>
68 #include <net/if_media.h>
69 #include <net/if_types.h>
70 #include <net/if_var.h>
71 #include <net/if_vlan_var.h>
73 #include <machine/bus.h>
74 #include <machine/fdt.h>
75 #include <machine/cpu.h>
76 #include <machine/intr.h>
78 #include <dev/beri/virtio/virtio.h>
79 #include <dev/beri/virtio/virtio_mmio_platform.h>
81 #include <dev/altera/pio/pio.h>
83 #include <dev/virtio/mmio/virtio_mmio.h>
84 #include <dev/virtio/network/virtio_net.h>
85 #include <dev/virtio/virtio_ids.h>
86 #include <dev/virtio/virtio_config.h>
87 #include <dev/virtio/virtio_ring.h>
91 #define DPRINTF(fmt, args...) printf(fmt, ##args)
93 #define READ4(_sc, _reg) \
94 bus_read_4((_sc)->res[0], _reg)
95 #define WRITE4(_sc, _reg, _val) \
96 bus_write_4((_sc)->res[0], _reg, _val)
98 #define VTBE_LOCK(sc) mtx_lock(&(sc)->mtx)
99 #define VTBE_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
100 #define VTBE_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED);
101 #define VTBE_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED);
104 * Driver data and defines.
106 #define DESC_COUNT 256
109 struct resource *res[2];
111 bus_space_handle_t bsh;
116 boolean_t is_attached;
123 struct vqueue_info vs_queues[2];
128 static struct resource_spec vtbe_spec[] = {
129 { SYS_RES_MEMORY, 0, RF_ACTIVE },
133 static void vtbe_txfinish_locked(struct vtbe_softc *sc);
134 static void vtbe_rxfinish_locked(struct vtbe_softc *sc);
135 static void vtbe_stop_locked(struct vtbe_softc *sc);
136 static int pio_enable_irq(struct vtbe_softc *sc, int enable);
139 vtbe_txstart_locked(struct vtbe_softc *sc)
141 struct iovec iov[DESC_COUNT];
142 struct virtio_net_hdr *vnh;
143 struct vqueue_info *vq;
155 VTBE_ASSERT_LOCKED(sc);
158 vq = &sc->vs_queues[0];
159 if (!vq_has_descs(vq)) {
164 if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
170 if (!vq_ring_ready(vq))
173 vq->vq_save_used = be16toh(vq->vq_used->idx);
176 if (!vq_has_descs(vq)) {
177 ifp->if_drv_flags |= IFF_DRV_OACTIVE;
181 IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
186 n = vq_getchain(sc->beri_mem_offset, vq, iov,
189 ("Unexpected amount of descriptors (%d)", n));
191 tiov = getcopy(iov, n);
192 vnh = iov[0].iov_base;
193 memset(vnh, 0, sc->hdrsize);
195 len = iov[1].iov_len;
197 uio.uio_iov = &tiov[1];
198 uio.uio_segflg = UIO_SYSSPACE;
201 uio.uio_rw = UIO_READ;
203 error = m_mbuftouio(&uio, m, 0);
205 panic("m_mbuftouio failed\n");
207 iolen = (len - uio.uio_resid + sc->hdrsize);
209 free(tiov, M_DEVBUF);
210 vq_relchain(vq, iov, n, iolen);
212 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
221 reg = htobe32(VIRTIO_MMIO_INT_VRING);
222 WRITE4(sc, VIRTIO_MMIO_INTERRUPT_STATUS, reg);
224 PIO_SET(sc->pio_send, Q_INTR, 1);
229 vtbe_txstart(struct ifnet *ifp)
231 struct vtbe_softc *sc = ifp->if_softc;
234 vtbe_txstart_locked(sc);
239 vtbe_stop_locked(struct vtbe_softc *sc)
243 VTBE_ASSERT_LOCKED(sc);
246 ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
250 vtbe_init_locked(struct vtbe_softc *sc)
252 struct ifnet *ifp = sc->ifp;
254 VTBE_ASSERT_LOCKED(sc);
256 if (ifp->if_drv_flags & IFF_DRV_RUNNING)
259 ifp->if_drv_flags |= IFF_DRV_RUNNING;
263 vtbe_init(void *if_softc)
265 struct vtbe_softc *sc = if_softc;
268 vtbe_init_locked(sc);
273 vtbe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
275 struct ifmediareq *ifmr;
276 struct vtbe_softc *sc;
281 ifr = (struct ifreq *)data;
287 if (ifp->if_flags & IFF_UP) {
288 pio_enable_irq(sc, 1);
290 if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
291 vtbe_init_locked(sc);
294 pio_enable_irq(sc, 0);
296 if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
297 vtbe_stop_locked(sc);
300 sc->if_flags = ifp->if_flags;
308 ifmr = (struct ifmediareq *)data;
310 ifmr->ifm_status = (IFM_AVALID | IFM_ACTIVE);
311 ifmr->ifm_active = (IFM_ETHER | IFM_10G_T | IFM_FDX);
312 ifmr->ifm_current = ifmr->ifm_active;
315 mask = ifp->if_capenable ^ ifr->ifr_reqcap;
316 if (mask & IFCAP_VLAN_MTU) {
317 ifp->if_capenable ^= IFCAP_VLAN_MTU;
322 pio_enable_irq(sc, 1);
324 error = ether_ioctl(ifp, cmd, data);
332 vtbe_txfinish_locked(struct vtbe_softc *sc)
336 VTBE_ASSERT_LOCKED(sc);
342 vq_init(struct vtbe_softc *sc)
344 struct vqueue_info *vq;
350 vq = &sc->vs_queues[sc->vs_curq];
351 vq->vq_qsize = DESC_COUNT;
353 reg = READ4(sc, VIRTIO_MMIO_QUEUE_PFN);
357 size = vring_size(vq->vq_qsize, VRING_ALIGN);
358 base = paddr_map(sc->beri_mem_offset,
359 (pfn << PAGE_SHIFT), size);
361 /* First pages are descriptors */
362 vq->vq_desc = (struct vring_desc *)base;
363 base += vq->vq_qsize * sizeof(struct vring_desc);
365 /* Then avail ring */
366 vq->vq_avail = (struct vring_avail *)base;
367 base += (2 + vq->vq_qsize + 1) * sizeof(uint16_t);
369 /* Then it's rounded up to the next page */
370 base = (uint8_t *)roundup2((uintptr_t)base, VRING_ALIGN);
372 /* And the last pages are the used ring */
373 vq->vq_used = (struct vring_used *)base;
375 /* Mark queue as allocated, and start at 0 when we use it. */
376 vq->vq_flags = VQ_ALLOC;
377 vq->vq_last_avail = 0;
383 vtbe_proc_rx(struct vtbe_softc *sc, struct vqueue_info *vq)
385 struct iovec iov[DESC_COUNT];
396 n = vq_getchain(sc->beri_mem_offset, vq, iov,
399 KASSERT(n >= 1 && n <= DESC_COUNT,
402 tiov = getcopy(iov, n);
405 for (i = 1; i < n; i++) {
406 iolen += iov[i].iov_len;
409 uio.uio_resid = iolen;
410 uio.uio_iov = &tiov[1];
411 uio.uio_segflg = UIO_SYSSPACE;
412 uio.uio_iovcnt = (n - 1);
413 uio.uio_rw = UIO_WRITE;
415 if ((m = m_uiotombuf(&uio, M_NOWAIT, 0, ETHER_ALIGN,
416 M_PKTHDR)) == NULL) {
417 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
421 m->m_pkthdr.rcvif = ifp;
423 if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
425 CURVNET_SET(ifp->if_vnet);
427 (*ifp->if_input)(ifp, m);
432 free(tiov, M_DEVBUF);
433 vq_relchain(vq, iov, n, iolen + sc->hdrsize);
437 vtbe_rxfinish_locked(struct vtbe_softc *sc)
439 struct vqueue_info *vq;
443 vq = &sc->vs_queues[1];
444 if (!vq_ring_ready(vq))
447 /* Process new descriptors */
448 vq->vq_save_used = be16toh(vq->vq_used->idx);
450 while (vq_has_descs(vq)) {
451 vtbe_proc_rx(sc, vq);
454 /* Interrupt the other side */
455 reg = htobe32(VIRTIO_MMIO_INT_VRING);
456 WRITE4(sc, VIRTIO_MMIO_INTERRUPT_STATUS, reg);
458 PIO_SET(sc->pio_send, Q_INTR, 1);
464 struct vtbe_softc *sc;
472 reg = PIO_READ(sc->pio_recv);
475 PIO_SET(sc->pio_recv, reg, 0);
477 pending = htobe32(reg);
478 if (pending & Q_SEL) {
479 reg = READ4(sc, VIRTIO_MMIO_QUEUE_SEL);
480 sc->vs_curq = be32toh(reg);
483 if (pending & Q_PFN) {
487 if (pending & Q_NOTIFY) {
488 /* beri rx / arm tx notify */
489 vtbe_txfinish_locked(sc);
492 if (pending & Q_NOTIFY1) {
493 vtbe_rxfinish_locked(sc);
500 vtbe_get_hwaddr(struct vtbe_softc *sc, uint8_t *hwaddr)
505 * Generate MAC address, use 'bsd' + random 24 low-order bits.
508 rnd = arc4random() & 0x00ffffff;
513 hwaddr[3] = rnd >> 16;
514 hwaddr[4] = rnd >> 8;
515 hwaddr[5] = rnd >> 0;
521 pio_enable_irq(struct vtbe_softc *sc, int enable)
525 * IRQ lines should be disabled while reprogram FPGA core.
529 if (sc->opened == 0) {
531 PIO_SETUP_IRQ(sc->pio_recv, vtbe_intr, sc);
534 if (sc->opened == 1) {
535 PIO_TEARDOWN_IRQ(sc->pio_recv);
544 vtbe_probe(device_t dev)
547 if (!ofw_bus_status_okay(dev))
550 if (!ofw_bus_is_compatible(dev, "sri-cambridge,beri-vtnet"))
553 device_set_desc(dev, "Virtio BERI Ethernet Controller");
554 return (BUS_PROBE_DEFAULT);
558 vtbe_attach(device_t dev)
560 uint8_t macaddr[ETHER_ADDR_LEN];
561 struct vtbe_softc *sc;
565 sc = device_get_softc(dev);
568 sc->hdrsize = sizeof(struct virtio_net_hdr);
570 if (bus_alloc_resources(dev, vtbe_spec, sc->res)) {
571 device_printf(dev, "could not allocate resources\n");
575 /* Memory interface */
576 sc->bst = rman_get_bustag(sc->res[0]);
577 sc->bsh = rman_get_bushandle(sc->res[0]);
579 mtx_init(&sc->mtx, device_get_nameunit(sc->dev),
580 MTX_NETWORK_LOCK, MTX_DEF);
582 if (setup_offset(dev, &sc->beri_mem_offset) != 0)
584 if (setup_pio(dev, "pio-send", &sc->pio_send) != 0)
586 if (setup_pio(dev, "pio-recv", &sc->pio_recv) != 0)
591 /* Specify that we provide network device */
592 reg = htobe32(VIRTIO_ID_NETWORK);
593 WRITE4(sc, VIRTIO_MMIO_DEVICE_ID, reg);
595 /* The number of desc we support */
596 reg = htobe32(DESC_COUNT);
597 WRITE4(sc, VIRTIO_MMIO_QUEUE_NUM_MAX, reg);
600 reg = htobe32(VIRTIO_NET_F_MAC |
601 VIRTIO_F_NOTIFY_ON_EMPTY);
602 WRITE4(sc, VIRTIO_MMIO_HOST_FEATURES, reg);
605 if (vtbe_get_hwaddr(sc, macaddr)) {
606 device_printf(sc->dev, "can't get mac\n");
610 /* Set up the ethernet interface. */
611 sc->ifp = ifp = if_alloc(IFT_ETHER);
612 ifp->if_baudrate = IF_Gbps(10);
614 if_initname(ifp, device_get_name(dev), device_get_unit(dev));
615 ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX |
616 IFF_MULTICAST | IFF_PROMISC);
617 ifp->if_capabilities = IFCAP_VLAN_MTU;
618 ifp->if_capenable = ifp->if_capabilities;
619 ifp->if_start = vtbe_txstart;
620 ifp->if_ioctl = vtbe_ioctl;
621 ifp->if_init = vtbe_init;
622 IFQ_SET_MAXLEN(&ifp->if_snd, DESC_COUNT - 1);
623 ifp->if_snd.ifq_drv_maxlen = DESC_COUNT - 1;
624 IFQ_SET_READY(&ifp->if_snd);
625 ifp->if_hdrlen = sizeof(struct ether_vlan_header);
627 /* All ready to run, attach the ethernet interface. */
628 ether_ifattach(ifp, macaddr);
630 sc->is_attached = true;
635 static device_method_t vtbe_methods[] = {
636 DEVMETHOD(device_probe, vtbe_probe),
637 DEVMETHOD(device_attach, vtbe_attach),
642 static driver_t vtbe_driver = {
645 sizeof(struct vtbe_softc),
648 static devclass_t vtbe_devclass;
650 DRIVER_MODULE(vtbe, simplebus, vtbe_driver, vtbe_devclass, 0, 0);
651 MODULE_DEPEND(vtbe, ether, 1, 1, 1);