linux-cxl.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RESEND PATCH v13 0/8] DCD Prep Series
@ 2026-09-08 10:15 Anisa Su
  2026-09-08 10:15 ` [RESEND PATCH v13 1/8] cxl/mbox: Flag support for Dynamic Capacity Devices (DCD) Anisa Su
                   ` (7 more replies)
  0 siblings, 8 replies; 33+ messages in thread
From: Anisa Su @ 2026-09-08 10:15 UTC (permalink / raw)
  To: linux-cxl
  Cc: alison.schofield, jic23, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Anisa Su

First send only sent cover letter :( Resend with patches.

These are the first eight patches of the Dynamic Capacity Device (DCD)
series. They set up: DCD enumeration, CDAT handling for DC partitions,
the event interrupt plumbing, a preparatory refactor, and
documentation of the DPA partition layout. They stand alone and keep DCD
disabled. They are not dependent on the rest of the series.

Patch 1 detects the 48h command set and then leaves mds->dcd_supported
false. The flag is only turned on by the series that adds DCD event
handling, so every DCD specific path added here is shut off at runtime:
cxl_configure_dcd() never runs, no DC partition is created, no DCD
interrupt is armed, and the CXL_PARTMODE_DYNAMIC_RAM_1 paths are
unreachable. The intent is to land the enumeration and plumbing while
the extent to DAX pipeline is still under review.

Based on v7.3-rc2

GitHub Branch:
https://github.com/anisa-su993/anisa-linux-kernel/tree/dcd-prep-v13

v12: https://lore.kernel.org/linux-cxl/20260731084901.1512819-1-anisa.su@samsung.com/

v12 -> v13 Changes:
===================
 - Dropped: cxl/core: Return endpoint decoder information from region
        search (v12 patch 7). The new interface is not paired with its
        first caller in this series -- all three call sites pass NULL --
        so its contract cannot be reviewed here. It will be posted with
        its first user instead (Alison). v12 patch 8 is now patch 7.

 - Added: Documentation/cxl: Document DPA partition layout and ordering
        rules (patch 8) in-tree in addition to the commit messages in order
        to be explicit about places Linux is stricter than the specification.
        Add a section to cxl-driver.rst separating what the spec mandates
        for ram and pmem from what Linux chooses for dynamic capacity.
        It is documentation only.

   The series is eight patches, one dropped and one added.

 - Patch 1: cxl/mbox: Flag support for Dynamic Capacity Devices (DCD)
        - Commit message explains why mds->dcd_supported is left false
          and what turns it back on (Dave).
        - Drop the single use cxl_verify_dcd_cmds() helper and test
          bitmap_full(dcd_cmds, CXL_DCD_ENABLED_MAX) directly (Alison).

 - Patch 2: cxl/mem: Read dynamic capacity configuration from the device
        - Validate only DC partition 0. Every partition the device
          reports is still read, so the framework stays the same if we
          decide to add support for additional partitions.
          But no validation is done for the other partitions,
          so a defect in other partitions that we don't use no
          longer prevents the driver from configuring dynamic capacity
          (Richard / Alison).
        - Rework the cxl_dc_check() validation: checks now run in
          dependency order, block size first, and each failure names the
          field that is wrong instead of four conditions sharing one
          "invalid length" message (Alison).
        - Drop the block size alignment requirement on the region base.
          Table 8-347 requires 256M for the base and states the block
          size alignment for extent start DPAs, not for the base, so
          Linux was enforcing a constraint the spec does not state
          (Alison).
        - Range check the device's available partition count against the
          1 to 8 of Table 8-346, before it is used as the read loop
          bound (Alison).
        - Split cxl_configure_dcd()'s base check: an error for a DC
          partition overlapping static capacity, a warning for a gap
          above it, both printing the addresses. The old message said
          "pmem" when the comparison is against total static capacity
          (Alison).
        - cxl_configure_dcd() returns an error instead of void;
          cxl_pci_probe() disables DCD and carries on rather than failing
          the memdev (Jonathan).
        - Check the block size is a power of 2 in 64 bits.
          is_power_of_2() takes an unsigned long, so a 32 bit build
          truncated blk_size and accepted values such as 0x100000040
          (Sashiko).

 - Patch 3: cxl/cdat: Gather DSMAS data for DCD partitions
        - Only assign shareable for the dynamic ram 1 partition. It was
          set for every partition the DSMAS range fell into, while the
          handle check beside it is DC only (Alison).
        - Reduce nesting in cxl_memdev_set_qos_class(): invert
          range_contains() to continue early, and use a 'part' local
          instead of repeating cxlds->part[i] (Alison). Doing this first
          is what made the reworded warning fit in 100 columns.

 - Patch 4: cxl/events: Split event msgnum configuration from irq setup
        - No change from v12.

 - Patch 5: cxl/pci: Factor out interrupt policy check
        - Rename cxl_event_validate_mem_policy() to
          cxl_event_fw_owns_mem_logs() and invert it. It never validated
          the policy, it reported whether firmware still owns the
          standard memory event logs despite _OSC granting the OS
          control, so the name now states that condition and true means
          firmware owns them (Alison).
        - Commit message: "validation" was the wrong word for what the
          helper does; it checks for firmware ownership of the memory
          event logs (Alison).

 - Patch 6: cxl/mem: Configure dynamic capacity interrupts
        - Disable DCD when the device supports the DCD commands but its
          interrupt policy is too short to carry dcd_settings. The Set is
          sized by the device's own policy length, so on a short policy
          dcd_settings is never sent, and the re-read afterwards leaves
          the driver's own value in the struct because the device does
          not return that byte. cxl_irqsetup() would then arm the DCD
          interrupt from a setting the device never accepted. A
          conforming device cannot be in that state -- DCD is CXL 3.x and
          a 3.x policy carries the field -- but nothing tied the two
          facts together (Alison).
        - Move the DCD bit out of cxl_event_drain_mask(), dropping the
          mds argument it no longer needs, so the bit lands in the patch
          that adds the code draining that log. This patch still defines
          CXLDEV_EVENT_STATUS_DCD, adds it to CXLDEV_EVENT_STATUS_ALL and
          arms the DCD interrupt; only the drain bit moved (Alison).

 - Patch 7: cxl/core: Enforce partition order/simplify partition calls
        - Document the DPA partition layout above enum
          cxl_partition_mode in cxl.h with ascii art, and cite where the
          order comes from: ram before pmem is mandated by CXL r4.0
          Table 8-310, while Table 8-347 only requires the DC Region Base
          to be 256MB aligned, so a dynamic partition following pmem is a
          Linux choice that cxl_configure_dcd() enforces (Alison).
        - Commit message: say what the partition order is, where it comes
          from, and that this patch starts enforcing it. The previous
          text named an "implied partition order" without ever saying
          what it implied (Alison).
        - Name the partitions in the failure: "Partition order mismatch:
          %d (%s) follows %d (%s)" via cxl_mode_name(), rather than the
          bare "Partition order mismatch" (Alison).

Review status
=============
Patch 1
+ Reviewed-by from Dave Jiang and Gregory Price from v12.
Patch 1 did change in v13: dropped the single use
cxl_verify_dcd_cmds() helper so cxl_walk_cel() now tests
bitmap_full() directly. That is a no-op cleanup -- the helper was a
one-line wrapper around the same bitmap_full() call and had no other
caller -- so carried both tags over rather than dropping them.
Dave, Gregory, please lmk if you would rather re-review.

Patch 2 had the most changes from v12, is the patch that most needs eyes.

Patch 3:
Minor changes. Dropped Dave's tag.

Patch 4 is unchanged from v12 and carries its existing tag.

Patches 5 and 7 did change, but quite trivially, so kept
the tags. Patch 5 renames cxl_event_validate_mem_policy() to
cxl_event_fw_owns_mem_logs(). Patch 7 picks up a
loop-local index, a reworded error message and a comment on enum
cxl_partition_mode.

Patch 8 (partition layout Documentation) is new in v13: no tags.

Patch organization
==================
 1-3: enumerate DCD command support, read the DC configuration, and pick
      up DSMAS data for DC partitions.
 4-6: split event msgnum configuration from irq setup, factor out the
      interrupt policy check, then configure the DCD event interrupt.
   7: preparatory refactor -- enforce partition order while collapsing
      the ram/pmem specific partition helpers into one.
   8: document the DPA partition layout the previous patches enforce,
      and where Linux is stricter than the specification.

Testing
=======
This series leaves mds->dcd_supported false on purpose, so cxl_configure_dcd(),
cxl_dev_dc_identify() and cxl_dc_check() are unreachable at
runtime as posted. The tests below are done with the rest of the series on top,
otherwise testing would not yield any meaningful results.

HW:
Tested add/release of a single extent to ensure interrupts are configured
and working and DSMAS attributes are read correctly.

Additional testing is done on QEMU to catch cases that would not occur
on the hardware because of configuration differences. Four topologies
are used, one guest boot each, with a DCD partition after static capacity.

1. Eight DC partitions, only the first validated
------------------------------------------------
2G ram + 512M pmem static, so static capacity ends at 0xa0000000, and
eight 512M DC partitions above it.  Five partition records fit in one
reply on the 256 byte mailbox, so the read continues from partition 5
in a second command.

  cxl_pci 0000:0d:00.0: Read 5/8 DC partitions
  cxl_pci 0000:0d:00.0: DC partition 0 start 0xa0000000 size 0x20000000 blk_size: 0x200000
  cxl_pci 0000:0d:00.0: Read 3/8 DC partitions
  cxl_pci 0000:0d:00.0: Adding dynamic ram partition 1; 0xa0000000 size 0x20000000
  cxl_pci 0000:0d:00.0: DPA(ram): [mem 0x00000000-0x7fffffff flags 0x200]
  cxl_pci 0000:0d:00.0: DPA(pmem): [mem 0x80000000-0x9fffffff flags 0x200]
  cxl_pci 0000:0d:00.0: DPA(dynamic_ram_1): [mem 0xa0000000-0xbfffffff flags 0x200]

All eight partitions are read, but only one "DC partition" line appears:
partition 0 is the only one validated.

2. Volatile-only static capacity
---------------------------------
2G ram, no pmem, one 512M DC partition. cxl_configure_dcd() compares
the DC base against the end of total static capacity, not the end of
pmem; a device with no persistent capacity is what tells those two
apart.

  cxl_pci 0000:0d:00.0: Read 1/1 DC partitions
  cxl_pci 0000:0d:00.0: DC partition 0 start 0x80000000 size 0x20000000 blk_size: 0x200000
  cxl_pci 0000:0d:00.0: Adding dynamic ram partition 1; 0x80000000 size 0x20000000
  cxl_pci 0000:0d:00.0: DPA(ram): [mem 0x00000000-0x7fffffff flags 0x200]
  cxl_pci 0000:0d:00.0: DPA(dynamic_ram_1): [mem 0x80000000-0x9fffffff flags 0x200]

The DC partition lands at 0x80000000, directly after ram, and no
static-capacity complaint is logged.

3. No static capacity at all
-----------------------------
No ram, no pmem, one 512M DC partition based at DPA 0.  This is the
boundary of the contiguity rule: with no static capacity the end of
static capacity is DPA 0, so a DC base of 0 meets it exactly and
neither the overlap error nor the gap warning may fire.

  cxl_pci 0000:0d:00.0: Read 1/1 DC partitions
  cxl_pci 0000:0d:00.0: DC partition 0 start 0x0 size 0x20000000 blk_size: 0x200000
  cxl_pci 0000:0d:00.0: Adding dynamic ram partition 1; 0x0 size 0x20000000
  cxl_pci 0000:0d:00.0: DPA(dynamic_ram_1): [mem 0x00000000-0x1fffffff flags 0x200]

4. Per-field validation
-----------------------
Each row is one malformed field on partition 0, everything else left
valid.  The message names the field that is wrong.

  block size 0x100000040   DC partition 0 invalid block size 0x100000040
  block size 0x30          DC partition 0 invalid block size 0x30
  decode length 0          DC partition 0 zero decode length
  base 0xa0001000          DC partition 0 base 0xa0001000 not aligned to 256M
  DSMAD handle 0x100       DSMAD handle 0x100 exceeds the 8 bit CDAT DSMAD handle
  0 partitions available   Device reported 0 available DC partitions, expected 1 to 8
  9 partitions available   Device reported 9 available DC partitions, expected 1 to 8

The first row is the 32 bit truncation Sashiko reported: 0x100000040 is
not a power of 2, but its low 32 bits are, so is_power_of_2() accepted
it on a 32 bit build.  All seven cases disable DCD and leave the memdev
attached with its static capacity.

DC partition 0 placed against static capacity, which cxl_configure_dcd()
checks separately, gives one message for the overlap and one for the
gap:

  cxl_pci 0000:0d:00.0: DC partition 0 base 0x90000000 overlaps static capacity ending at 0xa0000000
  cxl_pci 0000:0d:00.0: DC partition 0 base 0xb0000000 leaves a gap from static capacity ending at 0xa0000000

Also used ndctl-test-runner to run cxl_test for regressions.

Anisa Su (1):
  Documentation/cxl: Document DPA partition layout and ordering rules

Ira Weiny (7):
  cxl/mbox: Flag support for Dynamic Capacity Devices (DCD)
  cxl/mem: Read dynamic capacity configuration from the device
  cxl/cdat: Gather DSMAS data for DCD partitions
  cxl/events: Split event msgnum configuration from irq setup
  cxl/pci: Factor out interrupt policy check
  cxl/mem: Configure dynamic capacity interrupts
  cxl/core: Enforce partition order/simplify partition calls

 .../driver-api/cxl/linux/cxl-driver.rst       |  38 +++
 drivers/cxl/core/cdat.c                       |  32 +-
 drivers/cxl/core/hdm.c                        |  13 +
 drivers/cxl/core/mbox.c                       | 283 ++++++++++++++++++
 drivers/cxl/core/memdev.c                     |  84 ++++--
 drivers/cxl/cxl.h                             |   4 +-
 drivers/cxl/cxlmem.h                          |  88 +++++-
 drivers/cxl/mem.c                             |   2 +-
 drivers/cxl/pci.c                             | 159 ++++++++--
 include/cxl/cxl.h                             |  27 +-
 10 files changed, 653 insertions(+), 77 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [RESEND PATCH v13 1/8] cxl/mbox: Flag support for Dynamic Capacity Devices (DCD)
  2026-09-08 10:15 [RESEND PATCH v13 0/8] DCD Prep Series Anisa Su
@ 2026-09-08 10:15 ` Anisa Su
  2026-09-08 15:39   ` dave
  2026-09-08 18:45   ` Jonathan Cameron
  2026-09-08 10:15 ` [RESEND PATCH v13 2/8] cxl/mem: Read dynamic capacity configuration from the device Anisa Su
                   ` (6 subsequent siblings)
  7 siblings, 2 replies; 33+ messages in thread
From: Anisa Su @ 2026-09-08 10:15 UTC (permalink / raw)
  To: linux-cxl
  Cc: alison.schofield, jic23, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Ira Weiny, Anisa Su,
	Wonjae Lee, Junhee Park, Heesoo Kim

From: Ira Weiny <iweiny@kernel.org>

Per the CXL 4.0 specification software must check the Command Effects
Log (CEL) for dynamic capacity command support.

Detect support for the DCD commands while reading the CEL, including:

	Get DC Config
	Get DC Extent List
	Add DC Response
	Release DC

Leave mds->dcd_supported false. Dynamic capacity is only usable once
the driver can handle Add and Release Capacity events. Detect and log
the capability here and let the commit which adds DCD event handling set
the flag.

Based on an original patch by Navneet Singh.

Signed-off-by: Ira Weiny <iweiny@kernel.org>
Signed-off-by: Anisa Su <anisa.su@samsung.com>
Tested-by: Wonjae Lee <wj28.lee@samsung.com>
Tested-by: Junhee Park <jh9934.park@samsung.com>
Tested-by: Heesoo Kim <habil.kim@samsung.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>

---
Changes:
1. Commit message: explain why mds->dcd_supported is left
   false and when it's re-enabled in the commit message.

2. mbox.c: drop the single use cxl_verify_dcd_cmds() helper and test
   bitmap_full(dcd_cmds, CXL_DCD_ENABLED_MAX) directly. Reported by
   Alison Schofield.
---
 drivers/cxl/core/mbox.c | 39 +++++++++++++++++++++++++++++++++++++++
 drivers/cxl/cxlmem.h    | 20 ++++++++++++++++++++
 2 files changed, 59 insertions(+)

diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index 55828a836c01..199bb986d674 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -171,6 +171,33 @@ static void cxl_set_security_cmd_enabled(struct cxl_security_state *security,
 	}
 }
 
+static bool cxl_is_dcd_command(u16 opcode)
+{
+#define CXL_MBOX_OP_DCD_CMDS 0x48
+
+	return (opcode >> 8) == CXL_MBOX_OP_DCD_CMDS;
+}
+
+static void cxl_set_dcd_cmd_enabled(u16 opcode, unsigned long *cmd_mask)
+{
+	switch (opcode) {
+	case CXL_MBOX_OP_GET_DC_CONFIG:
+		set_bit(CXL_DCD_ENABLED_GET_CONFIG, cmd_mask);
+		break;
+	case CXL_MBOX_OP_GET_DC_EXTENT_LIST:
+		set_bit(CXL_DCD_ENABLED_GET_EXTENT_LIST, cmd_mask);
+		break;
+	case CXL_MBOX_OP_ADD_DC_RESPONSE:
+		set_bit(CXL_DCD_ENABLED_ADD_RESPONSE, cmd_mask);
+		break;
+	case CXL_MBOX_OP_RELEASE_DC:
+		set_bit(CXL_DCD_ENABLED_RELEASE, cmd_mask);
+		break;
+	default:
+		break;
+	}
+}
+
 static bool cxl_is_poison_command(u16 opcode)
 {
 #define CXL_MBOX_OP_POISON_CMDS 0x43
@@ -759,6 +786,7 @@ static void cxl_walk_cel(struct cxl_memdev_state *mds, size_t size, u8 *cel)
 	struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
 	struct cxl_cel_entry *cel_entry;
 	const int cel_entries = size / sizeof(*cel_entry);
+	DECLARE_BITMAP(dcd_cmds, CXL_DCD_ENABLED_MAX) = {};
 	struct device *dev = mds->cxlds.dev;
 	int i, ro_cmds = 0, wr_cmds = 0;
 
@@ -787,11 +815,22 @@ static void cxl_walk_cel(struct cxl_memdev_state *mds, size_t size, u8 *cel)
 			enabled++;
 		}
 
+		if (cxl_is_dcd_command(opcode)) {
+			cxl_set_dcd_cmd_enabled(opcode, dcd_cmds);
+			enabled++;
+		}
+
 		dev_dbg(dev, "Opcode 0x%04x %s\n", opcode,
 			enabled ? "enabled" : "unsupported by driver");
 	}
 
 	set_features_cap(cxl_mbox, ro_cmds, wr_cmds);
+	/*
+	 * Disabled until event handling implemented.
+	 */
+	if (bitmap_full(dcd_cmds, CXL_DCD_ENABLED_MAX))
+		dev_dbg(dev, "Device supports DCD; capability disabled\n");
+	mds->dcd_supported = false;
 }
 
 static struct cxl_mbox_get_supported_logs *cxl_get_gsl(struct cxl_memdev_state *mds)
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index c401e3a1af06..0c8e23276dc6 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -252,6 +252,20 @@ struct cxl_event_state {
 	struct mutex log_lock;
 };
 
+/*
+ * CXL r4.0 Section 8.2.10.9 - Memory Device Command Sets. See Table 8-308.
+ *
+ * The 48h Command Set (Opcodes 4800h - 4803h) defines the device-enabled DCD
+ * commands.
+ */
+enum dcd_cmd_enabled_bits {
+	CXL_DCD_ENABLED_GET_CONFIG,
+	CXL_DCD_ENABLED_GET_EXTENT_LIST,
+	CXL_DCD_ENABLED_ADD_RESPONSE,
+	CXL_DCD_ENABLED_RELEASE,
+	CXL_DCD_ENABLED_MAX
+};
+
 /* Device enabled poison commands */
 enum poison_cmd_enabled_bits {
 	CXL_POISON_ENABLED_LIST,
@@ -427,6 +441,7 @@ static inline struct cxl_dev_state *mbox_to_cxlds(struct cxl_mailbox *cxl_mbox)
  * @partition_align_bytes: alignment size for partition-able capacity
  * @active_volatile_bytes: sum of hard + soft volatile
  * @active_persistent_bytes: sum of hard + soft persistent
+ * @dcd_supported: all DCD commands are supported
  * @event: event log driver state
  * @poison: poison driver state info
  * @security: security driver state info
@@ -445,6 +460,7 @@ struct cxl_memdev_state {
 	u64 partition_align_bytes;
 	u64 active_volatile_bytes;
 	u64 active_persistent_bytes;
+	bool dcd_supported;
 
 	struct cxl_event_state event;
 	struct cxl_poison_state poison;
@@ -505,6 +521,10 @@ enum cxl_opcode {
 	CXL_MBOX_OP_UNLOCK		= 0x4503,
 	CXL_MBOX_OP_FREEZE_SECURITY	= 0x4504,
 	CXL_MBOX_OP_PASSPHRASE_SECURE_ERASE	= 0x4505,
+	CXL_MBOX_OP_GET_DC_CONFIG	= 0x4800,
+	CXL_MBOX_OP_GET_DC_EXTENT_LIST	= 0x4801,
+	CXL_MBOX_OP_ADD_DC_RESPONSE	= 0x4802,
+	CXL_MBOX_OP_RELEASE_DC		= 0x4803,
 	CXL_MBOX_OP_MAX			= 0x10000
 };
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RESEND PATCH v13 2/8] cxl/mem: Read dynamic capacity configuration from the device
  2026-09-08 10:15 [RESEND PATCH v13 0/8] DCD Prep Series Anisa Su
  2026-09-08 10:15 ` [RESEND PATCH v13 1/8] cxl/mbox: Flag support for Dynamic Capacity Devices (DCD) Anisa Su
@ 2026-09-08 10:15 ` Anisa Su
  2026-09-08 15:59   ` Davidlohr Bueso
  2026-09-08 20:43   ` Jonathan Cameron
  2026-09-08 10:15 ` [RESEND PATCH v13 3/8] cxl/cdat: Gather DSMAS data for DCD partitions Anisa Su
                   ` (5 subsequent siblings)
  7 siblings, 2 replies; 33+ messages in thread
From: Anisa Su @ 2026-09-08 10:15 UTC (permalink / raw)
  To: linux-cxl
  Cc: alison.schofield, jic23, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Ira Weiny, Anisa Su,
	Wonjae Lee, Junhee Park, Heesoo Kim

From: Ira Weiny <iweiny@kernel.org>

Devices which support Dynamic Capacity (DC) are configured
via mailbox commands. CXL r4.0 section 9.13.3 requires the host to issue
the Get DC Configuration command in order to properly configure DCDs.

Implement the DC mailbox commands as specified in CXL 4.0 section
8.2.10.9.9 (opcodes 48XXh) to read and store the DCD configuration
information. Disable DCD if an invalid configuration is found.

Linux has no support for more than one dynamic capacity partition. Read
all the partitions the device reports but validate only the first, and
configure it as 'dynamic ram 1'.

The specification requires that volatile capacity starts at DPA 0 and pmem
starts at the DPA immediately following it, but DC partitions only need
to be 256MB aligned according to CXL r4.0 section 8.2.10.9.9.1 Table 8-347.
So a device could leave a gap between ram/pmem (static) capacity and its first
DC partition, or between one DC partition and the next.

However, Linux follows the precedent set by PMEM/RAM partitions and requires the
first DC partition to begin at the DPA immediately following static
capacity.

Based on an original patch by Navneet Singh.

Signed-off-by: Ira Weiny <iweiny@kernel.org>
Signed-off-by: Anisa Su <anisa.su@samsung.com>
Tested-by: Wonjae Lee <wj28.lee@samsung.com>
Tested-by: Junhee Park <jh9934.park@samsung.com>
Tested-by: Heesoo Kim <habil.kim@samsung.com>

---
Changes:
1. mbox.c: validate only the first DC partition. Other partitions are read
   to make it easier to add support for additional partitions but not
   checked. Richard/Alison

2. mbox.c: rework the cxl_dc_check() validation. Run the checks in
   dependency order -- block size, decode length, length, base -- so the
   block size is validated before IS_ALIGNED() uses it as an alignment,
   and give each failure its own message naming the field that is wrong.
   Drop the block size alignment requirement on the region base; CXL
   r4.0 Table 8-347 requires the base to be 256M aligned and states the
   block size alignment for extent start DPAs, not for the base.
   Reported by Alison.

3. mbox.c: range check the number of available DC partitions reported by
   the device. CXL r4.0 Table 8-346 requires a DCD to report between 1
   and 8 regions, but the count was used unchecked as the read loop
   bound, so an out of range value failed later as "Invalid num of
   dynamic capacity partitions". Reported by Alison.

4. mbox.c/pci.c: cxl_configure_dcd() returns an error instead of void,
   and cxl_pci_probe() decides what to do with it. Failure to read the
   DC configuration is now reported rather than silently swallowed;
   -EINVAL for a partition overlapping static capacity, -EOPNOTSUPP for
   the gap Linux does not support, and the mailbox error propagated
   otherwise. cxl_disable_dcd() moves to the caller so the function
   reports and the caller sets policy. Probe still continues without
   DCD rather than failing the memdev, which would cost the device its
   static capacity too. Reported by Jonathan Cameron.

5. mbox.c: check the block size is a power of 2 in 64 bits.
   is_power_of_2() takes an unsigned long, so on a 32 bit build blk_size
   was truncated to its low 32 bits and a value such as 0x100000040 --
   non-zero and a multiple of 40h -- passed validation. CXL_BUS only
   depends on PCI, so this builds on 32 bit. Reported by Sashiko.
---
 drivers/cxl/core/hdm.c    |   2 +
 drivers/cxl/core/mbox.c   | 235 ++++++++++++++++++++++++++++++++++++++
 drivers/cxl/core/memdev.c |  37 ++++++
 drivers/cxl/cxlmem.h      |  55 +++++++++
 drivers/cxl/pci.c         |   6 +
 include/cxl/cxl.h         |   3 +-
 6 files changed, 337 insertions(+), 1 deletion(-)

diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index 0c80b76a5f9b..0ef076c08ed2 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -446,6 +446,8 @@ static const char *cxl_mode_name(enum cxl_partition_mode mode)
 		return "ram";
 	case CXL_PARTMODE_PMEM:
 		return "pmem";
+	case CXL_PARTMODE_DYNAMIC_RAM_1:
+		return "dynamic_ram_1";
 	default:
 		return "";
 	};
diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index 199bb986d674..a484e23b2b3a 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -1349,6 +1349,241 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)
 	return -EBUSY;
 }
 
+/*
+ * A partition unavailable for Dynamic Capacity reports zeros for decode_length,
+ * length, and block_size.
+ */
+static bool cxl_dc_partition_unavailable(struct cxl_dc_partition *dev_part)
+{
+	return !le64_to_cpu(dev_part->decode_length) &&
+	       !le64_to_cpu(dev_part->length) &&
+	       !le64_to_cpu(dev_part->block_size);
+}
+
+static int cxl_dc_check(struct device *dev, struct cxl_dc_partition_info *part,
+			struct cxl_dc_partition *dev_part)
+{
+	u64 blk_size = le64_to_cpu(dev_part->block_size);
+	u64 len = le64_to_cpu(dev_part->length);
+
+	/*
+	 * Not an error; leave the entry empty. A partially zeroed partition
+	 * is rejected by the checks below. CXL r4.0 Table 8-347.
+	 */
+	if (cxl_dc_partition_unavailable(dev_part)) {
+		*part = (struct cxl_dc_partition_info) { };
+		dev_dbg(dev, "Partition 0 unavailable for DC\n");
+		return 0;
+	}
+
+	*part = (struct cxl_dc_partition_info) {
+		.start = le64_to_cpu(dev_part->base),
+		.size = le64_to_cpu(dev_part->decode_length) * CXL_CAPACITY_MULTIPLIER,
+	};
+
+	/*
+	 * Block size is a power of 2 and a multiple of 40h. is_power_of_2()
+	 * takes an unsigned long, which truncates blk_size on 32 bit.
+	 */
+	if (blk_size == 0 || (blk_size & (blk_size - 1)) ||
+	    blk_size % CXL_DCD_BLOCK_LINE_SIZE) {
+		dev_err(dev, "DC partition 0 invalid block size %#llx\n", blk_size);
+		return -EINVAL;
+	}
+
+	if (part->size == 0) {
+		dev_err(dev, "DC partition 0 zero decode length\n");
+		return -EINVAL;
+	}
+
+	if (len == 0) {
+		dev_err(dev, "DC partition 0 zero length\n");
+		return -EINVAL;
+	}
+
+	if (len > part->size) {
+		dev_err(dev, "DC partition 0 length %#llx exceeds decode length %#llx\n",
+			len, part->size);
+		return -EINVAL;
+	}
+
+	if (!IS_ALIGNED(len, blk_size)) {
+		dev_err(dev, "DC partition 0 length %#llx not a multiple of block size %#llx\n",
+			len, blk_size);
+		return -EINVAL;
+	}
+
+	if (!IS_ALIGNED(part->start, SZ_256M)) {
+		dev_err(dev, "DC partition 0 base %#llx not aligned to 256M\n",
+			part->start);
+		return -EINVAL;
+	}
+
+	dev_dbg(dev, "DC partition 0 start %#llx size %#llx blk_size: %#llx\n",
+		part->start, part->size, blk_size);
+
+	return 0;
+}
+
+/* Returns the number of partitions in dc_resp or -ERRNO */
+static int cxl_get_dc_config(struct cxl_mailbox *mbox, u8 start_partition,
+			     u8 partition_count,
+			     struct cxl_mbox_get_dc_config_out *dc_resp,
+			     size_t dc_resp_size)
+{
+	struct cxl_mbox_get_dc_config_in get_dc = (struct cxl_mbox_get_dc_config_in) {
+		.partition_count = partition_count,
+		.start_partition_index = start_partition,
+	};
+	struct cxl_mbox_cmd mbox_cmd = (struct cxl_mbox_cmd) {
+		.opcode = CXL_MBOX_OP_GET_DC_CONFIG,
+		.payload_in = &get_dc,
+		.size_in = sizeof(get_dc),
+		.size_out = dc_resp_size,
+		.payload_out = dc_resp,
+		/* The device must return at least the fixed header */
+		.min_out = sizeof(*dc_resp),
+	};
+	size_t expected_sz;
+	int rc;
+
+	rc = cxl_internal_send_cmd(mbox, &mbox_cmd);
+	if (rc < 0)
+		return rc;
+
+	/* A DCD reports between 1 and 8 partitions */
+	if (dc_resp->avail_partition_count == 0 ||
+	    dc_resp->avail_partition_count > CXL_MAX_DC_PARTITIONS) {
+		dev_err(mbox->host,
+			"Device reported %u available DC partitions, expected 1 to %u\n",
+			dc_resp->avail_partition_count, CXL_MAX_DC_PARTITIONS);
+		return -EIO;
+	}
+
+	if (dc_resp->partitions_returned > partition_count) {
+		dev_err(mbox->host, "Device returned %u partitions, requested %u\n",
+			dc_resp->partitions_returned, partition_count);
+		return -EIO;
+	}
+
+	/*
+	 * The payload carries trailing extent/tag count fields after the
+	 * partition array (CXL r4.0 Table 8-346) which the driver ignores, so
+	 * the response is at least, not exactly, expected_sz.
+	 */
+	expected_sz = struct_size(dc_resp, partition,
+				  dc_resp->partitions_returned);
+
+	if (mbox_cmd.size_out < expected_sz) {
+		dev_err(mbox->host,
+			"Payload size %zu less than expected %zu for %u partitions\n",
+			mbox_cmd.size_out,
+			expected_sz,
+			dc_resp->partitions_returned);
+		return -EIO;
+	}
+
+	dev_dbg(mbox->host, "Read %d/%d DC partitions\n",
+		dc_resp->partitions_returned, dc_resp->avail_partition_count);
+	return dc_resp->partitions_returned;
+}
+
+/**
+ * cxl_dev_dc_identify() - Reads the dynamic capacity information from the
+ *                         device.
+ * @mbox: Mailbox to query
+ * @dc_info: The dynamic partition information to return
+ *
+ * Read every partition the device reports, but validate only the first:
+ * Linux maps partition 0 and nothing else, so a defect in capacity the
+ * driver never touches is not a reason to refuse the device dynamic
+ * capacity.  The remaining entries of @partitions are left unset.
+ *
+ * Return: 0 if identify was executed successfully, -ERRNO on error.
+ *         on error only dc_info is left unchanged.
+ */
+int cxl_dev_dc_identify(struct cxl_mailbox *mbox,
+			struct cxl_dc_partition_info *dc_info)
+{
+	struct cxl_dc_partition_info partitions[CXL_MAX_DC_PARTITIONS] = { };
+	struct cxl_mbox_get_dc_config_out *dc_resp __free(kfree) = NULL;
+	struct device *dev = mbox->host;
+	u8 start_partition;
+	u8 num_partitions;
+	u8 partition_count;
+	size_t dc_resp_size;
+
+	/*
+	 * Bound requested number of partitions by mailbox payload size. The
+	 * 256 byte spec minimum, verified in cxl_pci_setup_mailbox(), keeps
+	 * the subtraction below from underflowing.
+	 */
+	partition_count = min_t(size_t, CXL_MAX_DC_PARTITIONS,
+				(mbox->payload_size - sizeof(*dc_resp) -
+				 sizeof(struct cxl_mbox_get_dc_config_tail)) /
+				sizeof(struct cxl_dc_partition));
+	dc_resp_size = struct_size(dc_resp, partition, partition_count) +
+		       sizeof(struct cxl_mbox_get_dc_config_tail);
+
+	dc_resp = kmalloc(dc_resp_size, GFP_KERNEL);
+	if (!dc_resp)
+		return -ENOMEM;
+
+	start_partition = 0;
+	num_partitions = 0;
+	do {
+		int returned, rc;
+
+		returned = cxl_get_dc_config(mbox, start_partition,
+					     partition_count, dc_resp,
+					     dc_resp_size);
+		if (returned < 0) {
+			dev_err(dev, "Failed to get DC config: %d\n", returned);
+			return returned;
+		}
+
+		if (returned == 0) {
+			dev_err(dev,
+				"Device reported %u partitions available but returned none at index %u\n",
+				dc_resp->avail_partition_count, start_partition);
+			return -EIO;
+		}
+
+		/*
+		 * Only partition 0 is mapped, so it is the only one checked.
+		 * The rest are read to complete the enumeration and dropped.
+		 */
+		if (start_partition == 0) {
+			rc = cxl_dc_check(dev, &partitions[0],
+					  &dc_resp->partition[0]);
+			if (rc)
+				return rc;
+		}
+
+		num_partitions += returned;
+
+		if (num_partitions > CXL_MAX_DC_PARTITIONS) {
+			dev_err(dev, "Invalid num of dynamic capacity partitions %d\n",
+				num_partitions);
+			return -EINVAL;
+		}
+
+		start_partition = num_partitions;
+
+	} while (num_partitions < dc_resp->avail_partition_count);
+
+	/* Linux only supports the 1st partition; nothing to do if it is unavailable */
+	if (partitions[0].size == 0)
+		return -ENODEV;
+
+	*dc_info = partitions[0];
+	dev_dbg(dev, "Returning partition 0 %#llx size %#llx\n",
+		dc_info->start, dc_info->size);
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_dev_dc_identify, "CXL");
+
 int cxl_get_dirty_count(struct cxl_memdev_state *mds, u32 *count)
 {
 	struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index b3419df586b9..fdd6b395dcdf 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -643,6 +643,43 @@ int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
 }
 EXPORT_SYMBOL_NS_GPL(cxl_mem_dpa_fetch, "CXL");
 
+int cxl_configure_dcd(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
+{
+	struct cxl_dc_partition_info dc_info = { };
+	struct device *dev = mds->cxlds.dev;
+	int rc;
+
+	rc = cxl_dev_dc_identify(&mds->cxlds.cxl_mbox, &dc_info);
+	if (rc) {
+		dev_warn(dev,
+			 "Failed to read Dynamic Capacity config: %d\n", rc);
+		return rc;
+	}
+
+	if (dc_info.start < info->size) {
+		dev_err(dev,
+			"DC partition 0 base %#llx overlaps static capacity ending at %#llx\n",
+			dc_info.start, info->size);
+		return -EINVAL;
+	}
+
+	/* A gap between static capacity and the DC partition is not supported */
+	if (dc_info.start > info->size) {
+		dev_warn(dev,
+			 "DC partition 0 base %#llx leaves a gap from static capacity ending at %#llx\n",
+			 dc_info.start, info->size);
+		return -EOPNOTSUPP;
+	}
+
+	info->size += dc_info.size;
+	dev_dbg(dev, "Adding dynamic ram partition 1; %#llx size %#llx\n",
+		dc_info.start, dc_info.size);
+	add_part(info, dc_info.start, dc_info.size, CXL_PARTMODE_DYNAMIC_RAM_1);
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_configure_dcd, "CXL");
+
 
 /**
  * cxl_set_capacity: initialize dpa by a driver without a mailbox.
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 0c8e23276dc6..4fac65dbb808 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -407,6 +407,8 @@ struct cxl_security_state {
 	struct kernfs_node *sanitize_node;
 };
 
+#define CXL_MAX_DC_PARTITIONS 8
+
 static inline resource_size_t cxl_pmem_size(struct cxl_dev_state *cxlds)
 {
 	/*
@@ -689,6 +691,39 @@ struct cxl_mbox_set_shutdown_state_in {
 	u8 state;
 } __packed;
 
+/* See CXL r4.0 Table 8-345 get dynamic capacity config Input Payload */
+struct cxl_mbox_get_dc_config_in {
+	u8 partition_count;
+	u8 start_partition_index;
+} __packed;
+
+/* See CXL r4.0 Table 8-346 get dynamic capacity config Output Payload */
+struct cxl_mbox_get_dc_config_out {
+	u8 avail_partition_count;
+	u8 partitions_returned;
+	u8 rsvd[6];
+	/* See CXL r4.0 Table 8-347 */
+	struct cxl_dc_partition {
+		__le64 base;
+		__le64 decode_length;
+		__le64 length;
+		__le64 block_size;
+		__le32 dsmad_handle;
+		u8 flags;
+		u8 rsvd[3];
+	} __packed partition[] __counted_by(partitions_returned);
+	/* Trailing extent/tag count fields unused */
+} __packed;
+
+/* Trailing counts; cannot be a member after the flex array above */
+struct cxl_mbox_get_dc_config_tail {
+	__le32 num_extents_supported;
+	__le32 num_extents_available;
+	__le32 num_tags_supported;
+	__le32 num_tags_available;
+} __packed;
+#define CXL_DCD_BLOCK_LINE_SIZE 0x40
+
 /* Set Timestamp CXL 3.0 Spec 8.2.9.4.2 */
 struct cxl_mbox_set_timestamp_in {
 	__le64 timestamp;
@@ -812,9 +847,18 @@ enum {
 int cxl_internal_send_cmd(struct cxl_mailbox *cxl_mbox,
 			  struct cxl_mbox_cmd *cmd);
 int cxl_dev_state_identify(struct cxl_memdev_state *mds);
+
+struct cxl_dc_partition_info {
+	u64 start;
+	u64 size;
+};
+
+int cxl_dev_dc_identify(struct cxl_mailbox *mbox,
+			struct cxl_dc_partition_info *dc_info);
 int cxl_await_media_ready(struct cxl_dev_state *cxlds);
 int cxl_enumerate_cmds(struct cxl_memdev_state *mds);
 int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info);
+int cxl_configure_dcd(struct cxl_memdev_state *mds, struct cxl_dpa_info *info);
 struct cxl_memdev_state *cxl_memdev_state_create(struct device *dev, u64 serial,
 						 u16 dvsec);
 void set_exclusive_cxl_commands(struct cxl_memdev_state *mds,
@@ -828,6 +872,17 @@ void cxl_event_trace_record(struct cxl_memdev *cxlmd,
 			    const uuid_t *uuid, union cxl_event *evt);
 int cxl_get_dirty_count(struct cxl_memdev_state *mds, u32 *count);
 int cxl_arm_dirty_shutdown(struct cxl_memdev_state *mds);
+
+static inline bool cxl_dcd_supported(struct cxl_memdev_state *mds)
+{
+	return mds->dcd_supported;
+}
+
+static inline void cxl_disable_dcd(struct cxl_memdev_state *mds)
+{
+	mds->dcd_supported = false;
+}
+
 int cxl_set_timestamp(struct cxl_memdev_state *mds);
 int cxl_poison_state_init(struct cxl_memdev_state *mds);
 int cxl_mem_get_poison(struct cxl_memdev *cxlmd, u64 offset, u64 len,
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index c7c91e8dc51d..2fe9db4b3d86 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -868,6 +868,12 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (rc)
 		return rc;
 
+	if (cxl_dcd_supported(mds)) {
+		rc = cxl_configure_dcd(mds, &range_info);
+		if (rc)
+			cxl_disable_dcd(mds);
+	}
+
 	rc = cxl_dpa_setup(cxlds, &range_info);
 	if (rc)
 		return rc;
diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
index 802b143de83d..4ef9511fbbdd 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -133,6 +133,7 @@ struct cxl_dpa_perf {
 enum cxl_partition_mode {
 	CXL_PARTMODE_RAM,
 	CXL_PARTMODE_PMEM,
+	CXL_PARTMODE_DYNAMIC_RAM_1,
 };
 
 /**
@@ -147,7 +148,7 @@ struct cxl_dpa_partition {
 	enum cxl_partition_mode mode;
 };
 
-#define CXL_NR_PARTITIONS_MAX 2
+#define CXL_NR_PARTITIONS_MAX 3
 
 /**
  * struct cxl_dev_state - The driver device state
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RESEND PATCH v13 3/8] cxl/cdat: Gather DSMAS data for DCD partitions
  2026-09-08 10:15 [RESEND PATCH v13 0/8] DCD Prep Series Anisa Su
  2026-09-08 10:15 ` [RESEND PATCH v13 1/8] cxl/mbox: Flag support for Dynamic Capacity Devices (DCD) Anisa Su
  2026-09-08 10:15 ` [RESEND PATCH v13 2/8] cxl/mem: Read dynamic capacity configuration from the device Anisa Su
@ 2026-09-08 10:15 ` Anisa Su
  2026-09-08 20:52   ` Jonathan Cameron
  2026-09-08 10:15 ` [RESEND PATCH v13 4/8] cxl/events: Split event msgnum configuration from irq setup Anisa Su
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 33+ messages in thread
From: Anisa Su @ 2026-09-08 10:15 UTC (permalink / raw)
  To: linux-cxl
  Cc: alison.schofield, jic23, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Ira Weiny, Anisa Su,
	Wonjae Lee, Junhee Park, Heesoo Kim

From: Ira Weiny <iweiny@kernel.org>

Additional DCD partition (AKA region) information is contained in the
DSMAS CDAT tables, including performance and shareable attributes.

Match DCD partitions with DSMAS tables and store the meta data.

Signed-off-by: Ira Weiny <iweiny@kernel.org>
Co-developed-by: Anisa Su <anisa.su@samsung.com>
Signed-off-by: Anisa Su <anisa.su@samsung.com>
Tested-by: Wonjae Lee <wj28.lee@samsung.com>
Tested-by: Junhee Park <jh9934.park@samsung.com>
Tested-by: Heesoo Kim <habil.kim@samsung.com>

---
Changes:
1. cdat.c: set found=true as soon as a partition contains the range, and
   break out of the search on a DSMAD handle mismatch. Partitions are
   disjoint, so the continue could never match another one; the search
   always ran out and the entry was reported twice, once as a mismatch
   and again as "no partition for dsmas dpa" even though a partition did
   cover it.

2. cdat.c: only assign shareable for the dynamic ram 1 partition. It
   was set for every partition the DSMAS range fell into, while the
   handle check above it is DC only. The field describes a DC partition,
   so ram and pmem have no use for it.

3. Commit message: drop the claim that the read only attribute is
   gathered. Only the shareable flag is. Nothing in this series or the
   follow-on DCD work consumes a read only flag, so storing it would be
   dead state. Implementing read-only (reject writes to RO partitions)
   applies to any DSMAS described range, non-specific to dynamic capacity and
   belongs to separate patch.
---
 drivers/cxl/core/cdat.c   | 32 +++++++++++++++++++++++++-------
 drivers/cxl/core/hdm.c    |  1 +
 drivers/cxl/core/mbox.c   |  9 +++++++++
 drivers/cxl/core/memdev.c | 17 ++++++++++-------
 drivers/cxl/cxlmem.h      |  2 ++
 include/cxl/cxl.h         |  4 ++++
 6 files changed, 51 insertions(+), 14 deletions(-)

diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
index 5c9f07262513..05058d4520f2 100644
--- a/drivers/cxl/core/cdat.c
+++ b/drivers/cxl/core/cdat.c
@@ -17,6 +17,7 @@ struct dsmas_entry {
 	struct access_coordinate cdat_coord[ACCESS_COORDINATE_MAX];
 	int entries;
 	int qos_class;
+	bool shareable;
 };
 
 static u32 cdat_normalize(u16 entry, u64 base, u8 type)
@@ -74,6 +75,8 @@ static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg,
 		return -ENOMEM;
 
 	dent->handle = dsmas->dsmad_handle;
+	/* Shareable is CDAT 1.03 and later, DSMAS Flags bit 3 */
+	dent->shareable = dsmas->flags & ACPI_CDAT_DSMAS_SHAREABLE;
 	dent->dpa_range.start = le64_to_cpu((__force __le64)dsmas->dpa_base_address);
 	dent->dpa_range.end = le64_to_cpu((__force __le64)dsmas->dpa_base_address) +
 			      le64_to_cpu((__force __le64)dsmas->dpa_length) - 1;
@@ -266,18 +269,33 @@ static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds,
 		bool found = false;
 
 		for (int i = 0; i < cxlds->nr_partitions; i++) {
-			struct resource *res = &cxlds->part[i].res;
+			struct cxl_dpa_partition *part = &cxlds->part[i];
 			struct range range = {
-				.start = res->start,
-				.end = res->end,
+				.start = part->res.start,
+				.end = part->res.end,
 			};
 
-			if (range_contains(&range, &dent->dpa_range)) {
-				update_perf_entry(dev, dent,
-						  &cxlds->part[i].perf);
-				found = true;
+			if (!range_contains(&range, &dent->dpa_range))
+				continue;
+
+			found = true;
+			/*
+			 * part->handle is from Get DC Config, dent->handle
+			 * from the CDAT DSMAS entry.
+			 */
+			if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1 &&
+			    dent->handle != part->handle) {
+				dev_warn(dev,
+					 "DSMAD handle mismatch: %pra has %u, DSMAS %pra has %u\n",
+					 &range, part->handle,
+					 &dent->dpa_range, dent->handle);
 				break;
 			}
+
+			update_perf_entry(dev, dent, &part->perf);
+			if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1)
+				part->shareable = dent->shareable;
+			break;
 		}
 
 		if (!found)
diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index 0ef076c08ed2..7f63b86887f4 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -477,6 +477,7 @@ int cxl_dpa_setup(struct cxl_dev_state *cxlds, const struct cxl_dpa_info *info)
 
 		cxlds->part[i].perf.qos_class = CXL_QOS_CLASS_INVALID;
 		cxlds->part[i].mode = part->mode;
+		cxlds->part[i].handle = part->handle;
 
 		/* Require ordered + contiguous partitions */
 		if (i) {
diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
index a484e23b2b3a..efc3bf3563a5 100644
--- a/drivers/cxl/core/mbox.c
+++ b/drivers/cxl/core/mbox.c
@@ -1365,6 +1365,7 @@ static int cxl_dc_check(struct device *dev, struct cxl_dc_partition_info *part,
 {
 	u64 blk_size = le64_to_cpu(dev_part->block_size);
 	u64 len = le64_to_cpu(dev_part->length);
+	u32 handle = le32_to_cpu(dev_part->dsmad_handle);
 
 	/*
 	 * Not an error; leave the entry empty. A partially zeroed partition
@@ -1376,9 +1377,17 @@ static int cxl_dc_check(struct device *dev, struct cxl_dc_partition_info *part,
 		return 0;
 	}
 
+	/* The CDAT DSMAD handle this refers to is 8 bits */
+	if (handle & ~0xFF) {
+		dev_warn(dev, "DSMAD handle 0x%x exceeds the 8 bit CDAT DSMAD handle\n",
+			 handle);
+		return -EINVAL;
+	}
+
 	*part = (struct cxl_dc_partition_info) {
 		.start = le64_to_cpu(dev_part->base),
 		.size = le64_to_cpu(dev_part->decode_length) * CXL_CAPACITY_MULTIPLIER,
+		.handle = handle,
 	};
 
 	/*
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index fdd6b395dcdf..4a5793fa3cbf 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -594,7 +594,8 @@ bool is_cxl_memdev(const struct device *dev)
 }
 EXPORT_SYMBOL_NS_GPL(is_cxl_memdev, "CXL");
 
-static void add_part(struct cxl_dpa_info *info, u64 start, u64 size, enum cxl_partition_mode mode)
+static void add_part(struct cxl_dpa_info *info, u64 start, u64 size,
+		     enum cxl_partition_mode mode, u8 handle)
 {
 	int i = info->nr_partitions;
 
@@ -606,6 +607,7 @@ static void add_part(struct cxl_dpa_info *info, u64 start, u64 size, enum cxl_pa
 		.end = start + size - 1,
 	};
 	info->part[i].mode = mode;
+	info->part[i].handle = handle;
 	info->nr_partitions++;
 }
 
@@ -623,9 +625,9 @@ int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
 	info->size = mds->total_bytes;
 
 	if (mds->partition_align_bytes == 0) {
-		add_part(info, 0, mds->volatile_only_bytes, CXL_PARTMODE_RAM);
+		add_part(info, 0, mds->volatile_only_bytes, CXL_PARTMODE_RAM, 0);
 		add_part(info, mds->volatile_only_bytes,
-			 mds->persistent_only_bytes, CXL_PARTMODE_PMEM);
+			 mds->persistent_only_bytes, CXL_PARTMODE_PMEM, 0);
 		return 0;
 	}
 
@@ -635,9 +637,9 @@ int cxl_mem_dpa_fetch(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
 		return rc;
 	}
 
-	add_part(info, 0, mds->active_volatile_bytes, CXL_PARTMODE_RAM);
+	add_part(info, 0, mds->active_volatile_bytes, CXL_PARTMODE_RAM, 0);
 	add_part(info, mds->active_volatile_bytes, mds->active_persistent_bytes,
-		 CXL_PARTMODE_PMEM);
+		 CXL_PARTMODE_PMEM, 0);
 
 	return 0;
 }
@@ -674,7 +676,8 @@ int cxl_configure_dcd(struct cxl_memdev_state *mds, struct cxl_dpa_info *info)
 	info->size += dc_info.size;
 	dev_dbg(dev, "Adding dynamic ram partition 1; %#llx size %#llx\n",
 		dc_info.start, dc_info.size);
-	add_part(info, dc_info.start, dc_info.size, CXL_PARTMODE_DYNAMIC_RAM_1);
+	add_part(info, dc_info.start, dc_info.size, CXL_PARTMODE_DYNAMIC_RAM_1,
+		 dc_info.handle);
 
 	return 0;
 }
@@ -693,7 +696,7 @@ int cxl_set_capacity(struct cxl_dev_state *cxlds, u64 capacity)
 		.size = capacity,
 	};
 
-	add_part(&range_info, 0, capacity, CXL_PARTMODE_RAM);
+	add_part(&range_info, 0, capacity, CXL_PARTMODE_RAM, 0);
 	return cxl_dpa_setup(cxlds, &range_info);
 }
 EXPORT_SYMBOL_NS_GPL(cxl_set_capacity, "CXL");
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 4fac65dbb808..9fd5af2e41d4 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -140,6 +140,7 @@ struct cxl_dpa_info {
 	struct cxl_dpa_part_info {
 		struct range range;
 		enum cxl_partition_mode mode;
+		u8 handle;
 	} part[CXL_NR_PARTITIONS_MAX];
 	int nr_partitions;
 };
@@ -851,6 +852,7 @@ int cxl_dev_state_identify(struct cxl_memdev_state *mds);
 struct cxl_dc_partition_info {
 	u64 start;
 	u64 size;
+	u8 handle;
 };
 
 int cxl_dev_dc_identify(struct cxl_mailbox *mbox,
diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
index 4ef9511fbbdd..43edcde5bce3 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -141,11 +141,15 @@ enum cxl_partition_mode {
  * @res: shortcut to the partition in the DPA resource tree (cxlds->dpa_res)
  * @perf: performance attributes of the partition from CDAT
  * @mode: operation mode for the DPA capacity, e.g. ram, pmem, dynamic...
+ * @handle: DSMAS handle that represents this partition
+ * @shareable: Is the partition shareable (from its CDAT DSMAS entry)
  */
 struct cxl_dpa_partition {
 	struct resource res;
 	struct cxl_dpa_perf perf;
 	enum cxl_partition_mode mode;
+	u8 handle;
+	bool shareable;
 };
 
 #define CXL_NR_PARTITIONS_MAX 3
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RESEND PATCH v13 4/8] cxl/events: Split event msgnum configuration from irq setup
  2026-09-08 10:15 [RESEND PATCH v13 0/8] DCD Prep Series Anisa Su
                   ` (2 preceding siblings ...)
  2026-09-08 10:15 ` [RESEND PATCH v13 3/8] cxl/cdat: Gather DSMAS data for DCD partitions Anisa Su
@ 2026-09-08 10:15 ` Anisa Su
  2026-09-08 16:37   ` Davidlohr Bueso
  2026-09-08 10:15 ` [RESEND PATCH v13 5/8] cxl/pci: Factor out interrupt policy check Anisa Su
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 33+ messages in thread
From: Anisa Su @ 2026-09-08 10:15 UTC (permalink / raw)
  To: linux-cxl
  Cc: alison.schofield, jic23, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Ira Weiny, Anisa Su,
	Wonjae Lee, Junhee Park, Heesoo Kim, Fan Ni

From: Ira Weiny <iweiny@kernel.org>

Dynamic Capacity Devices (DCD) require event interrupts to process
memory addition or removal.  BIOS may have control over non-DCD event
processing.  DCD interrupt configuration needs to be separate from
memory event interrupt configuration.

Split cxl_event_config_msgnums() from irq setup in preparation for
separate DCD interrupts configuration.

Signed-off-by: Ira Weiny <iweiny@kernel.org>
Signed-off-by: Anisa Su <anisa.su@samsung.com>
Tested-by: Wonjae Lee <wj28.lee@samsung.com>
Tested-by: Junhee Park <jh9934.park@samsung.com>
Tested-by: Heesoo Kim <habil.kim@samsung.com>
Reviewed-by: Jonathan Cameron <jic23@kernel.org>
Reviewed-by: Fan Ni <nifan.cxl@gmail.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Li Ming <ming.li@zohomail.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
---
 drivers/cxl/pci.c | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 2fe9db4b3d86..4867657f5526 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -600,35 +600,31 @@ static int cxl_event_config_msgnums(struct cxl_memdev_state *mds,
 	return cxl_event_get_int_policy(mds, policy);
 }
 
-static int cxl_event_irqsetup(struct cxl_memdev_state *mds)
+static int cxl_event_irqsetup(struct cxl_memdev_state *mds,
+			      struct cxl_event_interrupt_policy *policy)
 {
 	struct cxl_dev_state *cxlds = &mds->cxlds;
-	struct cxl_event_interrupt_policy policy;
 	int rc;
 
-	rc = cxl_event_config_msgnums(mds, &policy);
-	if (rc)
-		return rc;
-
-	rc = cxl_event_req_irq(cxlds, policy.info_settings);
+	rc = cxl_event_req_irq(cxlds, policy->info_settings);
 	if (rc) {
 		dev_err(cxlds->dev, "Failed to get interrupt for event Info log\n");
 		return rc;
 	}
 
-	rc = cxl_event_req_irq(cxlds, policy.warn_settings);
+	rc = cxl_event_req_irq(cxlds, policy->warn_settings);
 	if (rc) {
 		dev_err(cxlds->dev, "Failed to get interrupt for event Warn log\n");
 		return rc;
 	}
 
-	rc = cxl_event_req_irq(cxlds, policy.failure_settings);
+	rc = cxl_event_req_irq(cxlds, policy->failure_settings);
 	if (rc) {
 		dev_err(cxlds->dev, "Failed to get interrupt for event Failure log\n");
 		return rc;
 	}
 
-	rc = cxl_event_req_irq(cxlds, policy.fatal_settings);
+	rc = cxl_event_req_irq(cxlds, policy->fatal_settings);
 	if (rc) {
 		dev_err(cxlds->dev, "Failed to get interrupt for event Fatal log\n");
 		return rc;
@@ -675,11 +671,15 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge,
 		return -EBUSY;
 	}
 
+	rc = cxl_event_config_msgnums(mds, &policy);
+	if (rc)
+		return rc;
+
 	rc = cxl_mem_alloc_event_buf(mds);
 	if (rc)
 		return rc;
 
-	rc = cxl_event_irqsetup(mds);
+	rc = cxl_event_irqsetup(mds, &policy);
 	if (rc)
 		return rc;
 
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RESEND PATCH v13 5/8] cxl/pci: Factor out interrupt policy check
  2026-09-08 10:15 [RESEND PATCH v13 0/8] DCD Prep Series Anisa Su
                   ` (3 preceding siblings ...)
  2026-09-08 10:15 ` [RESEND PATCH v13 4/8] cxl/events: Split event msgnum configuration from irq setup Anisa Su
@ 2026-09-08 10:15 ` Anisa Su
  2026-09-08 17:17   ` Davidlohr Bueso
  2026-09-08 10:15 ` [RESEND PATCH v13 6/8] cxl/mem: Configure dynamic capacity interrupts Anisa Su
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 33+ messages in thread
From: Anisa Su @ 2026-09-08 10:15 UTC (permalink / raw)
  To: linux-cxl
  Cc: alison.schofield, jic23, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Ira Weiny, Dan Williams,
	Anisa Su, Wonjae Lee, Junhee Park, Heesoo Kim, Fan Ni

From: Ira Weiny <iweiny@kernel.org>

Dynamic Capacity Devices (DCD) require event interrupts to process
memory addition or removal.  BIOS may have control over non-DCD event
processing.  DCD interrupt configuration needs to be separate from
memory event interrupt configuration.

Factor out check for firmware ownership of memory event logs.

Link: https://lore.kernel.org/all/663922b475e50_d54d72945b@dwillia2-xfh.jf.intel.com.notmuch/ [1]
Suggested-by: Dan Williams <djbw@kernel.org>
Signed-off-by: Ira Weiny <iweiny@kernel.org>
Signed-off-by: Anisa Su <anisa.su@samsung.com>
Tested-by: Wonjae Lee <wj28.lee@samsung.com>
Tested-by: Junhee Park <jh9934.park@samsung.com>
Tested-by: Heesoo Kim <habil.kim@samsung.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Jonathan Cameron <jic23@kernel.org>
Reviewed-by: Fan Ni <nifan.cxl@gmail.com>
Reviewed-by: Li Ming <ming.li@zohomail.com>

---
Changes:
1. pci.c: rename cxl_event_validate_mem_policy() to
   cxl_event_fw_owns_mem_logs() and invert it. It never validated the
   policy, it reported whether firmware still owns the standard memory
   event logs despite _OSC granting the OS control, so the name now
   states that condition and true means firmware owns them. The dev_err
   moves to the caller. Commit message reworded to reflect changes.
---
 drivers/cxl/pci.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 4867657f5526..7b754af2168d 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -640,6 +640,14 @@ static bool cxl_event_int_is_fw(u8 setting)
 	return mode == CXL_INT_FW;
 }
 
+static bool cxl_event_fw_owns_mem_logs(struct cxl_event_interrupt_policy *policy)
+{
+	return cxl_event_int_is_fw(policy->info_settings) ||
+	       cxl_event_int_is_fw(policy->warn_settings) ||
+	       cxl_event_int_is_fw(policy->failure_settings) ||
+	       cxl_event_int_is_fw(policy->fatal_settings);
+}
+
 static int cxl_event_config(struct pci_host_bridge *host_bridge,
 			    struct cxl_memdev_state *mds, bool irq_avail)
 {
@@ -662,10 +670,7 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge,
 	if (rc)
 		return rc;
 
-	if (cxl_event_int_is_fw(policy.info_settings) ||
-	    cxl_event_int_is_fw(policy.warn_settings) ||
-	    cxl_event_int_is_fw(policy.failure_settings) ||
-	    cxl_event_int_is_fw(policy.fatal_settings)) {
+	if (cxl_event_fw_owns_mem_logs(&policy)) {
 		dev_err(mds->cxlds.dev,
 			"FW still in control of Event Logs despite _OSC settings\n");
 		return -EBUSY;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RESEND PATCH v13 6/8] cxl/mem: Configure dynamic capacity interrupts
  2026-09-08 10:15 [RESEND PATCH v13 0/8] DCD Prep Series Anisa Su
                   ` (4 preceding siblings ...)
  2026-09-08 10:15 ` [RESEND PATCH v13 5/8] cxl/pci: Factor out interrupt policy check Anisa Su
@ 2026-09-08 10:15 ` Anisa Su
  2026-09-08 10:43   ` sashiko-bot
  2026-09-08 22:14   ` Jonathan Cameron
  2026-09-08 10:15 ` [RESEND PATCH v13 7/8] cxl/core: Enforce partition order/simplify partition calls Anisa Su
  2026-09-08 10:15 ` [RESEND PATCH v13 8/8] Documentation/cxl: Document DPA partition layout and ordering rules Anisa Su
  7 siblings, 2 replies; 33+ messages in thread
From: Anisa Su @ 2026-09-08 10:15 UTC (permalink / raw)
  To: linux-cxl
  Cc: alison.schofield, jic23, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Ira Weiny, Anisa Su,
	Wonjae Lee, Junhee Park, Heesoo Kim

From: Ira Weiny <iweiny@kernel.org>

Dynamic Capacity Devices (DCD) support extent change notifications
through the event log mechanism. The interrupt mailbox commands were
extended in CXL 3.1 to support these notifications. Firmware can't
configure DCD events to be FW controlled but can retain control of
memory events.

Configure DCD event log interrupts on devices supporting dynamic
capacity. Disable DCD if interrupts are not supported.

The DCD event log is not drained here. cxl_event_drain_mask() reports
only the logs the driver can service, and the DCD bit is added by
the patch introducing DCD event handling. Until then a DCD interrupt
wakes the event thread, which finds no log it owns and returns.

Care is taken to preserve the interrupt policy set by the FW if FW first
has been selected by the BIOS.

Based on an original patch by Navneet Singh.

Signed-off-by: Ira Weiny <iweiny@kernel.org>
Signed-off-by: Anisa Su <anisa.su@samsung.com>
Tested-by: Wonjae Lee <wj28.lee@samsung.com>
Tested-by: Junhee Park <jh9934.park@samsung.com>
Tested-by: Heesoo Kim <habil.kim@samsung.com>

---
Changes:
1. pci.c: disable DCD when the device supports the DCD commands but its
   interrupt policy is too short to carry dcd_settings. The Set is sized
   by the device's own policy length, so on a short policy dcd_settings
   is never sent, and the re-read afterwards leaves the driver's own
   value in the struct because the device does not return that byte.
   cxl_irqsetup() would then arm the DCD interrupt from a setting the
   device never accepted. A conforming device cannot be in that state,
   DCD is CXL 3.x and a 3.x policy carries the field, but nothing tied
   the two facts together. Reported by Alison Schofield.

2. pci.c: move the DCD bit out of cxl_event_drain_mask(), dropping the
   mds argument it no longer needs, so the bit lands with the code that
   drains the log as described above.  Requested by Alison Schofield.
---
 drivers/cxl/cxl.h    |   4 +-
 drivers/cxl/cxlmem.h |   2 +
 drivers/cxl/pci.c    | 124 ++++++++++++++++++++++++++++++++++++-------
 3 files changed, 109 insertions(+), 21 deletions(-)

diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index cab8ce39f465..d6e02bd0cf50 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -192,11 +192,13 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
 #define CXLDEV_EVENT_STATUS_WARN		BIT(1)
 #define CXLDEV_EVENT_STATUS_FAIL		BIT(2)
 #define CXLDEV_EVENT_STATUS_FATAL		BIT(3)
+#define CXLDEV_EVENT_STATUS_DCD			BIT(4)
 
 #define CXLDEV_EVENT_STATUS_ALL (CXLDEV_EVENT_STATUS_INFO |	\
 				 CXLDEV_EVENT_STATUS_WARN |	\
 				 CXLDEV_EVENT_STATUS_FAIL |	\
-				 CXLDEV_EVENT_STATUS_FATAL)
+				 CXLDEV_EVENT_STATUS_FATAL |	\
+				 CXLDEV_EVENT_STATUS_DCD)
 
 /* CXL rev 3.0 section 8.2.9.2.4; Table 8-52 */
 #define CXLDEV_EVENT_INT_MODE_MASK	GENMASK(1, 0)
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 9fd5af2e41d4..9106affd7c81 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -240,7 +240,9 @@ struct cxl_event_interrupt_policy {
 	u8 warn_settings;
 	u8 failure_settings;
 	u8 fatal_settings;
+	u8 dcd_settings;
 } __packed;
+#define CXL_EVENT_INT_POLICY_BASE_SIZE 4 /* info, warn, failure, fatal */
 
 /**
  * struct cxl_event_state - Event log driver state
diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
index 7b754af2168d..1ea505b1f40e 100644
--- a/drivers/cxl/pci.c
+++ b/drivers/cxl/pci.c
@@ -510,11 +510,23 @@ static bool cxl_alloc_irq_vectors(struct pci_dev *pdev)
 	return true;
 }
 
+/* Event logs the driver drains: standard logs when native_cxl */
+static u32 cxl_event_drain_mask(struct pci_host_bridge *host_bridge)
+{
+	if (host_bridge->native_cxl_error)
+		return CXLDEV_EVENT_STATUS_ALL & ~CXLDEV_EVENT_STATUS_DCD;
+
+	return 0;
+}
+
 static irqreturn_t cxl_event_thread(int irq, void *id)
 {
 	struct cxl_dev_id *dev_id = id;
 	struct cxl_dev_state *cxlds = dev_id->cxlds;
 	struct cxl_memdev_state *mds = to_cxl_memdev_state(cxlds);
+	struct pci_host_bridge *host_bridge =
+		pci_find_host_bridge(to_pci_dev(cxlds->dev)->bus);
+	u32 mask = cxl_event_drain_mask(host_bridge);
 	u32 status;
 
 	do {
@@ -523,8 +535,8 @@ static irqreturn_t cxl_event_thread(int irq, void *id)
 		 * ignore the reserved upper 32 bits
 		 */
 		status = readl(cxlds->regs.status + CXLDEV_DEV_EVENT_STATUS_OFFSET);
-		/* Ignore logs unknown to the driver */
-		status &= CXLDEV_EVENT_STATUS_ALL;
+		/* Ignore logs unknown to the driver or owned by BIOS */
+		status &= mask;
 		if (!status)
 			break;
 		cxl_mem_get_event_records(mds, status);
@@ -551,42 +563,62 @@ static int cxl_event_req_irq(struct cxl_dev_state *cxlds, u8 setting)
 }
 
 static int cxl_event_get_int_policy(struct cxl_memdev_state *mds,
-				    struct cxl_event_interrupt_policy *policy)
+				    struct cxl_event_interrupt_policy *policy,
+				    size_t *policy_size)
 {
 	struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
 	struct cxl_mbox_cmd mbox_cmd = {
 		.opcode = CXL_MBOX_OP_GET_EVT_INT_POLICY,
 		.payload_out = policy,
 		.size_out = sizeof(*policy),
+		/* CXL 2.0 firmware omits dcd_settings; accept the shorter reply */
+		.min_out = CXL_EVENT_INT_POLICY_BASE_SIZE,
 	};
 	int rc;
 
 	rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
-	if (rc < 0)
+	if (rc < 0) {
 		dev_err(mds->cxlds.dev,
 			"Failed to get event interrupt policy : %d", rc);
+		return rc;
+	}
 
+	if (policy_size)
+		*policy_size = mbox_cmd.size_out;
 	return rc;
 }
 
 static int cxl_event_config_msgnums(struct cxl_memdev_state *mds,
-				    struct cxl_event_interrupt_policy *policy)
+				    struct cxl_event_interrupt_policy *policy,
+				    bool native_cxl, size_t policy_size)
 {
 	struct cxl_mailbox *cxl_mbox = &mds->cxlds.cxl_mbox;
 	struct cxl_mbox_cmd mbox_cmd;
 	int rc;
 
-	*policy = (struct cxl_event_interrupt_policy) {
-		.info_settings = CXL_INT_MSI_MSIX,
-		.warn_settings = CXL_INT_MSI_MSIX,
-		.failure_settings = CXL_INT_MSI_MSIX,
-		.fatal_settings = CXL_INT_MSI_MSIX,
-	};
+	/* memory event policy is left if FW has control */
+	if (native_cxl) {
+		*policy = (struct cxl_event_interrupt_policy) {
+			.info_settings = CXL_INT_MSI_MSIX,
+			.warn_settings = CXL_INT_MSI_MSIX,
+			.failure_settings = CXL_INT_MSI_MSIX,
+			.fatal_settings = CXL_INT_MSI_MSIX,
+			.dcd_settings = 0,
+		};
+	}
+
+	/*
+	 * A CXL 3.0+ device can carry dcd_settings field without DCD command
+	 * support, so size the request by the device's policy_size and only
+	 * enable the DCD interrupt when DCD commands are supported.
+	 */
+	if (cxl_dcd_supported(mds))
+		policy->dcd_settings = CXL_INT_MSI_MSIX;
 
 	mbox_cmd = (struct cxl_mbox_cmd) {
 		.opcode = CXL_MBOX_OP_SET_EVT_INT_POLICY,
 		.payload_in = policy,
-		.size_in = sizeof(*policy),
+		.size_in = policy_size,
 	};
 
 	rc = cxl_internal_send_cmd(cxl_mbox, &mbox_cmd);
@@ -597,7 +629,7 @@ static int cxl_event_config_msgnums(struct cxl_memdev_state *mds,
 	}
 
 	/* Retrieve final interrupt settings */
-	return cxl_event_get_int_policy(mds, policy);
+	return cxl_event_get_int_policy(mds, policy, NULL);
 }
 
 static int cxl_event_irqsetup(struct cxl_memdev_state *mds,
@@ -633,6 +665,30 @@ static int cxl_event_irqsetup(struct cxl_memdev_state *mds,
 	return 0;
 }
 
+static int cxl_irqsetup(struct cxl_memdev_state *mds,
+			struct cxl_event_interrupt_policy *policy,
+			bool native_cxl)
+{
+	struct cxl_dev_state *cxlds = &mds->cxlds;
+	int rc;
+
+	if (native_cxl) {
+		rc = cxl_event_irqsetup(mds, policy);
+		if (rc)
+			return rc;
+	}
+
+	if (cxl_dcd_supported(mds)) {
+		rc = cxl_event_req_irq(cxlds, policy->dcd_settings);
+		if (rc) {
+			dev_err(cxlds->dev, "Failed to get interrupt for DCD event log\n");
+			cxl_disable_dcd(mds);
+		}
+	}
+
+	return 0;
+}
+
 static bool cxl_event_int_is_fw(u8 setting)
 {
 	u8 mode = FIELD_GET(CXLDEV_EVENT_INT_MODE_MASK, setting);
@@ -651,32 +707,54 @@ static bool cxl_event_fw_owns_mem_logs(struct cxl_event_interrupt_policy *policy
 static int cxl_event_config(struct pci_host_bridge *host_bridge,
 			    struct cxl_memdev_state *mds, bool irq_avail)
 {
-	struct cxl_event_interrupt_policy policy;
+	struct cxl_event_interrupt_policy policy = { 0 };
+	bool native_cxl = host_bridge->native_cxl_error;
+	size_t policy_size;
+	u32 mask;
 	int rc;
 
 	/*
 	 * When BIOS maintains CXL error reporting control, it will process
 	 * event records.  Only one agent can do so.
+	 *
+	 * If BIOS has control of events and DCD is not supported skip event
+	 * configuration.
 	 */
-	if (!host_bridge->native_cxl_error)
+	if (!native_cxl && !cxl_dcd_supported(mds))
 		return 0;
 
 	if (!irq_avail) {
 		dev_info(mds->cxlds.dev, "No interrupt support, disable event processing.\n");
+		if (cxl_dcd_supported(mds)) {
+			dev_info(mds->cxlds.dev, "DCD requires interrupts, disable DCD\n");
+			cxl_disable_dcd(mds);
+		}
 		return 0;
 	}
 
-	rc = cxl_event_get_int_policy(mds, &policy);
+	rc = cxl_event_get_int_policy(mds, &policy, &policy_size);
 	if (rc)
 		return rc;
 
-	if (cxl_event_fw_owns_mem_logs(&policy)) {
+	/*
+	 * dcd_settings cannot be sent to a device whose policy is too short
+	 * to hold it, so the device would never accept the setting
+	 * cxl_irqsetup() arms the DCD interrupt with.
+	 */
+	if (cxl_dcd_supported(mds) && policy_size < sizeof(policy)) {
+		dev_warn(mds->cxlds.dev,
+			 "DCD supported but interrupt policy is only %zu bytes\n",
+			 policy_size);
+		cxl_disable_dcd(mds);
+	}
+
+	if (native_cxl && cxl_event_fw_owns_mem_logs(&policy)) {
 		dev_err(mds->cxlds.dev,
 			"FW still in control of Event Logs despite _OSC settings\n");
 		return -EBUSY;
 	}
 
-	rc = cxl_event_config_msgnums(mds, &policy);
+	rc = cxl_event_config_msgnums(mds, &policy, native_cxl, policy_size);
 	if (rc)
 		return rc;
 
@@ -684,11 +762,17 @@ static int cxl_event_config(struct pci_host_bridge *host_bridge,
 	if (rc)
 		return rc;
 
-	rc = cxl_event_irqsetup(mds, &policy);
+	rc = cxl_irqsetup(mds, &policy, native_cxl);
 	if (rc)
 		return rc;
 
-	cxl_mem_get_event_records(mds, CXLDEV_EVENT_STATUS_ALL);
+	mask = cxl_event_drain_mask(host_bridge);
+	if (mask)
+		cxl_mem_get_event_records(mds, mask);
+
+	dev_dbg(mds->cxlds.dev, "Event config : %s DCD %s\n",
+		native_cxl ? "OS" : "BIOS",
+		cxl_dcd_supported(mds) ? "supported" : "not supported");
 
 	return 0;
 }
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RESEND PATCH v13 7/8] cxl/core: Enforce partition order/simplify partition calls
  2026-09-08 10:15 [RESEND PATCH v13 0/8] DCD Prep Series Anisa Su
                   ` (5 preceding siblings ...)
  2026-09-08 10:15 ` [RESEND PATCH v13 6/8] cxl/mem: Configure dynamic capacity interrupts Anisa Su
@ 2026-09-08 10:15 ` Anisa Su
  2026-09-08 10:15 ` [RESEND PATCH v13 8/8] Documentation/cxl: Document DPA partition layout and ordering rules Anisa Su
  7 siblings, 0 replies; 33+ messages in thread
From: Anisa Su @ 2026-09-08 10:15 UTC (permalink / raw)
  To: linux-cxl
  Cc: alison.schofield, jic23, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Ira Weiny, Anisa Su,
	Wonjae Lee, Junhee Park, Heesoo Kim, Jonathan Cameron

From: Ira Weiny <iweiny@kernel.org>

Device partitions share one flat DPA space in a fixed order: static
volatile capacity at DPA 0, static persistent capacity immediately above
it, and dynamic capacity above all static capacity.  The static pair is
mandated by CXL r4.0 8.2.10.9.2.1 "Get Partition Info", Table 8-310: the
device "shall provide this volatile capacity starting at DPA 0" and
"shall provide this persistent capacity starting at the DPA immediately
following the volatile capacity".  Dynamic capacity has no such rule.
Table 8-347 only requires the region base to be 256M aligned, so placing
it directly above static capacity is a Linux requirement,
enforced by cxl_configure_dcd().

    DPA 0                                                     end
    +---------------+---------------+---------------------------+
    |      ram      |     pmem      |       dynamic_ram_1       |
    +---------------+---------------+---------------------------+
    part[0]         part[1]         part[2]

Signed-off-by: Ira Weiny <iweiny@kernel.org>
Signed-off-by: Anisa Su <anisa.su@samsung.com>
Tested-by: Wonjae Lee <wj28.lee@samsung.com>
Tested-by: Junhee Park <jh9934.park@samsung.com>
Tested-by: Heesoo Kim <habil.kim@samsung.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>

---
Changes:
1. cxl.h: document the DPA partition layout above enum
   cxl_partition_mode with ascii art, and cite where the order comes
   from: the static ram and pmem order is mandated by CXL r4.0
   8.2.10.9.2.1 Table 8-310, while a dynamic partition has no such
   requirement -- 8.2.10.9.9.1 Table 8-347 only requires the DC Region
   Base to be 256MB aligned -- so following pmem is a Linux choice that
   cxl_configure_dcd() enforces. Reported by Alison Schofield.

2. Commit message: explain what the partition order is, where it comes
   from, and that this patch starts enforcing it. The previous text
   named an "implied partition order" without saying what it implied.
   Reported by Alison Schofield.
---
 drivers/cxl/core/hdm.c    | 10 ++++++++++
 drivers/cxl/core/memdev.c | 32 +++++++++-----------------------
 drivers/cxl/cxlmem.h      |  9 +++------
 drivers/cxl/mem.c         |  2 +-
 include/cxl/cxl.h         | 20 ++++++++++++++++++++
 5 files changed, 43 insertions(+), 30 deletions(-)

diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index 7f63b86887f4..18e9dfa115fb 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -469,6 +469,16 @@ int cxl_dpa_setup(struct cxl_dev_state *cxlds, const struct cxl_dpa_info *info)
 		return 0;
 	}
 
+	/* Verify partitions are in expected order. */
+	for (int i = 1; i < info->nr_partitions; i++) {
+		if (info->part[i].mode < info->part[i - 1].mode) {
+			dev_err(dev, "Partition order mismatch: %d (%s) follows %d (%s)\n",
+				i, cxl_mode_name(info->part[i].mode),
+				i - 1, cxl_mode_name(info->part[i - 1].mode));
+			return -EINVAL;
+		}
+	}
+
 	cxlds->dpa_res = DEFINE_RES_MEM(0, info->size);
 
 	for (int i = 0; i < info->nr_partitions; i++) {
diff --git a/drivers/cxl/core/memdev.c b/drivers/cxl/core/memdev.c
index 4a5793fa3cbf..5297fa20c8b0 100644
--- a/drivers/cxl/core/memdev.c
+++ b/drivers/cxl/core/memdev.c
@@ -77,20 +77,12 @@ static ssize_t label_storage_size_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(label_storage_size);
 
-static resource_size_t cxl_ram_size(struct cxl_dev_state *cxlds)
-{
-	/* Static RAM is only expected at partition 0. */
-	if (cxlds->part[0].mode != CXL_PARTMODE_RAM)
-		return 0;
-	return resource_size(&cxlds->part[0].res);
-}
-
 static ssize_t ram_size_show(struct device *dev, struct device_attribute *attr,
 			     char *buf)
 {
 	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
 	struct cxl_dev_state *cxlds = cxlmd->cxlds;
-	unsigned long long len = cxl_ram_size(cxlds);
+	unsigned long long len = cxl_part_size(cxlds, CXL_PARTMODE_RAM);
 
 	return sysfs_emit(buf, "%#llx\n", len);
 }
@@ -103,7 +95,7 @@ static ssize_t pmem_size_show(struct device *dev, struct device_attribute *attr,
 {
 	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
 	struct cxl_dev_state *cxlds = cxlmd->cxlds;
-	unsigned long long len = cxl_pmem_size(cxlds);
+	unsigned long long len = cxl_part_size(cxlds, CXL_PARTMODE_PMEM);
 
 	return sysfs_emit(buf, "%#llx\n", len);
 }
@@ -426,10 +418,11 @@ static struct attribute *cxl_memdev_attributes[] = {
 	NULL,
 };
 
-static struct cxl_dpa_perf *to_pmem_perf(struct cxl_dev_state *cxlds)
+static struct cxl_dpa_perf *part_perf(struct cxl_dev_state *cxlds,
+				      enum cxl_partition_mode mode)
 {
 	for (int i = 0; i < cxlds->nr_partitions; i++)
-		if (cxlds->part[i].mode == CXL_PARTMODE_PMEM)
+		if (cxlds->part[i].mode == mode)
 			return &cxlds->part[i].perf;
 	return NULL;
 }
@@ -440,7 +433,7 @@ static ssize_t pmem_qos_class_show(struct device *dev,
 	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
 	struct cxl_dev_state *cxlds = cxlmd->cxlds;
 
-	return sysfs_emit(buf, "%d\n", to_pmem_perf(cxlds)->qos_class);
+	return sysfs_emit(buf, "%d\n", part_perf(cxlds, CXL_PARTMODE_PMEM)->qos_class);
 }
 
 static struct device_attribute dev_attr_pmem_qos_class =
@@ -452,20 +445,13 @@ static struct attribute *cxl_memdev_pmem_attributes[] = {
 	NULL,
 };
 
-static struct cxl_dpa_perf *to_ram_perf(struct cxl_dev_state *cxlds)
-{
-	if (cxlds->part[0].mode != CXL_PARTMODE_RAM)
-		return NULL;
-	return &cxlds->part[0].perf;
-}
-
 static ssize_t ram_qos_class_show(struct device *dev,
 				  struct device_attribute *attr, char *buf)
 {
 	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
 	struct cxl_dev_state *cxlds = cxlmd->cxlds;
 
-	return sysfs_emit(buf, "%d\n", to_ram_perf(cxlds)->qos_class);
+	return sysfs_emit(buf, "%d\n", part_perf(cxlds, CXL_PARTMODE_RAM)->qos_class);
 }
 
 static struct device_attribute dev_attr_ram_qos_class =
@@ -501,7 +487,7 @@ static umode_t cxl_ram_visible(struct kobject *kobj, struct attribute *a, int n)
 {
 	struct device *dev = kobj_to_dev(kobj);
 	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
-	struct cxl_dpa_perf *perf = to_ram_perf(cxlmd->cxlds);
+	struct cxl_dpa_perf *perf = part_perf(cxlmd->cxlds, CXL_PARTMODE_RAM);
 
 	if (a == &dev_attr_ram_qos_class.attr &&
 	    (!perf || perf->qos_class == CXL_QOS_CLASS_INVALID))
@@ -520,7 +506,7 @@ static umode_t cxl_pmem_visible(struct kobject *kobj, struct attribute *a, int n
 {
 	struct device *dev = kobj_to_dev(kobj);
 	struct cxl_memdev *cxlmd = to_cxl_memdev(dev);
-	struct cxl_dpa_perf *perf = to_pmem_perf(cxlmd->cxlds);
+	struct cxl_dpa_perf *perf = part_perf(cxlmd->cxlds, CXL_PARTMODE_PMEM);
 
 	if (a == &dev_attr_pmem_qos_class.attr &&
 	    (!perf || perf->qos_class == CXL_QOS_CLASS_INVALID))
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index 9106affd7c81..35268d1c387c 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -412,14 +412,11 @@ struct cxl_security_state {
 
 #define CXL_MAX_DC_PARTITIONS 8
 
-static inline resource_size_t cxl_pmem_size(struct cxl_dev_state *cxlds)
+static inline resource_size_t cxl_part_size(struct cxl_dev_state *cxlds,
+					    enum cxl_partition_mode mode)
 {
-	/*
-	 * Static PMEM may be at partition index 0 when there is no static RAM
-	 * capacity.
-	 */
 	for (int i = 0; i < cxlds->nr_partitions; i++)
-		if (cxlds->part[i].mode == CXL_PARTMODE_PMEM)
+		if (cxlds->part[i].mode == mode)
 			return resource_size(&cxlds->part[i].res);
 	return 0;
 }
diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
index 798e5c369cfc..9c4ef401cbad 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/mem.c
@@ -139,7 +139,7 @@ static int cxl_mem_probe(struct device *dev)
 		return -ENXIO;
 	}
 
-	if (cxl_pmem_size(cxlds) && IS_ENABLED(CONFIG_CXL_PMEM)) {
+	if (cxl_part_size(cxlds, CXL_PARTMODE_PMEM) && IS_ENABLED(CONFIG_CXL_PMEM)) {
 		rc = devm_cxl_add_nvdimm(dev, parent_port, cxlmd);
 		if (rc) {
 			if (rc == -ENODEV)
diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
index 43edcde5bce3..b6895302a6ee 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -130,6 +130,26 @@ struct cxl_dpa_perf {
 	int qos_class;
 };
 
+/*
+ * Partitions share one flat DPA space in a fixed order:
+ *
+ *   DPA 0                                                     end
+ *   +---------------+---------------+---------------------------+
+ *   |      ram      |     pmem      |       dynamic_ram_1       |
+ *   +---------------+---------------+---------------------------+
+ *     part[0]         part[1]         part[2]
+ *
+ * The static ram and pmem partition order is mandated by CXL r4.0
+ * 8.2.10.9.2.1 "Get Partition Info" (opcode 4100h), Table 8-310: volatile
+ * capacity starts at DPA 0 and persistent capacity starts at the DPA
+ * immediately following it.  A dynamic partition has no such
+ * requirement -- 8.2.10.9.9.1 "Get Dynamic Capacity Configuration"
+ * (opcode 4800h), Table 8-347, only requires the DC Region Base to be
+ * 256MB aligned -- but Linux follows that precedent and requires it to
+ * start at the DPA immediately following static capacity: after pmem,
+ * after ram on a device with no pmem, or at DPA 0 on a device with no
+ * static capacity at all.  cxl_configure_dcd() enforces it.
+ */
 enum cxl_partition_mode {
 	CXL_PARTMODE_RAM,
 	CXL_PARTMODE_PMEM,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [RESEND PATCH v13 8/8] Documentation/cxl: Document DPA partition layout and ordering rules
  2026-09-08 10:15 [RESEND PATCH v13 0/8] DCD Prep Series Anisa Su
                   ` (6 preceding siblings ...)
  2026-09-08 10:15 ` [RESEND PATCH v13 7/8] cxl/core: Enforce partition order/simplify partition calls Anisa Su
@ 2026-09-08 10:15 ` Anisa Su
  2026-09-08 22:17   ` Jonathan Cameron
                     ` (2 more replies)
  7 siblings, 3 replies; 33+ messages in thread
From: Anisa Su @ 2026-09-08 10:15 UTC (permalink / raw)
  To: linux-cxl
  Cc: alison.schofield, jic23, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Anisa Su

DC Partitions complicate DPA ordering. Add a DPA Partitions section to
cxl-driver.rst describing spec-mandated and Linux requirements for the
layout.

Suggested-by: Gregory Price <gourry@gourry.net>
Signed-off-by: Anisa Su <anisa.su@samsung.com>

---
New patch in v13.
---
 .../driver-api/cxl/linux/cxl-driver.rst       | 38 +++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/Documentation/driver-api/cxl/linux/cxl-driver.rst b/Documentation/driver-api/cxl/linux/cxl-driver.rst
index dd6dd17dc536..f0742d6c86c3 100644
--- a/Documentation/driver-api/cxl/linux/cxl-driver.rst
+++ b/Documentation/driver-api/cxl/linux/cxl-driver.rst
@@ -181,6 +181,44 @@ A Memory Device is a discrete base object that is not a port.  While the
 physical device it belongs to may also host an `endpoint`, the relationship
 between an `endpoint` and a `memdev` is not captured in sysfs.
 
+DPA Partitions
+~~~~~~~~~~~~~~
+A memory device presents its capacity as one flat `Device Physical Address`
+(DPA) space divided into `partitions`, which Linux lays out in a fixed
+order::
+
+  DPA 0                                                     end
+  +---------------+---------------+---------------------------+
+  |      ram      |     pmem      |       dynamic_ram_1       |
+  +---------------+---------------+---------------------------+
+  part[0]         part[1]         part[2]
+
+Part of that order is required by the CXL specification and part of it is a
+Linux choice.
+
+The `ram` and `pmem` order is mandated.  CXL r4.0 section 8.2.10.9.2.1 "Get
+Partition Info" (4100h), Table 8-310, mandates that volatile capacity starts
+at DPA 0 and pmem starts at the DPA immediately following it.
+
+Dynamic Capacity partitions only need to be 256MB aligned according to
+CXL r4.0 section 8.2.10.9.9.1 "Get Dynamic Capacity Configuration"
+(opcode 4800h), Table 8-347. So a device could leave a gap between ram/pmem
+(static) capacity and its first DC partition, or between one DC partition
+and the next.
+
+Linux follows the static precedent anyway for the partition it maps: the
+first DC partition must begin at the DPA immediately following static
+capacity -- after pmem, after ram on a device with no pmem, or at DPA 0 on
+a device with no static capacity at all.
+
+Currently, only one dynamic partition is supported. A device may report up
+to eight (CXL r4.0 Table 8-346); Linux configures the first and exposes it as
+`dynamic_ram_1`.
+
+Support for additional dynamic partitions may be added if devices appear
+that need it, which is what the `dynamic_ram_1` name leaves room for.  Until
+then a device offering more than one is still usable, just not in full.
+
 Port Relationships
 ~~~~~~~~~~~~~~~~~~
 In our example described above, there are four host bridges attached to the
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 6/8] cxl/mem: Configure dynamic capacity interrupts
  2026-09-08 10:15 ` [RESEND PATCH v13 6/8] cxl/mem: Configure dynamic capacity interrupts Anisa Su
@ 2026-09-08 10:43   ` sashiko-bot
  2026-09-11 21:10     ` Anisa Su
  2026-09-08 22:14   ` Jonathan Cameron
  1 sibling, 1 reply; 33+ messages in thread
From: sashiko-bot @ 2026-09-08 10:43 UTC (permalink / raw)
  To: Anisa Su; +Cc: linux-cxl

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] If a CXL device is surprise-removed or a fatal PCIe error occurs, `cxl_event_thread` enters an infinite loop, pegging the CPU at 100% and deadlocking device removal.
--

commit f11145933c61ad9c3ba90b62e3f38dc571f856c5
Author: Ira Weiny <iweiny@kernel.org>

cxl/mem: Configure dynamic capacity interrupts

This commit configures Dynamic Capacity Device (DCD) event log interrupts
on devices supporting dynamic capacity. It disables DCD if interrupts are
not supported, and carefully preserves firmware-first interrupt policies
if selected by the BIOS.

> diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> index 7b754af2168d0..1ea505b1f40e8 100644
> --- a/drivers/cxl/pci.c
> +++ b/drivers/cxl/pci.c
[ ... ]
> @@ -523,8 +535,8 @@ static irqreturn_t cxl_event_thread(int irq, void *id)
>  		 * ignore the reserved upper 32 bits
>  		 */
>  		status = readl(cxlds->regs.status + CXLDEV_DEV_EVENT_STATUS_OFFSET);
> -		/* Ignore logs unknown to the driver */
> -		status &= CXLDEV_EVENT_STATUS_ALL;
> +		/* Ignore logs unknown to the driver or owned by BIOS */
> +		status &= mask;
>  		if (!status)
>  			break;
>  		cxl_mem_get_event_records(mds, status);
>  		cond_resched();
>  	} while (status);

