]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - usr.sbin/bhyve/pci_passthru.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / usr.sbin / bhyve / pci_passthru.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/types.h>
34 #include <sys/pciio.h>
35 #include <sys/ioctl.h>
36
37 #include <dev/io/iodev.h>
38 #include <dev/pci/pcireg.h>
39
40 #include <machine/iodev.h>
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <unistd.h>
48
49 #include <machine/vmm.h>
50 #include <vmmapi.h>
51 #include "pci_emul.h"
52 #include "mem.h"
53
54 #ifndef _PATH_DEVPCI
55 #define _PATH_DEVPCI    "/dev/pci"
56 #endif
57
58 #ifndef _PATH_DEVIO
59 #define _PATH_DEVIO     "/dev/io"
60 #endif
61
62 #define LEGACY_SUPPORT  1
63
64 #define MSIX_TABLE_COUNT(ctrl) (((ctrl) & PCIM_MSIXCTRL_TABLE_SIZE) + 1)
65 #define MSIX_CAPLEN 12
66
67 static int pcifd = -1;
68 static int iofd = -1;
69
70 struct passthru_softc {
71         struct pci_devinst *psc_pi;
72         struct pcibar psc_bar[PCI_BARMAX + 1];
73         struct {
74                 int             capoff;
75                 int             msgctrl;
76                 int             emulated;
77         } psc_msi;
78         struct {
79                 int             capoff;
80         } psc_msix;
81         struct pcisel psc_sel;
82 };
83
84 static int
85 msi_caplen(int msgctrl)
86 {
87         int len;
88         
89         len = 10;               /* minimum length of msi capability */
90
91         if (msgctrl & PCIM_MSICTRL_64BIT)
92                 len += 4;
93
94 #if 0
95         /*
96          * Ignore the 'mask' and 'pending' bits in the MSI capability.
97          * We'll let the guest manipulate them directly.
98          */
99         if (msgctrl & PCIM_MSICTRL_VECTOR)
100                 len += 10;
101 #endif
102
103         return (len);
104 }
105
106 static uint32_t
107 read_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
122 static void
123 write_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
137 static int
138 passthru_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
161 static int
162 cfginitmsi(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
268 static uint64_t
269 msix_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         offset -= pi->pi_msix.table_offset;
283
284         index = offset / MSIX_TABLE_ENTRY_SIZE;
285         if (index >= pi->pi_msix.table_count)
286                 return (-1);
287
288         entry = &pi->pi_msix.table[index];
289         entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
290
291         switch(size) {
292         case 1:
293                 src8 = (uint8_t *)((void *)entry + entry_offset);
294                 data = *src8;
295                 break;
296         case 2:
297                 src16 = (uint16_t *)((void *)entry + entry_offset);
298                 data = *src16;
299                 break;
300         case 4:
301                 src32 = (uint32_t *)((void *)entry + entry_offset);
302                 data = *src32;
303                 break;
304         case 8:
305                 src64 = (uint64_t *)((void *)entry + entry_offset);
306                 data = *src64;
307                 break;
308         default:
309                 return (-1);
310         }
311
312         return (data);
313 }
314
315 static void
316 msix_table_write(struct vmctx *ctx, int vcpu, struct passthru_softc *sc,
317                  uint64_t offset, int size, uint64_t data)
318 {
319         struct pci_devinst *pi;
320         struct msix_table_entry *entry;
321         uint32_t *dest;
322         size_t entry_offset;
323         uint32_t vector_control;
324         int error, index;
325
326         pi = sc->psc_pi;
327         offset -= pi->pi_msix.table_offset;
328
329         index = offset / MSIX_TABLE_ENTRY_SIZE;
330         if (index >= pi->pi_msix.table_count)
331                 return;
332
333         entry = &pi->pi_msix.table[index];
334         entry_offset = offset % MSIX_TABLE_ENTRY_SIZE;
335
336         /* Only 4 byte naturally-aligned writes are supported */
337         assert(size == 4);
338         assert(entry_offset % 4 == 0);
339
340         vector_control = entry->vector_control;
341         dest = (uint32_t *)((void *)entry + entry_offset);
342         *dest = data;
343         /* If MSI-X hasn't been enabled, do nothing */
344         if (pi->pi_msix.enabled) {
345                 /* If the entry is masked, don't set it up */
346                 if ((entry->vector_control & PCIM_MSIX_VCTRL_MASK) == 0 ||
347                     (vector_control & PCIM_MSIX_VCTRL_MASK) == 0) {
348                         error = vm_setup_msix(ctx, vcpu, sc->psc_sel.pc_bus,
349                                               sc->psc_sel.pc_dev, 
350                                               sc->psc_sel.pc_func,
351                                               index, entry->msg_data, 
352                                               entry->vector_control,
353                                               entry->addr);
354                 }
355         }
356 }
357
358 static int
359 init_msix_table(struct vmctx *ctx, struct passthru_softc *sc, uint64_t base)
360 {
361         int b, s, f;
362         int error, idx;
363         size_t len, remaining, table_size;
364         vm_paddr_t start;
365         struct pci_devinst *pi = sc->psc_pi;
366
367         assert(pci_msix_table_bar(pi) >= 0 && pci_msix_pba_bar(pi) >= 0);
368
369         b = sc->psc_sel.pc_bus;
370         s = sc->psc_sel.pc_dev;
371         f = sc->psc_sel.pc_func;
372
373         /* 
374          * If the MSI-X table BAR maps memory intended for
375          * other uses, it is at least assured that the table 
376          * either resides in its own page within the region, 
377          * or it resides in a page shared with only the PBA.
378          */
379         if (pi->pi_msix.pba_bar == pi->pi_msix.table_bar && 
380             ((pi->pi_msix.pba_offset - pi->pi_msix.table_offset) < 4096)) {
381                 /* Need to also emulate the PBA, not supported yet */
382                 printf("Unsupported MSI-X configuration: %d/%d/%d\n", b, s, f);
383                 return (-1);
384         }
385
386         /* Compute the MSI-X table size */
387         table_size = pi->pi_msix.table_count * MSIX_TABLE_ENTRY_SIZE;
388         table_size = roundup2(table_size, 4096);
389
390         idx = pi->pi_msix.table_bar;
391         start = pi->pi_bar[idx].addr;
392         remaining = pi->pi_bar[idx].size;
393
394         /* Map everything before the MSI-X table */
395         if (pi->pi_msix.table_offset > 0) {
396                 len = pi->pi_msix.table_offset;
397                 error = vm_map_pptdev_mmio(ctx, b, s, f, start, len, base);
398                 if (error)
399                         return (error);
400
401                 base += len;
402                 start += len;
403                 remaining -= len;
404         }
405
406         /* Skip the MSI-X table */
407         base += table_size;
408         start += table_size;
409         remaining -= table_size;
410
411         /* Map everything beyond the end of the MSI-X table */
412         if (remaining > 0) {
413                 len = remaining;
414                 error = vm_map_pptdev_mmio(ctx, b, s, f, start, len, base);
415                 if (error)
416                         return (error);
417         }
418
419         return (0);
420 }
421
422 static int
423 cfginitbar(struct vmctx *ctx, struct passthru_softc *sc)
424 {
425         int i, error;
426         struct pci_devinst *pi;
427         struct pci_bar_io bar;
428         enum pcibar_type bartype;
429         uint64_t base;
430
431         pi = sc->psc_pi;
432
433         /*
434          * Initialize BAR registers
435          */
436         for (i = 0; i <= PCI_BARMAX; i++) {
437                 bzero(&bar, sizeof(bar));
438                 bar.pbi_sel = sc->psc_sel;
439                 bar.pbi_reg = PCIR_BAR(i);
440
441                 if (ioctl(pcifd, PCIOCGETBAR, &bar) < 0)
442                         continue;
443
444                 if (PCI_BAR_IO(bar.pbi_base)) {
445                         bartype = PCIBAR_IO;
446                         base = bar.pbi_base & PCIM_BAR_IO_BASE;
447                 } else {
448                         switch (bar.pbi_base & PCIM_BAR_MEM_TYPE) {
449                         case PCIM_BAR_MEM_64:
450                                 bartype = PCIBAR_MEM64;
451                                 break;
452                         default:
453                                 bartype = PCIBAR_MEM32;
454                                 break;
455                         }
456                         base = bar.pbi_base & PCIM_BAR_MEM_BASE;
457                 }
458
459                 /* Cache information about the "real" BAR */
460                 sc->psc_bar[i].type = bartype;
461                 sc->psc_bar[i].size = bar.pbi_length;
462                 sc->psc_bar[i].addr = base;
463
464                 /* Allocate the BAR in the guest I/O or MMIO space */
465                 error = pci_emul_alloc_pbar(pi, i, base, bartype,
466                                             bar.pbi_length);
467                 if (error)
468                         return (-1);
469
470                 /* The MSI-X table needs special handling */
471                 if (i == pci_msix_table_bar(pi)) {
472                         error = init_msix_table(ctx, sc, base);
473                         if (error) 
474                                 return (-1);
475                 } else if (bartype != PCIBAR_IO) {
476                         /* Map the physical MMIO space in the guest MMIO space */
477                         error = vm_map_pptdev_mmio(ctx, sc->psc_sel.pc_bus,
478                                 sc->psc_sel.pc_dev, sc->psc_sel.pc_func,
479                                 pi->pi_bar[i].addr, pi->pi_bar[i].size, base);
480                         if (error)
481                                 return (-1);
482                 }
483
484                 /*
485                  * 64-bit BAR takes up two slots so skip the next one.
486                  */
487                 if (bartype == PCIBAR_MEM64) {
488                         i++;
489                         assert(i <= PCI_BARMAX);
490                         sc->psc_bar[i].type = PCIBAR_MEMHI64;
491                 }
492         }
493         return (0);
494 }
495
496 static int
497 cfginit(struct vmctx *ctx, struct pci_devinst *pi, int bus, int slot, int func)
498 {
499         int error;
500         struct passthru_softc *sc;
501
502         error = 1;
503         sc = pi->pi_arg;
504
505         bzero(&sc->psc_sel, sizeof(struct pcisel));
506         sc->psc_sel.pc_bus = bus;
507         sc->psc_sel.pc_dev = slot;
508         sc->psc_sel.pc_func = func;
509
510         if (cfginitmsi(sc) != 0)
511                 goto done;
512
513         if (cfginitbar(ctx, sc) != 0)
514                 goto done;
515
516         error = 0;                              /* success */
517 done:
518         return (error);
519 }
520
521 static int
522 passthru_init(struct vmctx *ctx, struct pci_devinst *pi, char *opts)
523 {
524         int bus, slot, func, error;
525         struct passthru_softc *sc;
526
527         sc = NULL;
528         error = 1;
529
530         if (pcifd < 0) {
531                 pcifd = open(_PATH_DEVPCI, O_RDWR, 0);
532                 if (pcifd < 0)
533                         goto done;
534         }
535
536         if (iofd < 0) {
537                 iofd = open(_PATH_DEVIO, O_RDWR, 0);
538                 if (iofd < 0)
539                         goto done;
540         }
541
542         if (opts == NULL ||
543             sscanf(opts, "%d/%d/%d", &bus, &slot, &func) != 3)
544                 goto done;
545
546         if (vm_assign_pptdev(ctx, bus, slot, func) != 0)
547                 goto done;
548
549         sc = malloc(sizeof(struct passthru_softc));
550         memset(sc, 0, sizeof(struct passthru_softc));
551
552         pi->pi_arg = sc;
553         sc->psc_pi = pi;
554
555         /* initialize config space */
556         if ((error = cfginit(ctx, pi, bus, slot, func)) != 0)
557                 goto done;
558         
559         error = 0;              /* success */
560 done:
561         if (error) {
562                 free(sc);
563                 vm_unassign_pptdev(ctx, bus, slot, func);
564         }
565         return (error);
566 }
567
568 static int
569 bar_access(int coff)
570 {
571         if (coff >= PCIR_BAR(0) && coff < PCIR_BAR(PCI_BARMAX + 1))
572                 return (1);
573         else
574                 return (0);
575 }
576
577 static int
578 msicap_access(struct passthru_softc *sc, int coff)
579 {
580         int caplen;
581
582         if (sc->psc_msi.capoff == 0)
583                 return (0);
584
585         caplen = msi_caplen(sc->psc_msi.msgctrl);
586
587         if (coff >= sc->psc_msi.capoff && coff < sc->psc_msi.capoff + caplen)
588                 return (1);
589         else
590                 return (0);
591 }
592
593 static int 
594 msixcap_access(struct passthru_softc *sc, int coff)
595 {
596         if (sc->psc_msix.capoff == 0) 
597                 return (0);
598
599         return (coff >= sc->psc_msix.capoff && 
600                 coff < sc->psc_msix.capoff + MSIX_CAPLEN);
601 }
602
603 static int
604 passthru_cfgread(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
605                  int coff, int bytes, uint32_t *rv)
606 {
607         struct passthru_softc *sc;
608
609         sc = pi->pi_arg;
610
611         /*
612          * PCI BARs and MSI capability is emulated.
613          */
614         if (bar_access(coff) || msicap_access(sc, coff))
615                 return (-1);
616
617 #ifdef LEGACY_SUPPORT
618         /*
619          * Emulate PCIR_CAP_PTR if this device does not support MSI capability
620          * natively.
621          */
622         if (sc->psc_msi.emulated) {
623                 if (coff >= PCIR_CAP_PTR && coff < PCIR_CAP_PTR + 4)
624                         return (-1);
625         }
626 #endif
627
628         /* Everything else just read from the device's config space */
629         *rv = read_config(&sc->psc_sel, coff, bytes);
630
631         return (0);
632 }
633
634 static int
635 passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi,
636                   int coff, int bytes, uint32_t val)
637 {
638         int error, msix_table_entries, i;
639         struct passthru_softc *sc;
640
641         sc = pi->pi_arg;
642
643         /*
644          * PCI BARs are emulated
645          */
646         if (bar_access(coff))
647                 return (-1);
648
649         /*
650          * MSI capability is emulated
651          */
652         if (msicap_access(sc, coff)) {
653                 msicap_cfgwrite(pi, sc->psc_msi.capoff, coff, bytes, val);
654
655                 error = vm_setup_msi(ctx, vcpu, sc->psc_sel.pc_bus,
656                         sc->psc_sel.pc_dev, sc->psc_sel.pc_func, pi->pi_msi.cpu,
657                         pi->pi_msi.vector, pi->pi_msi.msgnum);
658                 if (error != 0) {
659                         printf("vm_setup_msi returned error %d\r\n", errno);
660                         exit(1);
661                 }
662                 return (0);
663         }
664
665         if (msixcap_access(sc, coff)) {
666                 msixcap_cfgwrite(pi, sc->psc_msix.capoff, coff, bytes, val);
667                 if (pi->pi_msix.enabled) {
668                         msix_table_entries = pi->pi_msix.table_count;
669                         for (i = 0; i < msix_table_entries; i++) {
670                                 error = vm_setup_msix(ctx, vcpu, sc->psc_sel.pc_bus,
671                                                       sc->psc_sel.pc_dev, 
672                                                       sc->psc_sel.pc_func, i, 
673                                                       pi->pi_msix.table[i].msg_data,
674                                                       pi->pi_msix.table[i].vector_control,
675                                                       pi->pi_msix.table[i].addr);
676                 
677                                 if (error) {
678                                         printf("vm_setup_msix returned error %d\r\n", errno);
679                                         exit(1);        
680                                 }
681                         }
682                 }
683                 return (0);
684         }
685
686 #ifdef LEGACY_SUPPORT
687         /*
688          * If this device does not support MSI natively then we cannot let
689          * the guest disable legacy interrupts from the device. It is the
690          * legacy interrupt that is triggering the virtual MSI to the guest.
691          */
692         if (sc->psc_msi.emulated && pci_msi_enabled(pi)) {
693                 if (coff == PCIR_COMMAND && bytes == 2)
694                         val &= ~PCIM_CMD_INTxDIS;
695         }
696 #endif
697
698         write_config(&sc->psc_sel, coff, bytes, val);
699
700         return (0);
701 }
702
703 static void
704 passthru_write(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
705                uint64_t offset, int size, uint64_t value)
706 {
707         struct passthru_softc *sc;
708         struct iodev_pio_req pio;
709
710         sc = pi->pi_arg;
711
712         if (baridx == pci_msix_table_bar(pi)) {
713                 msix_table_write(ctx, vcpu, sc, offset, size, value);
714         } else {
715                 assert(pi->pi_bar[baridx].type == PCIBAR_IO);
716                 bzero(&pio, sizeof(struct iodev_pio_req));
717                 pio.access = IODEV_PIO_WRITE;
718                 pio.port = sc->psc_bar[baridx].addr + offset;
719                 pio.width = size;
720                 pio.val = value;
721                 
722                 (void)ioctl(iofd, IODEV_PIO, &pio);
723         }
724 }
725
726 static uint64_t
727 passthru_read(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, int baridx,
728               uint64_t offset, int size)
729 {
730         struct passthru_softc *sc;
731         struct iodev_pio_req pio;
732         uint64_t val;
733
734         sc = pi->pi_arg;
735
736         if (baridx == pci_msix_table_bar(pi)) {
737                 val = msix_table_read(sc, offset, size);
738         } else {
739                 assert(pi->pi_bar[baridx].type == PCIBAR_IO);
740                 bzero(&pio, sizeof(struct iodev_pio_req));
741                 pio.access = IODEV_PIO_READ;
742                 pio.port = sc->psc_bar[baridx].addr + offset;
743                 pio.width = size;
744                 pio.val = 0;
745
746                 (void)ioctl(iofd, IODEV_PIO, &pio);
747
748                 val = pio.val;
749         }
750
751         return (val);
752 }
753
754 struct pci_devemu passthru = {
755         .pe_emu         = "passthru",
756         .pe_init        = passthru_init,
757         .pe_cfgwrite    = passthru_cfgwrite,
758         .pe_cfgread     = passthru_cfgread,
759         .pe_barwrite    = passthru_write,
760         .pe_barread     = passthru_read,
761 };
762 PCI_EMUL_SET(passthru);