1 /******************************************************************************
2 * Copyright (c) 2011 IBM Corporation
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
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
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:
18 * http://ozlabs.org/~rusty/virtio-spec/virtio-spec.pdf
26 #include <byteorder.h>
28 #include "virtio-net.h"
33 # define dprintf(fmt...) do { printf(fmt); } while(0)
35 # define dprintf(fmt...)
38 #define sync() asm volatile (" sync \n" ::: "memory")
40 /* PCI virtio header offsets */
41 #define VIRTIOHDR_DEVICE_FEATURES 0
42 #define VIRTIOHDR_GUEST_FEATURES 4
43 #define VIRTIOHDR_QUEUE_ADDRESS 8
44 #define VIRTIOHDR_QUEUE_SIZE 12
45 #define VIRTIOHDR_QUEUE_SELECT 14
46 #define VIRTIOHDR_QUEUE_NOTIFY 16
47 #define VIRTIOHDR_DEVICE_STATUS 18
48 #define VIRTIOHDR_ISR_STATUS 19
49 #define VIRTIOHDR_DEVICE_CONFIG 20
50 #define VIRTIOHDR_MAC_ADDRESS 20
52 struct virtio_device virtiodev;
53 struct vqs vq[2]; /* Information about virtqueues */
55 /* See Virtio Spec, appendix C, "Device Operation" */
56 struct virtio_net_hdr {
63 // uint16_t num_buffers; /* Only if VIRTIO_NET_F_MRG_RXBUF */
66 static uint16_t last_rx_idx; /* Last index in RX "used" ring */
69 * Module init for virtio via PCI.
70 * Checks whether we're reponsible for the given device and set up
71 * the virtqueue configuration.
73 static int virtionet_init_pci(struct virtio_device *dev)
77 dprintf("virtionet: doing virtionet_init_pci!\n");
82 virtiodev.base = dev->base;
83 virtiodev.type = dev->type;
86 virtio_reset_device(&virtiodev);
88 /* The queue information can be retrieved via the virtio header that
89 * can be found in the I/O BAR. First queue is the receive queue,
90 * second the transmit queue, and the forth is the control queue for
92 * We are only interested in the receive and transmit queue here. */
94 for (i=VQ_RX; i<=VQ_TX; i++) {
95 /* Select ring (0=RX, 1=TX): */
97 ci_write_16(virtiodev.base+VIRTIOHDR_QUEUE_SELECT,
98 cpu_to_le16(vq[i].id));
100 vq[i].size = le16_to_cpu(ci_read_16(virtiodev.base+VIRTIOHDR_QUEUE_SIZE));
101 vq[i].desc = SLOF_alloc_mem_aligned(virtio_vring_size(vq[i].size), 4096);
103 printf("memory allocation failed!\n");
106 memset(vq[i].desc, 0, virtio_vring_size(vq[i].size));
107 ci_write_32(virtiodev.base+VIRTIOHDR_QUEUE_ADDRESS,
108 cpu_to_le32((long)vq[i].desc / 4096));
109 vq[i].avail = (void*)vq[i].desc
110 + vq[i].size * sizeof(struct vring_desc);
111 vq[i].used = (void*)VQ_ALIGN((long)vq[i].avail
112 + vq[i].size * sizeof(struct vring_avail));
114 dprintf("%i: vq.id = %llx\nvq.size =%x\n vq.avail =%p\nvq.used=%p\n",
115 i, vq[i].id, vq[i].size, vq[i].avail, vq[i].used);
118 /* Acknowledge device. */
119 virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE);
125 * Initialize the virtio-net device.
126 * See the Virtio Spec, chapter 2.2.1 and Appendix C "Device Initialization"
129 static int virtionet_init(net_driver_t *driver)
133 dprintf("virtionet_init(%02x:%02x:%02x:%02x:%02x:%02x)\n",
134 driver->mac_addr[0], driver->mac_addr[1],
135 driver->mac_addr[2], driver->mac_addr[3],
136 driver->mac_addr[4], driver->mac_addr[5]);
138 if (driver->running != 0)
141 /* Tell HV that we know how to drive the device. */
142 virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
144 /* Device specific setup - we do not support special features right now */
145 virtio_set_guest_features(&virtiodev, 0);
147 /* Allocate memory for one transmit an multiple receive buffers */
148 vq[VQ_RX].buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr))
150 if (!vq[VQ_RX].buf_mem) {
151 printf("virtionet: Failed to allocate buffers!\n");
152 virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED);
156 /* Prepare receive buffer queue */
157 for (i = 0; i < RX_QUEUE_SIZE; i++) {
158 struct vring_desc *desc;
159 /* Descriptor for net_hdr: */
160 desc = &vq[VQ_RX].desc[i*2];
161 desc->addr = (uint64_t)vq[VQ_RX].buf_mem
162 + i * (BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr));
163 desc->len = sizeof(struct virtio_net_hdr);
164 desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
167 /* Descriptor for data: */
168 desc = &vq[VQ_RX].desc[i*2+1];
169 desc->addr = vq[VQ_RX].desc[i*2].addr + sizeof(struct virtio_net_hdr);
170 desc->len = BUFFER_ENTRY_SIZE;
171 desc->flags = VRING_DESC_F_WRITE;
174 vq[VQ_RX].avail->ring[i] = i*2;
177 vq[VQ_RX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
178 vq[VQ_RX].avail->idx = RX_QUEUE_SIZE;
180 last_rx_idx = vq[VQ_RX].used->idx;
182 vq[VQ_TX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
183 vq[VQ_TX].avail->idx = 0;
185 /* Tell HV that setup succeeded */
186 virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE
188 |VIRTIO_STAT_DRIVER_OK);
190 /* Tell HV that RX queues are ready */
191 virtio_queue_notify(&virtiodev, VQ_RX);
201 * We've got to make sure that the hosts stops all transfers since the buffers
202 * in our main memory will become invalid after this module has been terminated.
204 static int virtionet_term(net_driver_t *driver)
206 dprintf("virtionet_term()\n");
208 if (driver->running == 0)
212 virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED);
215 virtio_reset_device(&virtiodev);
226 static int virtionet_xmit(char *buf, int len)
228 struct vring_desc *desc;
230 static struct virtio_net_hdr nethdr;
232 if (len > BUFFER_ENTRY_SIZE) {
233 printf("virtionet: Packet too big!\n");
237 dprintf("\nvirtionet_xmit(packet at %p, %d bytes)\n", buf, len);
239 memset(&nethdr, 0, sizeof(nethdr));
241 /* Determine descriptor index */
242 id = (vq[VQ_TX].avail->idx * 2) % vq[VQ_TX].size;
244 /* Set up virtqueue descriptor for header */
245 desc = &vq[VQ_TX].desc[id];
246 desc->addr = (uint64_t)&nethdr;
247 desc->len = sizeof(struct virtio_net_hdr);
248 desc->flags = VRING_DESC_F_NEXT;
251 /* Set up virtqueue descriptor for data */
252 desc = &vq[VQ_TX].desc[id+1];
253 desc->addr = (uint64_t)buf;
258 vq[VQ_TX].avail->ring[vq[VQ_TX].avail->idx % vq[VQ_TX].size] = id;
260 vq[VQ_TX].avail->idx += 1;
263 /* Tell HV that TX queue is ready */
264 virtio_queue_notify(&virtiodev, VQ_TX);
273 static int virtionet_receive(char *buf, int maxlen)
278 if (last_rx_idx == vq[VQ_RX].used->idx) {
279 /* Nothing received yet */
283 id = (vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].id + 1)
285 len = vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].len
286 - sizeof(struct virtio_net_hdr);
288 dprintf("virtionet_receive() last_rx_idx=%i, vq[VQ_RX].used->idx=%i,"
289 " id=%i len=%i\n", last_rx_idx, vq[VQ_RX].used->idx, id, len);
292 printf("virtio-net: Receive buffer not big enough!\n");
300 for (i=0; i<64; i++) {
301 printf(" %02x", *(uint8_t*)(vq[VQ_RX].desc[id].addr+i));
308 /* Copy data to destination buffer */
309 memcpy(buf, (void*)vq[VQ_RX].desc[id].addr, len);
311 /* Move indices to next entries */
312 last_rx_idx = last_rx_idx + 1;
314 vq[VQ_RX].avail->ring[vq[VQ_RX].avail->idx % vq[VQ_RX].size] = id - 1;
316 vq[VQ_RX].avail->idx += 1;
318 /* Tell HV that RX queue entry is ready */
319 virtio_queue_notify(&virtiodev, VQ_RX);
324 net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev)
326 net_driver_t *driver;
328 driver = SLOF_alloc_mem(sizeof(*driver));
330 printf("Unable to allocate virtio-net driver\n");
334 memcpy(driver->mac_addr, mac_addr, 6);
337 if (virtionet_init_pci(dev))
340 if (virtionet_init(driver))
345 FAIL: SLOF_free_mem(driver, sizeof(*driver));
349 void virtionet_close(net_driver_t *driver)
352 virtionet_term(driver);
353 SLOF_free_mem(driver, sizeof(*driver));
357 int virtionet_read(char *buf, int len)
360 return virtionet_receive(buf, len);
364 int virtionet_write(char *buf, int len)
367 return virtionet_xmit(buf, len);