[Severity: High]
This is a pre-existing issue, but does this loop lack a check for PCIe
surprise removal where MMIO reads return all 1s (~0)?

If a CXL device is surprise-removed or a fatal PCIe error occurs, readl()
will return 0xFFFFFFFF. When this is bitwise ANDed with mask, it leaves a
non-zero value, causing the loop to continue. 

Since cxl_mem_get_event_records() will also read ~0 (e.g., when checking
cxl_doorbell_busy()) and return immediately without changing hardware
state, won't this loop spin indefinitely, pegging the CPU at 100% and
deadlocking device removal when free_irq() waits for this thread to exit?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260908102124.2231730-2-anisa.su@samsung.com?part=6

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 1/8] cxl/mbox: Flag support for Dynamic Capacity Devices (DCD)
  2026-09-08 10:15 ` [RESEND PATCH v13 1/8] cxl/mbox: Flag support for Dynamic Capacity Devices (DCD) Anisa Su
@ 2026-09-08 15:39   ` dave
  2026-09-08 18:45   ` Jonathan Cameron
  1 sibling, 0 replies; 33+ messages in thread
From: dave @ 2026-09-08 15:39 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, jic23, dave.jiang, gourry, icheng,
	ming.li, vishal.l.verma, benjamin.cheatham, Ira Weiny, Anisa Su,
	Wonjae Lee, Junhee Park, Heesoo Kim

On 2026-09-08 03:15, Anisa Su wrote:
> From: Ira Weiny <iweiny@kernel.org>
> 
> Per the CXL 4.0 specification software must check the Command Effects
> Log (CEL) for dynamic capacity command support.
> 
> Detect support for the DCD commands while reading the CEL, including:
> 
> 	Get DC Config
> 	Get DC Extent List
> 	Add DC Response
> 	Release DC
> 
> Leave mds->dcd_supported false. Dynamic capacity is only usable once
> the driver can handle Add and Release Capacity events. Detect and log
> the capability here and let the commit which adds DCD event handling 
> set
> the flag.
> 
> Based on an original patch by Navneet Singh.
> 
> Signed-off-by: Ira Weiny <iweiny@kernel.org>
> Signed-off-by: Anisa Su <anisa.su@samsung.com>
> Tested-by: Wonjae Lee <wj28.lee@samsung.com>
> Tested-by: Junhee Park <jh9934.park@samsung.com>
> Tested-by: Heesoo Kim <habil.kim@samsung.com>
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>

Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 2/8] cxl/mem: Read dynamic capacity configuration from the device
  2026-09-08 10:15 ` [RESEND PATCH v13 2/8] cxl/mem: Read dynamic capacity configuration from the device Anisa Su
