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