From eb4663b07e13bc138aad9e2a93ee9893c7139f51 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Sun, 25 Jun 2023 11:35:20 -0700 Subject: [PATCH 01/14] cxl/acpi: Probe RCRB later during RCH downstream port creation The RCRB is extracted already during ACPI CEDT table parsing while the data of this is needed not earlier than dport creation. This implementation comes with drawbacks: During ACPI table scan there is already MMIO access including mapping and unmapping, but only ACPI data should be collected here. The collected data must be transferred through a couple of interfaces until it is finally consumed when creating the dport. This causes complex data structures and function interfaces. Additionally, RCRB parsing will be extended to also extract AER data, it would be much easier do this at a later point during port and dport creation when the data structures are available to hold that data. To simplify all that, probe the RCRB at a later point during RCH downstream port creation. Change ACPI table parser to only extract the base address of either the component registers or the RCRB. Parse and extract the RCRB in devm_cxl_add_rch_dport(). This is in preparation to centralize all RCRB scanning. Signed-off-by: Robert Richter Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-2-terry.bowman@amd.com Co-developed-by: Dan Williams Link: https://lore.kernel.org/r/20230622205523.85375-3-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/acpi.c | 51 +++++++++++++++-------------------- drivers/cxl/core/core.h | 8 ++++++ drivers/cxl/core/port.c | 21 +++++++++++---- drivers/cxl/core/regs.c | 15 ++++++++--- drivers/cxl/cxl.h | 12 +++------ drivers/cxl/mem.c | 4 +-- tools/testing/cxl/Kbuild | 3 ++- tools/testing/cxl/test/cxl.c | 10 ------- tools/testing/cxl/test/mock.c | 34 ++++++++++++++++++----- tools/testing/cxl/test/mock.h | 3 --- 10 files changed, 90 insertions(+), 71 deletions(-) diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index 7e1765b09e04..70cd9ac73a8b 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -372,21 +372,21 @@ static int add_host_bridge_uport(struct device *match, void *arg) return 0; } +/* Note, @dev is used by mock_acpi_table_parse_cedt() */ struct cxl_chbs_context { struct device *dev; unsigned long long uid; - resource_size_t rcrb; - resource_size_t chbcr; + resource_size_t base; u32 cxl_version; }; -static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg, +static int cxl_get_chbs(union acpi_subtable_headers *header, void *arg, const unsigned long end) { struct cxl_chbs_context *ctx = arg; struct acpi_cedt_chbs *chbs; - if (ctx->chbcr) + if (ctx->base) return 0; chbs = (struct acpi_cedt_chbs *) header; @@ -395,23 +395,16 @@ static int cxl_get_chbcr(union acpi_subtable_headers *header, void *arg, return 0; ctx->cxl_version = chbs->cxl_version; - ctx->rcrb = CXL_RESOURCE_NONE; - ctx->chbcr = CXL_RESOURCE_NONE; + ctx->base = CXL_RESOURCE_NONE; if (!chbs->base) return 0; - if (chbs->cxl_version != ACPI_CEDT_CHBS_VERSION_CXL11) { - ctx->chbcr = chbs->base; - return 0; - } - - if (chbs->length != CXL_RCRB_SIZE) + if (chbs->cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11 && + chbs->length != CXL_RCRB_SIZE) return 0; - ctx->rcrb = chbs->base; - ctx->chbcr = cxl_rcrb_to_component(ctx->dev, chbs->base, - CXL_RCRB_DOWNSTREAM); + ctx->base = chbs->base; return 0; } @@ -443,33 +436,31 @@ static int add_host_bridge_dport(struct device *match, void *arg) .dev = match, .uid = uid, }; - acpi_table_parse_cedt(ACPI_CEDT_TYPE_CHBS, cxl_get_chbcr, &ctx); + acpi_table_parse_cedt(ACPI_CEDT_TYPE_CHBS, cxl_get_chbs, &ctx); - if (!ctx.chbcr) { + if (!ctx.base) { dev_warn(match, "No CHBS found for Host Bridge (UID %lld)\n", uid); return 0; } - if (ctx.rcrb != CXL_RESOURCE_NONE) - dev_dbg(match, "RCRB found for UID %lld: %pa\n", uid, &ctx.rcrb); - - if (ctx.chbcr == CXL_RESOURCE_NONE) { - dev_warn(match, "CHBCR invalid for Host Bridge (UID %lld)\n", + if (ctx.base == CXL_RESOURCE_NONE) { + dev_warn(match, "CHBS invalid for Host Bridge (UID %lld)\n", uid); return 0; } - dev_dbg(match, "CHBCR found: %pa\n", &ctx.chbcr); - pci_root = acpi_pci_find_root(hb->handle); bridge = pci_root->bus->bridge; - if (ctx.cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11) - dport = devm_cxl_add_rch_dport(root_port, bridge, uid, - ctx.chbcr, ctx.rcrb); - else - dport = devm_cxl_add_dport(root_port, bridge, uid, - ctx.chbcr); + + if (ctx.cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11) { + dev_dbg(match, "RCRB found for UID %lld: %pa\n", uid, &ctx.base); + dport = devm_cxl_add_rch_dport(root_port, bridge, uid, ctx.base); + } else { + dev_dbg(match, "CHBCR found for UID %lld: %pa\n", uid, &ctx.base); + dport = devm_cxl_add_dport(root_port, bridge, uid, ctx.base); + } + if (IS_ERR(dport)) return PTR_ERR(dport); diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 27f0968449de..bd0a5788c696 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -63,6 +63,14 @@ int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, unsigned long long size); int cxl_dpa_free(struct cxl_endpoint_decoder *cxled); resource_size_t cxl_dpa_size(struct cxl_endpoint_decoder *cxled); resource_size_t cxl_dpa_resource_start(struct cxl_endpoint_decoder *cxled); + +enum cxl_rcrb { + CXL_RCRB_DOWNSTREAM, + CXL_RCRB_UPSTREAM, +}; +resource_size_t __rcrb_to_component(struct device *dev, resource_size_t rcrb, + enum cxl_rcrb which); + extern struct rw_semaphore cxl_dpa_rwsem; int cxl_memdev_init(void); diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index e7c284c890bc..45f5299af7a6 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -938,12 +938,25 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, if (!dport) return ERR_PTR(-ENOMEM); + if (rcrb != CXL_RESOURCE_NONE) { + component_reg_phys = __rcrb_to_component(dport_dev, rcrb, + CXL_RCRB_DOWNSTREAM); + if (component_reg_phys == CXL_RESOURCE_NONE) { + dev_warn(dport_dev, "Invalid Component Registers in RCRB"); + return ERR_PTR(-ENXIO); + } + + dport->rch = true; + } + + if (component_reg_phys != CXL_RESOURCE_NONE) + dev_dbg(dport_dev, "Component Registers found for dport: %pa\n", + &component_reg_phys); + dport->dport = dport_dev; dport->port_id = port_id; dport->component_reg_phys = component_reg_phys; dport->port = port; - if (rcrb != CXL_RESOURCE_NONE) - dport->rch = true; dport->rcrb = rcrb; cond_cxl_root_lock(port); @@ -1004,14 +1017,12 @@ EXPORT_SYMBOL_NS_GPL(devm_cxl_add_dport, CXL); * @port: the cxl_port that references this dport * @dport_dev: firmware or PCI device representing the dport * @port_id: identifier for this dport in a decoder's target list - * @component_reg_phys: optional location of CXL component registers * @rcrb: mandatory location of a Root Complex Register Block * * See CXL 3.0 9.11.8 CXL Devices Attached to an RCH */ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port, struct device *dport_dev, int port_id, - resource_size_t component_reg_phys, resource_size_t rcrb) { struct cxl_dport *dport; @@ -1022,7 +1033,7 @@ struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port, } dport = __devm_cxl_add_dport(port, dport_dev, port_id, - component_reg_phys, rcrb); + CXL_RESOURCE_NONE, rcrb); if (IS_ERR(dport)) { dev_dbg(dport_dev, "failed to add RCH dport to %s: %ld\n", dev_name(&port->dev), PTR_ERR(dport)); diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c index 1476a0299c9b..564dd430258a 100644 --- a/drivers/cxl/core/regs.c +++ b/drivers/cxl/core/regs.c @@ -332,9 +332,8 @@ int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type, } EXPORT_SYMBOL_NS_GPL(cxl_find_regblock, CXL); -resource_size_t cxl_rcrb_to_component(struct device *dev, - resource_size_t rcrb, - enum cxl_rcrb which) +resource_size_t __rcrb_to_component(struct device *dev, resource_size_t rcrb, + enum cxl_rcrb which) { resource_size_t component_reg_phys; void __iomem *addr; @@ -395,4 +394,12 @@ resource_size_t cxl_rcrb_to_component(struct device *dev, return component_reg_phys; } -EXPORT_SYMBOL_NS_GPL(cxl_rcrb_to_component, CXL); + +resource_size_t cxl_rcd_component_reg_phys(struct device *dev, + struct cxl_dport *dport) +{ + if (!dport->rch) + return CXL_RESOURCE_NONE; + return __rcrb_to_component(dev, dport->rcrb, CXL_RCRB_UPSTREAM); +} +EXPORT_SYMBOL_NS_GPL(cxl_rcd_component_reg_phys, CXL); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index f93a28538962..28888bb0c088 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -262,14 +262,9 @@ int cxl_map_device_regs(struct device *dev, struct cxl_device_regs *regs, enum cxl_regloc_type; int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type, struct cxl_register_map *map); - -enum cxl_rcrb { - CXL_RCRB_DOWNSTREAM, - CXL_RCRB_UPSTREAM, -}; -resource_size_t cxl_rcrb_to_component(struct device *dev, - resource_size_t rcrb, - enum cxl_rcrb which); +struct cxl_dport; +resource_size_t cxl_rcd_component_reg_phys(struct device *dev, + struct cxl_dport *dport); #define CXL_RESOURCE_NONE ((resource_size_t) -1) #define CXL_TARGET_STRLEN 20 @@ -671,7 +666,6 @@ struct cxl_dport *devm_cxl_add_dport(struct cxl_port *port, resource_size_t component_reg_phys); struct cxl_dport *devm_cxl_add_rch_dport(struct cxl_port *port, struct device *dport_dev, int port_id, - resource_size_t component_reg_phys, resource_size_t rcrb); struct cxl_decoder *to_cxl_decoder(struct device *dev); diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c index 519edd0eb196..45d4c32d78b0 100644 --- a/drivers/cxl/mem.c +++ b/drivers/cxl/mem.c @@ -72,8 +72,8 @@ static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd, * typical register locator mechanism. */ if (parent_dport->rch && cxlds->component_reg_phys == CXL_RESOURCE_NONE) - component_reg_phys = cxl_rcrb_to_component( - &cxlmd->dev, parent_dport->rcrb, CXL_RCRB_UPSTREAM); + component_reg_phys = + cxl_rcd_component_reg_phys(&cxlmd->dev, parent_dport); else component_reg_phys = cxlds->component_reg_phys; endpoint = devm_cxl_add_port(host, &cxlmd->dev, component_reg_phys, diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild index 6f9347ade82c..8a87d7d5f7f8 100644 --- a/tools/testing/cxl/Kbuild +++ b/tools/testing/cxl/Kbuild @@ -12,7 +12,8 @@ ldflags-y += --wrap=devm_cxl_enumerate_decoders ldflags-y += --wrap=cxl_await_media_ready ldflags-y += --wrap=cxl_hdm_decode_init ldflags-y += --wrap=cxl_dvsec_rr_decode -ldflags-y += --wrap=cxl_rcrb_to_component +ldflags-y += --wrap=devm_cxl_add_rch_dport +ldflags-y += --wrap=cxl_rcd_component_reg_phys DRIVERS := ../../../drivers CXL_SRC := $(DRIVERS)/cxl diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c index bf00dc52fe96..f5c04787bcc8 100644 --- a/tools/testing/cxl/test/cxl.c +++ b/tools/testing/cxl/test/cxl.c @@ -971,15 +971,6 @@ static int mock_cxl_port_enumerate_dports(struct cxl_port *port) return 0; } -resource_size_t mock_cxl_rcrb_to_component(struct device *dev, - resource_size_t rcrb, - enum cxl_rcrb which) -{ - dev_dbg(dev, "rcrb: %pa which: %d\n", &rcrb, which); - - return (resource_size_t) which + 1; -} - static struct cxl_mock_ops cxl_mock_ops = { .is_mock_adev = is_mock_adev, .is_mock_bridge = is_mock_bridge, @@ -988,7 +979,6 @@ static struct cxl_mock_ops cxl_mock_ops = { .is_mock_dev = is_mock_dev, .acpi_table_parse_cedt = mock_acpi_table_parse_cedt, .acpi_evaluate_integer = mock_acpi_evaluate_integer, - .cxl_rcrb_to_component = mock_cxl_rcrb_to_component, .acpi_pci_find_root = mock_acpi_pci_find_root, .devm_cxl_port_enumerate_dports = mock_cxl_port_enumerate_dports, .devm_cxl_setup_hdm = mock_cxl_setup_hdm, diff --git a/tools/testing/cxl/test/mock.c b/tools/testing/cxl/test/mock.c index 284416527644..30119a16ae85 100644 --- a/tools/testing/cxl/test/mock.c +++ b/tools/testing/cxl/test/mock.c @@ -259,24 +259,44 @@ int __wrap_cxl_dvsec_rr_decode(struct device *dev, int dvsec, } EXPORT_SYMBOL_NS_GPL(__wrap_cxl_dvsec_rr_decode, CXL); -resource_size_t __wrap_cxl_rcrb_to_component(struct device *dev, - resource_size_t rcrb, - enum cxl_rcrb which) +struct cxl_dport *__wrap_devm_cxl_add_rch_dport(struct cxl_port *port, + struct device *dport_dev, + int port_id, + resource_size_t rcrb) +{ + int index; + struct cxl_dport *dport; + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); + + if (ops && ops->is_mock_port(dport_dev)) { + dport = devm_cxl_add_dport(port, dport_dev, port_id, + CXL_RESOURCE_NONE); + if (!IS_ERR(dport)) + dport->rch = true; + } else + dport = devm_cxl_add_rch_dport(port, dport_dev, port_id, rcrb); + put_cxl_mock_ops(index); + + return dport; +} +EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_rch_dport, CXL); + +resource_size_t __wrap_cxl_rcd_component_reg_phys(struct device *dev, + struct cxl_dport *dport) { int index; resource_size_t component_reg_phys; struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); if (ops && ops->is_mock_port(dev)) - component_reg_phys = - ops->cxl_rcrb_to_component(dev, rcrb, which); + component_reg_phys = CXL_RESOURCE_NONE; else - component_reg_phys = cxl_rcrb_to_component(dev, rcrb, which); + component_reg_phys = cxl_rcd_component_reg_phys(dev, dport); put_cxl_mock_ops(index); return component_reg_phys; } -EXPORT_SYMBOL_NS_GPL(__wrap_cxl_rcrb_to_component, CXL); +EXPORT_SYMBOL_NS_GPL(__wrap_cxl_rcd_component_reg_phys, CXL); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS(ACPI); diff --git a/tools/testing/cxl/test/mock.h b/tools/testing/cxl/test/mock.h index bef8817b01f2..a94223750346 100644 --- a/tools/testing/cxl/test/mock.h +++ b/tools/testing/cxl/test/mock.h @@ -15,9 +15,6 @@ struct cxl_mock_ops { acpi_string pathname, struct acpi_object_list *arguments, unsigned long long *data); - resource_size_t (*cxl_rcrb_to_component)(struct device *dev, - resource_size_t rcrb, - enum cxl_rcrb which); struct acpi_pci_root *(*acpi_pci_find_root)(acpi_handle handle); bool (*is_mock_bus)(struct pci_bus *bus); bool (*is_mock_port)(struct device *dev); From 0619337856c9a1cb999417be38c4049a6b0235a0 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 22 Jun 2023 15:54:59 -0500 Subject: [PATCH 02/14] cxl/rch: Prepare for caching the MMIO mapped PCIe AER capability Prepare cxl_probe_rcrb() for retrieving more than just the component register block. The RCH AER handling code wants to get back to the AER capability that happens to be MMIO mapped rather then configuration cycles. Move RCRB specific downstream port data, like the RCRB base and the AER capability offset, into its own data structure ('struct cxl_rcrb_info') for cxl_probe_rcrb() to fill. Extend 'struct cxl_dport' to include a 'struct cxl_rcrb_info' attribute. This centralizes all RCRB scanning in one routine. Co-developed-by: Robert Richter Signed-off-by: Robert Richter Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-4-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/core/core.h | 4 +++- drivers/cxl/core/port.c | 4 ++-- drivers/cxl/core/regs.c | 5 +++-- drivers/cxl/cxl.h | 9 +++++++-- tools/testing/cxl/test/mock.c | 4 +++- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index bd0a5788c696..b001669a5133 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -68,7 +68,9 @@ enum cxl_rcrb { CXL_RCRB_DOWNSTREAM, CXL_RCRB_UPSTREAM, }; -resource_size_t __rcrb_to_component(struct device *dev, resource_size_t rcrb, +struct cxl_rcrb_info; +resource_size_t __rcrb_to_component(struct device *dev, + struct cxl_rcrb_info *ri, enum cxl_rcrb which); extern struct rw_semaphore cxl_dpa_rwsem; diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 45f5299af7a6..76888c75dae4 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -939,7 +939,8 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, return ERR_PTR(-ENOMEM); if (rcrb != CXL_RESOURCE_NONE) { - component_reg_phys = __rcrb_to_component(dport_dev, rcrb, + dport->rcrb.base = rcrb; + component_reg_phys = __rcrb_to_component(dport_dev, &dport->rcrb, CXL_RCRB_DOWNSTREAM); if (component_reg_phys == CXL_RESOURCE_NONE) { dev_warn(dport_dev, "Invalid Component Registers in RCRB"); @@ -957,7 +958,6 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, dport->port_id = port_id; dport->component_reg_phys = component_reg_phys; dport->port = port; - dport->rcrb = rcrb; cond_cxl_root_lock(port); rc = add_dport(port, dport); diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c index 564dd430258a..6c4b33133918 100644 --- a/drivers/cxl/core/regs.c +++ b/drivers/cxl/core/regs.c @@ -332,10 +332,11 @@ int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type, } EXPORT_SYMBOL_NS_GPL(cxl_find_regblock, CXL); -resource_size_t __rcrb_to_component(struct device *dev, resource_size_t rcrb, +resource_size_t __rcrb_to_component(struct device *dev, struct cxl_rcrb_info *ri, enum cxl_rcrb which) { resource_size_t component_reg_phys; + resource_size_t rcrb = ri->base; void __iomem *addr; u32 bar0, bar1; u16 cmd; @@ -400,6 +401,6 @@ resource_size_t cxl_rcd_component_reg_phys(struct device *dev, { if (!dport->rch) return CXL_RESOURCE_NONE; - return __rcrb_to_component(dev, dport->rcrb, CXL_RCRB_UPSTREAM); + return __rcrb_to_component(dev, &dport->rcrb, CXL_RCRB_UPSTREAM); } EXPORT_SYMBOL_NS_GPL(cxl_rcd_component_reg_phys, CXL); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 28888bb0c088..7c8674079f1a 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -582,12 +582,17 @@ cxl_find_dport_by_dev(struct cxl_port *port, const struct device *dport_dev) return xa_load(&port->dports, (unsigned long)dport_dev); } +struct cxl_rcrb_info { + resource_size_t base; + u16 aer_cap; +}; + /** * struct cxl_dport - CXL downstream port * @dport: PCI bridge or firmware device representing the downstream link * @port_id: unique hardware identifier for dport in decoder target list * @component_reg_phys: downstream port component registers - * @rcrb: base address for the Root Complex Register Block + * @rcrb: Data about the Root Complex Register Block layout * @rch: Indicate whether this dport was enumerated in RCH or VH mode * @port: reference to cxl_port that contains this downstream port */ @@ -595,7 +600,7 @@ struct cxl_dport { struct device *dport; int port_id; resource_size_t component_reg_phys; - resource_size_t rcrb; + struct cxl_rcrb_info rcrb; bool rch; struct cxl_port *port; }; diff --git a/tools/testing/cxl/test/mock.c b/tools/testing/cxl/test/mock.c index 30119a16ae85..dbeef5c6f606 100644 --- a/tools/testing/cxl/test/mock.c +++ b/tools/testing/cxl/test/mock.c @@ -271,8 +271,10 @@ struct cxl_dport *__wrap_devm_cxl_add_rch_dport(struct cxl_port *port, if (ops && ops->is_mock_port(dport_dev)) { dport = devm_cxl_add_dport(port, dport_dev, port_id, CXL_RESOURCE_NONE); - if (!IS_ERR(dport)) + if (!IS_ERR(dport)) { + dport->rcrb.base = rcrb; dport->rch = true; + } } else dport = devm_cxl_add_rch_dport(port, dport_dev, port_id, rcrb); put_cxl_mock_ops(index); From 227db57459e8b6dce33c071020b0c05b1f9fa8d6 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 22 Jun 2023 15:55:00 -0500 Subject: [PATCH 03/14] cxl: Rename member @dport of struct cxl_dport to @dport_dev Reading code like dport->dport does not immediately suggest that this points to the corresponding device structure of the dport. Rename struct member @dport to @dport_dev. While at it, also rename @new argument of add_dport() to @dport. This better describes the variable as a dport (e.g. new->dport becomes to dport->dport_dev). Co-developed-by: Terry Bowman Signed-off-by: Terry Bowman Signed-off-by: Robert Richter Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-5-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/core/port.c | 20 ++++++++++---------- drivers/cxl/core/region.c | 4 ++-- drivers/cxl/cxl.h | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 76888c75dae4..7d3079f5b7b5 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -605,7 +605,7 @@ static int devm_cxl_link_parent_dport(struct device *host, if (!parent_dport) return 0; - rc = sysfs_create_link(&port->dev.kobj, &parent_dport->dport->kobj, + rc = sysfs_create_link(&port->dev.kobj, &parent_dport->dport_dev->kobj, "parent_dport"); if (rc) return rc; @@ -658,7 +658,7 @@ static struct cxl_port *cxl_port_alloc(struct device *uport, if (iter->host_bridge) port->host_bridge = iter->host_bridge; else if (parent_dport->rch) - port->host_bridge = parent_dport->dport; + port->host_bridge = parent_dport->dport_dev; else port->host_bridge = iter->uport; dev_dbg(uport, "host-bridge: %s\n", dev_name(port->host_bridge)); @@ -847,22 +847,22 @@ static struct cxl_dport *find_dport(struct cxl_port *port, int id) return NULL; } -static int add_dport(struct cxl_port *port, struct cxl_dport *new) +static int add_dport(struct cxl_port *port, struct cxl_dport *dport) { struct cxl_dport *dup; int rc; device_lock_assert(&port->dev); - dup = find_dport(port, new->port_id); + dup = find_dport(port, dport->port_id); if (dup) { dev_err(&port->dev, "unable to add dport%d-%s non-unique port id (%s)\n", - new->port_id, dev_name(new->dport), - dev_name(dup->dport)); + dport->port_id, dev_name(dport->dport_dev), + dev_name(dup->dport_dev)); return -EBUSY; } - rc = xa_insert(&port->dports, (unsigned long)new->dport, new, + rc = xa_insert(&port->dports, (unsigned long)dport->dport_dev, dport, GFP_KERNEL); if (rc) return rc; @@ -895,8 +895,8 @@ static void cxl_dport_remove(void *data) struct cxl_dport *dport = data; struct cxl_port *port = dport->port; - xa_erase(&port->dports, (unsigned long) dport->dport); - put_device(dport->dport); + xa_erase(&port->dports, (unsigned long) dport->dport_dev); + put_device(dport->dport_dev); } static void cxl_dport_unlink(void *data) @@ -954,7 +954,7 @@ __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); - dport->dport = dport_dev; + dport->dport_dev = dport_dev; dport->port_id = port_id; dport->component_reg_phys = component_reg_phys; dport->port = port; diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index f822de44bee0..13cda989d944 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -1162,7 +1162,7 @@ add_target: dev_dbg(&cxlr->dev, "%s:%s: %s expected %s at %d\n", dev_name(port->uport), dev_name(&port->dev), dev_name(&cxlsd->cxld.dev), - dev_name(ep->dport->dport), + dev_name(ep->dport->dport_dev), cxl_rr->nr_targets_set); return -ENXIO; } @@ -1173,7 +1173,7 @@ out_target_set: cxl_rr->nr_targets_set += inc; dev_dbg(&cxlr->dev, "%s:%s target[%d] = %s for %s:%s @ %d\n", dev_name(port->uport), dev_name(&port->dev), - cxl_rr->nr_targets_set - 1, dev_name(ep->dport->dport), + cxl_rr->nr_targets_set - 1, dev_name(ep->dport->dport_dev), dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos); return 0; diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 7c8674079f1a..7232c2a0e27c 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -589,7 +589,7 @@ struct cxl_rcrb_info { /** * struct cxl_dport - CXL downstream port - * @dport: PCI bridge or firmware device representing the downstream link + * @dport_dev: PCI bridge or firmware device representing the downstream link * @port_id: unique hardware identifier for dport in decoder target list * @component_reg_phys: downstream port component registers * @rcrb: Data about the Root Complex Register Block layout @@ -597,7 +597,7 @@ struct cxl_rcrb_info { * @port: reference to cxl_port that contains this downstream port */ struct cxl_dport { - struct device *dport; + struct device *dport_dev; int port_id; resource_size_t component_reg_phys; struct cxl_rcrb_info rcrb; From 7481653deef24fb9a030339430d2f5723e0ccf78 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 22 Jun 2023 15:55:01 -0500 Subject: [PATCH 04/14] cxl: Rename 'uport' to 'uport_dev' For symmetry with the recent rename of ->dport_dev for a 'struct cxl_dport', add the "_dev" suffix to the ->uport property of a 'struct cxl_port'. These devices represent the downstream-port-device and upstream-port-device respectively in the CXL/PCIe topology. Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-6-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/core/pci.c | 4 +-- drivers/cxl/core/port.c | 61 +++++++++++++++++++---------------- drivers/cxl/core/region.c | 48 ++++++++++++++------------- drivers/cxl/cxl.h | 13 ++++---- drivers/cxl/cxlmem.h | 4 +-- drivers/cxl/mem.c | 2 +- drivers/cxl/port.c | 2 +- tools/testing/cxl/test/cxl.c | 20 ++++++------ tools/testing/cxl/test/mock.c | 10 +++--- 9 files changed, 86 insertions(+), 78 deletions(-) diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index 67f4ab6daa34..375f01c6cad6 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -67,7 +67,7 @@ static int match_add_dports(struct pci_dev *pdev, void *data) /** * devm_cxl_port_enumerate_dports - enumerate downstream ports of the upstream port - * @port: cxl_port whose ->uport is the upstream of dports to be enumerated + * @port: cxl_port whose ->uport_dev is the upstream of dports to be enumerated * * Returns a positive number of dports enumerated or a negative error * code. @@ -622,7 +622,7 @@ static int cxl_cdat_read_table(struct device *dev, */ void read_cdat_data(struct cxl_port *port) { - struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport); + struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev); struct device *host = cxlmd->dev.parent; struct device *dev = &port->dev; struct pci_doe_mb *cdat_doe; diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 7d3079f5b7b5..cdfe0ea7a2e9 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -561,9 +561,9 @@ static void unregister_port(void *_port) * unregistered while holding their parent port lock. */ if (!parent) - lock_dev = port->uport; + lock_dev = port->uport_dev; else if (is_cxl_root(parent)) - lock_dev = parent->uport; + lock_dev = parent->uport_dev; else lock_dev = &parent->dev; @@ -583,7 +583,8 @@ static int devm_cxl_link_uport(struct device *host, struct cxl_port *port) { int rc; - rc = sysfs_create_link(&port->dev.kobj, &port->uport->kobj, "uport"); + rc = sysfs_create_link(&port->dev.kobj, &port->uport_dev->kobj, + "uport"); if (rc) return rc; return devm_add_action_or_reset(host, cxl_unlink_uport, port); @@ -614,7 +615,7 @@ static int devm_cxl_link_parent_dport(struct device *host, static struct lock_class_key cxl_port_key; -static struct cxl_port *cxl_port_alloc(struct device *uport, +static struct cxl_port *cxl_port_alloc(struct device *uport_dev, resource_size_t component_reg_phys, struct cxl_dport *parent_dport) { @@ -630,7 +631,7 @@ static struct cxl_port *cxl_port_alloc(struct device *uport, if (rc < 0) goto err; port->id = rc; - port->uport = uport; + port->uport_dev = uport_dev; /* * The top-level cxl_port "cxl_root" does not have a cxl_port as @@ -660,10 +661,11 @@ static struct cxl_port *cxl_port_alloc(struct device *uport, else if (parent_dport->rch) port->host_bridge = parent_dport->dport_dev; else - port->host_bridge = iter->uport; - dev_dbg(uport, "host-bridge: %s\n", dev_name(port->host_bridge)); + port->host_bridge = iter->uport_dev; + dev_dbg(uport_dev, "host-bridge: %s\n", + dev_name(port->host_bridge)); } else - dev->parent = uport; + dev->parent = uport_dev; port->component_reg_phys = component_reg_phys; ida_init(&port->decoder_ida); @@ -687,7 +689,7 @@ err: } static struct cxl_port *__devm_cxl_add_port(struct device *host, - struct device *uport, + struct device *uport_dev, resource_size_t component_reg_phys, struct cxl_dport *parent_dport) { @@ -695,12 +697,12 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host, struct device *dev; int rc; - port = cxl_port_alloc(uport, component_reg_phys, parent_dport); + port = cxl_port_alloc(uport_dev, component_reg_phys, parent_dport); if (IS_ERR(port)) return port; dev = &port->dev; - if (is_cxl_memdev(uport)) + if (is_cxl_memdev(uport_dev)) rc = dev_set_name(dev, "endpoint%d", port->id); else if (parent_dport) rc = dev_set_name(dev, "port%d", port->id); @@ -735,28 +737,29 @@ err: /** * devm_cxl_add_port - register a cxl_port in CXL memory decode hierarchy * @host: host device for devm operations - * @uport: "physical" device implementing this upstream port + * @uport_dev: "physical" device implementing this upstream port * @component_reg_phys: (optional) for configurable cxl_port instances * @parent_dport: next hop up in the CXL memory decode hierarchy */ -struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport, +struct cxl_port *devm_cxl_add_port(struct device *host, + struct device *uport_dev, resource_size_t component_reg_phys, struct cxl_dport *parent_dport) { struct cxl_port *port, *parent_port; - port = __devm_cxl_add_port(host, uport, component_reg_phys, + port = __devm_cxl_add_port(host, uport_dev, component_reg_phys, parent_dport); parent_port = parent_dport ? parent_dport->port : NULL; if (IS_ERR(port)) { - dev_dbg(uport, "Failed to add%s%s%s: %ld\n", + dev_dbg(uport_dev, "Failed to add%s%s%s: %ld\n", parent_port ? " port to " : "", parent_port ? dev_name(&parent_port->dev) : "", parent_port ? "" : " root port", PTR_ERR(port)); } else { - dev_dbg(uport, "%s added%s%s%s\n", + dev_dbg(uport_dev, "%s added%s%s%s\n", dev_name(&port->dev), parent_port ? " to " : "", parent_port ? dev_name(&parent_port->dev) : "", @@ -773,33 +776,34 @@ struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port) if (is_cxl_root(port)) return NULL; - if (dev_is_pci(port->uport)) { - struct pci_dev *pdev = to_pci_dev(port->uport); + if (dev_is_pci(port->uport_dev)) { + struct pci_dev *pdev = to_pci_dev(port->uport_dev); return pdev->subordinate; } - return xa_load(&cxl_root_buses, (unsigned long)port->uport); + return xa_load(&cxl_root_buses, (unsigned long)port->uport_dev); } EXPORT_SYMBOL_NS_GPL(cxl_port_to_pci_bus, CXL); -static void unregister_pci_bus(void *uport) +static void unregister_pci_bus(void *uport_dev) { - xa_erase(&cxl_root_buses, (unsigned long)uport); + xa_erase(&cxl_root_buses, (unsigned long)uport_dev); } -int devm_cxl_register_pci_bus(struct device *host, struct device *uport, +int devm_cxl_register_pci_bus(struct device *host, struct device *uport_dev, struct pci_bus *bus) { int rc; - if (dev_is_pci(uport)) + if (dev_is_pci(uport_dev)) return -EINVAL; - rc = xa_insert(&cxl_root_buses, (unsigned long)uport, bus, GFP_KERNEL); + rc = xa_insert(&cxl_root_buses, (unsigned long)uport_dev, bus, + GFP_KERNEL); if (rc) return rc; - return devm_add_action_or_reset(host, unregister_pci_bus, uport); + return devm_add_action_or_reset(host, unregister_pci_bus, uport_dev); } EXPORT_SYMBOL_NS_GPL(devm_cxl_register_pci_bus, CXL); @@ -920,7 +924,7 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, int rc; if (is_cxl_root(port)) - host = port->uport; + host = port->uport_dev; else host = &port->dev; @@ -1374,7 +1378,7 @@ out: rc = PTR_ERR(port); else { dev_dbg(&cxlmd->dev, "add to new port %s:%s\n", - dev_name(&port->dev), dev_name(port->uport)); + dev_name(&port->dev), dev_name(port->uport_dev)); rc = cxl_add_ep(dport, &cxlmd->dev); if (rc == -EBUSY) { /* @@ -1436,7 +1440,8 @@ retry: if (port) { dev_dbg(&cxlmd->dev, "found already registered port %s:%s\n", - dev_name(&port->dev), dev_name(port->uport)); + dev_name(&port->dev), + dev_name(port->uport_dev)); rc = cxl_add_ep(dport, &cxlmd->dev); /* diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 13cda989d944..39825e5301d0 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -906,10 +906,10 @@ static int cxl_port_attach_region(struct cxl_port *port, dev_dbg(&cxlr->dev, "%s:%s %s add: %s:%s @ %d next: %s nr_eps: %d nr_targets: %d\n", - dev_name(port->uport), dev_name(&port->dev), + dev_name(port->uport_dev), dev_name(&port->dev), dev_name(&cxld->dev), dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos, - ep ? ep->next ? dev_name(ep->next->uport) : + ep ? ep->next ? dev_name(ep->next->uport_dev) : dev_name(&cxlmd->dev) : "none", cxl_rr->nr_eps, cxl_rr->nr_targets); @@ -984,7 +984,7 @@ static int check_last_peer(struct cxl_endpoint_decoder *cxled, */ if (pos < distance) { dev_dbg(&cxlr->dev, "%s:%s: cannot host %s:%s at %d\n", - dev_name(port->uport), dev_name(&port->dev), + dev_name(port->uport_dev), dev_name(&port->dev), dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos); return -ENXIO; } @@ -994,7 +994,7 @@ static int check_last_peer(struct cxl_endpoint_decoder *cxled, if (ep->dport != ep_peer->dport) { dev_dbg(&cxlr->dev, "%s:%s: %s:%s pos %d mismatched peer %s:%s\n", - dev_name(port->uport), dev_name(&port->dev), + dev_name(port->uport_dev), dev_name(&port->dev), dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos, dev_name(&cxlmd_peer->dev), dev_name(&cxled_peer->cxld.dev)); @@ -1026,7 +1026,7 @@ static int cxl_port_setup_targets(struct cxl_port *port, */ if (!is_power_of_2(cxl_rr->nr_targets)) { dev_dbg(&cxlr->dev, "%s:%s: invalid target count %d\n", - dev_name(port->uport), dev_name(&port->dev), + dev_name(port->uport_dev), dev_name(&port->dev), cxl_rr->nr_targets); return -EINVAL; } @@ -1076,7 +1076,7 @@ static int cxl_port_setup_targets(struct cxl_port *port, rc = granularity_to_eig(parent_ig, &peig); if (rc) { dev_dbg(&cxlr->dev, "%s:%s: invalid parent granularity: %d\n", - dev_name(parent_port->uport), + dev_name(parent_port->uport_dev), dev_name(&parent_port->dev), parent_ig); return rc; } @@ -1084,7 +1084,7 @@ static int cxl_port_setup_targets(struct cxl_port *port, rc = ways_to_eiw(parent_iw, &peiw); if (rc) { dev_dbg(&cxlr->dev, "%s:%s: invalid parent interleave: %d\n", - dev_name(parent_port->uport), + dev_name(parent_port->uport_dev), dev_name(&parent_port->dev), parent_iw); return rc; } @@ -1093,7 +1093,7 @@ static int cxl_port_setup_targets(struct cxl_port *port, rc = ways_to_eiw(iw, &eiw); if (rc) { dev_dbg(&cxlr->dev, "%s:%s: invalid port interleave: %d\n", - dev_name(port->uport), dev_name(&port->dev), iw); + dev_name(port->uport_dev), dev_name(&port->dev), iw); return rc; } @@ -1113,7 +1113,7 @@ static int cxl_port_setup_targets(struct cxl_port *port, rc = eig_to_granularity(eig, &ig); if (rc) { dev_dbg(&cxlr->dev, "%s:%s: invalid interleave: %d\n", - dev_name(port->uport), dev_name(&port->dev), + dev_name(port->uport_dev), dev_name(&port->dev), 256 << eig); return rc; } @@ -1126,11 +1126,11 @@ static int cxl_port_setup_targets(struct cxl_port *port, ((cxld->flags & CXL_DECODER_F_ENABLE) == 0)) { dev_err(&cxlr->dev, "%s:%s %s expected iw: %d ig: %d %pr\n", - dev_name(port->uport), dev_name(&port->dev), + dev_name(port->uport_dev), dev_name(&port->dev), __func__, iw, ig, p->res); dev_err(&cxlr->dev, "%s:%s %s got iw: %d ig: %d state: %s %#llx:%#llx\n", - dev_name(port->uport), dev_name(&port->dev), + dev_name(port->uport_dev), dev_name(&port->dev), __func__, cxld->interleave_ways, cxld->interleave_granularity, (cxld->flags & CXL_DECODER_F_ENABLE) ? @@ -1147,20 +1147,20 @@ static int cxl_port_setup_targets(struct cxl_port *port, .end = p->res->end, }; } - dev_dbg(&cxlr->dev, "%s:%s iw: %d ig: %d\n", dev_name(port->uport), + dev_dbg(&cxlr->dev, "%s:%s iw: %d ig: %d\n", dev_name(port->uport_dev), dev_name(&port->dev), iw, ig); add_target: if (cxl_rr->nr_targets_set == cxl_rr->nr_targets) { dev_dbg(&cxlr->dev, "%s:%s: targets full trying to add %s:%s at %d\n", - dev_name(port->uport), dev_name(&port->dev), + dev_name(port->uport_dev), dev_name(&port->dev), dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos); return -ENXIO; } if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags)) { if (cxlsd->target[cxl_rr->nr_targets_set] != ep->dport) { dev_dbg(&cxlr->dev, "%s:%s: %s expected %s at %d\n", - dev_name(port->uport), dev_name(&port->dev), + dev_name(port->uport_dev), dev_name(&port->dev), dev_name(&cxlsd->cxld.dev), dev_name(ep->dport->dport_dev), cxl_rr->nr_targets_set); @@ -1172,7 +1172,7 @@ add_target: out_target_set: cxl_rr->nr_targets_set += inc; dev_dbg(&cxlr->dev, "%s:%s target[%d] = %s for %s:%s @ %d\n", - dev_name(port->uport), dev_name(&port->dev), + dev_name(port->uport_dev), dev_name(&port->dev), cxl_rr->nr_targets_set - 1, dev_name(ep->dport->dport_dev), dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev), pos); @@ -1492,7 +1492,7 @@ static int cmp_decode_pos(const void *a, const void *b) if (!dev) { struct range *range = &cxled_a->cxld.hpa_range; - dev_err(port->uport, + dev_err(port->uport_dev, "failed to find decoder that maps %#llx-%#llx\n", range->start, range->end); goto err; @@ -1507,14 +1507,15 @@ static int cmp_decode_pos(const void *a, const void *b) put_device(dev); if (a_pos < 0 || b_pos < 0) { - dev_err(port->uport, + dev_err(port->uport_dev, "failed to find shared decoder for %s and %s\n", dev_name(cxlmd_a->dev.parent), dev_name(cxlmd_b->dev.parent)); goto err; } - dev_dbg(port->uport, "%s comes %s %s\n", dev_name(cxlmd_a->dev.parent), + dev_dbg(port->uport_dev, "%s comes %s %s\n", + dev_name(cxlmd_a->dev.parent), a_pos - b_pos < 0 ? "before" : "after", dev_name(cxlmd_b->dev.parent)); @@ -2059,11 +2060,11 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd, if (rc) goto err; - rc = devm_add_action_or_reset(port->uport, unregister_region, cxlr); + rc = devm_add_action_or_reset(port->uport_dev, unregister_region, cxlr); if (rc) return ERR_PTR(rc); - dev_dbg(port->uport, "%s: created %s\n", + dev_dbg(port->uport_dev, "%s: created %s\n", dev_name(&cxlrd->cxlsd.cxld.dev), dev_name(dev)); return cxlr; @@ -2191,7 +2192,7 @@ static ssize_t delete_region_store(struct device *dev, if (IS_ERR(cxlr)) return PTR_ERR(cxlr); - devm_release_action(port->uport, unregister_region, cxlr); + devm_release_action(port->uport_dev, unregister_region, cxlr); put_device(&cxlr->dev); return len; @@ -2356,7 +2357,8 @@ int cxl_get_poison_by_endpoint(struct cxl_port *port) rc = device_for_each_child(&port->dev, &ctx, poison_by_decoder); if (rc == 1) - rc = cxl_get_poison_unmapped(to_cxl_memdev(port->uport), &ctx); + rc = cxl_get_poison_unmapped(to_cxl_memdev(port->uport_dev), + &ctx); up_read(&cxl_region_rwsem); return rc; @@ -2732,7 +2734,7 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd, err: up_write(&cxl_region_rwsem); - devm_release_action(port->uport, unregister_region, cxlr); + devm_release_action(port->uport_dev, unregister_region, cxlr); return ERR_PTR(rc); } diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 7232c2a0e27c..754cfe59ae37 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -536,7 +536,7 @@ struct cxl_dax_region { * downstream port devices to construct a CXL memory * decode hierarchy. * @dev: this port's device - * @uport: PCI or platform device implementing the upstream port capability + * @uport_dev: PCI or platform device implementing the upstream port capability * @host_bridge: Shortcut to the platform attach point for this port * @id: id for port device-name * @dports: cxl_dport instances referenced by decoders @@ -555,7 +555,7 @@ struct cxl_dax_region { */ struct cxl_port { struct device dev; - struct device *uport; + struct device *uport_dev; struct device *host_bridge; int id; struct xarray dports; @@ -641,21 +641,22 @@ struct cxl_region_ref { /* * The platform firmware device hosting the root is also the top of the * CXL port topology. All other CXL ports have another CXL port as their - * parent and their ->uport / host device is out-of-line of the port + * parent and their ->uport_dev / host device is out-of-line of the port * ancestry. */ static inline bool is_cxl_root(struct cxl_port *port) { - return port->uport == port->dev.parent; + return port->uport_dev == port->dev.parent; } bool is_cxl_port(const struct device *dev); struct cxl_port *to_cxl_port(const struct device *dev); struct pci_bus; -int devm_cxl_register_pci_bus(struct device *host, struct device *uport, +int devm_cxl_register_pci_bus(struct device *host, struct device *uport_dev, struct pci_bus *bus); struct pci_bus *cxl_port_to_pci_bus(struct cxl_port *port); -struct cxl_port *devm_cxl_add_port(struct device *host, struct device *uport, +struct cxl_port *devm_cxl_add_port(struct device *host, + struct device *uport_dev, resource_size_t component_reg_phys, struct cxl_dport *parent_dport); struct cxl_port *find_cxl_root(struct cxl_port *port); diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h index a2845a7a69d8..76743016b64c 100644 --- a/drivers/cxl/cxlmem.h +++ b/drivers/cxl/cxlmem.h @@ -72,13 +72,13 @@ cxled_to_memdev(struct cxl_endpoint_decoder *cxled) { struct cxl_port *port = to_cxl_port(cxled->cxld.dev.parent); - return to_cxl_memdev(port->uport); + return to_cxl_memdev(port->uport_dev); } bool is_cxl_memdev(const struct device *dev); static inline bool is_cxl_endpoint(struct cxl_port *port) { - return is_cxl_memdev(port->uport); + return is_cxl_memdev(port->uport_dev); } struct cxl_memdev *devm_cxl_add_memdev(struct cxl_dev_state *cxlds); diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c index 45d4c32d78b0..4cc461c22b8b 100644 --- a/drivers/cxl/mem.c +++ b/drivers/cxl/mem.c @@ -163,7 +163,7 @@ static int cxl_mem_probe(struct device *dev) } if (dport->rch) - endpoint_parent = parent_port->uport; + endpoint_parent = parent_port->uport_dev; else endpoint_parent = &parent_port->dev; diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c index c23b6164e1c0..4cef2bf45ad2 100644 --- a/drivers/cxl/port.c +++ b/drivers/cxl/port.c @@ -91,7 +91,7 @@ static int cxl_switch_port_probe(struct cxl_port *port) static int cxl_endpoint_port_probe(struct cxl_port *port) { struct cxl_endpoint_dvsec_info info = { .port = port }; - struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport); + struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev); struct cxl_dev_state *cxlds = cxlmd->cxlds; struct cxl_hdm *cxlhdm; struct cxl_port *root; diff --git a/tools/testing/cxl/test/cxl.c b/tools/testing/cxl/test/cxl.c index f5c04787bcc8..4f62eb55f8b8 100644 --- a/tools/testing/cxl/test/cxl.c +++ b/tools/testing/cxl/test/cxl.c @@ -754,7 +754,7 @@ static void mock_init_hdm_decoder(struct cxl_decoder *cxld) /* check is endpoint is attach to host-bridge0 */ port = cxled_to_port(cxled); do { - if (port->uport == &cxl_host_bridge[0]->dev) { + if (port->uport_dev == &cxl_host_bridge[0]->dev) { hb0 = true; break; } @@ -889,7 +889,7 @@ static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, mock_init_hdm_decoder(cxld); if (target_count) { - rc = device_for_each_child(port->uport, &ctx, + rc = device_for_each_child(port->uport_dev, &ctx, map_targets); if (rc) { put_device(&cxld->dev); @@ -919,29 +919,29 @@ static int mock_cxl_port_enumerate_dports(struct cxl_port *port) int i, array_size; if (port->depth == 1) { - if (is_multi_bridge(port->uport)) { + if (is_multi_bridge(port->uport_dev)) { array_size = ARRAY_SIZE(cxl_root_port); array = cxl_root_port; - } else if (is_single_bridge(port->uport)) { + } else if (is_single_bridge(port->uport_dev)) { array_size = ARRAY_SIZE(cxl_root_single); array = cxl_root_single; } else { dev_dbg(&port->dev, "%s: unknown bridge type\n", - dev_name(port->uport)); + dev_name(port->uport_dev)); return -ENXIO; } } else if (port->depth == 2) { struct cxl_port *parent = to_cxl_port(port->dev.parent); - if (is_multi_bridge(parent->uport)) { + if (is_multi_bridge(parent->uport_dev)) { array_size = ARRAY_SIZE(cxl_switch_dport); array = cxl_switch_dport; - } else if (is_single_bridge(parent->uport)) { + } else if (is_single_bridge(parent->uport_dev)) { array_size = ARRAY_SIZE(cxl_swd_single); array = cxl_swd_single; } else { dev_dbg(&port->dev, "%s: unknown bridge type\n", - dev_name(port->uport)); + dev_name(port->uport_dev)); return -ENXIO; } } else { @@ -954,9 +954,9 @@ static int mock_cxl_port_enumerate_dports(struct cxl_port *port) struct platform_device *pdev = array[i]; struct cxl_dport *dport; - if (pdev->dev.parent != port->uport) { + if (pdev->dev.parent != port->uport_dev) { dev_dbg(&port->dev, "%s: mismatch parent %s\n", - dev_name(port->uport), + dev_name(port->uport_dev), dev_name(pdev->dev.parent)); continue; } diff --git a/tools/testing/cxl/test/mock.c b/tools/testing/cxl/test/mock.c index dbeef5c6f606..da554df50bac 100644 --- a/tools/testing/cxl/test/mock.c +++ b/tools/testing/cxl/test/mock.c @@ -139,7 +139,7 @@ struct cxl_hdm *__wrap_devm_cxl_setup_hdm(struct cxl_port *port, struct cxl_hdm *cxlhdm; struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); - if (ops && ops->is_mock_port(port->uport)) + if (ops && ops->is_mock_port(port->uport_dev)) cxlhdm = ops->devm_cxl_setup_hdm(port, info); else cxlhdm = devm_cxl_setup_hdm(port, info); @@ -154,7 +154,7 @@ int __wrap_devm_cxl_enable_hdm(struct cxl_port *port, struct cxl_hdm *cxlhdm) int index, rc; struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); - if (ops && ops->is_mock_port(port->uport)) + if (ops && ops->is_mock_port(port->uport_dev)) rc = 0; else rc = devm_cxl_enable_hdm(port, cxlhdm); @@ -169,7 +169,7 @@ int __wrap_devm_cxl_add_passthrough_decoder(struct cxl_port *port) int rc, index; struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); - if (ops && ops->is_mock_port(port->uport)) + if (ops && ops->is_mock_port(port->uport_dev)) rc = ops->devm_cxl_add_passthrough_decoder(port); else rc = devm_cxl_add_passthrough_decoder(port); @@ -186,7 +186,7 @@ int __wrap_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, struct cxl_port *port = cxlhdm->port; struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); - if (ops && ops->is_mock_port(port->uport)) + if (ops && ops->is_mock_port(port->uport_dev)) rc = ops->devm_cxl_enumerate_decoders(cxlhdm, info); else rc = devm_cxl_enumerate_decoders(cxlhdm, info); @@ -201,7 +201,7 @@ int __wrap_devm_cxl_port_enumerate_dports(struct cxl_port *port) int rc, index; struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); - if (ops && ops->is_mock_port(port->uport)) + if (ops && ops->is_mock_port(port->uport_dev)) rc = ops->devm_cxl_port_enumerate_dports(port); else rc = devm_cxl_port_enumerate_dports(port); From 573408049b7598a7c4ef6981b70b1275447d28e4 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 22 Jun 2023 15:55:02 -0500 Subject: [PATCH 05/14] cxl/core/regs: Add @dev to cxl_register_map The corresponding device of a register mapping is used for devm operations and logging. For operations with struct cxl_register_map the device needs to be kept track separately. To simpify the involved function interfaces, add @dev to cxl_register_map. While at it also reorder function arguments of cxl_map_device_regs() and cxl_map_component_regs() to have the object @cxl_register_map first. As a result a bunch of functions are available to be used with a @cxl_register_map object. This patch is in preparation of reworking the component register setup code. Signed-off-by: Robert Richter Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-7-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/core/hdm.c | 4 ++-- drivers/cxl/core/regs.c | 18 ++++++++++++------ drivers/cxl/cxl.h | 10 ++++++---- drivers/cxl/pci.c | 23 +++++++++++------------ 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index 7889ff203a34..5abfa9276dac 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -85,6 +85,7 @@ static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb, struct cxl_component_regs *regs) { struct cxl_register_map map = { + .dev = &port->dev, .resource = port->component_reg_phys, .base = crb, .max_size = CXL_COMPONENT_REG_BLOCK_SIZE, @@ -97,8 +98,7 @@ static int map_hdm_decoder_regs(struct cxl_port *port, void __iomem *crb, return -ENODEV; } - return cxl_map_component_regs(&port->dev, regs, &map, - BIT(CXL_CM_CAP_CAP_ID_HDM)); + return cxl_map_component_regs(&map, regs, BIT(CXL_CM_CAP_CAP_ID_HDM)); } static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info) diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c index 6c4b33133918..713e4a9ca35a 100644 --- a/drivers/cxl/core/regs.c +++ b/drivers/cxl/core/regs.c @@ -199,9 +199,11 @@ void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr, return ret_val; } -int cxl_map_component_regs(struct device *dev, struct cxl_component_regs *regs, - struct cxl_register_map *map, unsigned long map_mask) +int cxl_map_component_regs(struct cxl_register_map *map, + struct cxl_component_regs *regs, + unsigned long map_mask) { + struct device *dev = map->dev; struct mapinfo { struct cxl_reg_map *rmap; void __iomem **addr; @@ -231,10 +233,10 @@ int cxl_map_component_regs(struct device *dev, struct cxl_component_regs *regs, } EXPORT_SYMBOL_NS_GPL(cxl_map_component_regs, CXL); -int cxl_map_device_regs(struct device *dev, - struct cxl_device_regs *regs, - struct cxl_register_map *map) +int cxl_map_device_regs(struct cxl_register_map *map, + struct cxl_device_regs *regs) { + struct device *dev = map->dev; resource_size_t phys_addr = map->resource; struct mapinfo { struct cxl_reg_map *rmap; @@ -302,7 +304,11 @@ int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type, u32 regloc_size, regblocks; int regloc, i; - map->resource = CXL_RESOURCE_NONE; + *map = (struct cxl_register_map) { + .dev = &pdev->dev, + .resource = CXL_RESOURCE_NONE, + }; + regloc = pci_find_dvsec_capability(pdev, PCI_DVSEC_VENDOR_ID_CXL, CXL_DVSEC_REG_LOCATOR); if (!regloc) diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 754cfe59ae37..bd68d5fabf21 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -231,6 +231,7 @@ struct cxl_device_reg_map { /** * struct cxl_register_map - DVSEC harvested register block mapping parameters + * @dev: device for devm operations and logging * @base: virtual base of the register-block-BAR + @block_offset * @resource: physical resource base of the register block * @max_size: maximum mapping size to perform register search @@ -239,6 +240,7 @@ struct cxl_device_reg_map { * @device_map: cxl_reg_maps for device registers */ struct cxl_register_map { + struct device *dev; void __iomem *base; resource_size_t resource; resource_size_t max_size; @@ -253,11 +255,11 @@ void cxl_probe_component_regs(struct device *dev, void __iomem *base, struct cxl_component_reg_map *map); void cxl_probe_device_regs(struct device *dev, void __iomem *base, struct cxl_device_reg_map *map); -int cxl_map_component_regs(struct device *dev, struct cxl_component_regs *regs, - struct cxl_register_map *map, +int cxl_map_component_regs(struct cxl_register_map *map, + struct cxl_component_regs *regs, unsigned long map_mask); -int cxl_map_device_regs(struct device *dev, struct cxl_device_regs *regs, - struct cxl_register_map *map); +int cxl_map_device_regs(struct cxl_register_map *map, + struct cxl_device_regs *regs); enum cxl_regloc_type; int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type, diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 0872f2233ed0..0a89b96e6a8d 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -274,9 +274,9 @@ static int cxl_pci_setup_mailbox(struct cxl_dev_state *cxlds) return 0; } -static int cxl_map_regblock(struct pci_dev *pdev, struct cxl_register_map *map) +static int cxl_map_regblock(struct cxl_register_map *map) { - struct device *dev = &pdev->dev; + struct device *dev = map->dev; map->base = ioremap(map->resource, map->max_size); if (!map->base) { @@ -288,18 +288,17 @@ static int cxl_map_regblock(struct pci_dev *pdev, struct cxl_register_map *map) return 0; } -static void cxl_unmap_regblock(struct pci_dev *pdev, - struct cxl_register_map *map) +static void cxl_unmap_regblock(struct cxl_register_map *map) { iounmap(map->base); map->base = NULL; } -static int cxl_probe_regs(struct pci_dev *pdev, struct cxl_register_map *map) +static int cxl_probe_regs(struct cxl_register_map *map) { struct cxl_component_reg_map *comp_map; struct cxl_device_reg_map *dev_map; - struct device *dev = &pdev->dev; + struct device *dev = map->dev; void __iomem *base = map->base; switch (map->reg_type) { @@ -346,12 +345,12 @@ static int cxl_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type, if (rc) return rc; - rc = cxl_map_regblock(pdev, map); + rc = cxl_map_regblock(map); if (rc) return rc; - rc = cxl_probe_regs(pdev, map); - cxl_unmap_regblock(pdev, map); + rc = cxl_probe_regs(map); + cxl_unmap_regblock(map); return rc; } @@ -688,7 +687,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) return rc; - rc = cxl_map_device_regs(&pdev->dev, &cxlds->regs.device_regs, &map); + rc = cxl_map_device_regs(&map, &cxlds->regs.device_regs); if (rc) return rc; @@ -703,8 +702,8 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) cxlds->component_reg_phys = map.resource; - rc = cxl_map_component_regs(&pdev->dev, &cxlds->regs.component, - &map, BIT(CXL_CM_CAP_CAP_ID_RAS)); + rc = cxl_map_component_regs(&map, &cxlds->regs.component, + BIT(CXL_CM_CAP_CAP_ID_RAS)); if (rc) dev_dbg(&pdev->dev, "Failed to map RAS capability.\n"); From d076bb8c4cee23fa1ddeae36f72a4695529c9198 Mon Sep 17 00:00:00 2001 From: Terry Bowman Date: Thu, 22 Jun 2023 15:55:03 -0500 Subject: [PATCH 06/14] cxl/pci: Refactor component register discovery for reuse The endpoint implements component register setup code. Refactor it for reuse with RCRB, downstream port, and upstream port setup. Move PCI specifics from cxl_setup_regs() into cxl_pci_setup_regs(). Move cxl_setup_regs() into cxl/core/regs.c and export it. This also includes supporting static functions cxl_map_registerblock(), cxl_unmap_register_block() and cxl_probe_regs(). Co-developed-by: Robert Richter Signed-off-by: Robert Richter Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-8-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/core/regs.c | 77 +++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxl.h | 1 + drivers/cxl/pci.c | 79 +++-------------------------------------- 3 files changed, 83 insertions(+), 74 deletions(-) diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c index 713e4a9ca35a..e035ad8827a4 100644 --- a/drivers/cxl/core/regs.c +++ b/drivers/cxl/core/regs.c @@ -338,6 +338,83 @@ int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type, } EXPORT_SYMBOL_NS_GPL(cxl_find_regblock, CXL); +static int cxl_map_regblock(struct cxl_register_map *map) +{ + struct device *dev = map->dev; + + map->base = ioremap(map->resource, map->max_size); + if (!map->base) { + dev_err(dev, "failed to map registers\n"); + return -ENOMEM; + } + + dev_dbg(dev, "Mapped CXL Memory Device resource %pa\n", &map->resource); + return 0; +} + +static void cxl_unmap_regblock(struct cxl_register_map *map) +{ + iounmap(map->base); + map->base = NULL; +} + +static int cxl_probe_regs(struct cxl_register_map *map) +{ + struct cxl_component_reg_map *comp_map; + struct cxl_device_reg_map *dev_map; + struct device *dev = map->dev; + void __iomem *base = map->base; + + switch (map->reg_type) { + case CXL_REGLOC_RBI_COMPONENT: + comp_map = &map->component_map; + cxl_probe_component_regs(dev, base, comp_map); + if (!comp_map->hdm_decoder.valid) { + dev_err(dev, "HDM decoder registers not found\n"); + return -ENXIO; + } + + if (!comp_map->ras.valid) + dev_dbg(dev, "RAS registers not found\n"); + + dev_dbg(dev, "Set up component registers\n"); + break; + case CXL_REGLOC_RBI_MEMDEV: + dev_map = &map->device_map; + cxl_probe_device_regs(dev, base, dev_map); + if (!dev_map->status.valid || !dev_map->mbox.valid || + !dev_map->memdev.valid) { + dev_err(dev, "registers not found: %s%s%s\n", + !dev_map->status.valid ? "status " : "", + !dev_map->mbox.valid ? "mbox " : "", + !dev_map->memdev.valid ? "memdev " : ""); + return -ENXIO; + } + + dev_dbg(dev, "Probing device registers...\n"); + break; + default: + break; + } + + return 0; +} + +int cxl_setup_regs(struct cxl_register_map *map) +{ + int rc; + + rc = cxl_map_regblock(map); + if (rc) + return rc; + + rc = cxl_probe_regs(map); + cxl_unmap_regblock(map); + + return rc; +} +EXPORT_SYMBOL_NS_GPL(cxl_setup_regs, CXL); + resource_size_t __rcrb_to_component(struct device *dev, struct cxl_rcrb_info *ri, enum cxl_rcrb which) { diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index bd68d5fabf21..ae265357170e 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -264,6 +264,7 @@ int cxl_map_device_regs(struct cxl_register_map *map, enum cxl_regloc_type; int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type, struct cxl_register_map *map); +int cxl_setup_regs(struct cxl_register_map *map); struct cxl_dport; resource_size_t cxl_rcd_component_reg_phys(struct device *dev, struct cxl_dport *dport); diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 0a89b96e6a8d..ac17bc0430dc 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -274,70 +274,8 @@ static int cxl_pci_setup_mailbox(struct cxl_dev_state *cxlds) return 0; } -static int cxl_map_regblock(struct cxl_register_map *map) -{ - struct device *dev = map->dev; - - map->base = ioremap(map->resource, map->max_size); - if (!map->base) { - dev_err(dev, "failed to map registers\n"); - return -ENOMEM; - } - - dev_dbg(dev, "Mapped CXL Memory Device resource %pa\n", &map->resource); - return 0; -} - -static void cxl_unmap_regblock(struct cxl_register_map *map) -{ - iounmap(map->base); - map->base = NULL; -} - -static int cxl_probe_regs(struct cxl_register_map *map) -{ - struct cxl_component_reg_map *comp_map; - struct cxl_device_reg_map *dev_map; - struct device *dev = map->dev; - void __iomem *base = map->base; - - switch (map->reg_type) { - case CXL_REGLOC_RBI_COMPONENT: - comp_map = &map->component_map; - cxl_probe_component_regs(dev, base, comp_map); - if (!comp_map->hdm_decoder.valid) { - dev_err(dev, "HDM decoder registers not found\n"); - return -ENXIO; - } - - if (!comp_map->ras.valid) - dev_dbg(dev, "RAS registers not found\n"); - - dev_dbg(dev, "Set up component registers\n"); - break; - case CXL_REGLOC_RBI_MEMDEV: - dev_map = &map->device_map; - cxl_probe_device_regs(dev, base, dev_map); - if (!dev_map->status.valid || !dev_map->mbox.valid || - !dev_map->memdev.valid) { - dev_err(dev, "registers not found: %s%s%s\n", - !dev_map->status.valid ? "status " : "", - !dev_map->mbox.valid ? "mbox " : "", - !dev_map->memdev.valid ? "memdev " : ""); - return -ENXIO; - } - - dev_dbg(dev, "Probing device registers...\n"); - break; - default: - break; - } - - return 0; -} - -static int cxl_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type, - struct cxl_register_map *map) +static int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type, + struct cxl_register_map *map) { int rc; @@ -345,14 +283,7 @@ static int cxl_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type, if (rc) return rc; - rc = cxl_map_regblock(map); - if (rc) - return rc; - - rc = cxl_probe_regs(map); - cxl_unmap_regblock(map); - - return rc; + return cxl_setup_regs(map); } /* @@ -683,7 +614,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) dev_warn(&pdev->dev, "Device DVSEC not present, skip CXL.mem init\n"); - rc = cxl_setup_regs(pdev, CXL_REGLOC_RBI_MEMDEV, &map); + rc = cxl_pci_setup_regs(pdev, CXL_REGLOC_RBI_MEMDEV, &map); if (rc) return rc; @@ -696,7 +627,7 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) * still be useful for management functions so don't return an error. */ cxlds->component_reg_phys = CXL_RESOURCE_NONE; - rc = cxl_setup_regs(pdev, CXL_REGLOC_RBI_COMPONENT, &map); + rc = cxl_pci_setup_regs(pdev, CXL_REGLOC_RBI_COMPONENT, &map); if (rc) dev_warn(&pdev->dev, "No component registers (%d)\n", rc); From f44c7b7ad9b8def769ba709e369fe92906250c02 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 22 Jun 2023 15:55:04 -0500 Subject: [PATCH 07/14] cxl/acpi: Move add_host_bridge_uport() after cxl_get_chbs() Just moving code to reorder functions to later share cxl_get_chbs() with add_host_bridge_uport(). This makes changes in the next patch visible. No other changes at all. Signed-off-by: Robert Richter Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-9-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/acpi.c | 90 +++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index 70cd9ac73a8b..0c975ee684b0 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -327,51 +327,6 @@ __mock struct acpi_device *to_cxl_host_bridge(struct device *host, return NULL; } -/* - * A host bridge is a dport to a CFMWS decode and it is a uport to the - * dport (PCIe Root Ports) in the host bridge. - */ -static int add_host_bridge_uport(struct device *match, void *arg) -{ - struct cxl_port *root_port = arg; - struct device *host = root_port->dev.parent; - struct acpi_device *hb = to_cxl_host_bridge(host, match); - struct acpi_pci_root *pci_root; - struct cxl_dport *dport; - struct cxl_port *port; - struct device *bridge; - int rc; - - if (!hb) - return 0; - - pci_root = acpi_pci_find_root(hb->handle); - bridge = pci_root->bus->bridge; - dport = cxl_find_dport_by_dev(root_port, bridge); - if (!dport) { - dev_dbg(host, "host bridge expected and not found\n"); - return 0; - } - - if (dport->rch) { - dev_info(bridge, "host supports CXL (restricted)\n"); - return 0; - } - - rc = devm_cxl_register_pci_bus(host, bridge, pci_root->bus); - if (rc) - return rc; - - port = devm_cxl_add_port(host, bridge, dport->component_reg_phys, - dport); - if (IS_ERR(port)) - return PTR_ERR(port); - - dev_info(bridge, "host supports CXL\n"); - - return 0; -} - /* Note, @dev is used by mock_acpi_table_parse_cedt() */ struct cxl_chbs_context { struct device *dev; @@ -467,6 +422,51 @@ static int add_host_bridge_dport(struct device *match, void *arg) return 0; } +/* + * A host bridge is a dport to a CFMWS decode and it is a uport to the + * dport (PCIe Root Ports) in the host bridge. + */ +static int add_host_bridge_uport(struct device *match, void *arg) +{ + struct cxl_port *root_port = arg; + struct device *host = root_port->dev.parent; + struct acpi_device *hb = to_cxl_host_bridge(host, match); + struct acpi_pci_root *pci_root; + struct cxl_dport *dport; + struct cxl_port *port; + struct device *bridge; + int rc; + + if (!hb) + return 0; + + pci_root = acpi_pci_find_root(hb->handle); + bridge = pci_root->bus->bridge; + dport = cxl_find_dport_by_dev(root_port, bridge); + if (!dport) { + dev_dbg(host, "host bridge expected and not found\n"); + return 0; + } + + if (dport->rch) { + dev_info(bridge, "host supports CXL (restricted)\n"); + return 0; + } + + rc = devm_cxl_register_pci_bus(host, bridge, pci_root->bus); + if (rc) + return rc; + + port = devm_cxl_add_port(host, bridge, dport->component_reg_phys, + dport); + if (IS_ERR(port)) + return PTR_ERR(port); + + dev_info(bridge, "host supports CXL\n"); + + return 0; +} + static int add_root_nvdimm_bridge(struct device *match, void *data) { struct cxl_decoder *cxld; From d02034b4025a086b1294bfd4a2e77525e816cea4 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 22 Jun 2023 15:55:05 -0500 Subject: [PATCH 08/14] cxl/acpi: Directly bind the CEDT detected CHBCR to the Host Bridge's port During a Host Bridge's downstream port enumeration the CHBS entries in the CEDT table are parsed, its Component Register base address extracted and then stored in struct cxl_dport. The CHBS may contain either the RCRB (RCH mode) or the Host Bridge's Component Registers (CHBCR, VH mode). The RCRB further contains the CXL downstream port register base address, while in VH mode the CXL Downstream Switch Ports are visible in the PCI hierarchy and the DP's component regs are disovered using the CXL DVSEC register locator capability. The Component Registers derived from the CHBS for both modes are different and thus also must be treated differently. That is, in RCH mode, the component regs base should be bound to the dport, but in VH mode to the CXL host bridge's port object. The current implementation stores the CHBCR in addition in struct cxl_dport and copies it later from there to struct cxl_port. As a result, the dport contains the wrong Component Registers base address and, e.g. the RAS capability of a CXL Root Port cannot be detected. To fix the CHBCR binding, attach it directly to the Host Bridge's @cxl_port structure. Do this during port creation of the Host Bridge in add_host_bridge_uport(). Factor out CHBS parsing code in add_host_bridge_dport() and use it in both functions. Co-developed-by: Dan Williams Signed-off-by: Robert Richter Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-10-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/acpi.c | 91 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 28 deletions(-) diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index 0c975ee684b0..89ee01323d43 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -335,13 +335,13 @@ struct cxl_chbs_context { u32 cxl_version; }; -static int cxl_get_chbs(union acpi_subtable_headers *header, void *arg, - const unsigned long end) +static int cxl_get_chbs_iter(union acpi_subtable_headers *header, void *arg, + const unsigned long end) { struct cxl_chbs_context *ctx = arg; struct acpi_cedt_chbs *chbs; - if (ctx->base) + if (ctx->base != CXL_RESOURCE_NONE) return 0; chbs = (struct acpi_cedt_chbs *) header; @@ -350,8 +350,6 @@ static int cxl_get_chbs(union acpi_subtable_headers *header, void *arg, return 0; ctx->cxl_version = chbs->cxl_version; - ctx->base = CXL_RESOURCE_NONE; - if (!chbs->base) return 0; @@ -364,11 +362,35 @@ static int cxl_get_chbs(union acpi_subtable_headers *header, void *arg, return 0; } +static int cxl_get_chbs(struct device *dev, struct acpi_device *hb, + struct cxl_chbs_context *ctx) +{ + unsigned long long uid; + int rc; + + rc = acpi_evaluate_integer(hb->handle, METHOD_NAME__UID, NULL, &uid); + if (rc != AE_OK) { + dev_err(dev, "unable to retrieve _UID\n"); + return -ENOENT; + } + + dev_dbg(dev, "UID found: %lld\n", uid); + *ctx = (struct cxl_chbs_context) { + .dev = dev, + .uid = uid, + .base = CXL_RESOURCE_NONE, + .cxl_version = UINT_MAX, + }; + + acpi_table_parse_cedt(ACPI_CEDT_TYPE_CHBS, cxl_get_chbs_iter, ctx); + + return 0; +} + static int add_host_bridge_dport(struct device *match, void *arg) { acpi_status rc; struct device *bridge; - unsigned long long uid; struct cxl_dport *dport; struct cxl_chbs_context ctx; struct acpi_pci_root *pci_root; @@ -379,41 +401,38 @@ static int add_host_bridge_dport(struct device *match, void *arg) if (!hb) return 0; - rc = acpi_evaluate_integer(hb->handle, METHOD_NAME__UID, NULL, &uid); - if (rc != AE_OK) { - dev_err(match, "unable to retrieve _UID\n"); - return -ENODEV; - } + rc = cxl_get_chbs(match, hb, &ctx); + if (rc) + return rc; - dev_dbg(match, "UID found: %lld\n", uid); - - ctx = (struct cxl_chbs_context) { - .dev = match, - .uid = uid, - }; - acpi_table_parse_cedt(ACPI_CEDT_TYPE_CHBS, cxl_get_chbs, &ctx); - - if (!ctx.base) { + if (ctx.cxl_version == UINT_MAX) { dev_warn(match, "No CHBS found for Host Bridge (UID %lld)\n", - uid); + ctx.uid); return 0; } if (ctx.base == CXL_RESOURCE_NONE) { dev_warn(match, "CHBS invalid for Host Bridge (UID %lld)\n", - uid); + ctx.uid); return 0; } pci_root = acpi_pci_find_root(hb->handle); bridge = pci_root->bus->bridge; + /* + * In RCH mode, bind the component regs base to the dport. In + * VH mode it will be bound to the CXL host bridge's port + * object later in add_host_bridge_uport(). + */ if (ctx.cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11) { - dev_dbg(match, "RCRB found for UID %lld: %pa\n", uid, &ctx.base); - dport = devm_cxl_add_rch_dport(root_port, bridge, uid, ctx.base); + dev_dbg(match, "RCRB found for UID %lld: %pa\n", ctx.uid, + &ctx.base); + dport = devm_cxl_add_rch_dport(root_port, bridge, ctx.uid, + ctx.base); } else { - dev_dbg(match, "CHBCR found for UID %lld: %pa\n", uid, &ctx.base); - dport = devm_cxl_add_dport(root_port, bridge, uid, ctx.base); + dport = devm_cxl_add_dport(root_port, bridge, ctx.uid, + CXL_RESOURCE_NONE); } if (IS_ERR(dport)) @@ -435,6 +454,8 @@ static int add_host_bridge_uport(struct device *match, void *arg) struct cxl_dport *dport; struct cxl_port *port; struct device *bridge; + struct cxl_chbs_context ctx; + resource_size_t component_reg_phys; int rc; if (!hb) @@ -453,12 +474,26 @@ static int add_host_bridge_uport(struct device *match, void *arg) return 0; } + rc = cxl_get_chbs(match, hb, &ctx); + if (rc) + return rc; + + if (ctx.cxl_version == ACPI_CEDT_CHBS_VERSION_CXL11) { + dev_warn(bridge, + "CXL CHBS version mismatch, skip port registration\n"); + return 0; + } + + component_reg_phys = ctx.base; + if (component_reg_phys != CXL_RESOURCE_NONE) + dev_dbg(match, "CHBCR found for UID %lld: %pa\n", + ctx.uid, &component_reg_phys); + rc = devm_cxl_register_pci_bus(host, bridge, pci_root->bus); if (rc) return rc; - port = devm_cxl_add_port(host, bridge, dport->component_reg_phys, - dport); + port = devm_cxl_add_port(host, bridge, component_reg_phys, dport); if (IS_ERR(port)) return PTR_ERR(port); From d8bffff2016f7aef1c1dbe01125720475507b6f2 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 22 Jun 2023 15:55:06 -0500 Subject: [PATCH 09/14] cxl/port: Remove Component Register base address from struct cxl_dport The Component Register base address @component_reg_phys is no longer used after the rework of the Component Register setup which now uses struct member @comp_map instead. Remove the base address. Signed-off-by: Robert Richter Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-11-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/core/port.c | 1 - drivers/cxl/cxl.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index cdfe0ea7a2e9..e0d2e7596440 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -960,7 +960,6 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, dport->dport_dev = dport_dev; dport->port_id = port_id; - dport->component_reg_phys = component_reg_phys; dport->port = port; cond_cxl_root_lock(port); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index ae265357170e..7fbc52b81554 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -594,7 +594,6 @@ struct cxl_rcrb_info { * struct cxl_dport - CXL downstream port * @dport_dev: PCI bridge or firmware device representing the downstream link * @port_id: unique hardware identifier for dport in decoder target list - * @component_reg_phys: downstream port component registers * @rcrb: Data about the Root Complex Register Block layout * @rch: Indicate whether this dport was enumerated in RCH or VH mode * @port: reference to cxl_port that contains this downstream port @@ -602,7 +601,6 @@ struct cxl_rcrb_info { struct cxl_dport { struct device *dport_dev; int port_id; - resource_size_t component_reg_phys; struct cxl_rcrb_info rcrb; bool rch; struct cxl_port *port; From f1d0525effc4fffe821905671ea24c30a4bfa393 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 22 Jun 2023 15:55:07 -0500 Subject: [PATCH 10/14] cxl/regs: Remove early capability checks in Component Register setup When probing the Component Registers in function cxl_probe_regs() there are also checks for the existence of the HDM and RAS capabilities. The checks may fail for components that do not implement the HDM capability causing the Component Registers setup to fail too. Remove the checks for a generalized use of cxl_probe_regs() and check them directly before mapping the RAS or HDM capabilities. This allows it to setup other Component Registers esp. of an RCH Downstream Port, which will be implemented in a follow-on patch. Signed-off-by: Robert Richter Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-12-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/core/regs.c | 8 -------- drivers/cxl/pci.c | 2 ++ drivers/cxl/port.c | 5 ++++- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c index e035ad8827a4..e68848075bb6 100644 --- a/drivers/cxl/core/regs.c +++ b/drivers/cxl/core/regs.c @@ -369,14 +369,6 @@ static int cxl_probe_regs(struct cxl_register_map *map) case CXL_REGLOC_RBI_COMPONENT: comp_map = &map->component_map; cxl_probe_component_regs(dev, base, comp_map); - if (!comp_map->hdm_decoder.valid) { - dev_err(dev, "HDM decoder registers not found\n"); - return -ENXIO; - } - - if (!comp_map->ras.valid) - dev_dbg(dev, "RAS registers not found\n"); - dev_dbg(dev, "Set up component registers\n"); break; case CXL_REGLOC_RBI_MEMDEV: diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index ac17bc0430dc..945ca0304d68 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -630,6 +630,8 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) rc = cxl_pci_setup_regs(pdev, CXL_REGLOC_RBI_COMPONENT, &map); if (rc) dev_warn(&pdev->dev, "No component registers (%d)\n", rc); + else if (!map.component_map.ras.valid) + dev_dbg(&pdev->dev, "RAS registers not found\n"); cxlds->component_reg_phys = map.resource; diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c index 4cef2bf45ad2..01e84ea54f56 100644 --- a/drivers/cxl/port.c +++ b/drivers/cxl/port.c @@ -102,8 +102,11 @@ static int cxl_endpoint_port_probe(struct cxl_port *port) return rc; cxlhdm = devm_cxl_setup_hdm(port, &info); - if (IS_ERR(cxlhdm)) + if (IS_ERR(cxlhdm)) { + if (PTR_ERR(cxlhdm) == -ENODEV) + dev_err(&port->dev, "HDM decoder registers not found\n"); return PTR_ERR(cxlhdm); + } /* Cache the data early to ensure is_visible() works */ read_cdat_data(port); From 86917c560dcf29270093768d947387ca00f729b4 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 22 Jun 2023 15:55:08 -0500 Subject: [PATCH 11/14] cxl/mem: Prepare for early RCH dport component register setup In order to move the RCH dport component register setup to cxl_pci the base address must be stored in CXL device state (cxlds) for both modes, RCH and VH. Store it in cxlds->component_reg_phys and use it for endpoint creation. Signed-off-by: Robert Richter Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-13-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/mem.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c index 4cc461c22b8b..7638a7f8f333 100644 --- a/drivers/cxl/mem.c +++ b/drivers/cxl/mem.c @@ -51,7 +51,6 @@ static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd, struct cxl_port *parent_port = parent_dport->port; struct cxl_dev_state *cxlds = cxlmd->cxlds; struct cxl_port *endpoint, *iter, *down; - resource_size_t component_reg_phys; int rc; /* @@ -72,11 +71,11 @@ static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd, * typical register locator mechanism. */ if (parent_dport->rch && cxlds->component_reg_phys == CXL_RESOURCE_NONE) - component_reg_phys = + cxlds->component_reg_phys = cxl_rcd_component_reg_phys(&cxlmd->dev, parent_dport); - else - component_reg_phys = cxlds->component_reg_phys; - endpoint = devm_cxl_add_port(host, &cxlmd->dev, component_reg_phys, + + endpoint = devm_cxl_add_port(host, &cxlmd->dev, + cxlds->component_reg_phys, parent_dport); if (IS_ERR(endpoint)) return PTR_ERR(endpoint); From 733b57f262b0e9f05ffeac102fe5bd729e263170 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 22 Jun 2023 15:55:09 -0500 Subject: [PATCH 12/14] cxl/pci: Early setup RCH dport component registers from RCRB CXL RAS capabilities must be enabled and accessible as soon as the CXL endpoint is detected in the PCI hierarchy and bound to the cxl_pci driver. This needs to be independent of other modules such as cxl_port or cxl_mem. CXL RAS capabilities reside in the Component Registers. For an RCH this is determined by probing RCRB which is implemented very late once the CXL Memory Device is created. Change this by moving the RCRB probe to the cxl_pci driver. Do this by using a new introduced function cxl_pci_find_port() similar to cxl_mem_find_port() to determine the involved dport by the endpoint's PCI handle. Plug this into the existing cxl_pci_setup_regs() function to setup Component Registers. Probe the RCRB in case the Component Registers cannot be located through the CXL Register Locator capability. This unifies code and early sets up the Component Registers at the same time for both, VH and RCH mode. Only the cxl_pci driver is involved for this. This allows an early mapping of the CXL RAS capability registers. Signed-off-by: Robert Richter Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-14-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/core/port.c | 7 +++++ drivers/cxl/cxl.h | 2 ++ drivers/cxl/mem.c | 9 ------ drivers/cxl/pci.c | 63 +++++++++++++++++++++++++++++++++-------- 4 files changed, 60 insertions(+), 21 deletions(-) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index e0d2e7596440..679226023f0c 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -1480,6 +1480,13 @@ retry: } EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_ports, CXL); +struct cxl_port *cxl_pci_find_port(struct pci_dev *pdev, + struct cxl_dport **dport) +{ + return find_cxl_port(pdev->dev.parent, dport); +} +EXPORT_SYMBOL_NS_GPL(cxl_pci_find_port, CXL); + struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd, struct cxl_dport **dport) { diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 7fbc52b81554..fe95f08acb69 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -664,6 +664,8 @@ struct cxl_port *find_cxl_root(struct cxl_port *port); int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd); void cxl_bus_rescan(void); void cxl_bus_drain(void); +struct cxl_port *cxl_pci_find_port(struct pci_dev *pdev, + struct cxl_dport **dport); struct cxl_port *cxl_mem_find_port(struct cxl_memdev *cxlmd, struct cxl_dport **dport); bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd); diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c index 7638a7f8f333..205e2e280aed 100644 --- a/drivers/cxl/mem.c +++ b/drivers/cxl/mem.c @@ -65,15 +65,6 @@ static int devm_cxl_add_endpoint(struct device *host, struct cxl_memdev *cxlmd, ep->next = down; } - /* - * The component registers for an RCD might come from the - * host-bridge RCRB if they are not already mapped via the - * typical register locator mechanism. - */ - if (parent_dport->rch && cxlds->component_reg_phys == CXL_RESOURCE_NONE) - cxlds->component_reg_phys = - cxl_rcd_component_reg_phys(&cxlmd->dev, parent_dport); - endpoint = devm_cxl_add_port(host, &cxlmd->dev, cxlds->component_reg_phys, parent_dport); diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 945ca0304d68..99a75c54ee39 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -274,18 +274,6 @@ static int cxl_pci_setup_mailbox(struct cxl_dev_state *cxlds) return 0; } -static int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type, - struct cxl_register_map *map) -{ - int rc; - - rc = cxl_find_regblock(pdev, type, map); - if (rc) - return rc; - - return cxl_setup_regs(map); -} - /* * Assume that any RCIEP that emits the CXL memory expander class code * is an RCD @@ -295,6 +283,57 @@ static bool is_cxl_restricted(struct pci_dev *pdev) return pci_pcie_type(pdev) == PCI_EXP_TYPE_RC_END; } +static int cxl_rcrb_get_comp_regs(struct pci_dev *pdev, + struct cxl_register_map *map) +{ + struct cxl_port *port; + struct cxl_dport *dport; + resource_size_t component_reg_phys; + + *map = (struct cxl_register_map) { + .dev = &pdev->dev, + .resource = CXL_RESOURCE_NONE, + }; + + port = cxl_pci_find_port(pdev, &dport); + if (!port) + return -EPROBE_DEFER; + + component_reg_phys = cxl_rcd_component_reg_phys(&pdev->dev, dport); + + put_device(&port->dev); + + if (component_reg_phys == CXL_RESOURCE_NONE) + return -ENXIO; + + map->resource = component_reg_phys; + map->reg_type = CXL_REGLOC_RBI_COMPONENT; + map->max_size = CXL_COMPONENT_REG_BLOCK_SIZE; + + return 0; +} + +static int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type, + struct cxl_register_map *map) +{ + int rc; + + rc = cxl_find_regblock(pdev, type, map); + + /* + * If the Register Locator DVSEC does not exist, check if it + * is an RCH and try to extract the Component Registers from + * an RCRB. + */ + if (rc && type == CXL_REGLOC_RBI_COMPONENT && is_cxl_restricted(pdev)) + rc = cxl_rcrb_get_comp_regs(pdev, map); + + if (rc) + return rc; + + return cxl_setup_regs(map); +} + /* * 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 From 19ab69a60e3ba58b4942b9ab5095cf90477a54ce Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 22 Jun 2023 15:55:10 -0500 Subject: [PATCH 13/14] cxl/port: Store the port's Component Register mappings in struct cxl_port CXL capabilities are stored in the Component Registers. To use them, the specific I/O ranges of the capabilities must be determined by probing the registers. For this, the whole Component Register range needs to be mapped temporarily to detect the offset and length of a capability range. In order to use more than one capability of a component (e.g. RAS and HDM) the Component Register are probed and its mappings created multiple times. This also causes overlapping I/O ranges as the whole Component Register range must be mapped again while a capability's I/O range is already mapped. Different capabilities cannot be setup at the same time. E.g. the RAS capability must be made available as soon as the PCI driver is bound, the HDM decoder is setup later during port enumeration. Moreover, during early setup it is still unknown if a certain capability is needed. A central capability setup is therefore not possible, capabilities must be individually enabled once needed during initialization. To avoid a duplicate register probe and overlapping I/O mappings, only probe the Component Registers one time and store the Component Register mapping in struct port. The stored mappings can be used later to iomap the capability register range when enabling the capability, which will be implemented in a follow-on patch. Signed-off-by: Robert Richter Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-15-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/core/port.c | 27 +++++++++++++++++++++++++++ drivers/cxl/cxl.h | 2 ++ 2 files changed, 29 insertions(+) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 679226023f0c..43ffecebf1d8 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -688,6 +688,29 @@ err: return ERR_PTR(rc); } +static int cxl_setup_comp_regs(struct device *dev, struct cxl_register_map *map, + resource_size_t component_reg_phys) +{ + if (component_reg_phys == CXL_RESOURCE_NONE) + return 0; + + *map = (struct cxl_register_map) { + .dev = dev, + .reg_type = CXL_REGLOC_RBI_COMPONENT, + .resource = component_reg_phys, + .max_size = CXL_COMPONENT_REG_BLOCK_SIZE, + }; + + return cxl_setup_regs(map); +} + +static inline int cxl_port_setup_regs(struct cxl_port *port, + resource_size_t component_reg_phys) +{ + return cxl_setup_comp_regs(&port->dev, &port->comp_map, + component_reg_phys); +} + static struct cxl_port *__devm_cxl_add_port(struct device *host, struct device *uport_dev, resource_size_t component_reg_phys, @@ -711,6 +734,10 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host, if (rc) goto err; + rc = cxl_port_setup_regs(port, component_reg_phys); + if (rc) + goto err; + rc = device_add(dev); if (rc) goto err; diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index fe95f08acb69..37fa5b565362 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -547,6 +547,7 @@ struct cxl_dax_region { * @regions: cxl_region_ref instances, regions mapped by this port * @parent_dport: dport that points to this port in the parent * @decoder_ida: allocator for decoder ids + * @comp_map: component register capability mappings * @nr_dports: number of entries in @dports * @hdm_end: track last allocated HDM decoder instance for allocation ordering * @commit_end: cursor to track highest committed decoder for commit ordering @@ -566,6 +567,7 @@ struct cxl_port { struct xarray regions; struct cxl_dport *parent_dport; struct ida decoder_ida; + struct cxl_register_map comp_map; int nr_dports; int hdm_end; int commit_end; From 5d2ffbe4b81a3b6353bf888a523e7e5d4fec47ad Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 22 Jun 2023 15:55:11 -0500 Subject: [PATCH 14/14] cxl/port: Store the downstream port's Component Register mappings in struct cxl_dport Same as for ports, also store the downstream port's Component Register mappings, use struct cxl_dport for that. Signed-off-by: Robert Richter Signed-off-by: Terry Bowman Reviewed-by: Jonathan Cameron Link: https://lore.kernel.org/r/20230622205523.85375-16-terry.bowman@amd.com Signed-off-by: Dan Williams --- drivers/cxl/core/port.c | 11 +++++++++++ drivers/cxl/cxl.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 43ffecebf1d8..cbd3d17f6410 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -711,6 +711,13 @@ static inline int cxl_port_setup_regs(struct cxl_port *port, component_reg_phys); } +static inline int cxl_dport_setup_regs(struct cxl_dport *dport, + resource_size_t component_reg_phys) +{ + return cxl_setup_comp_regs(dport->dport_dev, &dport->comp_map, + component_reg_phys); +} + static struct cxl_port *__devm_cxl_add_port(struct device *host, struct device *uport_dev, resource_size_t component_reg_phys, @@ -989,6 +996,10 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, dport->port_id = port_id; dport->port = port; + rc = cxl_dport_setup_regs(dport, component_reg_phys); + 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 37fa5b565362..b1adca9b27ba 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -595,6 +595,7 @@ struct cxl_rcrb_info { /** * struct cxl_dport - CXL downstream port * @dport_dev: PCI bridge or firmware device representing the downstream link + * @comp_map: component register capability mappings * @port_id: unique hardware identifier for dport in decoder target list * @rcrb: Data about the Root Complex Register Block layout * @rch: Indicate whether this dport was enumerated in RCH or VH mode @@ -602,6 +603,7 @@ struct cxl_rcrb_info { */ struct cxl_dport { struct device *dport_dev; + struct cxl_register_map comp_map; int port_id; struct cxl_rcrb_info rcrb; bool rch;