From: Yishai Hadas <[email protected]> To support P2P on Guest we must expose to the guest OS the actual PCIe topology and configuration as set by the HYP.
Otherwise, the behavior is considered as un-defined. It might fail by SW or HW. Extend both root port and downstream port to get acs ctrl bits that should match the HYP and use them in the guest. Signed-off-by: Yishai Hadas <[email protected]> Signed-off-by: Tushar Dave <[email protected]> --- hw/pci-bridge/pcie_root_port.c | 10 ++++++++-- hw/pci-bridge/xio3130_downstream.c | 10 ++++++++-- hw/pci/pcie.c | 18 +++++++++++++++--- include/hw/pci/pcie.h | 6 +++--- include/hw/pci/pcie_port.h | 1 + 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/hw/pci-bridge/pcie_root_port.c b/hw/pci-bridge/pcie_root_port.c index 7c3e78010b..3ae0b75146 100644 --- a/hw/pci-bridge/pcie_root_port.c +++ b/hw/pci-bridge/pcie_root_port.c @@ -46,6 +46,7 @@ static void rp_write_config(PCIDevice *d, uint32_t address, static void rp_reset_hold(Object *obj, ResetType type) { PCIDevice *d = PCI_DEVICE(obj); + PCIEPort *p = PCIE_PORT(d); DeviceState *qdev = DEVICE(obj); rp_aer_vector_update(d); @@ -53,7 +54,7 @@ static void rp_reset_hold(Object *obj, ResetType type) pcie_cap_deverr_reset(d); pcie_cap_slot_reset(d); pcie_cap_arifwd_reset(d); - pcie_acs_reset(d); + pcie_acs_reset(d, p->acs_ctrl); pcie_aer_root_reset(d); pci_bridge_reset(qdev); pci_bridge_disable_base_limit(d); @@ -118,11 +119,15 @@ static void rp_realize(PCIDevice *d, Error **errp) rp_aer_vector_update(d); if (rpc->acs_offset) { - pcie_acs_init(d, rpc->acs_offset); + rc = pcie_acs_init(d, rpc->acs_offset, p->acs_ctrl, errp); + if (rc < 0) { + goto err; + } } return; err: + pcie_aer_exit(d); pcie_chassis_del_slot(s); err_pcie_cap: pcie_cap_exit(d); @@ -151,6 +156,7 @@ static void rp_exit(PCIDevice *d) static const Property rp_props[] = { DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present, QEMU_PCIE_SLTCAP_PCP_BITNR, true), + DEFINE_PROP_UINT16("acs-ctrl", PCIEPort, acs_ctrl, 0), }; static void rp_instance_post_init(Object *obj) diff --git a/hw/pci-bridge/xio3130_downstream.c b/hw/pci-bridge/xio3130_downstream.c index 87ba30eb36..9829832c39 100644 --- a/hw/pci-bridge/xio3130_downstream.c +++ b/hw/pci-bridge/xio3130_downstream.c @@ -58,11 +58,12 @@ static void xio3130_downstream_write_config(PCIDevice *d, uint32_t address, static void xio3130_downstream_reset(DeviceState *qdev) { PCIDevice *d = PCI_DEVICE(qdev); + PCIEPort *p = PCIE_PORT(d); pcie_cap_deverr_reset(d); pcie_cap_slot_reset(d); pcie_cap_arifwd_reset(d); - pcie_acs_reset(d); + pcie_acs_reset(d, p->acs_ctrl); pci_bridge_reset(qdev); } @@ -115,12 +116,16 @@ static void xio3130_downstream_realize(PCIDevice *d, Error **errp) } if (d->cap_present & QEMU_PCIE_CAP_ACS) { - pcie_acs_init(d, XIO3130_ACS_OFFSET); + rc = pcie_acs_init(d, XIO3130_ACS_OFFSET, p->acs_ctrl, errp); + if (rc < 0) { + goto err; + } } return; err: + pcie_aer_exit(d); pcie_chassis_del_slot(s); err_pcie_cap: pcie_cap_exit(d); @@ -144,6 +149,7 @@ static void xio3130_downstream_exitfn(PCIDevice *d) static const Property xio3130_downstream_props[] = { DEFINE_PROP_BIT(COMPAT_PROP_PCP, PCIDevice, cap_present, QEMU_PCIE_SLTCAP_PCP_BITNR, true), + DEFINE_PROP_UINT16("acs-ctrl", PCIEPort, acs_ctrl, 0), }; static const VMStateDescription vmstate_xio3130_downstream = { diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c index 42bcb9206d..c36f8c58c6 100644 --- a/hw/pci/pcie.c +++ b/hw/pci/pcie.c @@ -1260,7 +1260,8 @@ void pcie_ats_init(PCIDevice *dev, uint16_t offset, bool aligned) } /* ACS (Access Control Services) */ -void pcie_acs_init(PCIDevice *dev, uint16_t offset) +int pcie_acs_init(PCIDevice *dev, uint16_t offset, uint16_t ctrl_bits, + Error **errp) { bool is_downstream = pci_is_express_downstream_port(dev); uint16_t cap_bits = 0; @@ -1284,16 +1285,27 @@ void pcie_acs_init(PCIDevice *dev, uint16_t offset) */ cap_bits = PCI_ACS_SV | PCI_ACS_TB | PCI_ACS_RR | PCI_ACS_CR | PCI_ACS_UF | PCI_ACS_DT; + + if (ctrl_bits & ~cap_bits) { + error_setg(errp, + "Unsupported ACS capabilities 0x%hx were supplied. " + "Supported capabilities are 0x%hx", + ctrl_bits & ~cap_bits, cap_bits); + return -EINVAL; + } } pci_set_word(dev->config + offset + PCI_ACS_CAP, cap_bits); pci_set_word(dev->wmask + offset + PCI_ACS_CTRL, cap_bits); + pci_set_word(dev->config + offset + PCI_ACS_CTRL, ctrl_bits); + + return 0; } -void pcie_acs_reset(PCIDevice *dev) +void pcie_acs_reset(PCIDevice *dev, uint16_t val) { if (dev->exp.acs_cap) { - pci_set_word(dev->config + dev->exp.acs_cap + PCI_ACS_CTRL, 0); + pci_set_word(dev->config + dev->exp.acs_cap + PCI_ACS_CTRL, val); } } diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h index ec25e7a7de..1ab7b3eee5 100644 --- a/include/hw/pci/pcie.h +++ b/include/hw/pci/pcie.h @@ -137,9 +137,9 @@ bool pcie_insert_capability(PCIDevice *dev, uint16_t cap_id, uint8_t cap_ver, uint16_t offset, uint16_t size); void pcie_sync_bridge_lnk(PCIDevice *dev); -void pcie_acs_init(PCIDevice *dev, uint16_t offset); -void pcie_acs_reset(PCIDevice *dev); - +int pcie_acs_init(PCIDevice *dev, uint16_t offset, uint16_t ctrl_bits, + Error **errp); +void pcie_acs_reset(PCIDevice *dev, uint16_t val); void pcie_ari_init(PCIDevice *dev, uint16_t offset); void pcie_dev_ser_num_init(PCIDevice *dev, uint16_t offset, uint64_t ser_num); void pcie_ats_init(PCIDevice *dev, uint16_t offset, bool aligned); diff --git a/include/hw/pci/pcie_port.h b/include/hw/pci/pcie_port.h index b28af067a6..2ad9a563d9 100644 --- a/include/hw/pci/pcie_port.h +++ b/include/hw/pci/pcie_port.h @@ -36,6 +36,7 @@ struct PCIEPort { /* pci express switch port */ uint8_t port; + uint16_t acs_ctrl; }; void pcie_port_init_reg(PCIDevice *d); -- 2.34.1
