[PATCH 03/16] PCI: PCIe portdrv: Add CXL Isolation service driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add the CXL isolation service, which will provide the necessary
information to the PCIe portdrv and CXL drivers to map, setup, and
handle CXL isolation interrupts.

Add functions to get the CXL isolation MSI/-X interrupt vector
from the PCIe portdrv.

Signed-off-by: Ben Cheatham <Benjamin.Cheatham@xxxxxxx>
---
 drivers/cxl/Kconfig              | 14 +++++
 drivers/cxl/cxl.h                |  4 ++
 drivers/pci/pcie/Makefile        |  1 +
 drivers/pci/pcie/cxl_isolation.c | 87 ++++++++++++++++++++++++++++++++
 drivers/pci/pcie/portdrv.c       |  1 +
 drivers/pci/pcie/portdrv.h       | 18 ++++++-
 6 files changed, 124 insertions(+), 1 deletion(-)
 create mode 100644 drivers/pci/pcie/cxl_isolation.c

diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig
index 57274de54a45..537e1e8e13da 100644
--- a/drivers/cxl/Kconfig
+++ b/drivers/cxl/Kconfig
@@ -247,4 +247,18 @@ config CXL_NATIVE_RAS
 	  If unsure, or if this kernel is meant for production environments,
 	  say Y.
 
+config CXL_ISOLATION
+	bool "CXL.mem Isolation Support"
+	depends on PCIEPORTBUS
+	depends on CXL_BUS=PCIEPORTBUS
+	help
+	  Enables the CXL.mem isolation PCIe port bus service driver. This
+	  driver, in combination with the CXL driver core, is responsible
+	  for managing CXL-capable PCIe root ports that undergo CXL.mem
+	  error isolation due to either a CXL.mem transaction timeout or
+	  link down condition. Without error isolation, either of these
+	  conditions will trigger a system reset.
+
+	  If unsure say 'y'
+
 endif
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 3013ba600ba3..fdd7c4e024a6 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -135,6 +135,10 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
 }
 
 /* CXL 3.2 8.2.4.24 CXL Timeout and Isolation Capability Structure */
+#define CXL_ISOLATION_CAPABILITY_OFFSET 0x0
+#define   CXL_ISOLATION_CAP_MEM_ISO_SUPP BIT(16)
+#define   CXL_ISOLATION_CAP_INTR_SUPP BIT(26)
+#define   CXL_ISOLATION_CAP_INTR_MASK GENMASK(31, 27)
 #define CXL_ISOLATION_CAPABILITY_LENGTH 0x10
 
 /* RAS Registers CXL 2.0 8.2.5.9 CXL RAS Capability Structure */
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
index cd2cb925dbd5..8b959ddb9684 100644
--- a/drivers/pci/pcie/Makefile
+++ b/drivers/pci/pcie/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_PCIE_PME)		+= pme.o
 obj-$(CONFIG_PCIE_DPC)		+= dpc.o
 obj-$(CONFIG_PCIE_PTM)		+= ptm.o
 obj-$(CONFIG_PCIE_EDR)		+= edr.o
