Merge branch 'pci/atomics'

- Don't enable AtomicOps by RCiEPs since none of them need Atomic Ops and
  we can't tell whether the Root Complex would support them (Gerd Bayer)

- Enable AtomicOps only if we know the Root Port supports them (Gerd Bayer)

* pci/atomics:
  PCI: Update PCIe spec references for AtomicOps
  PCI: Enable AtomicOps only if Root Port supports them
  PCI: Do not enable AtomicOps by RCiEPs
This commit is contained in:
Bjorn Helgaas 2026-04-13 12:50:02 -05:00
commit 31e39c9ae1

View File

@ -3674,12 +3674,11 @@ void pci_acs_init(struct pci_dev *dev)
*/
int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask)
{
struct pci_bus *bus = dev->bus;
struct pci_dev *bridge;
struct pci_dev *root, *bridge;
u32 cap, ctl2;
/*
* Per PCIe r5.0, sec 9.3.5.10, the AtomicOp Requester Enable bit
* Per PCIe r7.0, sec 7.5.3.16, the AtomicOp Requester Enable bit
* in Device Control 2 is reserved in VFs and the PF value applies
* to all associated VFs.
*/
@ -3690,50 +3689,49 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask)
return -EINVAL;
/*
* Per PCIe r4.0, sec 6.15, endpoints and root ports may be
* AtomicOp requesters. For now, we only support endpoints as
* requesters and root ports as completers. No endpoints as
* Per PCIe r7.0, sec 6.15, endpoints and root ports may be
* AtomicOp requesters. For now, we only support (legacy) endpoints
* as requesters and root ports as completers. No endpoints as
* completers, and no peer-to-peer.
*/
switch (pci_pcie_type(dev)) {
case PCI_EXP_TYPE_ENDPOINT:
case PCI_EXP_TYPE_LEG_END:
case PCI_EXP_TYPE_RC_END:
break;
default:
return -EINVAL;
}
while (bus->parent) {
bridge = bus->self;
root = pcie_find_root_port(dev);
if (!root)
return -EINVAL;
pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap);
pcie_capability_read_dword(root, PCI_EXP_DEVCAP2, &cap);
if ((cap & cap_mask) != cap_mask)
return -EINVAL;
bridge = pci_upstream_bridge(dev);
while (bridge != root) {
switch (pci_pcie_type(bridge)) {
/* Ensure switch ports support AtomicOp routing */
case PCI_EXP_TYPE_UPSTREAM:
case PCI_EXP_TYPE_DOWNSTREAM:
if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE))
return -EINVAL;
break;
/* Ensure root port supports all the sizes we care about */
case PCI_EXP_TYPE_ROOT_PORT:
if ((cap & cap_mask) != cap_mask)
return -EINVAL;
break;
}
/* Ensure upstream ports don't block AtomicOps on egress */
if (pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM) {
/* Upstream ports must not block AtomicOps on egress */
pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2,
&ctl2);
if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK)
return -EINVAL;
fallthrough;
/* All switch ports need to route AtomicOps */
case PCI_EXP_TYPE_DOWNSTREAM:
pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2,
&cap);
if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE))
return -EINVAL;
break;
}
bus = bus->parent;
bridge = pci_upstream_bridge(bridge);
}
pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,