xref: /openbmc/qemu/hw/pci/pcie_sriov.c (revision 5e25c93ccb8ddc8dda6845d6c09334ca44cbef17)
17c0fa8dfSKnut Omang /*
27c0fa8dfSKnut Omang  * pcie_sriov.c:
37c0fa8dfSKnut Omang  *
47c0fa8dfSKnut Omang  * Implementation of SR/IOV emulation support.
57c0fa8dfSKnut Omang  *
67c0fa8dfSKnut Omang  * Copyright (c) 2015-2017 Knut Omang <knut.omang@oracle.com>
77c0fa8dfSKnut Omang  *
87c0fa8dfSKnut Omang  * This work is licensed under the terms of the GNU GPL, version 2 or later.
97c0fa8dfSKnut Omang  * See the COPYING file in the top-level directory.
107c0fa8dfSKnut Omang  *
117c0fa8dfSKnut Omang  */
127c0fa8dfSKnut Omang 
137c0fa8dfSKnut Omang #include "qemu/osdep.h"
14edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h"
157c0fa8dfSKnut Omang #include "hw/pci/pcie.h"
167c0fa8dfSKnut Omang #include "hw/pci/pci_bus.h"
177c0fa8dfSKnut Omang #include "hw/qdev-properties.h"
187c0fa8dfSKnut Omang #include "qemu/error-report.h"
197c0fa8dfSKnut Omang #include "qemu/range.h"
207c0fa8dfSKnut Omang #include "qapi/error.h"
217c0fa8dfSKnut Omang #include "trace.h"
227c0fa8dfSKnut Omang 
23b1282f1eSMichael S. Tsirkin static PCIDevice *register_vf(PCIDevice *pf, int devfn,
24b1282f1eSMichael S. Tsirkin                               const char *name, uint16_t vf_num);
25b1282f1eSMichael S. Tsirkin static void unregister_vfs(PCIDevice *dev);
267c0fa8dfSKnut Omang 
pcie_sriov_pf_init(PCIDevice * dev,uint16_t offset,const char * vfname,uint16_t vf_dev_id,uint16_t init_vfs,uint16_t total_vfs,uint16_t vf_offset,uint16_t vf_stride)2719c45c00SMichael S. Tsirkin void pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
28aa01c491SMichael S. Tsirkin                         const char *vfname, uint16_t vf_dev_id,
29aa01c491SMichael S. Tsirkin                         uint16_t init_vfs, uint16_t total_vfs,
3019c45c00SMichael S. Tsirkin                         uint16_t vf_offset, uint16_t vf_stride)
317c0fa8dfSKnut Omang {
327c0fa8dfSKnut Omang     uint8_t *cfg = dev->config + offset;
337c0fa8dfSKnut Omang     uint8_t *wmask;
347c0fa8dfSKnut Omang 
357c0fa8dfSKnut Omang     pcie_add_capability(dev, PCI_EXT_CAP_ID_SRIOV, 1,
367c0fa8dfSKnut Omang                         offset, PCI_EXT_CAP_SRIOV_SIZEOF);
377c0fa8dfSKnut Omang     dev->exp.sriov_cap = offset;
38ae9c192dSMichael S. Tsirkin     dev->exp.sriov_pf.num_vfs = 0;
39b1282f1eSMichael S. Tsirkin     dev->exp.sriov_pf.vfname = g_strdup(vfname);
407c0fa8dfSKnut Omang     dev->exp.sriov_pf.vf = NULL;
417c0fa8dfSKnut Omang 
427c0fa8dfSKnut Omang     pci_set_word(cfg + PCI_SRIOV_VF_OFFSET, vf_offset);
437c0fa8dfSKnut Omang     pci_set_word(cfg + PCI_SRIOV_VF_STRIDE, vf_stride);
447c0fa8dfSKnut Omang 
457c0fa8dfSKnut Omang     /*
467c0fa8dfSKnut Omang      * Mandatory page sizes to support.
477c0fa8dfSKnut Omang      * Device implementations can call pcie_sriov_pf_add_sup_pgsize()
487c0fa8dfSKnut Omang      * to set more bits:
497c0fa8dfSKnut Omang      */
507c0fa8dfSKnut Omang     pci_set_word(cfg + PCI_SRIOV_SUP_PGSIZE, SRIOV_SUP_PGSIZE_MINREQ);
517c0fa8dfSKnut Omang 
527c0fa8dfSKnut Omang     /*
537c0fa8dfSKnut Omang      * Default is to use 4K pages, software can modify it
547c0fa8dfSKnut Omang      * to any of the supported bits
557c0fa8dfSKnut Omang      */
567c0fa8dfSKnut Omang     pci_set_word(cfg + PCI_SRIOV_SYS_PGSIZE, 0x1);
577c0fa8dfSKnut Omang 
587c0fa8dfSKnut Omang     /* Set up device ID and initial/total number of VFs available */
597c0fa8dfSKnut Omang     pci_set_word(cfg + PCI_SRIOV_VF_DID, vf_dev_id);
607c0fa8dfSKnut Omang     pci_set_word(cfg + PCI_SRIOV_INITIAL_VF, init_vfs);
617c0fa8dfSKnut Omang     pci_set_word(cfg + PCI_SRIOV_TOTAL_VF, total_vfs);
627c0fa8dfSKnut Omang     pci_set_word(cfg + PCI_SRIOV_NUM_VF, 0);
637c0fa8dfSKnut Omang 
647c0fa8dfSKnut Omang     /* Write enable control bits */
657c0fa8dfSKnut Omang     wmask = dev->wmask + offset;
667c0fa8dfSKnut Omang     pci_set_word(wmask + PCI_SRIOV_CTRL,
677c0fa8dfSKnut Omang                  PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE | PCI_SRIOV_CTRL_ARI);
687c0fa8dfSKnut Omang     pci_set_word(wmask + PCI_SRIOV_NUM_VF, 0xffff);
697c0fa8dfSKnut Omang     pci_set_word(wmask + PCI_SRIOV_SYS_PGSIZE, 0x553);
707c0fa8dfSKnut Omang 
717c0fa8dfSKnut Omang     qdev_prop_set_bit(&dev->qdev, "multifunction", true);
727c0fa8dfSKnut Omang }
737c0fa8dfSKnut Omang 
pcie_sriov_pf_exit(PCIDevice * dev)747c0fa8dfSKnut Omang void pcie_sriov_pf_exit(PCIDevice *dev)
757c0fa8dfSKnut Omang {
76b1282f1eSMichael S. Tsirkin     unregister_vfs(dev);
77b1282f1eSMichael S. Tsirkin     g_free((char *)dev->exp.sriov_pf.vfname);
78b1282f1eSMichael S. Tsirkin     dev->exp.sriov_pf.vfname = NULL;
797c0fa8dfSKnut Omang }
807c0fa8dfSKnut Omang 
pcie_sriov_pf_init_vf_bar(PCIDevice * dev,int region_num,uint8_t type,dma_addr_t size)817c0fa8dfSKnut Omang void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num,
827c0fa8dfSKnut Omang                                uint8_t type, dma_addr_t size)
837c0fa8dfSKnut Omang {
847c0fa8dfSKnut Omang     uint32_t addr;
857c0fa8dfSKnut Omang     uint64_t wmask;
867c0fa8dfSKnut Omang     uint16_t sriov_cap = dev->exp.sriov_cap;
877c0fa8dfSKnut Omang 
887c0fa8dfSKnut Omang     assert(sriov_cap > 0);
897c0fa8dfSKnut Omang     assert(region_num >= 0);
907c0fa8dfSKnut Omang     assert(region_num < PCI_NUM_REGIONS);
917c0fa8dfSKnut Omang     assert(region_num != PCI_ROM_SLOT);
927c0fa8dfSKnut Omang 
937c0fa8dfSKnut Omang     wmask = ~(size - 1);
947c0fa8dfSKnut Omang     addr = sriov_cap + PCI_SRIOV_BAR + region_num * 4;
957c0fa8dfSKnut Omang 
967c0fa8dfSKnut Omang     pci_set_long(dev->config + addr, type);
977c0fa8dfSKnut Omang     if (!(type & PCI_BASE_ADDRESS_SPACE_IO) &&
987c0fa8dfSKnut Omang         type & PCI_BASE_ADDRESS_MEM_TYPE_64) {
997c0fa8dfSKnut Omang         pci_set_quad(dev->wmask + addr, wmask);
1007c0fa8dfSKnut Omang         pci_set_quad(dev->cmask + addr, ~0ULL);
1017c0fa8dfSKnut Omang     } else {
1027c0fa8dfSKnut Omang         pci_set_long(dev->wmask + addr, wmask & 0xffffffff);
1037c0fa8dfSKnut Omang         pci_set_long(dev->cmask + addr, 0xffffffff);
1047c0fa8dfSKnut Omang     }
1057c0fa8dfSKnut Omang     dev->exp.sriov_pf.vf_bar_type[region_num] = type;
1067c0fa8dfSKnut Omang }
1077c0fa8dfSKnut Omang 
pcie_sriov_vf_register_bar(PCIDevice * dev,int region_num,MemoryRegion * memory)1087c0fa8dfSKnut Omang void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num,
1097c0fa8dfSKnut Omang                                 MemoryRegion *memory)
1107c0fa8dfSKnut Omang {
111aa01c491SMichael S. Tsirkin     PCIIORegion *r;
112aa01c491SMichael S. Tsirkin     PCIBus *bus = pci_get_bus(dev);
1137c0fa8dfSKnut Omang     uint8_t type;
114aa01c491SMichael S. Tsirkin     pcibus_t size = memory_region_size(memory);
1157c0fa8dfSKnut Omang 
116aa01c491SMichael S. Tsirkin     assert(pci_is_vf(dev)); /* PFs must use pci_register_bar */
117aa01c491SMichael S. Tsirkin     assert(region_num >= 0);
118aa01c491SMichael S. Tsirkin     assert(region_num < PCI_NUM_REGIONS);
1197c0fa8dfSKnut Omang     type = dev->exp.sriov_vf.pf->exp.sriov_pf.vf_bar_type[region_num];
1207c0fa8dfSKnut Omang 
121aa01c491SMichael S. Tsirkin     if (!is_power_of_2(size)) {
122aa01c491SMichael S. Tsirkin         error_report("%s: PCI region size must be a power"
123aa01c491SMichael S. Tsirkin                      " of two - type=0x%x, size=0x%"FMT_PCIBUS,
124aa01c491SMichael S. Tsirkin                      __func__, type, size);
125aa01c491SMichael S. Tsirkin         exit(1);
1267c0fa8dfSKnut Omang     }
1277c0fa8dfSKnut Omang 
128aa01c491SMichael S. Tsirkin     r = &dev->io_regions[region_num];
129aa01c491SMichael S. Tsirkin     r->memory = memory;
130aa01c491SMichael S. Tsirkin     r->address_space =
131aa01c491SMichael S. Tsirkin         type & PCI_BASE_ADDRESS_SPACE_IO
132aa01c491SMichael S. Tsirkin         ? bus->address_space_io
133aa01c491SMichael S. Tsirkin         : bus->address_space_mem;
134aa01c491SMichael S. Tsirkin     r->size = size;
135aa01c491SMichael S. Tsirkin     r->type = type;
136aa01c491SMichael S. Tsirkin 
137aa01c491SMichael S. Tsirkin     r->addr = pci_bar_address(dev, region_num, r->type, r->size);
138aa01c491SMichael S. Tsirkin     if (r->addr != PCI_BAR_UNMAPPED) {
139aa01c491SMichael S. Tsirkin         memory_region_add_subregion_overlap(r->address_space,
140aa01c491SMichael S. Tsirkin                                             r->addr, r->memory, 1);
141aa01c491SMichael S. Tsirkin     }
142cbd9e512SAkihiko Odaki }
143cbd9e512SAkihiko Odaki 
register_vf(PCIDevice * pf,int devfn,const char * name,uint16_t vf_num)144b1282f1eSMichael S. Tsirkin static PCIDevice *register_vf(PCIDevice *pf, int devfn, const char *name,
145b1282f1eSMichael S. Tsirkin                               uint16_t vf_num)
146b1282f1eSMichael S. Tsirkin {
147b1282f1eSMichael S. Tsirkin     PCIDevice *dev = pci_new(devfn, name);
148b1282f1eSMichael S. Tsirkin     dev->exp.sriov_vf.pf = pf;
149b1282f1eSMichael S. Tsirkin     dev->exp.sriov_vf.vf_number = vf_num;
150b1282f1eSMichael S. Tsirkin     PCIBus *bus = pci_get_bus(pf);
151b1282f1eSMichael S. Tsirkin     Error *local_err = NULL;
152b1282f1eSMichael S. Tsirkin 
153b1282f1eSMichael S. Tsirkin     qdev_realize(&dev->qdev, &bus->qbus, &local_err);
154b1282f1eSMichael S. Tsirkin     if (local_err) {
155b1282f1eSMichael S. Tsirkin         error_report_err(local_err);
156b1282f1eSMichael S. Tsirkin         return NULL;
157b1282f1eSMichael S. Tsirkin     }
158b1282f1eSMichael S. Tsirkin 
159b1282f1eSMichael S. Tsirkin     /* set vid/did according to sr/iov spec - they are not used */
160b1282f1eSMichael S. Tsirkin     pci_config_set_vendor_id(dev->config, 0xffff);
161b1282f1eSMichael S. Tsirkin     pci_config_set_device_id(dev->config, 0xffff);
162b1282f1eSMichael S. Tsirkin 
163b1282f1eSMichael S. Tsirkin     return dev;
164b1282f1eSMichael S. Tsirkin }
165b1282f1eSMichael S. Tsirkin 
register_vfs(PCIDevice * dev)166aa01c491SMichael S. Tsirkin static void register_vfs(PCIDevice *dev)
167aa01c491SMichael S. Tsirkin {
168aa01c491SMichael S. Tsirkin     uint16_t num_vfs;
1697c0fa8dfSKnut Omang     uint16_t i;
170aa01c491SMichael S. Tsirkin     uint16_t sriov_cap = dev->exp.sriov_cap;
171b1282f1eSMichael S. Tsirkin     uint16_t vf_offset =
172b1282f1eSMichael S. Tsirkin         pci_get_word(dev->config + sriov_cap + PCI_SRIOV_VF_OFFSET);
173b1282f1eSMichael S. Tsirkin     uint16_t vf_stride =
174b1282f1eSMichael S. Tsirkin         pci_get_word(dev->config + sriov_cap + PCI_SRIOV_VF_STRIDE);
175b1282f1eSMichael S. Tsirkin     int32_t devfn = dev->devfn + vf_offset;
1767c0fa8dfSKnut Omang 
177aa01c491SMichael S. Tsirkin     assert(sriov_cap > 0);
178aa01c491SMichael S. Tsirkin     num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF);
179aa01c491SMichael S. Tsirkin     if (num_vfs > pci_get_word(dev->config + sriov_cap + PCI_SRIOV_TOTAL_VF)) {
180aa01c491SMichael S. Tsirkin         return;
1816081b424SAkihiko Odaki     }
1827c0fa8dfSKnut Omang 
183b1282f1eSMichael S. Tsirkin     dev->exp.sriov_pf.vf = g_new(PCIDevice *, num_vfs);
184b1282f1eSMichael S. Tsirkin 
185aa01c491SMichael S. Tsirkin     trace_sriov_register_vfs(dev->name, PCI_SLOT(dev->devfn),
186aa01c491SMichael S. Tsirkin                              PCI_FUNC(dev->devfn), num_vfs);
187aa01c491SMichael S. Tsirkin     for (i = 0; i < num_vfs; i++) {
188b1282f1eSMichael S. Tsirkin         dev->exp.sriov_pf.vf[i] = register_vf(dev, devfn,
189b1282f1eSMichael S. Tsirkin                                               dev->exp.sriov_pf.vfname, i);
190b1282f1eSMichael S. Tsirkin         if (!dev->exp.sriov_pf.vf[i]) {
191b1282f1eSMichael S. Tsirkin             num_vfs = i;
192b1282f1eSMichael S. Tsirkin             break;
193b1282f1eSMichael S. Tsirkin         }
194b1282f1eSMichael S. Tsirkin         devfn += vf_stride;
1957c0fa8dfSKnut Omang     }
196ae9c192dSMichael S. Tsirkin     dev->exp.sriov_pf.num_vfs = num_vfs;
1977c0fa8dfSKnut Omang }
1987c0fa8dfSKnut Omang 
unregister_vfs(PCIDevice * dev)199aa01c491SMichael S. Tsirkin static void unregister_vfs(PCIDevice *dev)
2007c0fa8dfSKnut Omang {
201ae9c192dSMichael S. Tsirkin     uint16_t num_vfs = dev->exp.sriov_pf.num_vfs;
202aa01c491SMichael S. Tsirkin     uint16_t i;
2037c0fa8dfSKnut Omang 
204aa01c491SMichael S. Tsirkin     trace_sriov_unregister_vfs(dev->name, PCI_SLOT(dev->devfn),
205ae9c192dSMichael S. Tsirkin                                PCI_FUNC(dev->devfn), num_vfs);
206ae9c192dSMichael S. Tsirkin     for (i = 0; i < num_vfs; i++) {
207*b0fdaee5SMichael S. Tsirkin         Error *err = NULL;
208b1282f1eSMichael S. Tsirkin         PCIDevice *vf = dev->exp.sriov_pf.vf[i];
209*b0fdaee5SMichael S. Tsirkin         if (!object_property_set_bool(OBJECT(vf), "realized", false, &err)) {
210*b0fdaee5SMichael S. Tsirkin             error_reportf_err(err, "Failed to unplug: ");
211*b0fdaee5SMichael S. Tsirkin         }
212b1282f1eSMichael S. Tsirkin         object_unparent(OBJECT(vf));
213b1282f1eSMichael S. Tsirkin         object_unref(OBJECT(vf));
2147c0fa8dfSKnut Omang     }
215b1282f1eSMichael S. Tsirkin     g_free(dev->exp.sriov_pf.vf);
216b1282f1eSMichael S. Tsirkin     dev->exp.sriov_pf.vf = NULL;
217ae9c192dSMichael S. Tsirkin     dev->exp.sriov_pf.num_vfs = 0;
2187c0fa8dfSKnut Omang }
2197c0fa8dfSKnut Omang 
pcie_sriov_config_write(PCIDevice * dev,uint32_t address,uint32_t val,int len)2207c0fa8dfSKnut Omang void pcie_sriov_config_write(PCIDevice *dev, uint32_t address,
2217c0fa8dfSKnut Omang                              uint32_t val, int len)
2227c0fa8dfSKnut Omang {
2237c0fa8dfSKnut Omang     uint32_t off;
2247c0fa8dfSKnut Omang     uint16_t sriov_cap = dev->exp.sriov_cap;
2257c0fa8dfSKnut Omang 
2267c0fa8dfSKnut Omang     if (!sriov_cap || address < sriov_cap) {
2277c0fa8dfSKnut Omang         return;
2287c0fa8dfSKnut Omang     }
2297c0fa8dfSKnut Omang     off = address - sriov_cap;
2307c0fa8dfSKnut Omang     if (off >= PCI_EXT_CAP_SRIOV_SIZEOF) {
2317c0fa8dfSKnut Omang         return;
2327c0fa8dfSKnut Omang     }
2337c0fa8dfSKnut Omang 
2347c0fa8dfSKnut Omang     trace_sriov_config_write(dev->name, PCI_SLOT(dev->devfn),
2357c0fa8dfSKnut Omang                              PCI_FUNC(dev->devfn), off, val, len);
2367c0fa8dfSKnut Omang 
2377c0fa8dfSKnut Omang     if (range_covers_byte(off, len, PCI_SRIOV_CTRL)) {
238b1282f1eSMichael S. Tsirkin         if (dev->exp.sriov_pf.num_vfs) {
239b1282f1eSMichael S. Tsirkin             if (!(val & PCI_SRIOV_CTRL_VFE)) {
240b1282f1eSMichael S. Tsirkin                 unregister_vfs(dev);
241b1282f1eSMichael S. Tsirkin             }
242b1282f1eSMichael S. Tsirkin         } else {
2437c0fa8dfSKnut Omang             if (val & PCI_SRIOV_CTRL_VFE) {
2447c0fa8dfSKnut Omang                 register_vfs(dev);
245b1282f1eSMichael S. Tsirkin             }
2467c0fa8dfSKnut Omang         }
2477c0fa8dfSKnut Omang     }
2487c0fa8dfSKnut Omang }
2497c0fa8dfSKnut Omang 
2507c0fa8dfSKnut Omang 
251c8bc4db4SAkihiko Odaki /* Reset SR/IOV */
pcie_sriov_pf_reset(PCIDevice * dev)252c8bc4db4SAkihiko Odaki void pcie_sriov_pf_reset(PCIDevice *dev)
2537c0fa8dfSKnut Omang {
2547c0fa8dfSKnut Omang     uint16_t sriov_cap = dev->exp.sriov_cap;
255c8bc4db4SAkihiko Odaki     if (!sriov_cap) {
256c8bc4db4SAkihiko Odaki         return;
2577c0fa8dfSKnut Omang     }
258c8bc4db4SAkihiko Odaki 
259c8bc4db4SAkihiko Odaki     pci_set_word(dev->config + sriov_cap + PCI_SRIOV_CTRL, 0);
260c8bc4db4SAkihiko Odaki     unregister_vfs(dev);
261c8bc4db4SAkihiko Odaki 
26263eb76ddSAkihiko Odaki     pci_set_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF, 0);
26363eb76ddSAkihiko Odaki 
264c8bc4db4SAkihiko Odaki     /*
265c8bc4db4SAkihiko Odaki      * Default is to use 4K pages, software can modify it
266c8bc4db4SAkihiko Odaki      * to any of the supported bits
267c8bc4db4SAkihiko Odaki      */
268c8bc4db4SAkihiko Odaki     pci_set_word(dev->config + sriov_cap + PCI_SRIOV_SYS_PGSIZE, 0x1);
269c8bc4db4SAkihiko Odaki 
270c8bc4db4SAkihiko Odaki     for (uint16_t i = 0; i < PCI_NUM_REGIONS; i++) {
271c8bc4db4SAkihiko Odaki         pci_set_quad(dev->config + sriov_cap + PCI_SRIOV_BAR + i * 4,
272c8bc4db4SAkihiko Odaki                      dev->exp.sriov_pf.vf_bar_type[i]);
2737c0fa8dfSKnut Omang     }
2747c0fa8dfSKnut Omang }
2757c0fa8dfSKnut Omang 
2767c0fa8dfSKnut Omang /* Add optional supported page sizes to the mask of supported page sizes */
pcie_sriov_pf_add_sup_pgsize(PCIDevice * dev,uint16_t opt_sup_pgsize)2777c0fa8dfSKnut Omang void pcie_sriov_pf_add_sup_pgsize(PCIDevice *dev, uint16_t opt_sup_pgsize)
2787c0fa8dfSKnut Omang {
2797c0fa8dfSKnut Omang     uint8_t *cfg = dev->config + dev->exp.sriov_cap;
2807c0fa8dfSKnut Omang     uint8_t *wmask = dev->wmask + dev->exp.sriov_cap;
2817c0fa8dfSKnut Omang 
2827c0fa8dfSKnut Omang     uint16_t sup_pgsize = pci_get_word(cfg + PCI_SRIOV_SUP_PGSIZE);
2837c0fa8dfSKnut Omang 
2847c0fa8dfSKnut Omang     sup_pgsize |= opt_sup_pgsize;
2857c0fa8dfSKnut Omang 
2867c0fa8dfSKnut Omang     /*
2877c0fa8dfSKnut Omang      * Make sure the new bits are set, and that system page size
2887c0fa8dfSKnut Omang      * also can be set to any of the new values according to spec:
2897c0fa8dfSKnut Omang      */
2907c0fa8dfSKnut Omang     pci_set_word(cfg + PCI_SRIOV_SUP_PGSIZE, sup_pgsize);
2917c0fa8dfSKnut Omang     pci_set_word(wmask + PCI_SRIOV_SYS_PGSIZE, sup_pgsize);
2927c0fa8dfSKnut Omang }
2937c0fa8dfSKnut Omang 
2947c0fa8dfSKnut Omang 
pcie_sriov_vf_number(PCIDevice * dev)2957c0fa8dfSKnut Omang uint16_t pcie_sriov_vf_number(PCIDevice *dev)
2967c0fa8dfSKnut Omang {
297aa01c491SMichael S. Tsirkin     assert(pci_is_vf(dev));
2987c0fa8dfSKnut Omang     return dev->exp.sriov_vf.vf_number;
2997c0fa8dfSKnut Omang }
3007c0fa8dfSKnut Omang 
pcie_sriov_get_pf(PCIDevice * dev)3017c0fa8dfSKnut Omang PCIDevice *pcie_sriov_get_pf(PCIDevice *dev)
3027c0fa8dfSKnut Omang {
3037c0fa8dfSKnut Omang     return dev->exp.sriov_vf.pf;
3047c0fa8dfSKnut Omang }
30569387f49SŁukasz Gieryk 
pcie_sriov_get_vf_at_index(PCIDevice * dev,int n)30669387f49SŁukasz Gieryk PCIDevice *pcie_sriov_get_vf_at_index(PCIDevice *dev, int n)
30769387f49SŁukasz Gieryk {
30869387f49SŁukasz Gieryk     assert(!pci_is_vf(dev));
309ae9c192dSMichael S. Tsirkin     if (n < dev->exp.sriov_pf.num_vfs) {
31069387f49SŁukasz Gieryk         return dev->exp.sriov_pf.vf[n];
31169387f49SŁukasz Gieryk     }
31269387f49SŁukasz Gieryk     return NULL;
31369387f49SŁukasz Gieryk }
31431180dbdSAkihiko Odaki 
pcie_sriov_num_vfs(PCIDevice * dev)31531180dbdSAkihiko Odaki uint16_t pcie_sriov_num_vfs(PCIDevice *dev)
31631180dbdSAkihiko Odaki {
317ae9c192dSMichael S. Tsirkin     return dev->exp.sriov_pf.num_vfs;
31831180dbdSAkihiko Odaki }
319