]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/pci_virtio_net.c
Dtrace: resolve const types from fbt and other fixes.
[FreeBSD/FreeBSD.git] / usr.sbin / bhyve / pci_virtio_net.c
1 /*-
2  * Copyright (c) 2011 NetApp, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/linker_set.h>
34 #include <sys/select.h>
35 #include <sys/uio.h>
36 #include <sys/ioctl.h>
37
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <stdint.h>
43 #include <string.h>
44 #include <strings.h>
45 #include <unistd.h>
46 #include <assert.h>
47 #include <md5.h>
48 #include <pthread.h>
49
50 #include "bhyverun.h"
51 #include "pci_emul.h"
52 #include "mevent.h"
53 #include "virtio.h"
54
55 #define VTNET_RINGSZ    256
56
57 #define VTNET_MAXSEGS   32
58
59 /*
60  * PCI config-space register offsets
61  */
62 #define VTNET_R_CFG0    24
63 #define VTNET_R_CFG1    25
64 #define VTNET_R_CFG2    26
65 #define VTNET_R_CFG3    27
66 #define VTNET_R_CFG4    28
67 #define VTNET_R_CFG5    29
68 #define VTNET_R_CFG6    30
69 #define VTNET_R_CFG7    31
70 #define VTNET_R_MAX     31
71
72 #define VTNET_REGSZ     VTNET_R_MAX+1
73
74 /*
75  * Host capabilities
76  */
77 #define VTNET_S_HOSTCAPS      \
78   ( 0x00000020 |        /* host supplies MAC */ \
79     0x00008000 |        /* host can merge Rx buffers */ \
80     0x00010000 )        /* config status available */
81
82 /*
83  * Queue definitions.
84  */
85 #define VTNET_RXQ       0
86 #define VTNET_TXQ       1
87 #define VTNET_CTLQ      2
88
89 #define VTNET_MAXQ      3
90
91 static int use_msix = 1;
92
93 struct vring_hqueue {
94         /* Internal state */
95         uint16_t        hq_size;
96         uint16_t        hq_cur_aidx;            /* trails behind 'avail_idx' */
97
98          /* Host-context pointers to the queue */
99         struct virtio_desc *hq_dtable;
100         uint16_t        *hq_avail_flags;
101         uint16_t        *hq_avail_idx;          /* monotonically increasing */
102         uint16_t        *hq_avail_ring;
103
104         uint16_t        *hq_used_flags;
105         uint16_t        *hq_used_idx;           /* monotonically increasing */
106         struct virtio_used *hq_used_ring;
107 };
108
109 /*
110  * Fixed network header size
111  */
112 struct virtio_net_rxhdr {
113         uint8_t         vrh_flags;
114         uint8_t         vrh_gso_type;
115         uint16_t        vrh_hdr_len;
116         uint16_t        vrh_gso_size;
117         uint16_t        vrh_csum_start;
118         uint16_t        vrh_csum_offset;
119         uint16_t        vrh_bufs;
120 } __packed;
121
122 /*
123  * Debug printf
124  */
125 static int pci_vtnet_debug;
126 #define DPRINTF(params) if (pci_vtnet_debug) printf params
127 #define WPRINTF(params) printf params
128
129 /*
130  * Per-device softc
131  */
132 struct pci_vtnet_softc {
133         struct pci_devinst *vsc_pi;
134         pthread_mutex_t vsc_mtx;
135         struct mevent   *vsc_mevp;
136
137         int             vsc_curq;
138         int             vsc_status;
139         int             vsc_isr;
140         int             vsc_tapfd;
141         int             vsc_rx_ready;
142         int             vsc_rxpend;
143
144         uint32_t        vsc_features;
145         uint8_t         vsc_macaddr[6];
146
147         uint64_t        vsc_pfn[VTNET_MAXQ];
148         struct  vring_hqueue vsc_hq[VTNET_MAXQ];
149         uint16_t        vsc_msix_table_idx[VTNET_MAXQ];
150 };
151 #define vtnet_ctx(sc)   ((sc)->vsc_pi->pi_vmctx)
152
153 /*
154  * Return the size of IO BAR that maps virtio header and device specific
155  * region. The size would vary depending on whether MSI-X is enabled or
156  * not.
157  */
158 static uint64_t
159 pci_vtnet_iosize(struct pci_devinst *pi)
160 {
161         if (pci_msix_enabled(pi))
162                 return (VTNET_REGSZ);
163         else
164                 return (VTNET_REGSZ - (VTCFG_R_CFG1 - VTCFG_R_MSIX));
165 }
166
167 /*
168  * Return the number of available descriptors in the vring taking care
169  * of the 16-bit index wraparound.
170  */
171 static int
172 hq_num_avail(struct vring_hqueue *hq)
173 {
174         uint16_t ndesc;
175
176         /*
177          * We're just computing (a-b) in GF(216).
178          *
179          * The only glitch here is that in standard C,
180          * uint16_t promotes to (signed) int when int has
181          * more than 16 bits (pretty much always now), so
182          * we have to force it back to unsigned.
183          */
184         ndesc = (unsigned)*hq->hq_avail_idx - (unsigned)hq->hq_cur_aidx;
185
186         assert(ndesc <= hq->hq_size);
187
188         return (ndesc);
189 }
190
191 static uint16_t
192 pci_vtnet_qsize(int qnum)
193 {
194         /* XXX no ctl queue currently */
195         if (qnum == VTNET_CTLQ) {
196                 return (0);
197         }
198
199         /* XXX fixed currently. Maybe different for tx/rx/ctl */
200         return (VTNET_RINGSZ);
201 }
202
203 static void
204 pci_vtnet_ring_reset(struct pci_vtnet_softc *sc, int ring)
205 {
206         struct vring_hqueue *hq;
207
208         assert(ring < VTNET_MAXQ);
209
210         hq = &sc->vsc_hq[ring];
211
212         /*
213          * Reset all soft state
214          */
215         hq->hq_cur_aidx = 0;
216 }
217
218 static void
219 pci_vtnet_update_status(struct pci_vtnet_softc *sc, uint32_t value)
220 {
221
222         if (value == 0) {
223                 DPRINTF(("vtnet: device reset requested !\n"));
224                 pci_vtnet_ring_reset(sc, VTNET_RXQ);
225                 pci_vtnet_ring_reset(sc, VTNET_TXQ);
226                 sc->vsc_rx_ready = 0;
227         }
228
229         sc->vsc_status = value;
230 }
231
232 /*
233  * Called to send a buffer chain out to the tap device
234  */
235 static void
236 pci_vtnet_tap_tx(struct pci_vtnet_softc *sc, struct iovec *iov, int iovcnt,
237                  int len)
238 {
239         char pad[60];
240
241         if (sc->vsc_tapfd == -1)
242                 return;
243
244         /*
245          * If the length is < 60, pad out to that and add the
246          * extra zero'd segment to the iov. It is guaranteed that
247          * there is always an extra iov available by the caller.
248          */
249         if (len < 60) {
250                 memset(pad, 0, 60 - len);
251                 iov[iovcnt].iov_base = pad;
252                 iov[iovcnt].iov_len = 60 - len;
253                 iovcnt++;
254         }
255         (void) writev(sc->vsc_tapfd, iov, iovcnt);
256 }
257
258 /*
259  *  Called when there is read activity on the tap file descriptor.
260  * Each buffer posted by the guest is assumed to be able to contain
261  * an entire ethernet frame + rx header.
262  *  MP note: the dummybuf is only used for discarding frames, so there
263  * is no need for it to be per-vtnet or locked.
264  */
265 static uint8_t dummybuf[2048];
266
267 static void
268 pci_vtnet_tap_rx(struct pci_vtnet_softc *sc)
269 {
270         struct virtio_desc *vd;
271         struct virtio_used *vu;
272         struct vring_hqueue *hq;
273         struct virtio_net_rxhdr *vrx;
274         uint8_t *buf;
275         int i;
276         int len;
277         int ndescs;
278         int didx, uidx, aidx;   /* descriptor, avail and used index */
279
280         /*
281          * Should never be called without a valid tap fd
282          */
283         assert(sc->vsc_tapfd != -1);
284
285         /*
286          * But, will be called when the rx ring hasn't yet
287          * been set up. 
288          */
289         if (sc->vsc_rx_ready == 0) {
290                 /*
291                  * Drop the packet and try later.
292                  */
293                 (void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf));
294                 return;
295         }
296
297         /*
298          * Calculate the number of available rx buffers
299          */
300         hq = &sc->vsc_hq[VTNET_RXQ];
301
302         ndescs = hq_num_avail(hq);
303
304         if (ndescs == 0) {
305                 /*
306                  * Need to wait for host notification to read
307                  */
308                 if (sc->vsc_rxpend == 0) {
309                         WPRINTF(("vtnet: no rx descriptors !\n"));
310                         sc->vsc_rxpend = 1;
311                 }
312
313                 /*
314                  * Drop the packet and try later
315                  */
316                 (void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf));
317                 return;
318         }
319
320         aidx = hq->hq_cur_aidx;
321         uidx = *hq->hq_used_idx;
322         for (i = 0; i < ndescs; i++) {
323                 /*
324                  * 'aidx' indexes into the an array of descriptor indexes
325                  */
326                 didx = hq->hq_avail_ring[aidx % hq->hq_size];
327                 assert(didx >= 0 && didx < hq->hq_size);
328
329                 vd = &hq->hq_dtable[didx];
330
331                 /*
332                  * Get a pointer to the rx header, and use the
333                  * data immediately following it for the packet buffer.
334                  */
335                 vrx = paddr_guest2host(vtnet_ctx(sc), vd->vd_addr, vd->vd_len);
336                 buf = (uint8_t *)(vrx + 1);
337
338                 len = read(sc->vsc_tapfd, buf,
339                            vd->vd_len - sizeof(struct virtio_net_rxhdr));
340
341                 if (len < 0 && errno == EWOULDBLOCK) {
342                         break;
343                 }
344
345                 /*
346                  * The only valid field in the rx packet header is the
347                  * number of buffers, which is always 1 without TSO
348                  * support.
349                  */
350                 memset(vrx, 0, sizeof(struct virtio_net_rxhdr));
351                 vrx->vrh_bufs = 1;
352
353                 /*
354                  * Write this descriptor into the used ring
355                  */
356                 vu = &hq->hq_used_ring[uidx % hq->hq_size];
357                 vu->vu_idx = didx;
358                 vu->vu_tlen = len + sizeof(struct virtio_net_rxhdr);
359                 uidx++;
360                 aidx++;
361         }
362
363         /*
364          * Update the used pointer, and signal an interrupt if allowed
365          */
366         *hq->hq_used_idx = uidx;
367         hq->hq_cur_aidx = aidx;
368
369         if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) {
370                 if (use_msix) {
371                         pci_generate_msix(sc->vsc_pi,
372                                           sc->vsc_msix_table_idx[VTNET_RXQ]);
373                 } else {
374                         sc->vsc_isr |= 1;
375                         pci_generate_msi(sc->vsc_pi, 0);
376                 }
377         }
378 }
379
380 static void
381 pci_vtnet_tap_callback(int fd, enum ev_type type, void *param)
382 {
383         struct pci_vtnet_softc *sc = param;
384
385         pthread_mutex_lock(&sc->vsc_mtx);
386         pci_vtnet_tap_rx(sc);
387         pthread_mutex_unlock(&sc->vsc_mtx);
388
389 }
390
391 static void
392 pci_vtnet_ping_rxq(struct pci_vtnet_softc *sc)
393 {
394         /*
395          * A qnotify means that the rx process can now begin
396          */
397         if (sc->vsc_rx_ready == 0) {
398                 sc->vsc_rx_ready = 1;
399         }
400
401         /*
402          * If the rx queue was empty, attempt to receive a
403          * packet that was previously blocked due to no rx bufs
404          * available
405          */
406         if (sc->vsc_rxpend) {
407                 WPRINTF(("vtnet: rx resumed\n\r"));
408                 sc->vsc_rxpend = 0;
409                 pci_vtnet_tap_rx(sc);
410         }
411 }
412
413 static void
414 pci_vtnet_proctx(struct pci_vtnet_softc *sc, struct vring_hqueue *hq)
415 {
416         struct iovec iov[VTNET_MAXSEGS + 1];
417         struct virtio_desc *vd;
418         struct virtio_used *vu;
419         int i;
420         int plen;
421         int tlen;
422         int uidx, aidx, didx;
423
424         uidx = *hq->hq_used_idx;
425         aidx = hq->hq_cur_aidx;
426         didx = hq->hq_avail_ring[aidx % hq->hq_size];
427         assert(didx >= 0 && didx < hq->hq_size);
428
429         vd = &hq->hq_dtable[didx];
430
431         /*
432          * Run through the chain of descriptors, ignoring the
433          * first header descriptor. However, include the header
434          * length in the total length that will be put into the
435          * used queue.
436          */
437         tlen = vd->vd_len;
438         vd = &hq->hq_dtable[vd->vd_next];
439
440         for (i = 0, plen = 0;
441              i < VTNET_MAXSEGS;
442              i++, vd = &hq->hq_dtable[vd->vd_next]) {
443                 iov[i].iov_base = paddr_guest2host(vtnet_ctx(sc),
444                                                    vd->vd_addr, vd->vd_len);
445                 iov[i].iov_len = vd->vd_len;
446                 plen += vd->vd_len;
447                 tlen += vd->vd_len;
448
449                 if ((vd->vd_flags & VRING_DESC_F_NEXT) == 0)
450                         break;
451         }
452         assert(i < VTNET_MAXSEGS);
453
454         DPRINTF(("virtio: packet send, %d bytes, %d segs\n\r", plen, i + 1));
455         pci_vtnet_tap_tx(sc, iov, i + 1, plen);
456
457         /*
458          * Return this chain back to the host
459          */
460         vu = &hq->hq_used_ring[uidx % hq->hq_size];
461         vu->vu_idx = didx;
462         vu->vu_tlen = tlen;
463         hq->hq_cur_aidx = aidx + 1;
464         *hq->hq_used_idx = uidx + 1;
465
466         /*
467          * Generate an interrupt if able
468          */
469         if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) {
470                 if (use_msix) {
471                         pci_generate_msix(sc->vsc_pi,
472                                           sc->vsc_msix_table_idx[VTNET_TXQ]);
473                 } else {
474                         sc->vsc_isr |= 1;
475                         pci_generate_msi(sc->vsc_pi, 0);
476                 }
477         }       
478 }
479
480 static void
481 pci_vtnet_ping_txq(struct pci_vtnet_softc *sc)
482 {
483         struct vring_hqueue *hq = &sc->vsc_hq[VTNET_TXQ];
484         int i;
485         int ndescs;
486
487         /*
488          * Calculate number of ring entries to process
489          */
490         ndescs = hq_num_avail(hq);
491
492         if (ndescs == 0)
493                 return;
494
495         /*
496          * Run through all the entries, placing them into iovecs and
497          * sending when an end-of-packet is found
498          */
499         for (i = 0; i < ndescs; i++)
500                 pci_vtnet_proctx(sc, hq);
501 }
502
503 static void
504 pci_vtnet_ping_ctlq(struct pci_vtnet_softc *sc)
505 {
506
507         DPRINTF(("vtnet: control qnotify!\n\r"));       
508 }
509
510 static void
511 pci_vtnet_ring_init(struct pci_vtnet_softc *sc, uint64_t pfn)
512 {
513         struct vring_hqueue *hq;
514         int qnum = sc->vsc_curq;
515
516         assert(qnum < VTNET_MAXQ);
517
518         sc->vsc_pfn[qnum] = pfn << VRING_PFN;
519         
520         /*
521          * Set up host pointers to the various parts of the
522          * queue
523          */
524         hq = &sc->vsc_hq[qnum];
525         hq->hq_size = pci_vtnet_qsize(qnum);
526
527         hq->hq_dtable = paddr_guest2host(vtnet_ctx(sc), pfn << VRING_PFN,
528                                          vring_size(hq->hq_size));
529         hq->hq_avail_flags =  (uint16_t *)(hq->hq_dtable + hq->hq_size);
530         hq->hq_avail_idx = hq->hq_avail_flags + 1;
531         hq->hq_avail_ring = hq->hq_avail_flags + 2;
532         hq->hq_used_flags = (uint16_t *)roundup2((uintptr_t)hq->hq_avail_ring,
533                                                  VRING_ALIGN);
534         hq->hq_used_idx = hq->hq_used_flags + 1;
535         hq->hq_used_ring = (struct virtio_used *)(hq->hq_used_flags + 2);
536
537         /*
538          * Initialize queue indexes
539          */
540         hq->hq_cur_aidx = 0;
541 }
542
543 static int
544 pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
545 {
546         MD5_CTX mdctx;
547         unsigned char digest[16];
548         char nstr[80];
549         struct pci_vtnet_softc *sc;
550         const char *env_msi;
551
552         sc = malloc(sizeof(struct pci_vtnet_softc));
553         memset(sc, 0, sizeof(struct pci_vtnet_softc));
554
555         pi->pi_arg = sc;
556         sc->vsc_pi = pi;
557
558         pthread_mutex_init(&sc->vsc_mtx, NULL);
559  
560         /*
561          * Use MSI if set by user
562          */
563         if ((env_msi = getenv("BHYVE_USE_MSI")) != NULL) {
564                 if (strcasecmp(env_msi, "yes") == 0)
565                         use_msix = 0;
566         }
567
568         /*
569          * Attempt to open the tap device
570          */
571         sc->vsc_tapfd = -1;
572         if (opts != NULL) {
573                 char tbuf[80];
574
575                 strcpy(tbuf, "/dev/");
576                 strlcat(tbuf, opts, sizeof(tbuf));
577
578                 sc->vsc_tapfd = open(tbuf, O_RDWR);
579                 if (sc->vsc_tapfd == -1) {
580                         WPRINTF(("open of tap device %s failed\n", tbuf));
581                 } else {
582                         /*
583                          * Set non-blocking and register for read
584                          * notifications with the event loop
585                          */
586                         int opt = 1;
587                         if (ioctl(sc->vsc_tapfd, FIONBIO, &opt) < 0) {
588                                 WPRINTF(("tap device O_NONBLOCK failed\n"));
589                                 close(sc->vsc_tapfd);
590                                 sc->vsc_tapfd = -1;
591                         }
592
593                         sc->vsc_mevp = mevent_add(sc->vsc_tapfd,
594                                                   EVF_READ,
595                                                   pci_vtnet_tap_callback,
596                                                   sc);
597                         if (sc->vsc_mevp == NULL) {
598                                 WPRINTF(("Could not register event\n"));
599                                 close(sc->vsc_tapfd);
600                                 sc->vsc_tapfd = -1;
601                         }
602                 }               
603         }
604
605         /*
606          * The MAC address is the standard NetApp OUI of 00-a0-98,
607          * followed by an MD5 of the vm name. The slot/func number is
608          * prepended to this for slots other than 1:0, so that 
609          * a bootloader can netboot from the equivalent of slot 1.
610          */
611         if (pi->pi_slot == 1 && pi->pi_func == 0) {
612                 strncpy(nstr, vmname, sizeof(nstr));
613         } else {
614                 snprintf(nstr, sizeof(nstr), "%d-%d-%s", pi->pi_slot,
615                     pi->pi_func, vmname);
616         }
617
618         MD5Init(&mdctx);
619         MD5Update(&mdctx, nstr, strlen(nstr));
620         MD5Final(digest, &mdctx);
621
622         sc->vsc_macaddr[0] = 0x00;
623         sc->vsc_macaddr[1] = 0xa0;
624         sc->vsc_macaddr[2] = 0x98;
625         sc->vsc_macaddr[3] = digest[0];
626         sc->vsc_macaddr[4] = digest[1];
627         sc->vsc_macaddr[5] = digest[2];
628
629         /* initialize config space */
630         pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET);
631         pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
632         pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK);
633         pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET);
634         
635         if (use_msix) {
636                 /* MSI-X support */
637                 int i;
638
639                 for (i = 0; i < VTNET_MAXQ; i++)
640                         sc->vsc_msix_table_idx[i] = VIRTIO_MSI_NO_VECTOR;
641
642                 /*
643                  * BAR 1 used to map MSI-X table and PBA
644                  */
645                 if (pci_emul_add_msixcap(pi, VTNET_MAXQ, 1))
646                         return (1);
647         } else {
648                 /* MSI support */
649                 pci_emul_add_msicap(pi, 1);
650         }
651         
652         pci_emul_alloc_bar(pi, 0, PCIBAR_IO, VTNET_REGSZ);
653
654         return (0);
655 }
656
657 /*
658  * Function pointer array to handle queue notifications
659  */
660 static void (*pci_vtnet_qnotify[VTNET_MAXQ])(struct pci_vtnet_softc *) = {
661         pci_vtnet_ping_rxq,
662         pci_vtnet_ping_txq,
663         pci_vtnet_ping_ctlq
664 };
665
666 static uint64_t
667 vtnet_adjust_offset(struct pci_devinst *pi, uint64_t offset)
668 {
669         /*
670          * Device specific offsets used by guest would change based on
671          * whether MSI-X capability is enabled or not
672          */
673         if (!pci_msix_enabled(pi)) {
674                 if (offset >= VTCFG_R_MSIX)
675                         return (offset + (VTCFG_R_CFG1 - VTCFG_R_MSIX));
676         }
677
678         return (offset);
679 }
680
681 static void
682 pci_vtnet_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
683                 int baridx, uint64_t offset, int size, uint64_t value)
684 {
685         struct pci_vtnet_softc *sc = pi->pi_arg;
686         void *ptr;
687
688         if (use_msix) {
689                 if (baridx == pci_msix_table_bar(pi) ||
690                     baridx == pci_msix_pba_bar(pi)) {
691                         pci_emul_msix_twrite(pi, offset, size, value);
692                         return;
693                 }
694         }
695
696         assert(baridx == 0);
697
698         if (offset + size > pci_vtnet_iosize(pi)) {
699                 DPRINTF(("vtnet_write: 2big, offset %ld size %d\n",
700                          offset, size));
701                 return;
702         }
703
704         pthread_mutex_lock(&sc->vsc_mtx);
705
706         offset = vtnet_adjust_offset(pi, offset);
707
708         switch (offset) {
709         case VTCFG_R_GUESTCAP:
710                 assert(size == 4);
711                 sc->vsc_features = value & VTNET_S_HOSTCAPS;
712                 break;
713         case VTCFG_R_PFN:
714                 assert(size == 4);
715                 pci_vtnet_ring_init(sc, value);
716                 break;
717         case VTCFG_R_QSEL:
718                 assert(size == 2);
719                 assert(value < VTNET_MAXQ);
720                 sc->vsc_curq = value;
721                 break;
722         case VTCFG_R_QNOTIFY:
723                 assert(size == 2);
724                 assert(value < VTNET_MAXQ);
725                 (*pci_vtnet_qnotify[value])(sc);
726                 break;
727         case VTCFG_R_STATUS:
728                 assert(size == 1);
729                 pci_vtnet_update_status(sc, value);
730                 break;
731         case VTCFG_R_CFGVEC:
732                 assert(size == 2);
733                 sc->vsc_msix_table_idx[VTNET_CTLQ] = value;
734                 break;
735         case VTCFG_R_QVEC:
736                 assert(size == 2);
737                 assert(sc->vsc_curq != VTNET_CTLQ);
738                 sc->vsc_msix_table_idx[sc->vsc_curq] = value;
739                 break;
740         case VTNET_R_CFG0:
741         case VTNET_R_CFG1:
742         case VTNET_R_CFG2:
743         case VTNET_R_CFG3:
744         case VTNET_R_CFG4:
745         case VTNET_R_CFG5:
746                 assert((size + offset) <= (VTNET_R_CFG5 + 1));
747                 ptr = &sc->vsc_macaddr[offset - VTNET_R_CFG0];
748                 /*
749                  * The driver is allowed to change the MAC address
750                  */
751                 sc->vsc_macaddr[offset - VTNET_R_CFG0] = value;
752                 if (size == 1) {
753                         *(uint8_t *) ptr = value;
754                 } else if (size == 2) {
755                         *(uint16_t *) ptr = value;
756                 } else {
757                         *(uint32_t *) ptr = value;
758                 }
759                 break;
760         case VTCFG_R_HOSTCAP:
761         case VTCFG_R_QNUM:
762         case VTCFG_R_ISR:
763         case VTNET_R_CFG6:
764         case VTNET_R_CFG7:
765                 DPRINTF(("vtnet: write to readonly reg %ld\n\r", offset));
766                 break;
767         default:
768                 DPRINTF(("vtnet: unknown i/o write offset %ld\n\r", offset));
769                 value = 0;
770                 break;
771         }
772
773         pthread_mutex_unlock(&sc->vsc_mtx);
774 }
775
776 uint64_t
777 pci_vtnet_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
778                int baridx, uint64_t offset, int size)
779 {
780         struct pci_vtnet_softc *sc = pi->pi_arg;
781         void *ptr;
782         uint64_t value;
783
784         if (use_msix) {
785                 if (baridx == pci_msix_table_bar(pi) ||
786                     baridx == pci_msix_pba_bar(pi)) {
787                         return (pci_emul_msix_tread(pi, offset, size));
788                 }
789         }
790
791         assert(baridx == 0);
792
793         if (offset + size > pci_vtnet_iosize(pi)) {
794                 DPRINTF(("vtnet_read: 2big, offset %ld size %d\n",
795                          offset, size));
796                 return (0);
797         }
798
799         pthread_mutex_lock(&sc->vsc_mtx);
800
801         offset = vtnet_adjust_offset(pi, offset);
802
803         switch (offset) {
804         case VTCFG_R_HOSTCAP:
805                 assert(size == 4);
806                 value = VTNET_S_HOSTCAPS;
807                 break;
808         case VTCFG_R_GUESTCAP:
809                 assert(size == 4);
810                 value = sc->vsc_features; /* XXX never read ? */
811                 break;
812         case VTCFG_R_PFN:
813                 assert(size == 4);
814                 value = sc->vsc_pfn[sc->vsc_curq] >> VRING_PFN;
815                 break;
816         case VTCFG_R_QNUM:
817                 assert(size == 2);
818                 value = pci_vtnet_qsize(sc->vsc_curq);
819                 break;
820         case VTCFG_R_QSEL:
821                 assert(size == 2);
822                 value = sc->vsc_curq;  /* XXX never read ? */
823                 break;
824         case VTCFG_R_QNOTIFY:
825                 assert(size == 2);
826                 value = sc->vsc_curq;  /* XXX never read ? */
827                 break;
828         case VTCFG_R_STATUS:
829                 assert(size == 1);
830                 value = sc->vsc_status;
831                 break;
832         case VTCFG_R_ISR:
833                 assert(size == 1);
834                 value = sc->vsc_isr;
835                 sc->vsc_isr = 0;     /* a read clears this flag */
836                 break;
837         case VTCFG_R_CFGVEC:
838                 assert(size == 2);
839                 value = sc->vsc_msix_table_idx[VTNET_CTLQ];
840                 break;
841         case VTCFG_R_QVEC:
842                 assert(size == 2);
843                 assert(sc->vsc_curq != VTNET_CTLQ);
844                 value = sc->vsc_msix_table_idx[sc->vsc_curq];
845                 break;
846         case VTNET_R_CFG0:
847         case VTNET_R_CFG1:
848         case VTNET_R_CFG2:
849         case VTNET_R_CFG3:
850         case VTNET_R_CFG4:
851         case VTNET_R_CFG5:
852                 assert((size + offset) <= (VTNET_R_CFG5 + 1));
853                 ptr = &sc->vsc_macaddr[offset - VTNET_R_CFG0];
854                 if (size == 1) {
855                         value = *(uint8_t *) ptr;
856                 } else if (size == 2) {
857                         value = *(uint16_t *) ptr;
858                 } else {
859                         value = *(uint32_t *) ptr;
860                 }
861                 break;
862         case VTNET_R_CFG6:
863                 assert(size != 4);
864                 value = 0x01; /* XXX link always up */
865                 break;
866         case VTNET_R_CFG7:
867                 assert(size == 1);
868                 value = 0; /* XXX link status in LSB */
869                 break;
870         default:
871                 DPRINTF(("vtnet: unknown i/o read offset %ld\n\r", offset));
872                 value = 0;
873                 break;
874         }
875
876         pthread_mutex_unlock(&sc->vsc_mtx);
877
878         return (value);
879 }
880
881 struct pci_devemu pci_de_vnet = {
882         .pe_emu =       "virtio-net",
883         .pe_init =      pci_vtnet_init,
884         .pe_barwrite =  pci_vtnet_write,
885         .pe_barread =   pci_vtnet_read
886 };
887 PCI_EMUL_SET(pci_de_vnet);