diff options
Diffstat (limited to 'hw/pci/pcie.c')
-rw-r--r-- | hw/pci/pcie.c | 13 |
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); } } |