|
@@ -66,20 +66,27 @@ enum {
|
66
|
66
|
QUEUE_NB
|
67
|
67
|
};
|
68
|
68
|
|
69
|
|
-static virtio_queue_t queue[QUEUE_NB];
|
70
|
|
-static struct vring vring[QUEUE_NB];
|
71
|
|
-static u16 free_head[QUEUE_NB];
|
72
|
|
-static u16 last_used_idx[QUEUE_NB];
|
73
|
|
-static u16 vdata[QUEUE_NB][MAX_QUEUE_NUM];
|
|
69
|
+struct vring_virtqueue {
|
|
70
|
+ virtio_queue_t queue;
|
|
71
|
+ struct vring vring;
|
|
72
|
+ u16 free_head;
|
|
73
|
+ u16 last_used_idx;
|
|
74
|
+ u16 vdata[MAX_QUEUE_NUM];
|
|
75
|
+ /* PCI */
|
|
76
|
+ int queue_index;
|
|
77
|
+};
|
|
78
|
+
|
|
79
|
+static struct vring_virtqueue virtqueue[QUEUE_NB];
|
74
|
80
|
|
75
|
81
|
/*
|
76
|
82
|
* Virtio PCI interface
|
77
|
83
|
*
|
78
|
84
|
*/
|
79
|
85
|
|
80
|
|
-static int vp_find_vq(unsigned int ioaddr, int queue_index)
|
|
86
|
+static int vp_find_vq(unsigned int ioaddr, int queue_index,
|
|
87
|
+ struct vring_virtqueue *vq)
|
81
|
88
|
{
|
82
|
|
- struct vring * vr = &vring[queue_index];
|
|
89
|
+ struct vring * vr = &vq->vring;
|
83
|
90
|
u16 num;
|
84
|
91
|
|
85
|
92
|
/* select the queue */
|
|
@@ -106,9 +113,11 @@ static int vp_find_vq(unsigned int ioaddr, int queue_index)
|
106
|
113
|
return -1;
|
107
|
114
|
}
|
108
|
115
|
|
|
116
|
+ vq->queue_index = queue_index;
|
|
117
|
+
|
109
|
118
|
/* initialize the queue */
|
110
|
119
|
|
111
|
|
- vring_init(vr, num, (unsigned char*)&queue[queue_index]);
|
|
120
|
+ vring_init(vr, num, (unsigned char*)&vq->queue);
|
112
|
121
|
|
113
|
122
|
/* activate the queue
|
114
|
123
|
*
|
|
@@ -126,14 +135,14 @@ static int vp_find_vq(unsigned int ioaddr, int queue_index)
|
126
|
135
|
*
|
127
|
136
|
*/
|
128
|
137
|
|
129
|
|
-static void vring_enable_cb(int queue_index)
|
|
138
|
+static void vring_enable_cb(struct vring_virtqueue *vq)
|
130
|
139
|
{
|
131
|
|
- vring[queue_index].avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
|
|
140
|
+ vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
|
132
|
141
|
}
|
133
|
142
|
|
134
|
|
-static void vring_disable_cb(int queue_index)
|
|
143
|
+static void vring_disable_cb(struct vring_virtqueue *vq)
|
135
|
144
|
{
|
136
|
|
- vring[queue_index].avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
|
|
145
|
+ vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
|
137
|
146
|
}
|
138
|
147
|
|
139
|
148
|
/*
|
|
@@ -142,12 +151,12 @@ static void vring_disable_cb(int queue_index)
|
142
|
151
|
* put at the begin of the free list the current desc[head]
|
143
|
152
|
*/
|
144
|
153
|
|
145
|
|
-static void vring_detach(int queue_index, unsigned int head)
|
|
154
|
+static void vring_detach(struct vring_virtqueue *vq, unsigned int head)
|
146
|
155
|
{
|
147
|
|
- struct vring *vr = &vring[queue_index];
|
148
|
|
- unsigned int i;
|
|
156
|
+ struct vring *vr = &vq->vring;
|
|
157
|
+ unsigned int i;
|
149
|
158
|
|
150
|
|
- /* find end of given descriptor */
|
|
159
|
+ /* find end of given descriptor */
|
151
|
160
|
|
152
|
161
|
i = head;
|
153
|
162
|
while (vr->desc[i].flags & VRING_DESC_F_NEXT)
|
|
@@ -155,9 +164,9 @@ static void vring_detach(int queue_index, unsigned int head)
|
155
|
164
|
|
156
|
165
|
/* link it with free list and point to it */
|
157
|
166
|
|
158
|
|
- vr->desc[i].next = free_head[queue_index];
|
|
167
|
+ vr->desc[i].next = vq->free_head;
|
159
|
168
|
wmb();
|
160
|
|
- free_head[queue_index] = head;
|
|
169
|
+ vq->free_head = head;
|
161
|
170
|
}
|
162
|
171
|
|
163
|
172
|
/*
|
|
@@ -167,10 +176,10 @@ static void vring_detach(int queue_index, unsigned int head)
|
167
|
176
|
*
|
168
|
177
|
*/
|
169
|
178
|
|
170
|
|
-static inline int vring_more_used(int queue_index)
|
|
179
|
+static inline int vring_more_used(struct vring_virtqueue *vq)
|
171
|
180
|
{
|
172
|
181
|
wmb();
|
173
|
|
- return last_used_idx[queue_index] != vring[queue_index].used->idx;
|
|
182
|
+ return vq->last_used_idx != vq->vring.used->idx;
|
174
|
183
|
}
|
175
|
184
|
|
176
|
185
|
/*
|
|
@@ -180,43 +189,42 @@ static inline int vring_more_used(int queue_index)
|
180
|
189
|
*
|
181
|
190
|
*/
|
182
|
191
|
|
183
|
|
-static int vring_get_buf(int queue_index, unsigned int *len)
|
|
192
|
+static int vring_get_buf(struct vring_virtqueue *vq, unsigned int *len)
|
184
|
193
|
{
|
185
|
|
- struct vring *vr = &vring[queue_index];
|
|
194
|
+ struct vring *vr = &vq->vring;
|
186
|
195
|
struct vring_used_elem *elem;
|
187
|
196
|
u32 id;
|
188
|
197
|
int ret;
|
189
|
198
|
|
190
|
|
- BUG_ON(!vring_more_used(queue_index));
|
|
199
|
+ BUG_ON(!vring_more_used(vq));
|
191
|
200
|
|
192
|
|
- elem = &vr->used->ring[last_used_idx[queue_index] % vr->num];
|
|
201
|
+ elem = &vr->used->ring[vq->last_used_idx % vr->num];
|
193
|
202
|
wmb();
|
194
|
203
|
id = elem->id;
|
195
|
204
|
if (len != NULL)
|
196
|
205
|
*len = elem->len;
|
197
|
206
|
|
198
|
|
- ret = vdata[queue_index][id];
|
|
207
|
+ ret = vq->vdata[id];
|
199
|
208
|
|
200
|
|
- vring_detach(queue_index, id);
|
|
209
|
+ vring_detach(vq, id);
|
201
|
210
|
|
202
|
|
- last_used_idx[queue_index]++;
|
|
211
|
+ vq->last_used_idx++;
|
203
|
212
|
|
204
|
213
|
return ret;
|
205
|
214
|
}
|
206
|
215
|
|
207
|
|
-static void vring_add_buf(int queue_index,
|
|
216
|
+static void vring_add_buf(struct vring_virtqueue *vq,
|
208
|
217
|
struct vring_list list[],
|
209
|
218
|
unsigned int out, unsigned int in,
|
210
|
219
|
int index, int num_added)
|
211
|
220
|
{
|
212
|
|
- struct vring *vr = &vring[queue_index];
|
|
221
|
+ struct vring *vr = &vq->vring;
|
213
|
222
|
int i, avail, head, prev;
|
214
|
223
|
|
215
|
|
- BUG_ON(queue_index >= QUEUE_NB);
|
216
|
224
|
BUG_ON(out + in == 0);
|
217
|
225
|
|
218
|
226
|
prev = 0;
|
219
|
|
- head = free_head[queue_index];
|
|
227
|
+ head = vq->free_head;
|
220
|
228
|
for (i = head; out; i = vr->desc[i].next, out--) {
|
221
|
229
|
|
222
|
230
|
vr->desc[i].flags = VRING_DESC_F_NEXT;
|
|
@@ -235,25 +243,26 @@ static void vring_add_buf(int queue_index,
|
235
|
243
|
}
|
236
|
244
|
vr->desc[prev].flags &= ~VRING_DESC_F_NEXT;
|
237
|
245
|
|
238
|
|
- free_head[queue_index] = i;
|
|
246
|
+ vq->free_head = i;
|
239
|
247
|
|
240
|
|
- vdata[queue_index][head] = index;
|
|
248
|
+ vq->vdata[head] = index;
|
241
|
249
|
|
242
|
250
|
avail = (vr->avail->idx + num_added) % vr->num;
|
243
|
251
|
vr->avail->ring[avail] = head;
|
244
|
252
|
wmb();
|
245
|
253
|
}
|
246
|
254
|
|
247
|
|
-static void vring_kick(struct nic *nic, int queue_index, int num_added)
|
|
255
|
+static void vring_kick(struct nic *nic, struct vring_virtqueue *vq,
|
|
256
|
+ int num_added)
|
248
|
257
|
{
|
249
|
|
- struct vring *vr = &vring[queue_index];
|
|
258
|
+ struct vring *vr = &vq->vring;
|
250
|
259
|
|
251
|
260
|
wmb();
|
252
|
261
|
vr->avail->idx += num_added;
|
253
|
262
|
|
254
|
263
|
mb();
|
255
|
264
|
if (!(vr->used->flags & VRING_USED_F_NO_NOTIFY))
|
256
|
|
- vp_notify(nic->ioaddr, queue_index);
|
|
265
|
+ vp_notify(nic->ioaddr, vq->queue_index);
|
257
|
266
|
}
|
258
|
267
|
|
259
|
268
|
/*
|
|
@@ -268,7 +277,7 @@ static void virtnet_disable(struct nic *nic)
|
268
|
277
|
int i;
|
269
|
278
|
|
270
|
279
|
for (i = 0; i < QUEUE_NB; i++) {
|
271
|
|
- vring_disable_cb(i);
|
|
280
|
+ vring_disable_cb(&virtqueue[i]);
|
272
|
281
|
vp_del_vq(nic->ioaddr, i);
|
273
|
282
|
}
|
274
|
283
|
vp_reset(nic->ioaddr);
|
|
@@ -292,13 +301,13 @@ static int virtnet_poll(struct nic *nic, int retrieve)
|
292
|
301
|
struct virtio_net_hdr *hdr;
|
293
|
302
|
struct vring_list list[2];
|
294
|
303
|
|
295
|
|
- if (!vring_more_used(RX_INDEX))
|
|
304
|
+ if (!vring_more_used(&virtqueue[RX_INDEX]))
|
296
|
305
|
return 0;
|
297
|
306
|
|
298
|
307
|
if (!retrieve)
|
299
|
308
|
return 1;
|
300
|
309
|
|
301
|
|
- token = vring_get_buf(RX_INDEX, &len);
|
|
310
|
+ token = vring_get_buf(&virtqueue[RX_INDEX], &len);
|
302
|
311
|
|
303
|
312
|
BUG_ON(len > sizeof(struct virtio_net_hdr) + ETH_FRAME_LEN);
|
304
|
313
|
|
|
@@ -315,8 +324,8 @@ static int virtnet_poll(struct nic *nic, int retrieve)
|
315
|
324
|
list[1].addr = (char*)&rx_buffer[token];
|
316
|
325
|
list[1].length = ETH_FRAME_LEN;
|
317
|
326
|
|
318
|
|
- vring_add_buf(RX_INDEX, list, 0, 2, token, 0);
|
319
|
|
- vring_kick(nic, RX_INDEX, 1);
|
|
327
|
+ vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, token, 0);
|
|
328
|
+ vring_kick(nic, &virtqueue[RX_INDEX], 1);
|
320
|
329
|
|
321
|
330
|
return 1;
|
322
|
331
|
}
|
|
@@ -362,9 +371,9 @@ static void virtnet_transmit(struct nic *nic, const char *destaddr,
|
362
|
371
|
list[1].addr = (char*)&tx_eth_frame;
|
363
|
372
|
list[1].length = ETH_FRAME_LEN;
|
364
|
373
|
|
365
|
|
- vring_add_buf(TX_INDEX, list, 2, 0, 0, 0);
|
|
374
|
+ vring_add_buf(&virtqueue[TX_INDEX], list, 2, 0, 0, 0);
|
366
|
375
|
|
367
|
|
- vring_kick(nic, TX_INDEX, 1);
|
|
376
|
+ vring_kick(nic, &virtqueue[TX_INDEX], 1);
|
368
|
377
|
|
369
|
378
|
/*
|
370
|
379
|
* http://www.etherboot.org/wiki/dev/devmanual
|
|
@@ -373,26 +382,26 @@ static void virtnet_transmit(struct nic *nic, const char *destaddr,
|
373
|
382
|
* before returning from this routine"
|
374
|
383
|
*/
|
375
|
384
|
|
376
|
|
- while (!vring_more_used(TX_INDEX)) {
|
|
385
|
+ while (!vring_more_used(&virtqueue[TX_INDEX])) {
|
377
|
386
|
mb();
|
378
|
387
|
udelay(10);
|
379
|
388
|
}
|
380
|
389
|
|
381
|
390
|
/* free desc */
|
382
|
391
|
|
383
|
|
- (void)vring_get_buf(TX_INDEX, NULL);
|
|
392
|
+ (void)vring_get_buf(&virtqueue[TX_INDEX], NULL);
|
384
|
393
|
}
|
385
|
394
|
|
386
|
395
|
static void virtnet_irq(struct nic *nic __unused, irq_action_t action)
|
387
|
396
|
{
|
388
|
397
|
switch ( action ) {
|
389
|
398
|
case DISABLE :
|
390
|
|
- vring_disable_cb(RX_INDEX);
|
391
|
|
- vring_disable_cb(TX_INDEX);
|
|
399
|
+ vring_disable_cb(&virtqueue[RX_INDEX]);
|
|
400
|
+ vring_disable_cb(&virtqueue[TX_INDEX]);
|
392
|
401
|
break;
|
393
|
402
|
case ENABLE :
|
394
|
|
- vring_enable_cb(RX_INDEX);
|
395
|
|
- vring_enable_cb(TX_INDEX);
|
|
403
|
+ vring_enable_cb(&virtqueue[RX_INDEX]);
|
|
404
|
+ vring_enable_cb(&virtqueue[TX_INDEX]);
|
396
|
405
|
break;
|
397
|
406
|
case FORCE :
|
398
|
407
|
break;
|
|
@@ -409,12 +418,12 @@ static void provide_buffers(struct nic *nic)
|
409
|
418
|
list[0].length = sizeof(struct virtio_net_hdr);
|
410
|
419
|
list[1].addr = (char*)&rx_buffer[i];
|
411
|
420
|
list[1].length = ETH_FRAME_LEN;
|
412
|
|
- vring_add_buf(RX_INDEX, list, 0, 2, i, i);
|
|
421
|
+ vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, i, i);
|
413
|
422
|
}
|
414
|
423
|
|
415
|
424
|
/* nofify */
|
416
|
425
|
|
417
|
|
- vring_kick(nic, RX_INDEX, i);
|
|
426
|
+ vring_kick(nic, &virtqueue[RX_INDEX], i);
|
418
|
427
|
}
|
419
|
428
|
|
420
|
429
|
static struct nic_operations virtnet_operations = {
|
|
@@ -464,10 +473,10 @@ static int virtnet_probe(struct nic *nic, struct pci_device *pci)
|
464
|
473
|
/* initialize emit/receive queue */
|
465
|
474
|
|
466
|
475
|
for (i = 0; i < QUEUE_NB; i++) {
|
467
|
|
- free_head[i] = 0;
|
468
|
|
- last_used_idx[i] = 0;
|
469
|
|
- memset((char*)&queue[i], 0, sizeof(queue[i]));
|
470
|
|
- if (vp_find_vq(nic->ioaddr, i) == -1)
|
|
476
|
+ virtqueue[i].free_head = 0;
|
|
477
|
+ virtqueue[i].last_used_idx = 0;
|
|
478
|
+ memset((char*)&virtqueue[i].queue, 0, sizeof(virtqueue[i].queue));
|
|
479
|
+ if (vp_find_vq(nic->ioaddr, i, &virtqueue[i]) == -1)
|
471
|
480
|
printf("Cannot register queue #%d\n", i);
|
472
|
481
|
}
|
473
|
482
|
|