@ 2026-09-08 15:59   ` Davidlohr Bueso
  2026-09-08 20:43   ` Jonathan Cameron
  1 sibling, 0 replies; 33+ messages in thread
From: Davidlohr Bueso @ 2026-09-08 15:59 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, jic23, dave.jiang, gourry, icheng,
	ming.li, vishal.l.verma, benjamin.cheatham, Ira Weiny, Anisa Su,
	Wonjae Lee, Junhee Park, Heesoo Kim

On 2026-09-08 03:15, Anisa Su wrote:
> From: Ira Weiny <iweiny@kernel.org>
> 
> Devices which support Dynamic Capacity (DC) are configured
> via mailbox commands. CXL r4.0 section 9.13.3 requires the host to 
> issue
> the Get DC Configuration command in order to properly configure DCDs.
> 
> Implement the DC mailbox commands as specified in CXL 4.0 section
> 8.2.10.9.9 (opcodes 48XXh) to read and store the DCD configuration
> information. Disable DCD if an invalid configuration is found.
> 
> Linux has no support for more than one dynamic capacity partition. Read
> all the partitions the device reports but validate only the first, and
> configure it as 'dynamic ram 1'.
> 
> The specification requires that volatile capacity starts at DPA 0 and 
> pmem
> starts at the DPA immediately following it, but DC partitions only need
> to be 256MB aligned according to CXL r4.0 section 8.2.10.9.9.1 Table 
> 8-347.
> So a device could leave a gap between ram/pmem (static) capacity and 
> its first
> DC partition, or between one DC partition and the next.
> 
> However, Linux follows the precedent set by PMEM/RAM partitions and 
> requires the
> first DC partition to begin at the DPA immediately following static
> capacity.
> 
> Based on an original patch by Navneet Singh.
> 
> Signed-off-by: Ira Weiny <iweiny@kernel.org>
> Signed-off-by: Anisa Su <anisa.su@samsung.com>
> Tested-by: Wonjae Lee <wj28.lee@samsung.com>
> Tested-by: Junhee Park <jh9934.park@samsung.com>
> Tested-by: Heesoo Kim <habil.kim@samsung.com>

Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 4/8] cxl/events: Split event msgnum configuration from irq setup
  2026-09-08 10:15 ` [RESEND PATCH v13 4/8] cxl/events: Split event msgnum configuration from irq setup Anisa Su
@ 2026-09-08 16:37   ` Davidlohr Bueso
  0 siblings, 0 replies; 33+ messages in thread
