Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


All updates on the VNET during summer
[palacios.git] / palacios / src / devices / lnx_virtio_nic.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2010, Lei Xia <lxia@northwestern.edu>
11  * Copyright (c) 2010, Cui Zheng <cuizheng@cs.unm.edu>
12  * Copyright (c) 2010, The V3VEE Project <http://www.v3vee.org> 
13  * All rights reserved.
14  *
15  * Author: Lei Xia <lxia@northwestern.edu>
16  *         Cui Zheng <cuizheng@cs.unm.edu>
17  *               
18  *
19  * This is free software.  You are permitted to use,
20  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
21  */
22  
23 #include <palacios/vmm.h>
24 #include <palacios/vmm_dev_mgr.h>
25 #include <devices/lnx_virtio_pci.h>
26 #include <palacios/vm_guest_mem.h>
27 #include <palacios/vmm_sprintf.h>
28 #include <palacios/vmm_vnet.h>
29 #include <palacios/vmm_lock.h>
30 #include <palacios/vmm_util.h>
31 #include <devices/pci.h>
32
33
34 #ifndef CONFIG_DEBUG_VIRTIO_NET
35 #undef PrintDebug
36 #define PrintDebug(fmt, args...)
37 #endif
38
39 #define VIRTIO_NET_S_LINK_UP    1       /* Link is up */
40 #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
41
42 struct virtio_net_hdr {
43         uint8_t flags;
44
45 #define VIRTIO_NET_HDR_GSO_NONE         0       /* Not a GSO frame */
46         uint8_t gso_type;
47         uint16_t hdr_len;               /* Ethernet + IP + tcp/udp hdrs */
48         uint16_t gso_size;              /* Bytes to append to hdr_len per frame */
49         uint16_t csum_start;            /* Position to start checksumming from */
50         uint16_t csum_offset;           /* Offset after that to place checksum */
51 }__attribute__((packed));
52
53
54 /* This is the version of the header to use when the MRG_RXBUF
55  * feature has been negotiated. */
56 struct virtio_net_hdr_mrg_rxbuf {
57         struct virtio_net_hdr hdr;
58         uint16_t num_buffers;   /* Number of merged rx buffers */
59 };
60
61         
62 #define TX_QUEUE_SIZE 64
63 #define RX_QUEUE_SIZE 1024
64 #define CTRL_QUEUE_SIZE 64
65 #define ETH_ALEN 6
66
67 #define VIRTIO_NET_F_MRG_RXBUF  15      /* Host can merge receive buffers. */
68 #define VIRTIO_NET_F_MAC        5       /* Host has given MAC address. */
69 #define VIRTIO_NET_F_GSO        6       /* Host handles pkts w/ any GSO type */
70 #define VIRTIO_NET_F_HOST_TSO4  11      /* Host can handle TSOv4 in. */
71
72 struct virtio_net_config
73 {
74     uint8_t mac[ETH_ALEN];      /* VIRTIO_NET_F_MAC */
75     uint16_t status;
76 } __attribute__((packed));
77
78 struct virtio_dev_state {
79     struct vm_device * pci_bus;
80     struct list_head dev_list;
81     struct v3_vm_info *vm;
82 };
83
84 struct virtio_net_state {
85     struct virtio_net_config net_cfg;
86     struct virtio_config virtio_cfg;
87
88     struct vm_device * dev;
89     struct pci_device * pci_dev; 
90     int io_range_size;
91     
92     struct virtio_queue rx_vq;          /* idx 0, pkts to guest */
93     struct virtio_queue tx_vq;          /* idx 1, pkts from guest */
94     struct virtio_queue ctrl_vq;        /* idx 2 */
95
96     int buffed_rx;
97     int tx_disabled;                    /* stop TX pkts from guest */
98     uint16_t cur_notify_tx_idx;         /*for used in update_tx_queue */
99
100     uint64_t pkt_sent, pkt_recv, pkt_drop;
101     uint64_t tx_stop_times, rx_stop_times, tx_poll_times, rx_ipi_num;
102
103     struct v3_dev_net_ops * net_ops;
104     v3_lock_t rx_lock, tx_lock;
105
106     void * backend_data;
107     struct virtio_dev_state * virtio_dev;
108     struct list_head dev_link;
109 };
110
111 /* virtio nic error type */
112 #define ERR_VIRTIO_OTHER  1
113 #define ERR_VIRTIO_RXQ_FULL  2
114 #define ERR_VIRTIO_RXQ_NOSET  3
115 #define ERR_VIRTIO_TXQ_NOSET 4
116 #define ERR_VIRTIO_TXQ_FULL 5
117 #define ERR_VIRTIO_TXQ_DISABLED 6
118
119
120 static int virtio_free(struct vm_device * dev) 
121 {
122         
123     return 0;
124 }
125
126 static int virtio_init_state(struct virtio_net_state * virtio) 
127 {
128     virtio->rx_vq.queue_size = RX_QUEUE_SIZE;
129     virtio->tx_vq.queue_size = TX_QUEUE_SIZE;
130     virtio->ctrl_vq.queue_size = CTRL_QUEUE_SIZE;
131
132     virtio->rx_vq.ring_desc_addr = 0;
133     virtio->rx_vq.ring_avail_addr = 0;
134     virtio->rx_vq.ring_used_addr = 0;
135     virtio->rx_vq.pfn = 0;
136     virtio->rx_vq.cur_avail_idx = 0;
137
138     virtio->tx_vq.ring_desc_addr = 0;
139     virtio->tx_vq.ring_avail_addr = 0;
140     virtio->tx_vq.ring_used_addr = 0;
141     virtio->tx_vq.pfn = 0;
142     virtio->tx_vq.cur_avail_idx = 0;
143
144     virtio->ctrl_vq.ring_desc_addr = 0;
145     virtio->ctrl_vq.ring_avail_addr = 0;
146     virtio->ctrl_vq.ring_used_addr = 0;
147     virtio->ctrl_vq.pfn = 0;
148     virtio->ctrl_vq.cur_avail_idx = 0;
149
150     virtio->virtio_cfg.pci_isr = 0;
151         
152     virtio->virtio_cfg.host_features = 0; // (1 << VIRTIO_NET_F_MAC);
153
154     if ((v3_lock_init(&(virtio->rx_lock)) == -1) ||
155           (v3_lock_init(&(virtio->tx_lock)) == -1)){
156         PrintError("Virtio NIC: Failure to init locks for net_state\n");
157     }
158
159     virtio->pkt_sent = virtio->pkt_recv = virtio->pkt_drop = 0;
160     virtio->buffed_rx = 0;
161
162     return 0;
163 }
164
165 static int pkt_tx(struct guest_info *core, struct virtio_net_state * virtio, struct vring_desc * buf_desc) 
166 {
167     uint8_t * buf = NULL;
168     uint32_t len = buf_desc->length;
169
170     if (v3_gpa_to_hva(core, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
171         PrintError("Could not translate buffer address\n");
172         return -ERR_VIRTIO_OTHER;
173     }
174
175     return virtio->net_ops->send(buf, len, virtio->backend_data, NULL);
176 }
177
178
179 static int copy_data_to_desc(struct guest_info *core, 
180                                         struct virtio_net_state * virtio_state, 
181                                         struct vring_desc * desc, 
182                                         uchar_t * buf, 
183                                         uint_t buf_len,
184                                         uint_t offset)
185 {
186     uint32_t len;
187     uint8_t * desc_buf = NULL;
188
189     if (v3_gpa_to_hva(core, desc->addr_gpa, (addr_t *)&(desc_buf)) == -1) {
190         PrintError("Could not translate buffer address\n");
191         return -1;
192     }
193     len = (desc->length < buf_len)?(desc->length - offset):buf_len;
194     memcpy(desc_buf+offset, buf, len);
195
196     return len;
197 }
198
199
200 static int get_desc_count(struct virtio_queue * q, int index) {
201     struct vring_desc * tmp_desc = &(q->desc[index]);
202     int cnt = 1;
203     
204     while (tmp_desc->flags & VIRTIO_NEXT_FLAG) {
205         tmp_desc = &(q->desc[tmp_desc->next]);
206         cnt++;
207     }
208
209     return cnt;
210 }
211
212 static inline void enable_cb(struct virtio_queue *queue){
213     queue->used->flags &= ~ VRING_NO_NOTIFY_FLAG;
214 }
215
216 static inline void disable_cb(struct virtio_queue *queue) {
217     queue->used->flags |= VRING_NO_NOTIFY_FLAG;
218 }
219
220 /* interrupt the guest, so the guest core get EXIT to Palacios
221  * this happens when there are either incoming pkts for the guest
222  * or the guest can start TX pkts again */
223 static inline void notify_guest(struct virtio_net_state * virtio){
224     v3_interrupt_cpu(virtio->virtio_dev->vm, virtio->virtio_dev->vm->cores[0].cpu_id, 0);
225 }
226
227
228 /* guest free some pkts from rx queue */
229 static int handle_rx_kick(struct guest_info *core, struct virtio_net_state * virtio) 
230 {
231     unsigned long flags;
232
233     flags = v3_lock_irqsave(virtio->rx_lock);
234
235     virtio->net_ops->start_rx(virtio->backend_data);
236     disable_cb(&virtio->rx_vq);
237
238     v3_unlock_irqrestore(virtio->rx_lock, flags);
239         
240     return 0;
241 }
242
243 #ifdef CONFIG_VNET_PROFILE
244 static void print_profile_info(struct virtio_net_state *virtio){
245     PrintError("Virtio NIC: %p,  sent: %lld, rxed: %lld, dropped: %lld, \
246                         tx_stop: %lld, rx_stop: %lld, poll_time: %lld, rx_ipi: %lld\n",
247                         virtio,
248                         virtio->pkt_sent,
249                         virtio->pkt_recv,
250                         virtio->pkt_drop, 
251                         virtio->tx_stop_times,
252                         virtio->rx_stop_times,
253                         virtio->tx_poll_times,
254                         virtio->rx_ipi_num);
255 }
256 #endif
257
258 static int handle_ctrl(struct guest_info *core, struct virtio_net_state * virtio) {
259         
260     return 0;
261 }
262
263 static int handle_pkt_tx(struct guest_info *core, struct virtio_net_state * virtio_state) 
264 {
265     struct virtio_queue * q = &(virtio_state->tx_vq);
266     struct virtio_net_hdr * hdr = NULL;
267     int recved = 0;
268     unsigned long flags;
269
270     if (!q->ring_avail_addr) 
271         return -ERR_VIRTIO_TXQ_NOSET;
272
273     if(virtio_state->tx_disabled)
274         return -ERR_VIRTIO_TXQ_DISABLED;
275
276     flags = v3_lock_irqsave(virtio_state->tx_lock);
277     while (q->cur_avail_idx != q->avail->index) {
278         struct vring_desc * hdr_desc = NULL;
279         addr_t hdr_addr = 0;
280         uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
281         int desc_cnt = get_desc_count(q, desc_idx);
282         uint32_t req_len = 0;
283         int i = 0;
284
285         hdr_desc = &(q->desc[desc_idx]);
286         if (v3_gpa_to_hva(core, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
287             PrintError("Could not translate block header address\n");
288             goto exit_error;
289         }
290
291         hdr = (struct virtio_net_hdr*)hdr_addr;
292         desc_idx = hdr_desc->next;
293
294         if(desc_cnt > 2){
295             PrintError("VNIC: merged rx buffer not supported\n");
296             goto exit_error;
297         }
298
299         /* here we assumed that one ethernet pkt is not splitted into multiple virtio buffer */
300         for (i = 0; i < desc_cnt - 1; i++) {    
301             struct vring_desc * buf_desc = &(q->desc[desc_idx]);
302             if (pkt_tx(core, virtio_state, buf_desc) == -1) {
303                 PrintError("Error handling nic operation\n");
304                 goto exit_error;
305             }
306
307             req_len += buf_desc->length;
308             desc_idx = buf_desc->next;
309         }
310         virtio_state->pkt_sent ++;
311         recved ++;
312
313         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
314         q->used->ring[q->used->index % q->queue_size].length = req_len; // What do we set this to????
315         q->used->index ++;
316         
317         q->cur_avail_idx ++;
318     }
319
320     v3_unlock_irqrestore(virtio_state->tx_lock, flags);
321
322     if(!recved)
323         return 0;
324         
325     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
326         v3_pci_raise_irq(virtio_state->virtio_dev->pci_bus, 0, virtio_state->pci_dev);
327         virtio_state->virtio_cfg.pci_isr = 0x1;
328     }
329
330
331 #ifdef CONFIG_VNET_PROFILE
332         static long min = 1024, max = 0, total=0;
333         static int i=0;
334         total += recved;
335         i ++;
336         if(recved > max) max = recved;
337         if(recved < min) min = recved;
338         if(total > 100000) {
339                 PrintError("VNIC: TX polling: %ld, min %ld, max %ld, avg: %ld pkts\n", total, min, max, total/i);
340                 min = 1024;
341                 max = 0;
342                 i = 1; 
343                 total = 0;
344         }
345 #endif
346
347
348     return 0;
349
350 exit_error:
351         
352     v3_unlock_irqrestore(virtio_state->tx_lock, flags);
353     return -ERR_VIRTIO_OTHER;
354 }
355
356
357 #if 0 //for multicore VNET
358 /* used for poll pkt from virtio nic by VNET
359  * only when vnet is running on sidecore */
360 static int handle_pkt_tx_sidecore(struct guest_info *core, struct virtio_net_state * virtio) 
361 {
362     struct virtio_queue * q = &(virtio->tx_vq);
363     struct virtio_net_hdr * hdr = NULL;
364     int recved = 0;
365     unsigned long flags;
366
367     if (!q->ring_avail_addr) {
368         return -ERR_VIRTIO_TXQ_NOSET;
369     }
370
371     flags = v3_lock_irqsave(virtio->tx_lock);
372
373     while (q->cur_avail_idx != q->avail->index) {
374         struct vring_desc * hdr_desc = NULL;
375         addr_t hdr_addr = 0;
376         uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
377         int desc_cnt = get_desc_count(q, desc_idx);
378         uint32_t req_len = 0;
379         int i = 0;
380
381         hdr_desc = &(q->desc[desc_idx]);
382         if (v3_gpa_to_hva(core, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
383             PrintError("Could not translate block header address\n");
384             goto exit_error;
385         }
386
387         hdr = (struct virtio_net_hdr*)hdr_addr;
388         desc_idx = hdr_desc->next;
389
390         if(desc_cnt > 2){
391             PrintError("VNIC: merged rx buffer not supported\n");
392             goto exit_error;
393         }
394
395         for (i = 0; i < desc_cnt - 1; i++) {    
396             struct vring_desc * buf_desc = &(q->desc[desc_idx]);
397             if (pkt_tx_sidecore(core, virtio, buf_desc) < 0) {
398                 PrintError("Error handling nic operation\n");
399                 goto exit_error;
400             }
401
402             req_len += buf_desc->length;
403             desc_idx = buf_desc->next;
404         }
405         recved ++;
406         
407         q->cur_avail_idx ++;
408     }
409
410     if(recved) PrintDebug("VNIC: Tx polling %d pkts\n", recved);
411         
412     v3_unlock_irqrestore(virtio->tx_lock, flags);
413
414     return 0;
415
416 exit_error:
417         
418     v3_unlock_irqrestore(virtio->tx_lock, flags);
419     return -ERR_VIRTIO_OTHER;
420 }
421
422
423 /* called by VNET, to notify Virtio to update the tx_queue used index 
424  * used only when vnet running on sidecore */
425 static int update_tx_queue(struct virtio_net_state * virtio, int handled_pkt){
426     struct virtio_queue * q = &(virtio->tx_vq);
427     unsigned long flags;
428
429     if (!q->ring_avail_addr) {
430         return -ERR_VIRTIO_TXQ_NOSET;
431     }
432
433     flags = v3_lock_irqsave(virtio->tx_lock);
434     while(handled_pkt > 0){
435         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[virtio->cur_notify_tx_idx % q->queue_size];
436         q->used->ring[q->used->index % q->queue_size].length = req_len; // TODO:
437         q->used->index ++;
438         virtio->cur_notify_tx_idx ++;
439         handled_pkt --;
440     }
441     v3_unlock_irqrestore(virtio->tx_lock, flags);
442
443     if (handled_pkt && (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG))) {
444         v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
445         virtio->virtio_cfg.pci_isr = 0x1;
446
447         /* do we need to notify here? */
448         notify_guest(virtio);
449     }
450
451     virtio->pkt_sent += handled_pkt;
452         
453 #ifdef CONFIG_VNET_PROFILE
454     if (virtio->pkt_sent % 50000 == 0){
455             long cur_time, time;
456             rdtscll(cur_time);
457             time = cur_time - virtio_state->last_sent_time;
458             PrintError("Virtio NIC: last sent 50000 cycles: %ld\n",time);
459             PrintError("Virtio NIC: sent: %ld, rxed: %ld, dropped: %ld\n",
460                         virtio->pkt_sent,
461                         virtio->pkt_recv,
462                         virtio->pkt_drop);
463             rdtscll(virtio->last_sent_time);
464     }
465 #endif
466
467
468     return 0;
469 }
470 #endif
471
472 static int virtio_setup_queue(struct guest_info *core, 
473                                 struct virtio_net_state * virtio_state, 
474                                 struct virtio_queue * queue, 
475                                                         addr_t pfn, 
476                                                         addr_t page_addr) {
477     queue->pfn = pfn;
478                 
479     queue->ring_desc_addr = page_addr;
480     queue->ring_avail_addr = page_addr + (queue->queue_size * sizeof(struct vring_desc));
481     queue->ring_used_addr = ((queue->ring_avail_addr) + 
482                              (sizeof(struct vring_avail)) + 
483                              (queue->queue_size * sizeof(uint16_t)));
484
485     // round up to next page boundary.
486     queue->ring_used_addr = (queue->ring_used_addr + 0xfff) & ~0xfff;
487     if (v3_gpa_to_hva(core, queue->ring_desc_addr, (addr_t *)&(queue->desc)) == -1) {
488         PrintError("Could not translate ring descriptor address\n");
489          return -1;
490     }
491  
492     if (v3_gpa_to_hva(core, queue->ring_avail_addr, (addr_t *)&(queue->avail)) == -1) {
493         PrintError("Could not translate ring available address\n");
494         return -1;
495     }
496
497     if (v3_gpa_to_hva(core, queue->ring_used_addr, (addr_t *)&(queue->used)) == -1) {
498         PrintError("Could not translate ring used address\n");
499         return -1;
500     }
501
502     PrintDebug("RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
503                (void *)(queue->ring_desc_addr),
504                (void *)(queue->ring_avail_addr),
505                (void *)(queue->ring_used_addr));
506     
507     PrintDebug("RingDesc=%p, Avail=%p, Used=%p\n", 
508                queue->desc, queue->avail, queue->used);
509     
510     return 0;
511 }
512
513 static int virtio_io_write(struct guest_info *core, uint16_t port, void * src, uint_t length, void * private_data) 
514 {
515     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
516     int port_idx = port % virtio->io_range_size;
517
518
519     PrintDebug("VIRTIO NIC %p Write for port %d (index=%d) len=%d, value=%x\n", private_data,
520                port, port_idx,  length, *(uint32_t *)src);
521
522     switch (port_idx) {
523         case GUEST_FEATURES_PORT:
524             if (length != 4) {
525                 PrintError("Illegal write length for guest features\n");
526                 return -1;
527             }       
528             virtio->virtio_cfg.guest_features = *(uint32_t *)src;
529             break;
530                 
531         case VRING_PG_NUM_PORT:
532             if (length != 4) {
533                 PrintError("Illegal write length for page frame number\n");
534                 return -1;
535             }
536             addr_t pfn = *(uint32_t *)src;
537             addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
538             uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
539             switch (queue_idx) {
540                 case 0:
541                     virtio_setup_queue(core, virtio, &virtio->rx_vq, pfn, page_addr);
542                     disable_cb(&virtio->rx_vq);
543                     break;
544                 case 1:
545                     virtio_setup_queue(core, virtio, &virtio->tx_vq, pfn, page_addr);
546                     disable_cb(&virtio->tx_vq);
547                     break;
548                 case 2:
549                     virtio_setup_queue(core, virtio, &virtio->ctrl_vq, pfn, page_addr);
550                     break;          
551                 default:
552                     break;
553             }
554             break;
555                 
556         case VRING_Q_SEL_PORT:
557             virtio->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
558             if (virtio->virtio_cfg.vring_queue_selector > 2) {
559                 PrintError("Virtio NIC: wrong queue idx: %d\n", 
560                            virtio->virtio_cfg.vring_queue_selector);
561                 return -1;
562             }
563             break;
564                 
565         case VRING_Q_NOTIFY_PORT: 
566             {
567                 uint16_t queue_idx = *(uint16_t *)src;                  
568                 if (queue_idx == 0){
569                     handle_rx_kick(core, virtio);
570                     PrintError("rx kick\n");
571                 } else if (queue_idx == 1){
572                     PrintError("tx kick\n");
573                     if (handle_pkt_tx(core, virtio) == -1) {
574                         PrintError("Could not handle NIC Notification\n");
575                         return -1;
576                     }
577                 } else if (queue_idx == 2){
578                     if (handle_ctrl(core, virtio) == -1) {
579                         PrintError("Could not handle NIC Notification\n");
580                         return -1;
581                     }
582                 } else {
583                     PrintError("Wrong queue index %d\n", queue_idx);
584                 }       
585                 break;          
586             }
587         
588         case VIRTIO_STATUS_PORT:
589             virtio->virtio_cfg.status = *(uint8_t *)src;
590             if (virtio->virtio_cfg.status == 0) {
591                 PrintDebug("Resetting device\n");
592                 virtio_init_state(virtio);
593             }
594             break;
595
596         case VIRTIO_ISR_PORT:
597             virtio->virtio_cfg.pci_isr = *(uint8_t *)src;
598             break;
599                 
600         default:
601             return -1;
602             break;
603     }
604
605     return length;
606 }
607
608 static int virtio_io_read(struct guest_info *core, uint16_t port, void * dst, uint_t length, void * private_data) 
609 {
610     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
611     int port_idx = port % virtio->io_range_size;
612     uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
613
614     PrintDebug("Virtio NIC %p: Read  for port %d (index =%d), length=%d\n", private_data,
615                port, port_idx, length);
616         
617     switch (port_idx) {
618         case HOST_FEATURES_PORT:
619             if (length != 4) {
620                 PrintError("Illegal read length for host features\n");
621                 return -1;
622             }
623             *(uint32_t *)dst = virtio->virtio_cfg.host_features;
624             break;
625
626         case VRING_PG_NUM_PORT:
627             if (length != 4) {
628                 PrintError("Illegal read length for page frame number\n");
629                 return -1;
630             }
631             switch (queue_idx) {
632                 case 0:
633                     *(uint32_t *)dst = virtio->rx_vq.pfn;
634                     break;
635                 case 1:
636                     *(uint32_t *)dst = virtio->tx_vq.pfn;
637                     break;      
638                 case 2:
639                     *(uint32_t *)dst = virtio->ctrl_vq.pfn;
640                     break;
641                 default:
642                     break;
643             }
644             break;
645
646         case VRING_SIZE_PORT:
647             if (length != 2) {
648                 PrintError("Illegal read length for vring size\n");
649                 return -1;
650             }
651             switch (queue_idx) {
652                 case 0:
653                     *(uint16_t *)dst = virtio->rx_vq.queue_size;
654                     break;
655                 case 1:
656                     *(uint16_t *)dst = virtio->tx_vq.queue_size;
657                     break;      
658                 case 2:
659                     *(uint16_t *)dst = virtio->ctrl_vq.queue_size;
660                     break;
661                 default:
662                     break;
663             }
664             break;
665
666         case VIRTIO_STATUS_PORT:
667             if (length != 1) {
668                 PrintError("Illegal read length for status\n");
669                 return -1;
670             }
671             *(uint8_t *)dst = virtio->virtio_cfg.status;
672             break;
673                 
674         case VIRTIO_ISR_PORT:
675             *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
676             virtio->virtio_cfg.pci_isr = 0;
677             v3_pci_lower_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
678             break;
679
680         default:
681             PrintError("Virtio NIC: Read of Unhandled Virtio Read:%d\n", port_idx);
682             return -1;
683     }
684
685     return length;
686 }
687
688
689 static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
690     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
691     struct virtio_queue * q = &(virtio->rx_vq);
692     struct virtio_net_hdr_mrg_rxbuf hdr;
693     uint32_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
694     uint32_t data_len = size;
695     uint32_t offset = 0;
696     unsigned long flags;
697     int ret_val = -ERR_VIRTIO_OTHER;
698     int raw = 1;
699
700     flags = v3_lock_irqsave(virtio->rx_lock);
701
702     virtio->pkt_recv ++;
703     if (!raw)
704         data_len -= hdr_len;
705
706     if (!raw)
707         memcpy(&hdr, buf, sizeof(struct virtio_net_hdr_mrg_rxbuf));
708     else
709         memset(&hdr, 0, sizeof(struct virtio_net_hdr_mrg_rxbuf));
710
711     if (q->ring_avail_addr == 0) {
712         PrintError("Queue is not set\n");
713         ret_val = -ERR_VIRTIO_RXQ_NOSET;
714         goto exit;
715     }
716
717     if (q->cur_avail_idx != q->avail->index){
718         addr_t hdr_addr = 0;
719         uint16_t hdr_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
720         uint16_t buf_idx = 0;
721         struct vring_desc * hdr_desc = NULL;
722
723         hdr_desc = &(q->desc[hdr_idx]);
724         if (v3_gpa_to_hva(&(virtio->virtio_dev->vm->cores[0]), hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
725             PrintError("Could not translate receive buffer address\n");
726             goto exit;
727         }
728         hdr.num_buffers = 1;
729         memcpy((void *)hdr_addr, &hdr, sizeof(struct virtio_net_hdr_mrg_rxbuf));
730         if (offset >= data_len) {
731             hdr_desc->flags &= ~VIRTIO_NEXT_FLAG;
732         }
733
734         struct vring_desc * buf_desc = NULL;
735         for (buf_idx = hdr_desc->next; offset < data_len; buf_idx = q->desc[hdr_idx].next) {
736             uint32_t len = 0;
737             buf_desc = &(q->desc[buf_idx]);
738
739             len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, buf_desc, buf + offset, data_len - offset, 0);     
740             offset += len;
741             if (offset < data_len) {
742                 buf_desc->flags = VIRTIO_NEXT_FLAG;             
743             }
744             buf_desc->length = len;
745         }
746         buf_desc->flags &= ~VIRTIO_NEXT_FLAG;
747         
748         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
749         q->used->ring[q->used->index % q->queue_size].length = data_len + hdr_len; /* This should be the total length of data sent to guest (header+pkt_data) */
750         q->used->index++;
751         q->cur_avail_idx++;
752
753         /* if there are certain num of pkts in the RX queue, notify guest 
754           * so guest will exit to palacios
755          * when it returns, guest gets the virtio rx interrupt */
756         if((++virtio->buffed_rx > q->queue_size/5) &&
757             (q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
758             if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
759                   notify_guest(virtio);
760                   virtio->rx_ipi_num ++;
761             }
762             virtio->buffed_rx = 0;
763         }
764     } else {
765         virtio->pkt_drop++;
766         /* RX queue is full,  tell backend to stop RX on this device */
767         virtio->net_ops->stop_rx(virtio->backend_data);
768         enable_cb(&virtio->rx_vq);
769
770         virtio->rx_stop_times ++;
771         
772         ret_val = -ERR_VIRTIO_RXQ_FULL;
773         goto exit;
774     }
775
776     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
777         PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
778         v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
779         virtio->virtio_cfg.pci_isr = 0x1;
780     }
781
782     ret_val = offset;
783
784 exit:
785
786     v3_unlock_irqrestore(virtio->rx_lock, flags);
787  
788     return ret_val;
789 }
790
791
792 #if 0 /* for encapuslation */
793 /* virtio RX with encapulation version */
794 static int virtio_rx_encap(uint8_t * data, 
795                                                   uint32_t size, 
796                                                   void * encap_header, 
797                                                   uint16_t encap_len,
798                                                   void * private_data) {
799     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
800     struct virtio_queue * q = &(virtio->rx_vq);
801     struct virtio_net_hdr_mrg_rxbuf hdr;
802     uint32_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
803     uint32_t data_len = size + encap_len;
804     unsigned long flags;
805     int ret_val = -ERR_VIRTIO_OTHER;
806
807     if (q->ring_avail_addr == 0) {
808         PrintError("Queue is not set\n");
809         ret_val = -ERR_VIRTIO_RXQ_NOSET;
810         goto exit;
811     }
812         
813     memset(&hdr, 0, sizeof(struct virtio_net_hdr_mrg_rxbuf));
814
815     flags = v3_lock_irqsave(virtio->rx_lock);
816     if (q->cur_avail_idx != q->avail->index){
817         addr_t hdr_addr = 0;
818         uint16_t hdr_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
819         uint16_t buf_idx = 0;
820         struct vring_desc * hdr_desc = NULL;
821        uint32_t offset = 0;
822
823         hdr_desc = &(q->desc[hdr_idx]);
824         if (guest_pa_to_host_va(&(virtio->virtio_dev->vm->cores[0]), hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
825             PrintError("Could not translate receive buffer address\n");
826             goto exit;
827         }
828         hdr.num_buffers = 1;
829         memcpy((void *)hdr_addr, &hdr, sizeof(struct virtio_net_hdr_mrg_rxbuf));
830         if (offset >= data_len) {
831             hdr_desc->flags &= ~VIRTIO_NEXT_FLAG;
832         }
833
834         struct vring_desc * buf_desc = NULL;
835        uint32_t len = 0;
836         buf_idx = hdr_desc->next;
837        buf_desc = &(q->desc[buf_idx]);
838         
839         if(hdr_len > 0 && !encap_header) {
840             len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, buf_desc, encap_header, encap_len, 0);
841             offset += len;
842         }
843         
844         len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, buf_desc, data + offset, data_len - offset, offset);           
845        offset += len;
846
847         if(data_len < offset)/* if there is large pkt, need merge more buffer */
848             PrintDebug("Virtio NIC: data pkt larger than RX queue buffer\n");
849
850         buf_desc->length = offset;      
851         buf_desc->flags &= ~VIRTIO_NEXT_FLAG;
852         
853         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
854         q->used->ring[q->used->index % q->queue_size].length = data_len + hdr_len; /* This should be the total length of data sent to guest (header+pkt_data) */
855         q->used->index++;
856         q->cur_avail_idx++;
857
858         /* notify guest 
859          * when it returns from EXIT, guest gets the virtio rx interrupt */
860         if((++virtio->buffed_rx > q->queue_size/2) &&
861             (q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
862             if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
863                   notify_guest(virtio);
864             }
865             virtio->buffed_rx = 0;
866         }
867        ret_val = offset;
868     } else {
869         virtio->pkt_drop++;
870         ret_val = -ERR_VIRTIO_RXQ_FULL;
871         goto exit;
872     }
873     virtio->pkt_recv ++;
874
875     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
876         PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
877         v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
878         virtio->virtio_cfg.pci_isr = 0x1;
879     }
880
881 #ifdef CONFIG_VNET_PROFILE
882     if (virtio->pkt_recv % 50000 == 0){
883             long cur_time, time;
884             rdtscll(cur_time);
885             time = cur_time - virtio->last_recv_time;
886             PrintError("Virtio NIC: sent: %ld, rxed: %ld, dropped: %ld\n",
887                 virtio->pkt_sent,
888                 virtio->pkt_recv,
889                 virtio->pkt_drop);
890             rdtscll(virtio->last_recv_time);
891     }
892 #endif
893
894 exit:
895
896     v3_unlock_irqrestore(virtio->rx_lock, flags);
897  
898     return ret_val;
899 }
900 #endif 
901
902
903
904 static struct v3_device_ops dev_ops = {
905     .free = virtio_free,
906     .reset = NULL,
907     .start = NULL,
908     .stop = NULL,
909 };
910
911 #if 0 //temporary hacking LX
912 static struct virtio_net_state *vnic_states[2] = {NULL, NULL};
913 static int num_vnic = 0;
914
915 void vnic_polling(void *data){
916     struct v3_vm_info *info = (struct v3_vm_info *)data;    
917     if(vnic_states[0] != NULL && info == vnic_states[0]->virtio_dev->vm){
918         handle_pkt_tx(&(info->cores[0]), vnic_states[0]);
919     }
920
921     if(vnic_states[1] != NULL && info == vnic_states[1]->virtio_dev->vm){
922         handle_pkt_tx(&(info->cores[0]), vnic_states[1]);
923     }
924 }
925 #endif
926
927 /* TODO: Issue here: which vm info it needs? calling VM or the device's own VM? */
928 static void virtio_nic_poll(struct v3_vm_info *vm, void *data){
929     struct virtio_net_state *virtio = (struct virtio_net_state *)data;
930         
931     handle_pkt_tx(&(vm->cores[0]), virtio);
932
933     virtio->tx_poll_times ++;
934
935 #ifdef CONFIG_VNET_PROFILE
936     static uint64_t last_time = 0;
937     uint64_t time;
938     rdtscll(time);
939     if((time - last_time) > 5000000000){
940         last_time = time;
941        print_profile_info(virtio);
942     }
943 #endif
944 }
945
946 #if 0 /* NAPI */
947 /* tx one pkt from guest */
948 static int virtio_tx_pkt(struct guest_info *core, struct virtio_net_state * virtio_state){
949
950 }
951
952 static void virtio_nic_poll(struct v3_vm_info *vm, void *data, int budget){
953
954
955 }
956
957 #endif
958
959
960 static void virtio_start_tx(void *data){
961     struct virtio_net_state * virtio = (struct virtio_net_state *)data;
962
963     /* do we need a lock here? */
964     virtio->tx_disabled = 0;
965
966     /* notify the device's guest it can start sending pkt */
967     if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
968         notify_guest(virtio);
969     }
970 }
971
972 static void virtio_stop_tx(void *data){
973     struct virtio_net_state * virtio = (struct virtio_net_state *)data;
974
975     /* do we need a lock here? */
976     virtio->tx_disabled = 1;
977
978     /* how do we stop the guest to exit to palacios for sending pkt? */
979     if(virtio->virtio_dev->vm->cores[0].cpu_id != V3_Get_CPU()){
980        disable_cb(&virtio->tx_vq);
981     }
982
983     virtio->tx_stop_times ++;
984 }
985
986         
987
988
989 static int register_dev(struct virtio_dev_state * virtio, struct virtio_net_state * net_state) 
990 {
991     struct pci_device * pci_dev = NULL;
992     struct v3_pci_bar bars[6];
993     int num_ports = sizeof(struct virtio_config);
994     int tmp_ports = num_ports;
995     int i;
996
997     // This gets the number of ports, rounded up to a power of 2
998     net_state->io_range_size = 1; // must be a power of 2
999     while (tmp_ports > 0) {
1000         tmp_ports >>= 1;
1001         net_state->io_range_size <<= 1;
1002     }
1003         
1004     // this is to account for any low order bits being set in num_ports
1005     // if there are none, then num_ports was already a power of 2 so we shift right to reset it
1006     if ((num_ports & ((net_state->io_range_size >> 1) - 1)) == 0) {
1007         net_state->io_range_size >>= 1;
1008     }
1009     
1010     for (i = 0; i < 6; i++) {
1011         bars[i].type = PCI_BAR_NONE;
1012     }
1013     
1014     PrintDebug("Virtio-NIC io_range_size = %d\n", net_state->io_range_size);
1015     
1016     bars[0].type = PCI_BAR_IO;
1017     bars[0].default_base_port = -1;
1018     bars[0].num_ports = net_state->io_range_size;
1019     bars[0].io_read = virtio_io_read;
1020     bars[0].io_write = virtio_io_write;
1021     bars[0].private_data = net_state;
1022     
1023     pci_dev = v3_pci_register_device(virtio->pci_bus, PCI_STD_DEVICE, 
1024                                      0, 4/*PCI_AUTO_DEV_NUM*/, 0,
1025                                      "LNX_VIRTIO_NIC", bars,
1026                                      NULL, NULL, NULL, net_state);
1027     
1028     if (!pci_dev) {
1029         PrintError("Virtio NIC: Could not register PCI Device\n");
1030         return -1;
1031     }
1032
1033     PrintDebug("Virtio NIC:  registered to PCI bus\n");
1034     
1035     pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
1036     pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
1037         
1038
1039     pci_dev->config_header.device_id = VIRTIO_NET_DEV_ID;
1040     pci_dev->config_header.class = PCI_CLASS_NETWORK;
1041     pci_dev->config_header.subclass = PCI_NET_SUBCLASS_OTHER;  
1042     pci_dev->config_header.subsystem_id = VIRTIO_NET_SUBDEVICE_ID;
1043     pci_dev->config_header.intr_pin = 1;
1044     pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
1045
1046     net_state->pci_dev = pci_dev;
1047     net_state->virtio_dev = virtio;
1048
1049     uchar_t mac[6] = {0x11,0x11,0x11,0x11,0x11,0x11};
1050     memcpy(net_state->net_cfg.mac, mac, 6);
1051                                                                                                            
1052     memcpy(pci_dev->config_data, net_state->net_cfg.mac, ETH_ALEN);
1053     
1054     virtio_init_state(net_state);
1055
1056 #if 0 //temporary hacking LX
1057     vnic_states[num_vnic ++] = net_state;
1058     PrintError("VNIC: num of vnic %d\n", num_vnic);
1059 #endif
1060
1061     return 0;
1062 }
1063
1064 static int connect_fn(struct v3_vm_info * info, 
1065                       void * frontend_data, 
1066                       struct v3_dev_net_ops * ops, 
1067                       v3_cfg_tree_t * cfg, 
1068                       void * private_data) {
1069     struct virtio_dev_state * virtio = (struct virtio_dev_state *)frontend_data;
1070     struct virtio_net_state * net_state  = (struct virtio_net_state *)V3_Malloc(sizeof(struct virtio_net_state));
1071
1072     memset(net_state, 0, sizeof(struct virtio_net_state));
1073     register_dev(virtio, net_state);
1074
1075     net_state->net_ops = ops;
1076     net_state->backend_data = private_data;
1077
1078     ops->recv = virtio_rx;
1079     ops->poll = virtio_nic_poll;
1080     ops->start_tx = virtio_start_tx;
1081     ops->stop_tx = virtio_stop_tx;
1082     ops->frontend_data = net_state;
1083
1084     return 0;
1085 }
1086
1087 static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
1088     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
1089     struct virtio_dev_state * virtio_state = NULL;
1090     char * name = v3_cfg_val(cfg, "name");
1091
1092     PrintDebug("Virtio NIC: Initializing VIRTIO Network device: %s\n", name);
1093
1094     if (pci_bus == NULL) {
1095         PrintError("Virtio NIC: VirtIO devices require a PCI Bus");
1096         return -1;
1097     }
1098
1099     virtio_state  = (struct virtio_dev_state *)V3_Malloc(sizeof(struct virtio_dev_state));
1100     memset(virtio_state, 0, sizeof(struct virtio_dev_state));
1101
1102     INIT_LIST_HEAD(&(virtio_state->dev_list));
1103     virtio_state->pci_bus = pci_bus;
1104     virtio_state->vm = vm;
1105
1106     struct vm_device * dev = v3_allocate_device(name, &dev_ops, virtio_state);
1107     if (v3_attach_device(vm, dev) == -1) {
1108         PrintError("Virtio NIC: Could not attach device %s\n", name);
1109         return -1;
1110     }
1111
1112     if (v3_dev_add_net_frontend(vm, name, connect_fn, (void *)virtio_state) == -1) {
1113         PrintError("Virtio NIC: Could not register %s as net frontend\n", name);
1114         return -1;
1115     }
1116         
1117     return 0;
1118 }
1119
1120 device_register("LNX_VIRTIO_NIC", virtio_init)
1121