]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/pci_virtio_net.c
Replace our (un)vis(1) commands with implementations from NetBSD to
[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
152 /*
153  * Return the size of IO BAR that maps virtio header and device specific
154  * region. The size would vary depending on whether MSI-X is enabled or
155  * not.
156  */
157 static uint64_t
158 pci_vtnet_iosize(struct pci_devinst *pi)
159 {
160         if (pci_msix_enabled(pi))
161                 return (VTNET_REGSZ);
162         else
163                 return (VTNET_REGSZ - (VTCFG_R_CFG1 - VTCFG_R_MSIX));
164 }
165
166 /*
167  * Return the number of available descriptors in the vring taking care
168  * of the 16-bit index wraparound.
169  */
170 static int
171 hq_num_avail(struct vring_hqueue *hq)
172 {
173         int ndesc;
174
175         /*
176          * We're just computing (a-b) in GF(216).
177          *
178          * The only glitch here is that in standard C,
179          * uint16_t promotes to (signed) int when int has
180          * more than 16 bits (pretty much always now), so
181          * we have to force it back to unsigned.
182          */
183         ndesc = (unsigned)*hq->hq_avail_idx - (unsigned)hq->hq_cur_aidx;
184
185         assert(ndesc <= hq->hq_size);
186
187         return (ndesc);
188 }
189
190 static uint16_t
191 pci_vtnet_qsize(int qnum)
192 {
193         /* XXX no ctl queue currently */
194         if (qnum == VTNET_CTLQ) {
195                 return (0);
196         }
197
198         /* XXX fixed currently. Maybe different for tx/rx/ctl */
199         return (VTNET_RINGSZ);
200 }
201
202 static void
203 pci_vtnet_ring_reset(struct pci_vtnet_softc *sc, int ring)
204 {
205         struct vring_hqueue *hq;
206
207         assert(ring < VTNET_MAXQ);
208
209         hq = &sc->vsc_hq[ring];
210
211         /*
212          * Reset all soft state
213          */
214         hq->hq_cur_aidx = 0;
215 }
216
217 static void
218 pci_vtnet_update_status(struct pci_vtnet_softc *sc, uint32_t value)
219 {
220
221         if (value == 0) {
222                 DPRINTF(("vtnet: device reset requested !\n"));
223                 pci_vtnet_ring_reset(sc, VTNET_RXQ);
224                 pci_vtnet_ring_reset(sc, VTNET_TXQ);
225                 sc->vsc_rx_ready = 0;
226         }
227
228         sc->vsc_status = value;
229 }
230
231 /*
232  * Called to send a buffer chain out to the tap device
233  */
234 static void
235 pci_vtnet_tap_tx(struct pci_vtnet_softc *sc, struct iovec *iov, int iovcnt,
236                  int len)
237 {
238         char pad[60];
239
240         if (sc->vsc_tapfd == -1)
241                 return;
242
243         /*
244          * If the length is < 60, pad out to that and add the
245          * extra zero'd segment to the iov. It is guaranteed that
246          * there is always an extra iov available by the caller.
247          */
248         if (len < 60) {
249                 memset(pad, 0, 60 - len);
250                 iov[iovcnt].iov_base = pad;
251                 iov[iovcnt].iov_len = 60 - len;
252                 iovcnt++;
253         }
254         (void) writev(sc->vsc_tapfd, iov, iovcnt);
255 }
256
257 /*
258  *  Called when there is read activity on the tap file descriptor.
259  * Each buffer posted by the guest is assumed to be able to contain
260  * an entire ethernet frame + rx header.
261  *  MP note: the dummybuf is only used for discarding frames, so there
262  * is no need for it to be per-vtnet or locked.
263  */
264 static uint8_t dummybuf[2048];
265
266 static void
267 pci_vtnet_tap_rx(struct pci_vtnet_softc *sc)
268 {
269         struct virtio_desc *vd;
270         struct virtio_used *vu;
271         struct vring_hqueue *hq;
272         struct virtio_net_rxhdr *vrx;
273         uint8_t *buf;
274         int i;
275         int len;
276         int ndescs;
277         int didx, uidx, aidx;   /* descriptor, avail and used index */
278
279         /*
280          * Should never be called without a valid tap fd
281          */
282         assert(sc->vsc_tapfd != -1);
283
284         /*
285          * But, will be called when the rx ring hasn't yet
286          * been set up. 
287          */
288         if (sc->vsc_rx_ready == 0) {
289                 /*
290                  * Drop the packet and try later.
291                  */
292                 (void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf));
293                 return;
294         }
295
296         /*
297          * Calculate the number of available rx buffers
298          */
299         hq = &sc->vsc_hq[VTNET_RXQ];
300
301         ndescs = hq_num_avail(hq);
302
303         if (ndescs == 0) {
304                 /*
305                  * Need to wait for host notification to read
306                  */
307                 if (sc->vsc_rxpend == 0) {
308                         WPRINTF(("vtnet: no rx descriptors !\n"));
309                         sc->vsc_rxpend = 1;
310                 }
311
312                 /*
313                  * Drop the packet and try later
314                  */
315                 (void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf));
316                 return;
317         }
318
319         aidx = hq->hq_cur_aidx;
320         uidx = *hq->hq_used_idx;
321         for (i = 0; i < ndescs; i++) {
322                 /*
323                  * 'aidx' indexes into the an array of descriptor indexes
324                  */
325                 didx = hq->hq_avail_ring[aidx % hq->hq_size];
326                 assert(didx >= 0 && didx < hq->hq_size);
327
328                 vd = &hq->hq_dtable[didx];
329
330                 /*
331                  * Get a pointer to the rx header, and use the
332                  * data immediately following it for the packet buffer.
333                  */
334                 vrx = paddr_guest2host(vd->vd_addr, vd->vd_len);
335                 buf = (uint8_t *)(vrx + 1);
336
337                 len = read(sc->vsc_tapfd, buf,
338                            vd->vd_len - sizeof(struct virtio_net_rxhdr));
339
340                 if (len < 0 && errno == EWOULDBLOCK) {
341                         break;
342                 }
343
344                 /*
345                  * The only valid field in the rx packet header is the
346                  * number of buffers, which is always 1 without TSO
347                  * support.
348                  */
349                 memset(vrx, 0, sizeof(struct virtio_net_rxhdr));
350                 vrx->vrh_bufs = 1;
351
352                 /*
353                  * Write this descriptor into the used ring
354                  */
355                 vu = &hq->hq_used_ring[uidx % hq->hq_size];
356                 vu->vu_idx = didx;
357                 vu->vu_tlen = len + sizeof(struct virtio_net_rxhdr);
358                 uidx++;
359                 aidx++;
360         }
361
362         /*
363          * Update the used pointer, and signal an interrupt if allowed
364          */
365         *hq->hq_used_idx = uidx;
366         hq->hq_cur_aidx = aidx;
367
368         if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) {
369                 if (use_msix) {
370                         pci_generate_msix(sc->vsc_pi,
371                                           sc->vsc_msix_table_idx[VTNET_RXQ]);
372                 } else {
373                         sc->vsc_isr |= 1;
374                         pci_generate_msi(sc->vsc_pi, 0);
375                 }
376         }
377 }
378
379 static void
380 pci_vtnet_tap_callback(int fd, enum ev_type type, void *param)
381 {
382         struct pci_vtnet_softc *sc = param;
383
384         pthread_mutex_lock(&sc->vsc_mtx);
385         pci_vtnet_tap_rx(sc);
386         pthread_mutex_unlock(&sc->vsc_mtx);
387
388 }
389
390 static void
391 pci_vtnet_ping_rxq(struct pci_vtnet_softc *sc)
392 {
393         /*
394          * A qnotify means that the rx process can now begin
395          */
396         if (sc->vsc_rx_ready == 0) {
397                 sc->vsc_rx_ready = 1;
398         }
399
400         /*
401          * If the rx queue was empty, attempt to receive a
402          * packet that was previously blocked due to no rx bufs
403          * available
404          */
405         if (sc->vsc_rxpend) {
406                 WPRINTF(("vtnet: rx resumed\n\r"));
407                 sc->vsc_rxpend = 0;
408                 pci_vtnet_tap_rx(sc);
409         }
410 }
411
412 static void
413 pci_vtnet_proctx(struct pci_vtnet_softc *sc, struct vring_hqueue *hq)
414 {
415         struct iovec iov[VTNET_MAXSEGS + 1];
416         struct virtio_desc *vd;
417         struct virtio_used *vu;
418         int i;
419         int plen;
420         int tlen;
421         int uidx, aidx, didx;
422
423         uidx = *hq->hq_used_idx;
424         aidx = hq->hq_cur_aidx;
425         didx = hq->hq_avail_ring[aidx % hq->hq_size];
426         assert(didx >= 0 && didx < hq->hq_size);
427
428         vd = &hq->hq_dtable[didx];
429
430         /*
431          * Run through the chain of descriptors, ignoring the
432          * first header descriptor. However, include the header
433          * length in the total length that will be put into the
434          * used queue.
435          */
436         tlen = vd->vd_len;
437         vd = &hq->hq_dtable[vd->vd_next];
438
439         for (i = 0, plen = 0;
440              i < VTNET_MAXSEGS;
441              i++, vd = &hq->hq_dtable[vd->vd_next]) {
442                 iov[i].iov_base = paddr_guest2host(vd->vd_addr, vd->vd_len);
443                 iov[i].iov_len = vd->vd_len;
444                 plen += vd->vd_len;
445                 tlen += vd->vd_len;
446
447                 if ((vd->vd_flags & VRING_DESC_F_NEXT) == 0)
448                         break;
449         }
450         assert(i < VTNET_MAXSEGS);
451
452         DPRINTF(("virtio: packet send, %d bytes, %d segs\n\r", plen, i + 1));
453         pci_vtnet_tap_tx(sc, iov, i + 1, plen);
454
455         /*
456          * Return this chain back to the host
457          */
458         vu = &hq->hq_used_ring[uidx % hq->hq_size];
459         vu->vu_idx = didx;
460         vu->vu_tlen = tlen;
461         hq->hq_cur_aidx = aidx + 1;
462         *hq->hq_used_idx = uidx + 1;
463
464         /*
465          * Generate an interrupt if able
466          */
467         if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) {
468                 if (use_msix) {
469                         pci_generate_msix(sc->vsc_pi,
470                                           sc->vsc_msix_table_idx[VTNET_TXQ]);
471                 } else {
472                         sc->vsc_isr |= 1;
473                         pci_generate_msi(sc->vsc_pi, 0);
474                 }
475         }       
476 }
477
478 static void
479 pci_vtnet_ping_txq(struct pci_vtnet_softc *sc)
480 {
481         struct vring_hqueue *hq = &sc->vsc_hq[VTNET_TXQ];
482         int i;
483         int ndescs;
484
485         /*
486          * Calculate number of ring entries to process
487          */
488         ndescs = hq_num_avail(hq);
489
490         if (ndescs == 0)
491                 return;
492
493         /*
494          * Run through all the entries, placing them into iovecs and
495          * sending when an end-of-packet is found
496          */
497         for (i = 0; i < ndescs; i++)
498                 pci_vtnet_proctx(sc, hq);
499 }
500
501 static void
502 pci_vtnet_ping_ctlq(struct pci_vtnet_softc *sc)
503 {
504
505         DPRINTF(("vtnet: control qnotify!\n\r"));       
506 }
507
508 static void
509 pci_vtnet_ring_init(struct pci_vtnet_softc *sc, uint64_t pfn)
510 {
511         struct vring_hqueue *hq;
512         int qnum = sc->vsc_curq;
513
514         assert(qnum < VTNET_MAXQ);
515
516         sc->vsc_pfn[qnum] = pfn << VRING_PFN;
517         
518         /*
519          * Set up host pointers to the various parts of the
520          * queue
521          */
522         hq = &sc->vsc_hq[qnum];
523         hq->hq_size = pci_vtnet_qsize(qnum);
524
525         hq->hq_dtable = paddr_guest2host(pfn << VRING_PFN,
526                                          vring_size(hq->hq_size));
527         hq->hq_avail_flags =  (uint16_t *)(hq->hq_dtable + hq->hq_size);
528         hq->hq_avail_idx = hq->hq_avail_flags + 1;
529         hq->hq_avail_ring = hq->hq_avail_flags + 2;
530         hq->hq_used_flags = (uint16_t *)roundup2((uintptr_t)hq->hq_avail_ring,
531                                                  VRING_ALIGN);
532         hq->hq_used_idx = hq->hq_used_flags + 1;
533         hq->hq_used_ring = (struct virtio_used *)(hq->hq_used_flags + 2);
534
535         /*
536          * Initialize queue indexes
537          */
538         hq->hq_cur_aidx = 0;
539 }
540
541 static int
542 pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
543 {
544         MD5_CTX mdctx;
545         unsigned char digest[16];
546         char nstr[80];
547         struct pci_vtnet_softc *sc;
548         const char *env_msi;
549
550         sc = malloc(sizeof(struct pci_vtnet_softc));
551         memset(sc, 0, sizeof(struct pci_vtnet_softc));
552
553         pi->pi_arg = sc;
554         sc->vsc_pi = pi;
555
556         pthread_mutex_init(&sc->vsc_mtx, NULL);
557  
558         /*
559          * Use MSI if set by user
560          */
561         if ((env_msi = getenv("BHYVE_USE_MSI")) != NULL) {
562                 if (strcasecmp(env_msi, "yes") == 0)
563                         use_msix = 0;
564         }
565
566         /*
567          * Attempt to open the tap device
568          */
569         sc->vsc_tapfd = -1;
570         if (opts != NULL) {
571                 char tbuf[80];
572
573                 strcpy(tbuf, "/dev/");
574                 strlcat(tbuf, opts, sizeof(tbuf));
575
576                 sc->vsc_tapfd = open(tbuf, O_RDWR);
577                 if (sc->vsc_tapfd == -1) {
578                         WPRINTF(("open of tap device %s failed\n", tbuf));
579                 } else {
580                         /*
581                          * Set non-blocking and register for read
582                          * notifications with the event loop
583                          */
584                         int opt = 1;
585                         if (ioctl(sc->vsc_tapfd, FIONBIO, &opt) < 0) {
586                                 WPRINTF(("tap device O_NONBLOCK failed\n"));
587                                 close(sc->vsc_tapfd);
588                                 sc->vsc_tapfd = -1;
589                         }
590
591                         sc->vsc_mevp = mevent_add(sc->vsc_tapfd,
592                                                   EVF_READ,
593                                                   pci_vtnet_tap_callback,
594                                                   sc);
595                         if (sc->vsc_mevp == NULL) {
596                                 WPRINTF(("Could not register event\n"));
597                                 close(sc->vsc_tapfd);
598                                 sc->vsc_tapfd = -1;
599                         }
600                 }               
601         }
602
603         /*
604          * The MAC address is the standard NetApp OUI of 00-a0-98,
605          * followed by an MD5 of the vm name. The slot/func number is
606          * prepended to this for slots other than 1:0, so that 
607          * a bootloader can netboot from the equivalent of slot 1.
608          */
609         if (pi->pi_slot == 1 && pi->pi_func == 0) {
610                 strncpy(nstr, vmname, sizeof(nstr));
611         } else {
612                 snprintf(nstr, sizeof(nstr), "%d-%d-%s", pi->pi_slot,
613                     pi->pi_func, vmname);
614         }
615
616         MD5Init(&mdctx);
617         MD5Update(&mdctx, nstr, strlen(nstr));
618         MD5Final(digest, &mdctx);
619
620         sc->vsc_macaddr[0] = 0x00;
621         sc->vsc_macaddr[1] = 0xa0;
622         sc->vsc_macaddr[2] = 0x98;
623         sc->vsc_macaddr[3] = digest[0];
624         sc->vsc_macaddr[4] = digest[1];
625         sc->vsc_macaddr[5] = digest[2];
626
627         /* initialize config space */
628         pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET);
629         pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR);
630         pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK);
631         pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET);
632         
633         if (use_msix) {
634                 /* MSI-X support */
635                 int i;
636
637                 for (i = 0; i < VTNET_MAXQ; i++)
638                         sc->vsc_msix_table_idx[i] = VIRTIO_MSI_NO_VECTOR;
639
640                 /*
641                  * BAR 1 used to map MSI-X table and PBA
642                  */
643                 if (pci_emul_add_msixcap(pi, VTNET_MAXQ, 1))
644                         return (1);
645         } else {
646                 /* MSI support */
647                 pci_emul_add_msicap(pi, 1);
648         }
649         
650         pci_emul_alloc_bar(pi, 0, PCIBAR_IO, VTNET_REGSZ);
651
652         return (0);
653 }
654
655 /*
656  * Function pointer array to handle queue notifications
657  */
658 static void (*pci_vtnet_qnotify[VTNET_MAXQ])(struct pci_vtnet_softc *) = {
659         pci_vtnet_ping_rxq,
660         pci_vtnet_ping_txq,
661         pci_vtnet_ping_ctlq
662 };
663
664 static uint64_t
665 vtnet_adjust_offset(struct pci_devinst *pi, uint64_t offset)
666 {
667         /*
668          * Device specific offsets used by guest would change based on
669          * whether MSI-X capability is enabled or not
670          */
671         if (!pci_msix_enabled(pi)) {
672                 if (offset >= VTCFG_R_MSIX)
673                         return (offset + (VTCFG_R_CFG1 - VTCFG_R_MSIX));
674         }
675
676         return (offset);
677 }
678
679 static void
680 pci_vtnet_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
681                 int baridx, uint64_t offset, int size, uint64_t value)
682 {
683         struct pci_vtnet_softc *sc = pi->pi_arg;
684         void *ptr;
685
686         if (use_msix) {
687                 if (baridx == pci_msix_table_bar(pi) ||
688                     baridx == pci_msix_pba_bar(pi)) {
689                         pci_emul_msix_twrite(pi, offset, size, value);
690                         return;
691                 }
692         }
693
694         assert(baridx == 0);
695
696         if (offset + size > pci_vtnet_iosize(pi)) {
697                 DPRINTF(("vtnet_write: 2big, offset %ld size %d\n",
698                          offset, size));
699                 return;
700         }
701
702         pthread_mutex_lock(&sc->vsc_mtx);
703
704         offset = vtnet_adjust_offset(pi, offset);
705
706         switch (offset) {
707         case VTCFG_R_GUESTCAP:
708                 assert(size == 4);
709                 sc->vsc_features = value & VTNET_S_HOSTCAPS;
710                 break;
711         case VTCFG_R_PFN:
712                 assert(size == 4);
713                 pci_vtnet_ring_init(sc, value);
714                 break;
715         case VTCFG_R_QSEL:
716                 assert(size == 2);
717                 assert(value < VTNET_MAXQ);
718                 sc->vsc_curq = value;
719                 break;
720         case VTCFG_R_QNOTIFY:
721                 assert(size == 2);
722                 assert(value < VTNET_MAXQ);
723                 (*pci_vtnet_qnotify[value])(sc);
724                 break;
725         case VTCFG_R_STATUS:
726                 assert(size == 1);
727                 pci_vtnet_update_status(sc, value);
728                 break;
729         case VTCFG_R_CFGVEC:
730                 assert(size == 2);
731                 sc->vsc_msix_table_idx[VTNET_CTLQ] = value;
732                 break;
733         case VTCFG_R_QVEC:
734                 assert(size == 2);
735                 assert(sc->vsc_curq != VTNET_CTLQ);
736                 sc->vsc_msix_table_idx[sc->vsc_curq] = value;
737                 break;
738         case VTNET_R_CFG0:
739         case VTNET_R_CFG1:
740         case VTNET_R_CFG2:
741         case VTNET_R_CFG3:
742         case VTNET_R_CFG4:
743         case VTNET_R_CFG5:
744                 assert((size + offset) <= (VTNET_R_CFG5 + 1));
745                 ptr = &sc->vsc_macaddr[offset - VTNET_R_CFG0];
746                 /*
747                  * The driver is allowed to change the MAC address
748                  */
749                 sc->vsc_macaddr[offset - VTNET_R_CFG0] = value;
750                 if (size == 1) {
751                         *(uint8_t *) ptr = value;
752                 } else if (size == 2) {
753                         *(uint16_t *) ptr = value;
754                 } else {
755                         *(uint32_t *) ptr = value;
756                 }
757                 break;
758         case VTCFG_R_HOSTCAP:
759         case VTCFG_R_QNUM:
760         case VTCFG_R_ISR:
761         case VTNET_R_CFG6:
762         case VTNET_R_CFG7:
763                 DPRINTF(("vtnet: write to readonly reg %ld\n\r", offset));
764                 break;
765         default:
766                 DPRINTF(("vtnet: unknown i/o write offset %ld\n\r", offset));
767                 value = 0;
768                 break;
769         }
770
771         pthread_mutex_unlock(&sc->vsc_mtx);
772 }
773
774 uint64_t
775 pci_vtnet_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
776                int baridx, uint64_t offset, int size)
777 {
778         struct pci_vtnet_softc *sc = pi->pi_arg;
779         void *ptr;
780         uint64_t value;
781
782         if (use_msix) {
783                 if (baridx == pci_msix_table_bar(pi) ||
784                     baridx == pci_msix_pba_bar(pi)) {
785                         return (pci_emul_msix_tread(pi, offset, size));
786                 }
787         }
788
789         assert(baridx == 0);
790
791         if (offset + size > pci_vtnet_iosize(pi)) {
792                 DPRINTF(("vtnet_read: 2big, offset %ld size %d\n",
793                          offset, size));
794                 return (0);
795         }
796
797         pthread_mutex_lock(&sc->vsc_mtx);
798
799         offset = vtnet_adjust_offset(pi, offset);
800
801         switch (offset) {
802         case VTCFG_R_HOSTCAP:
803                 assert(size == 4);
804                 value = VTNET_S_HOSTCAPS;
805                 break;
806         case VTCFG_R_GUESTCAP:
807                 assert(size == 4);
808                 value = sc->vsc_features; /* XXX never read ? */
809                 break;
810         case VTCFG_R_PFN:
811                 assert(size == 4);
812                 value = sc->vsc_pfn[sc->vsc_curq] >> VRING_PFN;
813                 break;
814         case VTCFG_R_QNUM:
815                 assert(size == 2);
816                 value = pci_vtnet_qsize(sc->vsc_curq);
817                 break;
818         case VTCFG_R_QSEL:
819                 assert(size == 2);
820                 value = sc->vsc_curq;  /* XXX never read ? */
821                 break;
822         case VTCFG_R_QNOTIFY:
823                 assert(size == 2);
824                 value = sc->vsc_curq;  /* XXX never read ? */
825                 break;
826         case VTCFG_R_STATUS:
827                 assert(size == 1);
828                 value = sc->vsc_status;
829                 break;
830         case VTCFG_R_ISR:
831                 assert(size == 1);
832                 value = sc->vsc_isr;
833                 sc->vsc_isr = 0;     /* a read clears this flag */
834                 break;
835         case VTCFG_R_CFGVEC:
836                 assert(size == 2);
837                 value = sc->vsc_msix_table_idx[VTNET_CTLQ];
838                 break;
839         case VTCFG_R_QVEC:
840                 assert(size == 2);
841                 assert(sc->vsc_curq != VTNET_CTLQ);
842                 value = sc->vsc_msix_table_idx[sc->vsc_curq];
843                 break;
844         case VTNET_R_CFG0:
845         case VTNET_R_CFG1:
846         case VTNET_R_CFG2:
847         case VTNET_R_CFG3:
848         case VTNET_R_CFG4:
849         case VTNET_R_CFG5:
850                 assert((size + offset) <= (VTNET_R_CFG5 + 1));
851                 ptr = &sc->vsc_macaddr[offset - VTNET_R_CFG0];
852                 if (size == 1) {
853                         value = *(uint8_t *) ptr;
854                 } else if (size == 2) {
855                         value = *(uint16_t *) ptr;
856                 } else {
857                         value = *(uint32_t *) ptr;
858                 }
859                 break;
860         case VTNET_R_CFG6:
861                 assert(size != 4);
862                 value = 0x01; /* XXX link always up */
863                 break;
864         case VTNET_R_CFG7:
865                 assert(size == 1);
866                 value = 0; /* XXX link status in LSB */
867                 break;
868         default:
869                 DPRINTF(("vtnet: unknown i/o read offset %ld\n\r", offset));
870                 value = 0;
871                 break;
872         }
873
874         pthread_mutex_unlock(&sc->vsc_mtx);
875
876         return (value);
877 }
878
879 struct pci_devemu pci_de_vnet = {
880         .pe_emu =       "virtio-net",
881         .pe_init =      pci_vtnet_init,
882         .pe_barwrite =  pci_vtnet_write,
883         .pe_barread =   pci_vtnet_read
884 };
885 PCI_EMUL_SET(pci_de_vnet);