1 /* virtio net driver for MINIX 3 2 * 3 * Copyright (c) 2013, A. Welzel, <arne.welzel@gmail.com> 4 * 5 * This software is released under the BSD license. See the LICENSE file 6 * included in the main directory of this source distribution for the 7 * license terms and conditions. 8 */ 9 10 #include <assert.h> 11 #include <sys/types.h> 12 13 #include <minix/drivers.h> 14 #include <minix/netdriver.h> 15 #include <minix/virtio.h> 16 17 #include <sys/queue.h> 18 19 #include "virtio_net.h" 20 21 #define VERBOSE 0 22 23 #if VERBOSE 24 #define dput(s) do { dprintf(s); printf("\n"); } while (0) 25 #define dprintf(s) do { \ 26 printf("%s: ", netdriver_name()); \ 27 printf s; \ 28 } while (0) 29 #else 30 #define dput(s) 31 #define dprintf(s) 32 #endif 33 34 static struct virtio_device *net_dev; 35 36 enum queue {RX_Q, TX_Q, CTRL_Q}; 37 38 /* Number of packets to work with */ 39 /* TODO: This should be an argument to the driver and possibly also 40 * depend on the queue sizes offered by this device. 41 */ 42 #define BUF_PACKETS 64 43 /* Maximum size of a packet */ 44 #define MAX_PACK_SIZE NDEV_ETH_PACKET_MAX 45 /* Buffer size needed for the payload of BUF_PACKETS */ 46 #define PACKET_BUF_SZ (BUF_PACKETS * MAX_PACK_SIZE) 47 48 struct packet { 49 int idx; 50 struct virtio_net_hdr *vhdr; 51 phys_bytes phdr; 52 char *vdata; 53 phys_bytes pdata; 54 size_t len; 55 STAILQ_ENTRY(packet) next; 56 }; 57 58 /* Allocated data chunks */ 59 static char *data_vir; 60 static phys_bytes data_phys; 61 static struct virtio_net_hdr *hdrs_vir; 62 static phys_bytes hdrs_phys; 63 static struct packet *packets; 64 static int in_rx; 65 66 /* Packets on this list can be given to the host */ 67 static STAILQ_HEAD(free_list, packet) free_list; 68 69 /* Packets on this list are to be given to inet */ 70 static STAILQ_HEAD(recv_list, packet) recv_list; 71 72 /* Various state data */ 73 static int spurious_interrupt; 74 75 /* Prototypes */ 76 static int virtio_net_probe(unsigned int skip); 77 static void virtio_net_config(netdriver_addr_t *addr); 78 static int virtio_net_alloc_bufs(void); 79 static void virtio_net_init_queues(void); 80 81 static void virtio_net_refill_rx_queue(void); 82 static void virtio_net_check_queues(void); 83 static void virtio_net_check_pending(void); 84 85 static int virtio_net_init(unsigned int instance, netdriver_addr_t * addr, 86 uint32_t * caps, unsigned int * ticks); 87 static void virtio_net_stop(void); 88 static int virtio_net_send(struct netdriver_data *data, size_t len); 89 static ssize_t virtio_net_recv(struct netdriver_data *data, size_t max); 90 static void virtio_net_intr(unsigned int mask); 91 92 static const struct netdriver virtio_net_table = { 93 .ndr_name = "vio", 94 .ndr_init = virtio_net_init, 95 .ndr_stop = virtio_net_stop, 96 .ndr_recv = virtio_net_recv, 97 .ndr_send = virtio_net_send, 98 .ndr_intr = virtio_net_intr, 99 }; 100 101 /* TODO: Features are pretty much ignored */ 102 static struct virtio_feature netf[] = { 103 { "partial csum", VIRTIO_NET_F_CSUM, 0, 0 }, 104 { "given mac", VIRTIO_NET_F_MAC, 0, 1 }, 105 { "status ", VIRTIO_NET_F_STATUS, 0, 0 }, 106 { "control channel", VIRTIO_NET_F_CTRL_VQ, 0, 1 }, 107 { "control channel rx", VIRTIO_NET_F_CTRL_RX, 0, 0 } 108 }; 109 110 static int 111 virtio_net_probe(unsigned int skip) 112 { 113 /* virtio-net has at least 2 queues */ 114 int queues = 2; 115 net_dev= virtio_setup_device(0x00001, netdriver_name(), netf, 116 sizeof(netf) / sizeof(netf[0]), 117 1 /* threads */, skip); 118 if (net_dev == NULL) 119 return ENXIO; 120 121 /* If the host supports the control queue, allocate it as well */ 122 if (virtio_host_supports(net_dev, VIRTIO_NET_F_CTRL_VQ)) 123 queues += 1; 124 125 if (virtio_alloc_queues(net_dev, queues) != OK) { 126 virtio_free_device(net_dev); 127 return ENOMEM; 128 } 129 130 return OK; 131 } 132 133 static void 134 virtio_net_config(netdriver_addr_t * addr) 135 { 136 u32_t mac14; 137 u32_t mac56; 138 int i; 139 140 if (virtio_host_supports(net_dev, VIRTIO_NET_F_MAC)) { 141 dprintf(("Mac set by host: ")); 142 mac14 = virtio_sread32(net_dev, 0); 143 mac56 = virtio_sread32(net_dev, 4); 144 memcpy(&addr->na_addr[0], &mac14, 4); 145 memcpy(&addr->na_addr[4], &mac56, 2); 146 147 for (i = 0; i < 6; i++) 148 dprintf(("%02x%s", addr->na_addr[i], 149 i == 5 ? "\n" : ":")); 150 } else { 151 dput(("No mac")); 152 } 153 154 if (virtio_host_supports(net_dev, VIRTIO_NET_F_STATUS)) { 155 dput(("Current Status %x", (u32_t)virtio_sread16(net_dev, 6))); 156 } else { 157 dput(("No status")); 158 } 159 160 if (virtio_host_supports(net_dev, VIRTIO_NET_F_CTRL_VQ)) 161 dput(("Host supports control channel")); 162 163 if (virtio_host_supports(net_dev, VIRTIO_NET_F_CTRL_RX)) 164 dput(("Host supports control channel for RX")); 165 } 166 167 static int 168 virtio_net_alloc_bufs(void) 169 { 170 data_vir = alloc_contig(PACKET_BUF_SZ, 0, &data_phys); 171 172 if (!data_vir) 173 return ENOMEM; 174 175 hdrs_vir = alloc_contig(BUF_PACKETS * sizeof(hdrs_vir[0]), 176 0, &hdrs_phys); 177 178 if (!hdrs_vir) { 179 free_contig(data_vir, PACKET_BUF_SZ); 180 return ENOMEM; 181 } 182 183 packets = malloc(BUF_PACKETS * sizeof(packets[0])); 184 185 if (!packets) { 186 free_contig(data_vir, PACKET_BUF_SZ); 187 free_contig(hdrs_vir, BUF_PACKETS * sizeof(hdrs_vir[0])); 188 return ENOMEM; 189 } 190 191 memset(data_vir, 0, PACKET_BUF_SZ); 192 memset(hdrs_vir, 0, BUF_PACKETS * sizeof(hdrs_vir[0])); 193 memset(packets, 0, BUF_PACKETS * sizeof(packets[0])); 194 195 return OK; 196 } 197 198 static void 199 virtio_net_init_queues(void) 200 { 201 int i; 202 STAILQ_INIT(&free_list); 203 STAILQ_INIT(&recv_list); 204 205 for (i = 0; i < BUF_PACKETS; i++) { 206 packets[i].idx = i; 207 packets[i].vhdr = &hdrs_vir[i]; 208 packets[i].phdr = hdrs_phys + i * sizeof(hdrs_vir[i]); 209 packets[i].vdata = data_vir + i * MAX_PACK_SIZE; 210 packets[i].pdata = data_phys + i * MAX_PACK_SIZE; 211 STAILQ_INSERT_HEAD(&free_list, &packets[i], next); 212 } 213 } 214 215 static void 216 virtio_net_refill_rx_queue(void) 217 { 218 struct vumap_phys phys[2]; 219 struct packet *p; 220 221 while ((in_rx < BUF_PACKETS / 2) && !STAILQ_EMPTY(&free_list)) { 222 /* peek */ 223 p = STAILQ_FIRST(&free_list); 224 /* remove */ 225 STAILQ_REMOVE_HEAD(&free_list, next); 226 227 phys[0].vp_addr = p->phdr; 228 assert(!(phys[0].vp_addr & 1)); 229 phys[0].vp_size = sizeof(struct virtio_net_hdr); 230 231 phys[1].vp_addr = p->pdata; 232 assert(!(phys[1].vp_addr & 1)); 233 phys[1].vp_size = MAX_PACK_SIZE; 234 235 /* RX queue needs write */ 236 phys[0].vp_addr |= 1; 237 phys[1].vp_addr |= 1; 238 239 virtio_to_queue(net_dev, RX_Q, phys, 2, p); 240 in_rx++; 241 } 242 243 if (in_rx == 0 && STAILQ_EMPTY(&free_list)) 244 dput(("warning: rx queue underflow!")); 245 } 246 247 static void 248 virtio_net_check_queues(void) 249 { 250 struct packet *p; 251 size_t len; 252 253 /* Put the received packets into the recv list */ 254 while (virtio_from_queue(net_dev, RX_Q, (void **)&p, &len) == 0) { 255 p->len = len; 256 STAILQ_INSERT_TAIL(&recv_list, p, next); 257 in_rx--; 258 } 259 260 /* 261 * Packets from the TX queue just indicated they are free to 262 * be reused now. inet already knows about them as being sent. 263 */ 264 while (virtio_from_queue(net_dev, TX_Q, (void **)&p, NULL) == 0) { 265 memset(p->vhdr, 0, sizeof(*p->vhdr)); 266 memset(p->vdata, 0, MAX_PACK_SIZE); 267 STAILQ_INSERT_HEAD(&free_list, p, next); 268 } 269 } 270 271 static void 272 virtio_net_check_pending(void) 273 { 274 275 /* Pending read and something in recv_list? */ 276 if (!STAILQ_EMPTY(&recv_list)) 277 netdriver_recv(); 278 279 if (!STAILQ_EMPTY(&free_list)) 280 netdriver_send(); 281 } 282 283 static void 284 virtio_net_intr(unsigned int __unused mask) 285 { 286 287 /* Check and clear interrupt flag */ 288 if (virtio_had_irq(net_dev)) { 289 virtio_net_check_queues(); 290 } else { 291 if (!spurious_interrupt) 292 dput(("Spurious interrupt")); 293 294 spurious_interrupt = 1; 295 } 296 297 virtio_net_check_pending(); 298 299 virtio_irq_enable(net_dev); 300 301 /* Readd packets to the receive queue as necessary. */ 302 virtio_net_refill_rx_queue(); 303 } 304 305 /* 306 * Put user bytes into a free packet buffer, forward this packet to the TX 307 * queue, and return OK. If there are no free packet buffers, return SUSPEND. 308 */ 309 static int 310 virtio_net_send(struct netdriver_data * data, size_t len) 311 { 312 struct vumap_phys phys[2]; 313 struct packet *p; 314 315 if (STAILQ_EMPTY(&free_list)) 316 return SUSPEND; 317 318 p = STAILQ_FIRST(&free_list); 319 STAILQ_REMOVE_HEAD(&free_list, next); 320 321 if (len > MAX_PACK_SIZE) 322 panic("%s: packet too large to send: %zu", 323 netdriver_name(), len); 324 325 netdriver_copyin(data, 0, p->vdata, len); 326 327 phys[0].vp_addr = p->phdr; 328 assert(!(phys[0].vp_addr & 1)); 329 phys[0].vp_size = sizeof(struct virtio_net_hdr); 330 phys[1].vp_addr = p->pdata; 331 assert(!(phys[1].vp_addr & 1)); 332 phys[1].vp_size = len; 333 virtio_to_queue(net_dev, TX_Q, phys, 2, p); 334 335 return OK; 336 } 337 338 /* 339 * Put a packet receive from the RX queue into a user buffer, and return the 340 * packet length. If there are no received packets, return SUSPEND. 341 */ 342 static ssize_t 343 virtio_net_recv(struct netdriver_data * data, size_t max) 344 { 345 struct packet *p; 346 ssize_t len; 347 348 /* Get the first received packet, if any. */ 349 if (STAILQ_EMPTY(&recv_list)) 350 return SUSPEND; 351 352 p = STAILQ_FIRST(&recv_list); 353 STAILQ_REMOVE_HEAD(&recv_list, next); 354 355 /* Copy out the packet contents. */ 356 if (p->len < sizeof(struct virtio_net_hdr)) 357 panic("received packet does not have virtio header"); 358 len = p->len - sizeof(struct virtio_net_hdr); 359 if ((size_t)len > max) 360 len = (ssize_t)max; 361 362 /* 363 * HACK: due to lack of padding, received packets may in fact be 364 * smaller than the minimum ethernet packet size. The TCP/IP service 365 * will accept the packets just fine if we increase the length to its 366 * minimum. We already zeroed out the rest of the packet data, so this 367 * is safe. 368 */ 369 if (len < NDEV_ETH_PACKET_MIN) 370 len = NDEV_ETH_PACKET_MIN; 371 372 netdriver_copyout(data, 0, p->vdata, len); 373 374 /* Clean the packet. */ 375 memset(p->vhdr, 0, sizeof(*p->vhdr)); 376 memset(p->vdata, 0, MAX_PACK_SIZE); 377 STAILQ_INSERT_HEAD(&free_list, p, next); 378 379 /* Readd packets to the receive queue as necessary. */ 380 virtio_net_refill_rx_queue(); 381 382 return len; 383 } 384 385 /* 386 * Initialize the driver and the virtual hardware. 387 */ 388 static int 389 virtio_net_init(unsigned int instance, netdriver_addr_t * addr, 390 uint32_t * caps, unsigned int * ticks __unused) 391 { 392 int r; 393 394 if ((r = virtio_net_probe(instance)) != OK) 395 return r; 396 397 virtio_net_config(addr); 398 399 if (virtio_net_alloc_bufs() != OK) 400 panic("%s: Buffer allocation failed", netdriver_name()); 401 402 virtio_net_init_queues(); 403 404 /* Add packets to the receive queue. */ 405 virtio_net_refill_rx_queue(); 406 407 virtio_device_ready(net_dev); 408 409 virtio_irq_enable(net_dev); 410 411 *caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST; 412 return OK; 413 } 414 415 /* 416 * The driver is terminating. Clean up. 417 */ 418 static void 419 virtio_net_stop(void) 420 { 421 422 dput(("Terminating")); 423 424 free_contig(data_vir, PACKET_BUF_SZ); 425 free_contig(hdrs_vir, BUF_PACKETS * sizeof(hdrs_vir[0])); 426 free(packets); 427 428 virtio_reset_device(net_dev); 429 virtio_free_queues(net_dev); 430 virtio_free_device(net_dev); 431 net_dev = NULL; 432 } 433 434 /* 435 * The virtio-net device driver. 436 */ 437 int 438 main(int argc, char *argv[]) 439 { 440 441 env_setargs(argc, argv); 442 443 netdriver_task(&virtio_net_table); 444 445 return 0; 446 } 447