cxl: add RAS status unmasking for CXL
authorDave Jiang <dave.jiang@intel.com>
Tue, 14 Feb 2023 17:00:24 +0000 (10:00 -0700)
committerDan Williams <dan.j.williams@intel.com>
Tue, 14 Feb 2023 22:12:54 +0000 (14:12 -0800)
By default the CXL RAS mask registers bits are defaulted to 1's and
suppress all error reporting. If the kernel has negotiated ownership
of error handling for CXL then unmask the mask registers by writing 0s.

PCI_EXP_DEVCTL capability is checked to see uncorrectable or correctable
errors bits are set before unmasking the respective errors.

Acked-by: Bjorn Helgaas <bhelgaas@google.com> # pci_regs.h
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/167639402301.778884.12556849214955646539.stgit@djiang5-mobl3.local
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/cxl/cxl.h
drivers/cxl/pci.c
include/uapi/linux/pci_regs.h

index aa3af3bb73b20ae98ea10b0ad0457e7ba4449a66..197ecffce4d09a908af53849f985f762c0e27b70 100644 (file)
@@ -130,6 +130,7 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
 #define   CXL_RAS_UNCORRECTABLE_STATUS_MASK (GENMASK(16, 14) | GENMASK(11, 0))
 #define CXL_RAS_UNCORRECTABLE_MASK_OFFSET 0x4
 #define   CXL_RAS_UNCORRECTABLE_MASK_MASK (GENMASK(16, 14) | GENMASK(11, 0))
+#define   CXL_RAS_UNCORRECTABLE_MASK_F256B_MASK BIT(8)
 #define CXL_RAS_UNCORRECTABLE_SEVERITY_OFFSET 0x8
 #define   CXL_RAS_UNCORRECTABLE_SEVERITY_MASK (GENMASK(16, 14) | GENMASK(11, 0))
 #define CXL_RAS_CORRECTABLE_STATUS_OFFSET 0xC
index cc8b5a766a827ad79c1af3f6d2a47f1292a83b75..a509640994d744da97c1abb027d696c06c06a32a 100644 (file)
@@ -412,6 +412,67 @@ static bool is_cxl_restricted(struct pci_dev *pdev)
        return pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END;
 }
 
+/*
+ * CXL v3.0 6.2.3 Table 6-4
+ * The table indicates that if PCIe Flit Mode is set, then CXL is in 256B flits
+ * mode, otherwise it's 68B flits mode.
+ */
+static bool cxl_pci_flit_256(struct pci_dev *pdev)
+{
+       u16 lnksta2;
+
+       pcie_capability_read_word(pdev, PCI_EXP_LNKSTA2, &lnksta2);
+       return lnksta2 & PCI_EXP_LNKSTA2_FLIT;
+}
+
+static int cxl_pci_ras_unmask(struct pci_dev *pdev)
+{
+       struct pci_host_bridge *host_bridge = pci_find_host_bridge(pdev->bus);
+       struct cxl_dev_state *cxlds = pci_get_drvdata(pdev);
+       void __iomem *addr;
+       u32 orig_val, val, mask;
+       u16 cap;
+       int rc;
+
+       if (!cxlds->regs.ras) {
+               dev_dbg(&pdev->dev, "No RAS registers.\n");
+               return 0;
+       }
+
+       /* BIOS has CXL error control */
+       if (!host_bridge->native_cxl_error)
+               return -ENXIO;
+
+       rc = pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &cap);
+       if (rc)
+               return rc;
+
+       if (cap & PCI_EXP_DEVCTL_URRE) {
+               addr = cxlds->regs.ras + CXL_RAS_UNCORRECTABLE_MASK_OFFSET;
+               orig_val = readl(addr);
+
+               mask = CXL_RAS_UNCORRECTABLE_MASK_MASK;
+               if (!cxl_pci_flit_256(pdev))
+                       mask &= ~CXL_RAS_UNCORRECTABLE_MASK_F256B_MASK;
+               val = orig_val & ~mask;
+               writel(val, addr);
+               dev_dbg(&pdev->dev,
+                       "Uncorrectable RAS Errors Mask: %#x -> %#x\n",
+                       orig_val, val);
+       }
+
+       if (cap & PCI_EXP_DEVCTL_CERE) {
+               addr = cxlds->regs.ras + CXL_RAS_CORRECTABLE_MASK_OFFSET;
+               orig_val = readl(addr);
+               val = orig_val & ~CXL_RAS_CORRECTABLE_MASK_MASK;
+               writel(val, addr);
+               dev_dbg(&pdev->dev, "Correctable RAS Errors Mask: %#x -> %#x\n",
+                       orig_val, val);
+       }
+
+       return 0;
+}
+
 static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        struct cxl_register_map map;
@@ -489,6 +550,10 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (IS_ERR(cxlmd))
                return PTR_ERR(cxlmd);
 
+       rc = cxl_pci_ras_unmask(pdev);
+       if (rc)
+               dev_dbg(&pdev->dev, "No RAS reporting unmasked\n");
+
        pci_save_state(pdev);
 
        return rc;
index 85ab1278811e1495d1ee007dfcb0ef860a779d4c..dc2000e0fe3a33fd930e71796989d0bfe16ef9b1 100644 (file)
 #define  PCI_EXP_LNKCTL2_TX_MARGIN     0x0380 /* Transmit Margin */
 #define  PCI_EXP_LNKCTL2_HASD          0x0020 /* HW Autonomous Speed Disable */
 #define PCI_EXP_LNKSTA2                0x32    /* Link Status 2 */
+#define  PCI_EXP_LNKSTA2_FLIT          0x0400 /* Flit Mode Status */
 #define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 0x32    /* end of v2 EPs w/ link */
 #define PCI_EXP_SLTCAP2                0x34    /* Slot Capabilities 2 */
 #define  PCI_EXP_SLTCAP2_IBPD  0x00000001 /* In-band PD Disable Supported */