Enable CXL.mem isolation during set up of CXL-capable PCIe Root Ports that have the capability. This capability is optional, so failure to enable isolation is not an error that should fail probe. Signed-off-by: Ben Cheatham <Benjamin.Cheatham@xxxxxxx> --- drivers/cxl/core/pci.c | 45 +++++++++++++++++++++++++++++++++++++++++ drivers/cxl/core/port.c | 36 +++++++++++++++++++++++++++++++++ drivers/cxl/cxl.h | 5 +++++ include/cxl/isolation.h | 10 +++++++++ 4 files changed, 96 insertions(+) diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index 3106ed6b5f49..c4d8d9690214 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -7,6 +7,7 @@ #include <linux/pci.h> #include <linux/pci-doe.h> #include <linux/aer.h> +#include <cxl/isolation.h> #include <cxlpci.h> #include <cxlmem.h> #include <cxl.h> @@ -1170,3 +1171,47 @@ int cxl_port_update_total_dports(struct cxl_port *port) return 0; } EXPORT_SYMBOL_NS_GPL(cxl_port_update_total_dports, "CXL"); + +void cxl_enable_isolation(struct cxl_dport *dport) +{ + u32 ctrl; + + ctrl = readl(dport->regs.isolation + CXL_ISOLATION_CTRL_OFFSET); + ctrl |= CXL_ISOLATION_CTRL_MEM_ISO_ENABLE; + writel(ctrl, dport->regs.isolation + CXL_ISOLATION_CTRL_OFFSET); + + dev_dbg(dport->dport_dev, "Enabled CXL.mem isolation\n"); +} + +static int cxl_dport_wait_for_rp_busy(void __iomem *reg) +{ + u32 status; + int i = 4; + + do { + status = readl(reg + CXL_ISOLATION_STATUS_OFFSET); + if (!(status & CXL_ISOLATION_STAT_RP_BUSY)) + return 0; + + msleep(500); + } while (--i); + + return -ETIMEDOUT; +} + +int cxl_disable_isolation(struct cxl_dport *dport) +{ + u32 ctrl; + int rc; + + rc = cxl_dport_wait_for_rp_busy(dport->regs.isolation); + if (rc) + return rc; + + ctrl = readl(dport->regs.isolation + CXL_ISOLATION_CTRL_OFFSET); + ctrl &= CXL_ISOLATION_CTRL_MEM_ISO_ENABLE; + writel(ctrl, dport->regs.isolation + CXL_ISOLATION_CTRL_OFFSET); + + dev_dbg(dport->dport_dev, "Disabled CXL.mem isolation\n"); + return 0; +} diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 48f632aa3c7e..71e954ebc5aa 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -10,6 +10,7 @@ #include <linux/slab.h> #include <linux/idr.h> #include <linux/node.h> +#include <cxl/isolation.h> #include <cxl/einj.h> #include <cxlmem.h> #include <cxlpci.h> @@ -1173,6 +1174,35 @@ static void cxl_dport_unlink(void *data) sysfs_remove_link(&port->dev.kobj, link_name); } +/** + * cxl_dport_enable_isolation - Enable CXL Isolation for a CXL dport. This is + * an optional capability only supported by PCIe Root Ports. + * + * @dport: CXL-capable PCIe Root Port + * + * Returns 0 if capability unsupported, or when enabled. + */ +static int cxl_dport_enable_isolation(struct cxl_dport *dport) +{ + u32 cap; + int rc; + + if (!dport->reg_map.component_map.isolation.valid) + return 0; + + rc = cxl_map_component_regs(&dport->reg_map, &dport->regs.component, + BIT(CXL_CM_CAP_CAP_ID_ISOLATION)); + if (rc) + return rc; + + cap = readl(dport->regs.isolation + CXL_ISOLATION_CAPABILITY_OFFSET); + if (!(cap & CXL_ISOLATION_CAP_MEM_ISO_SUPP)) + return 0; + + cxl_enable_isolation(dport); + return 0; +} + static struct cxl_dport * __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, int port_id, resource_size_t component_reg_phys, @@ -1235,6 +1265,12 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, dev_dbg(dport_dev, "Component Registers found for dport: %pa\n", &component_reg_phys); + if (IS_ENABLED(CONFIG_CXL_ISOLATION)) { + rc = cxl_dport_enable_isolation(dport); + if (rc) + return ERR_PTR(rc); + } + cond_cxl_root_lock(port); rc = add_dport(port, dport); cond_cxl_root_unlock(port); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index fdd7c4e024a6..999ffa05b68f 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -139,6 +139,11 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw) #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_CTRL_OFFSET 0x8 +#define CXL_ISOLATION_CTRL_MEM_ISO_ENABLE BIT(16) +#define CXL_ISOLATION_STATUS_OFFSET 0xC +#define CXL_ISOLATION_STAT_MEM_ISO BIT(8) +#define CXL_ISOLATION_STAT_RP_BUSY BIT(14) #define CXL_ISOLATION_CAPABILITY_LENGTH 0x10 /* RAS Registers CXL 2.0 8.2.5.9 CXL RAS Capability Structure */ diff --git a/include/cxl/isolation.h b/include/cxl/isolation.h index 20a3a8942b2c..429501a655dd 100644 --- a/include/cxl/isolation.h +++ b/include/cxl/isolation.h @@ -14,6 +14,16 @@ struct cxl_isolation_info { int irq; }; +struct cxl_dport; +#if IS_ENABLED(CONFIG_CXL_BUS) +void cxl_enable_isolation(struct cxl_dport *dport); +int cxl_disable_isolation(struct cxl_dport *dport); +#else /* !CONFIG_CXL_BUS */ +static inline void cxl_enable_isolation(struct cxl_dport *dport) {} +static inline int cxl_disable_isolation(struct cxl_dport *dport) +{ return -ENXIO; } +#endif /* !CONFIG_CXL_BUS */ + #ifdef CONFIG_CXL_ISOLATION struct cxl_isolation_info * pcie_cxl_dport_get_isolation_info(struct pci_dev *dport_dev); -- 2.34.1