From: Srirangan Madhavan <smadhavan@nvidia.com>
To: Alison Schofield <alison.schofield@intel.com>,
Bjorn Helgaas <bhelgaas@google.com>,
Dave Jiang <dave.jiang@intel.com>,
Davidlohr Bueso <dave@stgolabs.net>,
Ira Weiny <ira.weiny@intel.com>,
Jonathan Cameron <jic23@kernel.org>,
Vishal Verma <vishal.l.verma@intel.com>,
linux-cxl@vger.kernel.org, linux-pci@vger.kernel.org,
linux-kernel@vger.kernel.org
Cc: Alex Williamson <alex.williamson@redhat.com>,
vsethi@nvidia.com, alwilliamson@nvidia.com,
Sai Yashwanth Reddy Kancherla <skancherla@nvidia.com>,
Vishal Aslot <vaslot@nvidia.com>,
Manish Honap <mhonap@nvidia.com>, Jiandi An <jan@nvidia.com>,
Richard Cheng <icheng@nvidia.com>,
linux-tegra@vger.kernel.org,
Srirangan Madhavan <smadhavan@nvidia.com>
Subject: [PATCH v13 05/15] cxl: Introduce reusable HDM decoder settings
Date: Tue, 22 Sep 2026 08:39:14 +0000 [thread overview]
Message-ID: <20260922083924.2451158-6-smadhavan@nvidia.com> (raw)
In-Reply-To: <20260922083924.2451158-1-smadhavan@nvidia.com>
Represent HDM programming state with struct cxl_decoder_settings and pass
it to the commit helpers. Keep endpoint skip and switch targets at their
call sites, place flags with the programming state, and leave runtime
region ownership outside the snapshot.
Separate commit initiation from completion waiting so reset restoration
can reuse register programming without changing normal DPA-lock policy.
Signed-off-by: Srirangan Madhavan <smadhavan@nvidia.com>
---
drivers/cxl/core/core.h | 5 ++-
drivers/cxl/core/hdm.c | 40 +++++++++++++++++++---
drivers/cxl/core/resource.c | 67 ++++++++++++++++++-------------------
include/cxl/cxl.h | 27 +++++++++++----
4 files changed, 90 insertions(+), 49 deletions(-)
diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 9c6d4b99f787..3444479cbade 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -139,9 +139,8 @@ struct cxl_rwsem {
extern struct cxl_rwsem cxl_rwsem;
-int cxld_await_commit(void __iomem *hdm, int id);
-void cxlsd_set_targets(struct cxl_switch_decoder *cxlsd, u64 *tgt);
-void setup_hw_decoder(struct cxl_decoder *cxld, void __iomem *hdm);
+void cxl_commit_start(void __iomem *hdm, struct cxl_decoder_settings *settings);
+int cxl_commit_wait(void __iomem *hdm, struct cxl_decoder_settings *settings);
int cxl_memdev_init(void);
void cxl_memdev_exit(void);
diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index 008f04f0ca25..b3ddc02df65e 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -702,7 +702,7 @@ int cxl_dpa_alloc(struct cxl_endpoint_decoder *cxled, u64 size)
return devm_add_action_or_reset(&port->dev, cxl_dpa_release, cxled);
}
-void cxlsd_set_targets(struct cxl_switch_decoder *cxlsd, u64 *tgt)
+static void cxlsd_set_targets(struct cxl_switch_decoder *cxlsd, u64 *tgt)
{
struct cxl_dport **t = &cxlsd->target[0];
int ways = cxlsd->cxld.interleave_ways;
@@ -724,11 +724,41 @@ void cxlsd_set_targets(struct cxl_switch_decoder *cxlsd, u64 *tgt)
*tgt |= FIELD_PREP(GENMASK_ULL(63, 56), t[7]->port_id);
}
+/*
+ * Endpoint skip and switch targets have different owners. Keep that state with
+ * its owning type and flatten it only into a transient register-programming
+ * snapshot.
+ */
+static void cxl_decoder_snapshot(struct cxl_decoder *cxld,
+ struct cxl_decoder_settings *settings)
+{
+ lockdep_assert_held(&cxl_rwsem.dpa);
+
+ *settings = (struct cxl_decoder_settings) {
+ .config = cxld->config,
+ };
+
+ if (is_switch_decoder(&cxld->dev)) {
+ struct cxl_switch_decoder *cxlsd =
+ to_cxl_switch_decoder(&cxld->dev);
+ u64 targets;
+
+ cxlsd_set_targets(cxlsd, &targets);
+ settings->target_or_skip_reg_val = targets;
+ } else {
+ struct cxl_endpoint_decoder *cxled =
+ to_cxl_endpoint_decoder(&cxld->dev);
+
+ settings->target_or_skip_reg_val = cxled->skip;
+ }
+}
+
static int cxl_decoder_commit(struct cxl_decoder *cxld)
{
struct cxl_port *port = to_cxl_port(cxld->dev.parent);
struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
void __iomem *hdm = cxlhdm->regs.hdm_decoder;
+ struct cxl_decoder_settings settings;
int id = cxld->id, rc;
if (cxld->flags & CXL_DECODER_F_ENABLE)
@@ -761,10 +791,12 @@ static int cxl_decoder_commit(struct cxl_decoder *cxld)
}
}
- scoped_guard(rwsem_read, &cxl_rwsem.dpa)
- setup_hw_decoder(cxld, hdm);
+ scoped_guard(rwsem_read, &cxl_rwsem.dpa) {
+ cxl_decoder_snapshot(cxld, &settings);
+ cxl_commit_start(hdm, &settings);
+ }
- rc = cxld_await_commit(hdm, cxld->id);
+ rc = cxl_commit_wait(hdm, &settings);
if (rc) {
dev_dbg(&port->dev, "%s: error %d committing decoder\n",
dev_name(&cxld->dev), rc);
diff --git a/drivers/cxl/core/resource.c b/drivers/cxl/core/resource.c
index 68d40f745acc..ea0d855e5549 100644
--- a/drivers/cxl/core/resource.c
+++ b/drivers/cxl/core/resource.c
@@ -13,7 +13,7 @@ struct cxl_rwsem cxl_rwsem = {
.dpa = __RWSEM_INITIALIZER(cxl_rwsem.dpa),
};
-static void cxld_set_interleave(struct cxl_decoder *cxld, u32 *ctrl)
+static void cxld_set_interleave(struct cxl_decoder_config *config, u32 *ctrl)
{
u16 eig;
u8 eiw;
@@ -22,12 +22,12 @@ static void cxld_set_interleave(struct cxl_decoder *cxld, u32 *ctrl)
* Input validation ensures these warns never fire, but otherwise
* suppress unititalized variable usage warnings.
*/
- if (WARN_ONCE(ways_to_eiw(cxld->interleave_ways, &eiw),
- "invalid interleave_ways: %d\n", cxld->interleave_ways))
+ if (WARN_ONCE(ways_to_eiw(config->interleave_ways, &eiw),
+ "invalid interleave_ways: %d\n", config->interleave_ways))
return;
- if (WARN_ONCE(granularity_to_eig(cxld->interleave_granularity, &eig),
+ if (WARN_ONCE(granularity_to_eig(config->interleave_granularity, &eig),
"invalid interleave_granularity: %d\n",
- cxld->interleave_granularity))
+ config->interleave_granularity))
return;
u32p_replace_bits(ctrl, eig, CXL_HDM_DECODER0_CTRL_IG_MASK);
@@ -35,10 +35,10 @@ static void cxld_set_interleave(struct cxl_decoder *cxld, u32 *ctrl)
*ctrl |= CXL_HDM_DECODER0_CTRL_COMMIT;
}
-static void cxld_set_type(struct cxl_decoder *cxld, u32 *ctrl)
+static void cxld_set_type(struct cxl_decoder_config *config, u32 *ctrl)
{
u32p_replace_bits(ctrl,
- !!(cxld->target_type == CXL_DECODER_HOSTONLYMEM),
+ !!(config->target_type == CXL_DECODER_HOSTONLYMEM),
CXL_HDM_DECODER0_CTRL_HOSTONLY);
}
@@ -48,7 +48,7 @@ static void cxld_set_type(struct cxl_decoder *cxld, u32 *ctrl)
* clock skew and other marginal behavior
*/
#define COMMIT_TIMEOUT_MS 20
-int cxld_await_commit(void __iomem *hdm, int id)
+static int cxld_await_commit(void __iomem *hdm, int id)
{
u32 ctrl;
int i;
@@ -68,43 +68,40 @@ int cxld_await_commit(void __iomem *hdm, int id)
return -ETIMEDOUT;
}
-void setup_hw_decoder(struct cxl_decoder *cxld, void __iomem *hdm)
+static void setup_hw_decoder(void __iomem *hdm,
+ struct cxl_decoder_settings *settings)
{
- int id = cxld->id;
+ struct cxl_decoder_config *config = &settings->config;
+ int id = config->id;
+ u64 target_or_skip_reg_val;
u64 base, size;
u32 ctrl;
- /* common decoder settings */
- ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(cxld->id));
- cxld_set_interleave(cxld, &ctrl);
- cxld_set_type(cxld, &ctrl);
- base = cxld->hpa_range.start;
- size = range_len(&cxld->hpa_range);
+ ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
+ cxld_set_interleave(config, &ctrl);
+ cxld_set_type(config, &ctrl);
+ base = config->hpa_range.start;
+ size = range_len(&config->hpa_range);
+ target_or_skip_reg_val = settings->target_or_skip_reg_val;
writel(upper_32_bits(base), hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(id));
writel(lower_32_bits(base), hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(id));
writel(upper_32_bits(size), hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(id));
writel(lower_32_bits(size), hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(id));
+ /* Target-list and endpoint-skip registers alias the same slot. */
+ writel(upper_32_bits(target_or_skip_reg_val), hdm + CXL_HDM_DECODER0_TL_HIGH(id));
+ writel(lower_32_bits(target_or_skip_reg_val), hdm + CXL_HDM_DECODER0_TL_LOW(id));
- if (is_switch_decoder(&cxld->dev)) {
- struct cxl_switch_decoder *cxlsd =
- to_cxl_switch_decoder(&cxld->dev);
- void __iomem *tl_hi = hdm + CXL_HDM_DECODER0_TL_HIGH(id);
- void __iomem *tl_lo = hdm + CXL_HDM_DECODER0_TL_LOW(id);
- u64 targets;
-
- cxlsd_set_targets(cxlsd, &targets);
- writel(upper_32_bits(targets), tl_hi);
- writel(lower_32_bits(targets), tl_lo);
- } else {
- struct cxl_endpoint_decoder *cxled =
- to_cxl_endpoint_decoder(&cxld->dev);
- void __iomem *sk_hi = hdm + CXL_HDM_DECODER0_SKIP_HIGH(id);
- void __iomem *sk_lo = hdm + CXL_HDM_DECODER0_SKIP_LOW(id);
+ writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
+}
- writel(upper_32_bits(cxled->skip), sk_hi);
- writel(lower_32_bits(cxled->skip), sk_lo);
- }
+void cxl_commit_start(void __iomem *hdm, struct cxl_decoder_settings *settings)
+{
+ lockdep_assert_held(&cxl_rwsem.dpa);
+ setup_hw_decoder(hdm, settings);
+}
- writel(ctrl, hdm + CXL_HDM_DECODER0_CTRL_OFFSET(id));
+int cxl_commit_wait(void __iomem *hdm, struct cxl_decoder_settings *settings)
+{
+ return cxld_await_commit(hdm, settings->config.id);
}
diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
index 69941f7fdb76..1acdf537e4e9 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -42,8 +42,8 @@ enum cxl_decoder_type {
* @interleave_ways: number of cxl_dports in this decode
* @interleave_granularity: data stride per dport
* @target_type: accelerator vs expander (type2 vs type3) selector
- * @region: currently assigned region for this decoder
* @flags: memory type capabilities and locking
+ * @region: currently assigned region for this decoder
* @target_map: cached copy of hardware port-id list, available at init
* before all @dport objects have been instantiated. While
* dport id is 8bit, CFMWS interleave targets are 32bits.
@@ -52,18 +52,31 @@ enum cxl_decoder_type {
*/
struct cxl_decoder {
struct device dev;
- int id;
- struct range hpa_range;
- int interleave_ways;
- int interleave_granularity;
- enum cxl_decoder_type target_type;
+
+ struct_group_tagged(cxl_decoder_config, config,
+ int id;
+ struct range hpa_range;
+ int interleave_ways;
+ int interleave_granularity;
+ enum cxl_decoder_type target_type;
+ unsigned long flags;
+ );
struct cxl_region *region;
- unsigned long flags;
u32 target_map[CXL_DECODER_MAX_INTERLEAVE];
int (*commit)(struct cxl_decoder *cxld);
void (*reset)(struct cxl_decoder *cxld);
};
+/**
+ * struct cxl_decoder_settings - CXL HDM decoder programming snapshot
+ * @config: common decoder configuration
+ * @target_or_skip_reg_val: switch target list or endpoint skip register value
+ */
+struct cxl_decoder_settings {
+ struct cxl_decoder_config config;
+ u64 target_or_skip_reg_val;
+};
+
/*
* Using struct_group() allows for per register-block-type helper routines,
* without requiring block-type agnostic code to include the prefix.
--
2.43.0
next prev parent reply other threads:[~2026-09-22 8:39 UTC|newest]
Thread overview: 56+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-22 8:39 [PATCH v13 00/15] PCI/CXL: Add CXL reset support for Type 2 devices Srirangan Madhavan
2026-09-22 8:39 ` [PATCH v13 01/15] cxl: Drop stale decoder interleave limit comment Srirangan Madhavan
2026-09-24 1:16 ` Jonathan Cameron
2026-09-24 16:23 ` Dave Jiang
2026-09-22 8:39 ` [PATCH v13 02/15] cxl: Share CXL port upstream PCI device lookup Srirangan Madhavan
2026-09-23 21:39 ` Cheatham, Benjamin
2026-09-24 1:21 ` Jonathan Cameron
2026-09-24 16:55 ` Dave Jiang
2026-10-01 22:33 ` Srirangan Madhavan
2026-09-24 1:22 ` Jonathan Cameron
2026-10-01 22:28 ` Srirangan Madhavan
2026-09-24 17:01 ` Dave Jiang
2026-09-22 8:39 ` [PATCH v13 03/15] cxl: Move HDM decoder programming helpers Srirangan Madhavan
2026-09-24 1:29 ` Jonathan Cameron
2026-10-01 23:40 ` Srirangan Madhavan
2026-09-24 17:02 ` Dave Jiang
2026-09-22 8:39 ` [PATCH v13 04/15] cxl: Move decoder declarations to shared header Srirangan Madhavan
2026-09-24 1:31 ` Jonathan Cameron
2026-09-24 17:03 ` Dave Jiang
2026-09-22 8:39 ` Srirangan Madhavan [this message]
2026-09-23 21:39 ` [PATCH v13 05/15] cxl: Introduce reusable HDM decoder settings Cheatham, Benjamin
2026-09-24 1:35 ` Jonathan Cameron
2026-10-01 22:43 ` Srirangan Madhavan
2026-09-24 2:45 ` Jonathan Cameron
2026-10-01 23:42 ` Srirangan Madhavan
2026-09-22 8:39 ` [PATCH v13 06/15] cxl: Make HDM reset helpers available to built-in PCI code Srirangan Madhavan
2026-09-23 21:40 ` Cheatham, Benjamin
2026-09-24 2:49 ` Jonathan Cameron
2026-10-01 22:46 ` Srirangan Madhavan
2026-09-22 8:39 ` [PATCH v13 07/15] cxl: Share HDM decoder register unpacking Srirangan Madhavan
2026-09-24 3:05 ` Jonathan Cameron
2026-10-01 23:52 ` Srirangan Madhavan
2026-09-22 8:39 ` [PATCH v13 08/15] cxl: Refresh cached PCI HDM decoder settings Srirangan Madhavan
2026-09-23 21:40 ` Cheatham, Benjamin
2026-10-01 22:58 ` Srirangan Madhavan
2026-09-24 3:08 ` Jonathan Cameron
2026-09-22 8:39 ` [PATCH v13 09/15] cxl: Cache endpoint HDM state during PCI enumeration Srirangan Madhavan
2026-09-23 21:40 ` Cheatham, Benjamin
2026-10-01 23:14 ` Srirangan Madhavan
2026-09-24 3:36 ` Jonathan Cameron
2026-10-01 23:55 ` Srirangan Madhavan
2026-09-22 8:39 ` [PATCH v13 10/15] cxl: Add CXL Device Reset sequencing Srirangan Madhavan
2026-09-23 21:40 ` Cheatham, Benjamin
2026-09-24 17:29 ` Dave Jiang
2026-10-01 23:36 ` Srirangan Madhavan
2026-09-22 8:39 ` [PATCH v13 11/15] cxl: Validate and synchronize HDM ranges around reset Srirangan Madhavan
2026-09-23 21:40 ` Cheatham, Benjamin
2026-10-01 23:25 ` Srirangan Madhavan
2026-09-22 8:39 ` [PATCH v13 12/15] PCI/CXL: Reject reset with unsafe function scope Srirangan Madhavan
2026-09-23 21:41 ` Cheatham, Benjamin
2026-09-24 17:33 ` Dave Jiang
2026-09-22 8:39 ` [PATCH v13 13/15] cxl: Restore CXL state after PCI reset Srirangan Madhavan
2026-09-24 3:50 ` Jonathan Cameron
2026-10-01 23:58 ` Srirangan Madhavan
2026-09-22 8:39 ` [PATCH v13 14/15] PCI/CXL: Expose CXL Reset as a PCI reset method Srirangan Madhavan
2026-09-22 8:39 ` [PATCH v13 15/15] PCI/CXL: Restore CXL state after CXL bus reset Srirangan Madhavan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260922083924.2451158-6-smadhavan@nvidia.com \
--to=smadhavan@nvidia.com \
--cc=alex.williamson@redhat.com \
--cc=alison.schofield@intel.com \
--cc=alwilliamson@nvidia.com \
--cc=bhelgaas@google.com \
--cc=dave.jiang@intel.com \
--cc=dave@stgolabs.net \
--cc=icheng@nvidia.com \
--cc=ira.weiny@intel.com \
--cc=jan@nvidia.com \
--cc=jic23@kernel.org \
--cc=linux-cxl@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-tegra@vger.kernel.org \
--cc=mhonap@nvidia.com \
--cc=skancherla@nvidia.com \
--cc=vaslot@nvidia.com \
--cc=vishal.l.verma@intel.com \
--cc=vsethi@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®