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.


Fix to VMM/Guest model dynamic switch for Virtio NIC
[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 #include <palacios/vmm_ethernet.h>
33 #include <palacios/vmm_time.h>
34
35
36 #ifndef CONFIG_DEBUG_VIRTIO_NET
37 #undef PrintDebug
38 #define PrintDebug(fmt, args...)
39 #endif
40
41 #define VIRTIO_NET_MAX_BUFSIZE (sizeof(struct virtio_net_hdr) + (64 << 10))
42
43
44 struct virtio_net_hdr {
45         uint8_t flags;
46         
47         uint8_t gso_type;
48         uint16_t hdr_len;               /* Ethernet + IP + tcp/udp hdrs */
49         uint16_t gso_size;              /* Bytes to append to hdr_len per frame */
50         uint16_t csum_start;            /* Position to start checksumming from */
51         uint16_t csum_offset;           /* Offset after that to place checksum */
52 }__attribute__((packed));
53
54
55 struct virtio_net_hdr_mrg_rxbuf {
56         struct virtio_net_hdr hdr;
57         uint16_t num_buffers;   /* Number of merged rx buffers */
58 };
59
60         
61 #define TX_QUEUE_SIZE 256
62 #define RX_QUEUE_SIZE 4096
63 #define CTRL_QUEUE_SIZE 64
64
65 #define VIRTIO_NET_F_MRG_RXBUF  15      /* Host can merge receive buffers. */
66 #define VIRTIO_NET_F_MAC        5       /* Host has given MAC address. */
67 #define VIRTIO_NET_F_GSO        6       /* Host handles pkts w/ any GSO type */
68 #define VIRTIO_NET_F_HOST_TSO4  11      /* Host can handle TSOv4 in. */
69 #define VIRTIO_NET_F_HOST_UFO   14      /* Host can handle UFO in. */
70
71 /* Port to get virtio config */
72 #define VIRTIO_NET_CONFIG 20  
73
74 struct virtio_net_config
75 {
76     uint8_t mac[ETH_ALEN];      /* VIRTIO_NET_F_MAC */
77     uint16_t status;
78 } __attribute__((packed));
79
80 struct virtio_dev_state {
81     struct vm_device * pci_bus;
82     struct list_head dev_list;
83     struct v3_vm_info *vm;
84
85     uint8_t mac[ETH_ALEN];
86 };
87
88 struct virtio_net_state {
89     struct virtio_net_config net_cfg;
90     struct virtio_config virtio_cfg;
91
92     struct vm_device * dev;
93     struct pci_device * pci_dev; 
94     int io_range_size;
95     
96     struct virtio_queue rx_vq;          /* idx 0*/
97     struct virtio_queue tx_vq;          /* idx 1*/
98     struct virtio_queue ctrl_vq;        /* idx 2*/
99
100     struct v3_timer * timer;
101
102     struct nic_statistics statistics;
103
104     struct v3_dev_net_ops * net_ops;
105     v3_lock_t rx_lock, tx_lock;
106
107     uint8_t tx_notify, rx_notify;
108     uint32_t tx_pkts, rx_pkts;
109     uint64_t past_ms;
110
111     void * backend_data;
112     struct virtio_dev_state * virtio_dev;
113     struct list_head dev_link;
114 };
115
116 static int virtio_init_state(struct virtio_net_state * virtio) 
117 {
118     virtio->rx_vq.queue_size = RX_QUEUE_SIZE;
119     virtio->tx_vq.queue_size = TX_QUEUE_SIZE;
120     virtio->ctrl_vq.queue_size = CTRL_QUEUE_SIZE;
121
122     virtio->rx_vq.ring_desc_addr = 0;
123     virtio->rx_vq.ring_avail_addr = 0;
124     virtio->rx_vq.ring_used_addr = 0;
125     virtio->rx_vq.pfn = 0;
126     virtio->rx_vq.cur_avail_idx = 0;
127
128     virtio->tx_vq.ring_desc_addr = 0;
129     virtio->tx_vq.ring_avail_addr = 0;
130     virtio->tx_vq.ring_used_addr = 0;
131     virtio->tx_vq.pfn = 0;
132     virtio->tx_vq.cur_avail_idx = 0;
133
134     virtio->ctrl_vq.ring_desc_addr = 0;
135     virtio->ctrl_vq.ring_avail_addr = 0;
136     virtio->ctrl_vq.ring_used_addr = 0;
137     virtio->ctrl_vq.pfn = 0;
138     virtio->ctrl_vq.cur_avail_idx = 0;
139
140     virtio->virtio_cfg.pci_isr = 0;
141         
142     virtio->virtio_cfg.host_features = 0 | (1 << VIRTIO_NET_F_MAC) | 
143                                                                 (1 << VIRTIO_NET_F_HOST_UFO) | 
144                                                                 (1 << VIRTIO_NET_F_HOST_TSO4);
145
146     if ((v3_lock_init(&(virtio->rx_lock)) == -1) ||
147         (v3_lock_init(&(virtio->tx_lock)) == -1)){
148         PrintError("Virtio NIC: Failure to init locks for net_state\n");
149     }
150
151     return 0;
152 }
153
154 static int tx_one_pkt(struct guest_info * core, 
155        struct virtio_net_state * virtio, 
156        struct vring_desc * buf_desc) 
157 {
158     uint8_t * buf = NULL;
159     uint32_t len = buf_desc->length;
160
161     if (v3_gpa_to_hva(core, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
162         PrintDebug("Could not translate buffer address\n");
163         return -1;
164     }
165
166     if(virtio->net_ops->send(buf, len, virtio->backend_data) >= 0){
167         virtio->statistics.tx_pkts ++;
168         virtio->statistics.tx_bytes += len;
169
170         return 0;
171     }
172
173     virtio->statistics.tx_dropped ++;
174
175     return -1;
176 }
177
178
179 static int 
180 copy_data_to_desc(struct guest_info * core, 
181                   struct virtio_net_state * virtio_state, 
182                   struct vring_desc * desc, 
183                   uchar_t * buf, 
184                   uint_t buf_len,
185                   uint_t offset)
186 {
187     uint32_t len;
188     uint8_t * desc_buf = NULL;
189
190     if (v3_gpa_to_hva(core, desc->addr_gpa, (addr_t *)&(desc_buf)) == -1) {
191         PrintError("Could not translate buffer address\n");
192         return -1;
193     }
194     len = (desc->length < buf_len)?(desc->length - offset):buf_len;
195     memcpy(desc_buf+offset, buf, len);
196
197     return len;
198 }
199
200
201 static int get_desc_count(struct virtio_queue * q, int index) {
202     struct vring_desc * tmp_desc = &(q->desc[index]);
203     int cnt = 1;
204     
205     while (tmp_desc->flags & VIRTIO_NEXT_FLAG) {
206         tmp_desc = &(q->desc[tmp_desc->next]);
207         cnt++;
208     }
209
210     return cnt;
211 }
212
213 static inline void enable_cb(struct virtio_queue *queue){
214     queue->used->flags &= ~ VRING_NO_NOTIFY_FLAG;
215 }
216
217 static inline void disable_cb(struct virtio_queue *queue) {
218     queue->used->flags |= VRING_NO_NOTIFY_FLAG;
219 }
220
221
222 /* interrupt the guest, so the guest core get EXIT to Palacios */
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 for rx queue */
229 static int handle_rx_queue_kick(struct guest_info * core, 
230                           struct virtio_net_state * virtio) 
231 {
232     return 0;
233 }
234
235
236 static int handle_ctrl(struct guest_info * core, 
237                        struct virtio_net_state * virtio) {
238         
239     return 0;
240 }
241
242 static int handle_pkt_tx(struct guest_info * core, 
243                          struct virtio_net_state * virtio_state) 
244 {
245     struct virtio_queue *q = &(virtio_state->tx_vq);
246     struct virtio_net_hdr *hdr = NULL;
247     int txed = 0;
248     unsigned long flags;
249
250     if (!q->ring_avail_addr) {
251         return -1;
252     }
253
254     flags = v3_lock_irqsave(virtio_state->tx_lock);
255     while (q->cur_avail_idx != q->avail->index) {
256         struct vring_desc * hdr_desc = NULL;
257         addr_t hdr_addr = 0;
258         uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
259         int desc_cnt = get_desc_count(q, desc_idx);
260         uint32_t req_len = 0;
261         int i = 0;
262
263         hdr_desc = &(q->desc[desc_idx]);
264         if (v3_gpa_to_hva(core, hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
265             PrintError("Could not translate block header address\n");
266             goto exit_error;
267         }
268
269         hdr = (struct virtio_net_hdr *)hdr_addr;
270         desc_idx = hdr_desc->next;
271
272         if(desc_cnt > 2){
273             PrintError("VNIC: merged rx buffer not supported, desc_cnt %d\n", desc_cnt);
274             goto exit_error;
275         }
276
277         /* here we assumed that one ethernet pkt is not splitted into multiple virtio buffer */
278         for (i = 0; i < desc_cnt - 1; i++) {    
279             struct vring_desc * buf_desc = &(q->desc[desc_idx]);
280             if (tx_one_pkt(core, virtio_state, buf_desc) == -1) {
281                 PrintError("Error handling nic operation\n");
282                 goto exit_error;
283             }
284
285             req_len += buf_desc->length;
286             desc_idx = buf_desc->next;
287         }
288
289         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
290         q->used->ring[q->used->index % q->queue_size].length = req_len; /* What do we set this to???? */
291         q->used->index ++;
292         
293         q->cur_avail_idx ++;
294
295         txed ++;
296     }
297
298     v3_unlock_irqrestore(virtio_state->tx_lock, flags);
299         
300     if (txed && !(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
301         v3_pci_raise_irq(virtio_state->virtio_dev->pci_bus, 0, virtio_state->pci_dev);
302         virtio_state->virtio_cfg.pci_isr = 0x1;
303
304         virtio_state->statistics.interrupts ++;
305     }
306
307     return 0;
308
309 exit_error:
310         
311     v3_unlock_irqrestore(virtio_state->tx_lock, flags);
312     return -1;
313 }
314
315
316 static int virtio_setup_queue(struct guest_info *core, 
317                               struct virtio_net_state * virtio_state, 
318                               struct virtio_queue * queue, 
319                               addr_t pfn, addr_t page_addr) {
320     queue->pfn = pfn;
321                 
322     queue->ring_desc_addr = page_addr;
323     queue->ring_avail_addr = page_addr + (queue->queue_size * sizeof(struct vring_desc));
324     queue->ring_used_addr = ((queue->ring_avail_addr) + 
325                              (sizeof(struct vring_avail)) + 
326                              (queue->queue_size * sizeof(uint16_t)));
327
328     // round up to next page boundary.
329     queue->ring_used_addr = (queue->ring_used_addr + 0xfff) & ~0xfff;
330     if (v3_gpa_to_hva(core, queue->ring_desc_addr, (addr_t *)&(queue->desc)) == -1) {
331         PrintError("Could not translate ring descriptor address\n");
332          return -1;
333     }
334  
335     if (v3_gpa_to_hva(core, queue->ring_avail_addr, (addr_t *)&(queue->avail)) == -1) {
336         PrintError("Could not translate ring available address\n");
337         return -1;
338     }
339
340     if (v3_gpa_to_hva(core, queue->ring_used_addr, (addr_t *)&(queue->used)) == -1) {
341         PrintError("Could not translate ring used address\n");
342         return -1;
343     }
344
345     PrintDebug("RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
346                (void *)(queue->ring_desc_addr),
347                (void *)(queue->ring_avail_addr),
348                (void *)(queue->ring_used_addr));
349     
350     PrintDebug("RingDesc=%p, Avail=%p, Used=%p\n", 
351                queue->desc, queue->avail, queue->used);
352     
353     return 0;
354 }
355
356 static int virtio_io_write(struct guest_info *core, 
357                            uint16_t port, void * src, 
358                            uint_t length, void * private_data) 
359 {
360     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
361     int port_idx = port % virtio->io_range_size;
362
363     PrintDebug("VIRTIO NIC %p Write for port %d (index=%d) len=%d, value=%x\n", private_data,
364                port, port_idx,  length, *(uint32_t *)src);
365
366     switch (port_idx) {
367         case GUEST_FEATURES_PORT:
368             if (length != 4) {
369                 PrintError("Illegal write length for guest features\n");
370                 return -1;
371             }       
372             virtio->virtio_cfg.guest_features = *(uint32_t *)src;
373             break;
374                 
375         case VRING_PG_NUM_PORT:
376             if (length != 4) {
377                 PrintError("Illegal write length for page frame number\n");
378                 return -1;
379             }
380             addr_t pfn = *(uint32_t *)src;
381             addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
382             uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
383             switch (queue_idx) {
384                 case 0:
385                     virtio_setup_queue(core, virtio, &virtio->rx_vq, pfn, page_addr);
386                     break;
387                 case 1:
388                     virtio_setup_queue(core, virtio, &virtio->tx_vq, pfn, page_addr);
389                     break;
390                 case 2:
391                     virtio_setup_queue(core, virtio, &virtio->ctrl_vq, pfn, page_addr);
392                     break;          
393                 default:
394                     break;
395             }
396             break;
397                 
398         case VRING_Q_SEL_PORT:
399             virtio->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
400             if (virtio->virtio_cfg.vring_queue_selector > 2) {
401                 PrintError("Virtio NIC: wrong queue idx: %d\n", 
402                            virtio->virtio_cfg.vring_queue_selector);
403                 return -1;
404             }
405             break;
406                 
407         case VRING_Q_NOTIFY_PORT: 
408             {
409                 uint16_t queue_idx = *(uint16_t *)src;                  
410                 if (queue_idx == 0){
411                     if(handle_rx_queue_kick(core, virtio) == -1){
412                         PrintError("Could not handle Virtio NIC rx kick\n");
413                         return -1;
414                     }
415                 } else if (queue_idx == 1){
416                     if (handle_pkt_tx(core, virtio) == -1) {
417                         PrintError("Could not handle Virtio NIC tx kick\n");
418                         return -1;
419                     }
420                 } else if (queue_idx == 2){
421                     if (handle_ctrl(core, virtio) == -1) {
422                         PrintError("Could not handle Virtio NIC ctrl kick\n");
423                         return -1;
424                     }
425                 } else {
426                     PrintError("Wrong queue index %d\n", queue_idx);
427                 }       
428                 break;          
429             }
430         
431         case VIRTIO_STATUS_PORT:
432             virtio->virtio_cfg.status = *(uint8_t *)src;
433             if (virtio->virtio_cfg.status == 0) {
434                 virtio_init_state(virtio);
435             }
436             break;
437
438         case VIRTIO_ISR_PORT:
439             virtio->virtio_cfg.pci_isr = *(uint8_t *)src;
440             break;
441                 
442         default:
443             return -1;
444             break;
445     }
446
447     return length;
448 }
449
450 static int virtio_io_read(struct guest_info *core, 
451                           uint16_t port, void * dst, 
452                           uint_t length, void * private_data) 
453 {
454     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
455     int port_idx = port % virtio->io_range_size;
456     uint16_t queue_idx = virtio->virtio_cfg.vring_queue_selector;
457
458     PrintDebug("Virtio NIC %p: Read  for port 0x%x (index =%d), length=%d\n", private_data,
459                port, port_idx, length);
460         
461     switch (port_idx) {
462         case HOST_FEATURES_PORT:
463             if (length != 4) {
464                 PrintError("Illegal read length for host features\n");
465                 return -1;
466             }
467             *(uint32_t *)dst = virtio->virtio_cfg.host_features;
468             break;
469
470         case VRING_PG_NUM_PORT:
471             if (length != 4) {
472                 PrintError("Illegal read length for page frame number\n");
473                 return -1;
474             }
475             switch (queue_idx) {
476                 case 0:
477                     *(uint32_t *)dst = virtio->rx_vq.pfn;
478                     break;
479                 case 1:
480                     *(uint32_t *)dst = virtio->tx_vq.pfn;
481                     break;      
482                 case 2:
483                     *(uint32_t *)dst = virtio->ctrl_vq.pfn;
484                     break;
485                 default:
486                     break;
487             }
488             break;
489
490         case VRING_SIZE_PORT:
491             if (length != 2) {
492                 PrintError("Illegal read length for vring size\n");
493                 return -1;
494             }
495             switch (queue_idx) {
496                 case 0:
497                     *(uint16_t *)dst = virtio->rx_vq.queue_size;
498                     break;
499                 case 1:
500                     *(uint16_t *)dst = virtio->tx_vq.queue_size;
501                     break;      
502                 case 2:
503                     *(uint16_t *)dst = virtio->ctrl_vq.queue_size;
504                     break;
505                 default:
506                     break;
507             }
508             break;
509
510         case VIRTIO_STATUS_PORT:
511             if (length != 1) {
512                 PrintError("Illegal read length for status\n");
513                 return -1;
514             }
515             *(uint8_t *)dst = virtio->virtio_cfg.status;
516             break;
517                 
518         case VIRTIO_ISR_PORT:
519             *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
520             virtio->virtio_cfg.pci_isr = 0;
521             v3_pci_lower_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
522             break;
523
524         case VIRTIO_NET_CONFIG ... VIRTIO_NET_CONFIG + ETH_ALEN:
525             *(uint8_t *)dst = virtio->net_cfg.mac[port_idx-VIRTIO_NET_CONFIG];
526             break;
527
528         default:
529             PrintError("Virtio NIC: Read of Unhandled Virtio Read:%d\n", port_idx);
530             return -1;
531     }
532
533     return length;
534 }
535
536
537 /* receiving raw ethernet pkt from backend */
538 static int virtio_rx(uint8_t * buf, uint32_t size, void * private_data) {
539     struct virtio_net_state * virtio = (struct virtio_net_state *)private_data;
540     struct virtio_queue * q = &(virtio->rx_vq);
541     struct virtio_net_hdr_mrg_rxbuf hdr;
542     uint32_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
543     uint32_t data_len;
544     uint32_t offset = 0;
545     unsigned long flags;
546
547 #ifdef CONFIG_DEBUG_VIRTIO_NET
548     PrintDebug("Virtio-NIC: virtio_rx: size: %d\n", size);      
549     v3_hexdump(buf, size, NULL, 0);
550 #endif
551
552     flags = v3_lock_irqsave(virtio->rx_lock);
553
554     data_len = size;
555     memset(&hdr, 0, sizeof(struct virtio_net_hdr_mrg_rxbuf));
556
557     if (q->ring_avail_addr == 0) {
558         PrintDebug("Queue is not set\n");
559         goto err_exit;
560     }
561
562     if (q->cur_avail_idx != q->avail->index){
563         addr_t hdr_addr = 0;
564         uint16_t hdr_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
565         uint16_t buf_idx = 0;
566         struct vring_desc * hdr_desc = NULL;
567
568         hdr_desc = &(q->desc[hdr_idx]);
569         if (v3_gpa_to_hva(&(virtio->virtio_dev->vm->cores[0]), hdr_desc->addr_gpa, &(hdr_addr)) == -1) {
570             PrintDebug("Could not translate receive buffer address\n");
571             goto err_exit;
572         }
573         hdr.num_buffers = 1;
574         memcpy((void *)hdr_addr, &hdr, sizeof(struct virtio_net_hdr_mrg_rxbuf));
575         if (offset >= data_len) {
576             hdr_desc->flags &= ~VIRTIO_NEXT_FLAG;
577         }
578
579         struct vring_desc * buf_desc = NULL;
580         for (buf_idx = hdr_desc->next; offset < data_len; buf_idx = q->desc[hdr_idx].next) {
581             uint32_t len = 0;
582             buf_desc = &(q->desc[buf_idx]);
583
584             len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]), virtio, buf_desc, buf + offset, data_len - offset, 0);     
585             offset += len;
586             if (offset < data_len) {
587                 buf_desc->flags = VIRTIO_NEXT_FLAG;             
588             }
589             buf_desc->length = len;
590         }
591         buf_desc->flags &= ~VIRTIO_NEXT_FLAG;
592         
593         q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
594         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) */
595         q->used->index++;
596         q->cur_avail_idx++;
597
598         virtio->statistics.rx_pkts ++;
599         virtio->statistics.rx_bytes += size;
600     } else {
601         virtio->statistics.rx_dropped ++;
602         
603         goto err_exit;
604     }
605
606     if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
607         PrintDebug("Raising IRQ %d\n",  virtio->pci_dev->config_header.intr_line);
608         
609         v3_pci_raise_irq(virtio->virtio_dev->pci_bus, 0, virtio->pci_dev);
610         virtio->virtio_cfg.pci_isr = 0x1;
611         virtio->statistics.interrupts ++;
612     }
613
614     v3_unlock_irqrestore(virtio->rx_lock, flags);
615
616     /* notify guest if guest is running */
617     if(virtio->rx_notify == 1){
618         v3_interrupt_cpu(virtio->virtio_dev->vm, virtio->virtio_dev->vm->cores[0].cpu_id, 0);
619     }
620
621     return 0;
622
623 err_exit:
624
625     v3_unlock_irqrestore(virtio->rx_lock, flags);
626  
627     return -1;
628 }
629
630 static int virtio_free(struct virtio_dev_state * virtio) {
631     struct virtio_net_state * backend = NULL;
632     struct virtio_net_state * tmp = NULL;
633
634
635     list_for_each_entry_safe(backend, tmp, &(virtio->dev_list), dev_link) {
636
637         // unregister from PCI
638
639         list_del(&(backend->dev_link));
640         V3_Free(backend);
641     }
642
643     V3_Free(virtio);
644     return 0;
645 }
646
647
648 static struct v3_device_ops dev_ops = {
649     .free = (int (*)(void *))virtio_free,
650 };
651
652
653 static void virtio_nic_poll(struct v3_vm_info * vm, int budget, void * data){
654     struct virtio_net_state * virtio = (struct virtio_net_state *)data;
655
656     if(virtio->tx_notify == 0){
657         handle_pkt_tx(&(vm->cores[0]), virtio);
658     }
659 }
660
661 static int register_dev(struct virtio_dev_state * virtio, 
662                         struct virtio_net_state * net_state) 
663 {
664     struct pci_device * pci_dev = NULL;
665     struct v3_pci_bar bars[6];
666     int num_ports = sizeof(struct virtio_config);
667     int tmp_ports = num_ports;
668     int i;
669
670     // This gets the number of ports, rounded up to a power of 2
671     net_state->io_range_size = 1; // must be a power of 2
672     while (tmp_ports > 0) {
673         tmp_ports >>= 1;
674         net_state->io_range_size <<= 1;
675     }
676         
677     /* this is to account for any low order bits being set in num_ports
678       * if there are none, then num_ports was already a power of 2 so we shift right to reset it
679       */
680     if ((num_ports & ((net_state->io_range_size >> 1) - 1)) == 0) {
681         net_state->io_range_size >>= 1;
682     }
683     
684     for (i = 0; i < 6; i++) {
685         bars[i].type = PCI_BAR_NONE;
686     }
687     
688     PrintDebug("Virtio-NIC io_range_size = %d\n", net_state->io_range_size);
689     
690     bars[0].type = PCI_BAR_IO;
691     bars[0].default_base_port = -1;
692     bars[0].num_ports = net_state->io_range_size;
693     bars[0].io_read = virtio_io_read;
694     bars[0].io_write = virtio_io_write;
695     bars[0].private_data = net_state;
696     
697     pci_dev = v3_pci_register_device(virtio->pci_bus, PCI_STD_DEVICE, 
698                                      0, 4/*PCI_AUTO_DEV_NUM*/, 0,
699                                      "LNX_VIRTIO_NIC", bars,
700                                      NULL, NULL, NULL, net_state);
701     
702     if (!pci_dev) {
703         PrintError("Virtio NIC: Could not register PCI Device\n");
704         return -1;
705     }
706
707     PrintDebug("Virtio NIC:  registered to PCI bus\n");
708     
709     pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
710     pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
711         
712
713     pci_dev->config_header.device_id = VIRTIO_NET_DEV_ID;
714     pci_dev->config_header.class = PCI_CLASS_NETWORK;
715     pci_dev->config_header.subclass = PCI_NET_SUBCLASS_OTHER;  
716     pci_dev->config_header.subsystem_id = VIRTIO_NET_SUBDEVICE_ID;
717     pci_dev->config_header.intr_pin = 1;
718     pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
719
720     net_state->pci_dev = pci_dev;
721     net_state->virtio_dev = virtio;
722
723     memcpy(net_state->net_cfg.mac, virtio->mac, 6);                           
724         
725     virtio_init_state(net_state);
726
727     /* Add backend to list of devices */
728     list_add(&(net_state->dev_link), &(virtio->dev_list));
729
730     return 0;
731 }
732
733 #define RATE_UPPER_THRESHOLD 10  /* 10000 pkts per second, around 100Mbits */
734 #define RATE_LOWER_THRESHOLD 1
735 #define PROFILE_PERIOD 50 /*50ms*/
736
737 /* Timer Functions */
738 static void virtio_nic_timer(struct guest_info * core, 
739                              uint64_t cpu_cycles, uint64_t cpu_freq, 
740                              void * priv_data) {
741     struct virtio_net_state * net_state = (struct virtio_net_state *)priv_data;
742     uint64_t period_ms;
743
744     period_ms = cpu_cycles/cpu_freq;
745     net_state->past_ms += period_ms;
746
747     if(net_state->past_ms >  PROFILE_PERIOD){ 
748         uint32_t tx_rate, rx_rate;
749         
750         tx_rate = (net_state->statistics.tx_pkts - net_state->tx_pkts)/net_state->past_ms; /* pkts/per ms */
751         rx_rate = (net_state->statistics.rx_pkts - net_state->rx_pkts)/net_state->past_ms;
752
753         net_state->tx_pkts = net_state->statistics.tx_pkts;
754         net_state->rx_pkts = net_state->statistics.rx_pkts;
755
756         if(tx_rate > RATE_UPPER_THRESHOLD && net_state->tx_notify == 1){
757             V3_Print("Virtio NIC: Switch TX to VMM driven mode\n");
758             disable_cb(&(net_state->tx_vq));
759             net_state->tx_notify = 0;
760         }
761
762         if(tx_rate < RATE_LOWER_THRESHOLD && net_state->tx_notify == 0){
763             V3_Print("Virtio NIC: Switch TX to Guest  driven mode\n");
764             enable_cb(&(net_state->tx_vq));
765             net_state->tx_notify = 1;
766         }
767
768         if(rx_rate > RATE_UPPER_THRESHOLD && net_state->rx_notify == 1){
769             PrintDebug("Virtio NIC: Switch RX to VMM None notify mode\n");
770             net_state->rx_notify = 0;
771         }
772
773         if(rx_rate < RATE_LOWER_THRESHOLD && net_state->rx_notify == 0){
774             PrintDebug("Virtio NIC: Switch RX to VMM notify mode\n");
775             net_state->rx_notify = 1;
776         }
777
778         net_state->past_ms = 0;
779     }
780 }
781
782
783 static struct v3_timer_ops timer_ops = {
784     .update_timer = virtio_nic_timer,
785 };
786
787
788 static int connect_fn(struct v3_vm_info * info, 
789                       void * frontend_data, 
790                       struct v3_dev_net_ops * ops, 
791                       v3_cfg_tree_t * cfg, 
792                       void * private_data) {
793     struct virtio_dev_state * virtio = (struct virtio_dev_state *)frontend_data;
794     struct virtio_net_state * net_state  = (struct virtio_net_state *)V3_Malloc(sizeof(struct virtio_net_state));
795
796     memset(net_state, 0, sizeof(struct virtio_net_state));
797     register_dev(virtio, net_state);
798
799     net_state->net_ops = ops;
800     net_state->backend_data = private_data;
801     net_state->virtio_dev = virtio;
802     net_state->tx_notify = 1;
803     net_state->rx_notify = 1;
804
805     net_state->timer = v3_add_timer(&(info->cores[0]),&timer_ops,net_state);
806
807     ops->recv = virtio_rx;
808     ops->poll = virtio_nic_poll;
809     ops->frontend_data = net_state;
810     memcpy(ops->fnt_mac, virtio->mac, ETH_ALEN);
811
812     return 0;
813 }
814
815 static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
816     struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
817     struct virtio_dev_state * virtio_state = NULL;
818     char * dev_id = v3_cfg_val(cfg, "ID");
819     char macstr[128];
820     char * str = v3_cfg_val(cfg, "mac");
821     memcpy(macstr, str, strlen(str));
822
823     if (pci_bus == NULL) {
824         PrintError("Virtio NIC: VirtIO devices require a PCI Bus");
825         return -1;
826     }
827
828     virtio_state  = (struct virtio_dev_state *)V3_Malloc(sizeof(struct virtio_dev_state));
829     memset(virtio_state, 0, sizeof(struct virtio_dev_state));
830
831     INIT_LIST_HEAD(&(virtio_state->dev_list));
832     virtio_state->pci_bus = pci_bus;
833     virtio_state->vm = vm;
834
835     if (macstr != NULL && !str2mac(macstr, virtio_state->mac)) {
836         PrintDebug("Virtio NIC: Mac specified %s\n", macstr);
837         PrintDebug("MAC: %x:%x:%x:%x:%x:%x\n", virtio_state->mac[0],
838                                 virtio_state->mac[1],
839                                 virtio_state->mac[2],
840                                 virtio_state->mac[3],
841                                 virtio_state->mac[4],
842                                 virtio_state->mac[5]);
843     }else {
844         PrintDebug("Virtio NIC: MAC not specified\n");
845         random_ethaddr(virtio_state->mac);
846     }
847
848     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, virtio_state);
849
850     if (dev == NULL) {
851         PrintError("Virtio NIC: Could not attach device %s\n", dev_id);
852         V3_Free(virtio_state);
853         return -1;
854     }
855
856     if (v3_dev_add_net_frontend(vm, dev_id, connect_fn, (void *)virtio_state) == -1) {
857         PrintError("Virtio NIC: Could not register %s as net frontend\n", dev_id);
858         v3_remove_device(dev);
859         return -1;
860     }
861         
862     return 0;
863 }
864
865 device_register("LNX_VIRTIO_NIC", virtio_init)
866