|
|
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.