pci_passthru.c revision 245749
1207753Smm/*- 2207753Smm * Copyright (c) 2011 NetApp, Inc. 3207753Smm * All rights reserved. 4207753Smm * 5207753Smm * Redistribution and use in source and binary forms, with or without 6207753Smm * modification, are permitted provided that the following conditions 7207753Smm * are met: 8207753Smm * 1. Redistributions of source code must retain the above copyright 9207753Smm * notice, this list of conditions and the following disclaimer. 10207753Smm * 2. Redistributions in binary form must reproduce the above copyright 11207753Smm * notice, this list of conditions and the following disclaimer in the 12207753Smm * documentation and/or other materials provided with the distribution. 13207753Smm * 14207753Smm * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 15292588Sdelphij * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16292588Sdelphij * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17292588Sdelphij * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 18292588Sdelphij * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19292588Sdelphij * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20292588Sdelphij * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21312518Sdelphij * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22312518Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23312518Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24312518Sdelphij * SUCH DAMAGE. 25292588Sdelphij * 26292588Sdelphij * $FreeBSD: head/usr.sbin/bhyve/pci_passthru.c 245749 2013-01-21 22:07:05Z neel $ 27292588Sdelphij */ 28292588Sdelphij 29292588Sdelphij#include <sys/cdefs.h> 30292588Sdelphij__FBSDID("$FreeBSD: head/usr.sbin/bhyve/pci_passthru.c 245749 2013-01-21 22:07:05Z neel $"); 31207753Smm 32207753Smm#include <sys/param.h> 33207753Smm#include <sys/types.h> 34207753Smm#include <sys/pciio.h> 35207753Smm#include <sys/ioctl.h> 36207753Smm 37207753Smm#include <dev/io/iodev.h> 38213700Smm#include <dev/pci/pcireg.h> 39213700Smm 40213700Smm#include <machine/iodev.h> 41213700Smm 42213700Smm#include <stdio.h> 43207753Smm#include <stdlib.h> 44207753Smm#include <string.h> 45207753Smm#include <errno.h> 46207753Smm#include <fcntl.h> 47207753Smm#include <unistd.h> 48207753Smm 49207753Smm#include <machine/vmm.h> 50207753Smm#include <vmmapi.h> 51292588Sdelphij#include "pci_emul.h" 52292588Sdelphij#include "mem.h" 53292588Sdelphij 54292588Sdelphij#ifndef _PATH_DEVPCI 55292588Sdelphij#define _PATH_DEVPCI "/dev/pci" 56312518Sdelphij#endif 57312518Sdelphij 58312518Sdelphij#ifndef _PATH_DEVIO 59312518Sdelphij#define _PATH_DEVIO "/dev/io" 60312518Sdelphij#endif 61292588Sdelphij 62292588Sdelphij#define LEGACY_SUPPORT 1 63292588Sdelphij 64292588Sdelphij#define MSIX_TABLE_COUNT(ctrl) (((ctrl) & PCIM_MSIXCTRL_TABLE_SIZE) + 1) 65292588Sdelphij#define MSIX_CAPLEN 12 66292588Sdelphij 67292588Sdelphijstatic int pcifd = -1; 68292588Sdelphijstatic int iofd = -1; 69292588Sdelphij 70292588Sdelphijstruct passthru_softc { 71292588Sdelphij struct pci_devinst *psc_pi; 72292588Sdelphij struct pcibar psc_bar[PCI_BARMAX + 1]; 73292588Sdelphij struct { 74292588Sdelphij int capoff; 75207753Smm int msgctrl; 76207753Smm int emulated; 77207753Smm } psc_msi; 78207753Smm struct { 79207753Smm int capoff; 80213700Smm } psc_msix; 81207753Smm struct pcisel psc_sel; 82207753Smm}; 83207753Smm 84207753Smmstatic int 85207753Smmmsi_caplen(int msgctrl) 86207753Smm{ 87207753Smm int len; 88207753Smm 89207753Smm len = 10; /* minimum length of msi capability */ 90207753Smm 91213700Smm if (msgctrl & PCIM_MSICTRL_64BIT) 92213700Smm len += 4; 93213700Smm 94213700Smm#if 0 95213700Smm /* 96213700Smm * Ignore the 'mask' and 'pending' bits in the MSI capability. 97207753Smm * We'll let the guest manipulate them directly. 98207753Smm */ 99207753Smm if (msgctrl & PCIM_MSICTRL_VECTOR) 100207753Smm len += 10; 101#endif 102 103 return (len); 104} 105 106static uint32_t 107read_config(const struct pcisel *sel, long reg, int width) 108{ 109 struct pci_io pi; 110 111 bzero(&pi, sizeof(pi)); 112 pi.pi_sel = *sel; 113 pi.pi_reg = reg; 114 pi.pi_width = width; 115 116 if (ioctl(pcifd, PCIOCREAD, &pi) < 0) 117 return (0); /* XXX */ 118 else 119 return (pi.pi_data); 120} 121 122static void 123write_config(const struct pcisel *sel, long reg, int width, uint32_t data) 124{ 125 struct pci_io pi; 126 127 bzero(&pi, sizeof(pi)); 128 pi.pi_sel = *sel; 129 pi.pi_reg = reg; 130 pi.pi_width = width; 131 pi.pi_data = data; 132 133 (void)ioctl(pcifd, PCIOCWRITE, &pi); /* XXX */ 134} 135 136#ifdef LEGACY_SUPPORT 137static int 138passthru_add_msicap(struct pci_devinst *pi, int msgnum, int nextptr) 139{ 140 int capoff, i; 141 struct msicap msicap; 142 u_char *capdata; 143 144 pci_populate_msicap(&msicap, msgnum, nextptr); 145 146 /* 147 * XXX 148 * Copy the msi capability structure in the last 16 bytes of the 149 * config space. This is wrong because it could shadow something 150 * useful to the device. 151 */ 152 capoff = 256 - roundup(sizeof(msicap), 4); 153 capdata = (u_char *)&msicap; 154 for (i = 0; i < sizeof(msicap); i++) 155 pci_set_cfgdata8(pi, capoff + i, capdata[i]); 156 157 return (capoff); 158} 159#endif /* LEGACY_SUPPORT */ 160 161static int 162cfginitmsi(struct passthru_softc *sc) 163{ 164 int i, ptr, capptr, cap, sts, caplen, table_size; 165 uint32_t u32; 166 struct pcisel sel; 167 struct pci_devinst *pi; 168 struct msixcap msixcap; 169 uint32_t *msixcap_ptr; 170 171 pi = sc->psc_pi; 172 sel = sc->psc_sel; 173 174 /* 175 * Parse the capabilities and cache the location of the MSI 176 * and MSI-X capabilities. 177 */ 178 sts = read_config(&sel, PCIR_STATUS, 2); 179 if (sts & PCIM_STATUS_CAPPRESENT) { 180 ptr = read_config(&sel, PCIR_CAP_PTR, 1); 181 while (ptr != 0 && ptr != 0xff) { 182 cap = read_config(&sel, ptr + PCICAP_ID, 1); 183 if (cap == PCIY_MSI) { 184 /* 185 * Copy the MSI capability into the config 186 * space of the emulated pci device 187 */ 188 sc->psc_msi.capoff = ptr; 189 sc->psc_msi.msgctrl = read_config(&sel, 190 ptr + 2, 2); 191 sc->psc_msi.emulated = 0; 192 caplen = msi_caplen(sc->psc_msi.msgctrl); 193 capptr = ptr; 194 while (caplen > 0) { 195 u32 = read_config(&sel, capptr, 4); 196 pci_set_cfgdata32(pi, capptr, u32); 197 caplen -= 4; 198 capptr += 4; 199 } 200 } else if (cap == PCIY_MSIX) { 201 /* 202 * Copy the MSI-X capability 203 */ 204 sc->psc_msix.capoff = ptr; 205 caplen = 12; 206 msixcap_ptr = (uint32_t*) &msixcap; 207 capptr = ptr; 208 while (caplen > 0) { 209 u32 = read_config(&sel, capptr, 4); 210 *msixcap_ptr = u32; 211 pci_set_cfgdata32(pi, capptr, u32); 212 caplen -= 4; 213 capptr += 4; 214 msixcap_ptr++; 215 } 216 } 217 ptr = read_config(&sel, ptr + PCICAP_NEXTPTR, 1); 218 } 219 } 220 221 if (sc->psc_msix.capoff != 0) { 222 pi->pi_msix.pba_bar = 223 msixcap.pba_info & PCIM_MSIX_BIR_MASK; 224 pi->pi_msix.pba_offset = 225 msixcap.pba_info & ~PCIM_MSIX_BIR_MASK; 226 pi->pi_msix.table_bar = 227 msixcap.table_info & PCIM_MSIX_BIR_MASK; 228 pi->pi_msix.table_offset = 229 msixcap.table_info & ~PCIM_MSIX_BIR_MASK; 230 pi->pi_msix.table_count = MSIX_TABLE_COUNT(msixcap.msgctrl); 231 232 /* Allocate the emulated MSI-X table array */ 233 table_size = pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE; 234 pi->pi_msix.table = malloc(table_size); 235 bzero(pi->pi_msix.table, table_size); 236 237 /* Mask all table entries */ 238 for (i = 0; i < pi->pi_msix.table_count; i++) { 239 pi->pi_msix.table[i].vector_control |= 240 PCIM_MSIX_VCTRL_MASK; 241 } 242 } 243 244#ifdef LEGACY_SUPPORT 245 /* 246 * If the passthrough device does not support MSI then craft a 247 * MSI capability for it. We link the new MSI capability at the 248 * head of the list of capabilities. 249 */ 250 if ((sts & PCIM_STATUS_CAPPRESENT) != 0 && sc->psc_msi.capoff == 0) { 251 int origptr, msiptr; 252 origptr = read_config(&sel, PCIR_CAP_PTR, 1); 253 msiptr = passthru_add_msicap(pi, 1, origptr); 254 sc->psc_msi.capoff = msiptr; 255 sc->psc_msi.msgctrl = pci_get_cfgdata16(pi, msiptr + 2); 256 sc->psc_msi.emulated = 1; 257 pci_set_cfgdata8(pi, PCIR_CAP_PTR, msiptr); 258 } 259#endif 260 261 /* Make sure one of the capabilities is present */ 262 if (sc->psc_msi.capoff == 0 && sc->psc_msix.capoff == 0) 263 return (-1); 264 else 265 return (0); 266} 267 268static uint64_t 269msix_table_read(struct passthru_softc *sc, uint64_t offset, int size) 270{ 271 struct pci_devinst *pi; 272 struct msix_table_entry *entry; 273 uint8_t *src8; 274 uint16_t *src16; 275 uint32_t *src32; 276 uint64_t *src64; 277 uint64_t data; 278 size_t entry_offset; 279 int index; 280 281 pi = sc->psc_pi; 282 283 index = offset / MSIX_TABLE_ENTRY_SIZE; 284 if (index >= pi->pi_msix.table_count) 285 return (-1); 286 287 entry = &pi->pi_msix.table[index]; 288 entry_offset = offset % MSIX_TABLE_ENTRY_SIZE; 289 290 switch(size) { 291 case 1: 292 src8 = (uint8_t *)((void *)entry + entry_offset); 293 data = *src8; 294 break; 295 case 2: 296 src16 = (uint16_t *)((void *)entry + entry_offset); 297 data = *src16; 298 break; 299 case 4: 300 src32 = (uint32_t *)((void *)entry + entry_offset); 301 data = *src32; 302 break; 303 case 8: 304 src64 = (uint64_t *)((void *)entry + entry_offset); 305 data = *src64; 306 break; 307 default: 308 return (-1); 309 } 310 311 return (data); 312} 313 314static void 315msix_table_write(struct vmctx *ctx, int vcpu, struct passthru_softc *sc, 316 uint64_t offset, int size, uint64_t data) 317{ 318 struct pci_devinst *pi; 319 struct msix_table_entry *entry; 320 uint32_t *dest; 321 size_t entry_offset; 322 uint32_t vector_control; 323 int error, index; 324 325 pi = sc->psc_pi; 326 index = offset / MSIX_TABLE_ENTRY_SIZE; 327 if (index >= pi->pi_msix.table_count) 328 return; 329 330 entry = &pi->pi_msix.table[index]; 331 entry_offset = offset % MSIX_TABLE_ENTRY_SIZE; 332 333 /* Only 4 byte naturally-aligned writes are supported */ 334 assert(size == 4); 335 assert(entry_offset % 4 == 0); 336 337 vector_control = entry->vector_control; 338 dest = (uint32_t *)((void *)entry + entry_offset); 339 *dest = data; 340 /* If MSI-X hasn't been enabled, do nothing */ 341 if (pi->pi_msix.enabled) { 342 /* If the entry is masked, don't set it up */ 343 if ((entry->vector_control & PCIM_MSIX_VCTRL_MASK) == 0 || 344 (vector_control & PCIM_MSIX_VCTRL_MASK) == 0) { 345 error = vm_setup_msix(ctx, vcpu, sc->psc_sel.pc_bus, 346 sc->psc_sel.pc_dev, 347 sc->psc_sel.pc_func, 348 index, entry->msg_data, 349 entry->vector_control, 350 entry->addr); 351 } 352 } 353} 354 355static int 356init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base) 357{ 358 int idx; 359 size_t table_size; 360 vm_paddr_t start; 361 size_t len; 362 struct pci_devinst *pi = sc->psc_pi; 363 364 /* 365 * If the MSI-X table BAR maps memory intended for 366 * other uses, it is at least assured that the table 367 * either resides in its own page within the region, 368 * or it resides in a page shared with only the PBA. 369 */ 370 if (pi->pi_msix.pba_bar == pi->pi_msix.table_bar && 371 ((pi->pi_msix.pba_offset - pi->pi_msix.table_offset) < 4096)) { 372 /* Need to also emulate the PBA, not supported yet */ 373 printf("Unsupported MSI-X table and PBA in same page\n"); 374 return (-1); 375 } 376 377 /* 378 * May need to split the BAR into 3 regions: 379 * Before the MSI-X table, the MSI-X table, and after it 380 * XXX for now, assume that the table is not in the middle 381 */ 382 table_size = pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE; 383 idx = pi->pi_msix.table_bar; 384 385 /* Round up to page size */ 386 table_size = roundup2(table_size, 4096); 387 if (pi->pi_msix.table_offset == 0) { 388 /* Map everything after the MSI-X table */ 389 start = pi->pi_bar[idx].addr + table_size; 390 len = pi->pi_bar[idx].size - table_size; 391 } else { 392 /* Map everything before the MSI-X table */ 393 start = pi->pi_bar[idx].addr; 394 len = pi->pi_msix.table_offset; 395 } 396 return (vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus, 397 sc->psc_sel.pc_dev, sc->psc_sel.pc_func, 398 start, len, base + table_size)); 399} 400 401static int 402cfginitbar(struct vmctx *ctx, struct passthru_softc *sc) 403{ 404 int i, error; 405 struct pci_devinst *pi; 406 struct pci_bar_io bar; 407 enum pcibar_type bartype; 408 uint64_t base; 409 410 pi = sc->psc_pi; 411 412 /* 413 * Initialize BAR registers 414 */ 415 for (i = 0; i <= PCI_BARMAX; i++) { 416 bzero(&bar, sizeof(bar)); 417 bar.pbi_sel = sc->psc_sel; 418 bar.pbi_reg = PCIR_BAR(i); 419 420 if (ioctl(pcifd, PCIOCGETBAR, &bar) < 0) 421 continue; 422 423 if (PCI_BAR_IO(bar.pbi_base)) { 424 bartype = PCIBAR_IO; 425 base = bar.pbi_base & PCIM_BAR_IO_BASE; 426 } else { 427 switch (bar.pbi_base & PCIM_BAR_MEM_TYPE) { 428 case PCIM_BAR_MEM_64: 429 bartype = PCIBAR_MEM64; 430 break; 431 default: 432 bartype = PCIBAR_MEM32; 433 break; 434 } 435 base = bar.pbi_base & PCIM_BAR_MEM_BASE; 436 } 437 438 /* Cache information about the "real" BAR */ 439 sc->psc_bar[i].type = bartype; 440 sc->psc_bar[i].size = bar.pbi_length; 441 sc->psc_bar[i].addr = base; 442 443 /* Allocate the BAR in the guest I/O or MMIO space */ 444 error = pci_emul_alloc_pbar(pi, i, base, bartype, 445 bar.pbi_length); 446 if (error) 447 return (-1); 448 449 /* The MSI-X table needs special handling */ 450 if (i == pi->pi_msix.table_bar) { 451 error = init_msix_table(ctx, sc, base); 452 if (error) 453 return (-1); 454 } else if (bartype != PCIBAR_IO) { 455 /* Map the physical MMIO space in the guest MMIO space */ 456 error = vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus, 457 sc->psc_sel.pc_dev, sc->psc_sel.pc_func, 458 pi->pi_bar[i].addr, pi->pi_bar[i].size, base); 459 if (error) 460 return (-1); 461 } 462 463 /* 464 * 64-bit BAR takes up two slots so skip the next one. 465 */ 466 if (bartype == PCIBAR_MEM64) { 467 i++; 468 assert(i <= PCI_BARMAX); 469 sc->psc_bar[i].type = PCIBAR_MEMHI64; 470 } 471 } 472 return (0); 473} 474 475static int 476cfginit(struct vmctx *ctx, struct pci_devinst *pi, int bus, int slot, int func) 477{ 478 int error; 479 struct passthru_softc *sc; 480 481 error = 1; 482 sc = pi->pi_arg; 483 484 bzero(&sc->psc_sel, sizeof(struct pcisel)); 485 sc->psc_sel.pc_bus = bus; 486 sc->psc_sel.pc_dev = slot; 487 sc->psc_sel.pc_func = func; 488 489 if (cfginitmsi(sc) != 0) 490 goto done; 491 492 if (cfginitbar(ctx, sc) != 0) 493 goto done; 494 495 error = 0; /* success */ 496done: 497 return (error); 498} 499 500static int 501passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts) 502{ 503 int bus, slot, func, error; 504 struct passthru_softc *sc; 505 506 sc = NULL; 507 error = 1; 508 509 if (pcifd < 0) { 510 pcifd = open(_PATH_DEVPCI, O_RDWR, 0); 511 if (pcifd < 0) 512 goto done; 513 } 514 515 if (iofd < 0) { 516 iofd = open(_PATH_DEVIO, O_RDWR, 0); 517 if (iofd < 0) 518 goto done; 519 } 520 521 if (opts == NULL || 522 sscanf(opts, "%d/%d/%d", &bus, &slot, &func) != 3) 523 goto done; 524 525 if (vm_assign_pptdev(ctx, bus, slot, func) != 0) 526 goto done; 527 528 sc = malloc(sizeof(struct passthru_softc)); 529 memset(sc, 0, sizeof(struct passthru_softc)); 530 531 pi->pi_arg = sc; 532 sc->psc_pi = pi; 533 534 /* initialize config space */ 535 if ((error = cfginit(ctx, pi, bus, slot, func)) != 0) 536 goto done; 537 538 error = 0; /* success */ 539done: 540 if (error) { 541 free(sc); 542 vm_unassign_pptdev(ctx, bus, slot, func); 543 } 544 return (error); 545} 546 547static int 548bar_access(int coff) 549{ 550 if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1)) 551 return (1); 552 else 553 return (0); 554} 555 556static int 557msicap_access(struct passthru_softc *sc, int coff) 558{ 559 int caplen; 560 561 if (sc->psc_msi.capoff == 0) 562 return (0); 563 564 caplen = msi_caplen(sc->psc_msi.msgctrl); 565 566 if (coff >= sc->psc_msi.capoff && coff < sc->psc_msi.capoff + caplen) 567 return (1); 568 else 569 return (0); 570} 571 572static int 573msixcap_access(struct passthru_softc *sc, int coff) 574{ 575 if (sc->psc_msix.capoff == 0) 576 return (0); 577 578 return (coff >= sc->psc_msix.capoff && 579 coff < sc->psc_msix.capoff + MSIX_CAPLEN); 580} 581 582static int 583passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 584 int coff, int bytes, uint32_t *rv) 585{ 586 struct passthru_softc *sc; 587 588 sc = pi->pi_arg; 589 590 /* 591 * PCI BARs and MSI capability is emulated. 592 */ 593 if (bar_access(coff) || msicap_access(sc, coff)) 594 return (-1); 595 596#ifdef LEGACY_SUPPORT 597 /* 598 * Emulate PCIR_CAP_PTR if this device does not support MSI capability 599 * natively. 600 */ 601 if (sc->psc_msi.emulated) { 602 if (coff >= PCIR_CAP_PTR && coff < PCIR_CAP_PTR + 4) 603 return (-1); 604 } 605#endif 606 607 /* Everything else just read from the device's config space */ 608 *rv = read_config(&sc->psc_sel, coff, bytes); 609 610 return (0); 611} 612 613static int 614passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, 615 int coff, int bytes, uint32_t val) 616{ 617 int error, msix_table_entries, i; 618 struct passthru_softc *sc; 619 620 sc = pi->pi_arg; 621 622 /* 623 * PCI BARs are emulated 624 */ 625 if (bar_access(coff)) 626 return (-1); 627 628 /* 629 * MSI capability is emulated 630 */ 631 if (msicap_access(sc, coff)) { 632 msicap_cfgwrite(pi, sc->psc_msi.capoff, coff, bytes, val); 633 634 error = vm_setup_msi(ctx, vcpu, sc->psc_sel.pc_bus, 635 sc->psc_sel.pc_dev, sc->psc_sel.pc_func, pi->pi_msi.cpu, 636 pi->pi_msi.vector, pi->pi_msi.msgnum); 637 if (error != 0) { 638 printf("vm_setup_msi returned error %d\r\n", errno); 639 exit(1); 640 } 641 return (0); 642 } 643 644 if (msixcap_access(sc, coff)) { 645 msixcap_cfgwrite(pi, sc->psc_msix.capoff, coff, bytes, val); 646 if (pi->pi_msix.enabled) { 647 msix_table_entries = pi->pi_msix.table_count; 648 for (i = 0; i < msix_table_entries; i++) { 649 error = vm_setup_msix(ctx, vcpu, sc->psc_sel.pc_bus, 650 sc->psc_sel.pc_dev, 651 sc->psc_sel.pc_func, i, 652 pi->pi_msix.table[i].msg_data, 653 pi->pi_msix.table[i].vector_control, 654 pi->pi_msix.table[i].addr); 655 656 if (error) { 657 printf("vm_setup_msix returned error %d\r\n", errno); 658 exit(1); 659 } 660 } 661 } 662 return (0); 663 } 664 665#ifdef LEGACY_SUPPORT 666 /* 667 * If this device does not support MSI natively then we cannot let 668 * the guest disable legacy interrupts from the device. It is the 669 * legacy interrupt that is triggering the virtual MSI to the guest. 670 */ 671 if (sc->psc_msi.emulated && pci_msi_enabled(pi)) { 672 if (coff == PCIR_COMMAND && bytes == 2) 673 val &= ~PCIM_CMD_INTxDIS; 674 } 675#endif 676 677 write_config(&sc->psc_sel, coff, bytes, val); 678 679 return (0); 680} 681 682static void 683passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, 684 uint64_t offset, int size, uint64_t value) 685{ 686 struct passthru_softc *sc; 687 struct iodev_pio_req pio; 688 689 sc = pi->pi_arg; 690 691 if (pi->pi_msix.table_bar == baridx) { 692 msix_table_write(ctx, vcpu, sc, offset, size, value); 693 } else { 694 assert(pi->pi_bar[baridx].type == PCIBAR_IO); 695 bzero(&pio, sizeof(struct iodev_pio_req)); 696 pio.access = IODEV_PIO_WRITE; 697 pio.port = sc->psc_bar[baridx].addr + offset; 698 pio.width = size; 699 pio.val = value; 700 701 (void)ioctl(iofd, IODEV_PIO, &pio); 702 } 703} 704 705static uint64_t 706passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx, 707 uint64_t offset, int size) 708{ 709 struct passthru_softc *sc; 710 struct iodev_pio_req pio; 711 uint64_t val; 712 713 sc = pi->pi_arg; 714 715 if (pi->pi_msix.table_bar == baridx) { 716 val = msix_table_read(sc, offset, size); 717 } else { 718 assert(pi->pi_bar[baridx].type == PCIBAR_IO); 719 bzero(&pio, sizeof(struct iodev_pio_req)); 720 pio.access = IODEV_PIO_READ; 721 pio.port = sc->psc_bar[baridx].addr + offset; 722 pio.width = size; 723 pio.val = 0; 724 725 (void)ioctl(iofd, IODEV_PIO, &pio); 726 727 val = pio.val; 728 } 729 730 return (val); 731} 732 733struct pci_devemu passthru = { 734 .pe_emu = "passthru", 735 .pe_init = passthru_init, 736 .pe_cfgwrite = passthru_cfgwrite, 737 .pe_cfgread = passthru_cfgread, 738 .pe_barwrite = passthru_write, 739 .pe_barread = passthru_read, 740}; 741PCI_EMUL_SET(passthru); 742