From: Davidlohr Bueso @ 2026-09-08 16:37 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, jic23, dave.jiang, gourry, icheng,
	ming.li, vishal.l.verma, benjamin.cheatham, Ira Weiny, Anisa Su,
	Wonjae Lee, Junhee Park, Heesoo Kim, Fan Ni

On 2026-09-08 03:15, Anisa Su wrote:
> From: Ira Weiny <iweiny@kernel.org>
> 
> Dynamic Capacity Devices (DCD) require event interrupts to process
> memory addition or removal.  BIOS may have control over non-DCD event
> processing.  DCD interrupt configuration needs to be separate from
> memory event interrupt configuration.
> 
> Split cxl_event_config_msgnums() from irq setup in preparation for
> separate DCD interrupts configuration.
> 
> Signed-off-by: Ira Weiny <iweiny@kernel.org>
> Signed-off-by: Anisa Su <anisa.su@samsung.com>
> Tested-by: Wonjae Lee <wj28.lee@samsung.com>
> Tested-by: Junhee Park <jh9934.park@samsung.com>
> Tested-by: Heesoo Kim <habil.kim@samsung.com>
> Reviewed-by: Jonathan Cameron <jic23@kernel.org>
> Reviewed-by: Fan Ni <nifan.cxl@gmail.com>
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> Reviewed-by: Li Ming <ming.li@zohomail.com>
> Reviewed-by: Alison Schofield <alison.schofield@intel.com>

Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 5/8] cxl/pci: Factor out interrupt policy check
  2026-09-08 10:15 ` [RESEND PATCH v13 5/8] cxl/pci: Factor out interrupt policy check Anisa Su
@ 2026-09-08 17:17   ` Davidlohr Bueso
  0 siblings, 0 replies; 33+ messages in thread
From: Davidlohr Bueso @ 2026-09-08 17:17 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, jic23, dave.jiang, gourry, icheng,
	ming.li, vishal.l.verma, benjamin.cheatham, Ira Weiny,
	Dan Williams, Anisa Su, Wonjae Lee, Junhee Park, Heesoo Kim,
	Fan Ni

On 2026-09-08 03:15, Anisa Su wrote:
> From: Ira Weiny <iweiny@kernel.org>
> 
> Dynamic Capacity Devices (DCD) require event interrupts to process
> memory addition or removal.  BIOS may have control over non-DCD event
> processing.  DCD interrupt configuration needs to be separate from
> memory event interrupt configuration.
> 
> Factor out check for firmware ownership of memory event logs.
> 
> Link:
> https://lore.kernel.org/all/663922b475e50_d54d72945b@dwillia2-xfh.jf.intel.com.notmuch/
> [1]
> Suggested-by: Dan Williams <djbw@kernel.org>
> Signed-off-by: Ira Weiny <iweiny@kernel.org>
> Signed-off-by: Anisa Su <anisa.su@samsung.com>
> Tested-by: Wonjae Lee <wj28.lee@samsung.com>
> Tested-by: Junhee Park <jh9934.park@samsung.com>
> Tested-by: Heesoo Kim <habil.kim@samsung.com>
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> Reviewed-by: Jonathan Cameron <jic23@kernel.org>
> Reviewed-by: Fan Ni <nifan.cxl@gmail.com>
> Reviewed-by: Li Ming <ming.li@zohomail.com>

Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 1/8] cxl/mbox: Flag support for Dynamic Capacity Devices (DCD)
  2026-09-08 10:15 ` [RESEND PATCH v13 1/8] cxl/mbox: Flag support for Dynamic Capacity Devices (DCD) Anisa Su
  2026-09-08 15:39   ` dave
@ 2026-09-08 18:45   ` Jonathan Cameron
  1 sibling, 0 replies; 33+ messages in thread
From: Jonathan Cameron @ 2026-09-08 18:45 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Ira Weiny, Anisa Su,
	Wonjae Lee, Junhee Park, Heesoo Kim

On Tue,  8 Sep 2026 03:15:05 -0700
Anisa Su <anisa.su887@gmail.com> wrote:

> From: Ira Weiny <iweiny@kernel.org>
> 
> Per the CXL 4.0 specification software must check the Command Effects
> Log (CEL) for dynamic capacity command support.
> 
> Detect support for the DCD commands while reading the CEL, including:
> 
> 	Get DC Config
> 	Get DC Extent List
> 	Add DC Response
> 	Release DC
> 
> Leave mds->dcd_supported false. Dynamic capacity is only usable once
> the driver can handle Add and Release Capacity events. Detect and log
> the capability here and let the commit which adds DCD event handling set
> the flag.
> 
> Based on an original patch by Navneet Singh.
> 
> Signed-off-by: Ira Weiny <iweiny@kernel.org>
> Signed-off-by: Anisa Su <anisa.su@samsung.com>
> Tested-by: Wonjae Lee <wj28.lee@samsung.com>
> Tested-by: Junhee Park <jh9934.park@samsung.com>
> Tested-by: Heesoo Kim <habil.kim@samsung.com>
> Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>
Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 2/8] cxl/mem: Read dynamic capacity configuration from the device
  2026-09-08 10:15 ` [RESEND PATCH v13 2/8] cxl/mem: Read dynamic capacity configuration from the device Anisa Su
  2026-09-08 15:59   ` Davidlohr Bueso
@ 2026-09-08 20:43   ` Jonathan Cameron
  2026-09-10 23:56     ` Anisa Su
  1 sibling, 1 reply; 33+ messages in thread
From: Jonathan Cameron @ 2026-09-08 20:43 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Ira Weiny, Anisa Su,
	Wonjae Lee, Junhee Park, Heesoo Kim

On Tue,  8 Sep 2026 03:15:06 -0700
Anisa Su <anisa.su887@gmail.com> wrote:

> From: Ira Weiny <iweiny@kernel.org>
> 
> Devices which support Dynamic Capacity (DC) are configured
> via mailbox commands. CXL r4.0 section 9.13.3 requires the host to issue
> the Get DC Configuration command in order to properly configure DCDs.

I don't see text saying quite this and have a concern around what
might be interpreted as being required should we ever deal deeper
device resets.  I think you could in practice cache the result of
this.  There is no specific implication that it 'must' be issued.

The text I see that is relevant is
  The basic sequence to utilize Dynamic Capacity include:
...
   * Issue Get Dynamic Capacity Configuration command:  The device reports its
     number of available regions and each region's base address, length, block
     size, and DSMAD Handle.

I read that as meaning that the host does to get the info not that
it is needed to configure DCDs on the device side.

Anyhow, I'd just reword a tiny bit to something like
  CXL r4.0 section 9.13.3 describes the use of the Get DC Configuration command
  in order to obtain the DCD region/partition characteristics.

> 
> Implement the DC mailbox commands as specified in CXL 4.0 section
> 8.2.10.9.9 (opcodes 48XXh) to read and store the DCD configuration
> information. Disable DCD if an invalid configuration is found.
> 
> Linux has no support for more than one dynamic capacity partition. Read
Seems backwards. Perhaps
  Initial enablement for Linux only supports one dynamic capacity partition.

> all the partitions the device reports but validate only the first, and
> configure it as 'dynamic ram 1'.
> 
> The specification requires that volatile capacity starts at DPA 0 and pmem
> starts at the DPA immediately following it, but DC partitions only need
> to be 256MB aligned according to CXL r4.0 section 8.2.10.9.9.1 Table 8-347.
> So a device could leave a gap between ram/pmem (static) capacity and its first
> DC partition, or between one DC partition and the next.
> 
> However, Linux follows the precedent set by PMEM/RAM partitions and requires the
> first DC partition to begin at the DPA immediately following static
> capacity.
> 
> Based on an original patch by Navneet Singh.
> 
> Signed-off-by: Ira Weiny <iweiny@kernel.org>
> Signed-off-by: Anisa Su <anisa.su@samsung.com>
> Tested-by: Wonjae Lee <wj28.lee@samsung.com>
> Tested-by: Junhee Park <jh9934.park@samsung.com>
> Tested-by: Heesoo Kim <habil.kim@samsung.com>

A couple of other things inline.

Thanks,

Jonathan


> diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
> index 199bb986d674..a484e23b2b3a 100644
> --- a/drivers/cxl/core/mbox.c
> +++ b/drivers/cxl/core/mbox.c
> @@ -1349,6 +1349,241 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)
>  	return -EBUSY;
>  }
>  

...

> +static int cxl_dc_check(struct device *dev, struct cxl_dc_partition_info *part,
> +			struct cxl_dc_partition *dev_part)
> +{
> +	u64 blk_size = le64_to_cpu(dev_part->block_size);
> +	u64 len = le64_to_cpu(dev_part->length);
> +
> +	/*
> +	 * Not an error; leave the entry empty. A partially zeroed partition
> +	 * is rejected by the checks below. CXL r4.0 Table 8-347.
> +	 */
> +	if (cxl_dc_partition_unavailable(dev_part)) {
> +		*part = (struct cxl_dc_partition_info) { };
> +		dev_dbg(dev, "Partition 0 unavailable for DC\n");
> +		return 0;
> +	}
> +
> +	*part = (struct cxl_dc_partition_info) {
> +		.start = le64_to_cpu(dev_part->base),
> +		.size = le64_to_cpu(dev_part->decode_length) * CXL_CAPACITY_MULTIPLIER,
> +	};
> +
> +	/*
> +	 * Block size is a power of 2 and a multiple of 40h. is_power_of_2()
> +	 * takes an unsigned long, which truncates blk_size on 32 bit

oh. That's ugly.  Worth just fixing?  I guess we don't want a general
macro like that on the critical path for this patch.  Perhaps one to revisit.

> +	 */
> +	if (blk_size == 0 || (blk_size & (blk_size - 1)) ||
> +	    blk_size % CXL_DCD_BLOCK_LINE_SIZE) {
> +		dev_err(dev, "DC partition 0 invalid block size %#llx\n", blk_size);
> +		return -EINVAL;
> +	}

...


> +/* Returns the number of partitions in dc_resp or -ERRNO */
> +static int cxl_get_dc_config(struct cxl_mailbox *mbox, u8 start_partition,
> +			     u8 partition_count,
> +			     struct cxl_mbox_get_dc_config_out *dc_resp,
> +			     size_t dc_resp_size)
> +{
> +	struct cxl_mbox_get_dc_config_in get_dc = (struct cxl_mbox_get_dc_config_in) {
> +		.partition_count = partition_count,
> +		.start_partition_index = start_partition,
> +	};
> +	struct cxl_mbox_cmd mbox_cmd = (struct cxl_mbox_cmd) {
> +		.opcode = CXL_MBOX_OP_GET_DC_CONFIG,
> +		.payload_in = &get_dc,
> +		.size_in = sizeof(get_dc),
> +		.size_out = dc_resp_size,
> +		.payload_out = dc_resp,
> +		/* The device must return at least the fixed header */
> +		.min_out = sizeof(*dc_resp),
> +	};
> +	size_t expected_sz;
> +	int rc;
> +
> +	rc = cxl_internal_send_cmd(mbox, &mbox_cmd);
> +	if (rc < 0)
> +		return rc;
> +
> +	/* A DCD reports between 1 and 8 partitions */
> +	if (dc_resp->avail_partition_count == 0 ||
> +	    dc_resp->avail_partition_count > CXL_MAX_DC_PARTITIONS) {

This strikes me as a compatibility issue waiting to happen.  Today the spec
supports 8, but maybe in future it will support more and I'd not consider
that a backwards compatibility break (which this would make it).  I'd clamp
to CXL_MAX_DC_PARITIONS and maybe print with dev_info() if you see something
bigger in the wild.

> +		dev_err(mbox->host,
> +			"Device reported %u available DC partitions, expected 1 to %u\n",
> +			dc_resp->avail_partition_count, CXL_MAX_DC_PARTITIONS);
> +		return -EIO;
> +	}
> +
...


> +	/*
> +	 * The payload carries trailing extent/tag count fields after the
> +	 * partition array (CXL r4.0 Table 8-346) which the driver ignores, so
> +	 * the response is at least, not exactly, expected_sz.
> +	 */

More generally we shouldn't be checking that a record isn't longer than expected
because of similar backwards compat concerns.  Check is always that it is at least
as large as we need.

> +	expected_sz = struct_size(dc_resp, partition,
> +				  dc_resp->partitions_returned);
> +
> +	if (mbox_cmd.size_out < expected_sz) {
> +		dev_err(mbox->host,
> +			"Payload size %zu less than expected %zu for %u partitions\n",
> +			mbox_cmd.size_out,
> +			expected_sz,
> +			dc_resp->partitions_returned);
> +		return -EIO;
> +	}
> +
> +	dev_dbg(mbox->host, "Read %d/%d DC partitions\n",
> +		dc_resp->partitions_returned, dc_resp->avail_partition_count);
> +	return dc_resp->partitions_returned;
> +}
> +

> +/**
> + * cxl_dev_dc_identify() - Reads the dynamic capacity information from the
> + *                         device.
> + * @mbox: Mailbox to query
> + * @dc_info: The dynamic partition information to return
> + *
> + * Read every partition the device reports, but validate only the first:
> + * Linux maps partition 0 and nothing else, so a defect in capacity the
> + * driver never touches is not a reason to refuse the device dynamic
> + * capacity.  The remaining entries of @partitions are left unset.
> + *
> + * Return: 0 if identify was executed successfully, -ERRNO on error.
> + *         on error only dc_info is left unchanged.
> + */
> +int cxl_dev_dc_identify(struct cxl_mailbox *mbox,
> +			struct cxl_dc_partition_info *dc_info)
> +{
> +	struct cxl_dc_partition_info partitions[CXL_MAX_DC_PARTITIONS] = { };
> +	struct cxl_mbox_get_dc_config_out *dc_resp __free(kfree) = NULL;
> +	struct device *dev = mbox->host;
> +	u8 start_partition;
> +	u8 num_partitions;
> +	u8 partition_count;
> +	size_t dc_resp_size;
> +
> +	/*
> +	 * Bound requested number of partitions by mailbox payload size. The
> +	 * 256 byte spec minimum, verified in cxl_pci_setup_mailbox(), keeps
> +	 * the subtraction below from underflowing.
> +	 */
> +	partition_count = min_t(size_t, CXL_MAX_DC_PARTITIONS,
> +				(mbox->payload_size - sizeof(*dc_resp) -
> +				 sizeof(struct cxl_mbox_get_dc_config_tail)) /
> +				sizeof(struct cxl_dc_partition));

I doubt we need min_t() rather than min() but maybe I'm missing something.
Pretty much anything can be compared with small constants without needing
to specify the type used.

> +	dc_resp_size = struct_size(dc_resp, partition, partition_count) +
> +		       sizeof(struct cxl_mbox_get_dc_config_tail);
> +

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 3/8] cxl/cdat: Gather DSMAS data for DCD partitions
  2026-09-08 10:15 ` [RESEND PATCH v13 3/8] cxl/cdat: Gather DSMAS data for DCD partitions Anisa Su
