Provide the two combinations of Atomic Op Completion size attributes that a root port may support per PCIe Spec 7.0 section 6.15.3.1. - besides the trivial "No support" - as two new defines. Change documentation of pci_enable_atomic_ops_to_root() that these are the only ones that should be used. Also, spell out that all requested capabilities need to be supported at the root port for enable to succeed. Also emphasize that on success, this sets AtomicOpsCtl:ReqEn to 1, and leaves it untouched in case of failure. Suggested-by: Leon Romanovsky Signed-off-by: Gerd Bayer --- drivers/pci/pci.c | 13 +++++++------ include/uapi/linux/pci_regs.h | 8 ++++++++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8479c2e1f74f1044416281aba11bf071ea89488a..cc8abe6b1d07661488895876dbbcf8aaeadf4a17 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3663,15 +3663,16 @@ void pci_acs_init(struct pci_dev *dev) /** * pci_enable_atomic_ops_to_root - enable AtomicOp requests to root port * @dev: the PCI device - * @cap_mask: mask of desired AtomicOp sizes, including one or more of: - * PCI_EXP_DEVCAP2_ATOMIC_COMP32 - * PCI_EXP_DEVCAP2_ATOMIC_COMP64 - * PCI_EXP_DEVCAP2_ATOMIC_COMP128 + * @cap_mask: root port must support combinations of AtomicOp sizes + * PCI_EXP_ROOT_PORT_ATOMIC_BASE + * PCI_EXP_ROOT_PORT_ATOMIC_FULL * * Return 0 if all upstream bridges support AtomicOp routing, egress * blocking is disabled on all upstream ports, and the root port supports - * the requested completion capabilities (32-bit, 64-bit and/or 128-bit - * AtomicOp completion), or negative otherwise. + * all the requested completion capabilities (BASE: 32-bit, 64-bit or + * FULL: 32/64- and 128-bit AtomicOp completion). In that case enable the + * device to send AtomicOp requests. Otherwise, return negative and leave + * the enablement in the PCI config space untouched. */ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) { diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index 14f634ab9350d5442192162225b5e5202dbe2308..63ac62b882a94c6873a0db433ba808332ddbea04 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -669,6 +669,14 @@ #define PCI_EXP_DEVCAP2_ATOMIC_COMP32 0x00000080 /* 32b AtomicOp completion */ #define PCI_EXP_DEVCAP2_ATOMIC_COMP64 0x00000100 /* 64b AtomicOp completion */ #define PCI_EXP_DEVCAP2_ATOMIC_COMP128 0x00000200 /* 128b AtomicOp completion */ +/* PCIe spec 7.0 6.15.3.1: Root ports may support one of 2 sets of Atomic Ops */ +#define PCI_EXP_ROOT_PORT_ATOMIC_BASE \ + (PCI_EXP_DEVCAP2_ATOMIC_COMP32 | \ + PCI_EXP_DEVCAP2_ATOMIC_COMP64) +#define PCI_EXP_ROOT_PORT_ATOMIC_FULL \ + (PCI_EXP_DEVCAP2_ATOMIC_COMP32 | \ + PCI_EXP_DEVCAP2_ATOMIC_COMP64 | \ + PCI_EXP_DEVCAP2_ATOMIC_COMP128) #define PCI_EXP_DEVCAP2_LTR 0x00000800 /* Latency tolerance reporting */ #define PCI_EXP_DEVCAP2_TPH_COMP_MASK 0x00003000 /* TPH completer support */ #define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000 /* OBFF support mechanism */ -- 2.51.0 Move the check for root port requirements past the loop within pci_enable_atomic_ops_to_root() that checks on potential switch (up- and downstream) ports. Inside the loop traversing the PCI tree upwards, prepend the switch case to validate the routing capability on any port with a fallthrough-case that does the additional check for Atomic Ops not being blocked on upstream ports. Do not enable Atomic Op Requests if nothing can be learned about how the device is attached - e.g. if it is on an "isolated" bus, as in s390. Reported-by: Alexander Schmidt Cc: stable@vger.kernel.org Fixes: 430a23689dea ("PCI: Add pci_enable_atomic_ops_to_root()") Signed-off-by: Gerd Bayer --- drivers/pci/pci.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index cc8abe6b1d07661488895876dbbcf8aaeadf4a17..23db6ad5f310ed009a9b2ca4933c7498e0d22b85 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3677,7 +3677,7 @@ 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 *bridge = NULL; u32 cap, ctl2; /* @@ -3715,29 +3715,27 @@ int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask) 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: + if (!(cap & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) + return -EINVAL; + break; } - bus = bus->parent; } + /* Finally, last bridge must be root port and support requested sizes */ + if ((!bridge) || + (pci_pcie_type(bridge) != PCI_EXP_TYPE_ROOT_PORT) || + ((cap & cap_mask) != cap_mask)) + return -EINVAL; + pcie_capability_set_word(dev, PCI_EXP_DEVCTL2, PCI_EXP_DEVCTL2_ATOMIC_REQ); return 0; -- 2.51.0