aboutsummaryrefslogtreecommitdiff
path: root/hw/pci/pcie_sriov.c
diff options
context:
space:
mode:
authorMichael S. Tsirkin <mst@redhat.com>2024-08-01 03:44:42 -0400
committerMichael S. Tsirkin <mst@redhat.com>2024-08-01 04:32:00 -0400
commitb1282f1e352db9947267a6524c6ded9678e82629 (patch)
tree402144b2fca75e3a8da095e09858bff9c7388ebd /hw/pci/pcie_sriov.c
parent9bab08da4e932e9c95919951792ae09d0a59f726 (diff)
downloadqemu-b1282f1e352db9947267a6524c6ded9678e82629.zip
qemu-b1282f1e352db9947267a6524c6ded9678e82629.tar.gz
qemu-b1282f1e352db9947267a6524c6ded9678e82629.tar.bz2
Revert "pcie_sriov: Reuse SR-IOV VF device instances"
This reverts commit 139610ae67f6ecf92127bb7bf53ac6265b459ec8. Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/pci/pcie_sriov.c')
-rw-r--r--hw/pci/pcie_sriov.c95
1 files changed, 55 insertions, 40 deletions
diff --git a/hw/pci/pcie_sriov.c b/hw/pci/pcie_sriov.c
index faadb0d..f0bde0d 100644
--- a/hw/pci/pcie_sriov.c
+++ b/hw/pci/pcie_sriov.c
@@ -20,16 +20,9 @@
#include "qapi/error.h"
#include "trace.h"
-static void unparent_vfs(PCIDevice *dev, uint16_t total_vfs)
-{
- for (uint16_t i = 0; i < total_vfs; i++) {
- PCIDevice *vf = dev->exp.sriov_pf.vf[i];
- object_unparent(OBJECT(vf));
- object_unref(OBJECT(vf));
- }
- g_free(dev->exp.sriov_pf.vf);
- dev->exp.sriov_pf.vf = NULL;
-}
+static PCIDevice *register_vf(PCIDevice *pf, int devfn,
+ const char *name, uint16_t vf_num);
+static void unregister_vfs(PCIDevice *dev);
bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
const char *vfname, uint16_t vf_dev_id,
@@ -37,8 +30,6 @@ bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
uint16_t vf_offset, uint16_t vf_stride,
Error **errp)
{
- BusState *bus = qdev_get_parent_bus(&dev->qdev);
- int32_t devfn = dev->devfn + vf_offset;
uint8_t *cfg = dev->config + offset;
uint8_t *wmask;
@@ -58,6 +49,7 @@ bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
offset, PCI_EXT_CAP_SRIOV_SIZEOF);
dev->exp.sriov_cap = offset;
dev->exp.sriov_pf.num_vfs = 0;
+ dev->exp.sriov_pf.vfname = g_strdup(vfname);
dev->exp.sriov_pf.vf = NULL;
pci_set_word(cfg + PCI_SRIOV_VF_OFFSET, vf_offset);
@@ -91,34 +83,14 @@ bool pcie_sriov_pf_init(PCIDevice *dev, uint16_t offset,
qdev_prop_set_bit(&dev->qdev, "multifunction", true);
- dev->exp.sriov_pf.vf = g_new(PCIDevice *, total_vfs);
-
- for (uint16_t i = 0; i < total_vfs; i++) {
- PCIDevice *vf = pci_new(devfn, vfname);
- vf->exp.sriov_vf.pf = dev;
- vf->exp.sriov_vf.vf_number = i;
-
- if (!qdev_realize(&vf->qdev, bus, errp)) {
- unparent_vfs(dev, i);
- return false;
- }
-
- /* set vid/did according to sr/iov spec - they are not used */
- pci_config_set_vendor_id(vf->config, 0xffff);
- pci_config_set_device_id(vf->config, 0xffff);
-
- dev->exp.sriov_pf.vf[i] = vf;
- devfn += vf_stride;
- }
-
return true;
}
void pcie_sriov_pf_exit(PCIDevice *dev)
{
- uint8_t *cfg = dev->config + dev->exp.sriov_cap;
-
- unparent_vfs(dev, pci_get_word(cfg + PCI_SRIOV_TOTAL_VF));
+ unregister_vfs(dev);
+ g_free((char *)dev->exp.sriov_pf.vfname);
+ dev->exp.sriov_pf.vfname = NULL;
}
void pcie_sriov_pf_init_vf_bar(PCIDevice *dev, int region_num,
@@ -184,11 +156,38 @@ void pcie_sriov_vf_register_bar(PCIDevice *dev, int region_num,
}
}
+static PCIDevice *register_vf(PCIDevice *pf, int devfn, const char *name,
+ uint16_t vf_num)
+{
+ PCIDevice *dev = pci_new(devfn, name);
+ dev->exp.sriov_vf.pf = pf;
+ dev->exp.sriov_vf.vf_number = vf_num;
+ PCIBus *bus = pci_get_bus(pf);
+ Error *local_err = NULL;
+
+ qdev_realize(&dev->qdev, &bus->qbus, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ return NULL;
+ }
+
+ /* set vid/did according to sr/iov spec - they are not used */
+ pci_config_set_vendor_id(dev->config, 0xffff);
+ pci_config_set_device_id(dev->config, 0xffff);
+
+ return dev;
+}
+
static void register_vfs(PCIDevice *dev)
{
uint16_t num_vfs;
uint16_t i;
uint16_t sriov_cap = dev->exp.sriov_cap;
+ uint16_t vf_offset =
+ pci_get_word(dev->config + sriov_cap + PCI_SRIOV_VF_OFFSET);
+ uint16_t vf_stride =
+ pci_get_word(dev->config + sriov_cap + PCI_SRIOV_VF_STRIDE);
+ int32_t devfn = dev->devfn + vf_offset;
assert(sriov_cap > 0);
num_vfs = pci_get_word(dev->config + sriov_cap + PCI_SRIOV_NUM_VF);
@@ -196,10 +195,18 @@ static void register_vfs(PCIDevice *dev)
return;
}
+ dev->exp.sriov_pf.vf = g_new(PCIDevice *, num_vfs);
+
trace_sriov_register_vfs(dev->name, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), num_vfs);
for (i = 0; i < num_vfs; i++) {
- pci_set_enabled(dev->exp.sriov_pf.vf[i], true);
+ dev->exp.sriov_pf.vf[i] = register_vf(dev, devfn,
+ dev->exp.sriov_pf.vfname, i);
+ if (!dev->exp.sriov_pf.vf[i]) {
+ num_vfs = i;
+ break;
+ }
+ devfn += vf_stride;
}
dev->exp.sriov_pf.num_vfs = num_vfs;
}
@@ -212,8 +219,12 @@ static void unregister_vfs(PCIDevice *dev)
trace_sriov_unregister_vfs(dev->name, PCI_SLOT(dev->devfn),
PCI_FUNC(dev->devfn), num_vfs);
for (i = 0; i < num_vfs; i++) {
- pci_set_enabled(dev->exp.sriov_pf.vf[i], false);
+ PCIDevice *vf = dev->exp.sriov_pf.vf[i];
+ object_unparent(OBJECT(vf));
+ object_unref(OBJECT(vf));
}
+ g_free(dev->exp.sriov_pf.vf);
+ dev->exp.sriov_pf.vf = NULL;
dev->exp.sriov_pf.num_vfs = 0;
}
@@ -235,10 +246,14 @@ void pcie_sriov_config_write(PCIDevice *dev, uint32_t address,
PCI_FUNC(dev->devfn), off, val, len);
if (range_covers_byte(off, len, PCI_SRIOV_CTRL)) {
- if (val & PCI_SRIOV_CTRL_VFE) {
- register_vfs(dev);
+ if (dev->exp.sriov_pf.num_vfs) {
+ if (!(val & PCI_SRIOV_CTRL_VFE)) {
+ unregister_vfs(dev);
+ }
} else {
- unregister_vfs(dev);
+ if (val & PCI_SRIOV_CTRL_VFE) {
+ register_vfs(dev);
+ }
}
}
}