if_vtbe.c revision 276354
1275647Sbr/*- 2275647Sbr * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com> 3275647Sbr * All rights reserved. 4275647Sbr * 5275647Sbr * This software was developed by SRI International and the University of 6275647Sbr * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7275647Sbr * ("CTSRD"), as part of the DARPA CRASH research programme. 8275647Sbr * 9275647Sbr * Redistribution and use in source and binary forms, with or without 10275647Sbr * modification, are permitted provided that the following conditions 11275647Sbr * are met: 12275647Sbr * 1. Redistributions of source code must retain the above copyright 13275647Sbr * notice, this list of conditions and the following disclaimer. 14275647Sbr * 2. Redistributions in binary form must reproduce the above copyright 15275647Sbr * notice, this list of conditions and the following disclaimer in the 16275647Sbr * documentation and/or other materials provided with the distribution. 17275647Sbr * 18275647Sbr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19275647Sbr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20275647Sbr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21275647Sbr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22275647Sbr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23275647Sbr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24275647Sbr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25275647Sbr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26275647Sbr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27275647Sbr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28275647Sbr * SUCH DAMAGE. 29275647Sbr */ 30275647Sbr 31275647Sbr/* 32275647Sbr * BERI Virtio Networking Frontend 33275647Sbr */ 34275647Sbr 35275647Sbr#include <sys/cdefs.h> 36275647Sbr__FBSDID("$FreeBSD: head/sys/dev/beri/virtio/network/if_vtbe.c 276354 2014-12-29 00:35:44Z bryanv $"); 37275647Sbr 38275647Sbr#include <sys/param.h> 39275647Sbr#include <sys/systm.h> 40275647Sbr#include <sys/bus.h> 41275647Sbr#include <sys/kernel.h> 42275647Sbr#include <sys/module.h> 43275647Sbr#include <sys/malloc.h> 44275647Sbr#include <sys/rman.h> 45275647Sbr#include <sys/timeet.h> 46275647Sbr#include <sys/timetc.h> 47275647Sbr#include <sys/endian.h> 48275647Sbr#include <sys/lock.h> 49275647Sbr#include <sys/mbuf.h> 50275647Sbr#include <sys/mutex.h> 51275647Sbr#include <sys/socket.h> 52275647Sbr#include <sys/sockio.h> 53275647Sbr#include <sys/sysctl.h> 54275647Sbr#include <sys/mdioctl.h> 55275647Sbr#include <sys/conf.h> 56275647Sbr#include <sys/stat.h> 57275647Sbr#include <sys/uio.h> 58275647Sbr 59275647Sbr#include <dev/fdt/fdt_common.h> 60275647Sbr#include <dev/ofw/openfirm.h> 61275647Sbr#include <dev/ofw/ofw_bus.h> 62275647Sbr#include <dev/ofw/ofw_bus_subr.h> 63275647Sbr 64275647Sbr#include <net/bpf.h> 65275647Sbr#include <net/if.h> 66275647Sbr#include <net/ethernet.h> 67275647Sbr#include <net/if_dl.h> 68275647Sbr#include <net/if_media.h> 69275647Sbr#include <net/if_types.h> 70275647Sbr#include <net/if_var.h> 71275647Sbr#include <net/if_vlan_var.h> 72275647Sbr 73275647Sbr#include <machine/bus.h> 74275647Sbr#include <machine/fdt.h> 75275647Sbr#include <machine/cpu.h> 76275647Sbr#include <machine/intr.h> 77275647Sbr 78275647Sbr#include <dev/beri/virtio/virtio.h> 79275647Sbr#include <dev/beri/virtio/virtio_mmio_platform.h> 80275647Sbr 81275647Sbr#include <dev/altera/pio/pio.h> 82275647Sbr 83275647Sbr#include <dev/virtio/mmio/virtio_mmio.h> 84275647Sbr#include <dev/virtio/network/virtio_net.h> 85276354Sbryanv#include <dev/virtio/virtio_ids.h> 86276354Sbryanv#include <dev/virtio/virtio_config.h> 87275647Sbr#include <dev/virtio/virtio_ring.h> 88275647Sbr 89275647Sbr#include "pio_if.h" 90275647Sbr 91275647Sbr#define DPRINTF(fmt, args...) printf(fmt, ##args) 92275647Sbr 93275647Sbr#define READ4(_sc, _reg) \ 94275647Sbr bus_read_4((_sc)->res[0], _reg) 95275647Sbr#define WRITE4(_sc, _reg, _val) \ 96275647Sbr bus_write_4((_sc)->res[0], _reg, _val) 97275647Sbr 98275647Sbr#define VTBE_LOCK(sc) mtx_lock(&(sc)->mtx) 99275647Sbr#define VTBE_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 100275647Sbr#define VTBE_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED); 101275647Sbr#define VTBE_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED); 102275647Sbr 103275647Sbr/* 104275647Sbr * Driver data and defines. 105275647Sbr */ 106275647Sbr#define DESC_COUNT 256 107275647Sbr 108275647Sbrstruct vtbe_softc { 109275647Sbr struct resource *res[2]; 110275647Sbr bus_space_tag_t bst; 111275647Sbr bus_space_handle_t bsh; 112275647Sbr device_t dev; 113275647Sbr struct ifnet *ifp; 114275647Sbr int if_flags; 115275647Sbr struct mtx mtx; 116275647Sbr boolean_t is_attached; 117275647Sbr 118275647Sbr int beri_mem_offset; 119275647Sbr device_t pio_send; 120275647Sbr device_t pio_recv; 121275647Sbr int opened; 122275647Sbr 123275647Sbr struct vqueue_info vs_queues[2]; 124275647Sbr int vs_curq; 125275647Sbr int hdrsize; 126275647Sbr}; 127275647Sbr 128275647Sbrstatic struct resource_spec vtbe_spec[] = { 129275647Sbr { SYS_RES_MEMORY, 0, RF_ACTIVE }, 130275647Sbr { -1, 0 } 131275647Sbr}; 132275647Sbr 133275647Sbrstatic void vtbe_txfinish_locked(struct vtbe_softc *sc); 134275647Sbrstatic void vtbe_rxfinish_locked(struct vtbe_softc *sc); 135275647Sbrstatic void vtbe_stop_locked(struct vtbe_softc *sc); 136275647Sbrstatic int pio_enable_irq(struct vtbe_softc *sc, int enable); 137275647Sbr 138275647Sbrstatic void 139275647Sbrvtbe_txstart_locked(struct vtbe_softc *sc) 140275647Sbr{ 141275647Sbr struct virtio_net_hdr_mrg_rxbuf *vnh; 142275647Sbr struct iovec iov[DESC_COUNT]; 143275647Sbr struct vqueue_info *vq; 144275647Sbr struct iovec *riov; 145275647Sbr struct ifnet *ifp; 146275647Sbr struct mbuf *m; 147275647Sbr struct uio uio; 148275647Sbr int enqueued; 149275647Sbr int iolen; 150275647Sbr int error; 151275647Sbr int *addr; 152275647Sbr int reg; 153275647Sbr int len; 154275647Sbr int n; 155275647Sbr 156275647Sbr VTBE_ASSERT_LOCKED(sc); 157275647Sbr 158275647Sbr /* RX queue */ 159275647Sbr vq = &sc->vs_queues[0]; 160275647Sbr if (!vq_has_descs(vq)) { 161275647Sbr return; 162275647Sbr } 163275647Sbr 164275647Sbr ifp = sc->ifp; 165275647Sbr if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { 166275647Sbr return; 167275647Sbr } 168275647Sbr 169275647Sbr enqueued = 0; 170275647Sbr 171275647Sbr if (!vq_ring_ready(vq)) 172275647Sbr return; 173275647Sbr 174275647Sbr vq->vq_save_used = be16toh(vq->vq_used->idx); 175275647Sbr 176275647Sbr for (;;) { 177275647Sbr if (!vq_has_descs(vq)) { 178275647Sbr ifp->if_drv_flags |= IFF_DRV_OACTIVE; 179275647Sbr break; 180275647Sbr } 181275647Sbr 182275647Sbr IFQ_DRV_DEQUEUE(&ifp->if_snd, m); 183275647Sbr if (m == NULL) { 184275647Sbr break; 185275647Sbr } 186275647Sbr 187275647Sbr n = vq_getchain(sc->beri_mem_offset, vq, iov, 188275647Sbr DESC_COUNT, NULL); 189275647Sbr 190275647Sbr KASSERT(n >= 1 && n <= DESC_COUNT, 191275647Sbr ("wrong descriptors num %d", n)); 192275647Sbr 193275647Sbr addr = iov[0].iov_base; 194275647Sbr len = iov[0].iov_len; 195275647Sbr 196275647Sbr vnh = iov[0].iov_base; 197275647Sbr memset(vnh, 0, sc->hdrsize); 198275647Sbr vnh->num_buffers = htobe16(1); 199275647Sbr 200275647Sbr iov[0].iov_len -= sc->hdrsize; 201275647Sbr iov[0].iov_base = (void *)((uintptr_t)iov[0].iov_base + 202275647Sbr sc->hdrsize); 203275647Sbr riov = &iov[0]; 204275647Sbr 205275647Sbr uio.uio_resid = iov[0].iov_len; 206275647Sbr uio.uio_iov = riov; 207275647Sbr uio.uio_segflg = UIO_SYSSPACE; 208275647Sbr uio.uio_iovcnt = 1; 209275647Sbr uio.uio_offset = 0; 210275647Sbr uio.uio_rw = UIO_READ; 211275647Sbr 212275647Sbr error = m_mbuftouio(&uio, m, 0); 213275647Sbr if (error) 214275647Sbr panic("m_mbuftouio failed\n"); 215275647Sbr 216275647Sbr iolen = (len - iov[0].iov_len - sc->hdrsize); 217275647Sbr vq_relchain(vq, iov, 0, iolen + sc->hdrsize); 218275647Sbr paddr_unmap((void *)addr, len); 219275647Sbr 220275647Sbr if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 221275647Sbr 222275647Sbr BPF_MTAP(ifp, m); 223275647Sbr m_freem(m); 224275647Sbr 225275647Sbr ++enqueued; 226275647Sbr } 227275647Sbr 228275647Sbr if (enqueued != 0) { 229275647Sbr reg = htobe32(VIRTIO_MMIO_INT_VRING); 230275647Sbr WRITE4(sc, VIRTIO_MMIO_INTERRUPT_STATUS, reg); 231275647Sbr 232275647Sbr PIO_SET(sc->pio_send, Q_INTR, 1); 233275647Sbr } 234275647Sbr} 235275647Sbr 236275647Sbrstatic void 237275647Sbrvtbe_txstart(struct ifnet *ifp) 238275647Sbr{ 239275647Sbr struct vtbe_softc *sc = ifp->if_softc; 240275647Sbr 241275647Sbr VTBE_LOCK(sc); 242275647Sbr vtbe_txstart_locked(sc); 243275647Sbr VTBE_UNLOCK(sc); 244275647Sbr} 245275647Sbr 246275647Sbrstatic void 247275647Sbrvtbe_stop_locked(struct vtbe_softc *sc) 248275647Sbr{ 249275647Sbr struct ifnet *ifp; 250275647Sbr 251275647Sbr VTBE_ASSERT_LOCKED(sc); 252275647Sbr 253275647Sbr ifp = sc->ifp; 254275647Sbr ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE); 255275647Sbr} 256275647Sbr 257275647Sbrstatic void 258275647Sbrvtbe_init_locked(struct vtbe_softc *sc) 259275647Sbr{ 260275647Sbr struct ifnet *ifp = sc->ifp; 261275647Sbr 262275647Sbr VTBE_ASSERT_LOCKED(sc); 263275647Sbr 264275647Sbr if (ifp->if_drv_flags & IFF_DRV_RUNNING) 265275647Sbr return; 266275647Sbr 267275647Sbr ifp->if_drv_flags |= IFF_DRV_RUNNING; 268275647Sbr} 269275647Sbr 270275647Sbrstatic void 271275647Sbrvtbe_init(void *if_softc) 272275647Sbr{ 273275647Sbr struct vtbe_softc *sc = if_softc; 274275647Sbr 275275647Sbr VTBE_LOCK(sc); 276275647Sbr vtbe_init_locked(sc); 277275647Sbr VTBE_UNLOCK(sc); 278275647Sbr} 279275647Sbr 280275647Sbrstatic int 281275647Sbrvtbe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 282275647Sbr{ 283275647Sbr struct ifmediareq *ifmr; 284275647Sbr struct vtbe_softc *sc; 285275647Sbr struct ifreq *ifr; 286275647Sbr int mask, error; 287275647Sbr 288275647Sbr sc = ifp->if_softc; 289275647Sbr ifr = (struct ifreq *)data; 290275647Sbr 291275647Sbr error = 0; 292275647Sbr switch (cmd) { 293275647Sbr case SIOCSIFFLAGS: 294275647Sbr VTBE_LOCK(sc); 295275647Sbr if (ifp->if_flags & IFF_UP) { 296275647Sbr pio_enable_irq(sc, 1); 297275647Sbr 298275647Sbr if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 299275647Sbr vtbe_init_locked(sc); 300275647Sbr } 301275647Sbr } else { 302275647Sbr pio_enable_irq(sc, 0); 303275647Sbr 304275647Sbr if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 305275647Sbr vtbe_stop_locked(sc); 306275647Sbr } 307275647Sbr } 308275647Sbr sc->if_flags = ifp->if_flags; 309275647Sbr VTBE_UNLOCK(sc); 310275647Sbr break; 311275647Sbr case SIOCADDMULTI: 312275647Sbr case SIOCDELMULTI: 313275647Sbr break; 314275647Sbr case SIOCSIFMEDIA: 315275647Sbr case SIOCGIFMEDIA: 316275647Sbr ifmr = (struct ifmediareq *)data; 317275647Sbr ifmr->ifm_count = 1; 318275647Sbr ifmr->ifm_status = (IFM_AVALID | IFM_ACTIVE); 319275647Sbr ifmr->ifm_active = (IFM_ETHER | IFM_10G_T | IFM_FDX); 320275647Sbr ifmr->ifm_current = ifmr->ifm_active; 321275647Sbr break; 322275647Sbr case SIOCSIFCAP: 323275647Sbr mask = ifp->if_capenable ^ ifr->ifr_reqcap; 324275647Sbr if (mask & IFCAP_VLAN_MTU) { 325275647Sbr ifp->if_capenable ^= IFCAP_VLAN_MTU; 326275647Sbr } 327275647Sbr break; 328275647Sbr 329275647Sbr case SIOCSIFADDR: 330275647Sbr pio_enable_irq(sc, 1); 331275647Sbr default: 332275647Sbr error = ether_ioctl(ifp, cmd, data); 333275647Sbr break; 334275647Sbr } 335275647Sbr 336275647Sbr return (error); 337275647Sbr} 338275647Sbr 339275647Sbrstatic void 340275647Sbrvtbe_txfinish_locked(struct vtbe_softc *sc) 341275647Sbr{ 342275647Sbr struct ifnet *ifp; 343275647Sbr 344275647Sbr VTBE_ASSERT_LOCKED(sc); 345275647Sbr 346275647Sbr ifp = sc->ifp; 347275647Sbr} 348275647Sbr 349275647Sbrstatic int 350275647Sbrvq_init(struct vtbe_softc *sc) 351275647Sbr{ 352275647Sbr struct vqueue_info *vq; 353275647Sbr uint8_t *base; 354275647Sbr int size; 355275647Sbr int reg; 356275647Sbr int pfn; 357275647Sbr 358275647Sbr vq = &sc->vs_queues[sc->vs_curq]; 359275647Sbr vq->vq_qsize = DESC_COUNT; 360275647Sbr 361275647Sbr reg = READ4(sc, VIRTIO_MMIO_QUEUE_PFN); 362275647Sbr pfn = be32toh(reg); 363275647Sbr vq->vq_pfn = pfn; 364275647Sbr 365275647Sbr size = vring_size(vq->vq_qsize, VRING_ALIGN); 366275647Sbr base = paddr_map(sc->beri_mem_offset, 367275647Sbr (pfn << PAGE_SHIFT), size); 368275647Sbr 369275647Sbr /* First pages are descriptors */ 370275647Sbr vq->vq_desc = (struct vring_desc *)base; 371275647Sbr base += vq->vq_qsize * sizeof(struct vring_desc); 372275647Sbr 373275647Sbr /* Then avail ring */ 374275647Sbr vq->vq_avail = (struct vring_avail *)base; 375275647Sbr base += (2 + vq->vq_qsize + 1) * sizeof(uint16_t); 376275647Sbr 377275647Sbr /* Then it's rounded up to the next page */ 378275647Sbr base = (uint8_t *)roundup2((uintptr_t)base, VRING_ALIGN); 379275647Sbr 380275647Sbr /* And the last pages are the used ring */ 381275647Sbr vq->vq_used = (struct vring_used *)base; 382275647Sbr 383275647Sbr /* Mark queue as allocated, and start at 0 when we use it. */ 384275647Sbr vq->vq_flags = VQ_ALLOC; 385275647Sbr vq->vq_last_avail = 0; 386275647Sbr 387275647Sbr return (0); 388275647Sbr} 389275647Sbr 390275647Sbrstatic void 391275647Sbrvtbe_proc_rx(struct vtbe_softc *sc, struct vqueue_info *vq) 392275647Sbr{ 393275647Sbr struct iovec iov[DESC_COUNT]; 394275647Sbr struct ifnet *ifp; 395275647Sbr struct uio uio; 396275647Sbr struct mbuf *m; 397275647Sbr int iolen; 398275647Sbr int i; 399275647Sbr int n; 400275647Sbr 401275647Sbr ifp = sc->ifp; 402275647Sbr 403275647Sbr n = vq_getchain(sc->beri_mem_offset, vq, iov, 404275647Sbr DESC_COUNT, NULL); 405275647Sbr 406275647Sbr KASSERT(n >= 1 && n <= DESC_COUNT, 407275647Sbr ("wrong n %d", n)); 408275647Sbr 409275647Sbr iolen = 0; 410275647Sbr for (i = 1; i < n; i++) { 411275647Sbr iolen += iov[i].iov_len; 412275647Sbr } 413275647Sbr 414275647Sbr uio.uio_resid = iolen; 415275647Sbr uio.uio_iov = &iov[1]; 416275647Sbr uio.uio_segflg = UIO_SYSSPACE; 417275647Sbr uio.uio_iovcnt = (n - 1); 418275647Sbr uio.uio_rw = UIO_WRITE; 419275647Sbr 420275647Sbr if ((m = m_uiotombuf(&uio, M_NOWAIT, 0, ETHER_ALIGN, 421275647Sbr M_PKTHDR)) == NULL) { 422275647Sbr if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 423275647Sbr goto done; 424275647Sbr } 425275647Sbr 426275647Sbr m->m_pkthdr.rcvif = ifp; 427275647Sbr 428275647Sbr if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); 429275647Sbr 430275647Sbr CURVNET_SET(ifp->if_vnet); 431275647Sbr VTBE_UNLOCK(sc); 432275647Sbr (*ifp->if_input)(ifp, m); 433275647Sbr VTBE_LOCK(sc); 434275647Sbr CURVNET_RESTORE(); 435275647Sbr 436275647Sbrdone: 437275647Sbr vq_relchain(vq, iov, n, iolen + sc->hdrsize); 438275647Sbr} 439275647Sbr 440275647Sbrstatic void 441275647Sbrvtbe_rxfinish_locked(struct vtbe_softc *sc) 442275647Sbr{ 443275647Sbr struct vqueue_info *vq; 444275647Sbr int reg; 445275647Sbr 446275647Sbr /* TX queue */ 447275647Sbr vq = &sc->vs_queues[1]; 448275647Sbr if (!vq_ring_ready(vq)) 449275647Sbr return; 450275647Sbr 451275647Sbr /* Process new descriptors */ 452275647Sbr vq->vq_save_used = be16toh(vq->vq_used->idx); 453275647Sbr 454275647Sbr while (vq_has_descs(vq)) { 455275647Sbr vtbe_proc_rx(sc, vq); 456275647Sbr } 457275647Sbr 458275647Sbr /* Interrupt the other side */ 459275647Sbr reg = htobe32(VIRTIO_MMIO_INT_VRING); 460275647Sbr WRITE4(sc, VIRTIO_MMIO_INTERRUPT_STATUS, reg); 461275647Sbr 462275647Sbr PIO_SET(sc->pio_send, Q_INTR, 1); 463275647Sbr} 464275647Sbr 465275647Sbrstatic void 466275647Sbrvtbe_intr(void *arg) 467275647Sbr{ 468275647Sbr struct vtbe_softc *sc; 469275647Sbr int pending; 470275647Sbr uint32_t reg; 471275647Sbr 472275647Sbr sc = arg; 473275647Sbr 474275647Sbr VTBE_LOCK(sc); 475275647Sbr 476275647Sbr reg = PIO_READ(sc->pio_recv); 477275647Sbr 478275647Sbr /* Ack */ 479275647Sbr PIO_SET(sc->pio_recv, reg, 0); 480275647Sbr 481275647Sbr pending = htobe32(reg); 482275647Sbr if (pending & Q_SEL) { 483275647Sbr reg = READ4(sc, VIRTIO_MMIO_QUEUE_SEL); 484275647Sbr sc->vs_curq = be32toh(reg); 485275647Sbr } 486275647Sbr 487275647Sbr if (pending & Q_PFN) { 488275647Sbr vq_init(sc); 489275647Sbr } 490275647Sbr 491275647Sbr if (pending & Q_NOTIFY) { 492275647Sbr /* beri rx / arm tx notify */ 493275647Sbr vtbe_txfinish_locked(sc); 494275647Sbr } 495275647Sbr 496275647Sbr if (pending & Q_NOTIFY1) { 497275647Sbr vtbe_rxfinish_locked(sc); 498275647Sbr } 499275647Sbr 500275647Sbr VTBE_UNLOCK(sc); 501275647Sbr} 502275647Sbr 503275647Sbrstatic int 504275647Sbrvtbe_get_hwaddr(struct vtbe_softc *sc, uint8_t *hwaddr) 505275647Sbr{ 506275647Sbr int rnd; 507275647Sbr 508275647Sbr /* 509275647Sbr * Generate MAC address, use 'bsd' + random 24 low-order bits. 510275647Sbr */ 511275647Sbr 512275647Sbr rnd = arc4random() & 0x00ffffff; 513275647Sbr 514275647Sbr hwaddr[0] = 'b'; 515275647Sbr hwaddr[1] = 's'; 516275647Sbr hwaddr[2] = 'd'; 517275647Sbr hwaddr[3] = rnd >> 16; 518275647Sbr hwaddr[4] = rnd >> 8; 519275647Sbr hwaddr[5] = rnd >> 0; 520275647Sbr 521275647Sbr return (0); 522275647Sbr} 523275647Sbr 524275647Sbrstatic int 525275647Sbrpio_enable_irq(struct vtbe_softc *sc, int enable) 526275647Sbr{ 527275647Sbr 528275647Sbr /* 529275647Sbr * IRQ lines should be disabled while reprogram FPGA core. 530275647Sbr */ 531275647Sbr 532275647Sbr if (enable) { 533275647Sbr if (sc->opened == 0) { 534275647Sbr sc->opened = 1; 535275647Sbr PIO_SETUP_IRQ(sc->pio_recv, vtbe_intr, sc); 536275647Sbr } 537275647Sbr } else { 538275647Sbr if (sc->opened == 1) { 539275647Sbr PIO_TEARDOWN_IRQ(sc->pio_recv); 540275647Sbr sc->opened = 0; 541275647Sbr } 542275647Sbr } 543275647Sbr 544275647Sbr return (0); 545275647Sbr} 546275647Sbr 547275647Sbrstatic int 548275647Sbrvtbe_probe(device_t dev) 549275647Sbr{ 550275647Sbr 551275647Sbr if (!ofw_bus_status_okay(dev)) 552275647Sbr return (ENXIO); 553275647Sbr 554275647Sbr if (!ofw_bus_is_compatible(dev, "sri-cambridge,beri-vtnet")) 555275647Sbr return (ENXIO); 556275647Sbr 557275647Sbr device_set_desc(dev, "Virtio BERI Ethernet Controller"); 558275647Sbr return (BUS_PROBE_DEFAULT); 559275647Sbr} 560275647Sbr 561275647Sbrstatic int 562275647Sbrvtbe_attach(device_t dev) 563275647Sbr{ 564275647Sbr uint8_t macaddr[ETHER_ADDR_LEN]; 565275647Sbr struct vtbe_softc *sc; 566275647Sbr struct ifnet *ifp; 567275647Sbr int reg; 568275647Sbr 569275647Sbr sc = device_get_softc(dev); 570275647Sbr sc->dev = dev; 571275647Sbr 572275647Sbr sc->hdrsize = sizeof(struct virtio_net_hdr_mrg_rxbuf); 573275647Sbr 574275647Sbr if (bus_alloc_resources(dev, vtbe_spec, sc->res)) { 575275647Sbr device_printf(dev, "could not allocate resources\n"); 576275647Sbr return (ENXIO); 577275647Sbr } 578275647Sbr 579275647Sbr /* Memory interface */ 580275647Sbr sc->bst = rman_get_bustag(sc->res[0]); 581275647Sbr sc->bsh = rman_get_bushandle(sc->res[0]); 582275647Sbr 583275647Sbr mtx_init(&sc->mtx, device_get_nameunit(sc->dev), 584275647Sbr MTX_NETWORK_LOCK, MTX_DEF); 585275647Sbr 586275647Sbr if (setup_offset(dev, &sc->beri_mem_offset) != 0) 587275647Sbr return (ENXIO); 588275647Sbr if (setup_pio(dev, "pio-send", &sc->pio_send) != 0) 589275647Sbr return (ENXIO); 590275647Sbr if (setup_pio(dev, "pio-recv", &sc->pio_recv) != 0) 591275647Sbr return (ENXIO); 592275647Sbr 593275647Sbr /* Setup MMIO */ 594275647Sbr 595275647Sbr /* Specify that we provide network device */ 596275647Sbr reg = htobe32(VIRTIO_ID_NETWORK); 597275647Sbr WRITE4(sc, VIRTIO_MMIO_DEVICE_ID, reg); 598275647Sbr 599275647Sbr /* The number of desc we support */ 600275647Sbr reg = htobe32(DESC_COUNT); 601275647Sbr WRITE4(sc, VIRTIO_MMIO_QUEUE_NUM_MAX, reg); 602275647Sbr 603275647Sbr /* Our features */ 604275647Sbr reg = htobe32(VIRTIO_NET_F_MAC | 605275647Sbr VIRTIO_NET_F_MRG_RXBUF | 606275647Sbr VIRTIO_F_NOTIFY_ON_EMPTY); 607275647Sbr WRITE4(sc, VIRTIO_MMIO_HOST_FEATURES, reg); 608275647Sbr 609275647Sbr /* Get MAC */ 610275647Sbr if (vtbe_get_hwaddr(sc, macaddr)) { 611275647Sbr device_printf(sc->dev, "can't get mac\n"); 612275647Sbr return (ENXIO); 613275647Sbr } 614275647Sbr 615275647Sbr /* Set up the ethernet interface. */ 616275647Sbr sc->ifp = ifp = if_alloc(IFT_ETHER); 617275647Sbr ifp->if_baudrate = IF_Gbps(10); 618275647Sbr ifp->if_softc = sc; 619275647Sbr if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 620275647Sbr ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | 621275647Sbr IFF_MULTICAST | IFF_PROMISC); 622275647Sbr ifp->if_capabilities = IFCAP_VLAN_MTU; 623275647Sbr ifp->if_capenable = ifp->if_capabilities; 624275647Sbr ifp->if_start = vtbe_txstart; 625275647Sbr ifp->if_ioctl = vtbe_ioctl; 626275647Sbr ifp->if_init = vtbe_init; 627275647Sbr IFQ_SET_MAXLEN(&ifp->if_snd, DESC_COUNT - 1); 628275647Sbr ifp->if_snd.ifq_drv_maxlen = DESC_COUNT - 1; 629275647Sbr IFQ_SET_READY(&ifp->if_snd); 630275647Sbr ifp->if_hdrlen = sizeof(struct ether_vlan_header); 631275647Sbr 632275647Sbr /* All ready to run, attach the ethernet interface. */ 633275647Sbr ether_ifattach(ifp, macaddr); 634275647Sbr 635275647Sbr sc->is_attached = true; 636275647Sbr 637275647Sbr return (0); 638275647Sbr} 639275647Sbr 640275647Sbrstatic device_method_t vtbe_methods[] = { 641275647Sbr DEVMETHOD(device_probe, vtbe_probe), 642275647Sbr DEVMETHOD(device_attach, vtbe_attach), 643275647Sbr 644275647Sbr { 0, 0 } 645275647Sbr}; 646275647Sbr 647275647Sbrstatic driver_t vtbe_driver = { 648275647Sbr "vtbe", 649275647Sbr vtbe_methods, 650275647Sbr sizeof(struct vtbe_softc), 651275647Sbr}; 652275647Sbr 653275647Sbrstatic devclass_t vtbe_devclass; 654275647Sbr 655275647SbrDRIVER_MODULE(vtbe, simplebus, vtbe_driver, vtbe_devclass, 0, 0); 656275647SbrMODULE_DEPEND(vtbe, ether, 1, 1, 1); 657