+obj-$(CONFIG_CXL_ISOLATION)	+= cxl_isolation.o
diff --git a/drivers/pci/pcie/cxl_isolation.c b/drivers/pci/pcie/cxl_isolation.c
new file mode 100644
index 000000000000..550f16271d1c
--- /dev/null
+++ b/drivers/pci/pcie/cxl_isolation.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The CXL Isolation PCIe port service driver provides functions to allocate
+ * and set up CXL Timeout & Isolation interrupts (CXL 3.2 12.3). This driver
+ * does no actual interrupt handling, it only provides the information for
+ * the CXL driver to set up its own handling because the CXL driver is better
+ * equipped to handle isolation interrupts.
+ *
+ * Copyright (C) 2025, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Ben Cheatham <Benjamin.Cheatham@xxxxxxx>
+ */
+
+#include <linux/pci.h>
+
+#include "../../cxl/cxlpci.h"
+#include "portdrv.h"
+
+static int get_isolation_intr_vec(u32 cap)
+{
+	if (!FIELD_GET(CXL_ISOLATION_CAP_INTR_SUPP, cap) ||
+	    !FIELD_GET(CXL_ISOLATION_CAP_MEM_ISO_SUPP, cap))
+		return -ENXIO;
+
+	return FIELD_GET(CXL_ISOLATION_CAP_INTR_MASK, cap);
+}
+
+int pcie_cxliso_get_intr_vec(struct pci_dev *dev, int *vec)
+{
+	struct cxl_component_regs regs;
+	struct cxl_register_map map;
+	u32 cap;
+	int rc;
+
+	rc = cxl_find_regblock(dev, CXL_REGLOC_RBI_COMPONENT, &map);
+	if (rc)
+		return rc;
+
+	rc = cxl_setup_regs(&map);
+	if (rc)
+		return rc;
+
+	if (!map.component_map.isolation.valid)
+		return -ENXIO;
+
+	rc = cxl_map_component_regs(&map, &regs,
+				    BIT(CXL_CM_CAP_CAP_ID_ISOLATION));
+	if (rc)
+		return rc;
+
+	cap = readl(regs.isolation + CXL_ISOLATION_CAPABILITY_OFFSET);
+	rc = get_isolation_intr_vec(cap);
+	if (rc < 0) {
+		cxl_unmap_component_regs(&map, &regs,
+					 BIT(CXL_CM_CAP_CAP_ID_ISOLATION));
+		return rc;
+	}
+
+	if (vec)
+		*vec = rc;
+
+	cxl_unmap_component_regs(&map, &regs, BIT(CXL_CM_CAP_CAP_ID_ISOLATION));
+	return 0;
+
+}
+
+static int cxl_isolation_probe(struct pcie_device *dev)
+{
+	if (!pcie_is_cxl(dev->port) || pcie_cxliso_get_intr_vec(dev->port, NULL))
+		return -ENXIO;
+
+	pci_info(dev->port, "CXLISO: Signaling with IRQ %d\n", dev->irq);
+	return 0;
+}
+
+static struct pcie_port_service_driver isolationdriver = {
+	.name = "cxl_isolation",
+	.port_type = PCI_EXP_TYPE_ROOT_PORT,
+	.service = PCIE_PORT_SERVICE_CXLISO,
+	.probe = cxl_isolation_probe,
+};
+
+int __init pcie_cxliso_init(void)
+{
+	return pcie_port_service_register(&isolationdriver);
+}
diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c
index e8318fd5f6ed..465d1aec4ca6 100644
--- a/drivers/pci/pcie/portdrv.c
+++ b/drivers/pci/pcie/portdrv.c
@@ -834,6 +834,7 @@ static void __init pcie_init_services(void)
 	pcie_dpc_init();
 	pcie_bwctrl_init();
 	pcie_hp_init();
+	pcie_cxliso_init();
 }
 
 static int __init pcie_portdrv_init(void)
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index bd29d1cc7b8b..a9bfdb0b82be 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -22,8 +22,10 @@
 #define PCIE_PORT_SERVICE_DPC		(1 << PCIE_PORT_SERVICE_DPC_SHIFT)
 #define PCIE_PORT_SERVICE_BWCTRL_SHIFT	4	/* Bandwidth Controller (notifications) */
 #define PCIE_PORT_SERVICE_BWCTRL	(1 << PCIE_PORT_SERVICE_BWCTRL_SHIFT)
+#define PCIE_PORT_SERVICE_CXLISO_SHIFT	5	/* CXL Timeout & Isolation */
+#define PCIE_PORT_SERVICE_CXLISO	(1 << PCIE_PORT_SERVICE_CXLISO_SHIFT)
 
-#define PCIE_PORT_DEVICE_MAXSERVICES   5
+#define PCIE_PORT_DEVICE_MAXSERVICES   6
 
 extern bool pcie_ports_dpc_native;
 
@@ -53,6 +55,12 @@ static inline int pcie_dpc_init(void) { return 0; }
 
 int pcie_bwctrl_init(void);
 
+#ifdef CONFIG_CXL_ISOLATION
+int pcie_cxliso_init(void);
+#else
+static inline int pcie_cxliso_init(void) { return 0; }
+#endif
+
 /* Port Type */
 #define PCIE_ANY_PORT			(~0)
 
@@ -123,4 +131,12 @@ static inline void pcie_pme_interrupt_enable(struct pci_dev *dev, bool en) {}
 #endif /* !CONFIG_PCIE_PME */
 
 struct device *pcie_port_find_device(struct pci_dev *dev, u32 service);
+
+#ifdef CONFIG_CXL_ISOLATION
+int pcie_cxliso_get_intr_vec(struct pci_dev *dev, int *vec);
+#else
+static inline int pcie_cxliso_get_intr_vec(struct pci_dev *dev, int *vec)
+{ return -ENXIO; }
+#endif
+
 #endif /* _PORTDRV_H_ */
-- 
2.34.1





[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]
  Powered by Linux