@ 2026-09-08 20:52   ` Jonathan Cameron
  2026-09-11  0:02     ` Anisa Su
  0 siblings, 1 reply; 33+ messages in thread
From: Jonathan Cameron @ 2026-09-08 20:52 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Ira Weiny, Anisa Su,
	Wonjae Lee, Junhee Park, Heesoo Kim

On Tue,  8 Sep 2026 03:15:07 -0700
Anisa Su <anisa.su887@gmail.com> wrote:

> From: Ira Weiny <iweiny@kernel.org>
> 
> Additional DCD partition (AKA region) information is contained in the
> DSMAS CDAT tables, including performance and shareable attributes.
> 
> Match DCD partitions with DSMAS tables and store the meta data.
> 
> Signed-off-by: Ira Weiny <iweiny@kernel.org>
> Co-developed-by: Anisa Su <anisa.su@samsung.com>
> Signed-off-by: Anisa Su <anisa.su@samsung.com>
> Tested-by: Wonjae Lee <wj28.lee@samsung.com>
> Tested-by: Junhee Park <jh9934.park@samsung.com>
> Tested-by: Heesoo Kim <habil.kim@samsung.com>
> 
Minor thing inline. I think we can take a bit of refactoring
you did a little further and end up with simpler code.

> ---
>  drivers/cxl/core/cdat.c   | 32 +++++++++++++++++++++++++-------
>  drivers/cxl/core/hdm.c    |  1 +
>  drivers/cxl/core/mbox.c   |  9 +++++++++
>  drivers/cxl/core/memdev.c | 17 ++++++++++-------
>  drivers/cxl/cxlmem.h      |  2 ++
>  include/cxl/cxl.h         |  4 ++++
>  6 files changed, 51 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
> index 5c9f07262513..05058d4520f2 100644
> --- a/drivers/cxl/core/cdat.c
> +++ b/drivers/cxl/core/cdat.c
> @@ -17,6 +17,7 @@ struct dsmas_entry {
>  	struct access_coordinate cdat_coord[ACCESS_COORDINATE_MAX];
>  	int entries;
>  	int qos_class;
> +	bool shareable;
>  };
>  
>  static u32 cdat_normalize(u16 entry, u64 base, u8 type)
> @@ -74,6 +75,8 @@ static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg,
>  		return -ENOMEM;
>  
>  	dent->handle = dsmas->dsmad_handle;
> +	/* Shareable is CDAT 1.03 and later, DSMAS Flags bit 3 */
> +	dent->shareable = dsmas->flags & ACPI_CDAT_DSMAS_SHAREABLE;
>  	dent->dpa_range.start = le64_to_cpu((__force __le64)dsmas->dpa_base_address);
>  	dent->dpa_range.end = le64_to_cpu((__force __le64)dsmas->dpa_base_address) +
>  			      le64_to_cpu((__force __le64)dsmas->dpa_length) - 1;
> @@ -266,18 +269,33 @@ static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds,
>  		bool found = false;
>  
>  		for (int i = 0; i < cxlds->nr_partitions; i++) {
> -			struct resource *res = &cxlds->part[i].res;
> +			struct cxl_dpa_partition *part = &cxlds->part[i];
>  			struct range range = {
> -				.start = res->start,
> -				.end = res->end,
> +				.start = part->res.start,
> +				.end = part->res.end,
>  			};
>  
> -			if (range_contains(&range, &dent->dpa_range)) {
> -				update_perf_entry(dev, dent,
> -						  &cxlds->part[i].perf);
> -				found = true;
> +			if (!range_contains(&range, &dent->dpa_range))
> +				continue;
> +
> +			found = true;
> +			/*
> +			 * part->handle is from Get DC Config, dent->handle
> +			 * from the CDAT DSMAS entry.
> +			 */
> +			if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1 &&
> +			    dent->handle != part->handle) {
> +				dev_warn(dev,
> +					 "DSMAD handle mismatch: %pra has %u, DSMAS %pra has %u\n",
> +					 &range, part->handle,
> +					 &dent->dpa_range, dent->handle);
>  				break;

For the error path I'd just return here. Maybe there is more after this loop
in future patches that make it useful to break instead?

>  			}
> +
> +			update_perf_entry(dev, dent, &part->perf);
> +			if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1)
> +				part->shareable = dent->shareable;
> +			break;

Come to think of it, can return in this path too.  Then you don't need the
local variable found.

>  		}

>  
>  		if (!found)

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 6/8] cxl/mem: Configure dynamic capacity interrupts
  2026-09-08 10:15 ` [RESEND PATCH v13 6/8] cxl/mem: Configure dynamic capacity interrupts Anisa Su
  2026-09-08 10:43   ` sashiko-bot
@ 2026-09-08 22:14   ` Jonathan Cameron
  2026-09-11 18:21     ` Anisa Su
  1 sibling, 1 reply; 33+ messages in thread
From: Jonathan Cameron @ 2026-09-08 22:14 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Ira Weiny, Anisa Su,
	Wonjae Lee, Junhee Park, Heesoo Kim

On Tue,  8 Sep 2026 03:15:10 -0700
Anisa Su <anisa.su887@gmail.com> wrote:

> From: Ira Weiny <iweiny@kernel.org>
> 
> Dynamic Capacity Devices (DCD) support extent change notifications
> through the event log mechanism. The interrupt mailbox commands were
> extended in CXL 3.1 to support these notifications. Firmware can't
> configure DCD events to be FW controlled but can retain control of
> memory events.
> 
> Configure DCD event log interrupts on devices supporting dynamic
> capacity. Disable DCD if interrupts are not supported.
> 
> The DCD event log is not drained here. cxl_event_drain_mask() reports
> only the logs the driver can service, and the DCD bit is added by
> the patch introducing DCD event handling. Until then a DCD interrupt
> wakes the event thread, which finds no log it owns and returns.
> 
> Care is taken to preserve the interrupt policy set by the FW if FW first
> has been selected by the BIOS.
> 
> Based on an original patch by Navneet Singh.
> 
> Signed-off-by: Ira Weiny <iweiny@kernel.org>
> Signed-off-by: Anisa Su <anisa.su@samsung.com>
> Tested-by: Wonjae Lee <wj28.lee@samsung.com>
> Tested-by: Junhee Park <jh9934.park@samsung.com>
> Tested-by: Heesoo Kim <habil.kim@samsung.com>
> 

One minor thing inline.  Otherwise LGTM.

Jonathan

> ---
>  drivers/cxl/cxl.h    |   4 +-
>  drivers/cxl/cxlmem.h |   2 +
>  drivers/cxl/pci.c    | 124 ++++++++++++++++++++++++++++++++++++-------
>  3 files changed, 109 insertions(+), 21 deletions(-)
> 
> diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> index cab8ce39f465..d6e02bd0cf50 100644
> --- a/drivers/cxl/cxl.h
> +++ b/drivers/cxl/cxl.h
> @@ -192,11 +192,13 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
>  #define CXLDEV_EVENT_STATUS_WARN		BIT(1)
>  #define CXLDEV_EVENT_STATUS_FAIL		BIT(2)
>  #define CXLDEV_EVENT_STATUS_FATAL		BIT(3)
> +#define CXLDEV_EVENT_STATUS_DCD			BIT(4)
>  
>  #define CXLDEV_EVENT_STATUS_ALL (CXLDEV_EVENT_STATUS_INFO |	\
>  				 CXLDEV_EVENT_STATUS_WARN |	\
>  				 CXLDEV_EVENT_STATUS_FAIL |	\
> -				 CXLDEV_EVENT_STATUS_FATAL)
> +				 CXLDEV_EVENT_STATUS_FATAL |	\
> +				 CXLDEV_EVENT_STATUS_DCD)

See below. I think this define has become a bad idea, making things
more confusing rather than simpler.

> diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> index 7b754af2168d..1ea505b1f40e 100644
> --- a/drivers/cxl/pci.c
> +++ b/drivers/cxl/pci.c
> @@ -510,11 +510,23 @@ static bool cxl_alloc_irq_vectors(struct pci_dev *pdev)
>  	return true;
>  }
>  
> +/* Event logs the driver drains: standard logs when native_cxl */
> +static u32 cxl_event_drain_mask(struct pci_host_bridge *host_bridge)
> +{
> +	if (host_bridge->native_cxl_error)
> +		return CXLDEV_EVENT_STATUS_ALL & ~CXLDEV_EVENT_STATUS_DCD;

This seems a little backwards.    Better I think to just list the logs that
are supported. There are other logs coming and I think we'd want to opt into
them deliberately like you are doing for DCD rather than have them caught
by the _ALL define.

	if (host_bridge->native_cxl_error)
		return CXLDEV_EVENT_STATUS_INFO | CXLDEV_EVENT_STATUS_WARN |
		       CXLDEV_EVENT_STATUS_FAIL | CXLDEV_EVENT_STATUS_FATAL;
> +
> +	return 0;
> +}



^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 8/8] Documentation/cxl: Document DPA partition layout and ordering rules
  2026-09-08 10:15 ` [RESEND PATCH v13 8/8] Documentation/cxl: Document DPA partition layout and ordering rules Anisa Su
@ 2026-09-08 22:17   ` Jonathan Cameron
  2026-09-11 20:39     ` Anisa Su
  2026-09-09 15:19   ` Davidlohr Bueso
  2026-09-12  0:20   ` Gregory Price
  2 siblings, 1 reply; 33+ messages in thread
From: Jonathan Cameron @ 2026-09-08 22:17 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Anisa Su

On Tue,  8 Sep 2026 03:15:12 -0700
Anisa Su <anisa.su887@gmail.com> wrote:

> DC Partitions complicate DPA ordering. Add a DPA Partitions section to
> cxl-driver.rst describing spec-mandated and Linux requirements for the
> layout.
> 
> Suggested-by: Gregory Price <gourry@gourry.net>
> Signed-off-by: Anisa Su <anisa.su@samsung.com>
A couple of minor potential tweaks.  Otherwise LGTM
Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>

> 
> ---
> New patch in v13.
> ---
>  .../driver-api/cxl/linux/cxl-driver.rst       | 38 +++++++++++++++++++
>  1 file changed, 38 insertions(+)
> 
> diff --git a/Documentation/driver-api/cxl/linux/cxl-driver.rst b/Documentation/driver-api/cxl/linux/cxl-driver.rst
> index dd6dd17dc536..f0742d6c86c3 100644
> --- a/Documentation/driver-api/cxl/linux/cxl-driver.rst
> +++ b/Documentation/driver-api/cxl/linux/cxl-driver.rst
> @@ -181,6 +181,44 @@ A Memory Device is a discrete base object that is not a port.  While the
>  physical device it belongs to may also host an `endpoint`, the relationship
>  between an `endpoint` and a `memdev` is not captured in sysfs.
>  
> +DPA Partitions
> +~~~~~~~~~~~~~~
> +A memory device presents its capacity as one flat `Device Physical Address`
> +(DPA) space divided into `partitions`, which Linux lays out in a fixed
> +order::
> +
> +  DPA 0                                                     end
> +  +---------------+---------------+---------------------------+
> +  |      ram      |     pmem      |       dynamic_ram_1       |
> +  +---------------+---------------+---------------------------+
> +  part[0]         part[1]         part[2]
> +
> +Part of that order is required by the CXL specification and part of it is a
> +Linux choice.
> +
> +The `ram` and `pmem` order is mandated.  CXL r4.0 section 8.2.10.9.2.1 "Get
> +Partition Info" (4100h), Table 8-310, mandates that volatile capacity starts
> +at DPA 0 and pmem starts at the DPA immediately following it.
> +
> +Dynamic Capacity partitions only need to be 256MB aligned according to
> +CXL r4.0 section 8.2.10.9.9.1 "Get Dynamic Capacity Configuration"
> +(opcode 4800h), Table 8-347. So a device could leave a gap between ram/pmem
> +(static) capacity and its first DC partition, or between one DC partition
> +and the next.
> +
> +Linux follows the static precedent anyway for the partition it maps: the

Maybe "Linux chooses to only support...

> +first DC partition must begin at the DPA immediately following static
> +capacity -- after pmem, after ram on a device with no pmem, or at DPA 0 on
> +a device with no static capacity at all.
> +
> +Currently, only one dynamic partition is supported. A device may report up
> +to eight (CXL r4.0 Table 8-346); Linux configures the first and exposes it as
> +`dynamic_ram_1`.
> +
> +Support for additional dynamic partitions may be added if devices appear
> +that need it, which is what the `dynamic_ram_1` name leaves room for.  Until
> +then a device offering more than one is still usable, just not in full.
I'd drop this last paragraph. Predicting the future is tricky, even with a may.
Hopefully anyone realises that if something is needed Linux doesn't support
they should propose patches to add it!

Jonathan

> +
>  Port Relationships
>  ~~~~~~~~~~~~~~~~~~
>  In our example described above, there are four host bridges attached to the


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 8/8] Documentation/cxl: Document DPA partition layout and ordering rules
  2026-09-08 10:15 ` [RESEND PATCH v13 8/8] Documentation/cxl: Document DPA partition layout and ordering rules Anisa Su
  2026-09-08 22:17   ` Jonathan Cameron
@ 2026-09-09 15:19   ` Davidlohr Bueso
  2026-09-11 20:38     ` Anisa Su
  2026-09-12  0:20   ` Gregory Price
  2 siblings, 1 reply; 33+ messages in thread
From: Davidlohr Bueso @ 2026-09-09 15:19 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, jic23, dave.jiang, gourry, icheng,
	ming.li, vishal.l.verma, benjamin.cheatham, Anisa Su

On 2026-09-08 03:15, Anisa Su wrote:
> DC Partitions complicate DPA ordering. Add a DPA Partitions section to
> cxl-driver.rst describing spec-mandated and Linux requirements for the
> layout.
> 
> Suggested-by: Gregory Price <gourry@gourry.net>
> Signed-off-by: Anisa Su <anisa.su@samsung.com>

Aside from removing the last paragraph per Jonathan’s feedback, perhaps 
update the maturity map as well to keep this in sync for when big 
features get it.

Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 2/8] cxl/mem: Read dynamic capacity configuration from the device
  2026-09-08 20:43   ` Jonathan Cameron
@ 2026-09-10 23:56     ` Anisa Su
  2026-09-11  0:53       ` Jonathan Cameron
  0 siblings, 1 reply; 33+ messages in thread
From: Anisa Su @ 2026-09-10 23:56 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Anisa Su, linux-cxl, alison.schofield, dave.jiang, gourry, icheng,
	ming.li, vishal.l.verma, dave, benjamin.cheatham, Ira Weiny,
	Wonjae Lee, Junhee Park, Heesoo Kim

On Tue, Sep 08, 2026 at 09:43:10PM +0100, Jonathan Cameron wrote:
> On Tue,  8 Sep 2026 03:15:06 -0700
> Anisa Su <anisa.su887@gmail.com> wrote:
> 
> > From: Ira Weiny <iweiny@kernel.org>
> > 
> > Devices which support Dynamic Capacity (DC) are configured
> > via mailbox commands. CXL r4.0 section 9.13.3 requires the host to issue
> > the Get DC Configuration command in order to properly configure DCDs.
> 
> I don't see text saying quite this and have a concern around what
> might be interpreted as being required should we ever deal deeper
> device resets.  I think you could in practice cache the result of
> this.  There is no specific implication that it 'must' be issued.
> 
> The text I see that is relevant is
>   The basic sequence to utilize Dynamic Capacity include:
> ...
>    * Issue Get Dynamic Capacity Configuration command:  The device reports its
>      number of available regions and each region's base address, length, block
>      size, and DSMAD Handle.
> 
> I read that as meaning that the host does to get the info not that
> it is needed to configure DCDs on the device side.
> 
> Anyhow, I'd just reword a tiny bit to something like
>   CXL r4.0 section 9.13.3 describes the use of the Get DC Configuration command
>   in order to obtain the DCD region/partition characteristics.
> 
Sure, done.

> > 
> > Implement the DC mailbox commands as specified in CXL 4.0 section
> > 8.2.10.9.9 (opcodes 48XXh) to read and store the DCD configuration
> > information. Disable DCD if an invalid configuration is found.
> > 
> > Linux has no support for more than one dynamic capacity partition. Read
> Seems backwards. Perhaps
>   Initial enablement for Linux only supports one dynamic capacity partition.
> 
Makes sense, reworded.

> > all the partitions the device reports but validate only the first, and
> > configure it as 'dynamic ram 1'.
> > 
> > The specification requires that volatile capacity starts at DPA 0 and pmem
> > starts at the DPA immediately following it, but DC partitions only need
> > to be 256MB aligned according to CXL r4.0 section 8.2.10.9.9.1 Table 8-347.
> > So a device could leave a gap between ram/pmem (static) capacity and its first
> > DC partition, or between one DC partition and the next.
> > 
> > However, Linux follows the precedent set by PMEM/RAM partitions and requires the
> > first DC partition to begin at the DPA immediately following static
> > capacity.
> > 
> > Based on an original patch by Navneet Singh.
> > 
> > Signed-off-by: Ira Weiny <iweiny@kernel.org>
> > Signed-off-by: Anisa Su <anisa.su@samsung.com>
> > Tested-by: Wonjae Lee <wj28.lee@samsung.com>
> > Tested-by: Junhee Park <jh9934.park@samsung.com>
> > Tested-by: Heesoo Kim <habil.kim@samsung.com>
> 
> A couple of other things inline.
> 
> Thanks,
> 
> Jonathan
> 
> 
> > diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c
> > index 199bb986d674..a484e23b2b3a 100644
> > --- a/drivers/cxl/core/mbox.c
> > +++ b/drivers/cxl/core/mbox.c
> > @@ -1349,6 +1349,241 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd)
> >  	return -EBUSY;
> >  }
> >  
> 
> ...
> 
> > +static int cxl_dc_check(struct device *dev, struct cxl_dc_partition_info *part,
> > +			struct cxl_dc_partition *dev_part)
> > +{
> > +	u64 blk_size = le64_to_cpu(dev_part->block_size);
> > +	u64 len = le64_to_cpu(dev_part->length);
> > +
> > +	/*
> > +	 * Not an error; leave the entry empty. A partially zeroed partition
> > +	 * is rejected by the checks below. CXL r4.0 Table 8-347.
> > +	 */
> > +	if (cxl_dc_partition_unavailable(dev_part)) {
> > +		*part = (struct cxl_dc_partition_info) { };
> > +		dev_dbg(dev, "Partition 0 unavailable for DC\n");
> > +		return 0;
> > +	}
> > +
> > +	*part = (struct cxl_dc_partition_info) {
> > +		.start = le64_to_cpu(dev_part->base),
> > +		.size = le64_to_cpu(dev_part->decode_length) * CXL_CAPACITY_MULTIPLIER,
> > +	};
> > +
> > +	/*
> > +	 * Block size is a power of 2 and a multiple of 40h. is_power_of_2()
> > +	 * takes an unsigned long, which truncates blk_size on 32 bit
> 
> oh. That's ugly.  Worth just fixing?  I guess we don't want a general
> macro like that on the critical path for this patch.  Perhaps one to revisit.
>
+ 1 for revisiting.

> > +	 */
> > +	if (blk_size == 0 || (blk_size & (blk_size - 1)) ||
> > +	    blk_size % CXL_DCD_BLOCK_LINE_SIZE) {
> > +		dev_err(dev, "DC partition 0 invalid block size %#llx\n", blk_size);
> > +		return -EINVAL;
> > +	}
> 
> ...
> 
> 
> > +/* Returns the number of partitions in dc_resp or -ERRNO */
> > +static int cxl_get_dc_config(struct cxl_mailbox *mbox, u8 start_partition,
> > +			     u8 partition_count,
> > +			     struct cxl_mbox_get_dc_config_out *dc_resp,
> > +			     size_t dc_resp_size)
> > +{
> > +	struct cxl_mbox_get_dc_config_in get_dc = (struct cxl_mbox_get_dc_config_in) {
> > +		.partition_count = partition_count,
> > +		.start_partition_index = start_partition,
> > +	};
> > +	struct cxl_mbox_cmd mbox_cmd = (struct cxl_mbox_cmd) {
> > +		.opcode = CXL_MBOX_OP_GET_DC_CONFIG,
> > +		.payload_in = &get_dc,
> > +		.size_in = sizeof(get_dc),
> > +		.size_out = dc_resp_size,
> > +		.payload_out = dc_resp,
> > +		/* The device must return at least the fixed header */
> > +		.min_out = sizeof(*dc_resp),
> > +	};
> > +	size_t expected_sz;
> > +	int rc;
> > +
> > +	rc = cxl_internal_send_cmd(mbox, &mbox_cmd);
> > +	if (rc < 0)
> > +		return rc;
> > +
> > +	/* A DCD reports between 1 and 8 partitions */
> > +	if (dc_resp->avail_partition_count == 0 ||
> > +	    dc_resp->avail_partition_count > CXL_MAX_DC_PARTITIONS) {
> 
> This strikes me as a compatibility issue waiting to happen.  Today the spec
> supports 8, but maybe in future it will support more and I'd not consider
> that a backwards compatibility break (which this would make it).  I'd clamp
> to CXL_MAX_DC_PARITIONS and maybe print with dev_info() if you see something
> bigger in the wild.
> 
I see... I did the below and moved it to the caller
cxl_dev_dc_identify() so the dev_err/dev_info messages are only printed
once, since the current function is called in a loop.

		avail = dc_resp->avail_partition_count;
		if (avail == 0) {
			dev_err(dev, "Device reported no DC partitions\n");
			return -EIO;
		}

		/* More than Linux handles is not a reason to refuse DCD */
		if (avail > CXL_MAX_DC_PARTITIONS) {
			dev_info(dev, "Device reported %u DC partitions, reading the first %u\n",
				 avail, CXL_MAX_DC_PARTITIONS);
			avail = CXL_MAX_DC_PARTITIONS;
		}
> > +		dev_err(mbox->host,
> > +			"Device reported %u available DC partitions, expected 1 to %u\n",
> > +			dc_resp->avail_partition_count, CXL_MAX_DC_PARTITIONS);
> > +		return -EIO;
> > +	}
> > +
> ...
> 
> 
> > +	/*
> > +	 * The payload carries trailing extent/tag count fields after the
> > +	 * partition array (CXL r4.0 Table 8-346) which the driver ignores, so
> > +	 * the response is at least, not exactly, expected_sz.
> > +	 */
> 
> More generally we shouldn't be checking that a record isn't longer than expected
> because of similar backwards compat concerns.  Check is always that it is at least
> as large as we need.
> 
Reworded to just:

/* The trailing extent/tag counts (CXL r4.0 Table 8-346) are not read */

so it doesn't imply that if we were to read the trailing fields, the
check here would be mbox.size_out == expected_sz

> > +	expected_sz = struct_size(dc_resp, partition,
> > +				  dc_resp->partitions_returned);
> > +
> > +	if (mbox_cmd.size_out < expected_sz) {
> > +		dev_err(mbox->host,
> > +			"Payload size %zu less than expected %zu for %u partitions\n",
> > +			mbox_cmd.size_out,
> > +			expected_sz,
> > +			dc_resp->partitions_returned);
> > +		return -EIO;
> > +	}
> > +
> > +	dev_dbg(mbox->host, "Read %d/%d DC partitions\n",
> > +		dc_resp->partitions_returned, dc_resp->avail_partition_count);
> > +	return dc_resp->partitions_returned;
> > +}
> > +
> 
> > +/**
> > + * cxl_dev_dc_identify() - Reads the dynamic capacity information from the
> > + *                         device.
> > + * @mbox: Mailbox to query
> > + * @dc_info: The dynamic partition information to return
> > + *
> > + * Read every partition the device reports, but validate only the first:
> > + * Linux maps partition 0 and nothing else, so a defect in capacity the
> > + * driver never touches is not a reason to refuse the device dynamic
> > + * capacity.  The remaining entries of @partitions are left unset.
> > + *
> > + * Return: 0 if identify was executed successfully, -ERRNO on error.
> > + *         on error only dc_info is left unchanged.
> > + */
> > +int cxl_dev_dc_identify(struct cxl_mailbox *mbox,
> > +			struct cxl_dc_partition_info *dc_info)
> > +{
> > +	struct cxl_dc_partition_info partitions[CXL_MAX_DC_PARTITIONS] = { };
> > +	struct cxl_mbox_get_dc_config_out *dc_resp __free(kfree) = NULL;
> > +	struct device *dev = mbox->host;
> > +	u8 start_partition;
> > +	u8 num_partitions;
> > +	u8 partition_count;
> > +	size_t dc_resp_size;
> > +
> > +	/*
> > +	 * Bound requested number of partitions by mailbox payload size. The
> > +	 * 256 byte spec minimum, verified in cxl_pci_setup_mailbox(), keeps
> > +	 * the subtraction below from underflowing.
> > +	 */
> > +	partition_count = min_t(size_t, CXL_MAX_DC_PARTITIONS,
> > +				(mbox->payload_size - sizeof(*dc_resp) -
> > +				 sizeof(struct cxl_mbox_get_dc_config_tail)) /
> > +				sizeof(struct cxl_dc_partition));
> 
> I doubt we need min_t() rather than min() but maybe I'm missing something.
> Pretty much anything can be compared with small constants without needing
> to specify the type used.
> 
I think min() should be fine. Changed to min().

Thanks,
Anisa
> > +	dc_resp_size = struct_size(dc_resp, partition, partition_count) +
> > +		       sizeof(struct cxl_mbox_get_dc_config_tail);
> > +

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 3/8] cxl/cdat: Gather DSMAS data for DCD partitions
  2026-09-08 20:52   ` Jonathan Cameron
