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 <stdio.h>
23 #include <string.h>
24 #include <helpers.h>
25 #include <cache.h>
26 #include <byteorder.h>
27 #include "virtio-net.h"
28 #include "virtio-internal.h"
29 
30 #undef DEBUG
31 //#define DEBUG
32 #ifdef DEBUG
33 # define dprintf(fmt...) do { printf(fmt); } while(0)
34 #else
35 # define dprintf(fmt...)
36 #endif
37 
38 #define sync()  asm volatile (" sync \n" ::: "memory")
39 
40 #define DRIVER_FEATURE_SUPPORT  (VIRTIO_NET_F_MAC | VIRTIO_F_VERSION_1)
41 
42 /* See Virtio Spec, appendix C, "Device Operation" */
43 struct virtio_net_hdr {
44 	uint8_t  flags;
45 	uint8_t  gso_type;
46 	uint16_t  hdr_len;
47 	uint16_t  gso_size;
48 	uint16_t  csum_start;
49 	uint16_t  csum_offset;
50 	// uint16_t  num_buffers;	/* Only if VIRTIO_NET_F_MRG_RXBUF */
51 };
52 
53 static unsigned int net_hdr_size;
54 
55 struct virtio_net_hdr_v1 {
56 	uint8_t  flags;
57 	uint8_t  gso_type;
58 	le16  hdr_len;
59 	le16  gso_size;
60 	le16  csum_start;
61 	le16  csum_offset;
62 	le16  num_buffers;
63 };
64 
65 static uint16_t last_rx_idx;	/* Last index in RX "used" ring */
66 
67 /**
68  * Module init for virtio via PCI.
69  * Checks whether we're reponsible for the given device and set up
70  * the virtqueue configuration.
71  */
virtionet_init_pci(struct virtio_net * vnet,struct virtio_device * dev)72 static int virtionet_init_pci(struct virtio_net *vnet, struct virtio_device *dev)
73 {
74 	struct virtio_device *vdev = &vnet->vdev;
75 
76 	dprintf("virtionet: doing virtionet_init_pci!\n");
77 
78 	if (!dev)
79 		return -1;
80 
81 	/* make a copy of the device structure */
82 	memcpy(vdev, dev, sizeof(struct virtio_device));
83 
84 	/* Reset device */
85 	virtio_reset_device(vdev);
86 
87 	/* Acknowledge device. */
88 	virtio_set_status(vdev, VIRTIO_STAT_ACKNOWLEDGE);
89 
90 	return 0;
91 }
92 
93 /**
94  * Initialize the virtio-net device.
95  * See the Virtio Spec, chapter 2.2.1 and Appendix C "Device Initialization"
96  * for details.
97  */
virtionet_init(struct virtio_net * vnet)98 static int virtionet_init(struct virtio_net *vnet)
99 {
100 	int i;
101 	int status = VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER;
102 	struct virtio_device *vdev = &vnet->vdev;
103 	net_driver_t *driver = &vnet->driver;
104 	struct vqs *vq_tx, *vq_rx;
105 
106 	dprintf("virtionet_init(%02x:%02x:%02x:%02x:%02x:%02x)\n",
107 		driver->mac_addr[0], driver->mac_addr[1],
108 		driver->mac_addr[2], driver->mac_addr[3],
109 		driver->mac_addr[4], driver->mac_addr[5]);
110 
111 	if (driver->running != 0)
112 		return 0;
113 
114 	/* Tell HV that we know how to drive the device. */
115 	virtio_set_status(vdev, status);
116 
117 	/* Device specific setup */
118 	if (vdev->features & VIRTIO_F_VERSION_1) {
119 		if (virtio_negotiate_guest_features(vdev, DRIVER_FEATURE_SUPPORT))
120 			goto dev_error;
121 		net_hdr_size = sizeof(struct virtio_net_hdr_v1);
122 		virtio_get_status(vdev, &status);
123 	} else {
124 		net_hdr_size = sizeof(struct virtio_net_hdr);
125 		virtio_set_guest_features(vdev,  0);
126 	}
127 
128 	/* The queue information can be retrieved via the virtio header that
129 	 * can be found in the I/O BAR. First queue is the receive queue,
130 	 * second the transmit queue, and the forth is the control queue for
131 	 * networking options.
132 	 * We are only interested in the receive and transmit queue here. */
133 	vq_rx = virtio_queue_init_vq(vdev, VQ_RX);
134 	vq_tx = virtio_queue_init_vq(vdev, VQ_TX);
135 	if (!vq_rx || !vq_tx) {
136 		virtio_set_status(vdev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER
137 				  |VIRTIO_STAT_FAILED);
138 		return -1;
139 	}
140 
141 	/* Allocate memory for one transmit an multiple receive buffers */
142 	vq_rx->buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+net_hdr_size)
143 				   * RX_QUEUE_SIZE);
144 	if (!vq_rx->buf_mem) {
145 		printf("virtionet: Failed to allocate buffers!\n");
146 		goto dev_error;
147 	}
148 
149 	/* Prepare receive buffer queue */
150 	for (i = 0; i < RX_QUEUE_SIZE; i++) {
151 		uint64_t addr = (uint64_t)vq_rx->buf_mem
152 			+ i * (BUFFER_ENTRY_SIZE+net_hdr_size);
153 		uint32_t id = i*2;
154 		/* Descriptor for net_hdr: */
155 		virtio_fill_desc(vq_rx, id, vdev->features, addr, net_hdr_size,
156 				 VRING_DESC_F_NEXT | VRING_DESC_F_WRITE, id + 1);
157 
158 		/* Descriptor for data: */
159 		virtio_fill_desc(vq_rx, id + 1, vdev->features, addr + net_hdr_size,
160 				 BUFFER_ENTRY_SIZE, VRING_DESC_F_WRITE, 0);
161 
162 		vq_rx->avail->ring[i] = virtio_cpu_to_modern16(vdev, id);
163 	}
164 	sync();
165 
166 	vq_rx->avail->flags = virtio_cpu_to_modern16(vdev, VRING_AVAIL_F_NO_INTERRUPT);
167 	vq_rx->avail->idx = virtio_cpu_to_modern16(vdev, RX_QUEUE_SIZE);
168 
169 	last_rx_idx = virtio_modern16_to_cpu(vdev, vq_rx->used->idx);
170 
171 	vq_tx->avail->flags = virtio_cpu_to_modern16(vdev, VRING_AVAIL_F_NO_INTERRUPT);
172 	vq_tx->avail->idx = 0;
173 
174 	/* Tell HV that setup succeeded */
175 	status |= VIRTIO_STAT_DRIVER_OK;
176 	virtio_set_status(vdev, status);
177 
178 	/* Tell HV that RX queues are ready */
179 	virtio_queue_notify(vdev, VQ_RX);
180 
181 	driver->running = 1;
182 	for(i = 0; i < (int)sizeof(driver->mac_addr); i++) {
183 		driver->mac_addr[i] = virtio_get_config(vdev, i, 1);
184 	}
185 	return 0;
186 
187 dev_error:
188 	status |= VIRTIO_STAT_FAILED;
189 	virtio_set_status(vdev, status);
190 	return -1;
191 }
192 
193 
194 /**
195  * Shutdown driver.
196  * We've got to make sure that the hosts stops all transfers since the buffers
197  * in our main memory will become invalid after this module has been terminated.
198  */
virtionet_term(struct virtio_net * vnet)199 static int virtionet_term(struct virtio_net *vnet)
200 {
201 	struct virtio_device *vdev = &vnet->vdev;
202 	net_driver_t *driver = &vnet->driver;
203 	struct vqs *vq_tx = &vnet->vdev.vq[VQ_TX];
204 	struct vqs *vq_rx = &vnet->vdev.vq[VQ_RX];
205 
206 	dprintf("virtionet_term()\n");
207 
208 	if (driver->running == 0)
209 		return 0;
210 
211 	/* Quiesce device */
212 	virtio_set_status(vdev, VIRTIO_STAT_FAILED);
213 
214 	/* Reset device */
215 	virtio_reset_device(vdev);
216 
217 	driver->running = 0;
218 
219 	SLOF_free_mem(vq_rx->buf_mem,
220 		      (BUFFER_ENTRY_SIZE+net_hdr_size) * RX_QUEUE_SIZE);
221 	vq_rx->buf_mem = NULL;
222 
223 	virtio_queue_term_vq(vdev, vq_rx, VQ_RX);
224 	virtio_queue_term_vq(vdev, vq_tx, VQ_TX);
225 
226 	return 0;
227 }
228 
229 
230 /**
231  * Transmit a packet
232  */
virtionet_xmit(struct virtio_net * vnet,char * buf,int len)233 static int virtionet_xmit(struct virtio_net *vnet, char *buf, int len)
234 {
235 	int id, idx;
236 	static struct virtio_net_hdr_v1 nethdr_v1;
237 	static struct virtio_net_hdr nethdr_legacy;
238 	void *nethdr = &nethdr_legacy;
239 	struct virtio_device *vdev = &vnet->vdev;
240 	struct vqs *vq_tx = &vdev->vq[VQ_TX];
241 
242 	if (len > BUFFER_ENTRY_SIZE) {
243 		printf("virtionet: Packet too big!\n");
244 		return 0;
245 	}
246 
247 	dprintf("\nvirtionet_xmit(packet at %p, %d bytes)\n", buf, len);
248 
249 	if (vdev->features & VIRTIO_F_VERSION_1)
250 		nethdr = &nethdr_v1;
251 
252 	memset(nethdr, 0, net_hdr_size);
253 
254 	/* Determine descriptor index */
255 	idx = virtio_modern16_to_cpu(vdev, vq_tx->avail->idx);
256 	id = (idx * 2) % vq_tx->size;
257 
258 	virtio_free_desc(vq_tx, id, vdev->features);
259 	virtio_free_desc(vq_tx, id + 1, vdev->features);
260 
261 	/* Set up virtqueue descriptor for header */
262 	virtio_fill_desc(vq_tx, id, vdev->features, (uint64_t)nethdr,
263 			 net_hdr_size, VRING_DESC_F_NEXT, id + 1);
264 
265 	/* Set up virtqueue descriptor for data */
266 	virtio_fill_desc(vq_tx, id + 1, vdev->features, (uint64_t)buf, len, 0, 0);
267 
268 	vq_tx->avail->ring[idx % vq_tx->size] = virtio_cpu_to_modern16(vdev, id);
269 	sync();
270 	vq_tx->avail->idx = virtio_cpu_to_modern16(vdev, idx + 1);
271 	sync();
272 
273 	/* Tell HV that TX queue is ready */
274 	virtio_queue_notify(vdev, VQ_TX);
275 
276 	return len;
277 }
278 
279 
280 /**
281  * Receive a packet
282  */
virtionet_receive(struct virtio_net * vnet,char * buf,int maxlen)283 static int virtionet_receive(struct virtio_net *vnet, char *buf, int maxlen)
284 {
285 	uint32_t len = 0;
286 	uint32_t id, idx;
287 	uint16_t avail_idx;
288 	struct virtio_device *vdev = &vnet->vdev;
289 	struct vqs *vq_rx = &vnet->vdev.vq[VQ_RX];
290 
291 	idx = virtio_modern16_to_cpu(vdev, vq_rx->used->idx);
292 
293 	if (last_rx_idx == idx) {
294 		/* Nothing received yet */
295 		return 0;
296 	}
297 
298 	id = (virtio_modern32_to_cpu(vdev, vq_rx->used->ring[last_rx_idx % vq_rx->size].id) + 1)
299 		% vq_rx->size;
300 	len = virtio_modern32_to_cpu(vdev, vq_rx->used->ring[last_rx_idx % vq_rx->size].len)
301 		- net_hdr_size;
302 	dprintf("virtionet_receive() last_rx_idx=%i, vq_rx->used->idx=%i,"
303 		" id=%i len=%i\n", last_rx_idx, vq_rx->used->idx, id, len);
304 
305 	if (len > (uint32_t)maxlen) {
306 		printf("virtio-net: Receive buffer not big enough!\n");
307 		len = maxlen;
308 	}
309 
310 #if 0
311 	/* Dump packet */
312 	printf("\n");
313 	int i;
314 	for (i=0; i<64; i++) {
315 		printf(" %02x", *(uint8_t*)(vq_rx->desc[id].addr+i));
316 		if ((i%16)==15)
317 			printf("\n");
318 	}
319 	prinfk("\n");
320 #endif
321 
322 	/* Copy data to destination buffer */
323 	memcpy(buf, virtio_desc_addr(vdev, VQ_RX, id), len);
324 
325 	/* Move indices to next entries */
326 	last_rx_idx = last_rx_idx + 1;
327 
328 	avail_idx = virtio_modern16_to_cpu(vdev, vq_rx->avail->idx);
329 	vq_rx->avail->ring[avail_idx % vq_rx->size] = virtio_cpu_to_modern16(vdev, id - 1);
330 	sync();
331 	vq_rx->avail->idx = virtio_cpu_to_modern16(vdev, avail_idx + 1);
332 
333 	/* Tell HV that RX queue entry is ready */
334 	virtio_queue_notify(vdev, VQ_RX);
335 
336 	return len;
337 }
338 
virtionet_open(struct virtio_device * dev)339 struct virtio_net *virtionet_open(struct virtio_device *dev)
340 {
341 	struct virtio_net *vnet;
342 
343 	vnet = SLOF_alloc_mem(sizeof(*vnet));
344 	if (!vnet) {
345 		printf("Unable to allocate virtio-net driver\n");
346 		return NULL;
347 	}
348 
349 	vnet->driver.running = 0;
350 
351 	if (virtionet_init_pci(vnet, dev))
352 		goto FAIL;
353 
354 	if (virtionet_init(vnet))
355 		goto FAIL;
356 
357 	return vnet;
358 
359 FAIL:
360 	SLOF_free_mem(vnet, sizeof(*vnet));
361 	return NULL;
362 }
363 
virtionet_close(struct virtio_net * vnet)364 void virtionet_close(struct virtio_net *vnet)
365 {
366 	if (vnet) {
367 		virtionet_term(vnet);
368 		SLOF_free_mem(vnet, sizeof(*vnet));
369 	}
370 }
371 
virtionet_read(struct virtio_net * vnet,char * buf,int len)372 int virtionet_read(struct virtio_net *vnet, char *buf, int len)
373 {
374 	if (vnet && buf)
375 		return virtionet_receive(vnet, buf, len);
376 	return -1;
377 }
378 
virtionet_write(struct virtio_net * vnet,char * buf,int len)379 int virtionet_write(struct virtio_net *vnet, char *buf, int len)
380 {
381 	if (vnet && buf)
382 		return virtionet_xmit(vnet, buf, len);
383 	return -1;
384 }
385