aboutsummaryrefslogtreecommitdiff
path: root/hw/pci/pcie.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/pci/pcie.c')
-rw-r--r--hw/pci/pcie.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
index 3f7c366093..3618d6ab2e 100644
--- a/hw/pci/pcie.c
+++ b/hw/pci/pcie.c
@@ -834,9 +834,12 @@ void pcie_add_capability(PCIDevice *dev,
/*
* Sync the PCIe Link Status negotiated speed and width of a bridge with the
* downstream device. If downstream device is not present, re-write with the
- * Link Capability fields. Limit width and speed to bridge capabilities for
- * compatibility. Use config_read to access the downstream device since it
- * could be an assigned device with volatile link information.
+ * Link Capability fields. If downstream device reports invalid width or
+ * speed, replace with minimum values (LnkSta fields are RsvdZ on VFs but such
+ * values interfere with PCIe native hotplug detecting new devices). Limit
+ * width and speed to bridge capabilities for compatibility. Use config_read
+ * to access the downstream device since it could be an assigned device with
+ * volatile link information.
*/
void pcie_sync_bridge_lnk(PCIDevice *bridge_dev)
{
@@ -856,11 +859,15 @@ void pcie_sync_bridge_lnk(PCIDevice *bridge_dev)
if ((lnksta & PCI_EXP_LNKSTA_NLW) > (lnkcap & PCI_EXP_LNKCAP_MLW)) {
lnksta &= ~PCI_EXP_LNKSTA_NLW;
lnksta |= lnkcap & PCI_EXP_LNKCAP_MLW;
+ } else if (!(lnksta & PCI_EXP_LNKSTA_NLW)) {
+ lnksta |= QEMU_PCI_EXP_LNKSTA_NLW(QEMU_PCI_EXP_LNK_X1);
}
if ((lnksta & PCI_EXP_LNKSTA_CLS) > (lnkcap & PCI_EXP_LNKCAP_SLS)) {
lnksta &= ~PCI_EXP_LNKSTA_CLS;
lnksta |= lnkcap & PCI_EXP_LNKCAP_SLS;
+ } else if (!(lnksta & PCI_EXP_LNKSTA_CLS)) {
+ lnksta |= QEMU_PCI_EXP_LNKSTA_CLS(QEMU_PCI_EXP_LNK_2_5GT);
}
}