@ 2026-09-11  0:02     ` Anisa Su
  2026-09-11  0:56       ` Jonathan Cameron
  0 siblings, 1 reply; 33+ messages in thread
From: Anisa Su @ 2026-09-11  0:02 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Anisa Su, linux-cxl, alison.schofield, dave.jiang, gourry, icheng,
	ming.li, vishal.l.verma, dave, benjamin.cheatham, Ira Weiny,
	Wonjae Lee, Junhee Park, Heesoo Kim

On Tue, Sep 08, 2026 at 09:52:00PM +0100, Jonathan Cameron wrote:
> On Tue,  8 Sep 2026 03:15:07 -0700
> Anisa Su <anisa.su887@gmail.com> wrote:
> 
> > From: Ira Weiny <iweiny@kernel.org>
> > 
> > Additional DCD partition (AKA region) information is contained in the
> > DSMAS CDAT tables, including performance and shareable attributes.
> > 
> > Match DCD partitions with DSMAS tables and store the meta data.
> > 
> > Signed-off-by: Ira Weiny <iweiny@kernel.org>
> > Co-developed-by: Anisa Su <anisa.su@samsung.com>
> > Signed-off-by: Anisa Su <anisa.su@samsung.com>
> > Tested-by: Wonjae Lee <wj28.lee@samsung.com>
> > Tested-by: Junhee Park <jh9934.park@samsung.com>
> > Tested-by: Heesoo Kim <habil.kim@samsung.com>
> > 
> Minor thing inline. I think we can take a bit of refactoring
> you did a little further and end up with simpler code.
> 
> > ---
> >  drivers/cxl/core/cdat.c   | 32 +++++++++++++++++++++++++-------
> >  drivers/cxl/core/hdm.c    |  1 +
> >  drivers/cxl/core/mbox.c   |  9 +++++++++
> >  drivers/cxl/core/memdev.c | 17 ++++++++++-------
> >  drivers/cxl/cxlmem.h      |  2 ++
> >  include/cxl/cxl.h         |  4 ++++
> >  6 files changed, 51 insertions(+), 14 deletions(-)
> > 
> > diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
> > index 5c9f07262513..05058d4520f2 100644
> > --- a/drivers/cxl/core/cdat.c
> > +++ b/drivers/cxl/core/cdat.c
> > @@ -17,6 +17,7 @@ struct dsmas_entry {
> >  	struct access_coordinate cdat_coord[ACCESS_COORDINATE_MAX];
> >  	int entries;
> >  	int qos_class;
> > +	bool shareable;
> >  };
> >  
> >  static u32 cdat_normalize(u16 entry, u64 base, u8 type)
> > @@ -74,6 +75,8 @@ static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg,
> >  		return -ENOMEM;
> >  
> >  	dent->handle = dsmas->dsmad_handle;
> > +	/* Shareable is CDAT 1.03 and later, DSMAS Flags bit 3 */
> > +	dent->shareable = dsmas->flags & ACPI_CDAT_DSMAS_SHAREABLE;
> >  	dent->dpa_range.start = le64_to_cpu((__force __le64)dsmas->dpa_base_address);
> >  	dent->dpa_range.end = le64_to_cpu((__force __le64)dsmas->dpa_base_address) +
> >  			      le64_to_cpu((__force __le64)dsmas->dpa_length) - 1;
> > @@ -266,18 +269,33 @@ static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds,
> >  		bool found = false;
> >  
> >  		for (int i = 0; i < cxlds->nr_partitions; i++) {
> > -			struct resource *res = &cxlds->part[i].res;
> > +			struct cxl_dpa_partition *part = &cxlds->part[i];
> >  			struct range range = {
> > -				.start = res->start,
> > -				.end = res->end,
> > +				.start = part->res.start,
> > +				.end = part->res.end,
> >  			};
> >  
> > -			if (range_contains(&range, &dent->dpa_range)) {
> > -				update_perf_entry(dev, dent,
> > -						  &cxlds->part[i].perf);
> > -				found = true;
> > +			if (!range_contains(&range, &dent->dpa_range))
> > +				continue;
> > +
> > +			found = true;
> > +			/*
> > +			 * part->handle is from Get DC Config, dent->handle
> > +			 * from the CDAT DSMAS entry.
> > +			 */
> > +			if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1 &&
> > +			    dent->handle != part->handle) {
> > +				dev_warn(dev,
> > +					 "DSMAD handle mismatch: %pra has %u, DSMAS %pra has %u\n",
> > +					 &range, part->handle,
> > +					 &dent->dpa_range, dent->handle);
> >  				break;
> 
> For the error path I'd just return here. Maybe there is more after this loop
> in future patches that make it useful to break instead?
> 
> >  			}
> > +
> > +			update_perf_entry(dev, dent, &part->perf);
> > +			if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1)
> > +				part->shareable = dent->shareable;
> > +			break;
> 
> Come to think of it, can return in this path too.  Then you don't need the
> local variable found.
> 
Ah the break in both spots is so we print a debug message if no
partition is found matching the dsmas entry:

if (!found)
	dev_dbg(dev, "no partition for dsmas dpa: %pra\n",
		&dent->dpa_range);

It got cut off in the diff.

> >  		}
> 
> >  
> >  		if (!found)

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 2/8] cxl/mem: Read dynamic capacity configuration from the device
  2026-09-10 23:56     ` Anisa Su
@ 2026-09-11  0:53       ` Jonathan Cameron
  2026-09-11 16:38         ` Anisa Su
  0 siblings, 1 reply; 33+ messages in thread
From: Jonathan Cameron @ 2026-09-11  0:53 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Ira Weiny, Wonjae Lee,
	Junhee Park, Heesoo Kim

...

> > > +	/* A DCD reports between 1 and 8 partitions */
> > > +	if (dc_resp->avail_partition_count == 0 ||
> > > +	    dc_resp->avail_partition_count > CXL_MAX_DC_PARTITIONS) {  
> > 
> > This strikes me as a compatibility issue waiting to happen.  Today the spec
> > supports 8, but maybe in future it will support more and I'd not consider
> > that a backwards compatibility break (which this would make it).  I'd clamp
> > to CXL_MAX_DC_PARITIONS and maybe print with dev_info() if you see something
> > bigger in the wild.
> >   
> I see... I did the below and moved it to the caller
> cxl_dev_dc_identify() so the dev_err/dev_info messages are only printed
> once, since the current function is called in a loop.
> 
> 		avail = dc_resp->avail_partition_count;
> 		if (avail == 0) {
> 			dev_err(dev, "Device reported no DC partitions\n");
> 			return -EIO;
> 		}
> 
> 		/* More than Linux handles is not a reason to refuse DCD */
> 		if (avail > CXL_MAX_DC_PARTITIONS) {
> 			dev_info(dev, "Device reported %u DC partitions, reading the first %u\n",
> 				 avail, CXL_MAX_DC_PARTITIONS);
> 			avail = CXL_MAX_DC_PARTITIONS;
> 		}

Given you don't do anything with most of them I'd just do

		avail = min(avail, CXL_MAX_DC_PARTITIONS);

and not print anything.

Thanks,

Jonathan

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 3/8] cxl/cdat: Gather DSMAS data for DCD partitions
  2026-09-11  0:02     ` Anisa Su
@ 2026-09-11  0:56       ` Jonathan Cameron
  2026-09-11 16:37         ` Anisa Su
  0 siblings, 1 reply; 33+ messages in thread
From: Jonathan Cameron @ 2026-09-11  0:56 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, dave.jiang, gourry, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Ira Weiny, Wonjae Lee,
	Junhee Park, Heesoo Kim

On Fri, 11 Sep 2026 09:02:25 +0900
Anisa Su <anisa.su887@gmail.com> wrote:

> On Tue, Sep 08, 2026 at 09:52:00PM +0100, Jonathan Cameron wrote:
> > On Tue,  8 Sep 2026 03:15:07 -0700
> > Anisa Su <anisa.su887@gmail.com> wrote:
> >   
> > > From: Ira Weiny <iweiny@kernel.org>
> > > 
> > > Additional DCD partition (AKA region) information is contained in the
> > > DSMAS CDAT tables, including performance and shareable attributes.
> > > 
> > > Match DCD partitions with DSMAS tables and store the meta data.
> > > 
> > > Signed-off-by: Ira Weiny <iweiny@kernel.org>
> > > Co-developed-by: Anisa Su <anisa.su@samsung.com>
> > > Signed-off-by: Anisa Su <anisa.su@samsung.com>
> > > Tested-by: Wonjae Lee <wj28.lee@samsung.com>
> > > Tested-by: Junhee Park <jh9934.park@samsung.com>
> > > Tested-by: Heesoo Kim <habil.kim@samsung.com>
> > >   
> > Minor thing inline. I think we can take a bit of refactoring
> > you did a little further and end up with simpler code.
> >   
> > > ---
> > >  drivers/cxl/core/cdat.c   | 32 +++++++++++++++++++++++++-------
> > >  drivers/cxl/core/hdm.c    |  1 +
> > >  drivers/cxl/core/mbox.c   |  9 +++++++++
> > >  drivers/cxl/core/memdev.c | 17 ++++++++++-------
> > >  drivers/cxl/cxlmem.h      |  2 ++
> > >  include/cxl/cxl.h         |  4 ++++
> > >  6 files changed, 51 insertions(+), 14 deletions(-)
> > > 
> > > diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
> > > index 5c9f07262513..05058d4520f2 100644
> > > --- a/drivers/cxl/core/cdat.c
> > > +++ b/drivers/cxl/core/cdat.c
> > > @@ -17,6 +17,7 @@ struct dsmas_entry {
> > >  	struct access_coordinate cdat_coord[ACCESS_COORDINATE_MAX];
> > >  	int entries;
> > >  	int qos_class;
> > > +	bool shareable;
> > >  };
> > >  
> > >  static u32 cdat_normalize(u16 entry, u64 base, u8 type)
> > > @@ -74,6 +75,8 @@ static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg,
> > >  		return -ENOMEM;
> > >  
> > >  	dent->handle = dsmas->dsmad_handle;
> > > +	/* Shareable is CDAT 1.03 and later, DSMAS Flags bit 3 */
> > > +	dent->shareable = dsmas->flags & ACPI_CDAT_DSMAS_SHAREABLE;
> > >  	dent->dpa_range.start = le64_to_cpu((__force __le64)dsmas->dpa_base_address);
> > >  	dent->dpa_range.end = le64_to_cpu((__force __le64)dsmas->dpa_base_address) +
> > >  			      le64_to_cpu((__force __le64)dsmas->dpa_length) - 1;
> > > @@ -266,18 +269,33 @@ static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds,
> > >  		bool found = false;
> > >  
> > >  		for (int i = 0; i < cxlds->nr_partitions; i++) {
> > > -			struct resource *res = &cxlds->part[i].res;
> > > +			struct cxl_dpa_partition *part = &cxlds->part[i];
> > >  			struct range range = {
> > > -				.start = res->start,
> > > -				.end = res->end,
> > > +				.start = part->res.start,
> > > +				.end = part->res.end,
> > >  			};
> > >  
> > > -			if (range_contains(&range, &dent->dpa_range)) {
> > > -				update_perf_entry(dev, dent,
> > > -						  &cxlds->part[i].perf);
> > > -				found = true;
> > > +			if (!range_contains(&range, &dent->dpa_range))
> > > +				continue;
> > > +
> > > +			found = true;
> > > +			/*
> > > +			 * part->handle is from Get DC Config, dent->handle
> > > +			 * from the CDAT DSMAS entry.
> > > +			 */
> > > +			if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1 &&
> > > +			    dent->handle != part->handle) {
> > > +				dev_warn(dev,
> > > +					 "DSMAD handle mismatch: %pra has %u, DSMAS %pra has %u\n",
> > > +					 &range, part->handle,
> > > +					 &dent->dpa_range, dent->handle);
> > >  				break;  
> > 
> > For the error path I'd just return here. Maybe there is more after this loop
> > in future patches that make it useful to break instead?
> >   
> > >  			}
> > > +
> > > +			update_perf_entry(dev, dent, &part->perf);
> > > +			if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1)
> > > +				part->shareable = dent->shareable;
> > > +			break;  
> > 
> > Come to think of it, can return in this path too.  Then you don't need the
> > local variable found.
> >   
> Ah the break in both spots is so we print a debug message if no
> partition is found matching the dsmas entry:
> 
> if (!found)
> 	dev_dbg(dev, "no partition for dsmas dpa: %pra\n",
> 		&dent->dpa_range);
> 
> It got cut off in the diff.

For both break paths, found == true

Jonathan

> 
> > >  		}  
> >   
> > >  
> > >  		if (!found)  


^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 3/8] cxl/cdat: Gather DSMAS data for DCD partitions
  2026-09-11  0:56       ` Jonathan Cameron
@ 2026-09-11 16:37         ` Anisa Su
  0 siblings, 0 replies; 33+ messages in thread
From: Anisa Su @ 2026-09-11 16:37 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Anisa Su, linux-cxl, alison.schofield, dave.jiang, gourry, icheng,
	ming.li, vishal.l.verma, dave, benjamin.cheatham, Ira Weiny,
	Wonjae Lee, Junhee Park, Heesoo Kim

