From patchwork Fri Apr 4 22:57:33 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 14039002 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C0F7F19DF66 for ; Fri, 4 Apr 2025 23:00:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743807654; cv=none; b=cod6DDhn/SOuR17zDE709BFigII7g73hCl4BTuLezGHhEnE9QaM/wrlFpjb5BwjI0NsDfphQvM2wC7sgmbCcxTstT4f3Wl8J05HusnUvpC3eLbtgr5pKlPmWXi52GCHEDgx9BgXtX5YO5NCAtqq1DXVMr30OJoNslCO9FbubeeM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743807654; c=relaxed/simple; bh=SY/JztmW44NId5HAYhAay2/HTISDrXqEcbzC7TStz9w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Nb+IDHNRug/zSCM1wTY8T2LOrt21zB8bbJsMQKjsYAo3v6Iw7PhNeumaD7zRmUNidfL6+c0n5jMJYFQSK95eJes9+NmAbhj3bEi0eE+0BAvEP/ItbmbDIB0fH/7w4APiBUCa0hpi3CpeYC2nflcndHKLd3HfDKi33zTvwD2piSw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 28FF3C4CEDD; Fri, 4 Apr 2025 23:00:54 +0000 (UTC) From: Dave Jiang To: linux-cxl@vger.kernel.org Cc: dan.j.williams@intel.com, dave@stgolabs.net, jonathan.cameron@huawei.com, alison.schofield@intel.com, ira.weiny@intel.com, rrichter@amd.com, ming.li@zohomail.com Subject: [PATCH 1/4] cxl: Saperate out CXL dport->id vs actual dport hardware id Date: Fri, 4 Apr 2025 15:57:33 -0700 Message-ID: <20250404230049.3578835-2-dave.jiang@intel.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250404230049.3578835-1-dave.jiang@intel.com> References: <20250404230049.3578835-1-dave.jiang@intel.com> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 In preparation to allow dport to be allocated without being active, make dport->id to be Linux id that enumerates the dport objects per port. Keep the hardware id under dport->port_id to maintain compatibility and introduce a dport->id as the enumeration id. Signed-off-by: Dave Jiang --- drivers/cxl/core/port.c | 40 +++++++++++++++++++++++++++++----------- drivers/cxl/cxl.h | 4 ++++ 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 0fd6646c1a2e..e90e55bc11ac 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -159,7 +159,7 @@ static ssize_t emit_target_list(struct cxl_switch_decoder *cxlsd, char *buf) if (i + 1 < cxld->interleave_ways) next = cxlsd->target[i + 1]; - rc = sysfs_emit_at(buf, offset, "%d%s", dport->port_id, + rc = sysfs_emit_at(buf, offset, "%d%s", dport->id, next ? "," : ""); if (rc < 0) return rc; @@ -739,6 +739,7 @@ static struct cxl_port *cxl_port_alloc(struct device *uport_dev, dev->parent = uport_dev; ida_init(&port->decoder_ida); + ida_init(&port->dport_ida); port->hdm_end = -1; port->commit_end = -1; xa_init(&port->dports); @@ -1044,14 +1045,14 @@ void put_cxl_root(struct cxl_root *cxl_root) } EXPORT_SYMBOL_NS_GPL(put_cxl_root, "CXL"); -static struct cxl_dport *find_dport(struct cxl_port *port, int id) +static struct cxl_dport *find_dport(struct cxl_port *port, int port_id) { struct cxl_dport *dport; unsigned long index; device_lock_assert(&port->dev); xa_for_each(&port->dports, index, dport) - if (dport->port_id == id) + if (dport->port_id == port_id) return dport; return NULL; } @@ -1105,6 +1106,7 @@ static void cxl_dport_remove(void *data) struct cxl_port *port = dport->port; xa_erase(&port->dports, (unsigned long) dport->dport_dev); + ida_free(&port->dport_ida, dport->id); put_device(dport->dport_dev); } @@ -1114,7 +1116,7 @@ static void cxl_dport_unlink(void *data) struct cxl_port *port = dport->port; char link_name[CXL_TARGET_STRLEN]; - sprintf(link_name, "dport%d", dport->port_id); + sprintf(link_name, "dport%d", dport->id); sysfs_remove_link(&port->dev.kobj, link_name); } @@ -1126,7 +1128,7 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, char link_name[CXL_TARGET_STRLEN]; struct cxl_dport *dport; struct device *host; - int rc; + int id, rc; if (is_cxl_root(port)) host = port->uport_dev; @@ -1139,29 +1141,41 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, return ERR_PTR(-ENXIO); } - if (snprintf(link_name, CXL_TARGET_STRLEN, "dport%d", port_id) >= - CXL_TARGET_STRLEN) + id = ida_alloc(&port->dport_ida, GFP_KERNEL); + if (id < 0) + return ERR_PTR(id); + + if (snprintf(link_name, CXL_TARGET_STRLEN, "dport%d", id) >= + CXL_TARGET_STRLEN) { + ida_free(&port->dport_ida, id); return ERR_PTR(-EINVAL); + } dport = devm_kzalloc(host, sizeof(*dport), GFP_KERNEL); - if (!dport) + if (!dport) { + ida_free(&port->dport_ida, id); return ERR_PTR(-ENOMEM); + } dport->dport_dev = dport_dev; dport->port_id = port_id; dport->port = port; + dport->id = id; if (rcrb == CXL_RESOURCE_NONE) { rc = cxl_dport_setup_regs(&port->dev, dport, component_reg_phys); - if (rc) + if (rc) { + ida_free(&port->dport_ida, id); return ERR_PTR(rc); + } } else { 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"); + ida_free(&port->dport_ida, id); return ERR_PTR(-ENXIO); } @@ -1170,8 +1184,10 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, * memdev */ rc = cxl_dport_setup_regs(NULL, dport, component_reg_phys); - if (rc) + if (rc) { + ida_free(&port->dport_ida, id); return ERR_PTR(rc); + } dport->rch = true; } @@ -1183,8 +1199,10 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, cond_cxl_root_lock(port); rc = add_dport(port, dport); cond_cxl_root_unlock(port); - if (rc) + if (rc) { + ida_free(&port->dport_ida, id); return ERR_PTR(rc); + } get_device(dport_dev); rc = devm_add_action_or_reset(host, cxl_dport_remove, dport); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index be8a7dc77719..c942fa40c869 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -583,6 +583,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 + * @dport_ida: allocator for dport ids * @reg_map: component and ras register mapping parameters * @nr_dports: number of entries in @dports * @hdm_end: track last allocated HDM decoder instance for allocation ordering @@ -604,6 +605,7 @@ struct cxl_port { struct xarray regions; struct cxl_dport *parent_dport; struct ida decoder_ida; + struct ida dport_ida; struct cxl_register_map reg_map; int nr_dports; int hdm_end; @@ -657,6 +659,7 @@ struct cxl_rcrb_info { * struct cxl_dport - CXL downstream port * @dport_dev: PCI bridge or firmware device representing the downstream link * @reg_map: component and ras register mapping parameters + * @id: Linux id to enumerate dport instances per port * @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 @@ -668,6 +671,7 @@ struct cxl_rcrb_info { struct cxl_dport { struct device *dport_dev; struct cxl_register_map reg_map; + int id; int port_id; struct cxl_rcrb_info rcrb; bool rch; From patchwork Fri Apr 4 22:57:34 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 14039003 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 355AC15990C for ; Fri, 4 Apr 2025 23:00:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743807656; cv=none; b=VcQk9fDw1ZUoS0mbjhLrF8ptKbCMEb7DztOSZQSp24QbUX7HBmIy98OfkJj9kCr8tgYiHr6rxAGujBA+JyykUQhBE/ib+wRoLWty2tlJGokV6lUI8LI0n0LJJ8LNZxruVs0bODOgnJbvhDtvSGxJZh/C2cYRBYyePT6d4ag2KPw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743807656; c=relaxed/simple; bh=QIKC7LLpZs8/Uu007q/vqLqpXlv3HqABsxRs/AjuSuw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=p+rgmckLlMkoS+lpD7VEl4kQ+sfihLIdmsAtABC3X3IUjh4s9cuXdUJAcY2VG6QENz5upYiZA6oiw60P1RExGsngcyL/49ST/r/k2w4w5sM+oPe5QVmo7CRIiys8NGH7tLIb9tfh7v58fETDNE6PmCuHW6zLXu7DjeOMMV57hMo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 94A33C4CEDD; Fri, 4 Apr 2025 23:00:55 +0000 (UTC) From: Dave Jiang To: linux-cxl@vger.kernel.org Cc: dan.j.williams@intel.com, dave@stgolabs.net, jonathan.cameron@huawei.com, alison.schofield@intel.com, ira.weiny@intel.com, rrichter@amd.com, ming.li@zohomail.com Subject: [PATCH 2/4] cxl: Defer hardware dport->port_id assignment and registers probing Date: Fri, 4 Apr 2025 15:57:34 -0700 Message-ID: <20250404230049.3578835-3-dave.jiang@intel.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250404230049.3578835-1-dave.jiang@intel.com> References: <20250404230049.3578835-1-dave.jiang@intel.com> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Current implementation only enuemrates the dports dupring the port probe. Without an endpoint connected, the dport may not be active during port probe. This scheme may prevent a valid hardware dport id to be retrieved and MMIO registers to be read when an endpoint is hot-plugged. Move the hw dport id assignment and the register probing to behind memdev probe so the endpoint is guaranteed to be connected. The detection of duplicate dport for add_dport() is removed. The port_id is not read from the hw at this point any longer. The port->id will always be unique since it's retrieved from an ida. The dup detection thus become irrelevant. Signed-off-by: Dave Jiang --- drivers/cxl/core/core.h | 4 ++ drivers/cxl/core/pci.c | 74 ++++++++++++++++++++++++++++------ drivers/cxl/core/port.c | 88 ++++++++++++++++++++++------------------- drivers/cxl/cxl.h | 1 + drivers/cxl/port.c | 2 - 5 files changed, 114 insertions(+), 55 deletions(-) diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h index 15699299dc11..e2822ead6a67 100644 --- a/drivers/cxl/core/core.h +++ b/drivers/cxl/core/core.h @@ -134,4 +134,8 @@ int cxl_set_feature(struct cxl_mailbox *cxl_mbox, const uuid_t *feat_uuid, u16 *return_code); #endif +int cxl_dport_probe(struct cxl_dport *dport, resource_size_t component_reg_phys, + resource_size_t rcrb); +void cxl_port_probe_dports(struct cxl_port *port); + #endif /* __CXL_CORE_H__ */ diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index 96fecb799cbc..a47dd032abd7 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -24,6 +24,66 @@ static unsigned short media_ready_timeout = 60; module_param(media_ready_timeout, ushort, 0644); MODULE_PARM_DESC(media_ready_timeout, "seconds to wait for media ready"); +static int probe_dports(struct cxl_dport *dport) +{ + struct device *dport_dev = dport->dport_dev; + struct cxl_port *port = dport->port; + struct cxl_register_map map; + struct pci_dev *pdev; + u32 lnkcap, port_num; + int rc; + + if (!dev_is_pci(dport_dev)) + return 0; + + /* + * dport->port_id is valid means that dport has been probed and is + * setup. + */ + if (dport->port_id != CXL_PORT_ID_INVALID) + return 0; + + pdev = to_pci_dev(dport_dev); + if (pci_read_config_dword(pdev, pci_pcie_cap(pdev) + PCI_EXP_LNKCAP, + &lnkcap)) + return 0; + + rc = cxl_find_regblock(pdev, CXL_REGLOC_RBI_COMPONENT, &map); + if (rc) { + dev_dbg(&port->dev, "failed to find component registers\n"); + return 0; + } + + port_num = FIELD_GET(PCI_EXP_LNKCAP_PN, lnkcap); + rc = cxl_dport_probe(dport, map.resource, CXL_RESOURCE_NONE); + if (rc) + return rc; + + /* + * port_id is only set if the register block is also probed + * successfully. + */ + dport->port_id = port_num; + cxl_switch_parse_cdat(port); + + return 0; +} + +/** + * cxl_port_probe_dports - probe downstream ports of the upstream port + * @port: cxl_port whose ->uport_dev is the upstream of dports to be probed + * + */ +void cxl_port_probe_dports(struct cxl_port *port) +{ + struct cxl_dport *dport; + unsigned long index; + + device_lock_assert(&port->dev); + xa_for_each(&port->dports, index, dport) + probe_dports(dport); +} + struct cxl_walk_context { struct pci_bus *bus; struct cxl_port *port; @@ -37,10 +97,7 @@ static int match_add_dports(struct pci_dev *pdev, void *data) struct cxl_walk_context *ctx = data; struct cxl_port *port = ctx->port; int type = pci_pcie_type(pdev); - struct cxl_register_map map; struct cxl_dport *dport; - u32 lnkcap, port_num; - int rc; if (pdev->bus != ctx->bus) return 0; @@ -48,16 +105,9 @@ static int match_add_dports(struct pci_dev *pdev, void *data) return 0; if (type != ctx->type) return 0; - if (pci_read_config_dword(pdev, pci_pcie_cap(pdev) + PCI_EXP_LNKCAP, - &lnkcap)) - return 0; - rc = cxl_find_regblock(pdev, CXL_REGLOC_RBI_COMPONENT, &map); - if (rc) - dev_dbg(&port->dev, "failed to find component registers\n"); - - port_num = FIELD_GET(PCI_EXP_LNKCAP_PN, lnkcap); - dport = devm_cxl_add_dport(port, &pdev->dev, port_num, map.resource); + dport = devm_cxl_add_dport(port, &pdev->dev, CXL_PORT_ID_INVALID, + CXL_RESOURCE_NONE); if (IS_ERR(dport)) { ctx->error = PTR_ERR(dport); return PTR_ERR(dport); diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index e90e55bc11ac..1c772c516dbe 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -1059,18 +1059,9 @@ static struct cxl_dport *find_dport(struct cxl_port *port, int port_id) 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, dport->port_id); - if (dup) { - dev_err(&port->dev, - "unable to add dport%d-%s non-unique port id (%s)\n", - dport->port_id, dev_name(dport->dport_dev), - dev_name(dup->dport_dev)); - return -EBUSY; - } rc = xa_insert(&port->dports, (unsigned long)dport->dport_dev, dport, GFP_KERNEL); @@ -1120,6 +1111,45 @@ static void cxl_dport_unlink(void *data) sysfs_remove_link(&port->dev.kobj, link_name); } +int cxl_dport_probe(struct cxl_dport *dport, resource_size_t component_reg_phys, + resource_size_t rcrb) +{ + struct device *dport_dev = dport->dport_dev; + struct cxl_port *port = dport->port; + int rc; + + if (rcrb == CXL_RESOURCE_NONE) { + rc = cxl_dport_setup_regs(&port->dev, dport, + component_reg_phys); + if (rc) + return rc; + } else { + 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"); + return -ENXIO; + } + + /* + * RCH @dport is not ready to map until associated with its + * memdev + */ + rc = cxl_dport_setup_regs(NULL, dport, component_reg_phys); + if (rc) + return rc; + + dport->rch = true; + } + + if (component_reg_phys != CXL_RESOURCE_NONE) + dev_dbg(dport_dev, "Component Registers found for dport: %pa\n", + &component_reg_phys); + + 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, @@ -1162,40 +1192,12 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev, dport->port = port; dport->id = id; - if (rcrb == CXL_RESOURCE_NONE) { - rc = cxl_dport_setup_regs(&port->dev, dport, - component_reg_phys); - if (rc) { - ida_free(&port->dport_ida, id); - return ERR_PTR(rc); - } - } else { - 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"); - ida_free(&port->dport_ida, id); - return ERR_PTR(-ENXIO); - } - - /* - * RCH @dport is not ready to map until associated with its - * memdev - */ - rc = cxl_dport_setup_regs(NULL, dport, component_reg_phys); - if (rc) { - ida_free(&port->dport_ida, id); - return ERR_PTR(rc); - } - - dport->rch = true; + rc = cxl_dport_probe(dport, component_reg_phys, rcrb); + if (rc) { + ida_free(&port->dport_ida, id); + return ERR_PTR(rc); } - if (component_reg_phys != CXL_RESOURCE_NONE) - dev_dbg(dport_dev, "Component Registers found for dport: %pa\n", - &component_reg_phys); - cond_cxl_root_lock(port); rc = add_dport(port, dport); cond_cxl_root_unlock(port); @@ -1684,6 +1686,10 @@ int devm_cxl_enumerate_ports(struct cxl_memdev *cxlmd) "found already registered port %s:%s\n", dev_name(&port->dev), dev_name(port->uport_dev)); + + scoped_guard(device, &port->dev) + cxl_port_probe_dports(port); + rc = cxl_add_ep(dport, &cxlmd->dev); /* diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index c942fa40c869..0e61b76f5c13 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -345,6 +345,7 @@ enum cxl_decoder_type { #define CXL_DECODER_MAX_INTERLEAVE 16 #define CXL_QOS_CLASS_INVALID -1 +#define CXL_PORT_ID_INVALID -1 /** * struct cxl_decoder - Common CXL HDM Decoder Attributes diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c index a35fc5552845..30c0335089b9 100644 --- a/drivers/cxl/port.c +++ b/drivers/cxl/port.c @@ -69,8 +69,6 @@ static int cxl_switch_port_probe(struct cxl_port *port) if (rc < 0) return rc; - cxl_switch_parse_cdat(port); - cxlhdm = devm_cxl_setup_hdm(port, NULL); if (!IS_ERR(cxlhdm)) return devm_cxl_enumerate_decoders(cxlhdm, NULL); From patchwork Fri Apr 4 22:57:35 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 14039004 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BB6431A841E for ; Fri, 4 Apr 2025 23:00:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743807657; cv=none; b=qnFnp0BluzQacVcJkeDeQ1O7CSJDrFikkWa9X/oHU3tlVfGb8MNHIb2UUK4WM4yfrdUwSIAqGgWBiKhXdeBFTV69ml2MsILvxvJ5aNZ19O9JWcu5IXodZDgXrnh9lTm/cezb72m5kiXqvbvkmFMj8Wq7P6/3psLSUGcStvQpgxA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743807657; c=relaxed/simple; bh=q0QapgzcUOkDwfeR5QFxB8f2jaHlnadea2o7v4oij5Q=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=GU0yoL7MIWkaIncui4czgtpeg1qXDZzs9SwQ04EwwTuZERKuoa3EhgquRz2MKpUHwDolDdvP2rpqihxNJl494M7gKDIDlB4IdrAGJf02PSUjrgfhToZ04y+cw45QkW8CjkNnrC9izdAu4npKFXZbtmIQ3Jl3ab/wkosODBVExlA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1B124C4CEDD; Fri, 4 Apr 2025 23:00:57 +0000 (UTC) From: Dave Jiang To: linux-cxl@vger.kernel.org Cc: dan.j.williams@intel.com, dave@stgolabs.net, jonathan.cameron@huawei.com, alison.schofield@intel.com, ira.weiny@intel.com, rrichter@amd.com, ming.li@zohomail.com Subject: [PATCH 3/4] cxl: Add late host bridge uport mapping update Date: Fri, 4 Apr 2025 15:57:35 -0700 Message-ID: <20250404230049.3578835-4-dave.jiang@intel.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250404230049.3578835-1-dave.jiang@intel.com> References: <20250404230049.3578835-1-dave.jiang@intel.com> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Error message "cxl portN: Couldn't locate the CXL.cache and CXL.mem capability array header" is reported through testing when a platform is enabled with PCIe hotplug. The cxl_acpi module is responsible for enumerating the host bridges through ACPI objects. During the enumeration of the host bridge upstream ports (uports), the root port (RP) registers are mapped. The enumeration can happen as soon as the cxl_acpi module probe() function is called. However if the CXL link between the endpoint device and the RP is not established before the enumeration happens, the platform may not expose DVSEC ID 3 and/or DVSEC ID 7 blocks which triggers the error message. Add an attempt to map the register block under the memdev probe() port enumeration. When the PCI probe of the device endpoint is called, the driver is now communicating with the CXL device and the CXL link is considered established. Doing the register block mapping at that point guarantees that the mandatory DVSEC blocks are present. Signed-off-by: Dave Jiang --- drivers/cxl/acpi.c | 17 +++++++++- drivers/cxl/core/port.c | 72 +++++++++++++++++++++++++++++++++++++++-- drivers/cxl/cxl.h | 4 +++ drivers/cxl/port.c | 19 ++--------- 4 files changed, 93 insertions(+), 19 deletions(-) diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index cb14829bb9be..3c8f04bee9a3 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -662,9 +662,24 @@ static int add_host_bridge_uport(struct device *match, void *arg) if (rc) return rc; - port = devm_cxl_add_port(host, bridge, component_reg_phys, dport); + /* + * While there is a chance the uport gets mapped when the probe + * function gets called, it is not a guarantee due to acpi driver + * can be probed before the root port has established the CXL + * connection to the endpoint device. Bypass mapping during + * port creation by pass in CXL_RESOURCE_NONE for the + * component_reg_phys parameter. After, set the 'resource' + * parameter of port->map to allow a setup via the endpoint + * memdev probe. + */ + port = devm_cxl_add_port(host, bridge, CXL_RESOURCE_NONE, dport); if (IS_ERR(port)) return PTR_ERR(port); + port->reg_map = (struct cxl_register_map) { + .host = host, + .reg_type = CXL_REGLOC_RBI_EMPTY, + .resource = component_reg_phys, + }; dev_info(bridge, "host supports CXL\n"); diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 1c772c516dbe..8c29db214d60 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -758,6 +758,10 @@ static struct cxl_port *cxl_port_alloc(struct device *uport_dev, static int cxl_setup_comp_regs(struct device *host, struct cxl_register_map *map, resource_size_t component_reg_phys) { + /* Skip the setup if the map has been setup previously. */ + if (map->reg_type != CXL_REGLOC_RBI_EMPTY) + return 0; + *map = (struct cxl_register_map) { .host = host, .reg_type = CXL_REGLOC_RBI_EMPTY, @@ -773,7 +777,7 @@ static int cxl_setup_comp_regs(struct device *host, struct cxl_register_map *map return cxl_setup_regs(map); } -static int cxl_port_setup_regs(struct cxl_port *port, +int cxl_port_setup_regs(struct cxl_port *port, resource_size_t component_reg_phys) { if (dev_is_platform(port->uport_dev)) @@ -781,6 +785,7 @@ static int cxl_port_setup_regs(struct cxl_port *port, return cxl_setup_comp_regs(&port->dev, &port->reg_map, component_reg_phys); } +EXPORT_SYMBOL_NS_GPL(cxl_port_setup_regs, "CXL"); static int cxl_dport_setup_regs(struct device *host, struct cxl_dport *dport, resource_size_t component_reg_phys) @@ -1004,7 +1009,7 @@ int devm_cxl_register_pci_bus(struct device *host, struct device *uport_dev, } EXPORT_SYMBOL_NS_GPL(devm_cxl_register_pci_bus, "CXL"); -static bool dev_is_cxl_root_child(struct device *dev) +bool dev_is_cxl_root_child(struct device *dev) { struct cxl_port *port, *parent; @@ -1021,6 +1026,7 @@ static bool dev_is_cxl_root_child(struct device *dev) return false; } +EXPORT_SYMBOL_NS_GPL(dev_is_cxl_root_child, "CXL"); struct cxl_root *find_cxl_root(struct cxl_port *port) { @@ -1565,6 +1571,57 @@ static resource_size_t find_component_registers(struct device *dev) return map.resource; } +int devm_cxl_decoders_setup(struct cxl_port *port) +{ + struct cxl_dport *dport; + struct cxl_hdm *cxlhdm; + unsigned long index; + int dports = 0; + + /* Make sure that no decoders have been allocated before proceeding. */ + if (!ida_is_empty(&port->decoder_ida)) + return 0; + + cxlhdm = devm_cxl_setup_hdm(port, NULL); + if (!IS_ERR(cxlhdm)) + return devm_cxl_enumerate_decoders(cxlhdm, NULL); + + if (PTR_ERR(cxlhdm) != -ENODEV) { + dev_err(&port->dev, "Failed to map HDM decoder capability\n"); + return PTR_ERR(cxlhdm); + } + + xa_for_each(&port->dports, index, dport) + dports++; + + if (dports == 1) { + dev_dbg(&port->dev, "Fallback to passthrough decoder\n"); + return devm_cxl_add_passthrough_decoder(port); + } + + dev_err(&port->dev, "HDM decoder capability not found\n"); + return -ENXIO; +} +EXPORT_SYMBOL_NS_GPL(devm_cxl_decoders_setup, "CXL"); + +static int cxl_hb_port_setup(struct cxl_port *port) +{ + int rc; + + device_lock_assert(&port->dev); + + if (!dev_is_cxl_root_child(&port->dev)) + return 0; + + cxl_port_probe_dports(port); + + rc = cxl_port_setup_regs(port, port->reg_map.resource); + if (rc) + return rc; + + return devm_cxl_decoders_setup(port); +} + static int add_port_attach_ep(struct cxl_memdev *cxlmd, struct device *uport_dev, struct device *dport_dev) @@ -1605,6 +1662,17 @@ static int add_port_attach_ep(struct cxl_memdev *cxlmd, return -ENXIO; } + /* + * Initiate delayed host bridge setup here in the path of memdev probe + * to ensure that the CXL link is established. + */ + rc = cxl_hb_port_setup(parent_port); + if (rc) { + dev_warn(&cxlmd->dev, "Failed HB port setup of %s.\n", + dev_name(&parent_port->dev)); + return rc; + } + port = find_cxl_port_at(parent_port, dport_dev, &dport); if (!port) { component_reg_phys = find_component_registers(uport_dev); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 0e61b76f5c13..b27e9d3306fe 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -906,6 +906,10 @@ void cxl_coordinates_combine(struct access_coordinate *out, struct access_coordinate *c2); bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port); +int devm_cxl_decoders_setup(struct cxl_port *port); +bool dev_is_cxl_root_child(struct device *dev); +int cxl_port_setup_regs(struct cxl_port *port, + resource_size_t component_reg_phys); /* * Unit test builds overrides this to __weak, find the 'strong' version diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c index 30c0335089b9..dc532ee9065f 100644 --- a/drivers/cxl/port.c +++ b/drivers/cxl/port.c @@ -59,7 +59,6 @@ static int discover_region(struct device *dev, void *root) static int cxl_switch_port_probe(struct cxl_port *port) { - struct cxl_hdm *cxlhdm; int rc; /* Cache the data early to ensure is_visible() works */ @@ -69,22 +68,10 @@ static int cxl_switch_port_probe(struct cxl_port *port) if (rc < 0) return rc; - cxlhdm = devm_cxl_setup_hdm(port, NULL); - if (!IS_ERR(cxlhdm)) - return devm_cxl_enumerate_decoders(cxlhdm, NULL); + if (dev_is_cxl_root_child(&port->dev)) + return 0; - if (PTR_ERR(cxlhdm) != -ENODEV) { - dev_err(&port->dev, "Failed to map HDM decoder capability\n"); - return PTR_ERR(cxlhdm); - } - - if (rc == 1) { - dev_dbg(&port->dev, "Fallback to passthrough decoder\n"); - return devm_cxl_add_passthrough_decoder(port); - } - - dev_err(&port->dev, "HDM decoder capability not found\n"); - return -ENXIO; + return devm_cxl_decoders_setup(port); } static int cxl_endpoint_port_probe(struct cxl_port *port) From patchwork Fri Apr 4 22:57:36 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Jiang X-Patchwork-Id: 14039005 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 419D615990C for ; Fri, 4 Apr 2025 23:00:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743807659; cv=none; b=WRX3abkbfZC7LdhZZzc/M5CRtJIBlUzsf85zZav7vICvZSOJ3vuNdQR88pwfrzY8QSafx31uPbdpGmmYmaHsc1yM7Nwwsv2tFi+dm8aN+j9/FWbBK9+iYX4DEV7bvSxv1UNmVTZTdjZCBsKltcCZIWbqoQJacHDOFvoRZLIrF28= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1743807659; c=relaxed/simple; bh=8UukJ7od9194w+AZpeJi+LadeVF6Wy1JvRcUC4clVmQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=t8YI9F6+ISgD/RRssD513Su/REmLrqnoN+8htQau7wrUbjTt37I5HYeELfJNVZ41zOWZCEHVLCCbxu8g0zi4PBxvF0QkaKXni57V+iVqcu3he+R0+7gqaNrPEv12VSASCE1pwvRob2CJtNG5KTk2o+7inAplh5vJNL02mZl8hCA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8A3D8C4CEDD; Fri, 4 Apr 2025 23:00:58 +0000 (UTC) From: Dave Jiang To: linux-cxl@vger.kernel.org Cc: dan.j.williams@intel.com, dave@stgolabs.net, jonathan.cameron@huawei.com, alison.schofield@intel.com, ira.weiny@intel.com, rrichter@amd.com, ming.li@zohomail.com Subject: [PATCH 4/4] cxl/test: Add workaround for cxl_test for cxl_core calling mocked functions Date: Fri, 4 Apr 2025 15:57:36 -0700 Message-ID: <20250404230049.3578835-5-dave.jiang@intel.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250404230049.3578835-1-dave.jiang@intel.com> References: <20250404230049.3578835-1-dave.jiang@intel.com> Precedence: bulk X-Mailing-List: linux-cxl@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 When cxl_core calls a cxl_core exported function and that function is mocked by cxl_test, the call chain causes a circular dependency issue. Dan provided a workaround to avoid this issue. Apply the method to changes from the late host bridge uport mapping update changes in order to enable cxl-test. Suggested-by: Dan Williams Signed-off-by: Dave Jiang --- drivers/cxl/core/hdm.c | 51 +++++++++++++++++++++++++++++------ drivers/cxl/cxl.h | 16 +++++++++++ tools/testing/cxl/Kbuild | 3 --- tools/testing/cxl/test/mock.c | 34 +++++++++++++++-------- 4 files changed, 82 insertions(+), 22 deletions(-) diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index 70cae4ebf8a4..ed6bdbd6b452 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -39,14 +39,19 @@ static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld, return 0; } -/* +/** + * __devm_cxl_add_passthrough_decoder - Add passthrough decoder + * @port: The cxl_port context + * + * Return 0 on success or errno on failure. + * * Per the CXL specification (8.2.5.12 CXL HDM Decoder Capability Structure) * single ported host-bridges need not publish a decoder capability when a * passthrough decode can be assumed, i.e. all transactions that the uport sees * are claimed and passed to the single dport. Disable the range until the first * CXL region is enumerated / activated. */ -int devm_cxl_add_passthrough_decoder(struct cxl_port *port) +int __devm_cxl_add_passthrough_decoder(struct cxl_port *port) { struct cxl_switch_decoder *cxlsd; struct cxl_dport *dport = NULL; @@ -73,6 +78,16 @@ int devm_cxl_add_passthrough_decoder(struct cxl_port *port) return add_hdm_decoder(port, &cxlsd->cxld, single_port_map); } +EXPORT_SYMBOL_NS_GPL(__devm_cxl_add_passthrough_decoder, "CXL"); + +cxl_add_pt_decoder_fn _devm_cxl_add_passthrough_decoder = + __devm_cxl_add_passthrough_decoder; +EXPORT_SYMBOL_NS_GPL(_devm_cxl_add_passthrough_decoder, "CXL"); + +int devm_cxl_add_passthrough_decoder(struct cxl_port *port) +{ + return _devm_cxl_add_passthrough_decoder(port); +} EXPORT_SYMBOL_NS_GPL(devm_cxl_add_passthrough_decoder, "CXL"); static void parse_hdm_decoder_caps(struct cxl_hdm *cxlhdm) @@ -139,12 +154,12 @@ static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info) } /** - * devm_cxl_setup_hdm - map HDM decoder component registers + * __devm_cxl_setup_hdm - map HDM decoder component registers * @port: cxl_port to map * @info: cached DVSEC range register info */ -struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, - struct cxl_endpoint_dvsec_info *info) +struct cxl_hdm *__devm_cxl_setup_hdm(struct cxl_port *port, + struct cxl_endpoint_dvsec_info *info) { struct cxl_register_map *reg_map = &port->reg_map; struct device *dev = &port->dev; @@ -199,6 +214,16 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, return cxlhdm; } +EXPORT_SYMBOL_NS_GPL(__devm_cxl_setup_hdm, "CXL"); + +cxl_setup_hdm_fn _devm_cxl_setup_hdm = __devm_cxl_setup_hdm; +EXPORT_SYMBOL_NS_GPL(_devm_cxl_setup_hdm, "CXL"); + +struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port, + struct cxl_endpoint_dvsec_info *info) +{ + return _devm_cxl_setup_hdm(port, info); +} EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_hdm, "CXL"); static void __cxl_dpa_debug(struct seq_file *file, struct resource *r, int depth) @@ -1150,12 +1175,12 @@ static void cxl_settle_decoders(struct cxl_hdm *cxlhdm) } /** - * devm_cxl_enumerate_decoders - add decoder objects per HDM register set + * __devm_cxl_enumerate_decoders - add decoder objects per HDM register set * @cxlhdm: Structure to populate with HDM capabilities * @info: cached DVSEC range register info */ -int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, - struct cxl_endpoint_dvsec_info *info) +int __devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, + struct cxl_endpoint_dvsec_info *info) { void __iomem *hdm = cxlhdm->regs.hdm_decoder; struct cxl_port *port = cxlhdm->port; @@ -1212,4 +1237,14 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, return 0; } +EXPORT_SYMBOL_NS_GPL(__devm_cxl_enumerate_decoders, "CXL"); + +cxl_enum_decoders_fn _devm_cxl_enumerate_decoders = __devm_cxl_enumerate_decoders; +EXPORT_SYMBOL_NS_GPL(_devm_cxl_enumerate_decoders, "CXL"); + +int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, + struct cxl_endpoint_dvsec_info *info) +{ + return _devm_cxl_enumerate_decoders(cxlhdm, info); +} EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_decoders, "CXL"); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index b27e9d3306fe..ffcd6de18e20 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -911,6 +911,22 @@ bool dev_is_cxl_root_child(struct device *dev); int cxl_port_setup_regs(struct cxl_port *port, resource_size_t component_reg_phys); +typedef struct cxl_hdm *(*cxl_setup_hdm_fn)(struct cxl_port *port, + struct cxl_endpoint_dvsec_info *info); +extern cxl_setup_hdm_fn _devm_cxl_setup_hdm; +struct cxl_hdm *__devm_cxl_setup_hdm(struct cxl_port *port, + struct cxl_endpoint_dvsec_info *info); + +typedef int (*cxl_enum_decoders_fn)(struct cxl_hdm *cxlhdm, + struct cxl_endpoint_dvsec_info *info); +extern cxl_enum_decoders_fn _devm_cxl_enumerate_decoders; +int __devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, + struct cxl_endpoint_dvsec_info *info); + +typedef int (*cxl_add_pt_decoder_fn)(struct cxl_port *port); +extern cxl_add_pt_decoder_fn _devm_cxl_add_passthrough_decoder; +int __devm_cxl_add_passthrough_decoder(struct cxl_port *port); + /* * Unit test builds overrides this to __weak, find the 'strong' version * of these symbols in tools/testing/cxl/. diff --git a/tools/testing/cxl/Kbuild b/tools/testing/cxl/Kbuild index 387f3df8b988..34ea6e6f773b 100644 --- a/tools/testing/cxl/Kbuild +++ b/tools/testing/cxl/Kbuild @@ -5,9 +5,6 @@ ldflags-y += --wrap=acpi_evaluate_integer ldflags-y += --wrap=acpi_pci_find_root ldflags-y += --wrap=nvdimm_bus_register ldflags-y += --wrap=devm_cxl_port_enumerate_dports -ldflags-y += --wrap=devm_cxl_setup_hdm -ldflags-y += --wrap=devm_cxl_add_passthrough_decoder -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 diff --git a/tools/testing/cxl/test/mock.c b/tools/testing/cxl/test/mock.c index af2594e4f35d..f3d97652b9ee 100644 --- a/tools/testing/cxl/test/mock.c +++ b/tools/testing/cxl/test/mock.c @@ -13,9 +13,21 @@ static LIST_HEAD(mock); +static struct cxl_hdm * +redirect_devm_cxl_setup_hdm(struct cxl_port *port, + struct cxl_endpoint_dvsec_info *info); +static int +redirect_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, + struct cxl_endpoint_dvsec_info *info); +static int redirect_devm_cxl_add_passthrough_decoder(struct cxl_port *port); + void register_cxl_mock_ops(struct cxl_mock_ops *ops) { list_add_rcu(&ops->list, &mock); + _devm_cxl_setup_hdm = redirect_devm_cxl_setup_hdm; + _devm_cxl_enumerate_decoders = redirect_devm_cxl_enumerate_decoders; + _devm_cxl_add_passthrough_decoder = + redirect_devm_cxl_add_passthrough_decoder; } EXPORT_SYMBOL_GPL(register_cxl_mock_ops); @@ -23,6 +35,9 @@ DEFINE_STATIC_SRCU(cxl_mock_srcu); void unregister_cxl_mock_ops(struct cxl_mock_ops *ops) { + _devm_cxl_setup_hdm = __devm_cxl_setup_hdm; + _devm_cxl_enumerate_decoders = __devm_cxl_enumerate_decoders; + _devm_cxl_add_passthrough_decoder = __devm_cxl_add_passthrough_decoder; list_del_rcu(&ops->list); synchronize_srcu(&cxl_mock_srcu); } @@ -131,8 +146,8 @@ __wrap_nvdimm_bus_register(struct device *dev, } EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register); -struct cxl_hdm *__wrap_devm_cxl_setup_hdm(struct cxl_port *port, - struct cxl_endpoint_dvsec_info *info) +struct cxl_hdm *redirect_devm_cxl_setup_hdm(struct cxl_port *port, + struct cxl_endpoint_dvsec_info *info) { int index; @@ -142,14 +157,13 @@ struct cxl_hdm *__wrap_devm_cxl_setup_hdm(struct cxl_port *port, 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); + cxlhdm = __devm_cxl_setup_hdm(port, info); put_cxl_mock_ops(index); return cxlhdm; } -EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_setup_hdm, "CXL"); -int __wrap_devm_cxl_add_passthrough_decoder(struct cxl_port *port) +int redirect_devm_cxl_add_passthrough_decoder(struct cxl_port *port) { int rc, index; struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); @@ -157,15 +171,14 @@ int __wrap_devm_cxl_add_passthrough_decoder(struct cxl_port *port) 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); + rc = __devm_cxl_add_passthrough_decoder(port); put_cxl_mock_ops(index); return rc; } -EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_passthrough_decoder, "CXL"); -int __wrap_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, - struct cxl_endpoint_dvsec_info *info) +int redirect_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, + struct cxl_endpoint_dvsec_info *info) { int rc, index; struct cxl_port *port = cxlhdm->port; @@ -174,12 +187,11 @@ int __wrap_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm, 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); + rc = __devm_cxl_enumerate_decoders(cxlhdm, info); put_cxl_mock_ops(index); return rc; } -EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_enumerate_decoders, "CXL"); int __wrap_devm_cxl_port_enumerate_dports(struct cxl_port *port) {