diff --git a/hypervisor/dm/vpci/pci_pt.c b/hypervisor/dm/vpci/pci_pt.c index 541a7060f..324dad981 100644 --- a/hypervisor/dm/vpci/pci_pt.c +++ b/hypervisor/dm/vpci/pci_pt.c @@ -345,6 +345,21 @@ static void init_bars(struct pci_vdev *vdev, bool is_sriov_bar) } } +void vdev_pt_hide_sriov_cap(struct pci_vdev *vdev) +{ + uint32_t pre_pos = vdev->pdev->sriov.pre_pos; + uint32_t pre_hdr, hdr, vhdr; + + pre_hdr = pci_pdev_read_cfg(vdev->pdev->bdf, pre_pos, 4U); + hdr = pci_pdev_read_cfg(vdev->pdev->bdf, vdev->pdev->sriov.capoff, 4U); + + vhdr = pre_hdr & 0xfffffU; + vhdr |= hdr & 0xfff00000U; + pci_vdev_write_vcfg(vdev, pre_pos, 4U, vhdr); + vdev->pdev->sriov.hide_sriov = true; + + pr_acrnlog("Hide sriov cap for %02x:%02x.%x", vdev->pdev->bdf.bits.b, vdev->pdev->bdf.bits.d, vdev->pdev->bdf.bits.f); +} /* * @brief Initialize a specified passthrough vdev structure. * diff --git a/hypervisor/dm/vpci/vpci.c b/hypervisor/dm/vpci/vpci.c index 1c2ec5432..6b4e6ed69 100644 --- a/hypervisor/dm/vpci/vpci.c +++ b/hypervisor/dm/vpci/vpci.c @@ -494,11 +494,13 @@ static int32_t write_pt_dev_cfg(struct pci_vdev *vdev, uint32_t offset, } else if (sriovcap_access(vdev, offset)) { write_sriov_cap_reg(vdev, offset, bytes, val); } else { - if (!is_quirk_ptdev(vdev)) { - /* passthru to physical device */ - pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, val); - } else { - ret = -ENODEV; + if (offset != vdev->pdev->sriov.pre_pos) { + if (!is_quirk_ptdev(vdev)) { + /* passthru to physical device */ + pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, val); + } else { + ret = -ENODEV; + } } } @@ -519,7 +521,9 @@ static int32_t read_pt_dev_cfg(const struct pci_vdev *vdev, uint32_t offset, } else if (sriovcap_access(vdev, offset)) { read_sriov_cap_reg(vdev, offset, bytes, val); } else { - if (!is_quirk_ptdev(vdev)) { + if (offset == vdev->pdev->sriov.pre_pos) { + *val = pci_vdev_read_vcfg(vdev, offset, bytes); + } else if (!is_quirk_ptdev(vdev)) { /* passthru to physical device */ *val = pci_pdev_read_cfg(vdev->pdev->bdf, offset, bytes); } else { diff --git a/hypervisor/dm/vpci/vpci_priv.h b/hypervisor/dm/vpci/vpci_priv.h index ce5bd2c49..9e7e8fb60 100644 --- a/hypervisor/dm/vpci/vpci_priv.h +++ b/hypervisor/dm/vpci/vpci_priv.h @@ -156,4 +156,6 @@ void pci_vdev_write_vcfg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t pci_vdev_read_vbar(const struct pci_vdev *vdev, uint32_t idx); void pci_vdev_write_vbar(struct pci_vdev *vdev, uint32_t idx, uint32_t val); + +void vdev_pt_hide_sriov_cap(struct pci_vdev *vdev); #endif /* VPCI_PRIV_H_ */ diff --git a/hypervisor/dm/vpci/vsriov.c b/hypervisor/dm/vpci/vsriov.c index a9bb4bbec..4fc71a562 100644 --- a/hypervisor/dm/vpci/vsriov.c +++ b/hypervisor/dm/vpci/vsriov.c @@ -273,8 +273,12 @@ void init_vsriov(struct pci_vdev *vdev) */ void read_sriov_cap_reg(const struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t *val) { - /* no need to do emulation, passthrough to physical device directly */ - *val = pci_pdev_read_cfg(vdev->pdev->bdf, offset, bytes); + if (!vdev->pdev->sriov.hide_sriov) { + /* no need to do emulation, passthrough to physical device directly */ + *val = pci_pdev_read_cfg(vdev->pdev->bdf, offset, bytes); + } else { + *val = 0xffffffffU; + } } /** @@ -287,41 +291,43 @@ void write_sriov_cap_reg(struct pci_vdev *vdev, uint32_t offset, uint32_t bytes, uint32_t reg; reg = offset - vdev->sriov.capoff; - if (reg == PCIR_SRIOV_CONTROL) { - bool enable; + if (!vdev->pdev->sriov.hide_sriov) { + if (reg == PCIR_SRIOV_CONTROL) { + bool enable; - enable = (((val & PCIM_SRIOV_VF_ENABLE) != 0U) ? true : false); - if (enable != is_vf_enabled(vdev)) { - if (enable) { - /* - * set VF_ENABLE to PF physical device before enable_vfs - * since need to ask hardware to create VF physical - * devices firstly - */ - pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, val); - enable_vfs(vdev); + enable = (((val & PCIM_SRIOV_VF_ENABLE) != 0U) ? true : false); + if (enable != is_vf_enabled(vdev)) { + if (enable) { + /* + * set VF_ENABLE to PF physical device before enable_vfs + * since need to ask hardware to create VF physical + * devices firstly + */ + pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, val); + enable_vfs(vdev); + } else { + disable_vfs(vdev); + pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, val); + } } else { - disable_vfs(vdev); + pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, val); + } + } else if (reg == PCIR_SRIOV_NUMVFS) { + uint16_t total; + + total = read_sriov_reg(vdev, PCIR_SRIOV_TOTAL_VFS); + /* + * sanity check for NumVFs register based on PCE Express Base 4.0 9.3.3.7 chapter + * The results are undefined if NumVFs is set to a value greater than TotalVFs + * NumVFs may only be written while VF Enable is Clear + * If NumVFs is written when VF Enable is Set, the results are undefined + */ + if ((((uint16_t)(val & 0xFFU)) <= total) && (!is_vf_enabled(vdev))) { pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, val); } } else { pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, val); } - } else if (reg == PCIR_SRIOV_NUMVFS) { - uint16_t total; - - total = read_sriov_reg(vdev, PCIR_SRIOV_TOTAL_VFS); - /* - * sanity check for NumVFs register based on PCE Express Base 4.0 9.3.3.7 chapter - * The results are undefined if NumVFs is set to a value greater than TotalVFs - * NumVFs may only be written while VF Enable is Clear - * If NumVFs is written when VF Enable is Set, the results are undefined - */ - if ((((uint16_t)(val & 0xFFU)) <= total) && (!is_vf_enabled(vdev))) { - pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, val); - } - } else { - pci_pdev_write_cfg(vdev->pdev->bdf, offset, bytes, val); } } diff --git a/hypervisor/hw/pci.c b/hypervisor/hw/pci.c index 2096630b4..30086f7b2 100644 --- a/hypervisor/hw/pci.c +++ b/hypervisor/hw/pci.c @@ -663,7 +663,7 @@ static inline uint32_t pci_pdev_get_nr_bars(uint8_t hdr_type) */ static void pci_enumerate_ext_cap(struct pci_pdev *pdev) { - uint32_t hdr, pos; + uint32_t hdr, pos, pre_pos = 0U; pos = PCI_ECAP_BASE_PTR; @@ -673,12 +673,13 @@ static void pci_enumerate_ext_cap(struct pci_pdev *pdev) { if (PCI_ECAP_ID(hdr) == PCIZ_SRIOV) { pdev->sriov.capoff = pos; pdev->sriov.caplen = PCI_SRIOV_CAP_LEN; + pdev->sriov.pre_pos = pre_pos; } + pre_pos = pos; pos = PCI_ECAP_NEXT(hdr); if (pos == 0U) { break; } - hdr = pci_pdev_read_cfg(pdev->bdf, pos, 4U); }; } diff --git a/hypervisor/include/hw/pci.h b/hypervisor/include/hw/pci.h index a79b73f8b..a4bc48be3 100644 --- a/hypervisor/include/hw/pci.h +++ b/hypervisor/include/hw/pci.h @@ -221,6 +221,8 @@ struct pci_msix_cap { struct pci_sriov_cap { uint32_t capoff; uint32_t caplen; + uint32_t pre_pos; + bool hide_sriov; }; struct pci_pdev {