From: Ben Cheatham <Benjamin.Cheatham@amd.com>
To: <linux-cxl@vger.kernel.org>, <linux-pci@vger.kernel.org>
Cc: <dave@stgolabs.net>, <jonathan.cameron@huawei.com>,
<dave.jiang@intel.com>, <alison.schofield@intel.com>,
<vishal.l.verma@intel.com>, <ira.weiny@intel.com>,
<dan.j.williams@intel.com>, <bhelgaas@google.com>,
<benjamin.cheatham@amd.com>
Subject: [RFC PATCH 2/6] pcie/cxl_timeout: Add CXL Timeout & Isolation service driver
Date: Thu, 15 Feb 2024 13:40:44 -0600 [thread overview]
Message-ID: <20240215194048.141411-3-Benjamin.Cheatham@amd.com> (raw)
In-Reply-To: <20240215194048.141411-1-Benjamin.Cheatham@amd.com>
Add a CXL Timeout & Isolation (CXL 3.0 12.3) service driver to the
PCIe port bus driver for CXL root ports. The service will support
enabling/programming CXL.mem transaction timeout, error isolation,
and interrupt handling.
Add code to find and map CXL Timeout & Isolation capability register
(CXL 3.0 8.2.4.23.1) from service driver. Then use capability register
mapping to enable CXL.mem transaction timeout with the default value.
Signed-off-by: Ben Cheatham <Benjamin.Cheatham@amd.com>
---
drivers/cxl/cxl.h | 4 +
drivers/pci/pcie/Kconfig | 10 ++
drivers/pci/pcie/Makefile | 1 +
drivers/pci/pcie/cxl_timeout.c | 197 +++++++++++++++++++++++++++++++++
drivers/pci/pcie/portdrv.c | 1 +
drivers/pci/pcie/portdrv.h | 10 +-
6 files changed, 222 insertions(+), 1 deletion(-)
create mode 100644 drivers/pci/pcie/cxl_timeout.c
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 87f3178d6642..0c65f4ec7aae 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -129,7 +129,11 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
/* CXL 3.0 8.2.4.23 CXL Timeout and Isolation Capability Structure */
#define CXL_TIMEOUT_CAPABILITY_OFFSET 0x0
+#define CXL_TIMEOUT_CAP_MEM_TIMEOUT_SUPP BIT(4)
+#define CXL_TIMEOUT_CONTROL_OFFSET 0x8
+#define CXL_TIMEOUT_CONTROL_MEM_TIMEOUT_ENABLE BIT(4)
#define CXL_TIMEOUT_CAPABILITY_LENGTH 0x10
+
/* RAS Registers CXL 2.0 8.2.5.9 CXL RAS Capability Structure */
#define CXL_RAS_UNCORRECTABLE_STATUS_OFFSET 0x0
#define CXL_RAS_UNCORRECTABLE_STATUS_MASK (GENMASK(16, 14) | GENMASK(11, 0))
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 8999fcebde6a..27820af4502e 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -58,6 +58,16 @@ config PCIEAER_CXL
If unsure, say Y.
+config PCIE_CXL_TIMEOUT
+ bool "PCI Express CXL.mem Timeout & Isolation Interrupt support"
+ depends on PCIEPORTBUS
+ depends on CXL_BUS=PCIEPORTBUS && CXL_PORT
+ help
+ Enables the CXL.mem Timeout & Isolation PCIE port service driver. This
+ driver, in combination with the CXL driver core, is responsible for
+ handling CXL capable PCIE root ports that undergo CXL.mem error isolation
+ due to either a CXL.mem transaction timeout or uncorrectable device error.
+
#
# PCI Express ECRC
#
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
index 8de4ed5f98f1..433ef08efc6f 100644
--- a/drivers/pci/pcie/Makefile
+++ b/drivers/pci/pcie/Makefile
@@ -13,3 +13,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_PCIE_CXL_TIMEOUT) += cxl_timeout.o
diff --git a/drivers/pci/pcie/cxl_timeout.c b/drivers/pci/pcie/cxl_timeout.c
new file mode 100644
index 000000000000..84f2df0e0397
--- /dev/null
+++ b/drivers/pci/pcie/cxl_timeout.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Implements CXL Timeout & Isolation (CXL 3.0 12.3.2) interrupt support as a
+ * PCIE port service driver. The driver is set up such that near all of the
+ * work for setting up and handling interrupts are in this file, while the
+ * CXL core enables the interrupts during port enumeration.
+ *
+ * Copyright (C) 2024, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Author: Ben Cheatham <Benjamin.Cheatham@amd.com>
+ */
+
+#define pr_fmt(fmt) "cxl_timeout: " fmt
+#define dev_fmt pr_fmt
+
+#include <linux/pci.h>
+#include <linux/acpi.h>
+
+#include "../../cxl/cxlpci.h"
+#include "portdrv.h"
+
+struct cxl_timeout {
+ struct pcie_device *dev;
+ void __iomem *regs;
+ u32 cap;
+};
+
+struct pcie_cxlt_data {
+ struct cxl_timeout *cxlt;
+ struct cxl_dport *dport;
+};
+
+static int cxl_map_timeout_regs(struct pci_dev *port,
+ struct cxl_register_map *map,
+ struct cxl_component_regs *regs)
+{
+ int rc = 0;
+
+ rc = cxl_find_regblock(port, CXL_REGLOC_RBI_COMPONENT, map);
+ if (rc)
+ return rc;
+
+ rc = cxl_setup_regs(map);
+ if (rc)
+ return rc;
+
+ rc = cxl_map_component_regs(map, regs,
+ BIT(CXL_CM_CAP_CAP_ID_TIMEOUT));
+ return rc;
+}
+
+static void cxl_unmap_timeout_regs(struct pci_dev *port,
+ struct cxl_register_map *map,
+ struct cxl_component_regs *regs)
+{
+ struct cxl_reg_map *timeout_map = &map->component_map.timeout;
+
+ devm_iounmap(map->host, regs->timeout);
+ devm_release_mem_region(map->host, map->resource + timeout_map->offset,
+ timeout_map->size);
+}
+
+static struct cxl_timeout *cxl_create_cxlt(struct pcie_device *dev)
+{
+ struct cxl_component_regs *regs;
+ struct cxl_register_map *map;
+ struct cxl_timeout *cxlt;
+ int rc;
+
+ regs = devm_kmalloc(&dev->device, sizeof(*regs), GFP_KERNEL);
+ if (!regs)
+ return ERR_PTR(-ENOMEM);
+
+ map = devm_kmalloc(&dev->device, sizeof(*map), GFP_KERNEL);
+ if (!map) {
+ devm_kfree(&dev->device, regs);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ rc = cxl_map_timeout_regs(dev->port, map, regs);
+ if (rc)
+ goto err;
+
+ cxlt = devm_kmalloc(&dev->device, sizeof(*cxlt), GFP_KERNEL);
+ if (!cxlt)
+ goto err;
+
+ cxlt->regs = regs->timeout;
+ cxlt->dev = dev;
+ cxlt->cap = readl(cxlt->regs + CXL_TIMEOUT_CAPABILITY_OFFSET);
+
+ return cxlt;
+
+err:
+ cxl_unmap_timeout_regs(dev->port, map, regs);
+ return ERR_PTR(rc);
+}
+
+int cxl_find_timeout_cap(struct pci_dev *dev, u32 *cap)
+{
+ struct cxl_component_regs regs;
+ struct cxl_register_map map;
+ int rc = 0;
+
+ rc = cxl_map_timeout_regs(dev, &map, ®s);
+ if (rc)
+ return rc;
+
+ *cap = readl(regs.timeout + CXL_TIMEOUT_CAPABILITY_OFFSET);
+ cxl_unmap_timeout_regs(dev, &map, ®s);
+
+ return rc;
+}
+
+static struct pcie_cxlt_data *cxlt_create_pdata(struct pcie_device *dev)
+{
+ struct pcie_cxlt_data *data;
+
+ data = devm_kzalloc(&dev->device, sizeof(*data), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(data))
+ return ERR_PTR(-ENOMEM);
+
+ data->cxlt = cxl_create_cxlt(dev);
+ if (IS_ERR_OR_NULL(data->cxlt))
+ return ERR_PTR(PTR_ERR(data->cxlt));
+
+ data->dport = NULL;
+
+ return data;
+}
+
+static void cxl_disable_timeout(void *data)
+{
+ struct cxl_timeout *cxlt = data;
+ u32 cntrl = readl(cxlt->regs + CXL_TIMEOUT_CONTROL_OFFSET);
+
+ cntrl &= ~CXL_TIMEOUT_CONTROL_MEM_TIMEOUT_ENABLE;
+ writel(cntrl, cxlt->regs + CXL_TIMEOUT_CONTROL_OFFSET);
+}
+
+static int cxl_enable_timeout(struct pcie_device *dev, struct cxl_timeout *cxlt)
+{
+ u32 cntrl;
+
+ if (!cxlt || !FIELD_GET(CXL_TIMEOUT_CAP_MEM_TIMEOUT_SUPP, cxlt->cap))
+ return -ENXIO;
+
+ cntrl = readl(cxlt->regs + CXL_TIMEOUT_CONTROL_OFFSET);
+ cntrl |= CXL_TIMEOUT_CONTROL_MEM_TIMEOUT_ENABLE;
+ writel(cntrl, cxlt->regs + CXL_TIMEOUT_CONTROL_OFFSET);
+
+ return devm_add_action_or_reset(&dev->device, cxl_disable_timeout,
+ cxlt);
+}
+
+static int cxl_timeout_probe(struct pcie_device *dev)
+{
+ struct pci_dev *port = dev->port;
+ struct pcie_cxlt_data *pdata;
+ struct cxl_timeout *cxlt;
+ int rc = 0;
+
+ /* Limit to CXL root ports */
+ if (!pci_find_dvsec_capability(port, PCI_DVSEC_VENDOR_ID_CXL,
+ CXL_DVSEC_PORT_EXTENSIONS))
+ return -ENODEV;
+
+ pdata = cxlt_create_pdata(dev);
+ if (IS_ERR_OR_NULL(pdata))
+ return PTR_ERR(pdata);
+
+ set_service_data(dev, pdata);
+ cxlt = pdata->cxlt;
+
+ rc = cxl_enable_timeout(dev, cxlt);
+ if (rc)
+ pci_dbg(dev->port, "Failed to enable CXL.mem timeout: %d\n",
+ rc);
+
+ return rc;
+}
+
+static struct pcie_port_service_driver cxltdriver = {
+ .name = "cxl_timeout",
+ .port_type = PCI_EXP_TYPE_ROOT_PORT,
+ .service = PCIE_PORT_SERVICE_CXLT,
+
+ .probe = cxl_timeout_probe,
+};
+
+int __init pcie_cxlt_init(void)
+{
+ return pcie_port_service_register(&cxltdriver);
+}
+
+MODULE_IMPORT_NS(CXL);
diff --git a/drivers/pci/pcie/portdrv.c b/drivers/pci/pcie/portdrv.c
index 14a4b89a3b83..7aa0a6f2da4e 100644
--- a/drivers/pci/pcie/portdrv.c
+++ b/drivers/pci/pcie/portdrv.c
@@ -829,6 +829,7 @@ static void __init pcie_init_services(void)
pcie_pme_init();
pcie_dpc_init();
pcie_hp_init();
+ pcie_cxlt_init();
}
static int __init pcie_portdrv_init(void)
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index 1f3803bde7ee..5395a0e36956 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_BWNOTIF_SHIFT 4 /* Bandwidth notification */
#define PCIE_PORT_SERVICE_BWNOTIF (1 << PCIE_PORT_SERVICE_BWNOTIF_SHIFT)
+#define PCIE_PORT_SERVICE_CXLT_SHIFT 5 /* CXL Timeout & Isolation */
+#define PCIE_PORT_SERVICE_CXLT (1 << PCIE_PORT_SERVICE_CXLT_SHIFT)
-#define PCIE_PORT_DEVICE_MAXSERVICES 5
+#define PCIE_PORT_DEVICE_MAXSERVICES 6
extern bool pcie_ports_dpc_native;
@@ -51,6 +53,12 @@ int pcie_dpc_init(void);
static inline int pcie_dpc_init(void) { return 0; }
#endif
+#ifdef CONFIG_PCIE_CXL_TIMEOUT
+int pcie_cxlt_init(void);
+#else
+static inline int pcie_cxlt_init(void) { return 0; }
+#endif
+
/* Port Type */
#define PCIE_ANY_PORT (~0)
--
2.34.1
next prev parent reply other threads:[~2024-02-15 19:41 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-15 19:40 [RFC PATCH 0/6] Implement initial CXL Timeout & Isolation support Ben Cheatham
2024-02-15 19:40 ` [RFC PATCH 1/6] cxl/core: Add CXL Timeout & Isolation capability parsing Ben Cheatham
2024-02-15 19:40 ` Ben Cheatham [this message]
2024-02-15 21:13 ` [RFC PATCH 2/6] pcie/cxl_timeout: Add CXL Timeout & Isolation service driver Bjorn Helgaas
2024-02-15 22:21 ` Ben Cheatham
2024-02-15 22:26 ` Bjorn Helgaas
2024-02-15 19:40 ` [RFC PATCH 3/6] pcie/cxl_timeout: Add CXL.mem timeout range programming Ben Cheatham
2024-02-15 21:35 ` Bjorn Helgaas
2024-02-15 22:21 ` Ben Cheatham
2024-02-15 22:29 ` Bjorn Helgaas
2024-02-15 22:30 ` Ben Cheatham
2024-02-15 19:40 ` [RFC PATCH 4/6] pcie/cxl_timeout: Add CXL.mem error isolation support Ben Cheatham
2024-02-15 21:49 ` Bjorn Helgaas
2024-02-15 22:21 ` Ben Cheatham
2024-02-15 19:40 ` [RFC PATCH 5/6] pcie/portdrv: Add CXL MSI/-X allocation Ben Cheatham
2024-02-15 21:51 ` Bjorn Helgaas
2024-02-15 22:22 ` Ben Cheatham
2024-02-15 19:40 ` [RFC PATCH 6/6] pcie/cxl_timeout: Add CXL.mem Timeout & Isolation interrupt support Ben Cheatham
2024-02-15 21:57 ` Bjorn Helgaas
2024-02-15 22:22 ` Ben Cheatham
2024-02-17 21:31 ` kernel test robot
2024-02-17 22:44 ` kernel test robot
2024-02-17 22:55 ` kernel test robot
2024-02-15 23:43 ` [RFC PATCH 0/6] Implement initial CXL Timeout & Isolation support Dan Williams
2024-03-25 15:15 ` Ben Cheatham
2024-03-25 15:54 ` Dan Williams
2024-04-01 19:41 ` Ben Cheatham
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240215194048.141411-3-Benjamin.Cheatham@amd.com \
--to=benjamin.cheatham@amd.com \
--cc=alison.schofield@intel.com \
--cc=bhelgaas@google.com \
--cc=dan.j.williams@intel.com \
--cc=dave.jiang@intel.com \
--cc=dave@stgolabs.net \
--cc=ira.weiny@intel.com \
--cc=jonathan.cameron@huawei.com \
--cc=linux-cxl@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=vishal.l.verma@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.