On Fri, Sep 11, 2026 at 01:56:25AM +0100, Jonathan Cameron wrote:
> On Fri, 11 Sep 2026 09:02:25 +0900
> Anisa Su <anisa.su887@gmail.com> wrote:
> 
> > On Tue, Sep 08, 2026 at 09:52:00PM +0100, Jonathan Cameron wrote:
> > > On Tue,  8 Sep 2026 03:15:07 -0700
> > > Anisa Su <anisa.su887@gmail.com> wrote:
> > >   
> > > > From: Ira Weiny <iweiny@kernel.org>
> > > > 
> > > > Additional DCD partition (AKA region) information is contained in the
> > > > DSMAS CDAT tables, including performance and shareable attributes.
> > > > 
> > > > Match DCD partitions with DSMAS tables and store the meta data.
> > > > 
> > > > Signed-off-by: Ira Weiny <iweiny@kernel.org>
> > > > Co-developed-by: Anisa Su <anisa.su@samsung.com>
> > > > Signed-off-by: Anisa Su <anisa.su@samsung.com>
> > > > Tested-by: Wonjae Lee <wj28.lee@samsung.com>
> > > > Tested-by: Junhee Park <jh9934.park@samsung.com>
> > > > Tested-by: Heesoo Kim <habil.kim@samsung.com>
> > > >   
> > > Minor thing inline. I think we can take a bit of refactoring
> > > you did a little further and end up with simpler code.
> > >   
> > > > ---
> > > >  drivers/cxl/core/cdat.c   | 32 +++++++++++++++++++++++++-------
> > > >  drivers/cxl/core/hdm.c    |  1 +
> > > >  drivers/cxl/core/mbox.c   |  9 +++++++++
> > > >  drivers/cxl/core/memdev.c | 17 ++++++++++-------
> > > >  drivers/cxl/cxlmem.h      |  2 ++
> > > >  include/cxl/cxl.h         |  4 ++++
> > > >  6 files changed, 51 insertions(+), 14 deletions(-)
> > > > 
> > > > diff --git a/drivers/cxl/core/cdat.c b/drivers/cxl/core/cdat.c
> > > > index 5c9f07262513..05058d4520f2 100644
> > > > --- a/drivers/cxl/core/cdat.c
> > > > +++ b/drivers/cxl/core/cdat.c
> > > > @@ -17,6 +17,7 @@ struct dsmas_entry {
> > > >  	struct access_coordinate cdat_coord[ACCESS_COORDINATE_MAX];
> > > >  	int entries;
> > > >  	int qos_class;
> > > > +	bool shareable;
> > > >  };
> > > >  
> > > >  static u32 cdat_normalize(u16 entry, u64 base, u8 type)
> > > > @@ -74,6 +75,8 @@ static int cdat_dsmas_handler(union acpi_subtable_headers *header, void *arg,
> > > >  		return -ENOMEM;
> > > >  
> > > >  	dent->handle = dsmas->dsmad_handle;
> > > > +	/* Shareable is CDAT 1.03 and later, DSMAS Flags bit 3 */
> > > > +	dent->shareable = dsmas->flags & ACPI_CDAT_DSMAS_SHAREABLE;
> > > >  	dent->dpa_range.start = le64_to_cpu((__force __le64)dsmas->dpa_base_address);
> > > >  	dent->dpa_range.end = le64_to_cpu((__force __le64)dsmas->dpa_base_address) +
> > > >  			      le64_to_cpu((__force __le64)dsmas->dpa_length) - 1;
> > > > @@ -266,18 +269,33 @@ static void cxl_memdev_set_qos_class(struct cxl_dev_state *cxlds,
> > > >  		bool found = false;
> > > >  
> > > >  		for (int i = 0; i < cxlds->nr_partitions; i++) {
> > > > -			struct resource *res = &cxlds->part[i].res;
> > > > +			struct cxl_dpa_partition *part = &cxlds->part[i];
> > > >  			struct range range = {
> > > > -				.start = res->start,
> > > > -				.end = res->end,
> > > > +				.start = part->res.start,
> > > > +				.end = part->res.end,
> > > >  			};
> > > >  
> > > > -			if (range_contains(&range, &dent->dpa_range)) {
> > > > -				update_perf_entry(dev, dent,
> > > > -						  &cxlds->part[i].perf);
> > > > -				found = true;
> > > > +			if (!range_contains(&range, &dent->dpa_range))
> > > > +				continue;
> > > > +
> > > > +			found = true;
> > > > +			/*
> > > > +			 * part->handle is from Get DC Config, dent->handle
> > > > +			 * from the CDAT DSMAS entry.
> > > > +			 */
> > > > +			if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1 &&
> > > > +			    dent->handle != part->handle) {
> > > > +				dev_warn(dev,
> > > > +					 "DSMAD handle mismatch: %pra has %u, DSMAS %pra has %u\n",
> > > > +					 &range, part->handle,
> > > > +					 &dent->dpa_range, dent->handle);
> > > >  				break;  
> > > 
> > > For the error path I'd just return here. Maybe there is more after this loop
> > > in future patches that make it useful to break instead?
> > >   
> > > >  			}
> > > > +
> > > > +			update_perf_entry(dev, dent, &part->perf);
> > > > +			if (part->mode == CXL_PARTMODE_DYNAMIC_RAM_1)
> > > > +				part->shareable = dent->shareable;
> > > > +			break;  
> > > 
> > > Come to think of it, can return in this path too.  Then you don't need the
> > > local variable found.
> > >   
> > Ah the break in both spots is so we print a debug message if no
> > partition is found matching the dsmas entry:
> > 
> > if (!found)
> > 	dev_dbg(dev, "no partition for dsmas dpa: %pra\n",
> > 		&dent->dpa_range);
> > 
> > It got cut off in the diff.
> 
> For both break paths, found == true
> 
> Jonathan
> 
Woah that was really dumb of me. Pretend I agreed with you the first
time.

Anisa
> > 
> > > >  		}  
> > >   
> > > >  
> > > >  		if (!found)  
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 2/8] cxl/mem: Read dynamic capacity configuration from the device
  2026-09-11  0:53       ` Jonathan Cameron
@ 2026-09-11 16:38         ` Anisa Su
  0 siblings, 0 replies; 33+ messages in thread
From: Anisa Su @ 2026-09-11 16:38 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Anisa Su, linux-cxl, alison.schofield, dave.jiang, gourry, icheng,
	ming.li, vishal.l.verma, dave, benjamin.cheatham, Ira Weiny,
	Wonjae Lee, Junhee Park, Heesoo Kim

On Fri, Sep 11, 2026 at 01:53:48AM +0100, Jonathan Cameron wrote:
> ...
> 
> > > > +	/* A DCD reports between 1 and 8 partitions */
> > > > +	if (dc_resp->avail_partition_count == 0 ||
> > > > +	    dc_resp->avail_partition_count > CXL_MAX_DC_PARTITIONS) {  
> > > 
> > > This strikes me as a compatibility issue waiting to happen.  Today the spec
> > > supports 8, but maybe in future it will support more and I'd not consider
> > > that a backwards compatibility break (which this would make it).  I'd clamp
> > > to CXL_MAX_DC_PARITIONS and maybe print with dev_info() if you see something
> > > bigger in the wild.
> > >   
> > I see... I did the below and moved it to the caller
> > cxl_dev_dc_identify() so the dev_err/dev_info messages are only printed
> > once, since the current function is called in a loop.
> > 
> > 		avail = dc_resp->avail_partition_count;
> > 		if (avail == 0) {
> > 			dev_err(dev, "Device reported no DC partitions\n");
> > 			return -EIO;
> > 		}
> > 
> > 		/* More than Linux handles is not a reason to refuse DCD */
> > 		if (avail > CXL_MAX_DC_PARTITIONS) {
> > 			dev_info(dev, "Device reported %u DC partitions, reading the first %u\n",
> > 				 avail, CXL_MAX_DC_PARTITIONS);
> > 			avail = CXL_MAX_DC_PARTITIONS;
> > 		}
> 
> Given you don't do anything with most of them I'd just do
> 
> 		avail = min(avail, CXL_MAX_DC_PARTITIONS);
> 
> and not print anything.
> 
> Thanks,
> 
> Jonathan

Makes sense. Done.

Thanks,
Anisa

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 6/8] cxl/mem: Configure dynamic capacity interrupts
  2026-09-08 22:14   ` Jonathan Cameron
@ 2026-09-11 18:21     ` Anisa Su
  0 siblings, 0 replies; 33+ messages in thread
From: Anisa Su @ 2026-09-11 18:21 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Anisa Su, linux-cxl, alison.schofield, dave.jiang, gourry, icheng,
	ming.li, vishal.l.verma, dave, benjamin.cheatham, Ira Weiny,
	Wonjae Lee, Junhee Park, Heesoo Kim

On Tue, Sep 08, 2026 at 11:14:14PM +0100, Jonathan Cameron wrote:
> On Tue,  8 Sep 2026 03:15:10 -0700
> Anisa Su <anisa.su887@gmail.com> wrote:
> 
> > From: Ira Weiny <iweiny@kernel.org>
> > 
> > Dynamic Capacity Devices (DCD) support extent change notifications
> > through the event log mechanism. The interrupt mailbox commands were
> > extended in CXL 3.1 to support these notifications. Firmware can't
> > configure DCD events to be FW controlled but can retain control of
> > memory events.
> > 
> > Configure DCD event log interrupts on devices supporting dynamic
> > capacity. Disable DCD if interrupts are not supported.
> > 
> > The DCD event log is not drained here. cxl_event_drain_mask() reports
> > only the logs the driver can service, and the DCD bit is added by
> > the patch introducing DCD event handling. Until then a DCD interrupt
> > wakes the event thread, which finds no log it owns and returns.
> > 
> > Care is taken to preserve the interrupt policy set by the FW if FW first
> > has been selected by the BIOS.
> > 
> > Based on an original patch by Navneet Singh.
> > 
> > Signed-off-by: Ira Weiny <iweiny@kernel.org>
> > Signed-off-by: Anisa Su <anisa.su@samsung.com>
> > Tested-by: Wonjae Lee <wj28.lee@samsung.com>
> > Tested-by: Junhee Park <jh9934.park@samsung.com>
> > Tested-by: Heesoo Kim <habil.kim@samsung.com>
> > 
> 
> One minor thing inline.  Otherwise LGTM.
> 
> Jonathan
> 
> > ---
> >  drivers/cxl/cxl.h    |   4 +-
> >  drivers/cxl/cxlmem.h |   2 +
> >  drivers/cxl/pci.c    | 124 ++++++++++++++++++++++++++++++++++++-------
> >  3 files changed, 109 insertions(+), 21 deletions(-)
> > 
> > diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
> > index cab8ce39f465..d6e02bd0cf50 100644
> > --- a/drivers/cxl/cxl.h
> > +++ b/drivers/cxl/cxl.h
> > @@ -192,11 +192,13 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
> >  #define CXLDEV_EVENT_STATUS_WARN		BIT(1)
> >  #define CXLDEV_EVENT_STATUS_FAIL		BIT(2)
> >  #define CXLDEV_EVENT_STATUS_FATAL		BIT(3)
> > +#define CXLDEV_EVENT_STATUS_DCD			BIT(4)
> >  
> >  #define CXLDEV_EVENT_STATUS_ALL (CXLDEV_EVENT_STATUS_INFO |	\
> >  				 CXLDEV_EVENT_STATUS_WARN |	\
> >  				 CXLDEV_EVENT_STATUS_FAIL |	\
> > -				 CXLDEV_EVENT_STATUS_FATAL)
> > +				 CXLDEV_EVENT_STATUS_FATAL |	\
> > +				 CXLDEV_EVENT_STATUS_DCD)
> 
> See below. I think this define has become a bad idea, making things
> more confusing rather than simpler.
> 
> > diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> > index 7b754af2168d..1ea505b1f40e 100644
> > --- a/drivers/cxl/pci.c
> > +++ b/drivers/cxl/pci.c
> > @@ -510,11 +510,23 @@ static bool cxl_alloc_irq_vectors(struct pci_dev *pdev)
> >  	return true;
> >  }
> >  
> > +/* Event logs the driver drains: standard logs when native_cxl */
> > +static u32 cxl_event_drain_mask(struct pci_host_bridge *host_bridge)
> > +{
> > +	if (host_bridge->native_cxl_error)
> > +		return CXLDEV_EVENT_STATUS_ALL & ~CXLDEV_EVENT_STATUS_DCD;
> 
> This seems a little backwards.    Better I think to just list the logs that
> are supported. There are other logs coming and I think we'd want to opt into
> them deliberately like you are doing for DCD rather than have them caught
> by the _ALL define.
> 
> 	if (host_bridge->native_cxl_error)
> 		return CXLDEV_EVENT_STATUS_INFO | CXLDEV_EVENT_STATUS_WARN |
> 		       CXLDEV_EVENT_STATUS_FAIL | CXLDEV_EVENT_STATUS_FATAL;
Applied.

Thanks,
Anisa
> > +
> > +	return 0;
> > +}
> 
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 8/8] Documentation/cxl: Document DPA partition layout and ordering rules
  2026-09-09 15:19   ` Davidlohr Bueso
@ 2026-09-11 20:38     ` Anisa Su
  2026-09-11 20:50       ` Davidlohr Bueso
  0 siblings, 1 reply; 33+ messages in thread
From: Anisa Su @ 2026-09-11 20:38 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: Anisa Su, linux-cxl, alison.schofield, jic23, dave.jiang, gourry,
	icheng, ming.li, vishal.l.verma, benjamin.cheatham

On Wed, Sep 09, 2026 at 08:19:54AM -0700, Davidlohr Bueso wrote:
> On 2026-09-08 03:15, Anisa Su wrote:
> > DC Partitions complicate DPA ordering. Add a DPA Partitions section to
> > cxl-driver.rst describing spec-mandated and Linux requirements for the
> > layout.
> > 
> > Suggested-by: Gregory Price <gourry@gourry.net>
> > Signed-off-by: Anisa Su <anisa.su@samsung.com>
> 
> Aside from removing the last paragraph per Jonathan’s feedback, perhaps
> update the maturity map as well to keep this in sync for when big features
> get it.
> 
> Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>

For the maturity map part, I have another commit at the end of the full series
that describes how DCD works from extent record --> dax device
creation/tearing down, so I could update the maturity map in that
commit, when DCD becomes functional.

Thanks,
Anisa

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 8/8] Documentation/cxl: Document DPA partition layout and ordering rules
  2026-09-08 22:17   ` Jonathan Cameron
@ 2026-09-11 20:39     ` Anisa Su
  0 siblings, 0 replies; 33+ messages in thread
From: Anisa Su @ 2026-09-11 20:39 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Anisa Su, linux-cxl, alison.schofield, dave.jiang, gourry, icheng,
	ming.li, vishal.l.verma, dave, benjamin.cheatham

On Tue, Sep 08, 2026 at 11:17:00PM +0100, Jonathan Cameron wrote:
> On Tue,  8 Sep 2026 03:15:12 -0700
> Anisa Su <anisa.su887@gmail.com> wrote:
> 
> > DC Partitions complicate DPA ordering. Add a DPA Partitions section to
> > cxl-driver.rst describing spec-mandated and Linux requirements for the
> > layout.
> > 
> > Suggested-by: Gregory Price <gourry@gourry.net>
> > Signed-off-by: Anisa Su <anisa.su@samsung.com>
> A couple of minor potential tweaks.  Otherwise LGTM
> Reviewed-by: Jonathan Cameron <jonathan.cameron@oss.qualcomm.com>
> 
> > 
> > ---
> > New patch in v13.
> > ---
> >  .../driver-api/cxl/linux/cxl-driver.rst       | 38 +++++++++++++++++++
> >  1 file changed, 38 insertions(+)
> > 
> > diff --git a/Documentation/driver-api/cxl/linux/cxl-driver.rst b/Documentation/driver-api/cxl/linux/cxl-driver.rst
> > index dd6dd17dc536..f0742d6c86c3 100644
> > --- a/Documentation/driver-api/cxl/linux/cxl-driver.rst
> > +++ b/Documentation/driver-api/cxl/linux/cxl-driver.rst
> > @@ -181,6 +181,44 @@ A Memory Device is a discrete base object that is not a port.  While the
> >  physical device it belongs to may also host an `endpoint`, the relationship
> >  between an `endpoint` and a `memdev` is not captured in sysfs.
> >  
> > +DPA Partitions
> > +~~~~~~~~~~~~~~
> > +A memory device presents its capacity as one flat `Device Physical Address`
> > +(DPA) space divided into `partitions`, which Linux lays out in a fixed
> > +order::
> > +
> > +  DPA 0                                                     end
> > +  +---------------+---------------+---------------------------+
> > +  |      ram      |     pmem      |       dynamic_ram_1       |
> > +  +---------------+---------------+---------------------------+
> > +  part[0]         part[1]         part[2]
> > +
> > +Part of that order is required by the CXL specification and part of it is a
> > +Linux choice.
> > +
> > +The `ram` and `pmem` order is mandated.  CXL r4.0 section 8.2.10.9.2.1 "Get
> > +Partition Info" (4100h), Table 8-310, mandates that volatile capacity starts
> > +at DPA 0 and pmem starts at the DPA immediately following it.
> > +
> > +Dynamic Capacity partitions only need to be 256MB aligned according to
> > +CXL r4.0 section 8.2.10.9.9.1 "Get Dynamic Capacity Configuration"
> > +(opcode 4800h), Table 8-347. So a device could leave a gap between ram/pmem
> > +(static) capacity and its first DC partition, or between one DC partition
> > +and the next.
> > +
> > +Linux follows the static precedent anyway for the partition it maps: the
> 
> Maybe "Linux chooses to only support...
> 
I went with "Linux chooses not to support gaps between static and
dynamic capacity: the first DC partition must begin..."

> > +first DC partition must begin at the DPA immediately following static
> > +capacity -- after pmem, after ram on a device with no pmem, or at DPA 0 on
> > +a device with no static capacity at all.
> > +
> > +Currently, only one dynamic partition is supported. A device may report up
> > +to eight (CXL r4.0 Table 8-346); Linux configures the first and exposes it as
> > +`dynamic_ram_1`.
> > +
> > +Support for additional dynamic partitions may be added if devices appear
> > +that need it, which is what the `dynamic_ram_1` name leaves room for.  Until
> > +then a device offering more than one is still usable, just not in full.
> I'd drop this last paragraph. Predicting the future is tricky, even with a may.
> Hopefully anyone realises that if something is needed Linux doesn't support
> they should propose patches to add it!
> 
Agreed, dropped this paragraph.

> Jonathan

Thanks,
Anisa
> 
> > +
> >  Port Relationships
> >  ~~~~~~~~~~~~~~~~~~
> >  In our example described above, there are four host bridges attached to the
> 

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 8/8] Documentation/cxl: Document DPA partition layout and ordering rules
  2026-09-11 20:38     ` Anisa Su
@ 2026-09-11 20:50       ` Davidlohr Bueso
  0 siblings, 0 replies; 33+ messages in thread
From: Davidlohr Bueso @ 2026-09-11 20:50 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, jic23, dave.jiang, gourry, icheng,
	ming.li, vishal.l.verma, benjamin.cheatham

On 2026-09-11 13:38, Anisa Su wrote:
> For the maturity map part, I have another commit at the end of the full 
> series
> that describes how DCD works from extent record --> dax device
> creation/tearing down, so I could update the maturity map in that
> commit, when DCD becomes functional.

So if DCD upstreaming is going to be multi-step, then the maturity map 
should indicate what is there and help users understand and set 
expectations.

Thanks,
Davidlohr

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 6/8] cxl/mem: Configure dynamic capacity interrupts
  2026-09-08 10:43   ` sashiko-bot
@ 2026-09-11 21:10     ` Anisa Su
  2026-09-12  0:09       ` Gregory Price
  0 siblings, 1 reply; 33+ messages in thread
From: Anisa Su @ 2026-09-11 21:10 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: Anisa Su, linux-cxl

On Tue, Sep 08, 2026 at 10:43:27AM +0000, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> 
> Pre-existing issues:
> - [High] If a CXL device is surprise-removed or a fatal PCIe error occurs, `cxl_event_thread` enters an infinite loop, pegging the CPU at 100% and deadlocking device removal.
> --
Surpise removal is unsupported. Jonathan mentioned the same on a similar
thread: 
https://lore.kernel.org/linux-cxl/aqLZP3ORYzCLfSgR@acer-nitro-anv15-41/T/#m8e12567a42b07fae8aa307406e6e017fe24ad832
> 
> commit f11145933c61ad9c3ba90b62e3f38dc571f856c5
> Author: Ira Weiny <iweiny@kernel.org>
> 
> cxl/mem: Configure dynamic capacity interrupts
> 
> This commit configures Dynamic Capacity Device (DCD) event log interrupts
> on devices supporting dynamic capacity. It disables DCD if interrupts are
> not supported, and carefully preserves firmware-first interrupt policies
> if selected by the BIOS.
> 
> > diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c
> > index 7b754af2168d0..1ea505b1f40e8 100644
> > --- a/drivers/cxl/pci.c
> > +++ b/drivers/cxl/pci.c
> [ ... ]
> > @@ -523,8 +535,8 @@ static irqreturn_t cxl_event_thread(int irq, void *id)
> >  		 * ignore the reserved upper 32 bits
> >  		 */
> >  		status = readl(cxlds->regs.status + CXLDEV_DEV_EVENT_STATUS_OFFSET);
> > -		/* Ignore logs unknown to the driver */
> > -		status &= CXLDEV_EVENT_STATUS_ALL;
> > +		/* Ignore logs unknown to the driver or owned by BIOS */
> > +		status &= mask;
> >  		if (!status)
> >  			break;
> >  		cxl_mem_get_event_records(mds, status);
> >  		cond_resched();
> >  	} while (status);
> 
> [Severity: High]
> This is a pre-existing issue, but does this loop lack a check for PCIe
> surprise removal where MMIO reads return all 1s (~0)?
> 
> If a CXL device is surprise-removed or a fatal PCIe error occurs, readl()
> will return 0xFFFFFFFF. When this is bitwise ANDed with mask, it leaves a
> non-zero value, causing the loop to continue. 
> 
> Since cxl_mem_get_event_records() will also read ~0 (e.g., when checking
> cxl_doorbell_busy()) and return immediately without changing hardware
> state, won't this loop spin indefinitely, pegging the CPU at 100% and
> deadlocking device removal when free_irq() waits for this thread to exit?
> 
> -- 
> Sashiko AI review · https://sashiko.dev/#/patchset/20260908102124.2231730-2-anisa.su@samsung.com?part=6

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 6/8] cxl/mem: Configure dynamic capacity interrupts
  2026-09-11 21:10     ` Anisa Su
@ 2026-09-12  0:09       ` Gregory Price
  0 siblings, 0 replies; 33+ messages in thread
From: Gregory Price @ 2026-09-12  0:09 UTC (permalink / raw)
  To: Anisa Su; +Cc: sashiko-reviews, linux-cxl

On Sat, Sep 12, 2026 at 06:10:57AM +0900, Anisa Su wrote:
> On Tue, Sep 08, 2026 at 10:43:27AM +0000, sashiko-bot@kernel.org wrote:
> > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> > 
> > Pre-existing issues:
> > - [High] If a CXL device is surprise-removed or a fatal PCIe error occurs, `cxl_event_thread` enters an infinite loop, pegging the CPU at 100% and deadlocking device removal.
> > --
> Surpise removal is unsupported. Jonathan mentioned the same on a similar
> thread: 
> https://lore.kernel.org/linux-cxl/aqLZP3ORYzCLfSgR@acer-nitro-anv15-41/T/#m8e12567a42b07fae8aa307406e6e017fe24ad832

This has been my favorite sashiko response so far

"If memory is surprised-removed, the system deadlocks!"

lol.

(your series is great, sorry i haven't gotten around to reviewing it
properly, i appreciate the doc updates very much)

~Gregory

^ permalink raw reply	[flat|nested] 33+ messages in thread

* Re: [RESEND PATCH v13 8/8] Documentation/cxl: Document DPA partition layout and ordering rules
  2026-09-08 10:15 ` [RESEND PATCH v13 8/8] Documentation/cxl: Document DPA partition layout and ordering rules Anisa Su
  2026-09-08 22:17   ` Jonathan Cameron
  2026-09-09 15:19   ` Davidlohr Bueso
@ 2026-09-12  0:20   ` Gregory Price
  2 siblings, 0 replies; 33+ messages in thread
From: Gregory Price @ 2026-09-12  0:20 UTC (permalink / raw)
  To: Anisa Su
  Cc: linux-cxl, alison.schofield, jic23, dave.jiang, icheng, ming.li,
	vishal.l.verma, dave, benjamin.cheatham, Anisa Su

On Tue, Sep 08, 2026 at 03:15:12AM -0700, Anisa Su wrote:

Reviewed-by: Gregory Price (Meta) <gourry@gourry.net>

one question here, but not overly necessary to document because it
instantly becomes the moment the code changes (for reasons).

> +
> +Linux follows the static precedent anyway for the partition it maps: the
> +first DC partition must begin at the DPA immediately following static
> +capacity -- after pmem, after ram on a device with no pmem, or at DPA 0 on
> +a device with no static capacity at all.
> +

What is the reason for this requirement? Just easier to code?

is fine to leave as-is, the first device that comes along that needs
it changed "for reasons" can fix it, but it seems an entirely reasonable
restriction.


^ permalink raw reply	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2026-09-12  0:20 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-08 10:15 [RESEND PATCH v13 0/8] DCD Prep Series Anisa Su
2026-09-08 10:15 ` [RESEND PATCH v13 1/8] cxl/mbox: Flag support for Dynamic Capacity Devices (DCD) Anisa Su
2026-09-08 15:39   ` dave
2026-09-08 18:45   ` Jonathan Cameron
2026-09-08 10:15 ` [RESEND PATCH v13 2/8] cxl/mem: Read dynamic capacity configuration from the device Anisa Su
2026-09-08 15:59   ` Davidlohr Bueso
2026-09-08 20:43   ` Jonathan Cameron
2026-09-10 23:56     ` Anisa Su
2026-09-11  0:53       ` Jonathan Cameron
2026-09-11 16:38         ` Anisa Su
2026-09-08 10:15 ` [RESEND PATCH v13 3/8] cxl/cdat: Gather DSMAS data for DCD partitions Anisa Su
2026-09-08 20:52   ` Jonathan Cameron
2026-09-11  0:02     ` Anisa Su
2026-09-11  0:56       ` Jonathan Cameron
2026-09-11 16:37         ` Anisa Su
2026-09-08 10:15 ` [RESEND PATCH v13 4/8] cxl/events: Split event msgnum configuration from irq setup Anisa Su
2026-09-08 16:37   ` Davidlohr Bueso
2026-09-08 10:15 ` [RESEND PATCH v13 5/8] cxl/pci: Factor out interrupt policy check Anisa Su
2026-09-08 17:17   ` Davidlohr Bueso
2026-09-08 10:15 ` [RESEND PATCH v13 6/8] cxl/mem: Configure dynamic capacity interrupts Anisa Su
2026-09-08 10:43   ` sashiko-bot
2026-09-11 21:10     ` Anisa Su
2026-09-12  0:09       ` Gregory Price
2026-09-08 22:14   ` Jonathan Cameron
2026-09-11 18:21     ` Anisa Su
2026-09-08 10:15 ` [RESEND PATCH v13 7/8] cxl/core: Enforce partition order/simplify partition calls Anisa Su
2026-09-08 10:15 ` [RESEND PATCH v13 8/8] Documentation/cxl: Document DPA partition layout and ordering rules Anisa Su
2026-09-08 22:17   ` Jonathan Cameron
2026-09-11 20:39     ` Anisa Su
2026-09-09 15:19   ` Davidlohr Bueso
2026-09-11 20:38     ` Anisa Su
2026-09-11 20:50       ` Davidlohr Bueso
2026-09-12  0:20   ` Gregory Price

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).