pci_virtio_net.c revision 245652
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 20 63#define VTNET_R_CFG1 21 64#define VTNET_R_CFG2 22 65#define VTNET_R_CFG3 23 66#define VTNET_R_CFG4 24 67#define VTNET_R_CFG5 25 68#define VTNET_R_CFG6 26 69#define VTNET_R_CFG7 27 70#define VTNET_R_MAX 27 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 91struct vring_hqueue { 92 /* Internal state */ 93 uint16_t hq_size; 94 uint16_t hq_cur_aidx; /* trails behind 'avail_idx' */ 95 96 /* Host-context pointers to the queue */ 97 struct virtio_desc *hq_dtable; 98 uint16_t *hq_avail_flags; 99 uint16_t *hq_avail_idx; /* monotonically increasing */ 100 uint16_t *hq_avail_ring; 101 102 uint16_t *hq_used_flags; 103 uint16_t *hq_used_idx; /* monotonically increasing */ 104 struct virtio_used *hq_used_ring; 105}; 106 107/* 108 * Fixed network header size 109 */ 110struct virtio_net_rxhdr { 111 uint8_t vrh_flags; 112 uint8_t vrh_gso_type; 113 uint16_t vrh_hdr_len; 114 uint16_t vrh_gso_size; 115 uint16_t vrh_csum_start; 116 uint16_t vrh_csum_offset; 117 uint16_t vrh_bufs; 118} __packed; 119 120/* 121 * Debug printf 122 */ 123static int pci_vtnet_debug; 124#define DPRINTF(params) if (pci_vtnet_debug) printf params 125#define WPRINTF(params) printf params 126 127/* 128 * Per-device softc 129 */ 130struct pci_vtnet_softc { 131 struct pci_devinst *vsc_pi; 132 pthread_mutex_t vsc_mtx; 133 struct mevent *vsc_mevp; 134 135 int vsc_curq; 136 int vsc_status; 137 int vsc_isr; 138 int vsc_tapfd; 139 int vsc_rx_ready; 140 int vsc_rxpend; 141 142 uint32_t vsc_features; 143 uint8_t vsc_macaddr[6]; 144 145 uint64_t vsc_pfn[VTNET_MAXQ]; 146 struct vring_hqueue vsc_hq[VTNET_MAXQ]; 147}; 148 149/* 150 * Return the number of available descriptors in the vring taking care 151 * of the 16-bit index wraparound. 152 */ 153static int 154hq_num_avail(struct vring_hqueue *hq) 155{ 156 int ndesc; 157 158 if (*hq->hq_avail_idx >= hq->hq_cur_aidx) 159 ndesc = *hq->hq_avail_idx - hq->hq_cur_aidx; 160 else 161 ndesc = UINT16_MAX - hq->hq_cur_aidx + *hq->hq_avail_idx + 1; 162 163 assert(ndesc >= 0 && ndesc <= hq->hq_size); 164 165 return (ndesc); 166} 167 168static uint16_t 169pci_vtnet_qsize(int qnum) 170{ 171 /* XXX no ctl queue currently */ 172 if (qnum == VTNET_CTLQ) { 173 return (0); 174 } 175 176 /* XXX fixed currently. Maybe different for tx/rx/ctl */ 177 return (VTNET_RINGSZ); 178} 179 180static void 181pci_vtnet_ring_reset(struct pci_vtnet_softc *sc, int ring) 182{ 183 struct vring_hqueue *hq; 184 185 assert(ring < VTNET_MAXQ); 186 187 hq = &sc->vsc_hq[ring]; 188 189 /* 190 * Reset all soft state 191 */ 192 hq->hq_cur_aidx = 0; 193} 194 195static void 196pci_vtnet_update_status(struct pci_vtnet_softc *sc, uint32_t value) 197{ 198 199 if (value == 0) { 200 DPRINTF(("vtnet: device reset requested !\n")); 201 pci_vtnet_ring_reset(sc, VTNET_RXQ); 202 pci_vtnet_ring_reset(sc, VTNET_TXQ); 203 sc->vsc_rx_ready = 0; 204 } 205 206 sc->vsc_status = value; 207} 208 209/* 210 * Called to send a buffer chain out to the tap device 211 */ 212static void 213pci_vtnet_tap_tx(struct pci_vtnet_softc *sc, struct iovec *iov, int iovcnt, 214 int len) 215{ 216 char pad[60]; 217 218 if (sc->vsc_tapfd == -1) 219 return; 220 221 /* 222 * If the length is < 60, pad out to that and add the 223 * extra zero'd segment to the iov. It is guaranteed that 224 * there is always an extra iov available by the caller. 225 */ 226 if (len < 60) { 227 memset(pad, 0, 60 - len); 228 iov[iovcnt].iov_base = pad; 229 iov[iovcnt].iov_len = 60 - len; 230 iovcnt++; 231 } 232 (void) writev(sc->vsc_tapfd, iov, iovcnt); 233} 234 235/* 236 * Called when there is read activity on the tap file descriptor. 237 * Each buffer posted by the guest is assumed to be able to contain 238 * an entire ethernet frame + rx header. 239 * MP note: the dummybuf is only used for discarding frames, so there 240 * is no need for it to be per-vtnet or locked. 241 */ 242static uint8_t dummybuf[2048]; 243 244static void 245pci_vtnet_tap_rx(struct pci_vtnet_softc *sc) 246{ 247 struct virtio_desc *vd; 248 struct virtio_used *vu; 249 struct vring_hqueue *hq; 250 struct virtio_net_rxhdr *vrx; 251 uint8_t *buf; 252 int i; 253 int len; 254 int ndescs; 255 int didx, uidx, aidx; /* descriptor, avail and used index */ 256 257 /* 258 * Should never be called without a valid tap fd 259 */ 260 assert(sc->vsc_tapfd != -1); 261 262 /* 263 * But, will be called when the rx ring hasn't yet 264 * been set up. 265 */ 266 if (sc->vsc_rx_ready == 0) { 267 /* 268 * Drop the packet and try later. 269 */ 270 (void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf)); 271 return; 272 } 273 274 /* 275 * Calculate the number of available rx buffers 276 */ 277 hq = &sc->vsc_hq[VTNET_RXQ]; 278 279 ndescs = hq_num_avail(hq); 280 281 if (ndescs == 0) { 282 /* 283 * Need to wait for host notification to read 284 */ 285 if (sc->vsc_rxpend == 0) { 286 WPRINTF(("vtnet: no rx descriptors !\n")); 287 sc->vsc_rxpend = 1; 288 } 289 290 /* 291 * Drop the packet and try later 292 */ 293 (void) read(sc->vsc_tapfd, dummybuf, sizeof(dummybuf)); 294 return; 295 } 296 297 aidx = hq->hq_cur_aidx; 298 uidx = *hq->hq_used_idx; 299 for (i = 0; i < ndescs; i++) { 300 /* 301 * 'aidx' indexes into the an array of descriptor indexes 302 */ 303 didx = hq->hq_avail_ring[aidx % hq->hq_size]; 304 assert(didx >= 0 && didx < hq->hq_size); 305 306 vd = &hq->hq_dtable[didx]; 307 308 /* 309 * Get a pointer to the rx header, and use the 310 * data immediately following it for the packet buffer. 311 */ 312 vrx = (struct virtio_net_rxhdr *)paddr_guest2host(vd->vd_addr); 313 buf = (uint8_t *)(vrx + 1); 314 315 len = read(sc->vsc_tapfd, buf, 316 vd->vd_len - sizeof(struct virtio_net_rxhdr)); 317 318 if (len < 0 && errno == EWOULDBLOCK) { 319 break; 320 } 321 322 /* 323 * The only valid field in the rx packet header is the 324 * number of buffers, which is always 1 without TSO 325 * support. 326 */ 327 memset(vrx, 0, sizeof(struct virtio_net_rxhdr)); 328 vrx->vrh_bufs = 1; 329 330 /* 331 * Write this descriptor into the used ring 332 */ 333 vu = &hq->hq_used_ring[uidx % hq->hq_size]; 334 vu->vu_idx = didx; 335 vu->vu_tlen = len + sizeof(struct virtio_net_rxhdr); 336 uidx++; 337 aidx++; 338 } 339 340 /* 341 * Update the used pointer, and signal an interrupt if allowed 342 */ 343 *hq->hq_used_idx = uidx; 344 hq->hq_cur_aidx = aidx; 345 346 if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) { 347 sc->vsc_isr |= 1; 348 pci_generate_msi(sc->vsc_pi, 0); 349 } 350} 351 352static void 353pci_vtnet_tap_callback(int fd, enum ev_type type, void *param) 354{ 355 struct pci_vtnet_softc *sc = param; 356 357 pthread_mutex_lock(&sc->vsc_mtx); 358 pci_vtnet_tap_rx(sc); 359 pthread_mutex_unlock(&sc->vsc_mtx); 360 361} 362 363static void 364pci_vtnet_ping_rxq(struct pci_vtnet_softc *sc) 365{ 366 /* 367 * A qnotify means that the rx process can now begin 368 */ 369 if (sc->vsc_rx_ready == 0) { 370 sc->vsc_rx_ready = 1; 371 } 372 373 /* 374 * If the rx queue was empty, attempt to receive a 375 * packet that was previously blocked due to no rx bufs 376 * available 377 */ 378 if (sc->vsc_rxpend) { 379 WPRINTF(("vtnet: rx resumed\n\r")); 380 sc->vsc_rxpend = 0; 381 pci_vtnet_tap_rx(sc); 382 } 383} 384 385static void 386pci_vtnet_proctx(struct pci_vtnet_softc *sc, struct vring_hqueue *hq) 387{ 388 struct iovec iov[VTNET_MAXSEGS + 1]; 389 struct virtio_desc *vd; 390 struct virtio_used *vu; 391 int i; 392 int plen; 393 int tlen; 394 int uidx, aidx, didx; 395 396 uidx = *hq->hq_used_idx; 397 aidx = hq->hq_cur_aidx; 398 didx = hq->hq_avail_ring[aidx % hq->hq_size]; 399 assert(didx >= 0 && didx < hq->hq_size); 400 401 vd = &hq->hq_dtable[didx]; 402 403 /* 404 * Run through the chain of descriptors, ignoring the 405 * first header descriptor. However, include the header 406 * length in the total length that will be put into the 407 * used queue. 408 */ 409 tlen = vd->vd_len; 410 vd = &hq->hq_dtable[vd->vd_next]; 411 412 for (i = 0, plen = 0; 413 i < VTNET_MAXSEGS; 414 i++, vd = &hq->hq_dtable[vd->vd_next]) { 415 iov[i].iov_base = paddr_guest2host(vd->vd_addr); 416 iov[i].iov_len = vd->vd_len; 417 plen += vd->vd_len; 418 tlen += vd->vd_len; 419 420 if ((vd->vd_flags & VRING_DESC_F_NEXT) == 0) 421 break; 422 } 423 assert(i < VTNET_MAXSEGS); 424 425 DPRINTF(("virtio: packet send, %d bytes, %d segs\n\r", plen, i + 1)); 426 pci_vtnet_tap_tx(sc, iov, i + 1, plen); 427 428 /* 429 * Return this chain back to the host 430 */ 431 vu = &hq->hq_used_ring[uidx % hq->hq_size]; 432 vu->vu_idx = didx; 433 vu->vu_tlen = tlen; 434 hq->hq_cur_aidx = aidx + 1; 435 *hq->hq_used_idx = uidx + 1; 436 437 /* 438 * Generate an interrupt if able 439 */ 440 if ((*hq->hq_avail_flags & VRING_AVAIL_F_NO_INTERRUPT) == 0) { 441 sc->vsc_isr |= 1; 442 pci_generate_msi(sc->vsc_pi, 0); 443 } 444} 445 446static void 447pci_vtnet_ping_txq(struct pci_vtnet_softc *sc) 448{ 449 struct vring_hqueue *hq = &sc->vsc_hq[VTNET_TXQ]; 450 int i; 451 int ndescs; 452 453 /* 454 * Calculate number of ring entries to process 455 */ 456 ndescs = hq_num_avail(hq); 457 458 if (ndescs == 0) 459 return; 460 461 /* 462 * Run through all the entries, placing them into iovecs and 463 * sending when an end-of-packet is found 464 */ 465 for (i = 0; i < ndescs; i++) 466 pci_vtnet_proctx(sc, hq); 467} 468 469static void 470pci_vtnet_ping_ctlq(struct pci_vtnet_softc *sc) 471{ 472 473 DPRINTF(("vtnet: control qnotify!\n\r")); 474} 475 476static void 477pci_vtnet_ring_init(struct pci_vtnet_softc *sc, uint64_t pfn) 478{ 479 struct vring_hqueue *hq; 480 int qnum = sc->vsc_curq; 481 482 assert(qnum < VTNET_MAXQ); 483 484 sc->vsc_pfn[qnum] = pfn << VRING_PFN; 485 486 /* 487 * Set up host pointers to the various parts of the 488 * queue 489 */ 490 hq = &sc->vsc_hq[qnum]; 491 hq->hq_size = pci_vtnet_qsize(qnum); 492 493 hq->hq_dtable = paddr_guest2host(pfn << VRING_PFN); 494 hq->hq_avail_flags = (uint16_t *)(hq->hq_dtable + hq->hq_size); 495 hq->hq_avail_idx = hq->hq_avail_flags + 1; 496 hq->hq_avail_ring = hq->hq_avail_flags + 2; 497 hq->hq_used_flags = (uint16_t *)roundup2((uintptr_t)hq->hq_avail_ring, 498 VRING_ALIGN); 499 hq->hq_used_idx = hq->hq_used_flags + 1; 500 hq->hq_used_ring = (struct virtio_used *)(hq->hq_used_flags + 2); 501 502 /* 503 * Initialize queue indexes 504 */ 505 hq->hq_cur_aidx = 0; 506} 507 508static int 509pci_vtnet_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) 510{ 511 MD5_CTX mdctx; 512 unsigned char digest[16]; 513 char nstr[80]; 514 struct pci_vtnet_softc *sc; 515 516 /* 517 * Access to guest memory is required. Fail if 518 * memory not mapped 519 */ 520 if (paddr_guest2host(0) == NULL) 521 return (1); 522 523 sc = malloc(sizeof(struct pci_vtnet_softc)); 524 memset(sc, 0, sizeof(struct pci_vtnet_softc)); 525 526 pi->pi_arg = sc; 527 sc->vsc_pi = pi; 528 529 pthread_mutex_init(&sc->vsc_mtx, NULL); 530 531 /* 532 * Attempt to open the tap device 533 */ 534 sc->vsc_tapfd = -1; 535 if (opts != NULL) { 536 char tbuf[80]; 537 538 strcpy(tbuf, "/dev/"); 539 strlcat(tbuf, opts, sizeof(tbuf)); 540 541 sc->vsc_tapfd = open(tbuf, O_RDWR); 542 if (sc->vsc_tapfd == -1) { 543 WPRINTF(("open of tap device %s failed\n", tbuf)); 544 } else { 545 /* 546 * Set non-blocking and register for read 547 * notifications with the event loop 548 */ 549 int opt = 1; 550 if (ioctl(sc->vsc_tapfd, FIONBIO, &opt) < 0) { 551 WPRINTF(("tap device O_NONBLOCK failed\n")); 552 close(sc->vsc_tapfd); 553 sc->vsc_tapfd = -1; 554 } 555 556 sc->vsc_mevp = mevent_add(sc->vsc_tapfd, 557 EVF_READ, 558 pci_vtnet_tap_callback, 559 sc); 560 if (sc->vsc_mevp == NULL) { 561 WPRINTF(("Could not register event\n")); 562 close(sc->vsc_tapfd); 563 sc->vsc_tapfd = -1; 564 } 565 } 566 } 567 568 /* 569 * The MAC address is the standard NetApp OUI of 00-a0-98, 570 * followed by an MD5 of the vm name. The slot/func number is 571 * prepended to this for slots other than 1:0, so that 572 * a bootloader can netboot from the equivalent of slot 1. 573 */ 574 if (pi->pi_slot == 1 && pi->pi_func == 0) { 575 strncpy(nstr, vmname, sizeof(nstr)); 576 } else { 577 snprintf(nstr, sizeof(nstr), "%d-%d-%s", pi->pi_slot, 578 pi->pi_func, vmname); 579 } 580 581 MD5Init(&mdctx); 582 MD5Update(&mdctx, nstr, strlen(nstr)); 583 MD5Final(digest, &mdctx); 584 585 sc->vsc_macaddr[0] = 0x00; 586 sc->vsc_macaddr[1] = 0xa0; 587 sc->vsc_macaddr[2] = 0x98; 588 sc->vsc_macaddr[3] = digest[0]; 589 sc->vsc_macaddr[4] = digest[1]; 590 sc->vsc_macaddr[5] = digest[2]; 591 592 /* initialize config space */ 593 pci_set_cfgdata16(pi, PCIR_DEVICE, VIRTIO_DEV_NET); 594 pci_set_cfgdata16(pi, PCIR_VENDOR, VIRTIO_VENDOR); 595 pci_set_cfgdata8(pi, PCIR_CLASS, PCIC_NETWORK); 596 pci_set_cfgdata16(pi, PCIR_SUBDEV_0, VIRTIO_TYPE_NET); 597 pci_emul_add_msicap(pi, 1); 598 pci_emul_alloc_bar(pi, 0, PCIBAR_IO, VTNET_REGSZ); 599 600 return (0); 601} 602 603/* 604 * Function pointer array to handle queue notifications 605 */ 606static void (*pci_vtnet_qnotify[VTNET_MAXQ])(struct pci_vtnet_softc *) = { 607 pci_vtnet_ping_rxq, 608 pci_vtnet_ping_txq, 609 pci_vtnet_ping_ctlq 610}; 611 612static void 613pci_vtnet_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 614 int baridx, uint64_t offset, int size, uint64_t value) 615{ 616 struct pci_vtnet_softc *sc = pi->pi_arg; 617 void *ptr; 618 619 assert(baridx == 0); 620 621 if (offset + size > VTNET_REGSZ) { 622 DPRINTF(("vtnet_write: 2big, offset %ld size %d\n", 623 offset, size)); 624 return; 625 } 626 627 pthread_mutex_lock(&sc->vsc_mtx); 628 629 switch (offset) { 630 case VTCFG_R_GUESTCAP: 631 assert(size == 4); 632 sc->vsc_features = value & VTNET_S_HOSTCAPS; 633 break; 634 case VTCFG_R_PFN: 635 assert(size == 4); 636 pci_vtnet_ring_init(sc, value); 637 break; 638 case VTCFG_R_QSEL: 639 assert(size == 2); 640 assert(value < VTNET_MAXQ); 641 sc->vsc_curq = value; 642 break; 643 case VTCFG_R_QNOTIFY: 644 assert(size == 2); 645 assert(value < VTNET_MAXQ); 646 (*pci_vtnet_qnotify[value])(sc); 647 break; 648 case VTCFG_R_STATUS: 649 assert(size == 1); 650 pci_vtnet_update_status(sc, value); 651 break; 652 case VTNET_R_CFG0: 653 case VTNET_R_CFG1: 654 case VTNET_R_CFG2: 655 case VTNET_R_CFG3: 656 case VTNET_R_CFG4: 657 case VTNET_R_CFG5: 658 assert((size + offset) <= (VTNET_R_CFG5 + 1)); 659 ptr = &sc->vsc_macaddr[offset - VTNET_R_CFG0]; 660 /* 661 * The driver is allowed to change the MAC address 662 */ 663 sc->vsc_macaddr[offset - VTNET_R_CFG0] = value; 664 if (size == 1) { 665 *(uint8_t *) ptr = value; 666 } else if (size == 2) { 667 *(uint16_t *) ptr = value; 668 } else { 669 *(uint32_t *) ptr = value; 670 } 671 break; 672 case VTCFG_R_HOSTCAP: 673 case VTCFG_R_QNUM: 674 case VTCFG_R_ISR: 675 case VTNET_R_CFG6: 676 case VTNET_R_CFG7: 677 DPRINTF(("vtnet: write to readonly reg %ld\n\r", offset)); 678 break; 679 default: 680 DPRINTF(("vtnet: unknown i/o write offset %ld\n\r", offset)); 681 value = 0; 682 break; 683 } 684 685 pthread_mutex_unlock(&sc->vsc_mtx); 686} 687 688uint64_t 689pci_vtnet_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 690 int baridx, uint64_t offset, int size) 691{ 692 struct pci_vtnet_softc *sc = pi->pi_arg; 693 void *ptr; 694 uint64_t value; 695 696 assert(baridx == 0); 697 698 if (offset + size > VTNET_REGSZ) { 699 DPRINTF(("vtnet_read: 2big, offset %ld size %d\n", 700 offset, size)); 701 return (0); 702 } 703 704 pthread_mutex_lock(&sc->vsc_mtx); 705 706 switch (offset) { 707 case VTCFG_R_HOSTCAP: 708 assert(size == 4); 709 value = VTNET_S_HOSTCAPS; 710 break; 711 case VTCFG_R_GUESTCAP: 712 assert(size == 4); 713 value = sc->vsc_features; /* XXX never read ? */ 714 break; 715 case VTCFG_R_PFN: 716 assert(size == 4); 717 value = sc->vsc_pfn[sc->vsc_curq] >> VRING_PFN; 718 break; 719 case VTCFG_R_QNUM: 720 assert(size == 2); 721 value = pci_vtnet_qsize(sc->vsc_curq); 722 break; 723 case VTCFG_R_QSEL: 724 assert(size == 2); 725 value = sc->vsc_curq; /* XXX never read ? */ 726 break; 727 case VTCFG_R_QNOTIFY: 728 assert(size == 2); 729 value = sc->vsc_curq; /* XXX never read ? */ 730 break; 731 case VTCFG_R_STATUS: 732 assert(size == 1); 733 value = sc->vsc_status; 734 break; 735 case VTCFG_R_ISR: 736 assert(size == 1); 737 value = sc->vsc_isr; 738 sc->vsc_isr = 0; /* a read clears this flag */ 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 if (size == 1) { 749 value = *(uint8_t *) ptr; 750 } else if (size == 2) { 751 value = *(uint16_t *) ptr; 752 } else { 753 value = *(uint32_t *) ptr; 754 } 755 break; 756 case VTNET_R_CFG6: 757 assert(size != 4); 758 value = 0x01; /* XXX link always up */ 759 break; 760 case VTNET_R_CFG7: 761 assert(size == 1); 762 value = 0; /* XXX link status in LSB */ 763 break; 764 default: 765 DPRINTF(("vtnet: unknown i/o read offset %ld\n\r", offset)); 766 value = 0; 767 break; 768 } 769 770 pthread_mutex_unlock(&sc->vsc_mtx); 771 772 return (value); 773} 774 775struct pci_devemu pci_de_vnet = { 776 .pe_emu = "virtio-net", 777 .pe_init = pci_vtnet_init, 778 .pe_barwrite = pci_vtnet_write, 779 .pe_barread = pci_vtnet_read 780}; 781PCI_EMUL_SET(pci_de_vnet); 782