RDMA/qedr: properly check atomic capabilities
authorAmrani, Ram <Ram.Amrani@cavium.com>
Thu, 27 Apr 2017 10:35:32 +0000 (13:35 +0300)
committerDoug Ledford <dledford@redhat.com>
Fri, 28 Apr 2017 16:47:57 +0000 (12:47 -0400)
After checking the path upwards towards root complex, actualy check
root complex atomic_req capability, and not our own NIC.
Verify that the PCIe device control register's atomic egress block
is cleared in the path.
Verify that the PCIe version is at least 2.

Signed-off-by: Ram Amrani <Ram.Amrani@cavium.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/hw/qedr/main.c
include/uapi/linux/pci_regs.h

index ced0461d6e9ff822633d60505d4b390450f7a082..c64dabe8ae6e15ffbab147fb31db209cf58bf5a3 100644 (file)
@@ -340,43 +340,58 @@ 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 val;
-
-       dev->atomic_cap = IB_ATOMIC_NONE;
+       u32 ctl2, cap2;
+       u16 flags;
+       int rc;
 
        bridge = pdev->bus->self;
        if (!bridge)
-               return;
-
-       /* Check whether we are connected directly or via a switch */
-       while (bridge && bridge->bus->parent) {
-               DP_DEBUG(dev, QEDR_MSG_INIT,
-                        "Device is not connected directly to root. bridge->bus->number=%d primary=%d\n",
-                        bridge->bus->number, bridge->bus->primary);
-               /* Need to check Atomic Op Routing Supported all the way to
-                * root complex.
-                */
-               pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &val);
-               if (!(val & PCI_EXP_DEVCAP2_ATOMIC_ROUTE)) {
-                       pcie_capability_clear_word(pdev,
-                                                  PCI_EXP_DEVCTL2,
-                                                  PCI_EXP_DEVCTL2_ATOMIC_REQ);
-                       return;
-               }
+               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;
        }
-       bridge = pdev->bus->self;
 
-       /* according to bridge capability */
-       pcie_capability_read_dword(bridge, PCI_EXP_DEVCAP2, &val);
-       if (val & PCI_EXP_DEVCAP2_ATOMIC_COMP64) {
-               pcie_capability_set_word(pdev, PCI_EXP_DEVCTL2,
-                                        PCI_EXP_DEVCTL2_ATOMIC_REQ);
-               dev->atomic_cap = IB_ATOMIC_GLOB;
-       } else {
-               pcie_capability_clear_word(pdev, PCI_EXP_DEVCTL2,
-                                          PCI_EXP_DEVCTL2_ATOMIC_REQ);
-       }
+       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;
index 634c9c44ed6cb2173174efab81b0826f28c2dcd3..18a26c16bd808204c5155af45ba5686a1d8795dd 100644 (file)
 #define  PCI_EXP_DEVCTL2_COMP_TIMEOUT  0x000f  /* Completion Timeout Value */
 #define  PCI_EXP_DEVCTL2_ARI           0x0020  /* Alternative Routing-ID */
 #define PCI_EXP_DEVCTL2_ATOMIC_REQ     0x0040  /* Set Atomic requests */
+#define PCI_EXP_DEVCTL2_ATOMIC_EGRESS_BLOCK 0x0080 /* Block atomic egress */
 #define  PCI_EXP_DEVCTL2_IDO_REQ_EN    0x0100  /* Allow IDO for requests */
 #define  PCI_EXP_DEVCTL2_IDO_CMP_EN    0x0200  /* Allow IDO for completions */
 #define  PCI_EXP_DEVCTL2_LTR_EN                0x0400  /* Enable LTR mechanism */