|
|
1.1 ! root 1: /****************************************************************************** ! 2: * Copyright (c) 2011 IBM Corporation ! 3: * All rights reserved. ! 4: * This program and the accompanying materials ! 5: * are made available under the terms of the BSD License ! 6: * which accompanies this distribution, and is available at ! 7: * http://www.opensource.org/licenses/bsd-license.php ! 8: * ! 9: * Contributors: ! 10: * IBM Corporation - initial implementation ! 11: *****************************************************************************/ ! 12: ! 13: /* ! 14: * This is the implementation for the Virtio network device driver. Details ! 15: * about the virtio-net interface can be found in Rusty Russel's "Virtio PCI ! 16: * Card Specification v0.8.10", appendix C, which can be found here: ! 17: * ! 18: * http://ozlabs.org/~rusty/virtio-spec/virtio-spec.pdf ! 19: */ ! 20: ! 21: #include <stdint.h> ! 22: #include "netdriver_int.h" ! 23: #include <libhvcall.h> ! 24: #include <virtio.h> ! 25: #include <string.h> ! 26: #include "virtio-net.h" ! 27: ! 28: ! 29: #define sync() asm volatile (" sync \n" ::: "memory") ! 30: ! 31: ! 32: struct virtio_device virtiodev; ! 33: struct vqs vq[2]; /* Information about virtqueues */ ! 34: ! 35: ! 36: /* See Virtio Spec, appendix C, "Device Operation" */ ! 37: struct virtio_net_hdr { ! 38: uint8_t flags; ! 39: uint8_t gso_type; ! 40: uint16_t hdr_len; ! 41: uint16_t gso_size; ! 42: uint16_t csum_start; ! 43: uint16_t csum_offset; ! 44: // uint16_t num_buffers; /* Only if VIRTIO_NET_F_MRG_RXBUF */ ! 45: }; ! 46: ! 47: static uint16_t last_rx_idx; /* Last index in RX "used" ring */ ! 48: ! 49: ! 50: /** ! 51: * Initialize the virtio-net device. ! 52: * See the Virtio Spec, chapter 2.2.1 and Appendix C "Device Initialization" ! 53: * for details. ! 54: */ ! 55: static int virtionet_init(void) ! 56: { ! 57: int i; ! 58: ! 59: dprintk("virtionet_init(%02x:%02x:%02x:%02x:%02x:%02x)\n", ! 60: snk_module_interface->mac_addr[0], snk_module_interface->mac_addr[1], ! 61: snk_module_interface->mac_addr[2], snk_module_interface->mac_addr[3], ! 62: snk_module_interface->mac_addr[4], snk_module_interface->mac_addr[5]); ! 63: ! 64: if (snk_module_interface->running != 0) ! 65: return 0; ! 66: ! 67: /* Tell HV that we know how to drive the device. */ ! 68: virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER); ! 69: ! 70: /* Device specific setup - we do not support special features right now */ ! 71: virtio_set_guest_features(&virtiodev, 0); ! 72: ! 73: /* Allocate memory for one transmit an multiple receive buffers */ ! 74: vq[VQ_RX].buf_mem = malloc((BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr)) ! 75: * RX_QUEUE_SIZE); ! 76: if (!vq[VQ_RX].buf_mem) { ! 77: printk("virtionet: Failed to allocate buffers!\n"); ! 78: virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED); ! 79: return -1; ! 80: } ! 81: ! 82: /* Prepare receive buffer queue */ ! 83: for (i = 0; i < RX_QUEUE_SIZE; i++) { ! 84: struct vring_desc *desc; ! 85: /* Descriptor for net_hdr: */ ! 86: desc = &vq[VQ_RX].desc[i*2]; ! 87: desc->addr = (uint64_t)vq[VQ_RX].buf_mem ! 88: + i * (BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr)); ! 89: // printk("RX buf %i addr = 0x%llx\n", i, desc->addr); ! 90: desc->len = sizeof(struct virtio_net_hdr); ! 91: desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE; ! 92: desc->next = i*2+1; ! 93: ! 94: /* Descriptor for data: */ ! 95: desc = &vq[VQ_RX].desc[i*2+1]; ! 96: desc->addr = vq[VQ_RX].desc[i*2].addr + sizeof(struct virtio_net_hdr); ! 97: desc->len = BUFFER_ENTRY_SIZE; ! 98: desc->flags = VRING_DESC_F_WRITE; ! 99: desc->next = 0; ! 100: ! 101: vq[VQ_RX].avail->ring[i] = i*2; ! 102: } ! 103: sync(); ! 104: vq[VQ_RX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT; ! 105: vq[VQ_RX].avail->idx = RX_QUEUE_SIZE; ! 106: ! 107: last_rx_idx = vq[VQ_RX].used->idx; ! 108: ! 109: vq[VQ_TX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT; ! 110: vq[VQ_TX].avail->idx = 0; ! 111: ! 112: /* Tell HV that setup succeeded */ ! 113: virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE ! 114: |VIRTIO_STAT_DRIVER ! 115: |VIRTIO_STAT_DRIVER_OK); ! 116: ! 117: /* Tell HV that RX queues are ready */ ! 118: virtio_queue_notify(&virtiodev, VQ_RX); ! 119: ! 120: snk_module_interface->running = 1; ! 121: ! 122: return 0; ! 123: } ! 124: ! 125: ! 126: /** ! 127: * Shutdown driver. ! 128: * We've got to make sure that the hosts stops all transfers since the buffers ! 129: * in our main memory will become invalid after this module has been terminated. ! 130: */ ! 131: static int virtionet_term(void) ! 132: { ! 133: dprintk("virtionet_term()\n"); ! 134: ! 135: if (snk_module_interface->running == 0) ! 136: return 0; ! 137: ! 138: /* Quiesce device */ ! 139: virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED); ! 140: ! 141: /* Reset device */ ! 142: virtio_reset_device(&virtiodev); ! 143: ! 144: snk_module_interface->running = 0; ! 145: ! 146: return 0; ! 147: } ! 148: ! 149: ! 150: /** ! 151: * Transmit a packet ! 152: */ ! 153: static int virtionet_xmit(char *buf, int len) ! 154: { ! 155: struct vring_desc *desc; ! 156: int id; ! 157: static struct virtio_net_hdr nethdr = { ! 158: 0, 0, sizeof(struct virtio_net_hdr), ! 159: 0, 0, 0 ! 160: }; ! 161: ! 162: if (len > BUFFER_ENTRY_SIZE) { ! 163: printk("virtionet: Packet too big!\n"); ! 164: return 0; ! 165: } ! 166: ! 167: dprintk("\nvirtionet_xmit(packet at %p, %d bytes)\n", buf, len); ! 168: ! 169: /* Determine descriptor index */ ! 170: id = (vq[VQ_TX].avail->idx * 2) % vq[VQ_TX].size; ! 171: ! 172: /* Set up virtqueue descriptor for header */ ! 173: desc = &vq[VQ_TX].desc[id]; ! 174: desc->addr = (uint64_t)&nethdr; ! 175: desc->len = sizeof(struct virtio_net_hdr); ! 176: desc->flags = VRING_DESC_F_NEXT; ! 177: desc->next = id + 1; ! 178: ! 179: /* Set up virtqueue descriptor for data */ ! 180: desc = &vq[VQ_TX].desc[id+1]; ! 181: desc->addr = (uint64_t)buf; ! 182: desc->len = len; ! 183: desc->flags = 0; ! 184: desc->next = 0; ! 185: ! 186: vq[VQ_TX].avail->ring[vq[VQ_TX].avail->idx % vq[VQ_TX].size] = id; ! 187: sync(); ! 188: vq[VQ_TX].avail->idx += 1; ! 189: ! 190: /* Tell HV that TX queue is ready */ ! 191: virtio_queue_notify(&virtiodev, VQ_TX); ! 192: ! 193: return len; ! 194: } ! 195: ! 196: ! 197: /** ! 198: * Receive a packet ! 199: */ ! 200: static int virtionet_receive(char *buf, int maxlen) ! 201: { ! 202: int len = 0; ! 203: int id; ! 204: ! 205: if (last_rx_idx == vq[VQ_RX].used->idx) { ! 206: /* Nothing received yet */ ! 207: return 0; ! 208: } ! 209: ! 210: id = (vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].id + 1) ! 211: % vq[VQ_RX].size; ! 212: len = vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].len ! 213: - sizeof(struct virtio_net_hdr); ! 214: ! 215: dprintk("virtionet_receive() last_rx_idx=%i, vq[VQ_RX].used->idx=%i," ! 216: " id=%i len=%i\n", last_rx_idx, vq[VQ_RX].used->idx, id, len); ! 217: ! 218: if (len > maxlen) { ! 219: printk("virtio-net: Receive buffer not big enough!\n"); ! 220: len = maxlen; ! 221: } ! 222: ! 223: #if 0 ! 224: /* Dump packet */ ! 225: printk("\n"); ! 226: int i; ! 227: for (i=0; i<64; i++) { ! 228: printk(" %02x", *(uint8_t*)(vq[VQ_RX].desc[id].addr+i)); ! 229: if ((i%16)==15) ! 230: printk("\n"); ! 231: } ! 232: printk("\n"); ! 233: #endif ! 234: ! 235: /* Copy data to destination buffer */ ! 236: memcpy(buf, (void*)vq[VQ_RX].desc[id].addr, len); ! 237: ! 238: /* Move indices to next entries */ ! 239: last_rx_idx = last_rx_idx + 1; ! 240: ! 241: vq[VQ_RX].avail->ring[vq[VQ_RX].avail->idx % vq[VQ_RX].size] = id - 1; ! 242: sync(); ! 243: vq[VQ_RX].avail->idx += 1; ! 244: ! 245: /* Tell HV that RX queue entry is ready */ ! 246: virtio_queue_notify(&virtiodev, VQ_RX); ! 247: ! 248: return len; ! 249: } ! 250: ! 251: ! 252: /** ! 253: * Network IO control function - not implemented. ! 254: */ ! 255: static int virtionet_ioctl(int request, void* data) ! 256: { ! 257: dprintk("virtionet_ioctl()\n"); ! 258: ! 259: return -1; ! 260: } ! 261: ! 262: ! 263: /** ! 264: * Module definition ! 265: */ ! 266: snk_module_t virtionet_interface = { ! 267: .version = 1, ! 268: .type = MOD_TYPE_NETWORK, ! 269: .running = 0, ! 270: .init = virtionet_init, ! 271: .term = virtionet_term, ! 272: .write = virtionet_xmit, ! 273: .read = virtionet_receive, ! 274: .ioctl = virtionet_ioctl ! 275: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.