1*433d6423SLionel Sambuc /* virtio net driver for MINIX 3 2*433d6423SLionel Sambuc * 3*433d6423SLionel Sambuc * Copyright (c) 2013, A. Welzel, <arne.welzel@gmail.com> 4*433d6423SLionel Sambuc * 5*433d6423SLionel Sambuc * This software is released under the BSD license. See the LICENSE file 6*433d6423SLionel Sambuc * included in the main directory of this source distribution for the 7*433d6423SLionel Sambuc * license terms and conditions. 8*433d6423SLionel Sambuc */ 9*433d6423SLionel Sambuc 10*433d6423SLionel Sambuc #include <assert.h> 11*433d6423SLionel Sambuc #include <sys/types.h> 12*433d6423SLionel Sambuc 13*433d6423SLionel Sambuc #include <net/gen/ether.h> 14*433d6423SLionel Sambuc #include <net/gen/eth_io.h> 15*433d6423SLionel Sambuc 16*433d6423SLionel Sambuc #include <minix/drivers.h> 17*433d6423SLionel Sambuc #include <minix/netdriver.h> 18*433d6423SLionel Sambuc #include <minix/sysutil.h> 19*433d6423SLionel Sambuc #include <minix/virtio.h> 20*433d6423SLionel Sambuc 21*433d6423SLionel Sambuc #include <sys/queue.h> 22*433d6423SLionel Sambuc 23*433d6423SLionel Sambuc #include "virtio_net.h" 24*433d6423SLionel Sambuc 25*433d6423SLionel Sambuc #define dput(s) do { dprintf(s); printf("\n"); } while (0) 26*433d6423SLionel Sambuc #define dprintf(s) do { \ 27*433d6423SLionel Sambuc printf("%s: ", name); \ 28*433d6423SLionel Sambuc printf s; \ 29*433d6423SLionel Sambuc } while (0) 30*433d6423SLionel Sambuc 31*433d6423SLionel Sambuc static struct virtio_device *net_dev; 32*433d6423SLionel Sambuc 33*433d6423SLionel Sambuc static const char *const name = "virtio-net"; 34*433d6423SLionel Sambuc 35*433d6423SLionel Sambuc enum queue {RX_Q, TX_Q, CTRL_Q}; 36*433d6423SLionel Sambuc 37*433d6423SLionel Sambuc /* Number of packets to work with */ 38*433d6423SLionel Sambuc /* TODO: This should be an argument to the driver and possibly also 39*433d6423SLionel Sambuc * depend on the queue sizes offered by this device. 40*433d6423SLionel Sambuc */ 41*433d6423SLionel Sambuc #define BUF_PACKETS 64 42*433d6423SLionel Sambuc /* Maximum size of a packet */ 43*433d6423SLionel Sambuc #define MAX_PACK_SIZE ETH_MAX_PACK_SIZE 44*433d6423SLionel Sambuc /* Buffer size needed for the payload of BUF_PACKETS */ 45*433d6423SLionel Sambuc #define PACKET_BUF_SZ (BUF_PACKETS * MAX_PACK_SIZE) 46*433d6423SLionel Sambuc 47*433d6423SLionel Sambuc struct packet { 48*433d6423SLionel Sambuc int idx; 49*433d6423SLionel Sambuc struct virtio_net_hdr *vhdr; 50*433d6423SLionel Sambuc phys_bytes phdr; 51*433d6423SLionel Sambuc char *vdata; 52*433d6423SLionel Sambuc phys_bytes pdata; 53*433d6423SLionel Sambuc STAILQ_ENTRY(packet) next; 54*433d6423SLionel Sambuc }; 55*433d6423SLionel Sambuc 56*433d6423SLionel Sambuc /* Allocated data chunks */ 57*433d6423SLionel Sambuc static char *data_vir; 58*433d6423SLionel Sambuc static phys_bytes data_phys; 59*433d6423SLionel Sambuc static struct virtio_net_hdr *hdrs_vir; 60*433d6423SLionel Sambuc static phys_bytes hdrs_phys; 61*433d6423SLionel Sambuc static struct packet *packets; 62*433d6423SLionel Sambuc static int in_rx; 63*433d6423SLionel Sambuc static int started; 64*433d6423SLionel Sambuc 65*433d6423SLionel Sambuc /* Packets on this list can be given to the host */ 66*433d6423SLionel Sambuc static STAILQ_HEAD(free_list, packet) free_list; 67*433d6423SLionel Sambuc 68*433d6423SLionel Sambuc /* Packets on this list are to be given to inet */ 69*433d6423SLionel Sambuc static STAILQ_HEAD(recv_list, packet) recv_list; 70*433d6423SLionel Sambuc 71*433d6423SLionel Sambuc /* State about pending inet messages */ 72*433d6423SLionel Sambuc static int rx_pending; 73*433d6423SLionel Sambuc static message pending_rx_msg; 74*433d6423SLionel Sambuc static int tx_pending; 75*433d6423SLionel Sambuc static message pending_tx_msg; 76*433d6423SLionel Sambuc 77*433d6423SLionel Sambuc /* Various state data */ 78*433d6423SLionel Sambuc static u8_t virtio_net_mac[6]; 79*433d6423SLionel Sambuc static eth_stat_t virtio_net_stats; 80*433d6423SLionel Sambuc static int spurious_interrupt; 81*433d6423SLionel Sambuc 82*433d6423SLionel Sambuc 83*433d6423SLionel Sambuc /* Prototypes */ 84*433d6423SLionel Sambuc static int virtio_net_probe(int skip); 85*433d6423SLionel Sambuc static int virtio_net_config(void); 86*433d6423SLionel Sambuc static int virtio_net_alloc_bufs(void); 87*433d6423SLionel Sambuc static void virtio_net_init_queues(void); 88*433d6423SLionel Sambuc 89*433d6423SLionel Sambuc static void virtio_net_refill_rx_queue(void); 90*433d6423SLionel Sambuc static void virtio_net_check_queues(void); 91*433d6423SLionel Sambuc static void virtio_net_check_pending(void); 92*433d6423SLionel Sambuc 93*433d6423SLionel Sambuc static void virtio_net_fetch_iovec(iovec_s_t *iov, message *m, 94*433d6423SLionel Sambuc cp_grant_id_t grant, size_t count); 95*433d6423SLionel Sambuc static int virtio_net_cpy_to_user(message *m); 96*433d6423SLionel Sambuc static int virtio_net_cpy_from_user(message *m); 97*433d6423SLionel Sambuc 98*433d6423SLionel Sambuc static void virtio_net_intr(message *m); 99*433d6423SLionel Sambuc static void virtio_net_write(message *m); 100*433d6423SLionel Sambuc static void virtio_net_read(message *m); 101*433d6423SLionel Sambuc static void virtio_net_conf(message *m); 102*433d6423SLionel Sambuc static void virtio_net_getstat(message *m); 103*433d6423SLionel Sambuc 104*433d6423SLionel Sambuc static void virtio_net_notify(message *m); 105*433d6423SLionel Sambuc static void virtio_net_msg(message *m); 106*433d6423SLionel Sambuc static void virtio_net_main_loop(void); 107*433d6423SLionel Sambuc 108*433d6423SLionel Sambuc static void sef_local_startup(void); 109*433d6423SLionel Sambuc static int sef_cb_init_fresh(int type, sef_init_info_t *info); 110*433d6423SLionel Sambuc static void sef_cb_signal_handler(int signo); 111*433d6423SLionel Sambuc 112*433d6423SLionel Sambuc 113*433d6423SLionel Sambuc /* TODO: Features are pretty much ignored */ 114*433d6423SLionel Sambuc struct virtio_feature netf[] = { 115*433d6423SLionel Sambuc { "partial csum", VIRTIO_NET_F_CSUM, 0, 0 }, 116*433d6423SLionel Sambuc { "given mac", VIRTIO_NET_F_MAC, 0, 1 }, 117*433d6423SLionel Sambuc { "status ", VIRTIO_NET_F_STATUS, 0, 0 }, 118*433d6423SLionel Sambuc { "control channel", VIRTIO_NET_F_CTRL_VQ, 0, 1 }, 119*433d6423SLionel Sambuc { "control channel rx", VIRTIO_NET_F_CTRL_RX, 0, 0 } 120*433d6423SLionel Sambuc }; 121*433d6423SLionel Sambuc 122*433d6423SLionel Sambuc static int 123*433d6423SLionel Sambuc virtio_net_probe(int skip) 124*433d6423SLionel Sambuc { 125*433d6423SLionel Sambuc /* virtio-net has at least 2 queues */ 126*433d6423SLionel Sambuc int queues = 2; 127*433d6423SLionel Sambuc net_dev= virtio_setup_device(0x00001, name, netf, 128*433d6423SLionel Sambuc sizeof(netf) / sizeof(netf[0]), 129*433d6423SLionel Sambuc 1 /* threads */, skip); 130*433d6423SLionel Sambuc if (net_dev == NULL) 131*433d6423SLionel Sambuc return ENXIO; 132*433d6423SLionel Sambuc 133*433d6423SLionel Sambuc /* If the host supports the control queue, allocate it as well */ 134*433d6423SLionel Sambuc if (virtio_host_supports(net_dev, VIRTIO_NET_F_CTRL_VQ)) 135*433d6423SLionel Sambuc queues += 1; 136*433d6423SLionel Sambuc 137*433d6423SLionel Sambuc if (virtio_alloc_queues(net_dev, queues) != OK) { 138*433d6423SLionel Sambuc virtio_free_device(net_dev); 139*433d6423SLionel Sambuc return ENOMEM; 140*433d6423SLionel Sambuc } 141*433d6423SLionel Sambuc 142*433d6423SLionel Sambuc return OK; 143*433d6423SLionel Sambuc } 144*433d6423SLionel Sambuc 145*433d6423SLionel Sambuc static int 146*433d6423SLionel Sambuc virtio_net_config(void) 147*433d6423SLionel Sambuc { 148*433d6423SLionel Sambuc u32_t mac14; 149*433d6423SLionel Sambuc u32_t mac56; 150*433d6423SLionel Sambuc int i; 151*433d6423SLionel Sambuc 152*433d6423SLionel Sambuc if (virtio_host_supports(net_dev, VIRTIO_NET_F_MAC)) { 153*433d6423SLionel Sambuc dprintf(("Mac set by host: ")); 154*433d6423SLionel Sambuc mac14 = virtio_sread32(net_dev, 0); 155*433d6423SLionel Sambuc mac56 = virtio_sread32(net_dev, 4); 156*433d6423SLionel Sambuc *(u32_t*)virtio_net_mac = mac14; 157*433d6423SLionel Sambuc *(u16_t*)(virtio_net_mac + 4) = mac56; 158*433d6423SLionel Sambuc 159*433d6423SLionel Sambuc for (i = 0; i < 6; i++) 160*433d6423SLionel Sambuc printf("%02x%s", virtio_net_mac[i], 161*433d6423SLionel Sambuc i == 5 ? "\n" : ":"); 162*433d6423SLionel Sambuc } else { 163*433d6423SLionel Sambuc dput(("No mac")); 164*433d6423SLionel Sambuc } 165*433d6423SLionel Sambuc 166*433d6423SLionel Sambuc if (virtio_host_supports(net_dev, VIRTIO_NET_F_STATUS)) { 167*433d6423SLionel Sambuc dput(("Current Status %x", (u32_t)virtio_sread16(net_dev, 6))); 168*433d6423SLionel Sambuc } else { 169*433d6423SLionel Sambuc dput(("No status")); 170*433d6423SLionel Sambuc } 171*433d6423SLionel Sambuc 172*433d6423SLionel Sambuc if (virtio_host_supports(net_dev, VIRTIO_NET_F_CTRL_VQ)) 173*433d6423SLionel Sambuc dput(("Host supports control channel")); 174*433d6423SLionel Sambuc 175*433d6423SLionel Sambuc if (virtio_host_supports(net_dev, VIRTIO_NET_F_CTRL_RX)) 176*433d6423SLionel Sambuc dput(("Host supports control channel for RX")); 177*433d6423SLionel Sambuc 178*433d6423SLionel Sambuc return OK; 179*433d6423SLionel Sambuc } 180*433d6423SLionel Sambuc 181*433d6423SLionel Sambuc static int 182*433d6423SLionel Sambuc virtio_net_alloc_bufs(void) 183*433d6423SLionel Sambuc { 184*433d6423SLionel Sambuc data_vir = alloc_contig(PACKET_BUF_SZ, 0, &data_phys); 185*433d6423SLionel Sambuc 186*433d6423SLionel Sambuc if (!data_vir) 187*433d6423SLionel Sambuc return ENOMEM; 188*433d6423SLionel Sambuc 189*433d6423SLionel Sambuc hdrs_vir = alloc_contig(BUF_PACKETS * sizeof(hdrs_vir[0]), 190*433d6423SLionel Sambuc 0, &hdrs_phys); 191*433d6423SLionel Sambuc 192*433d6423SLionel Sambuc if (!hdrs_vir) { 193*433d6423SLionel Sambuc free_contig(data_vir, PACKET_BUF_SZ); 194*433d6423SLionel Sambuc return ENOMEM; 195*433d6423SLionel Sambuc } 196*433d6423SLionel Sambuc 197*433d6423SLionel Sambuc packets = malloc(BUF_PACKETS * sizeof(packets[0])); 198*433d6423SLionel Sambuc 199*433d6423SLionel Sambuc if (!packets) { 200*433d6423SLionel Sambuc free_contig(data_vir, PACKET_BUF_SZ); 201*433d6423SLionel Sambuc free_contig(hdrs_vir, BUF_PACKETS * sizeof(hdrs_vir[0])); 202*433d6423SLionel Sambuc return ENOMEM; 203*433d6423SLionel Sambuc } 204*433d6423SLionel Sambuc 205*433d6423SLionel Sambuc memset(data_vir, 0, PACKET_BUF_SZ); 206*433d6423SLionel Sambuc memset(hdrs_vir, 0, BUF_PACKETS * sizeof(hdrs_vir[0])); 207*433d6423SLionel Sambuc memset(packets, 0, BUF_PACKETS * sizeof(packets[0])); 208*433d6423SLionel Sambuc 209*433d6423SLionel Sambuc return OK; 210*433d6423SLionel Sambuc } 211*433d6423SLionel Sambuc 212*433d6423SLionel Sambuc static void 213*433d6423SLionel Sambuc virtio_net_init_queues(void) 214*433d6423SLionel Sambuc { 215*433d6423SLionel Sambuc int i; 216*433d6423SLionel Sambuc STAILQ_INIT(&free_list); 217*433d6423SLionel Sambuc STAILQ_INIT(&recv_list); 218*433d6423SLionel Sambuc 219*433d6423SLionel Sambuc for (i = 0; i < BUF_PACKETS; i++) { 220*433d6423SLionel Sambuc packets[i].idx = i; 221*433d6423SLionel Sambuc packets[i].vhdr = &hdrs_vir[i]; 222*433d6423SLionel Sambuc packets[i].phdr = hdrs_phys + i * sizeof(hdrs_vir[i]); 223*433d6423SLionel Sambuc packets[i].vdata = data_vir + i * MAX_PACK_SIZE; 224*433d6423SLionel Sambuc packets[i].pdata = data_phys + i * MAX_PACK_SIZE; 225*433d6423SLionel Sambuc STAILQ_INSERT_HEAD(&free_list, &packets[i], next); 226*433d6423SLionel Sambuc } 227*433d6423SLionel Sambuc } 228*433d6423SLionel Sambuc 229*433d6423SLionel Sambuc static void 230*433d6423SLionel Sambuc virtio_net_refill_rx_queue(void) 231*433d6423SLionel Sambuc { 232*433d6423SLionel Sambuc struct vumap_phys phys[2]; 233*433d6423SLionel Sambuc struct packet *p; 234*433d6423SLionel Sambuc 235*433d6423SLionel Sambuc while ((in_rx < BUF_PACKETS / 2) && !STAILQ_EMPTY(&free_list)) { 236*433d6423SLionel Sambuc 237*433d6423SLionel Sambuc /* peek */ 238*433d6423SLionel Sambuc p = STAILQ_FIRST(&free_list); 239*433d6423SLionel Sambuc /* remove */ 240*433d6423SLionel Sambuc STAILQ_REMOVE_HEAD(&free_list, next); 241*433d6423SLionel Sambuc 242*433d6423SLionel Sambuc phys[0].vp_addr = p->phdr; 243*433d6423SLionel Sambuc assert(!(phys[0].vp_addr & 1)); 244*433d6423SLionel Sambuc phys[0].vp_size = sizeof(struct virtio_net_hdr); 245*433d6423SLionel Sambuc 246*433d6423SLionel Sambuc phys[1].vp_addr = p->pdata; 247*433d6423SLionel Sambuc assert(!(phys[1].vp_addr & 1)); 248*433d6423SLionel Sambuc phys[1].vp_size = MAX_PACK_SIZE; 249*433d6423SLionel Sambuc 250*433d6423SLionel Sambuc /* RX queue needs write */ 251*433d6423SLionel Sambuc phys[0].vp_addr |= 1; 252*433d6423SLionel Sambuc phys[1].vp_addr |= 1; 253*433d6423SLionel Sambuc 254*433d6423SLionel Sambuc virtio_to_queue(net_dev, RX_Q, phys, 2, p); 255*433d6423SLionel Sambuc in_rx++; 256*433d6423SLionel Sambuc 257*433d6423SLionel Sambuc } 258*433d6423SLionel Sambuc 259*433d6423SLionel Sambuc if (in_rx == 0 && STAILQ_EMPTY(&free_list)) { 260*433d6423SLionel Sambuc dput(("warning: rx queue underflow!")); 261*433d6423SLionel Sambuc virtio_net_stats.ets_fifoUnder++; 262*433d6423SLionel Sambuc } 263*433d6423SLionel Sambuc } 264*433d6423SLionel Sambuc 265*433d6423SLionel Sambuc static void 266*433d6423SLionel Sambuc virtio_net_check_queues(void) 267*433d6423SLionel Sambuc { 268*433d6423SLionel Sambuc struct packet *p; 269*433d6423SLionel Sambuc 270*433d6423SLionel Sambuc /* Put the received packets into the recv list */ 271*433d6423SLionel Sambuc while (virtio_from_queue(net_dev, RX_Q, (void **)&p) == 0) { 272*433d6423SLionel Sambuc STAILQ_INSERT_TAIL(&recv_list, p, next); 273*433d6423SLionel Sambuc in_rx--; 274*433d6423SLionel Sambuc virtio_net_stats.ets_packetR++; 275*433d6423SLionel Sambuc } 276*433d6423SLionel Sambuc 277*433d6423SLionel Sambuc /* Packets from the TX queue just indicated they are free to 278*433d6423SLionel Sambuc * be reused now. inet already knows about them as being sent. 279*433d6423SLionel Sambuc */ 280*433d6423SLionel Sambuc while (virtio_from_queue(net_dev, TX_Q, (void **)&p) == 0) { 281*433d6423SLionel Sambuc memset(p->vhdr, 0, sizeof(*p->vhdr)); 282*433d6423SLionel Sambuc memset(p->vdata, 0, MAX_PACK_SIZE); 283*433d6423SLionel Sambuc STAILQ_INSERT_HEAD(&free_list, p, next); 284*433d6423SLionel Sambuc virtio_net_stats.ets_packetT++; 285*433d6423SLionel Sambuc } 286*433d6423SLionel Sambuc } 287*433d6423SLionel Sambuc 288*433d6423SLionel Sambuc static void 289*433d6423SLionel Sambuc virtio_net_check_pending(void) 290*433d6423SLionel Sambuc { 291*433d6423SLionel Sambuc int dst = 0xDEAD; 292*433d6423SLionel Sambuc int r; 293*433d6423SLionel Sambuc 294*433d6423SLionel Sambuc message reply; 295*433d6423SLionel Sambuc reply.m_type = DL_TASK_REPLY; 296*433d6423SLionel Sambuc reply.m_netdrv_net_dl_task.flags = DL_NOFLAGS; 297*433d6423SLionel Sambuc reply.m_netdrv_net_dl_task.count = 0; 298*433d6423SLionel Sambuc 299*433d6423SLionel Sambuc /* Pending read and something in recv_list? */ 300*433d6423SLionel Sambuc if (!STAILQ_EMPTY(&recv_list) && rx_pending) { 301*433d6423SLionel Sambuc dst = pending_rx_msg.m_source; 302*433d6423SLionel Sambuc reply.m_netdrv_net_dl_task.count = 303*433d6423SLionel Sambuc virtio_net_cpy_to_user(&pending_rx_msg); 304*433d6423SLionel Sambuc reply.m_netdrv_net_dl_task.flags |= DL_PACK_RECV; 305*433d6423SLionel Sambuc rx_pending = 0; 306*433d6423SLionel Sambuc } 307*433d6423SLionel Sambuc 308*433d6423SLionel Sambuc if (!STAILQ_EMPTY(&free_list) && tx_pending) { 309*433d6423SLionel Sambuc dst = pending_tx_msg.m_source; 310*433d6423SLionel Sambuc virtio_net_cpy_from_user(&pending_tx_msg); 311*433d6423SLionel Sambuc reply.m_netdrv_net_dl_task.flags |= DL_PACK_SEND; 312*433d6423SLionel Sambuc tx_pending = 0; 313*433d6423SLionel Sambuc } 314*433d6423SLionel Sambuc 315*433d6423SLionel Sambuc /* Only reply if a pending request was handled */ 316*433d6423SLionel Sambuc if (reply.m_netdrv_net_dl_task.flags != DL_NOFLAGS) 317*433d6423SLionel Sambuc if ((r = ipc_send(dst, &reply)) != OK) 318*433d6423SLionel Sambuc panic("%s: ipc_send to %d failed (%d)", name, dst, r); 319*433d6423SLionel Sambuc } 320*433d6423SLionel Sambuc 321*433d6423SLionel Sambuc static void 322*433d6423SLionel Sambuc virtio_net_fetch_iovec(iovec_s_t *iov, message *m, cp_grant_id_t grant, size_t count) 323*433d6423SLionel Sambuc { 324*433d6423SLionel Sambuc int r; 325*433d6423SLionel Sambuc r = sys_safecopyfrom(m->m_source, grant, 0, (vir_bytes)iov, 326*433d6423SLionel Sambuc count * sizeof(iov[0])); 327*433d6423SLionel Sambuc 328*433d6423SLionel Sambuc if (r != OK) 329*433d6423SLionel Sambuc panic("%s: iovec fail for %d (%d)", name, m->m_source, r); 330*433d6423SLionel Sambuc } 331*433d6423SLionel Sambuc 332*433d6423SLionel Sambuc static int 333*433d6423SLionel Sambuc virtio_net_cpy_to_user(message *m) 334*433d6423SLionel Sambuc { 335*433d6423SLionel Sambuc /* Hmm, this looks so similar to cpy_from_user... TODO */ 336*433d6423SLionel Sambuc int i, r, size, ivsz; 337*433d6423SLionel Sambuc int left = MAX_PACK_SIZE; /* Try copying the whole packet */ 338*433d6423SLionel Sambuc int bytes = 0; 339*433d6423SLionel Sambuc iovec_s_t iovec[NR_IOREQS]; 340*433d6423SLionel Sambuc struct packet *p; 341*433d6423SLionel Sambuc 342*433d6423SLionel Sambuc /* This should only be called if recv_list has some entries */ 343*433d6423SLionel Sambuc assert(!STAILQ_EMPTY(&recv_list)); 344*433d6423SLionel Sambuc 345*433d6423SLionel Sambuc p = STAILQ_FIRST(&recv_list); 346*433d6423SLionel Sambuc STAILQ_REMOVE_HEAD(&recv_list, next); 347*433d6423SLionel Sambuc 348*433d6423SLionel Sambuc virtio_net_fetch_iovec(iovec, m, m->m_net_netdrv_dl_readv_s.grant, 349*433d6423SLionel Sambuc m->m_net_netdrv_dl_readv_s.count); 350*433d6423SLionel Sambuc 351*433d6423SLionel Sambuc for (i = 0; i < m->m_net_netdrv_dl_readv_s.count && left > 0; i++) { 352*433d6423SLionel Sambuc ivsz = iovec[i].iov_size; 353*433d6423SLionel Sambuc size = left > ivsz ? ivsz : left; 354*433d6423SLionel Sambuc r = sys_safecopyto(m->m_source, iovec[i].iov_grant, 0, 355*433d6423SLionel Sambuc (vir_bytes) p->vdata + bytes, size); 356*433d6423SLionel Sambuc 357*433d6423SLionel Sambuc if (r != OK) 358*433d6423SLionel Sambuc panic("%s: copy to %d failed (%d)", name, 359*433d6423SLionel Sambuc m->m_source, 360*433d6423SLionel Sambuc r); 361*433d6423SLionel Sambuc 362*433d6423SLionel Sambuc left -= size; 363*433d6423SLionel Sambuc bytes += size; 364*433d6423SLionel Sambuc } 365*433d6423SLionel Sambuc 366*433d6423SLionel Sambuc if (left != 0) 367*433d6423SLionel Sambuc dput(("Uhm... left=%d", left)); 368*433d6423SLionel Sambuc 369*433d6423SLionel Sambuc /* Clean the packet */ 370*433d6423SLionel Sambuc memset(p->vhdr, 0, sizeof(*p->vhdr)); 371*433d6423SLionel Sambuc memset(p->vdata, 0, MAX_PACK_SIZE); 372*433d6423SLionel Sambuc STAILQ_INSERT_HEAD(&free_list, p, next); 373*433d6423SLionel Sambuc 374*433d6423SLionel Sambuc return bytes; 375*433d6423SLionel Sambuc } 376*433d6423SLionel Sambuc 377*433d6423SLionel Sambuc static int 378*433d6423SLionel Sambuc sys_easy_vsafecopy_from(endpoint_t src_proc, iovec_s_t *iov, int count, 379*433d6423SLionel Sambuc vir_bytes dst, size_t max, size_t *copied) 380*433d6423SLionel Sambuc { 381*433d6423SLionel Sambuc int i, r; 382*433d6423SLionel Sambuc size_t left = max; 383*433d6423SLionel Sambuc vir_bytes cur_off = 0; 384*433d6423SLionel Sambuc struct vscp_vec vv[NR_IOREQS]; 385*433d6423SLionel Sambuc 386*433d6423SLionel Sambuc for (i = 0; i < count && left > 0; i++) { 387*433d6423SLionel Sambuc vv[i].v_from = src_proc; 388*433d6423SLionel Sambuc vv[i].v_to = SELF; 389*433d6423SLionel Sambuc vv[i].v_gid = iov[i].iov_grant; 390*433d6423SLionel Sambuc vv[i].v_offset = 0; 391*433d6423SLionel Sambuc vv[i].v_addr = dst + cur_off; 392*433d6423SLionel Sambuc vv[i].v_bytes = iov[i].iov_size; 393*433d6423SLionel Sambuc 394*433d6423SLionel Sambuc /* More data in iov than the buffer can hold, this should be 395*433d6423SLionel Sambuc * manageable by the caller. 396*433d6423SLionel Sambuc */ 397*433d6423SLionel Sambuc if (left - vv[i].v_bytes > left) { 398*433d6423SLionel Sambuc printf("sys_easy_vsafecopy_from: buf too small!\n"); 399*433d6423SLionel Sambuc return ENOMEM; 400*433d6423SLionel Sambuc } 401*433d6423SLionel Sambuc 402*433d6423SLionel Sambuc left -= iov[i].iov_size; 403*433d6423SLionel Sambuc cur_off += iov[i].iov_size; 404*433d6423SLionel Sambuc } 405*433d6423SLionel Sambuc 406*433d6423SLionel Sambuc /* Now that we prepared the vscp_vec, we can call vsafecopy() */ 407*433d6423SLionel Sambuc if ((r = sys_vsafecopy(vv, count)) != OK) 408*433d6423SLionel Sambuc printf("sys_vsafecopy: failed: (%d)\n", r); 409*433d6423SLionel Sambuc 410*433d6423SLionel Sambuc if (copied) 411*433d6423SLionel Sambuc *copied = cur_off; 412*433d6423SLionel Sambuc 413*433d6423SLionel Sambuc return OK; 414*433d6423SLionel Sambuc } 415*433d6423SLionel Sambuc 416*433d6423SLionel Sambuc static int 417*433d6423SLionel Sambuc virtio_net_cpy_from_user(message *m) 418*433d6423SLionel Sambuc { 419*433d6423SLionel Sambuc /* Put user bytes into a a free packet buffer and 420*433d6423SLionel Sambuc * then forward this packet to the TX queue. 421*433d6423SLionel Sambuc */ 422*433d6423SLionel Sambuc int r; 423*433d6423SLionel Sambuc iovec_s_t iovec[NR_IOREQS]; 424*433d6423SLionel Sambuc struct vumap_phys phys[2]; 425*433d6423SLionel Sambuc struct packet *p; 426*433d6423SLionel Sambuc size_t bytes; 427*433d6423SLionel Sambuc 428*433d6423SLionel Sambuc /* This should only be called if free_list has some entries */ 429*433d6423SLionel Sambuc assert(!STAILQ_EMPTY(&free_list)); 430*433d6423SLionel Sambuc 431*433d6423SLionel Sambuc p = STAILQ_FIRST(&free_list); 432*433d6423SLionel Sambuc STAILQ_REMOVE_HEAD(&free_list, next); 433*433d6423SLionel Sambuc 434*433d6423SLionel Sambuc virtio_net_fetch_iovec(iovec, m, m->m_net_netdrv_dl_writev_s.grant, 435*433d6423SLionel Sambuc m->m_net_netdrv_dl_writev_s.count); 436*433d6423SLionel Sambuc 437*433d6423SLionel Sambuc r = sys_easy_vsafecopy_from(m->m_source, iovec, 438*433d6423SLionel Sambuc m->m_net_netdrv_dl_writev_s.count, (vir_bytes)p->vdata, 439*433d6423SLionel Sambuc MAX_PACK_SIZE, &bytes); 440*433d6423SLionel Sambuc 441*433d6423SLionel Sambuc if (r != OK) 442*433d6423SLionel Sambuc panic("%s: copy from %d failed", name, m->m_source); 443*433d6423SLionel Sambuc 444*433d6423SLionel Sambuc 445*433d6423SLionel Sambuc phys[0].vp_addr = p->phdr; 446*433d6423SLionel Sambuc assert(!(phys[0].vp_addr & 1)); 447*433d6423SLionel Sambuc phys[0].vp_size = sizeof(struct virtio_net_hdr); 448*433d6423SLionel Sambuc phys[1].vp_addr = p->pdata; 449*433d6423SLionel Sambuc assert(!(phys[1].vp_addr & 1)); 450*433d6423SLionel Sambuc phys[1].vp_size = bytes; 451*433d6423SLionel Sambuc virtio_to_queue(net_dev, TX_Q, phys, 2, p); 452*433d6423SLionel Sambuc return bytes; 453*433d6423SLionel Sambuc } 454*433d6423SLionel Sambuc 455*433d6423SLionel Sambuc static void 456*433d6423SLionel Sambuc virtio_net_intr(message *m) 457*433d6423SLionel Sambuc { 458*433d6423SLionel Sambuc /* Check and clear interrupt flag */ 459*433d6423SLionel Sambuc if (virtio_had_irq(net_dev)) { 460*433d6423SLionel Sambuc virtio_net_check_queues(); 461*433d6423SLionel Sambuc } else { 462*433d6423SLionel Sambuc if (!spurious_interrupt) 463*433d6423SLionel Sambuc dput(("Spurious interrupt")); 464*433d6423SLionel Sambuc 465*433d6423SLionel Sambuc spurious_interrupt = 1; 466*433d6423SLionel Sambuc } 467*433d6423SLionel Sambuc 468*433d6423SLionel Sambuc virtio_net_check_pending(); 469*433d6423SLionel Sambuc 470*433d6423SLionel Sambuc virtio_irq_enable(net_dev); 471*433d6423SLionel Sambuc } 472*433d6423SLionel Sambuc 473*433d6423SLionel Sambuc static void 474*433d6423SLionel Sambuc virtio_net_write(message *m) 475*433d6423SLionel Sambuc { 476*433d6423SLionel Sambuc int r; 477*433d6423SLionel Sambuc message reply; 478*433d6423SLionel Sambuc 479*433d6423SLionel Sambuc reply.m_type = DL_TASK_REPLY; 480*433d6423SLionel Sambuc reply.m_netdrv_net_dl_task.flags = DL_NOFLAGS; 481*433d6423SLionel Sambuc reply.m_netdrv_net_dl_task.count = 0; 482*433d6423SLionel Sambuc 483*433d6423SLionel Sambuc 484*433d6423SLionel Sambuc if (!STAILQ_EMPTY(&free_list)) { 485*433d6423SLionel Sambuc /* free_list contains at least one packet, use it */ 486*433d6423SLionel Sambuc reply.m_netdrv_net_dl_task.count = virtio_net_cpy_from_user(m); 487*433d6423SLionel Sambuc reply.m_netdrv_net_dl_task.flags = DL_PACK_SEND; 488*433d6423SLionel Sambuc } else { 489*433d6423SLionel Sambuc pending_tx_msg = *m; 490*433d6423SLionel Sambuc tx_pending = 1; 491*433d6423SLionel Sambuc } 492*433d6423SLionel Sambuc 493*433d6423SLionel Sambuc if ((r = ipc_send(m->m_source, &reply)) != OK) 494*433d6423SLionel Sambuc panic("%s: ipc_send to %d failed (%d)", name, m->m_source, r); 495*433d6423SLionel Sambuc } 496*433d6423SLionel Sambuc 497*433d6423SLionel Sambuc static void 498*433d6423SLionel Sambuc virtio_net_read(message *m) 499*433d6423SLionel Sambuc { 500*433d6423SLionel Sambuc int r; 501*433d6423SLionel Sambuc message reply; 502*433d6423SLionel Sambuc 503*433d6423SLionel Sambuc reply.m_type = DL_TASK_REPLY; 504*433d6423SLionel Sambuc reply.m_netdrv_net_dl_task.flags = DL_NOFLAGS; 505*433d6423SLionel Sambuc reply.m_netdrv_net_dl_task.count = 0; 506*433d6423SLionel Sambuc 507*433d6423SLionel Sambuc if (!STAILQ_EMPTY(&recv_list)) { 508*433d6423SLionel Sambuc /* recv_list contains at least one packet, copy it */ 509*433d6423SLionel Sambuc reply.m_netdrv_net_dl_task.count = virtio_net_cpy_to_user(m); 510*433d6423SLionel Sambuc reply.m_netdrv_net_dl_task.flags = DL_PACK_RECV; 511*433d6423SLionel Sambuc } else { 512*433d6423SLionel Sambuc rx_pending = 1; 513*433d6423SLionel Sambuc pending_rx_msg = *m; 514*433d6423SLionel Sambuc } 515*433d6423SLionel Sambuc 516*433d6423SLionel Sambuc if ((r = ipc_send(m->m_source, &reply)) != OK) 517*433d6423SLionel Sambuc panic("%s: ipc_send to %d failed (%d)", name, m->m_source, r); 518*433d6423SLionel Sambuc } 519*433d6423SLionel Sambuc 520*433d6423SLionel Sambuc static void 521*433d6423SLionel Sambuc virtio_net_conf(message *m) 522*433d6423SLionel Sambuc { 523*433d6423SLionel Sambuc /* TODO: Add the multicast, broadcast filtering etc. */ 524*433d6423SLionel Sambuc int i, r; 525*433d6423SLionel Sambuc 526*433d6423SLionel Sambuc message reply; 527*433d6423SLionel Sambuc 528*433d6423SLionel Sambuc /* If this is the first CONF message we see, fully initialize 529*433d6423SLionel Sambuc * the device now. 530*433d6423SLionel Sambuc */ 531*433d6423SLionel Sambuc if (!started) { 532*433d6423SLionel Sambuc started = 1; 533*433d6423SLionel Sambuc virtio_device_ready(net_dev); 534*433d6423SLionel Sambuc virtio_irq_enable(net_dev); 535*433d6423SLionel Sambuc } 536*433d6423SLionel Sambuc 537*433d6423SLionel Sambuc /* Prepare reply */ 538*433d6423SLionel Sambuc memcpy(reply.m_netdrv_net_dl_conf.hw_addr, virtio_net_mac, 539*433d6423SLionel Sambuc sizeof(reply.m_netdrv_net_dl_conf.hw_addr)); 540*433d6423SLionel Sambuc 541*433d6423SLionel Sambuc reply.m_type = DL_CONF_REPLY; 542*433d6423SLionel Sambuc reply.m_netdrv_net_dl_conf.stat = OK; 543*433d6423SLionel Sambuc 544*433d6423SLionel Sambuc if ((r = ipc_send(m->m_source, &reply)) != OK) 545*433d6423SLionel Sambuc panic("%s: ipc_send to %d failed (%d)", name, m->m_source, r); 546*433d6423SLionel Sambuc } 547*433d6423SLionel Sambuc 548*433d6423SLionel Sambuc static void 549*433d6423SLionel Sambuc virtio_net_getstat(message *m) 550*433d6423SLionel Sambuc { 551*433d6423SLionel Sambuc int r; 552*433d6423SLionel Sambuc message reply; 553*433d6423SLionel Sambuc 554*433d6423SLionel Sambuc reply.m_type = DL_STAT_REPLY; 555*433d6423SLionel Sambuc 556*433d6423SLionel Sambuc r = sys_safecopyto(m->m_source, m->m_net_netdrv_dl_getstat_s.grant, 0, 557*433d6423SLionel Sambuc (vir_bytes)&virtio_net_stats, 558*433d6423SLionel Sambuc sizeof(virtio_net_stats)); 559*433d6423SLionel Sambuc 560*433d6423SLionel Sambuc if (r != OK) 561*433d6423SLionel Sambuc panic("%s: copy to %d failed (%d)", name, m->m_source, r); 562*433d6423SLionel Sambuc 563*433d6423SLionel Sambuc if ((r = ipc_send(m->m_source, &reply)) != OK) 564*433d6423SLionel Sambuc panic("%s: ipc_send to %d failed (%d)", name, m->m_source, r); 565*433d6423SLionel Sambuc } 566*433d6423SLionel Sambuc 567*433d6423SLionel Sambuc static void 568*433d6423SLionel Sambuc virtio_net_notify(message *m) 569*433d6423SLionel Sambuc { 570*433d6423SLionel Sambuc if (_ENDPOINT_P(m->m_source) == HARDWARE) 571*433d6423SLionel Sambuc virtio_net_intr(m); 572*433d6423SLionel Sambuc } 573*433d6423SLionel Sambuc 574*433d6423SLionel Sambuc static void 575*433d6423SLionel Sambuc virtio_net_msg(message *m) 576*433d6423SLionel Sambuc { 577*433d6423SLionel Sambuc switch (m->m_type) { 578*433d6423SLionel Sambuc case DL_WRITEV_S: 579*433d6423SLionel Sambuc virtio_net_write(m); 580*433d6423SLionel Sambuc break; 581*433d6423SLionel Sambuc case DL_READV_S: 582*433d6423SLionel Sambuc virtio_net_read(m); 583*433d6423SLionel Sambuc break; 584*433d6423SLionel Sambuc case DL_CONF: 585*433d6423SLionel Sambuc virtio_net_conf(m); 586*433d6423SLionel Sambuc break; 587*433d6423SLionel Sambuc case DL_GETSTAT_S: 588*433d6423SLionel Sambuc virtio_net_getstat(m); 589*433d6423SLionel Sambuc break; 590*433d6423SLionel Sambuc default: 591*433d6423SLionel Sambuc panic("%s: illegal message: %d", name, m->m_type); 592*433d6423SLionel Sambuc } 593*433d6423SLionel Sambuc } 594*433d6423SLionel Sambuc 595*433d6423SLionel Sambuc static void 596*433d6423SLionel Sambuc virtio_net_main_loop(void) 597*433d6423SLionel Sambuc { 598*433d6423SLionel Sambuc message m; 599*433d6423SLionel Sambuc int ipc_status; 600*433d6423SLionel Sambuc int r; 601*433d6423SLionel Sambuc 602*433d6423SLionel Sambuc while (TRUE) { 603*433d6423SLionel Sambuc 604*433d6423SLionel Sambuc virtio_net_refill_rx_queue(); 605*433d6423SLionel Sambuc 606*433d6423SLionel Sambuc if ((r = netdriver_receive(ANY, &m, &ipc_status)) != OK) 607*433d6423SLionel Sambuc panic("%s: netdriver_receive failed: %d", name, r); 608*433d6423SLionel Sambuc 609*433d6423SLionel Sambuc if (is_ipc_notify(ipc_status)) 610*433d6423SLionel Sambuc virtio_net_notify(&m); 611*433d6423SLionel Sambuc else 612*433d6423SLionel Sambuc virtio_net_msg(&m); 613*433d6423SLionel Sambuc } 614*433d6423SLionel Sambuc } 615*433d6423SLionel Sambuc 616*433d6423SLionel Sambuc int 617*433d6423SLionel Sambuc main(int argc, char *argv[]) 618*433d6423SLionel Sambuc { 619*433d6423SLionel Sambuc env_setargs(argc, argv); 620*433d6423SLionel Sambuc sef_local_startup(); 621*433d6423SLionel Sambuc 622*433d6423SLionel Sambuc virtio_net_main_loop(); 623*433d6423SLionel Sambuc } 624*433d6423SLionel Sambuc 625*433d6423SLionel Sambuc static void 626*433d6423SLionel Sambuc sef_local_startup() 627*433d6423SLionel Sambuc { 628*433d6423SLionel Sambuc sef_setcb_init_fresh(sef_cb_init_fresh); 629*433d6423SLionel Sambuc sef_setcb_init_lu(sef_cb_init_fresh); 630*433d6423SLionel Sambuc sef_setcb_init_restart(sef_cb_init_fresh); 631*433d6423SLionel Sambuc 632*433d6423SLionel Sambuc sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); 633*433d6423SLionel Sambuc sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree); 634*433d6423SLionel Sambuc 635*433d6423SLionel Sambuc sef_setcb_signal_handler(sef_cb_signal_handler); 636*433d6423SLionel Sambuc 637*433d6423SLionel Sambuc sef_startup(); 638*433d6423SLionel Sambuc } 639*433d6423SLionel Sambuc 640*433d6423SLionel Sambuc static int 641*433d6423SLionel Sambuc sef_cb_init_fresh(int type, sef_init_info_t *info) 642*433d6423SLionel Sambuc { 643*433d6423SLionel Sambuc long instance = 0; 644*433d6423SLionel Sambuc env_parse("instance", "d", 0, &instance, 0, 255); 645*433d6423SLionel Sambuc 646*433d6423SLionel Sambuc if (virtio_net_probe((int)instance) != OK) 647*433d6423SLionel Sambuc panic("%s: No device found", name); 648*433d6423SLionel Sambuc 649*433d6423SLionel Sambuc if (virtio_net_config() != OK) 650*433d6423SLionel Sambuc panic("%s: No device found", name); 651*433d6423SLionel Sambuc 652*433d6423SLionel Sambuc if (virtio_net_alloc_bufs() != OK) 653*433d6423SLionel Sambuc panic("%s: Buffer allocation failed", name); 654*433d6423SLionel Sambuc 655*433d6423SLionel Sambuc virtio_net_init_queues(); 656*433d6423SLionel Sambuc 657*433d6423SLionel Sambuc netdriver_announce(); 658*433d6423SLionel Sambuc 659*433d6423SLionel Sambuc return(OK); 660*433d6423SLionel Sambuc } 661*433d6423SLionel Sambuc 662*433d6423SLionel Sambuc static void 663*433d6423SLionel Sambuc sef_cb_signal_handler(int signo) 664*433d6423SLionel Sambuc { 665*433d6423SLionel Sambuc if (signo != SIGTERM) 666*433d6423SLionel Sambuc return; 667*433d6423SLionel Sambuc 668*433d6423SLionel Sambuc dput(("Terminating")); 669*433d6423SLionel Sambuc 670*433d6423SLionel Sambuc free_contig(data_vir, PACKET_BUF_SZ); 671*433d6423SLionel Sambuc free_contig(hdrs_vir, BUF_PACKETS * sizeof(hdrs_vir[0])); 672*433d6423SLionel Sambuc free(packets); 673*433d6423SLionel Sambuc 674*433d6423SLionel Sambuc virtio_reset_device(net_dev); 675*433d6423SLionel Sambuc virtio_free_queues(net_dev); 676*433d6423SLionel Sambuc virtio_free_device(net_dev); 677*433d6423SLionel Sambuc net_dev = NULL; 678*433d6423SLionel Sambuc 679*433d6423SLionel Sambuc exit(1); 680*433d6423SLionel Sambuc } 681