From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from buffalo.tulip.relay.mailchannels.net (buffalo.tulip.relay.mailchannels.net [23.83.218.24]) (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 BC9723D646B for ; Mon, 27 Jul 2026 19:36:17 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=23.83.218.24 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785180984; cv=none; b=ciXUCeiBz5rAf6B2yfVZEow4gWJrwhw4O0mHAnqT0gtH/Ru/Mxfdjq2h1bBEEK68jCvW/KijGIBVWjcg4aSa7NjzRpnM3FNGKM02KKayx/QjofAJ/xrUNHK5mX9RrJ9aNcqi6F6F3wbrWQGflodsA7/Uw94lZ12rapvFity0Yzg= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785180984; c=relaxed/simple; bh=MvRMIq0qQ2aAZdVTzBNJDfHfGh+pB0CFhy4Ir9ZQ3Tw=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=VX8pKSRgiGFwliKYm/SqTCdfCrdxhuxb53oZ+ReTTJa9U74KRuUsOwFaNvlIH5e/77iON9Jy7egbkK0KckmbH3ip4tMzztk4CF//5wJUl+WYVx/rfzOG6AHatAQIL3YfTEmvz+BFxM9IT8Yjj4DeFpYdUiVeOitkOuXAp1Ovzjw= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=stgolabs.net; spf=fail smtp.mailfrom=stgolabs.net; dkim=pass (2048-bit key) header.d=stgolabs.net header.i=@stgolabs.net header.b=IrzI97Pe; arc=none smtp.client-ip=23.83.218.24 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=stgolabs.net Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=stgolabs.net Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=stgolabs.net header.i=@stgolabs.net header.b="IrzI97Pe" X-Sender-Id: dreamhost|x-authsender|dave@stgolabs.net Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id EEF87163416; Mon, 27 Jul 2026 19:36:09 +0000 (UTC) Received: from pdx1-sub0-mail-a227.dreamhost.com (100-104-243-140.trex-nlb.outbound.svc.cluster.local [100.104.243.140]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id BB0A1161BCA; Mon, 27 Jul 2026 19:36:09 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|dave@stgolabs.net X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|dave@stgolabs.net X-MailChannels-Auth-Id: dreamhost X-Unite-Irritate: 5996fe4f5b756d8e_1785180969888_4019830505 X-MC-Loop-Signature: 1785180969888:468092569 X-MC-Ingress-Time: 1785180969887 Received: from pdx1-sub0-mail-a227.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.104.243.140 (trex/8.0.2); Mon, 27 Jul 2026 19:36:09 +0000 Received: from offworld.lan (unknown [76.167.199.67]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: dave@stgolabs.net) by pdx1-sub0-mail-a227.dreamhost.com (Postfix) with ESMTPSA id 4h883F0BjJz2C; Mon, 27 Jul 2026 12:36:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=stgolabs.net; s=dreamhost; t=1785180969; bh=Mqc1+uh1hIPN09O9PoFJ1FT2YMnMZqunIKEIDUM09oM=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=IrzI97PemJgzIDQt9j7NWc0NiOgeGNko4fjhOA0O5Iqf5yxJX+7OkUtSk7YOQOze/ 3ocywlkwUiPGPsDP6ipQY7qaJyJWpB9j9mndZObnm0uGv6N3aqHYy0xHNGApu34pdN bhZ6y7zkoaQxwKGt3oRfTkmGOFYrpbNoDwqlzDg8cDfjxvnYo32Rl5KuhRi7evfoJB ZzsV4oAQ+LGg/J7r4tr8EZiG0AqXwY4YEchCq17iLYkOsPJomZ40qT89LpA6DvlTiR sZZWs43VauNIpvwZPD/9gk+Js3W0PbbIEyP74nr+Kx/rxYA+/glUqgqc/MSv33d75b dq/SDeIMuiFXA== From: Davidlohr Bueso To: dave.jiang@intel.com Cc: jic23@kernel.org, alison.schofield@intel.com, icheng@nvidia.com, benjamin.cheatham@amd.com, alucerop@amd.com, dongjoo.seo1@samsung.com, dave@stgolabs.net, linux-kernel@vger.kernel.org Subject: [PATCH v6 7/9] cxl: Move BI setup to endpoint port probe Date: Mon, 27 Jul 2026 12:35:59 -0700 Message-Id: <20260727193601.651871-8-dave@stgolabs.net> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260727193601.651871-1-dave@stgolabs.net> References: <20260727193601.651871-1-dave@stgolabs.net> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Move cxl_bi_setup (BI-ID allocation) from cxl_mem_probe() into cxl_endpoint_port_probe(): the BI-ID and path enablement belong to the endpoint port's lifetime, not the memdev driver's. The dealloc devm action moves to the endpoint port accordingly. Setup is safe in endpoint port probe context: the port probes synchronously from cxl_mem_probe(), pinning the memdev state the walk consumes, and the whole ancestor path already exists with BI registers mapped (dports at dport-add time, the switch USP RT at first-dport setup) because devm_cxl_enumerate_ports() completes before the endpoint is created. Dealloc is safe in endpoint devres context: both setup and dealloc walk the endpoint's parent_dport topology rather than getting the port by bus lookup - an ancestor teardown delists the parent port before the endpoint's devres runs. The topology walk is stable as parent_dport pointers are fixed at port creation; ancestors cannot be reaped while holding this memdev's cxl_ep; and their own teardown frees dports only after the endpoint is gone. The device state holds up as well: cxlmd->cxlds is nulled only after cxl_memdev_unregister() has torn the endpoint down, and delete_endpoint() clears cxlmd->endpoint only after the endpoint devres has run. With dealloc in the endpoint's devres, delete_endpoint() already holds the parent port's device lock, so to avoid deadlocking, add a per-port bi_lock, serializing only dports that share state (ie: sibling nr_bi on a root port, the switch USP's BI RT). Signed-off-by: Davidlohr Bueso --- drivers/cxl/core/pci.c | 57 +++++++++++++++++++---------------------- drivers/cxl/core/port.c | 1 + drivers/cxl/cxl.h | 4 ++- drivers/cxl/mem.c | 4 --- drivers/cxl/port.c | 4 +++ 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index 12cb50640f65..a87c2ad9ac53 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -1092,7 +1092,7 @@ static int __cxl_bi_ctrl_dport(struct cxl_dport *dport, bool enable) u32 ctrl, value; int rc; - guard(device)(&port->dev); + guard(mutex)(&port->bi_lock); if (!bi) return -EINVAL; @@ -1211,29 +1211,31 @@ static int cxl_bi_ctrl_endpoint_disable(struct cxl_dev_state *cxlds) } /* - * devm teardown on cxl_mem unbind. Endpoint decoders may still be - * committed here (cxl_workqueue tears them down asynchronously), but - * memory access has been quiesced. + * devm teardown on endpoint port destruction. Endpoint decoders may + * still be committed here (cxl_workqueue tears them down + * asynchronously), but memory access has been quiesced. */ static void cxl_bi_dealloc(void *data) { - struct cxl_dev_state *cxlds = data; - struct cxl_dport *dport_iter, *dport; + struct cxl_port *endpoint = data; + struct cxl_memdev *cxlmd = to_cxl_memdev(endpoint->uport_dev); + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_dport *dport_iter; struct cxl_port *port_iter; - if (!dev_is_pci(cxlds->dev)) - return; - - struct cxl_port *port __free(put_cxl_port) = - cxl_pci_find_port(to_pci_dev(cxlds->dev), &dport); - if (!port || !cxlds->bi) + if (!cxlds->bi) return; scoped_guard(rwsem_read, &cxl_rwsem.region) cxl_bi_ctrl_endpoint_disable(cxlds); - port_iter = port; - dport_iter = dport; + /* + * Walk the same parent_dport chain that enabled the path. A bus + * lookup cannot stand in for it: an ancestor-driven teardown + * delists the parent port before this devres action runs. + */ + dport_iter = endpoint->parent_dport; + port_iter = dport_iter->port; while (!is_cxl_root(port_iter)) { int rc = cxl_bi_ctrl_dport_disable(dport_iter); @@ -1288,12 +1290,13 @@ static int cxl_bi_enable_path(struct cxl_dev_state *cxlds, return rc; } -int cxl_bi_setup(struct cxl_dev_state *cxlds) +int cxl_bi_setup(struct cxl_port *endpoint) { - struct cxl_port *endpoint = cxlds->cxlmd->endpoint; - struct cxl_dport *dport_iter, *dport; + struct cxl_memdev *cxlmd = to_cxl_memdev(endpoint->uport_dev); + struct cxl_dev_state *cxlds = cxlmd->cxlds; + struct cxl_dport *dport = endpoint->parent_dport; + struct cxl_dport *dport_iter; struct cxl_port *port_iter; - struct pci_dev *pdev; int rc; if (!dev_is_pci(cxlds->dev)) @@ -1303,18 +1306,12 @@ int cxl_bi_setup(struct cxl_dev_state *cxlds) if (cxlds->rcd) return 0; - pdev = to_pci_dev(cxlds->dev); - struct cxl_port *port __free(put_cxl_port) = - cxl_pci_find_port(pdev, &dport); - - if (!port) - return -EINVAL; - - if (!cxl_is_bi_capable(pdev, endpoint->regs.bi_decoder)) + if (!cxl_is_bi_capable(to_pci_dev(cxlds->dev), + endpoint->regs.bi_decoder)) return 0; /* walkup the topology twice, first to check, then to enable */ - port_iter = port; + port_iter = dport->port; dport_iter = dport; while (!is_cxl_root(port_iter)) { /* check rp, dsp */ @@ -1338,11 +1335,11 @@ int cxl_bi_setup(struct cxl_dev_state *cxlds) port_iter = dport_iter->port; } - rc = cxl_bi_enable_path(cxlds, port, dport); + rc = cxl_bi_enable_path(cxlds, dport->port, dport); if (rc) return rc; - return devm_add_action_or_reset(&cxlds->cxlmd->dev, - cxl_bi_dealloc, cxlds); + return devm_add_action_or_reset(&endpoint->dev, cxl_bi_dealloc, + endpoint); } EXPORT_SYMBOL_NS_GPL(cxl_bi_setup, "CXL"); diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 4fce2188cd8c..57882f4c2d8e 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -772,6 +772,7 @@ static struct cxl_port *cxl_port_alloc(struct device *uport_dev, xa_init(&port->dports); xa_init(&port->endpoints); xa_init(&port->regions); + mutex_init(&port->bi_lock); port->component_reg_phys = CXL_RESOURCE_NONE; device_initialize(dev); diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h index 5f4a11538bbf..ca7051641c47 100644 --- a/drivers/cxl/cxl.h +++ b/drivers/cxl/cxl.h @@ -594,6 +594,7 @@ struct cxl_dax_region { * @decoder_ida: allocator for decoder ids * @reg_map: component and ras register mapping parameters * @regs: mapped component registers + * @bi_lock: serializes BI Decoder/RT state of this port's dports * @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 @@ -616,6 +617,7 @@ struct cxl_port { struct ida decoder_ida; struct cxl_register_map reg_map; struct cxl_component_regs regs; + struct mutex bi_lock; int nr_dports; int hdm_end; int commit_end; @@ -961,7 +963,7 @@ void cxl_coordinates_combine(struct access_coordinate *out, struct access_coordinate *c2); bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port); -int cxl_bi_setup(struct cxl_dev_state *cxlds); +int cxl_bi_setup(struct cxl_port *endpoint); struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port, struct device *dport_dev); diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c index ab28c20d7897..798e5c369cfc 100644 --- a/drivers/cxl/mem.c +++ b/drivers/cxl/mem.c @@ -175,10 +175,6 @@ static int cxl_mem_probe(struct device *dev) if (rc) dev_dbg(dev, "CXL memdev EDAC registration failed rc=%d\n", rc); - rc = cxl_bi_setup(cxlds); - if (rc) - dev_dbg(dev, "BI setup failed rc=%d\n", rc); - /* * The kernel may be operating out of CXL memory on this device, * there is no spec defined way to determine whether this device diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c index a527dd13fb68..22bd4254ba8d 100644 --- a/drivers/cxl/port.c +++ b/drivers/cxl/port.c @@ -180,6 +180,10 @@ static int cxl_endpoint_port_probe(struct cxl_port *port) if (rc) return rc; + rc = cxl_bi_setup(port); + if (rc) + dev_dbg(&port->dev, "BI setup failed rc=%d\n", rc); + /* * With VH (CXL Virtual Host) topology the cxl_port::add_dport() method * handles RAS setup for downstream ports. With RCH (CXL Restricted CXL -- 2.39.5