Merge branch 'pci/enumeration' into next

* pci/enumeration:
  RDMA/qedr: Use pci_enable_atomic_ops_to_root()
  PCI: Add pci_enable_atomic_ops_to_root()
  PCI: Make PCI_SCAN_ALL_PCIE_DEVS work for Root as well as Downstream Ports
This commit is contained in:
Bjorn Helgaas 2018-01-31 10:10:30 -06:00 committed by Bjorn Helgaas
commit 5be31686cf
5 changed files with 104 additions and 64 deletions

View file

@ -430,59 +430,16 @@ static void qedr_remove_sysfiles(struct qedr_dev *dev)
static void qedr_pci_set_atomic(struct qedr_dev *dev, struct pci_dev *pdev)
{
struct pci_dev *bridge;
u32 ctl2, cap2;
u16 flags;
int rc;
int rc = pci_enable_atomic_ops_to_root(pdev,
PCI_EXP_DEVCAP2_ATOMIC_COMP64);
bridge = pdev->bus->self;
if (!bridge)
goto disable;
/* Check atomic routing support all the way to root complex */
while (bridge->bus->parent) {
rc = pcie_capability_read_word(bridge, PCI_EXP_FLAGS, &flags);
if (rc || ((flags & PCI_EXP_FLAGS_VERS) < 2))
goto disable;
rc = pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap2);
if (rc)
goto disable;
rc = pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2, &ctl2);
if (rc)
goto disable;
if (!(cap2 & PCI_EXP_DEVCAP2_ATOMIC_ROUTE) ||
(ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK))
goto disable;
bridge = bridge->bus->parent->self;
if (rc) {
dev->atomic_cap = IB_ATOMIC_NONE;
DP_DEBUG(dev, QEDR_MSG_INIT, "Atomic capability disabled\n");
} else {
dev->atomic_cap = IB_ATOMIC_GLOB;
DP_DEBUG(dev, QEDR_MSG_INIT, "Atomic capability enabled\n");
}
rc = pcie_capability_read_word(bridge, PCI_EXP_FLAGS, &flags);
if (rc || ((flags & PCI_EXP_FLAGS_VERS) < 2))
goto disable;
rc = pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap2);
if (rc || !(cap2 & PCI_EXP_DEVCAP2_ATOMIC_COMP64))
goto disable;
/* Set atomic operations */
pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_ATOMIC_REQ);
dev->atomic_cap = IB_ATOMIC_GLOB;
DP_DEBUG(dev, QEDR_MSG_INIT, "Atomic capability enabled\n");
return;
disable:
pcie_capability_clear_word(pdev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_ATOMIC_REQ);
dev->atomic_cap = IB_ATOMIC_NONE;
DP_DEBUG(dev, QEDR_MSG_INIT, "Atomic capability disabled\n");
}
static const struct qed_rdma_ops *qed_ops;

View file

@ -3065,6 +3065,81 @@ int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size)
return 0;
}
/**
* 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
*
* 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.
*/
int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask)
{
struct pci_bus *bus = dev->bus;
struct pci_dev *bridge;
u32 cap, ctl2;
if (!pci_is_pcie(dev))
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
* 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;
pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &cap);
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 (!bridge->has_secondary_link) {
pcie_capability_read_dword(bridge, PCI_EXP_DEVCTL2,
&ctl2);
if (ctl2 & PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK)
return -EINVAL;
}
bus = bus->parent;
}
pcie_capability_set_word(dev, PCI_EXP_DEVCTL2,
PCI_EXP_DEVCTL2_ATOMIC_REQ);
return 0;
}
EXPORT_SYMBOL(pci_enable_atomic_ops_to_root);
/**
* pci_swizzle_interrupt_pin - swizzle INTx for device behind bridge
* @dev: the PCI device

View file

@ -2248,22 +2248,27 @@ static unsigned next_fn(struct pci_bus *bus, struct pci_dev *dev, unsigned fn)
static int only_one_child(struct pci_bus *bus)
{
struct pci_dev *parent = bus->self;
if (!parent || !pci_is_pcie(parent))
return 0;
if (pci_pcie_type(parent) == PCI_EXP_TYPE_ROOT_PORT)
return 1;
struct pci_dev *bridge = bus->self;
/*
* PCIe downstream ports are bridges that normally lead to only a
* device 0, but if PCI_SCAN_ALL_PCIE_DEVS is set, scan all
* possible devices, not just device 0. See PCIe spec r3.0,
* sec 7.3.1.
* Systems with unusual topologies set PCI_SCAN_ALL_PCIE_DEVS so
* we scan for all possible devices, not just Device 0.
*/
if (parent->has_secondary_link &&
!pci_has_flag(PCI_SCAN_ALL_PCIE_DEVS))
if (pci_has_flag(PCI_SCAN_ALL_PCIE_DEVS))
return 0;
/*
* A PCIe Downstream Port normally leads to a Link with only Device
* 0 on it (PCIe spec r3.1, sec 7.3.1). As an optimization, scan
* only for Device 0 in that situation.
*
* Checking has_secondary_link is a hack to identify Downstream
* Ports because sometimes Switches are configured such that the
* PCIe Port Type labels are backwards.
*/
if (bridge && pci_is_pcie(bridge) && bridge->has_secondary_link)
return 1;
return 0;
}

View file

@ -2063,6 +2063,7 @@ void pci_request_acs(void);
bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags);
bool pci_acs_path_enabled(struct pci_dev *start,
struct pci_dev *end, u16 acs_flags);
int pci_enable_atomic_ops_to_root(struct pci_dev *dev, u32 cap_mask);
#define PCI_VPD_LRDT 0x80 /* Large Resource Data Type */
#define PCI_VPD_LRDT_ID(x) ((x) | PCI_VPD_LRDT)

View file

@ -624,7 +624,9 @@
#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */
#define PCI_EXP_DEVCAP2_ARI 0x00000020 /* Alternative Routing-ID */
#define PCI_EXP_DEVCAP2_ATOMIC_ROUTE 0x00000040 /* Atomic Op routing */
#define PCI_EXP_DEVCAP2_ATOMIC_COMP64 0x00000100 /* Atomic 64-bit compare */
#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 */
#define PCI_EXP_DEVCAP2_LTR 0x00000800 /* Latency tolerance reporting */
#define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000 /* OBFF support mechanism */
#define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000 /* New message signaling */