mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v6 0/9] cxl: Support Back-Invalidate
@ 2026-07-27 19:35 Davidlohr Bueso
  2026-07-27 19:35 ` [PATCH v6 1/9] cxl: Add BI register probing and port initialization Davidlohr Bueso
                   ` (9 more replies)
  0 siblings, 10 replies; 14+ messages in thread
From: Davidlohr Bueso @ 2026-07-27 19:35 UTC (permalink / raw)
  To: dave.jiang
  Cc: jic23, alison.schofield, icheng, benjamin.cheatham, alucerop,
	dongjoo.seo1, dave, linux-kernel

Hello,

Changes from v5 (https://lore.kernel.org/all/20260615145529.13848-1-dave@stgolabs.net):
  - Patch 1 documented the BI register block with the spec references
    at the definitions. (Dave)
  - Patch 2 split the enable/rollback into a helper so the unwind path
    no longer mixes goto and scope-based cleanup (Sashiko).
  - Patch 2 reworded the changelog around root port enablement.
  - Patch 3 introduced cxled_default_type() so decoders present the
    device's default target type when not attached to a region (Sashiko).
  - Patch 4 defaults to host-only when firmware sets both CFMWS
    coherency restrictions (Richard).
  - Patch 4 restores the default target type on detach, fixing a stale
    DEVMEM type leaking into a later HDM-H attach (Sashiko).
  - Patch 4 'bi' sysfs now reports against the attached region's root
    decoder rather than device state alone (Sashiko).
  - Picked up review tags (thanks!).
  - New patch 6: trivially log the coherency model at region creation dbg.
  - New patches 7-9: move BI setup to endpoint port probe, split the
    capability probe from BI-ID allocation, and allow for auto-committed
    BI decoders instead of failing enumeration.

This series is the initial plumbing to enable HDM-DB in Linux. The
model allows Type 2 and Type 3 devices to expose their local memory
to the host CPU in a coherent manner. In alignment with what was
discussed at 2024 LPC type2 support session, this series takes the
Type 3 memory expander approach, which is more direct. Further,
afaik there is no Type 2 + BI hardware out there.

A flagship use case of Type 3 + BI is coherent shared memory, and
there is currently a big gap in this regard (ie: GFAM). Another
is P2P via PCIe UIO, which is also lacking today. Media Operation
(4402h) for ranged sanitize/zero also trigger snoops and there are
some patches out there[0]. As such this series focuses on BI enablement
in terms of discovery and configuration.

The idea is for Type 3 memdevs and Type 2 devices to make use of
cxlds->bi when committing HDM decoders, such that different device
coherence models can be differentiated as:

  type2 hdm-d:  cxlds->type == CXL_DEVTYPE_DEVMEM && cxlds->bi == false
  type2 hdm-db: cxlds->type == CXL_DEVTYPE_DEVMEM && cxlds->bi == true
  type3 hdm-h:  cxlds->type == CXL_DEVTYPE_CLASSMEM && cxlds->bi == false
  type3 hdm-db: cxlds->type == CXL_DEVTYPE_CLASSMEM && cxlds->bi == true

Unlike previous versions, an auto-committed BI decoder found during
enumeration is no longer rejected: patches 7-9 adopt the inherited
configuration when the device and path are BI capable, refusing only
broken combinations. See the auto-discovery tests section below.

o Patch 1 probes BI capabilities during register discovery, and maps BI
  Decoder registers.

o Patch 2 implements the BI-ID allocation (and deallocation).

o Patch 3 adds coherency support for endpoint decoders based on what the
root decoder restricts.

o Patch 4 adds support for HDM-DB region creation.

o Patch 5 trivially renames some coherency flags.

o Patch 6 logs the coherency model (HDM-H, HDM-D, HDM-DB) when a
  region is created.

o Patch 7 moves BI setup to endpoint port probe, tying the BI-ID
  lifetime to the endpoint port.

o Patch 8 splits the BI capability walk from BI-ID allocation so the
  answer is available when committed decoders are first parsed.

o Patch 9 allows committed BI decoders. Overall this series
  could be picked up with or without this patch.

Please note that patch 7+8 could be consolidated into patch 2,
instead of starting out with cxl_mem but I chose to add them
incrementally because 1) want to see what sashiko says,
2) it isolates the requirements for the auto-committed support
(patch 9); 3) details why endpoint lifecycle is safe and
4) reuses already valuable review times of the current state
of the series. But I certainly see the reasons to avoid the
additional patches. 

Testing
-------

Testing has been done on top of upstream qemu with the CFMW options series:

  https://lore.kernel.org/all/20260720233242.901544-1-dave@stgolabs.net/

A new qemu-based test suite has been added for full automation and pounding,
covering many topologies and corner cases:

  https://github.com/davidlohr/cxl-bi-tests

This passes regression testing (nothing breaks) ndctl suite via cxl_test.

1. HDM Decoder with BI through ad-hoc region creation.
------------------------------------------------------
# cxl list -D
[
  {
    "decoder":"decoder0.0",
    "resource":6710886400,
    "size":4294967296,
    "interleave_ways":1,
    "accelmem_capable":true,
    "nr_targets":1
  }
]

# ROOT=/sys/bus/cxl/devices/decoder0.0
# EP=/sys/bus/cxl/devices/decoder2.0
# echo region0 > $ROOT/create_ram_region
[    7.662871] cxl_core:devm_cxl_add_region:2829: cxl_acpi ACPI0017:00: decoder0.0: created HDM-DB region0
# REG=/sys/bus/cxl/devices/region0
# echo ram > $EP/mode
# echo 0x40000000 > $EP/dpa_size
# echo 1 > $REG/interleave_ways
# echo 4096 > $REG/interleave_granularity
# echo 0x40000000 > $REG/size
# cat $EP/bi
0
# echo decoder2.0 > $REG/target0
[    8.153566] cxl_core:cxl_port_attach_region:1295: cxl region0: mem0:endpoint2 decoder2.0 add: mem0:decoder2.0 @ 0 next: none nr_eps: 1 nr_targets: 1
[    8.157683] cxl_core:cxl_port_attach_region:1295: cxl region0: pci0000:0c:port1 decoder1.0 add: mem0:decoder2.0 @ 0 next: mem0 nr_eps: 1 nr_targets: 1
[    8.159570] cxl_core:cxl_port_setup_targets:1630: cxl region0: pci0000:0c:port1 iw: 1 ig: 4096
[    8.160487] cxl_core:cxl_port_setup_targets:1638: cxl region0: pci0000:0c:port1 target[0] = 0000:0c:00.0 for mem0:decoder2.0 @ 0
[    8.161759] cxl_core:cxl_calc_interleave_pos:2046: cxl_mem mem0: decoder:decoder2.0 parent:0000:0d:00.0 port:endpoint2 range:0x190000000-0x1cfffffff pos:0
[    8.163681] cxl_core:cxl_region_attach:2270: cxl decoder2.0: Test cxl_calc_interleave_pos(): success test_pos:0 target->pos:0
# cat $EP/bi
1
# echo 1 > $REG/commit
# cxl list -D
[
  {
    "root decoders":[
      {
        "decoder":"decoder0.0",
        "resource":6710886400,
        "size":4294967296,
        "interleave_ways":1,
        "accelmem_capable":true,
        "nr_targets":1
      }
    ]
  },
  {
    "port decoders":[
      {
        "decoder":"decoder1.0",
        "resource":6710886400,
        "size":1073741824,
        "interleave_ways":1,
        "region":"region0",
        "nr_targets":1
      }
    ]
  },
  {
    "endpoint decoders":[
      {
        "decoder":"decoder2.0",
        "resource":6710886400,
        "size":1073741824,
        "interleave_ways":1,
        "region":"region0",
        "dpa_resource":0,
        "dpa_size":1073741824,
        "mode":"ram"
      }
    ]
  }
]

2. Type3 device does not support BI, but CFMW has BI restriction
----------------------------------------------------------------
# echo decoder2.0 > $REG/target0
[    7.311927] cxl region0: mem0:decoder2.0 BI not enabled on device
[    7.313907] cxl_port endpoint2: failed to attach decoder2.0 to region0: -6

3. Type3 device supports BI but CFMW does not, create HDM-H region
------------------------------------------------------------------
# cxl list -D
[
  {
    "decoder":"decoder0.0",
    "resource":6710886400,
    "size":4294967296,
    "interleave_ways":1,
    "max_available_extent":4294967296,
    "pmem_capable":true,
    "volatile_capable":true,
    "accelmem_capable":true,
    "nr_targets":1
  }
]
# echo region0 > $ROOT/create_ram_region
[    7.679496] cxl_core:devm_cxl_add_region:2829: cxl_acpi ACPI0017:00: decoder0.0: created HDM-H region0
# cat $EP/bi
0
# echo decoder2.0 > $REG/target0
[    8.165400] cxl_core:cxl_port_attach_region:1295: cxl region0: mem0:endpoint2 decoder2.0 add: mem0:decoder2.0 @ 0 next: none nr_eps: 1 nr_targets: 1
[    8.167128] cxl_core:cxl_port_attach_region:1295: cxl region0: pci0000:0c:port1 decoder1.0 add: mem0:decoder2.0 @ 0 next: mem0 nr_eps: 1 nr_targets: 1
[    8.168834] cxl_core:cxl_port_setup_targets:1630: cxl region0: pci0000:0c:port1 iw: 1 ig: 4096
[    8.169893] cxl_core:cxl_port_setup_targets:1638: cxl region0: pci0000:0c:port1 target[0] = 0000:0c:00.0 for mem0:decoder2.0 @ 0
[    8.171302] cxl_core:cxl_calc_interleave_pos:2046: cxl_mem mem0: decoder:decoder2.0 parent:0000:0d:00.0 port:endpoint2 range:0x190000000-0x1cfffffff pos:0
[    8.173036] cxl_core:cxl_region_attach:2270: cxl decoder2.0: Test cxl_calc_interleave_pos(): success test_pos:0 target->pos:0
# echo 1 > $REG/commit
# cat $EP/bi
0

4. Unbind + Bind
----------------
# echo mem0 > /sys/bus/cxl/drivers/cxl_mem/unbind
[    7.645330] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests disabled
[    7.648838] cxl_core:cxl_port_commit_reap:900: cxl_port endpoint2: reap: decoder2.0 commit_end: -1
[    7.651284] cxl_core:cxl_detach_ep:1556: cxl_mem mem0: disconnect mem0 from port1

# echo mem0 > /sys/bus/cxl/drivers/cxl_mem/bind
[    8.909437] cxl_core:devm_cxl_enumerate_ports:1871: cxl_mem mem0: scan: iter: mem0 dport_dev: 0000:0c:00.0 parent: pci0000:0c
[    8.911170] cxl_core:devm_cxl_enumerate_ports:1877: cxl_mem mem0: found already registered port port1:pci0000:0c
[    8.945969] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x0-0xffffffffffffffff iw: 1 ig: 4096
[    8.949705] cxl_core:add_hdm_decoder:39: cxl_mem mem0: decoder2.0 added to endpoint2
[    8.960378] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests enabled
[    8.961196] cxl_core:cxl_bus_probe:2299: cxl_port endpoint2: probe: 0
[    8.962592] cxl_core:cxl_bus_probe:2299: cxl_mem mem0: probe: 0

The same applies to the endpoint port, with the memdev rebind recovering the endpoint:

# echo endpoint2 > /sys/bus/cxl/drivers/cxl_port/unbind
[   10.483509] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests disabled
[   10.487570] cxl_core:cxl_port_commit_reap:900: cxl_port endpoint2: reap: decoder2.0 commit_end: -1
[   10.491501] cxl_core:cxl_detach_ep:1556: cxl_mem mem0: disconnect mem0 from port1

# echo mem0 > /sys/bus/cxl/drivers/cxl_mem/bind
[   11.754957] cxl_core:devm_cxl_enumerate_ports:1871: cxl_mem mem0: scan: iter: mem0 dport_dev: 0000:0c:00.0 parent: pci0000:0c
[   11.756343] cxl_core:devm_cxl_enumerate_ports:1877: cxl_mem mem0: found already registered port port1:pci0000:0c
[   11.789821] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x0-0xffffffffffffffff iw: 1 ig: 4096
[   11.794674] cxl_core:add_hdm_decoder:39: cxl_mem mem0: decoder2.0 added to endpoint2
[   11.805772] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests enabled
[   11.806810] cxl_core:cxl_bus_probe:2299: cxl_port endpoint2: probe: 0
[   11.808661] cxl_core:cxl_bus_probe:2299: cxl_mem mem0: probe: 0

From a cold boot, without a region ever created, the endpoint port
unbind only disables BI - there is no committed decoder to reap:

# echo endpoint2 > /sys/bus/cxl/drivers/cxl_port/unbind
[   22.046813] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests disabled
[   22.049676] cxl_core:cxl_detach_ep:1556: cxl_mem mem0: disconnect mem0 from port1

# echo mem0 > /sys/bus/cxl/drivers/cxl_mem/bind
[   24.270628] cxl_core:devm_cxl_enumerate_ports:1871: cxl_mem mem0: scan: iter: mem0 dport_dev: 0000:0c:00.0 parent: pci0000:0c
[   24.273682] cxl_core:devm_cxl_enumerate_ports:1877: cxl_mem mem0: found already registered port port1:pci0000:0c
[   24.312426] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x0-0xffffffffffffffff iw: 1 ig: 256
[   24.315677] cxl_core:add_hdm_decoder:39: cxl_mem mem0: decoder2.0 added to endpoint2
[   24.332406] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests enabled
[   24.334427] cxl_core:cxl_bus_probe:2299: cxl_port endpoint2: probe: 0
[   24.337952] cxl_core:cxl_bus_probe:2299: cxl_mem mem0: probe: 0

5. Discovery behind a Switch
----------------------------
[    0.782301] cxl_core:cxl_probe_component_regs:102: cxl_pci 0000:0f:00.0: found BI Decoder capability (0xab4)
[    0.851085] cxl_core:cxl_probe_component_regs:102: pcieport 0000:0c:00.0: found BI Decoder capability (0xab4)
[    0.866840] cxl_core:cxl_probe_component_regs:96: cxl_port port2: found BI RT capability (0xaa8)
[    0.902485] cxl_core:cxl_probe_component_regs:102: pcieport 0000:0e:00.0: found BI Decoder capability (0xab4)
[    1.221118] cxl_core:__cxl_bi_wait_commit:1032: pcieport 0000:0e:00.0: BI-ID commit wait took 250908us
[    1.368581] cxl_core:__cxl_bi_wait_commit:1032: cxl_port port2: BI-ID commit wait took 146455us
[    1.371579] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0f:00.0: BI requests enabled

6. Corrupted hw (commit timeout handling)
-----------------------------------------
[    1.003566] cxl_core:cxl_probe_component_regs:102: pcieport 0000:0e:00.0: found BI Decoder capability (0xab4)
[    3.203147] pcieport 0000:0e:00.0: BI-ID commit timed out (2000000us)
[    3.206048] cxl_port:cxl_endpoint_port_probe:190: cxl_port endpoint3: BI setup failed rc=-110

7. Mixed Configurations (BI-capable Type 3 but DSP 68b)
-------------------------------------------------------
[    0.837902] cxl_mem:cxl_mem_probe:155: cxl_mem mem0: BI setup failed rc=-22

8. Auto-discovered (committed) BI decoders
------------------------------------------
For testing, qemu hack emulates auto-committed decoder:

[    0.670374] cxl_core:devm_cxl_switch_port_decoders_setup:1282: cxl_port port1: Fallback to passthrough decoder
[    0.718374] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x190000000-0x19fffffff iw: 1 ig: 256
[    0.728498] cxl_core:__cxl_bi_ctrl_endpoint:1200: cxl_pci 0000:0d:00.0: adopting firmware-enabled BI
[    0.730880] cxl_core:devm_cxl_add_region:2829: cxl_acpi ACPI0017:00: decoder0.0: created HDM-DB region0
[    0.731906] cxl_core:__construct_region:3843: cxl_pci 0000:0d:00.0: mem0:decoder2.0: __construct_region region0 res: [mem 0x190000000-0x19fffffff flags 0x200] iw: 1 ig: 256
[    0.734473] cxl_core:cxl_region_sort_targets:2104: cxl region0: region sort successful
[    0.739452] cxl_core:devm_cxl_add_dax_region:101: cxl_region region0: region0: register dax_region0
[    0.740239] cxl_core:cxl_bus_probe:2299: cxl_region region0: probe: 0
# cat /sys/bus/cxl/devices/region0/commit
1
# cat /sys/bus/cxl/devices/decoder2.0/bi
1

A committed BI decoder under a window without the BI restriction is
refused at region assembly:

[    0.794477] cxl_core:__cxl_bi_ctrl_endpoint:1200: cxl_pci 0000:0d:00.0: adopting firmware-enabled BI
[    0.795396] cxl_pci 0000:0d:00.0: mem0:decoder2.0 BI decoder in a non-BI window
[    0.796050] cxl_port:discover_region:55: cxl decoder2.0: failed to add to region: 0x190000000-0x19fffffff

Applies against v7.2-rc5. Please consider for v7.3.

[0] https://lore.kernel.org/linux-cxl/20260428200410.705675-1-dave@stgolabs.net/

Thanks!

Davidlohr Bueso (9):
  cxl: Add BI register probing and port initialization
  cxl/pci: Add BI topology enable/disable
  cxl/hdm: Add BI coherency support for endpoint decoders
  cxl: Add HDM-DB region creation
  cxl/hdm: Rename decoder coherency flags
  cxl/region: Log the coherency model at region creation
  cxl: Move BI setup to endpoint port probe
  cxl/pci: Split BI capability probe from setup
  cxl: Allow auto-committed BI hdm decoders

 Documentation/ABI/testing/sysfs-bus-cxl |  18 +-
 drivers/cxl/acpi.c                      |  19 +-
 drivers/cxl/core/core.h                 |   2 +
 drivers/cxl/core/hdm.c                  |  68 ++++-
 drivers/cxl/core/pci.c                  | 456 ++++++++++++++++++++++++++++++++
 drivers/cxl/core/port.c                 |  48 +++-
 drivers/cxl/core/region.c               |  97 ++++++-
 drivers/cxl/core/regs.c                 |  14 +
 drivers/cxl/cxl.h                       |  55 +++-
 drivers/cxl/cxlmem.h                    |   2 +
 drivers/cxl/port.c                      |  54 ++++
 include/cxl/cxl.h                       |  10 +
 12 files changed, 808 insertions(+), 35 deletions(-)

--
2.39.5

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

* [PATCH v6 1/9] cxl: Add BI register probing and port initialization
  2026-07-27 19:35 [PATCH v6 0/9] cxl: Support Back-Invalidate Davidlohr Bueso
@ 2026-07-27 19:35 ` Davidlohr Bueso
  2026-07-27 19:35 ` [PATCH v6 2/9] cxl/pci: Add BI topology enable/disable Davidlohr Bueso
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Davidlohr Bueso @ 2026-07-27 19:35 UTC (permalink / raw)
  To: dave.jiang
  Cc: jic23, alison.schofield, icheng, benjamin.cheatham, alucerop,
	dongjoo.seo1, dave, linux-kernel

Add register probing for BI Route Table and BI Decoder capability
structures in cxl_probe_component_regs(), and helpers to map them.

cxl_dport_map_bi() maps the BI Decoder of a downstream port (root
port or switch DSP) at dport-creation time via cxl_port_add_dport();
cxl_port_map_bi() maps a port's own BI capability during port probe
when the upstream link is in 256B Flit operation -- BI Decoder for
an endpoint, BI RT for a switch USP.

Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 drivers/cxl/core/core.h |  1 +
 drivers/cxl/core/pci.c  | 38 ++++++++++++++++++++++++++++++++++
 drivers/cxl/core/port.c |  4 +++-
 drivers/cxl/core/regs.c | 14 +++++++++++++
 drivers/cxl/cxl.h       |  7 +++++++
 drivers/cxl/port.c      | 45 +++++++++++++++++++++++++++++++++++++++++
 include/cxl/cxl.h       |  6 ++++++
 7 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index 07555ae63859..e36b55fd63bd 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -209,6 +209,7 @@ static inline void devm_cxl_dport_ras_setup(struct cxl_dport *dport) { }
 #endif /* CONFIG_CXL_RAS */
 
 int cxl_gpf_port_setup(struct cxl_dport *dport);
+void devm_cxl_dport_bi_setup(struct cxl_dport *dport);
 
 struct cxl_hdm;
 int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index e4338fd7e01b..f82559d8a8c5 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -926,3 +926,41 @@ int cxl_port_get_possible_dports(struct cxl_port *port)
 
 	return ctx.count;
 }
+
+static void cxl_dport_map_bi(struct cxl_dport *dport)
+{
+	struct cxl_register_map *map = &dport->reg_map;
+	struct device *dev = dport->dport_dev;
+
+	if (!map->component_map.bi_decoder.valid) {
+		dev_dbg(dev, "BI Decoder registers not found\n");
+		return;
+	}
+
+	if (cxl_map_component_regs(map, &dport->regs.component,
+				   BIT(CXL_CM_CAP_CAP_ID_BI_DECODER)))
+		dev_dbg(dev, "Failed to map BI Decoder capability\n");
+}
+
+/**
+ * devm_cxl_dport_bi_setup - Map BI Decoder registers on a CXL dport
+ * @dport: the cxl_dport that needs to be initialized
+ *
+ * Must be called while the dport's devres group is open so iomap
+ * allocations are released on dport removal.
+ */
+void devm_cxl_dport_bi_setup(struct cxl_dport *dport)
+{
+	if (!dev_is_pci(dport->dport_dev))
+		return;
+
+	switch (pci_pcie_type(to_pci_dev(dport->dport_dev))) {
+	case PCI_EXP_TYPE_ROOT_PORT:
+	case PCI_EXP_TYPE_DOWNSTREAM:
+		dport->reg_map.host = dport_to_host(dport);
+		cxl_dport_map_bi(dport);
+		break;
+	default:
+		break;
+	}
+}
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 1215ee4f4035..b2f8fb9547d3 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -1242,8 +1242,10 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev,
 
 	cxl_debugfs_create_dport_dir(dport);
 
-	if (!dport->rch)
+	if (!dport->rch) {
 		devm_cxl_dport_ras_setup(dport);
+		devm_cxl_dport_bi_setup(dport);
+	}
 
 	/* keep the group, and mark the end of devm actions */
 	cxl_dport_close_dr_group(dport, no_free_ptr(dport_dr_group));
diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
index 93710cf4f0a6..a6caa793e7a4 100644
--- a/drivers/cxl/core/regs.c
+++ b/drivers/cxl/core/regs.c
@@ -92,6 +92,18 @@ void cxl_probe_component_regs(struct device *dev, void __iomem *base,
 			length = CXL_RAS_CAPABILITY_LENGTH;
 			rmap = &map->ras;
 			break;
+		case CXL_CM_CAP_CAP_ID_BI_RT:
+			dev_dbg(dev, "found BI RT capability (0x%x)\n",
+				offset);
+			length = CXL_BI_RT_CAPABILITY_LENGTH;
+			rmap = &map->bi_rt;
+			break;
+		case CXL_CM_CAP_CAP_ID_BI_DECODER:
+			dev_dbg(dev, "found BI Decoder capability (0x%x)\n",
+				offset);
+			length = CXL_BI_DECODER_CAPABILITY_LENGTH;
+			rmap = &map->bi_decoder;
+			break;
 		default:
 			dev_dbg(dev, "Unknown CM cap ID: %d (0x%x)\n", cap_id,
 				offset);
@@ -211,6 +223,8 @@ int cxl_map_component_regs(const struct cxl_register_map *map,
 	} mapinfo[] = {
 		{ &map->component_map.hdm_decoder, &regs->hdm_decoder },
 		{ &map->component_map.ras, &regs->ras },
+		{ &map->component_map.bi_rt, &regs->bi_rt },
+		{ &map->component_map.bi_decoder, &regs->bi_decoder },
 	};
 	int i;
 
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index c0e5308e4d1b..f9fcb6387fc8 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -39,9 +39,16 @@ extern const struct nvdimm_security_ops *cxl_security_ops;
 #define   CXL_CM_CAP_HDR_ARRAY_SIZE_MASK GENMASK(31, 24)
 #define CXL_CM_CAP_PTR_MASK GENMASK(31, 20)
 
+/* CXL 4.0 8.2.4 Table 8-74 */
 #define   CXL_CM_CAP_CAP_ID_RAS 0x2
 #define   CXL_CM_CAP_CAP_ID_HDM 0x5
 #define   CXL_CM_CAP_CAP_HDM_VERSION 1
+#define   CXL_CM_CAP_CAP_ID_BI_RT 0xB
+#define   CXL_CM_CAP_CAP_ID_BI_DECODER 0xC
+
+/* CXL 4.0 8.2.4.26 / 8.2.4.27 BI Capability Structures */
+#define CXL_BI_RT_CAPABILITY_LENGTH 0xC
+#define CXL_BI_DECODER_CAPABILITY_LENGTH 0xC
 
 /* HDM decoders CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure */
 #define CXL_HDM_DECODER_CAP_OFFSET 0x0
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 99cf77b6b699..a527dd13fb68 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -58,6 +58,47 @@ static int discover_region(struct device *dev, void *unused)
 	return 0;
 }
 
+static void cxl_port_map_bi(struct cxl_port *port)
+{
+	struct cxl_register_map *map = &port->reg_map;
+	struct cxl_dport *parent_dport = port->parent_dport;
+	struct device *udev;
+	int cap_id;
+
+	/* no upstream BI registers above host bridges or the cxl_root */
+	if (!parent_dport || is_cxl_root(parent_dport->port))
+		return;
+
+	udev = is_cxl_endpoint(port) ?
+		port->uport_dev->parent : port->uport_dev;
+	if (!dev_is_pci(udev))
+		return;
+
+	/* BI requires 256B Flit on the upstream link */
+	if (!cxl_pci_flit_256(to_pci_dev(udev)))
+		return;
+
+	/* map this port's own BI capability */
+	if (is_cxl_endpoint(port)) {
+		if (!map->component_map.bi_decoder.valid) {
+			dev_dbg(&port->dev, "BI Decoder registers not found\n");
+			return;
+		}
+		cap_id = CXL_CM_CAP_CAP_ID_BI_DECODER;
+	} else {
+		if (!map->component_map.bi_rt.valid) {
+			dev_dbg(&port->dev, "BI RT registers not found\n");
+			return;
+		}
+		cap_id = CXL_CM_CAP_CAP_ID_BI_RT;
+	}
+
+	map->host = &port->dev;
+	if (cxl_map_component_regs(map, &port->regs, BIT(cap_id)))
+		dev_dbg(&port->dev, "Failed to map BI capability 0x%x\n",
+			cap_id);
+}
+
 static int cxl_switch_port_probe(struct cxl_port *port)
 {
 	/* Reset nr_dports for rebind of driver */
@@ -128,6 +169,8 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
 	read_cdat_data(port);
 	cxl_endpoint_parse_cdat(port);
 
+	cxl_port_map_bi(port);
+
 	get_device(&cxlmd->dev);
 	rc = devm_add_action_or_reset(&port->dev, schedule_detach, cxlmd);
 	if (rc)
@@ -252,6 +295,8 @@ static struct cxl_dport *cxl_port_add_dport(struct cxl_port *port,
 		 * on failure, or the device does not implement RAS registers.
 		 */
 		devm_cxl_port_ras_setup(port);
+
+		cxl_port_map_bi(port);
 	}
 
 	dport = devm_cxl_add_dport_by_dev(port, dport_dev);
diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
index 016c74fb747c..2816954680b3 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -34,10 +34,14 @@ struct cxl_regs {
 	 * Common set of CXL Component register block base pointers
 	 * @hdm_decoder: CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure
 	 * @ras: CXL 2.0 8.2.5.9 CXL RAS Capability Structure
+	 * @bi_rt: CXL 4.0 8.2.4.26 CXL BI Route Table Capability Structure
+	 * @bi_decoder: CXL 4.0 8.2.4.27 CXL BI Decoder Capability Structure
 	 */
 	struct_group_tagged(cxl_component_regs, component,
 		void __iomem *hdm_decoder;
 		void __iomem *ras;
+		void __iomem *bi_rt;
+		void __iomem *bi_decoder;
 	);
 	/*
 	 * Common set of CXL Device register block base pointers
@@ -80,6 +84,8 @@ struct cxl_reg_map {
 struct cxl_component_reg_map {
 	struct cxl_reg_map hdm_decoder;
 	struct cxl_reg_map ras;
+	struct cxl_reg_map bi_rt;
+	struct cxl_reg_map bi_decoder;
 };
 
 struct cxl_device_reg_map {
-- 
2.39.5


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

* [PATCH v6 2/9] cxl/pci: Add BI topology enable/disable
  2026-07-27 19:35 [PATCH v6 0/9] cxl: Support Back-Invalidate Davidlohr Bueso
  2026-07-27 19:35 ` [PATCH v6 1/9] cxl: Add BI register probing and port initialization Davidlohr Bueso
@ 2026-07-27 19:35 ` Davidlohr Bueso
  2026-07-27 19:35 ` [PATCH v6 3/9] cxl/hdm: Add BI coherency support for endpoint decoders Davidlohr Bueso
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Davidlohr Bueso @ 2026-07-27 19:35 UTC (permalink / raw)
  To: dave.jiang
  Cc: jic23, alison.schofield, icheng, benjamin.cheatham, alucerop,
	dongjoo.seo1, dave, linux-kernel

Implement cxl_bi_setup(), which walks the CXL port topology to enable
BI flows on the device and every component in the path between the
device and the root port. The walk is two-pass: first to verify each
component advertises BI capability, then to program each dport's BI
Decoder Control register -- BI Enable on the DSP directly connected
to the device, BI Forward on the root port -- and BI Enable on the
device. On failure during the enable pass, partially-enabled dports
are rolled back.

The teardown counterpart, cxl_bi_dealloc(), runs automatically on
cxl_mem unbind.

cxl_bi_setup() does not touch HDM decoder configuration -- the BI bit
in each decoder is programmed separately at commit time. After a
successful setup the device is BI-capable but not yet using BI for
decode coherence.

Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 drivers/cxl/core/pci.c | 382 +++++++++++++++++++++++++++++++++++++++++
 drivers/cxl/cxl.h      |  28 +++
 drivers/cxl/mem.c      |   4 +
 include/cxl/cxl.h      |   2 +
 4 files changed, 416 insertions(+)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index f82559d8a8c5..12cb50640f65 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -2,11 +2,13 @@
 /* Copyright(c) 2021 Intel Corporation. All rights reserved. */
 #include <linux/units.h>
 #include <linux/io-64-nonatomic-lo-hi.h>
+#include <linux/iopoll.h>
 #include <linux/device.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/pci-doe.h>
 #include <linux/aer.h>
+#include <linux/string_choices.h>
 #include <cxlpci.h>
 #include <cxlmem.h>
 #include <cxl.h>
@@ -964,3 +966,383 @@ void devm_cxl_dport_bi_setup(struct cxl_dport *dport)
 		break;
 	}
 }
+/*
+ * BI requires 256B Flit operation on the link. RP/DSP/endpoint must
+ * also have the BI Decoder cap mapped (@bi); for USPs the BI RT cap
+ * is optional per CXL 4.0 8.2.4.26, so absent @bi is allowed.
+ */
+static bool cxl_is_bi_capable(struct pci_dev *pdev, void __iomem *bi)
+{
+	if (!cxl_pci_flit_256(pdev))
+		return false;
+	if (pci_pcie_type(pdev) != PCI_EXP_TYPE_UPSTREAM && !bi) {
+		dev_dbg(&pdev->dev, "No BI Decoder registers.\n");
+		return false;
+	}
+	return true;
+}
+
+/* limit any insane timeouts from hw */
+#define CXL_BI_COMMIT_MAXTMO_US (5 * USEC_PER_SEC)
+
+static unsigned long __cxl_bi_get_timeout_us(struct device *dev,
+					     unsigned int scale,
+					     unsigned int base)
+{
+	static const unsigned long scale_tbl[] = {
+		1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
+	};
+
+	if (scale >= ARRAY_SIZE(scale_tbl) || !base) {
+		dev_dbg(dev, "Invalid BI commit timeout: scale=%u base=%u\n",
+			scale, base);
+		return CXL_BI_COMMIT_MAXTMO_US;
+	}
+
+	return scale_tbl[scale] * base;
+}
+
+static int __cxl_bi_wait_commit(struct device *dev, void __iomem *status_reg,
+				u32 committed_bit, u32 err_bit,
+				unsigned int scale, unsigned int base)
+{
+	unsigned long tmo_us, poll_us;
+	ktime_t start;
+	u32 status;
+	int rc;
+
+	tmo_us = min_t(unsigned long, CXL_BI_COMMIT_MAXTMO_US,
+		       __cxl_bi_get_timeout_us(dev, scale, base));
+	poll_us = max_t(unsigned long, tmo_us / 10, 1); /* ~10% */
+	start = ktime_get();
+
+	rc = readx_poll_timeout(readl, status_reg, status,
+				status & (committed_bit | err_bit),
+				poll_us, tmo_us);
+	if (rc) {
+		dev_err(dev, "BI-ID commit timed out (%luus)\n", tmo_us);
+		return rc; /* -ETIMEDOUT */
+	}
+
+	if (status & err_bit) {
+		dev_err(dev, "BI-ID commit rejected by hardware\n");
+		return -EIO;
+	}
+
+	dev_dbg(dev, "BI-ID commit wait took %lluus\n",
+		ktime_to_us(ktime_sub(ktime_get(), start)));
+	return 0;
+}
+
+/* BI RT only exists on switch upstream ports. */
+static int __cxl_bi_commit_rt(struct device *dev, void __iomem *bi)
+{
+	u32 status, ctrl;
+	unsigned int scale, base;
+
+	if (!FIELD_GET(CXL_BI_RT_CAPS_EXPLICIT_COMMIT_REQ,
+		       readl(bi + CXL_BI_RT_CAPS_OFFSET)))
+		return 0;
+
+	ctrl = readl(bi + CXL_BI_RT_CTRL_OFFSET);
+	writel(ctrl & ~CXL_BI_RT_CTRL_BI_COMMIT, bi + CXL_BI_RT_CTRL_OFFSET);
+	writel(ctrl | CXL_BI_RT_CTRL_BI_COMMIT, bi + CXL_BI_RT_CTRL_OFFSET);
+
+	status = readl(bi + CXL_BI_RT_STATUS_OFFSET);
+	scale = FIELD_GET(CXL_BI_RT_STATUS_BI_COMMIT_TM_SCALE, status);
+	base = FIELD_GET(CXL_BI_RT_STATUS_BI_COMMIT_TM_BASE, status);
+
+	return __cxl_bi_wait_commit(dev, bi + CXL_BI_RT_STATUS_OFFSET,
+				    CXL_BI_RT_STATUS_BI_COMMITTED,
+				    CXL_BI_RT_STATUS_BI_ERR_NOT_COMMITTED,
+				    scale, base);
+}
+
+static int __cxl_bi_commit_decoder(struct device *dev, void __iomem *bi)
+{
+	u32 status, ctrl;
+	unsigned int scale, base;
+
+	if (!FIELD_GET(CXL_BI_DECODER_CAPS_EXPLICIT_COMMIT_REQ,
+		       readl(bi + CXL_BI_DECODER_CAPS_OFFSET)))
+		return 0;
+
+	ctrl = readl(bi + CXL_BI_DECODER_CTRL_OFFSET);
+	writel(ctrl & ~CXL_BI_DECODER_CTRL_BI_COMMIT,
+	       bi + CXL_BI_DECODER_CTRL_OFFSET);
+	writel(ctrl | CXL_BI_DECODER_CTRL_BI_COMMIT,
+	       bi + CXL_BI_DECODER_CTRL_OFFSET);
+
+	status = readl(bi + CXL_BI_DECODER_STATUS_OFFSET);
+	scale = FIELD_GET(CXL_BI_DECODER_STATUS_BI_COMMIT_TM_SCALE, status);
+	base = FIELD_GET(CXL_BI_DECODER_STATUS_BI_COMMIT_TM_BASE, status);
+
+	return __cxl_bi_wait_commit(dev, bi + CXL_BI_DECODER_STATUS_OFFSET,
+				    CXL_BI_DECODER_STATUS_BI_COMMITTED,
+				    CXL_BI_DECODER_STATUS_BI_ERR_NOT_COMMITTED,
+				    scale, base);
+}
+
+/* Enable or dealloc BI-ID changes in the given level of the topology. */
+static int __cxl_bi_ctrl_dport(struct cxl_dport *dport, bool enable)
+{
+	struct pci_dev *pdev = to_pci_dev(dport->dport_dev);
+	void __iomem *bi = dport->regs.bi_decoder;
+	struct cxl_port *port = dport->port;
+	u32 ctrl, value;
+	int rc;
+
+	guard(device)(&port->dev);
+	if (!bi)
+		return -EINVAL;
+
+	ctrl = readl(bi + CXL_BI_DECODER_CTRL_OFFSET);
+
+	switch (pci_pcie_type(pdev)) {
+	case PCI_EXP_TYPE_ROOT_PORT:
+		if (enable) {
+			/*
+			 * There is no point of failure from here on,
+			 * BI will be enabled on the endpoint device.
+			 */
+			dport->nr_bi++;
+
+			if (FIELD_GET(CXL_BI_DECODER_CTRL_BI_FW, ctrl) &&
+			    !FIELD_GET(CXL_BI_DECODER_CTRL_BI_ENABLE, ctrl))
+				return 0;
+
+			value = ctrl | CXL_BI_DECODER_CTRL_BI_FW;
+			value &= ~CXL_BI_DECODER_CTRL_BI_ENABLE;
+		} else {
+			if (WARN_ON_ONCE(dport->nr_bi == 0))
+				return -EINVAL;
+			if (--dport->nr_bi > 0)
+				return 0;
+
+			value = ctrl & ~(CXL_BI_DECODER_CTRL_BI_FW |
+					 CXL_BI_DECODER_CTRL_BI_ENABLE);
+		}
+
+		writel(value, bi + CXL_BI_DECODER_CTRL_OFFSET);
+		return 0;
+	case PCI_EXP_TYPE_DOWNSTREAM:
+		if (enable) {
+			value = ctrl & ~CXL_BI_DECODER_CTRL_BI_FW;
+			value |= CXL_BI_DECODER_CTRL_BI_ENABLE;
+		} else {
+			if (!FIELD_GET(CXL_BI_DECODER_CTRL_BI_ENABLE, ctrl))
+				return 0;
+			value = ctrl & ~(CXL_BI_DECODER_CTRL_BI_FW |
+					 CXL_BI_DECODER_CTRL_BI_ENABLE);
+		}
+
+		writel(value, bi + CXL_BI_DECODER_CTRL_OFFSET);
+
+		rc = __cxl_bi_commit_decoder(dport->dport_dev, bi);
+		if (rc)
+			return rc;
+
+		if (port->regs.bi_rt)
+			return __cxl_bi_commit_rt(&port->dev, port->regs.bi_rt);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int cxl_bi_ctrl_dport_enable(struct cxl_dport *dport)
+{
+	return __cxl_bi_ctrl_dport(dport, true);
+}
+
+static int cxl_bi_ctrl_dport_disable(struct cxl_dport *dport)
+{
+	return __cxl_bi_ctrl_dport(dport, false);
+}
+
+static int __cxl_bi_ctrl_endpoint(struct cxl_dev_state *cxlds, bool enable)
+{
+	struct cxl_port *endpoint = cxlds->cxlmd->endpoint;
+	void __iomem *bi = endpoint->regs.bi_decoder;
+	u32 ctrl, val;
+
+	if (!bi)
+		return -EINVAL;
+
+	ctrl = readl(bi + CXL_BI_DECODER_CTRL_OFFSET);
+
+	if (enable) {
+		if (FIELD_GET(CXL_BI_DECODER_CTRL_BI_ENABLE, ctrl)) {
+			if (cxlds->bi)
+				return 0;
+			dev_err(cxlds->dev,
+				"BI already enabled in hardware\n");
+			return -EBUSY;
+		}
+		val = ctrl | CXL_BI_DECODER_CTRL_BI_ENABLE;
+	} else {
+		if (!FIELD_GET(CXL_BI_DECODER_CTRL_BI_ENABLE, ctrl)) {
+			if (!cxlds->bi)
+				return 0;
+			dev_err(cxlds->dev,
+				"BI already disabled in hardware\n");
+			return -EBUSY;
+		}
+		val = ctrl & ~CXL_BI_DECODER_CTRL_BI_ENABLE;
+	}
+
+	writel(val, bi + CXL_BI_DECODER_CTRL_OFFSET);
+	cxlds->bi = enable;
+
+	dev_dbg(cxlds->dev, "BI requests %s\n",
+		str_enabled_disabled(enable));
+
+	return 0;
+}
+
+static int cxl_bi_ctrl_endpoint_enable(struct cxl_dev_state *cxlds)
+{
+	return __cxl_bi_ctrl_endpoint(cxlds, true);
+}
+
+static int cxl_bi_ctrl_endpoint_disable(struct cxl_dev_state *cxlds)
+{
+	return __cxl_bi_ctrl_endpoint(cxlds, false);
+}
+
+/*
+ * devm teardown on cxl_mem unbind. Endpoint decoders may still be
+ * committed here (cxl_workqueue tears them down asynchronously), but
+ * memory access has been quiesced.
+ */
+static void cxl_bi_dealloc(void *data)
+{
+	struct cxl_dev_state *cxlds = data;
+	struct cxl_dport *dport_iter, *dport;
+	struct cxl_port *port_iter;
+
+	if (!dev_is_pci(cxlds->dev))
+		return;
+
+	struct cxl_port *port __free(put_cxl_port) =
+		cxl_pci_find_port(to_pci_dev(cxlds->dev), &dport);
+	if (!port || !cxlds->bi)
+		return;
+
+	scoped_guard(rwsem_read, &cxl_rwsem.region)
+		cxl_bi_ctrl_endpoint_disable(cxlds);
+
+	port_iter = port;
+	dport_iter = dport;
+	while (!is_cxl_root(port_iter)) {
+		int rc = cxl_bi_ctrl_dport_disable(dport_iter);
+
+		/* best effort */
+		if (rc)
+			dev_dbg(&port_iter->dev,
+				"BI dport disable failed: %d\n", rc);
+
+		dport_iter = port_iter->parent_dport;
+		port_iter = dport_iter->port;
+	}
+}
+
+/*
+ * Enable BI on every dport in the path, then on the device itself.
+ * On failure, unwind only the dports that fully enabled.
+ */
+static int cxl_bi_enable_path(struct cxl_dev_state *cxlds,
+			      struct cxl_port *port, struct cxl_dport *dport)
+{
+	struct cxl_dport *dport_iter, *failed;
+	struct cxl_port *port_iter;
+	int rc;
+
+	port_iter = port;
+	dport_iter = dport;
+	while (!is_cxl_root(port_iter)) {
+		rc = cxl_bi_ctrl_dport_enable(dport_iter);
+		if (rc)
+			goto err_rollback;
+
+		dport_iter = port_iter->parent_dport;
+		port_iter = dport_iter->port;
+	}
+
+	/* finally, enable BI on the device */
+	rc = cxl_bi_ctrl_endpoint_enable(cxlds);
+	if (rc)
+		goto err_rollback;
+
+	return 0;
+
+err_rollback:
+	failed = dport_iter;
+	dport_iter = dport;
+	port_iter = port;
+	while (!is_cxl_root(port_iter) && dport_iter != failed) {
+		cxl_bi_ctrl_dport_disable(dport_iter);
+		dport_iter = port_iter->parent_dport;
+		port_iter = dport_iter->port;
+	}
+	return rc;
+}
+
+int cxl_bi_setup(struct cxl_dev_state *cxlds)
+{
+	struct cxl_port *endpoint = cxlds->cxlmd->endpoint;
+	struct cxl_dport *dport_iter, *dport;
+	struct cxl_port *port_iter;
+	struct pci_dev *pdev;
+	int rc;
+
+	if (!dev_is_pci(cxlds->dev))
+		return 0;
+
+	/* BI is VH-only */
+	if (cxlds->rcd)
+		return 0;
+
+	pdev = to_pci_dev(cxlds->dev);
+	struct cxl_port *port __free(put_cxl_port) =
+		cxl_pci_find_port(pdev, &dport);
+
+	if (!port)
+		return -EINVAL;
+
+	if (!cxl_is_bi_capable(pdev, endpoint->regs.bi_decoder))
+		return 0;
+
+	/* walkup the topology twice, first to check, then to enable */
+	port_iter = port;
+	dport_iter = dport;
+	while (!is_cxl_root(port_iter)) {
+		/* check rp, dsp */
+		if (!cxl_is_bi_capable(to_pci_dev(dport_iter->dport_dev),
+				       dport_iter->regs.bi_decoder)) {
+			dev_dbg(cxlds->dev, "BI not supported by topology\n");
+			return 0;
+		}
+
+		/* check usp */
+		if (dev_is_pci(port_iter->uport_dev) &&
+		    pci_pcie_type(to_pci_dev(port_iter->uport_dev)) ==
+			    PCI_EXP_TYPE_UPSTREAM &&
+		    !cxl_is_bi_capable(to_pci_dev(port_iter->uport_dev),
+				       port_iter->regs.bi_rt)) {
+			dev_dbg(cxlds->dev, "BI not supported by USP\n");
+			return 0;
+		}
+
+		dport_iter = port_iter->parent_dport;
+		port_iter = dport_iter->port;
+	}
+
+	rc = cxl_bi_enable_path(cxlds, port, dport);
+	if (rc)
+		return rc;
+
+	return devm_add_action_or_reset(&cxlds->cxlmd->dev,
+					cxl_bi_dealloc, cxlds);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_bi_setup, "CXL");
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index f9fcb6387fc8..e4683aefce7f 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -180,6 +180,31 @@ static inline int ways_to_eiw(unsigned int ways, u8 *eiw)
 #define CXL_HEADERLOG_TRACE_SIZE SZ_512
 #define CXL_HEADERLOG_TRACE_SIZE_U32 (CXL_HEADERLOG_TRACE_SIZE / sizeof(u32))
 
+/* CXL 4.0 8.2.4.26 CXL BI Route Table Capability Structure */
+#define CXL_BI_RT_CAPS_OFFSET 0x0
+#define   CXL_BI_RT_CAPS_EXPLICIT_COMMIT_REQ BIT(0)
+#define CXL_BI_RT_CTRL_OFFSET 0x4
+#define   CXL_BI_RT_CTRL_BI_COMMIT BIT(0)
+#define CXL_BI_RT_STATUS_OFFSET 0x8
+#define   CXL_BI_RT_STATUS_BI_COMMITTED BIT(0)
+#define   CXL_BI_RT_STATUS_BI_ERR_NOT_COMMITTED BIT(1)
+#define   CXL_BI_RT_STATUS_BI_COMMIT_TM_SCALE GENMASK(11, 8)
+#define   CXL_BI_RT_STATUS_BI_COMMIT_TM_BASE GENMASK(15, 12)
+
+/* CXL 4.0 8.2.4.27 CXL BI Decoder Capability Structure */
+#define CXL_BI_DECODER_CAPS_OFFSET 0x0
+#define   CXL_BI_DECODER_CAPS_HDMD_CAP BIT(0)
+#define   CXL_BI_DECODER_CAPS_EXPLICIT_COMMIT_REQ BIT(1)
+#define CXL_BI_DECODER_CTRL_OFFSET 0x4
+#define   CXL_BI_DECODER_CTRL_BI_FW BIT(0)
+#define   CXL_BI_DECODER_CTRL_BI_ENABLE BIT(1)
+#define   CXL_BI_DECODER_CTRL_BI_COMMIT BIT(2)
+#define CXL_BI_DECODER_STATUS_OFFSET 0x8
+#define   CXL_BI_DECODER_STATUS_BI_COMMITTED BIT(0)
+#define   CXL_BI_DECODER_STATUS_BI_ERR_NOT_COMMITTED BIT(1)
+#define   CXL_BI_DECODER_STATUS_BI_COMMIT_TM_SCALE GENMASK(11, 8)
+#define   CXL_BI_DECODER_STATUS_BI_COMMIT_TM_BASE GENMASK(15, 12)
+
 /* CXL 2.0 8.2.8.1 Device Capabilities Array Register */
 #define CXLDEV_CAP_ARRAY_OFFSET 0x0
 #define   CXLDEV_CAP_ARRAY_CAP_ID 0
@@ -647,6 +672,7 @@ struct cxl_rcrb_info {
  * @coord: access coordinates (bandwidth and latency performance attributes)
  * @link_latency: calculated PCIe downstream latency
  * @gpf_dvsec: Cached GPF port DVSEC
+ * @nr_bi: number of BI-enabled endpoints below this dport
  */
 struct cxl_dport {
 	struct device *dport_dev;
@@ -659,6 +685,7 @@ struct cxl_dport {
 	struct access_coordinate coord[ACCESS_COORDINATE_MAX];
 	long link_latency;
 	int gpf_dvsec;
+	int nr_bi;
 };
 
 /**
@@ -923,6 +950,7 @@ void cxl_coordinates_combine(struct access_coordinate *out,
 			     struct access_coordinate *c2);
 
 bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port);
+int cxl_bi_setup(struct cxl_dev_state *cxlds);
 struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port,
 					    struct device *dport_dev);
 
diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
index 798e5c369cfc..ab28c20d7897 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/mem.c
@@ -175,6 +175,10 @@ static int cxl_mem_probe(struct device *dev)
 	if (rc)
 		dev_dbg(dev, "CXL memdev EDAC registration failed rc=%d\n", rc);
 
+	rc = cxl_bi_setup(cxlds);
+	if (rc)
+		dev_dbg(dev, "BI setup failed rc=%d\n", rc);
+
 	/*
 	 * The kernel may be operating out of CXL memory on this device,
 	 * there is no spec defined way to determine whether this device
diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
index 2816954680b3..e507cb0f777f 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -168,6 +168,7 @@ struct cxl_dpa_partition {
  * @regs: Parsed register blocks
  * @cxl_dvsec: Offset to the PCIe device DVSEC
  * @rcd: operating in RCD mode (CXL 3.0 9.11.8 CXL Devices Attached to an RCH)
+ * @bi: device is BI (Back-Invalidate) enabled
  * @media_ready: Indicate whether the device media is usable
  * @dpa_res: Overall DPA resource tree for the device
  * @part: DPA partition array
@@ -187,6 +188,7 @@ struct cxl_dev_state {
 	struct cxl_device_regs regs;
 	int cxl_dvsec;
 	bool rcd;
+	bool bi;
 	bool media_ready;
 	struct resource dpa_res;
 	struct cxl_dpa_partition part[CXL_NR_PARTITIONS_MAX];
-- 
2.39.5


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

* [PATCH v6 3/9] cxl/hdm: Add BI coherency support for endpoint decoders
  2026-07-27 19:35 [PATCH v6 0/9] cxl: Support Back-Invalidate Davidlohr Bueso
  2026-07-27 19:35 ` [PATCH v6 1/9] cxl: Add BI register probing and port initialization Davidlohr Bueso
  2026-07-27 19:35 ` [PATCH v6 2/9] cxl/pci: Add BI topology enable/disable Davidlohr Bueso
@ 2026-07-27 19:35 ` Davidlohr Bueso
  2026-07-27 19:35 ` [PATCH v6 4/9] cxl: Add HDM-DB region creation Davidlohr Bueso
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Davidlohr Bueso @ 2026-07-27 19:35 UTC (permalink / raw)
  To: dave.jiang
  Cc: jic23, alison.schofield, icheng, benjamin.cheatham, alucerop,
	dongjoo.seo1, dave, linux-kernel

Cache the HDM decoder's Supported Coherency Models on struct cxl_hdm.
Region attach consults this to verify the HDM supports the region's
coherency type.

For uncommitted endpoint decoders, init_hdm_decoder() defaults
target_type from supported_coherency: Type 3 devices default to
HDM-DB when the HDM is device-coherent-only, HDM-H otherwise.

Pre-committed decoders with the BI bit set are not supported because
endpoint and port enumerations are independent -- at decoder
enumeration cxlds->bi is not yet known, so the topology cannot be
verified.

Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 drivers/cxl/core/core.h |  1 +
 drivers/cxl/core/hdm.c  | 42 ++++++++++++++++++++++++++++++-----------
 drivers/cxl/cxl.h       |  8 +++++++-
 drivers/cxl/cxlmem.h    |  2 ++
 4 files changed, 41 insertions(+), 12 deletions(-)

diff --git a/drivers/cxl/core/core.h b/drivers/cxl/core/core.h
index e36b55fd63bd..b7757de83012 100644
--- a/drivers/cxl/core/core.h
+++ b/drivers/cxl/core/core.h
@@ -215,6 +215,7 @@ struct cxl_hdm;
 int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
 			struct cxl_endpoint_dvsec_info *info);
 int cxl_port_get_possible_dports(struct cxl_port *port);
+enum cxl_decoder_type cxled_default_type(struct cxl_endpoint_decoder *cxled);
 
 #ifdef CONFIG_CXL_FEATURES
 struct cxl_feat_entry *
diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index 0c80b76a5f9b..fb01b88548c9 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -87,6 +87,8 @@ static void parse_hdm_decoder_caps(struct cxl_hdm *cxlhdm)
 		cxlhdm->iw_cap_mask |= BIT(3) | BIT(6) | BIT(12);
 	if (FIELD_GET(CXL_HDM_DECODER_INTERLEAVE_16_WAY, hdm_cap))
 		cxlhdm->iw_cap_mask |= BIT(16);
+	cxlhdm->supported_coherency =
+		FIELD_GET(CXL_HDM_DECODER_SUPPORTED_COHERENCY_MASK, hdm_cap);
 }
 
 static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info)
@@ -968,6 +970,26 @@ static int cxl_setup_hdm_decoder_from_dvsec(
 	return 0;
 }
 
+/*
+ * HDMs that advertise support for both coherency modes
+ * (CXL_HDM_DECODER_COHERENCY_BOTH) default to host-only; the region
+ * attach path switches target_type to device-coherent if the region's
+ * root decoder has the CFMWS BI bit set. Only HDMs that strictly
+ * support device-coherent mode default to HDM-DB.
+ */
+enum cxl_decoder_type cxled_default_type(struct cxl_endpoint_decoder *cxled)
+{
+	struct cxl_dev_state *cxlds = cxled_to_memdev(cxled)->cxlds;
+	struct cxl_port *port = cxled_to_port(cxled);
+	struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
+
+	if (cxlds->type == CXL_DEVTYPE_CLASSMEM &&
+	    cxlhdm->supported_coherency != CXL_HDM_DECODER_COHERENCY_DEV)
+		return CXL_DECODER_HOSTONLYMEM;
+
+	return CXL_DECODER_DEVMEM;
+}
+
 static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
 			    void __iomem *hdm, int which,
 			    u64 *dpa_base, struct cxl_endpoint_dvsec_info *info)
@@ -1023,6 +1045,14 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
 		else
 			cxld->target_type = CXL_DECODER_DEVMEM;
 
+		/*
+		 * Autocommit BI-enabled decoders is not supported.
+		 * At this point cxlds->bi is not yet setup, so there
+		 * are no guarantees that the platform supports BI.
+		 */
+		if (FIELD_GET(CXL_HDM_DECODER0_CTRL_BI, ctrl))
+			return -ENXIO;
+
 		guard(rwsem_write)(&cxl_rwsem.region);
 		if (cxld->id != cxl_num_decoders_committed(port)) {
 			dev_warn(&port->dev,
@@ -1040,17 +1070,7 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
 		port->commit_end = cxld->id;
 	} else {
 		if (cxled) {
-			struct cxl_memdev *cxlmd = cxled_to_memdev(cxled);
-			struct cxl_dev_state *cxlds = cxlmd->cxlds;
-
-			/*
-			 * Default by devtype until a device arrives that needs
-			 * more precision.
-			 */
-			if (cxlds->type == CXL_DEVTYPE_CLASSMEM)
-				cxld->target_type = CXL_DECODER_HOSTONLYMEM;
-			else
-				cxld->target_type = CXL_DECODER_DEVMEM;
+			cxld->target_type = cxled_default_type(cxled);
 		} else {
 			/* To be overridden by region type at commit time */
 			cxld->target_type = CXL_DECODER_HOSTONLYMEM;
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index e4683aefce7f..ef73efeca76a 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -50,7 +50,7 @@ extern const struct nvdimm_security_ops *cxl_security_ops;
 #define CXL_BI_RT_CAPABILITY_LENGTH 0xC
 #define CXL_BI_DECODER_CAPABILITY_LENGTH 0xC
 
-/* HDM decoders CXL 2.0 8.2.5.12 CXL HDM Decoder Capability Structure */
+/* HDM decoders CXL 4.0 8.2.4.20 CXL HDM Decoder Capability Structure */
 #define CXL_HDM_DECODER_CAP_OFFSET 0x0
 #define   CXL_HDM_DECODER_COUNT_MASK GENMASK(3, 0)
 #define   CXL_HDM_DECODER_TARGET_COUNT_MASK GENMASK(7, 4)
@@ -58,6 +58,11 @@ extern const struct nvdimm_security_ops *cxl_security_ops;
 #define   CXL_HDM_DECODER_INTERLEAVE_14_12 BIT(9)
 #define   CXL_HDM_DECODER_INTERLEAVE_3_6_12_WAY BIT(11)
 #define   CXL_HDM_DECODER_INTERLEAVE_16_WAY BIT(12)
+#define   CXL_HDM_DECODER_SUPPORTED_COHERENCY_MASK GENMASK(22, 21)
+#define     CXL_HDM_DECODER_COHERENCY_UNKNOWN 0x0
+#define     CXL_HDM_DECODER_COHERENCY_DEV 0x1
+#define     CXL_HDM_DECODER_COHERENCY_HOST 0x2
+#define     CXL_HDM_DECODER_COHERENCY_BOTH 0x3
 #define CXL_HDM_DECODER_CTRL_OFFSET 0x4
 #define   CXL_HDM_DECODER_ENABLE BIT(1)
 #define CXL_HDM_DECODER0_BASE_LOW_OFFSET(i) (0x20 * (i) + 0x10)
@@ -72,6 +77,7 @@ extern const struct nvdimm_security_ops *cxl_security_ops;
 #define   CXL_HDM_DECODER0_CTRL_COMMITTED BIT(10)
 #define   CXL_HDM_DECODER0_CTRL_COMMIT_ERROR BIT(11)
 #define   CXL_HDM_DECODER0_CTRL_HOSTONLY BIT(12)
+#define   CXL_HDM_DECODER0_CTRL_BI BIT(13)
 #define CXL_HDM_DECODER0_TL_LOW(i) (0x20 * (i) + 0x24)
 #define CXL_HDM_DECODER0_TL_HIGH(i) (0x20 * (i) + 0x28)
 #define CXL_HDM_DECODER0_SKIP_LOW(i) CXL_HDM_DECODER0_TL_LOW(i)
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index ed419d0c59f2..344424684cd6 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -859,6 +859,7 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd);
  * @target_count: for switch decoders, max downstream port targets
  * @interleave_mask: interleave granularity capability, see check_interleave_cap()
  * @iw_cap_mask: bitmask of supported interleave ways, see check_interleave_cap()
+ * @supported_coherency: HDM Decoder Capability supported coherency models
  * @port: mapped cxl_port, see devm_cxl_setup_hdm()
  */
 struct cxl_hdm {
@@ -867,6 +868,7 @@ struct cxl_hdm {
 	unsigned int target_count;
 	unsigned int interleave_mask;
 	unsigned long iw_cap_mask;
+	unsigned int supported_coherency;
 	struct cxl_port *port;
 };
 
-- 
2.39.5


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

* [PATCH v6 4/9] cxl: Add HDM-DB region creation
  2026-07-27 19:35 [PATCH v6 0/9] cxl: Support Back-Invalidate Davidlohr Bueso
                   ` (2 preceding siblings ...)
  2026-07-27 19:35 ` [PATCH v6 3/9] cxl/hdm: Add BI coherency support for endpoint decoders Davidlohr Bueso
@ 2026-07-27 19:35 ` Davidlohr Bueso
  2026-07-27 19:35 ` [PATCH v6 5/9] cxl/hdm: Rename decoder coherency flags Davidlohr Bueso
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Davidlohr Bueso @ 2026-07-27 19:35 UTC (permalink / raw)
  To: dave.jiang
  Cc: jic23, alison.schofield, icheng, benjamin.cheatham, alucerop,
	dongjoo.seo1, dave, linux-kernel

A region inherits its coherency from the chosen root decoder: HDM-DB
if the root has CXL_DECODER_F_BI, otherwise HDM-H.

Surface the topology through read-only sysfs:

  - decoderX.Y/cap_bi (root): CFMWS BI restriction.
  - decoderX.Y/bi (endpoint): '1' when configured for HDM-DB.

cxl_region_attach() rejects endpoints whose device or HDM cannot
serve the region's type; target_type is inherited from cxlr->type
in cxl_rr_assign_decoder() and restored to the endpoint default on
detach.

The HDM Decoder Control BI bit is set at commit time only when the
target_type is DEVMEM and the BI capability is advertised
(cxlds->bi for endpoints, root F_BI for switches).

Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 Documentation/ABI/testing/sysfs-bus-cxl | 18 ++++++++--
 drivers/cxl/acpi.c                      | 15 ++++++++
 drivers/cxl/core/hdm.c                  | 16 +++++++++
 drivers/cxl/core/port.c                 | 39 +++++++++++++++++---
 drivers/cxl/core/region.c               | 48 +++++++++++++++++++++----
 drivers/cxl/cxl.h                       |  5 +++
 6 files changed, 127 insertions(+), 14 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-cxl b/Documentation/ABI/testing/sysfs-bus-cxl
index 16a9b3d2e2c0..370c6fd7d245 100644
--- a/Documentation/ABI/testing/sysfs-bus-cxl
+++ b/Documentation/ABI/testing/sysfs-bus-cxl
@@ -297,7 +297,7 @@ Description:
 		Each entry in the list is a dport id.
 
 
-What:		/sys/bus/cxl/devices/decoderX.Y/cap_{pmem,ram,type2,type3}
+What:		/sys/bus/cxl/devices/decoderX.Y/cap_{pmem,ram,type2,type3,bi}
 Date:		June, 2021
 KernelVersion:	v5.14
 Contact:	linux-cxl@vger.kernel.org
@@ -306,8 +306,9 @@ Description:
 		represents a fixed memory window identified by platform
 		firmware. A fixed window may only support a subset of memory
 		types. The 'cap_*' attributes indicate whether persistent
-		memory, volatile memory, accelerator memory, and / or expander
-		memory may be mapped behind this decoder's memory window.
+		memory, volatile memory, accelerator memory, expander memory,
+		and / or back-invalidate (HDM-DB) memory may be mapped behind
+		this decoder's memory window.
 
 
 What:		/sys/bus/cxl/devices/decoderX.Y/target_type
@@ -426,6 +427,17 @@ Description:
 		current cached value.
 
 
+What:		/sys/bus/cxl/devices/decoderX.Y/bi
+Date:		July, 2026
+KernelVersion:	v7.3
+Contact:	linux-cxl@vger.kernel.org
+Description:
+		(RO) Shows '1' if this endpoint decoder is currently configured
+		for HDM-DB (device-managed coherency with back-invalidate).
+		The HDM-DB state is inherited from the region the decoder is
+		attached to, which is in turn set from the chosen root
+		decoder's CFMWS BI restriction (see cap_bi).
+
 What:		/sys/bus/cxl/devices/decoderX.Y/delete_region
 Date:		May, 2022
 KernelVersion:	v6.0
diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
index 3b818adbd38b..eceb8dd97df2 100644
--- a/drivers/cxl/acpi.c
+++ b/drivers/cxl/acpi.c
@@ -152,6 +152,8 @@ static unsigned long cfmws_to_decoder_flags(int restrictions)
 		flags |= CXL_DECODER_F_PMEM;
 	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_FIXED)
 		flags |= CXL_DECODER_F_LOCK;
+	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_BI)
+		flags |= CXL_DECODER_F_BI;
 
 	return flags;
 }
@@ -198,6 +200,12 @@ static int cxl_acpi_cfmws_verify(struct device *dev,
 		dev_dbg(dev, "CFMWS length %d greater than expected %d\n",
 			cfmws->header.length, expected_len);
 
+	if ((cfmws->restrictions & ACPI_CEDT_CFMWS_RESTRICT_HOSTONLYMEM) &&
+	    (cfmws->restrictions & ACPI_CEDT_CFMWS_RESTRICT_BI)) {
+		dev_err(dev, "CFMWS cannot have both HDM-H and HDM-DB\n");
+		return -EINVAL;
+	}
+
 	return 0;
 }
 
@@ -437,7 +445,14 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
 
 	cxld = &cxlrd->cxlsd.cxld;
 	cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
+	/* host-only wins if firmware sets both coherency restrictions */
 	cxld->target_type = CXL_DECODER_HOSTONLYMEM;
+	if (cxld->flags & CXL_DECODER_F_TYPE2) {
+		if (cxld->flags & CXL_DECODER_F_TYPE3)
+			dev_dbg(dev, "CFMWS has both HDM-H and HDM-D\n");
+		else
+			cxld->target_type = CXL_DECODER_DEVMEM;
+	}
 	cxld->hpa_range = (struct range) {
 		.start = cfmws->base_hpa,
 		.end = cfmws->base_hpa + cfmws->window_size - 1,
diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index fb01b88548c9..f437fe15c6df 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -705,9 +705,25 @@ static void cxld_set_interleave(struct cxl_decoder *cxld, u32 *ctrl)
 
 static void cxld_set_type(struct cxl_decoder *cxld, u32 *ctrl)
 {
+	bool bi = cxld->target_type == CXL_DECODER_DEVMEM;
+
+	if (bi) {
+		if (is_endpoint_decoder(&cxld->dev)) {
+			struct cxl_endpoint_decoder *cxled =
+				to_cxl_endpoint_decoder(&cxld->dev);
+			struct cxl_dev_state *cxlds =
+				cxled_to_memdev(cxled)->cxlds;
+
+			bi = cxlds->bi;
+		} else if (cxld->region) {
+			bi = cxl_root_decoder_is_bi(cxld->region->cxlrd);
+		}
+	}
+
 	u32p_replace_bits(ctrl,
 			  !!(cxld->target_type == CXL_DECODER_HOSTONLYMEM),
 			  CXL_HDM_DECODER0_CTRL_HOSTONLY);
+	u32p_replace_bits(ctrl, bi, CXL_HDM_DECODER0_CTRL_BI);
 }
 
 static void cxlsd_set_targets(struct cxl_switch_decoder *cxlsd, u64 *tgt)
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index b2f8fb9547d3..0bcb3ad7905c 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -131,6 +131,7 @@ CXL_DECODER_FLAG_ATTR(cap_ram, CXL_DECODER_F_RAM);
 CXL_DECODER_FLAG_ATTR(cap_type2, CXL_DECODER_F_TYPE2);
 CXL_DECODER_FLAG_ATTR(cap_type3, CXL_DECODER_F_TYPE3);
 CXL_DECODER_FLAG_ATTR(locked, CXL_DECODER_F_LOCK);
+CXL_DECODER_FLAG_ATTR(cap_bi, CXL_DECODER_F_BI);
 
 static ssize_t target_type_show(struct device *dev,
 				struct device_attribute *attr, char *buf)
@@ -233,6 +234,26 @@ static ssize_t mode_store(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RW(mode);
 
+static ssize_t bi_show(struct device *dev, struct device_attribute *attr,
+		       char *buf)
+{
+	struct cxl_endpoint_decoder *cxled = to_cxl_endpoint_decoder(dev);
+	struct cxl_dev_state *cxlds = cxled_to_memdev(cxled)->cxlds;
+	struct cxl_region *cxlr;
+
+	guard(rwsem_read)(&cxl_rwsem.region);
+	/*
+	 * An endpoint decoder is HDM-DB when the device advertises BI
+	 * (cxlds->bi) and it is attached to a device-coherent (DEVMEM)
+	 * region whose root decoder advertises the CFMWS BI restriction.
+	 */
+	cxlr = cxled->cxld.region;
+	return sysfs_emit(buf, "%d\n", cxlds->bi && cxlr &&
+			  cxled->cxld.target_type == CXL_DECODER_DEVMEM &&
+			  cxl_root_decoder_is_bi(cxlr->cxlrd));
+}
+static DEVICE_ATTR_RO(bi);
+
 static ssize_t dpa_resource_show(struct device *dev, struct device_attribute *attr,
 			    char *buf)
 {
@@ -329,6 +350,7 @@ static struct attribute *cxl_decoder_root_attrs[] = {
 	&dev_attr_cap_ram.attr,
 	&dev_attr_cap_type2.attr,
 	&dev_attr_cap_type3.attr,
+	&dev_attr_cap_bi.attr,
 	&dev_attr_target_list.attr,
 	&dev_attr_qos_class.attr,
 	SET_CXL_REGION_ATTR(create_pmem_region)
@@ -339,16 +361,24 @@ static struct attribute *cxl_decoder_root_attrs[] = {
 
 static bool can_create_pmem(struct cxl_root_decoder *cxlrd)
 {
-	unsigned long flags = CXL_DECODER_F_TYPE3 | CXL_DECODER_F_PMEM;
+	unsigned long flags = cxlrd->cxlsd.cxld.flags;
+	unsigned long hdm_h, hdm_db;
 
-	return (cxlrd->cxlsd.cxld.flags & flags) == flags;
+	hdm_h = CXL_DECODER_F_TYPE3 | CXL_DECODER_F_PMEM;
+	hdm_db = CXL_DECODER_F_TYPE2 | CXL_DECODER_F_BI | CXL_DECODER_F_PMEM;
+
+	return (flags & hdm_h) == hdm_h || (flags & hdm_db) == hdm_db;
 }
 
 static bool can_create_ram(struct cxl_root_decoder *cxlrd)
 {
-	unsigned long flags = CXL_DECODER_F_TYPE3 | CXL_DECODER_F_RAM;
+	unsigned long flags = cxlrd->cxlsd.cxld.flags;
+	unsigned long hdm_h, hdm_db;
+
+	hdm_h = CXL_DECODER_F_TYPE3 | CXL_DECODER_F_RAM;
+	hdm_db = CXL_DECODER_F_TYPE2 | CXL_DECODER_F_BI | CXL_DECODER_F_RAM;
 
-	return (cxlrd->cxlsd.cxld.flags & flags) == flags;
+	return (flags & hdm_h) == hdm_h || (flags & hdm_db) == hdm_db;
 }
 
 static umode_t cxl_root_decoder_visible(struct kobject *kobj, struct attribute *a, int n)
@@ -402,6 +432,7 @@ static const struct attribute_group *cxl_decoder_switch_attribute_groups[] = {
 static struct attribute *cxl_decoder_endpoint_attrs[] = {
 	&dev_attr_target_type.attr,
 	&dev_attr_mode.attr,
+	&dev_attr_bi.attr,
 	&dev_attr_dpa_size.attr,
 	&dev_attr_dpa_resource.attr,
 	SET_CXL_REGION_ATTR(region)
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 1e211542b6b6..1b8284f66e61 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -1132,11 +1132,13 @@ static int cxl_rr_assign_decoder(struct cxl_port *port, struct cxl_region *cxlr,
 	/*
 	 * Endpoints should already match the region type, but backstop that
 	 * assumption with an assertion. Switch-decoders change mapping-type
-	 * based on what is mapped when they are assigned to a region.
+	 * based on what is mapped when they are assigned to a region. HDM-DB
+	 * endpoint decoders inherit their type from cxlr->type below.
 	 */
 	dev_WARN_ONCE(&cxlr->dev,
 		      port == cxled_to_port(cxled) &&
-			      cxld->target_type != cxlr->type,
+			      cxld->target_type != cxlr->type &&
+			      !cxl_root_decoder_is_bi(cxlr->cxlrd),
 		      "%s:%s mismatch decoder type %d -> %d\n",
 		      dev_name(&cxled_to_memdev(cxled)->dev),
 		      dev_name(&cxld->dev), cxld->target_type, cxlr->type);
@@ -2059,6 +2061,7 @@ static int cxl_region_attach(struct cxl_region *cxlr,
 	struct cxl_region_params *p = &cxlr->params;
 	struct cxl_port *ep_port, *root_port;
 	struct cxl_dport *dport;
+	struct cxl_hdm *cxlhdm;
 	int rc = -ENXIO;
 
 	rc = check_interleave_cap(&cxled->cxld, p->interleave_ways,
@@ -2108,10 +2111,31 @@ static int cxl_region_attach(struct cxl_region *cxlr,
 		return -ENXIO;
 	}
 
-	if (cxled->cxld.target_type != cxlr->type) {
-		dev_dbg(&cxlr->dev, "%s:%s type mismatch: %d vs %d\n",
-			dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev),
-			cxled->cxld.target_type, cxlr->type);
+	/*
+	 * Verify the device and HDM are capable of the region's flavor before
+	 * proceeding. The endpoint decoder's target_type is then inherited
+	 * from cxlr->type later in cxl_rr_assign_decoder().
+	 */
+	if (cxlr->type == CXL_DECODER_DEVMEM &&
+	    cxl_root_decoder_is_bi(cxlrd) && !cxlds->bi) {
+		dev_err(&cxlr->dev, "%s:%s BI not enabled on device\n",
+			dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev));
+		return -ENXIO;
+	}
+
+	cxlhdm = dev_get_drvdata(&ep_port->dev);
+	if (!cxlhdm)
+		return -ENXIO;
+	if (cxlr->type == CXL_DECODER_HOSTONLYMEM &&
+	    cxlhdm->supported_coherency == CXL_HDM_DECODER_COHERENCY_DEV) {
+		dev_warn(&cxlr->dev, "%s:%s HDM is device-coherent only\n",
+			 dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev));
+		return -ENXIO;
+	}
+	if (cxlr->type == CXL_DECODER_DEVMEM &&
+	    cxlhdm->supported_coherency == CXL_HDM_DECODER_COHERENCY_HOST) {
+		dev_warn(&cxlr->dev, "%s:%s HDM is host-only coherent\n",
+			 dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev));
 		return -ENXIO;
 	}
 
@@ -2327,6 +2351,8 @@ __cxl_decoder_detach(struct cxl_region *cxlr,
 		.start = 0,
 		.end = -1,
 	};
+	/* undo cxl_rr_assign_decoder() type inheritance */
+	cxled->cxld.target_type = cxled_default_type(cxled);
 
 	get_device(&cxlr->dev);
 	return cxlr;
@@ -2823,6 +2849,7 @@ static ssize_t create_region_store(struct device *dev, const char *buf,
 				   size_t len, enum cxl_partition_mode mode)
 {
 	struct cxl_root_decoder *cxlrd = to_cxl_root_decoder(dev);
+	enum cxl_decoder_type target_type;
 	struct cxl_region *cxlr;
 	int rc, id;
 
@@ -2834,7 +2861,14 @@ static ssize_t create_region_store(struct device *dev, const char *buf,
 	if ((rc = ACQUIRE_ERR(mutex_intr, &regions_lock)))
 		return rc;
 
-	cxlr = __create_region(cxlrd, mode, id, CXL_DECODER_HOSTONLYMEM);
+	/*
+	 * The CFMWS dictates endpoint coherency: a BI-restricted Window
+	 * produces an HDM-DB region; otherwise HDM-H.
+	 */
+	target_type = cxl_root_decoder_is_bi(cxlrd) ?
+		CXL_DECODER_DEVMEM : CXL_DECODER_HOSTONLYMEM;
+
+	cxlr = __create_region(cxlrd, mode, id, target_type);
 	if (IS_ERR(cxlr))
 		return PTR_ERR(cxlr);
 
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index ef73efeca76a..62c5bd9e295c 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -300,6 +300,7 @@ int cxl_dport_map_rcd_linkcap(struct pci_dev *pdev, struct cxl_dport *dport);
 #define CXL_DECODER_F_LOCK  BIT(4)
 #define CXL_DECODER_F_ENABLE    BIT(5)
 #define CXL_DECODER_F_NORMALIZED_ADDRESSING BIT(6)
+#define CXL_DECODER_F_BI    BIT(7)
 #define CXL_DECODER_F_RESET_MASK (CXL_DECODER_F_ENABLE | CXL_DECODER_F_LOCK)
 
 enum cxl_decoder_type {
@@ -824,6 +825,10 @@ static inline int cxl_root_decoder_autoremove(struct device *host,
 {
 	return cxl_decoder_autoremove(host, &cxlrd->cxlsd.cxld);
 }
+static inline bool cxl_root_decoder_is_bi(struct cxl_root_decoder *cxlrd)
+{
+	return cxlrd->cxlsd.cxld.flags & CXL_DECODER_F_BI;
+}
 int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint);
 
 /**
-- 
2.39.5


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

* [PATCH v6 5/9] cxl/hdm: Rename decoder coherency flags
  2026-07-27 19:35 [PATCH v6 0/9] cxl: Support Back-Invalidate Davidlohr Bueso
                   ` (3 preceding siblings ...)
  2026-07-27 19:35 ` [PATCH v6 4/9] cxl: Add HDM-DB region creation Davidlohr Bueso
@ 2026-07-27 19:35 ` Davidlohr Bueso
  2026-07-27 19:35 ` [PATCH v6 6/9] cxl/region: Log the coherency model at region creation Davidlohr Bueso
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Davidlohr Bueso @ 2026-07-27 19:35 UTC (permalink / raw)
  To: dave.jiang
  Cc: jic23, alison.schofield, icheng, benjamin.cheatham, alucerop,
	dongjoo.seo1, dave, linux-kernel

Align with the ACPI CXL Window restriction naming and convert
CXL_DECODER_F_TYPE2/F_TYPE3 to F_DEVMEM/F_HOSTONLY. Type2 and
Type3 coherency models were named prior to Back-Invalidate.

Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 drivers/cxl/acpi.c      |  8 ++++----
 drivers/cxl/core/port.c | 12 ++++++------
 drivers/cxl/cxl.h       |  4 ++--
 3 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c
index eceb8dd97df2..2c54f709c45d 100644
--- a/drivers/cxl/acpi.c
+++ b/drivers/cxl/acpi.c
@@ -143,9 +143,9 @@ static unsigned long cfmws_to_decoder_flags(int restrictions)
 	unsigned long flags = CXL_DECODER_F_ENABLE;
 
 	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_DEVMEM)
-		flags |= CXL_DECODER_F_TYPE2;
+		flags |= CXL_DECODER_F_DEVMEM;
 	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_HOSTONLYMEM)
-		flags |= CXL_DECODER_F_TYPE3;
+		flags |= CXL_DECODER_F_HOSTONLY;
 	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_VOLATILE)
 		flags |= CXL_DECODER_F_RAM;
 	if (restrictions & ACPI_CEDT_CFMWS_RESTRICT_PMEM)
@@ -447,8 +447,8 @@ static int __cxl_parse_cfmws(struct acpi_cedt_cfmws *cfmws,
 	cxld->flags = cfmws_to_decoder_flags(cfmws->restrictions);
 	/* host-only wins if firmware sets both coherency restrictions */
 	cxld->target_type = CXL_DECODER_HOSTONLYMEM;
-	if (cxld->flags & CXL_DECODER_F_TYPE2) {
-		if (cxld->flags & CXL_DECODER_F_TYPE3)
+	if (cxld->flags & CXL_DECODER_F_DEVMEM) {
+		if (cxld->flags & CXL_DECODER_F_HOSTONLY)
 			dev_dbg(dev, "CFMWS has both HDM-H and HDM-D\n");
 		else
 			cxld->target_type = CXL_DECODER_DEVMEM;
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 0bcb3ad7905c..4fce2188cd8c 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -128,8 +128,8 @@ static DEVICE_ATTR_RO(name)
 
 CXL_DECODER_FLAG_ATTR(cap_pmem, CXL_DECODER_F_PMEM);
 CXL_DECODER_FLAG_ATTR(cap_ram, CXL_DECODER_F_RAM);
-CXL_DECODER_FLAG_ATTR(cap_type2, CXL_DECODER_F_TYPE2);
-CXL_DECODER_FLAG_ATTR(cap_type3, CXL_DECODER_F_TYPE3);
+CXL_DECODER_FLAG_ATTR(cap_type2, CXL_DECODER_F_DEVMEM);
+CXL_DECODER_FLAG_ATTR(cap_type3, CXL_DECODER_F_HOSTONLY);
 CXL_DECODER_FLAG_ATTR(locked, CXL_DECODER_F_LOCK);
 CXL_DECODER_FLAG_ATTR(cap_bi, CXL_DECODER_F_BI);
 
@@ -364,8 +364,8 @@ static bool can_create_pmem(struct cxl_root_decoder *cxlrd)
 	unsigned long flags = cxlrd->cxlsd.cxld.flags;
 	unsigned long hdm_h, hdm_db;
 
-	hdm_h = CXL_DECODER_F_TYPE3 | CXL_DECODER_F_PMEM;
-	hdm_db = CXL_DECODER_F_TYPE2 | CXL_DECODER_F_BI | CXL_DECODER_F_PMEM;
+	hdm_h = CXL_DECODER_F_HOSTONLY | CXL_DECODER_F_PMEM;
+	hdm_db = CXL_DECODER_F_DEVMEM | CXL_DECODER_F_BI | CXL_DECODER_F_PMEM;
 
 	return (flags & hdm_h) == hdm_h || (flags & hdm_db) == hdm_db;
 }
@@ -375,8 +375,8 @@ static bool can_create_ram(struct cxl_root_decoder *cxlrd)
 	unsigned long flags = cxlrd->cxlsd.cxld.flags;
 	unsigned long hdm_h, hdm_db;
 
-	hdm_h = CXL_DECODER_F_TYPE3 | CXL_DECODER_F_RAM;
-	hdm_db = CXL_DECODER_F_TYPE2 | CXL_DECODER_F_BI | CXL_DECODER_F_RAM;
+	hdm_h = CXL_DECODER_F_HOSTONLY | CXL_DECODER_F_RAM;
+	hdm_db = CXL_DECODER_F_DEVMEM | CXL_DECODER_F_BI | CXL_DECODER_F_RAM;
 
 	return (flags & hdm_h) == hdm_h || (flags & hdm_db) == hdm_db;
 }
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 62c5bd9e295c..5f4a11538bbf 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -295,8 +295,8 @@ int cxl_dport_map_rcd_linkcap(struct pci_dev *pdev, struct cxl_dport *dport);
  */
 #define CXL_DECODER_F_RAM   BIT(0)
 #define CXL_DECODER_F_PMEM  BIT(1)
-#define CXL_DECODER_F_TYPE2 BIT(2)
-#define CXL_DECODER_F_TYPE3 BIT(3)
+#define CXL_DECODER_F_DEVMEM BIT(2)
+#define CXL_DECODER_F_HOSTONLY BIT(3)
 #define CXL_DECODER_F_LOCK  BIT(4)
 #define CXL_DECODER_F_ENABLE    BIT(5)
 #define CXL_DECODER_F_NORMALIZED_ADDRESSING BIT(6)
-- 
2.39.5


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

* [PATCH v6 6/9] cxl/region: Log the coherency model at region creation
  2026-07-27 19:35 [PATCH v6 0/9] cxl: Support Back-Invalidate Davidlohr Bueso
                   ` (4 preceding siblings ...)
  2026-07-27 19:35 ` [PATCH v6 5/9] cxl/hdm: Rename decoder coherency flags Davidlohr Bueso
@ 2026-07-27 19:35 ` Davidlohr Bueso
  2026-07-27 19:35 ` [PATCH v6 7/9] cxl: Move BI setup to endpoint port probe Davidlohr Bueso
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Davidlohr Bueso @ 2026-07-27 19:35 UTC (permalink / raw)
  To: dave.jiang
  Cc: jic23, alison.schofield, icheng, benjamin.cheatham, alucerop,
	dongjoo.seo1, dave, linux-kernel

Region assembly emits plenty of debug information - resources,
interleave geometry, target placement - but not the coherency model
the region operates in.

Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 drivers/cxl/core/region.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 1b8284f66e61..7c11d5788d99 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -2746,6 +2746,17 @@ void kill_regions(struct cxl_root_decoder *cxlrd)
 		unregister_region(cxlr);
 }
 
+static const char *cxl_region_coherency(struct cxl_region *cxlr)
+{
+	if (cxlr->type == CXL_DECODER_HOSTONLYMEM)
+		return "HDM-H";
+
+	if (cxl_root_decoder_is_bi(cxlr->cxlrd))
+		return "HDM-DB";
+
+	return "HDM-D";
+}
+
 /**
  * devm_cxl_add_region - Adds a region to a decoder
  * @cxlrd: root decoder
@@ -2790,8 +2801,9 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd,
 		return ERR_PTR(rc);
 	}
 
-	dev_dbg(port->uport_dev, "%s: created %s\n",
-		dev_name(&cxlrd->cxlsd.cxld.dev), dev_name(dev));
+	dev_dbg(port->uport_dev, "%s: created %s %s\n",
+		dev_name(&cxlrd->cxlsd.cxld.dev), cxl_region_coherency(cxlr),
+		dev_name(dev));
 	return cxlr;
 err:
 	put_device(dev);
-- 
2.39.5


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

* [PATCH v6 7/9] cxl: Move BI setup to endpoint port probe
  2026-07-27 19:35 [PATCH v6 0/9] cxl: Support Back-Invalidate Davidlohr Bueso
                   ` (5 preceding siblings ...)
  2026-07-27 19:35 ` [PATCH v6 6/9] cxl/region: Log the coherency model at region creation Davidlohr Bueso
@ 2026-07-27 19:35 ` Davidlohr Bueso
  2026-07-27 19:36 ` [PATCH v6 8/9] cxl/pci: Split BI capability probe from setup Davidlohr Bueso
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 14+ messages in thread
From: Davidlohr Bueso @ 2026-07-27 19:35 UTC (permalink / raw)
  To: dave.jiang
  Cc: jic23, alison.schofield, icheng, benjamin.cheatham, alucerop,
	dongjoo.seo1, dave, linux-kernel

Move cxl_bi_setup (BI-ID allocation) from cxl_mem_probe() into
cxl_endpoint_port_probe(): the BI-ID and path enablement belong to
the endpoint port's lifetime, not the memdev driver's. The dealloc
devm action moves to the endpoint port accordingly.

Setup is safe in endpoint port probe context: the port probes
synchronously from cxl_mem_probe(), pinning the memdev state the
walk consumes, and the whole ancestor path already exists with BI
registers mapped (dports at dport-add time, the switch USP RT at
first-dport setup) because devm_cxl_enumerate_ports() completes
before the endpoint is created.

Dealloc is safe in endpoint devres context: both setup and dealloc
walk the endpoint's parent_dport topology rather than getting the
port by bus lookup - an ancestor teardown delists the parent port
before the endpoint's devres runs.

The topology walk is stable as parent_dport pointers are fixed at
port creation; ancestors cannot be reaped while holding this
memdev's cxl_ep; and their own teardown frees dports only after
the endpoint is gone.

The device state holds up as well: cxlmd->cxlds is nulled only
after cxl_memdev_unregister() has torn the endpoint down, and
delete_endpoint() clears cxlmd->endpoint only after the endpoint
devres has run.

With dealloc in the endpoint's devres, delete_endpoint() already
holds the parent port's device lock, so to avoid deadlocking, add a
per-port bi_lock, serializing only dports that share state (ie:
sibling nr_bi on a root port, the switch USP's BI RT).

Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 drivers/cxl/core/pci.c  | 57 +++++++++++++++++++----------------------
 drivers/cxl/core/port.c |  1 +
 drivers/cxl/cxl.h       |  4 ++-
 drivers/cxl/mem.c       |  4 ---
 drivers/cxl/port.c      |  4 +++
 5 files changed, 35 insertions(+), 35 deletions(-)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 12cb50640f65..a87c2ad9ac53 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -1092,7 +1092,7 @@ static int __cxl_bi_ctrl_dport(struct cxl_dport *dport, bool enable)
 	u32 ctrl, value;
 	int rc;
 
-	guard(device)(&port->dev);
+	guard(mutex)(&port->bi_lock);
 	if (!bi)
 		return -EINVAL;
 
@@ -1211,29 +1211,31 @@ static int cxl_bi_ctrl_endpoint_disable(struct cxl_dev_state *cxlds)
 }
 
 /*
- * devm teardown on cxl_mem unbind. Endpoint decoders may still be
- * committed here (cxl_workqueue tears them down asynchronously), but
- * memory access has been quiesced.
+ * devm teardown on endpoint port destruction. Endpoint decoders may
+ * still be committed here (cxl_workqueue tears them down
+ * asynchronously), but memory access has been quiesced.
  */
 static void cxl_bi_dealloc(void *data)
 {
-	struct cxl_dev_state *cxlds = data;
-	struct cxl_dport *dport_iter, *dport;
+	struct cxl_port *endpoint = data;
+	struct cxl_memdev *cxlmd = to_cxl_memdev(endpoint->uport_dev);
+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
+	struct cxl_dport *dport_iter;
 	struct cxl_port *port_iter;
 
-	if (!dev_is_pci(cxlds->dev))
-		return;
-
-	struct cxl_port *port __free(put_cxl_port) =
-		cxl_pci_find_port(to_pci_dev(cxlds->dev), &dport);
-	if (!port || !cxlds->bi)
+	if (!cxlds->bi)
 		return;
 
 	scoped_guard(rwsem_read, &cxl_rwsem.region)
 		cxl_bi_ctrl_endpoint_disable(cxlds);
 
-	port_iter = port;
-	dport_iter = dport;
+	/*
+	 * Walk the same parent_dport chain that enabled the path. A bus
+	 * lookup cannot stand in for it: an ancestor-driven teardown
+	 * delists the parent port before this devres action runs.
+	 */
+	dport_iter = endpoint->parent_dport;
+	port_iter = dport_iter->port;
 	while (!is_cxl_root(port_iter)) {
 		int rc = cxl_bi_ctrl_dport_disable(dport_iter);
 
@@ -1288,12 +1290,13 @@ static int cxl_bi_enable_path(struct cxl_dev_state *cxlds,
 	return rc;
 }
 
-int cxl_bi_setup(struct cxl_dev_state *cxlds)
+int cxl_bi_setup(struct cxl_port *endpoint)
 {
-	struct cxl_port *endpoint = cxlds->cxlmd->endpoint;
-	struct cxl_dport *dport_iter, *dport;
+	struct cxl_memdev *cxlmd = to_cxl_memdev(endpoint->uport_dev);
+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
+	struct cxl_dport *dport = endpoint->parent_dport;
+	struct cxl_dport *dport_iter;
 	struct cxl_port *port_iter;
-	struct pci_dev *pdev;
 	int rc;
 
 	if (!dev_is_pci(cxlds->dev))
@@ -1303,18 +1306,12 @@ int cxl_bi_setup(struct cxl_dev_state *cxlds)
 	if (cxlds->rcd)
 		return 0;
 
-	pdev = to_pci_dev(cxlds->dev);
-	struct cxl_port *port __free(put_cxl_port) =
-		cxl_pci_find_port(pdev, &dport);
-
-	if (!port)
-		return -EINVAL;
-
-	if (!cxl_is_bi_capable(pdev, endpoint->regs.bi_decoder))
+	if (!cxl_is_bi_capable(to_pci_dev(cxlds->dev),
+			       endpoint->regs.bi_decoder))
 		return 0;
 
 	/* walkup the topology twice, first to check, then to enable */
-	port_iter = port;
+	port_iter = dport->port;
 	dport_iter = dport;
 	while (!is_cxl_root(port_iter)) {
 		/* check rp, dsp */
@@ -1338,11 +1335,11 @@ int cxl_bi_setup(struct cxl_dev_state *cxlds)
 		port_iter = dport_iter->port;
 	}
 
-	rc = cxl_bi_enable_path(cxlds, port, dport);
+	rc = cxl_bi_enable_path(cxlds, dport->port, dport);
 	if (rc)
 		return rc;
 
-	return devm_add_action_or_reset(&cxlds->cxlmd->dev,
-					cxl_bi_dealloc, cxlds);
+	return devm_add_action_or_reset(&endpoint->dev, cxl_bi_dealloc,
+					endpoint);
 }
 EXPORT_SYMBOL_NS_GPL(cxl_bi_setup, "CXL");
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 4fce2188cd8c..57882f4c2d8e 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -772,6 +772,7 @@ static struct cxl_port *cxl_port_alloc(struct device *uport_dev,
 	xa_init(&port->dports);
 	xa_init(&port->endpoints);
 	xa_init(&port->regions);
+	mutex_init(&port->bi_lock);
 	port->component_reg_phys = CXL_RESOURCE_NONE;
 
 	device_initialize(dev);
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index 5f4a11538bbf..ca7051641c47 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -594,6 +594,7 @@ struct cxl_dax_region {
  * @decoder_ida: allocator for decoder ids
  * @reg_map: component and ras register mapping parameters
  * @regs: mapped component registers
+ * @bi_lock: serializes BI Decoder/RT state of this port's dports
  * @nr_dports: number of entries in @dports
  * @hdm_end: track last allocated HDM decoder instance for allocation ordering
  * @commit_end: cursor to track highest committed decoder for commit ordering
@@ -616,6 +617,7 @@ struct cxl_port {
 	struct ida decoder_ida;
 	struct cxl_register_map reg_map;
 	struct cxl_component_regs regs;
+	struct mutex bi_lock;
 	int nr_dports;
 	int hdm_end;
 	int commit_end;
@@ -961,7 +963,7 @@ void cxl_coordinates_combine(struct access_coordinate *out,
 			     struct access_coordinate *c2);
 
 bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port);
-int cxl_bi_setup(struct cxl_dev_state *cxlds);
+int cxl_bi_setup(struct cxl_port *endpoint);
 struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port,
 					    struct device *dport_dev);
 
diff --git a/drivers/cxl/mem.c b/drivers/cxl/mem.c
index ab28c20d7897..798e5c369cfc 100644
--- a/drivers/cxl/mem.c
+++ b/drivers/cxl/mem.c
@@ -175,10 +175,6 @@ static int cxl_mem_probe(struct device *dev)
 	if (rc)
 		dev_dbg(dev, "CXL memdev EDAC registration failed rc=%d\n", rc);
 
-	rc = cxl_bi_setup(cxlds);
-	if (rc)
-		dev_dbg(dev, "BI setup failed rc=%d\n", rc);
-
 	/*
 	 * The kernel may be operating out of CXL memory on this device,
 	 * there is no spec defined way to determine whether this device
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index a527dd13fb68..22bd4254ba8d 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -180,6 +180,10 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
 	if (rc)
 		return rc;
 
+	rc = cxl_bi_setup(port);
+	if (rc)
+		dev_dbg(&port->dev, "BI setup failed rc=%d\n", rc);
+
 	/*
 	 * With VH (CXL Virtual Host) topology the cxl_port::add_dport() method
 	 * handles RAS setup for downstream ports. With RCH (CXL Restricted CXL
-- 
2.39.5


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

* [PATCH v6 8/9] cxl/pci: Split BI capability probe from setup
  2026-07-27 19:35 [PATCH v6 0/9] cxl: Support Back-Invalidate Davidlohr Bueso
                   ` (6 preceding siblings ...)
  2026-07-27 19:35 ` [PATCH v6 7/9] cxl: Move BI setup to endpoint port probe Davidlohr Bueso
@ 2026-07-27 19:36 ` Davidlohr Bueso
  2026-07-27 19:36 ` [PATCH v6 9/9] cxl: Allow auto-committed BI hdm decoders Davidlohr Bueso
  2026-07-27 20:59 ` [PATCH v6 0/9] cxl: Support Back-Invalidate Jonathan Cameron
  9 siblings, 0 replies; 14+ messages in thread
From: Davidlohr Bueso @ 2026-07-27 19:36 UTC (permalink / raw)
  To: dave.jiang
  Cc: jic23, alison.schofield, icheng, benjamin.cheatham, alucerop,
	dongjoo.seo1, dave, linux-kernel

Decouple the topology read-only capability verification phase from
cxl_bi_setup() into cxl_bi_probe_capable(), recording the result in
cxlds->bi_capable.

This allows further dealing with auto-committed BI hdm decoders;
having such knowledge upon decoder enumeration time.

No functional change intended.

Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 drivers/cxl/core/pci.c | 39 ++++++++++++++++++++++++++++-----------
 drivers/cxl/cxl.h      |  1 +
 drivers/cxl/port.c     |  1 +
 include/cxl/cxl.h      |  2 ++
 4 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index a87c2ad9ac53..554058ccb1e9 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -1290,35 +1290,38 @@ static int cxl_bi_enable_path(struct cxl_dev_state *cxlds,
 	return rc;
 }
 
-int cxl_bi_setup(struct cxl_port *endpoint)
+/*
+ * Verify the device and every component in the path up to the root
+ * are BI capable.
+ */
+void cxl_bi_probe_capable(struct cxl_port *endpoint)
 {
 	struct cxl_memdev *cxlmd = to_cxl_memdev(endpoint->uport_dev);
 	struct cxl_dev_state *cxlds = cxlmd->cxlds;
-	struct cxl_dport *dport = endpoint->parent_dport;
 	struct cxl_dport *dport_iter;
 	struct cxl_port *port_iter;
-	int rc;
+
+	cxlds->bi_capable = false;
 
 	if (!dev_is_pci(cxlds->dev))
-		return 0;
+		return;
 
 	/* BI is VH-only */
 	if (cxlds->rcd)
-		return 0;
+		return;
 
 	if (!cxl_is_bi_capable(to_pci_dev(cxlds->dev),
 			       endpoint->regs.bi_decoder))
-		return 0;
+		return;
 
-	/* walkup the topology twice, first to check, then to enable */
-	port_iter = dport->port;
-	dport_iter = dport;
+	dport_iter = endpoint->parent_dport;
+	port_iter = dport_iter->port;
 	while (!is_cxl_root(port_iter)) {
 		/* check rp, dsp */
 		if (!cxl_is_bi_capable(to_pci_dev(dport_iter->dport_dev),
 				       dport_iter->regs.bi_decoder)) {
 			dev_dbg(cxlds->dev, "BI not supported by topology\n");
-			return 0;
+			return;
 		}
 
 		/* check usp */
@@ -1328,13 +1331,27 @@ int cxl_bi_setup(struct cxl_port *endpoint)
 		    !cxl_is_bi_capable(to_pci_dev(port_iter->uport_dev),
 				       port_iter->regs.bi_rt)) {
 			dev_dbg(cxlds->dev, "BI not supported by USP\n");
-			return 0;
+			return;
 		}
 
 		dport_iter = port_iter->parent_dport;
 		port_iter = dport_iter->port;
 	}
 
+	cxlds->bi_capable = true;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_bi_probe_capable, "CXL");
+
+int cxl_bi_setup(struct cxl_port *endpoint)
+{
+	struct cxl_memdev *cxlmd = to_cxl_memdev(endpoint->uport_dev);
+	struct cxl_dev_state *cxlds = cxlmd->cxlds;
+	struct cxl_dport *dport = endpoint->parent_dport;
+	int rc;
+
+	if (!cxlds->bi_capable)
+		return 0;
+
 	rc = cxl_bi_enable_path(cxlds, dport->port, dport);
 	if (rc)
 		return rc;
diff --git a/drivers/cxl/cxl.h b/drivers/cxl/cxl.h
index ca7051641c47..e10d642684e1 100644
--- a/drivers/cxl/cxl.h
+++ b/drivers/cxl/cxl.h
@@ -963,6 +963,7 @@ void cxl_coordinates_combine(struct access_coordinate *out,
 			     struct access_coordinate *c2);
 
 bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port);
+void cxl_bi_probe_capable(struct cxl_port *endpoint);
 int cxl_bi_setup(struct cxl_port *endpoint);
 struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port,
 					    struct device *dport_dev);
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index 22bd4254ba8d..ab3317fc1388 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -170,6 +170,7 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
 	cxl_endpoint_parse_cdat(port);
 
 	cxl_port_map_bi(port);
+	cxl_bi_probe_capable(port);
 
 	get_device(&cxlmd->dev);
 	rc = devm_add_action_or_reset(&port->dev, schedule_detach, cxlmd);
diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
index e507cb0f777f..80d942eb9456 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -169,6 +169,7 @@ struct cxl_dpa_partition {
  * @cxl_dvsec: Offset to the PCIe device DVSEC
  * @rcd: operating in RCD mode (CXL 3.0 9.11.8 CXL Devices Attached to an RCH)
  * @bi: device is BI (Back-Invalidate) enabled
+ * @bi_capable: device and topology path are BI capable
  * @media_ready: Indicate whether the device media is usable
  * @dpa_res: Overall DPA resource tree for the device
  * @part: DPA partition array
@@ -189,6 +190,7 @@ struct cxl_dev_state {
 	int cxl_dvsec;
 	bool rcd;
 	bool bi;
+	bool bi_capable;
 	bool media_ready;
 	struct resource dpa_res;
 	struct cxl_dpa_partition part[CXL_NR_PARTITIONS_MAX];
-- 
2.39.5


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

* [PATCH v6 9/9] cxl: Allow auto-committed BI hdm decoders
  2026-07-27 19:35 [PATCH v6 0/9] cxl: Support Back-Invalidate Davidlohr Bueso
                   ` (7 preceding siblings ...)
  2026-07-27 19:36 ` [PATCH v6 8/9] cxl/pci: Split BI capability probe from setup Davidlohr Bueso
@ 2026-07-27 19:36 ` Davidlohr Bueso
  2026-07-27 20:59 ` [PATCH v6 0/9] cxl: Support Back-Invalidate Jonathan Cameron
  9 siblings, 0 replies; 14+ messages in thread
From: Davidlohr Bueso @ 2026-07-27 19:36 UTC (permalink / raw)
  To: dave.jiang
  Cc: jic23, alison.schofield, icheng, benjamin.cheatham, alucerop,
	dongjoo.seo1, dave, linux-kernel

Allow auto-committed BI hdm decoders on sane platforms, rejecting
only broken paths (ie: one that cannot route BISnp, or BI paired
with a host-only target range type).

The respective region creation is done like any other committed
decoder - with cxlds->bi set by the time an decoder attaches.

A committed BI decoder under a window without the BI restriction is
refused (undefined behavior per the CFMWS Window Restrictions), as
is a committed decoder attaching to a region of a different
coherency model.

Signed-off-by: Davidlohr Bueso <dave@stgolabs.net>
---
 drivers/cxl/core/hdm.c    | 24 +++++++++++++++++-------
 drivers/cxl/core/pci.c    | 36 +++++++++++++++++++++++++++++-------
 drivers/cxl/core/region.c | 33 +++++++++++++++++++++++++++++++++
 drivers/cxl/port.c        |  4 ++++
 4 files changed, 83 insertions(+), 14 deletions(-)

diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c
index f437fe15c6df..c5be6fe4c77a 100644
--- a/drivers/cxl/core/hdm.c
+++ b/drivers/cxl/core/hdm.c
@@ -1061,13 +1061,23 @@ static int init_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld,
 		else
 			cxld->target_type = CXL_DECODER_DEVMEM;
 
-		/*
-		 * Autocommit BI-enabled decoders is not supported.
-		 * At this point cxlds->bi is not yet setup, so there
-		 * are no guarantees that the platform supports BI.
-		 */
-		if (FIELD_GET(CXL_HDM_DECODER0_CTRL_BI, ctrl))
-			return -ENXIO;
+		if (FIELD_GET(CXL_HDM_DECODER0_CTRL_BI, ctrl)) {
+			struct cxl_dev_state *cxlds = cxled ?
+				cxled_to_memdev(cxled)->cxlds : NULL;
+
+			if (cxld->target_type == CXL_DECODER_HOSTONLYMEM) {
+				dev_warn(&port->dev,
+					 "decoder%d.%d: BI with host-only\n",
+					 port->id, cxld->id);
+				return -ENXIO;
+			}
+			if (cxlds && !cxlds->bi_capable) {
+				dev_warn(&port->dev,
+					 "decoder%d.%d: path not BI capable\n",
+					 port->id, cxld->id);
+				return -ENXIO;
+			}
+		}
 
 		guard(rwsem_write)(&cxl_rwsem.region);
 		if (cxld->id != cxl_num_decoders_committed(port)) {
diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index 554058ccb1e9..8d2651e06a79 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -1083,6 +1083,18 @@ static int __cxl_bi_commit_decoder(struct device *dev, void __iomem *bi)
 				    scale, base);
 }
 
+/* Committed, or no explicit commit required */
+static bool cxl_bi_decoder_committed(void __iomem *bi)
+{
+	u32 caps = readl(bi + CXL_BI_DECODER_CAPS_OFFSET);
+	u32 sts = readl(bi + CXL_BI_DECODER_STATUS_OFFSET);
+
+	if (!FIELD_GET(CXL_BI_DECODER_CAPS_EXPLICIT_COMMIT_REQ, caps))
+		return true;
+
+	return FIELD_GET(CXL_BI_DECODER_STATUS_BI_COMMITTED, sts);
+}
+
 /* Enable or dealloc BI-ID changes in the given level of the topology. */
 static int __cxl_bi_ctrl_dport(struct cxl_dport *dport, bool enable)
 {
@@ -1127,6 +1139,16 @@ static int __cxl_bi_ctrl_dport(struct cxl_dport *dport, bool enable)
 		return 0;
 	case PCI_EXP_TYPE_DOWNSTREAM:
 		if (enable) {
+			/*
+			 * Adopt a dport that was already programmed and
+			 * committed by firmware: nothing new is enabled
+			 * below it, so no commit is due.
+			 */
+			if (FIELD_GET(CXL_BI_DECODER_CTRL_BI_ENABLE, ctrl) &&
+			    !FIELD_GET(CXL_BI_DECODER_CTRL_BI_FW, ctrl) &&
+			    cxl_bi_decoder_committed(bi))
+				return 0;
+
 			value = ctrl & ~CXL_BI_DECODER_CTRL_BI_FW;
 			value |= CXL_BI_DECODER_CTRL_BI_ENABLE;
 		} else {
@@ -1173,11 +1195,11 @@ static int __cxl_bi_ctrl_endpoint(struct cxl_dev_state *cxlds, bool enable)
 
 	if (enable) {
 		if (FIELD_GET(CXL_BI_DECODER_CTRL_BI_ENABLE, ctrl)) {
-			if (cxlds->bi)
-				return 0;
-			dev_err(cxlds->dev,
-				"BI already enabled in hardware\n");
-			return -EBUSY;
+			/* adopt firmware enabled */
+			if (!cxlds->bi)
+				dev_dbg(cxlds->dev,
+					"adopting firmware-enabled BI\n");
+			goto done;
 		}
 		val = ctrl | CXL_BI_DECODER_CTRL_BI_ENABLE;
 	} else {
@@ -1192,11 +1214,11 @@ static int __cxl_bi_ctrl_endpoint(struct cxl_dev_state *cxlds, bool enable)
 	}
 
 	writel(val, bi + CXL_BI_DECODER_CTRL_OFFSET);
-	cxlds->bi = enable;
 
 	dev_dbg(cxlds->dev, "BI requests %s\n",
 		str_enabled_disabled(enable));
-
+done:
+	cxlds->bi = enable;
 	return 0;
 }
 
diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
index 7c11d5788d99..5f72f5e1afc4 100644
--- a/drivers/cxl/core/region.c
+++ b/drivers/cxl/core/region.c
@@ -1832,6 +1832,21 @@ static int cxl_region_attach_position(struct cxl_region *cxlr,
 	return rc;
 }
 
+/* Read back the committed BI bit of an auto-discovered decoder */
+static bool cxled_committed_bi(struct cxl_endpoint_decoder *cxled)
+{
+	struct cxl_port *port = cxled_to_port(cxled);
+	struct cxl_hdm *cxlhdm = dev_get_drvdata(&port->dev);
+	u32 ctrl;
+
+	if (!cxlhdm || !cxlhdm->regs.hdm_decoder)
+		return false;
+
+	ctrl = readl(cxlhdm->regs.hdm_decoder +
+		     CXL_HDM_DECODER0_CTRL_OFFSET(cxled->cxld.id));
+	return FIELD_GET(CXL_HDM_DECODER0_CTRL_BI, ctrl);
+}
+
 static int cxl_region_attach_auto(struct cxl_region *cxlr,
 				  struct cxl_endpoint_decoder *cxled, int pos)
 {
@@ -1844,6 +1859,16 @@ static int cxl_region_attach_auto(struct cxl_region *cxlr,
 		return -EINVAL;
 	}
 
+	/* A committed decoder may only join a region of its own flavor */
+	if (cxled_committed_bi(cxled) !=
+	    (cxlr->type == CXL_DECODER_DEVMEM &&
+	     cxl_root_decoder_is_bi(cxlr->cxlrd))) {
+		dev_err(&cxlr->dev, "%s:%s coherency model mismatch\n",
+			dev_name(&cxled_to_memdev(cxled)->dev),
+			dev_name(&cxled->cxld.dev));
+		return -ENXIO;
+	}
+
 	if (pos >= 0) {
 		dev_dbg(&cxlr->dev, "%s: expected auto position, not %d\n",
 			dev_name(&cxled->cxld.dev), pos);
@@ -3811,6 +3836,14 @@ static struct cxl_region *construct_region(struct cxl_root_decoder *cxlrd,
 	if (part < 0)
 		return ERR_PTR(-EBUSY);
 
+	/* avoid UB */
+	if (cxled_committed_bi(cxled) && !cxl_root_decoder_is_bi(cxlrd)) {
+		dev_err(cxlmd->dev.parent,
+			"%s:%s BI decoder in a non-BI window\n",
+			dev_name(&cxlmd->dev), dev_name(&cxled->cxld.dev));
+		return ERR_PTR(-ENXIO);
+	}
+
 	do {
 		cxlr = __create_region(cxlrd, cxlds->part[part].mode,
 				       atomic_read(&cxlrd->region_id),
diff --git a/drivers/cxl/port.c b/drivers/cxl/port.c
index ab3317fc1388..0c666ce00aa2 100644
--- a/drivers/cxl/port.c
+++ b/drivers/cxl/port.c
@@ -181,6 +181,10 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
 	if (rc)
 		return rc;
 
+	/*
+	 * Must precede region discovery so that any firmware-committed BI
+	 * decoder is adopted before its region is assembled.
+	 */
 	rc = cxl_bi_setup(port);
 	if (rc)
 		dev_dbg(&port->dev, "BI setup failed rc=%d\n", rc);
-- 
2.39.5


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

* Re: [PATCH v6 0/9] cxl: Support Back-Invalidate
  2026-07-27 19:35 [PATCH v6 0/9] cxl: Support Back-Invalidate Davidlohr Bueso
                   ` (8 preceding siblings ...)
  2026-07-27 19:36 ` [PATCH v6 9/9] cxl: Allow auto-committed BI hdm decoders Davidlohr Bueso
@ 2026-07-27 20:59 ` Jonathan Cameron
  2026-07-27 21:26   ` Davidlohr Bueso
  9 siblings, 1 reply; 14+ messages in thread
From: Jonathan Cameron @ 2026-07-27 20:59 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: dave.jiang, alison.schofield, icheng, benjamin.cheatham,
	alucerop, dongjoo.seo1, linux-kernel

On Mon, 27 Jul 2026 12:35:52 -0700
Davidlohr Bueso <dave@stgolabs.net> wrote:

> Hello,

Hi Davidlohr,

You missed linux-cxl

J
> 
> Changes from v5 (https://lore.kernel.org/all/20260615145529.13848-1-dave@stgolabs.net):
>   - Patch 1 documented the BI register block with the spec references
>     at the definitions. (Dave)
>   - Patch 2 split the enable/rollback into a helper so the unwind path
>     no longer mixes goto and scope-based cleanup (Sashiko).
>   - Patch 2 reworded the changelog around root port enablement.
>   - Patch 3 introduced cxled_default_type() so decoders present the
>     device's default target type when not attached to a region (Sashiko).
>   - Patch 4 defaults to host-only when firmware sets both CFMWS
>     coherency restrictions (Richard).
>   - Patch 4 restores the default target type on detach, fixing a stale
>     DEVMEM type leaking into a later HDM-H attach (Sashiko).
>   - Patch 4 'bi' sysfs now reports against the attached region's root
>     decoder rather than device state alone (Sashiko).
>   - Picked up review tags (thanks!).
>   - New patch 6: trivially log the coherency model at region creation dbg.
>   - New patches 7-9: move BI setup to endpoint port probe, split the
>     capability probe from BI-ID allocation, and allow for auto-committed
>     BI decoders instead of failing enumeration.
> 
> This series is the initial plumbing to enable HDM-DB in Linux. The
> model allows Type 2 and Type 3 devices to expose their local memory
> to the host CPU in a coherent manner. In alignment with what was
> discussed at 2024 LPC type2 support session, this series takes the
> Type 3 memory expander approach, which is more direct. Further,
> afaik there is no Type 2 + BI hardware out there.
> 
> A flagship use case of Type 3 + BI is coherent shared memory, and
> there is currently a big gap in this regard (ie: GFAM). Another
> is P2P via PCIe UIO, which is also lacking today. Media Operation
> (4402h) for ranged sanitize/zero also trigger snoops and there are
> some patches out there[0]. As such this series focuses on BI enablement
> in terms of discovery and configuration.
> 
> The idea is for Type 3 memdevs and Type 2 devices to make use of
> cxlds->bi when committing HDM decoders, such that different device
> coherence models can be differentiated as:
> 
>   type2 hdm-d:  cxlds->type == CXL_DEVTYPE_DEVMEM && cxlds->bi == false
>   type2 hdm-db: cxlds->type == CXL_DEVTYPE_DEVMEM && cxlds->bi == true
>   type3 hdm-h:  cxlds->type == CXL_DEVTYPE_CLASSMEM && cxlds->bi == false
>   type3 hdm-db: cxlds->type == CXL_DEVTYPE_CLASSMEM && cxlds->bi == true
> 
> Unlike previous versions, an auto-committed BI decoder found during
> enumeration is no longer rejected: patches 7-9 adopt the inherited
> configuration when the device and path are BI capable, refusing only
> broken combinations. See the auto-discovery tests section below.
> 
> o Patch 1 probes BI capabilities during register discovery, and maps BI
>   Decoder registers.
> 
> o Patch 2 implements the BI-ID allocation (and deallocation).
> 
> o Patch 3 adds coherency support for endpoint decoders based on what the
> root decoder restricts.
> 
> o Patch 4 adds support for HDM-DB region creation.
> 
> o Patch 5 trivially renames some coherency flags.
> 
> o Patch 6 logs the coherency model (HDM-H, HDM-D, HDM-DB) when a
>   region is created.
> 
> o Patch 7 moves BI setup to endpoint port probe, tying the BI-ID
>   lifetime to the endpoint port.
> 
> o Patch 8 splits the BI capability walk from BI-ID allocation so the
>   answer is available when committed decoders are first parsed.
> 
> o Patch 9 allows committed BI decoders. Overall this series
>   could be picked up with or without this patch.
> 
> Please note that patch 7+8 could be consolidated into patch 2,
> instead of starting out with cxl_mem but I chose to add them
> incrementally because 1) want to see what sashiko says,
> 2) it isolates the requirements for the auto-committed support
> (patch 9); 3) details why endpoint lifecycle is safe and
> 4) reuses already valuable review times of the current state
> of the series. But I certainly see the reasons to avoid the
> additional patches. 
> 
> Testing
> -------
> 
> Testing has been done on top of upstream qemu with the CFMW options series:
> 
>   https://lore.kernel.org/all/20260720233242.901544-1-dave@stgolabs.net/
> 
> A new qemu-based test suite has been added for full automation and pounding,
> covering many topologies and corner cases:
> 
>   https://github.com/davidlohr/cxl-bi-tests
> 
> This passes regression testing (nothing breaks) ndctl suite via cxl_test.
> 
> 1. HDM Decoder with BI through ad-hoc region creation.
> ------------------------------------------------------
> # cxl list -D
> [
>   {
>     "decoder":"decoder0.0",
>     "resource":6710886400,
>     "size":4294967296,
>     "interleave_ways":1,
>     "accelmem_capable":true,
>     "nr_targets":1
>   }
> ]
> 
> # ROOT=/sys/bus/cxl/devices/decoder0.0
> # EP=/sys/bus/cxl/devices/decoder2.0
> # echo region0 > $ROOT/create_ram_region
> [    7.662871] cxl_core:devm_cxl_add_region:2829: cxl_acpi ACPI0017:00: decoder0.0: created HDM-DB region0
> # REG=/sys/bus/cxl/devices/region0
> # echo ram > $EP/mode
> # echo 0x40000000 > $EP/dpa_size
> # echo 1 > $REG/interleave_ways
> # echo 4096 > $REG/interleave_granularity
> # echo 0x40000000 > $REG/size
> # cat $EP/bi
> 0
> # echo decoder2.0 > $REG/target0
> [    8.153566] cxl_core:cxl_port_attach_region:1295: cxl region0: mem0:endpoint2 decoder2.0 add: mem0:decoder2.0 @ 0 next: none nr_eps: 1 nr_targets: 1
> [    8.157683] cxl_core:cxl_port_attach_region:1295: cxl region0: pci0000:0c:port1 decoder1.0 add: mem0:decoder2.0 @ 0 next: mem0 nr_eps: 1 nr_targets: 1
> [    8.159570] cxl_core:cxl_port_setup_targets:1630: cxl region0: pci0000:0c:port1 iw: 1 ig: 4096
> [    8.160487] cxl_core:cxl_port_setup_targets:1638: cxl region0: pci0000:0c:port1 target[0] = 0000:0c:00.0 for mem0:decoder2.0 @ 0
> [    8.161759] cxl_core:cxl_calc_interleave_pos:2046: cxl_mem mem0: decoder:decoder2.0 parent:0000:0d:00.0 port:endpoint2 range:0x190000000-0x1cfffffff pos:0
> [    8.163681] cxl_core:cxl_region_attach:2270: cxl decoder2.0: Test cxl_calc_interleave_pos(): success test_pos:0 target->pos:0
> # cat $EP/bi
> 1
> # echo 1 > $REG/commit
> # cxl list -D
> [
>   {
>     "root decoders":[
>       {
>         "decoder":"decoder0.0",
>         "resource":6710886400,
>         "size":4294967296,
>         "interleave_ways":1,
>         "accelmem_capable":true,
>         "nr_targets":1
>       }
>     ]
>   },
>   {
>     "port decoders":[
>       {
>         "decoder":"decoder1.0",
>         "resource":6710886400,
>         "size":1073741824,
>         "interleave_ways":1,
>         "region":"region0",
>         "nr_targets":1
>       }
>     ]
>   },
>   {
>     "endpoint decoders":[
>       {
>         "decoder":"decoder2.0",
>         "resource":6710886400,
>         "size":1073741824,
>         "interleave_ways":1,
>         "region":"region0",
>         "dpa_resource":0,
>         "dpa_size":1073741824,
>         "mode":"ram"
>       }
>     ]
>   }
> ]
> 
> 2. Type3 device does not support BI, but CFMW has BI restriction
> ----------------------------------------------------------------
> # echo decoder2.0 > $REG/target0
> [    7.311927] cxl region0: mem0:decoder2.0 BI not enabled on device
> [    7.313907] cxl_port endpoint2: failed to attach decoder2.0 to region0: -6
> 
> 3. Type3 device supports BI but CFMW does not, create HDM-H region
> ------------------------------------------------------------------
> # cxl list -D
> [
>   {
>     "decoder":"decoder0.0",
>     "resource":6710886400,
>     "size":4294967296,
>     "interleave_ways":1,
>     "max_available_extent":4294967296,
>     "pmem_capable":true,
>     "volatile_capable":true,
>     "accelmem_capable":true,
>     "nr_targets":1
>   }
> ]
> # echo region0 > $ROOT/create_ram_region
> [    7.679496] cxl_core:devm_cxl_add_region:2829: cxl_acpi ACPI0017:00: decoder0.0: created HDM-H region0
> # cat $EP/bi
> 0
> # echo decoder2.0 > $REG/target0
> [    8.165400] cxl_core:cxl_port_attach_region:1295: cxl region0: mem0:endpoint2 decoder2.0 add: mem0:decoder2.0 @ 0 next: none nr_eps: 1 nr_targets: 1
> [    8.167128] cxl_core:cxl_port_attach_region:1295: cxl region0: pci0000:0c:port1 decoder1.0 add: mem0:decoder2.0 @ 0 next: mem0 nr_eps: 1 nr_targets: 1
> [    8.168834] cxl_core:cxl_port_setup_targets:1630: cxl region0: pci0000:0c:port1 iw: 1 ig: 4096
> [    8.169893] cxl_core:cxl_port_setup_targets:1638: cxl region0: pci0000:0c:port1 target[0] = 0000:0c:00.0 for mem0:decoder2.0 @ 0
> [    8.171302] cxl_core:cxl_calc_interleave_pos:2046: cxl_mem mem0: decoder:decoder2.0 parent:0000:0d:00.0 port:endpoint2 range:0x190000000-0x1cfffffff pos:0
> [    8.173036] cxl_core:cxl_region_attach:2270: cxl decoder2.0: Test cxl_calc_interleave_pos(): success test_pos:0 target->pos:0
> # echo 1 > $REG/commit
> # cat $EP/bi
> 0
> 
> 4. Unbind + Bind
> ----------------
> # echo mem0 > /sys/bus/cxl/drivers/cxl_mem/unbind
> [    7.645330] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests disabled
> [    7.648838] cxl_core:cxl_port_commit_reap:900: cxl_port endpoint2: reap: decoder2.0 commit_end: -1
> [    7.651284] cxl_core:cxl_detach_ep:1556: cxl_mem mem0: disconnect mem0 from port1
> 
> # echo mem0 > /sys/bus/cxl/drivers/cxl_mem/bind
> [    8.909437] cxl_core:devm_cxl_enumerate_ports:1871: cxl_mem mem0: scan: iter: mem0 dport_dev: 0000:0c:00.0 parent: pci0000:0c
> [    8.911170] cxl_core:devm_cxl_enumerate_ports:1877: cxl_mem mem0: found already registered port port1:pci0000:0c
> [    8.945969] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x0-0xffffffffffffffff iw: 1 ig: 4096
> [    8.949705] cxl_core:add_hdm_decoder:39: cxl_mem mem0: decoder2.0 added to endpoint2
> [    8.960378] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests enabled
> [    8.961196] cxl_core:cxl_bus_probe:2299: cxl_port endpoint2: probe: 0
> [    8.962592] cxl_core:cxl_bus_probe:2299: cxl_mem mem0: probe: 0
> 
> The same applies to the endpoint port, with the memdev rebind recovering the endpoint:
> 
> # echo endpoint2 > /sys/bus/cxl/drivers/cxl_port/unbind
> [   10.483509] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests disabled
> [   10.487570] cxl_core:cxl_port_commit_reap:900: cxl_port endpoint2: reap: decoder2.0 commit_end: -1
> [   10.491501] cxl_core:cxl_detach_ep:1556: cxl_mem mem0: disconnect mem0 from port1
> 
> # echo mem0 > /sys/bus/cxl/drivers/cxl_mem/bind
> [   11.754957] cxl_core:devm_cxl_enumerate_ports:1871: cxl_mem mem0: scan: iter: mem0 dport_dev: 0000:0c:00.0 parent: pci0000:0c
> [   11.756343] cxl_core:devm_cxl_enumerate_ports:1877: cxl_mem mem0: found already registered port port1:pci0000:0c
> [   11.789821] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x0-0xffffffffffffffff iw: 1 ig: 4096
> [   11.794674] cxl_core:add_hdm_decoder:39: cxl_mem mem0: decoder2.0 added to endpoint2
> [   11.805772] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests enabled
> [   11.806810] cxl_core:cxl_bus_probe:2299: cxl_port endpoint2: probe: 0
> [   11.808661] cxl_core:cxl_bus_probe:2299: cxl_mem mem0: probe: 0
> 
> From a cold boot, without a region ever created, the endpoint port
> unbind only disables BI - there is no committed decoder to reap:
> 
> # echo endpoint2 > /sys/bus/cxl/drivers/cxl_port/unbind
> [   22.046813] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests disabled
> [   22.049676] cxl_core:cxl_detach_ep:1556: cxl_mem mem0: disconnect mem0 from port1
> 
> # echo mem0 > /sys/bus/cxl/drivers/cxl_mem/bind
> [   24.270628] cxl_core:devm_cxl_enumerate_ports:1871: cxl_mem mem0: scan: iter: mem0 dport_dev: 0000:0c:00.0 parent: pci0000:0c
> [   24.273682] cxl_core:devm_cxl_enumerate_ports:1877: cxl_mem mem0: found already registered port port1:pci0000:0c
> [   24.312426] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x0-0xffffffffffffffff iw: 1 ig: 256
> [   24.315677] cxl_core:add_hdm_decoder:39: cxl_mem mem0: decoder2.0 added to endpoint2
> [   24.332406] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests enabled
> [   24.334427] cxl_core:cxl_bus_probe:2299: cxl_port endpoint2: probe: 0
> [   24.337952] cxl_core:cxl_bus_probe:2299: cxl_mem mem0: probe: 0
> 
> 5. Discovery behind a Switch
> ----------------------------
> [    0.782301] cxl_core:cxl_probe_component_regs:102: cxl_pci 0000:0f:00.0: found BI Decoder capability (0xab4)
> [    0.851085] cxl_core:cxl_probe_component_regs:102: pcieport 0000:0c:00.0: found BI Decoder capability (0xab4)
> [    0.866840] cxl_core:cxl_probe_component_regs:96: cxl_port port2: found BI RT capability (0xaa8)
> [    0.902485] cxl_core:cxl_probe_component_regs:102: pcieport 0000:0e:00.0: found BI Decoder capability (0xab4)
> [    1.221118] cxl_core:__cxl_bi_wait_commit:1032: pcieport 0000:0e:00.0: BI-ID commit wait took 250908us
> [    1.368581] cxl_core:__cxl_bi_wait_commit:1032: cxl_port port2: BI-ID commit wait took 146455us
> [    1.371579] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0f:00.0: BI requests enabled
> 
> 6. Corrupted hw (commit timeout handling)
> -----------------------------------------
> [    1.003566] cxl_core:cxl_probe_component_regs:102: pcieport 0000:0e:00.0: found BI Decoder capability (0xab4)
> [    3.203147] pcieport 0000:0e:00.0: BI-ID commit timed out (2000000us)
> [    3.206048] cxl_port:cxl_endpoint_port_probe:190: cxl_port endpoint3: BI setup failed rc=-110
> 
> 7. Mixed Configurations (BI-capable Type 3 but DSP 68b)
> -------------------------------------------------------
> [    0.837902] cxl_mem:cxl_mem_probe:155: cxl_mem mem0: BI setup failed rc=-22
> 
> 8. Auto-discovered (committed) BI decoders
> ------------------------------------------
> For testing, qemu hack emulates auto-committed decoder:
> 
> [    0.670374] cxl_core:devm_cxl_switch_port_decoders_setup:1282: cxl_port port1: Fallback to passthrough decoder
> [    0.718374] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x190000000-0x19fffffff iw: 1 ig: 256
> [    0.728498] cxl_core:__cxl_bi_ctrl_endpoint:1200: cxl_pci 0000:0d:00.0: adopting firmware-enabled BI
> [    0.730880] cxl_core:devm_cxl_add_region:2829: cxl_acpi ACPI0017:00: decoder0.0: created HDM-DB region0
> [    0.731906] cxl_core:__construct_region:3843: cxl_pci 0000:0d:00.0: mem0:decoder2.0: __construct_region region0 res: [mem 0x190000000-0x19fffffff flags 0x200] iw: 1 ig: 256
> [    0.734473] cxl_core:cxl_region_sort_targets:2104: cxl region0: region sort successful
> [    0.739452] cxl_core:devm_cxl_add_dax_region:101: cxl_region region0: region0: register dax_region0
> [    0.740239] cxl_core:cxl_bus_probe:2299: cxl_region region0: probe: 0
> # cat /sys/bus/cxl/devices/region0/commit
> 1
> # cat /sys/bus/cxl/devices/decoder2.0/bi
> 1
> 
> A committed BI decoder under a window without the BI restriction is
> refused at region assembly:
> 
> [    0.794477] cxl_core:__cxl_bi_ctrl_endpoint:1200: cxl_pci 0000:0d:00.0: adopting firmware-enabled BI
> [    0.795396] cxl_pci 0000:0d:00.0: mem0:decoder2.0 BI decoder in a non-BI window
> [    0.796050] cxl_port:discover_region:55: cxl decoder2.0: failed to add to region: 0x190000000-0x19fffffff
> 
> Applies against v7.2-rc5. Please consider for v7.3.
> 
> [0] https://lore.kernel.org/linux-cxl/20260428200410.705675-1-dave@stgolabs.net/
> 
> Thanks!
> 
> Davidlohr Bueso (9):
>   cxl: Add BI register probing and port initialization
>   cxl/pci: Add BI topology enable/disable
>   cxl/hdm: Add BI coherency support for endpoint decoders
>   cxl: Add HDM-DB region creation
>   cxl/hdm: Rename decoder coherency flags
>   cxl/region: Log the coherency model at region creation
>   cxl: Move BI setup to endpoint port probe
>   cxl/pci: Split BI capability probe from setup
>   cxl: Allow auto-committed BI hdm decoders
> 
>  Documentation/ABI/testing/sysfs-bus-cxl |  18 +-
>  drivers/cxl/acpi.c                      |  19 +-
>  drivers/cxl/core/core.h                 |   2 +
>  drivers/cxl/core/hdm.c                  |  68 ++++-
>  drivers/cxl/core/pci.c                  | 456 ++++++++++++++++++++++++++++++++
>  drivers/cxl/core/port.c                 |  48 +++-
>  drivers/cxl/core/region.c               |  97 ++++++-
>  drivers/cxl/core/regs.c                 |  14 +
>  drivers/cxl/cxl.h                       |  55 +++-
>  drivers/cxl/cxlmem.h                    |   2 +
>  drivers/cxl/port.c                      |  54 ++++
>  include/cxl/cxl.h                       |  10 +
>  12 files changed, 808 insertions(+), 35 deletions(-)
> 
> --
> 2.39.5


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

* Re: [PATCH v6 0/9] cxl: Support Back-Invalidate
  2026-07-27 20:59 ` [PATCH v6 0/9] cxl: Support Back-Invalidate Jonathan Cameron
@ 2026-07-27 21:26   ` Davidlohr Bueso
  2026-07-27 23:02     ` Dave Jiang
  0 siblings, 1 reply; 14+ messages in thread
From: Davidlohr Bueso @ 2026-07-27 21:26 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: dave.jiang, alison.schofield, icheng, benjamin.cheatham,
	alucerop, dongjoo.seo1, linux-kernel, linux-cxl

On Mon, 27 Jul 2026, Jonathan Cameron wrote:

>On Mon, 27 Jul 2026 12:35:52 -0700
>Davidlohr Bueso <dave@stgolabs.net> wrote:
>
>> Hello,
>
>Hi Davidlohr,
>
>You missed linux-cxl

bleh yeah that was a braino, I meant cxl not lkml - probably not worth another respin,
but Cc'ing here.

>
>J
>>
>> Changes from v5 (https://lore.kernel.org/all/20260615145529.13848-1-dave@stgolabs.net):
>>   - Patch 1 documented the BI register block with the spec references
>>     at the definitions. (Dave)
>>   - Patch 2 split the enable/rollback into a helper so the unwind path
>>     no longer mixes goto and scope-based cleanup (Sashiko).
>>   - Patch 2 reworded the changelog around root port enablement.
>>   - Patch 3 introduced cxled_default_type() so decoders present the
>>     device's default target type when not attached to a region (Sashiko).
>>   - Patch 4 defaults to host-only when firmware sets both CFMWS
>>     coherency restrictions (Richard).
>>   - Patch 4 restores the default target type on detach, fixing a stale
>>     DEVMEM type leaking into a later HDM-H attach (Sashiko).
>>   - Patch 4 'bi' sysfs now reports against the attached region's root
>>     decoder rather than device state alone (Sashiko).
>>   - Picked up review tags (thanks!).
>>   - New patch 6: trivially log the coherency model at region creation dbg.
>>   - New patches 7-9: move BI setup to endpoint port probe, split the
>>     capability probe from BI-ID allocation, and allow for auto-committed
>>     BI decoders instead of failing enumeration.
>>
>> This series is the initial plumbing to enable HDM-DB in Linux. The
>> model allows Type 2 and Type 3 devices to expose their local memory
>> to the host CPU in a coherent manner. In alignment with what was
>> discussed at 2024 LPC type2 support session, this series takes the
>> Type 3 memory expander approach, which is more direct. Further,
>> afaik there is no Type 2 + BI hardware out there.
>>
>> A flagship use case of Type 3 + BI is coherent shared memory, and
>> there is currently a big gap in this regard (ie: GFAM). Another
>> is P2P via PCIe UIO, which is also lacking today. Media Operation
>> (4402h) for ranged sanitize/zero also trigger snoops and there are
>> some patches out there[0]. As such this series focuses on BI enablement
>> in terms of discovery and configuration.
>>
>> The idea is for Type 3 memdevs and Type 2 devices to make use of
>> cxlds->bi when committing HDM decoders, such that different device
>> coherence models can be differentiated as:
>>
>>   type2 hdm-d:  cxlds->type == CXL_DEVTYPE_DEVMEM && cxlds->bi == false
>>   type2 hdm-db: cxlds->type == CXL_DEVTYPE_DEVMEM && cxlds->bi == true
>>   type3 hdm-h:  cxlds->type == CXL_DEVTYPE_CLASSMEM && cxlds->bi == false
>>   type3 hdm-db: cxlds->type == CXL_DEVTYPE_CLASSMEM && cxlds->bi == true
>>
>> Unlike previous versions, an auto-committed BI decoder found during
>> enumeration is no longer rejected: patches 7-9 adopt the inherited
>> configuration when the device and path are BI capable, refusing only
>> broken combinations. See the auto-discovery tests section below.
>>
>> o Patch 1 probes BI capabilities during register discovery, and maps BI
>>   Decoder registers.
>>
>> o Patch 2 implements the BI-ID allocation (and deallocation).
>>
>> o Patch 3 adds coherency support for endpoint decoders based on what the
>> root decoder restricts.
>>
>> o Patch 4 adds support for HDM-DB region creation.
>>
>> o Patch 5 trivially renames some coherency flags.
>>
>> o Patch 6 logs the coherency model (HDM-H, HDM-D, HDM-DB) when a
>>   region is created.
>>
>> o Patch 7 moves BI setup to endpoint port probe, tying the BI-ID
>>   lifetime to the endpoint port.
>>
>> o Patch 8 splits the BI capability walk from BI-ID allocation so the
>>   answer is available when committed decoders are first parsed.
>>
>> o Patch 9 allows committed BI decoders. Overall this series
>>   could be picked up with or without this patch.
>>
>> Please note that patch 7+8 could be consolidated into patch 2,
>> instead of starting out with cxl_mem but I chose to add them
>> incrementally because 1) want to see what sashiko says,
>> 2) it isolates the requirements for the auto-committed support
>> (patch 9); 3) details why endpoint lifecycle is safe and
>> 4) reuses already valuable review times of the current state
>> of the series. But I certainly see the reasons to avoid the
>> additional patches.
>>
>> Testing
>> -------
>>
>> Testing has been done on top of upstream qemu with the CFMW options series:
>>
>>   https://lore.kernel.org/all/20260720233242.901544-1-dave@stgolabs.net/
>>
>> A new qemu-based test suite has been added for full automation and pounding,
>> covering many topologies and corner cases:
>>
>>   https://github.com/davidlohr/cxl-bi-tests
>>
>> This passes regression testing (nothing breaks) ndctl suite via cxl_test.
>>
>> 1. HDM Decoder with BI through ad-hoc region creation.
>> ------------------------------------------------------
>> # cxl list -D
>> [
>>   {
>>     "decoder":"decoder0.0",
>>     "resource":6710886400,
>>     "size":4294967296,
>>     "interleave_ways":1,
>>     "accelmem_capable":true,
>>     "nr_targets":1
>>   }
>> ]
>>
>> # ROOT=/sys/bus/cxl/devices/decoder0.0
>> # EP=/sys/bus/cxl/devices/decoder2.0
>> # echo region0 > $ROOT/create_ram_region
>> [    7.662871] cxl_core:devm_cxl_add_region:2829: cxl_acpi ACPI0017:00: decoder0.0: created HDM-DB region0
>> # REG=/sys/bus/cxl/devices/region0
>> # echo ram > $EP/mode
>> # echo 0x40000000 > $EP/dpa_size
>> # echo 1 > $REG/interleave_ways
>> # echo 4096 > $REG/interleave_granularity
>> # echo 0x40000000 > $REG/size
>> # cat $EP/bi
>> 0
>> # echo decoder2.0 > $REG/target0
>> [    8.153566] cxl_core:cxl_port_attach_region:1295: cxl region0: mem0:endpoint2 decoder2.0 add: mem0:decoder2.0 @ 0 next: none nr_eps: 1 nr_targets: 1
>> [    8.157683] cxl_core:cxl_port_attach_region:1295: cxl region0: pci0000:0c:port1 decoder1.0 add: mem0:decoder2.0 @ 0 next: mem0 nr_eps: 1 nr_targets: 1
>> [    8.159570] cxl_core:cxl_port_setup_targets:1630: cxl region0: pci0000:0c:port1 iw: 1 ig: 4096
>> [    8.160487] cxl_core:cxl_port_setup_targets:1638: cxl region0: pci0000:0c:port1 target[0] = 0000:0c:00.0 for mem0:decoder2.0 @ 0
>> [    8.161759] cxl_core:cxl_calc_interleave_pos:2046: cxl_mem mem0: decoder:decoder2.0 parent:0000:0d:00.0 port:endpoint2 range:0x190000000-0x1cfffffff pos:0
>> [    8.163681] cxl_core:cxl_region_attach:2270: cxl decoder2.0: Test cxl_calc_interleave_pos(): success test_pos:0 target->pos:0
>> # cat $EP/bi
>> 1
>> # echo 1 > $REG/commit
>> # cxl list -D
>> [
>>   {
>>     "root decoders":[
>>       {
>>         "decoder":"decoder0.0",
>>         "resource":6710886400,
>>         "size":4294967296,
>>         "interleave_ways":1,
>>         "accelmem_capable":true,
>>         "nr_targets":1
>>       }
>>     ]
>>   },
>>   {
>>     "port decoders":[
>>       {
>>         "decoder":"decoder1.0",
>>         "resource":6710886400,
>>         "size":1073741824,
>>         "interleave_ways":1,
>>         "region":"region0",
>>         "nr_targets":1
>>       }
>>     ]
>>   },
>>   {
>>     "endpoint decoders":[
>>       {
>>         "decoder":"decoder2.0",
>>         "resource":6710886400,
>>         "size":1073741824,
>>         "interleave_ways":1,
>>         "region":"region0",
>>         "dpa_resource":0,
>>         "dpa_size":1073741824,
>>         "mode":"ram"
>>       }
>>     ]
>>   }
>> ]
>>
>> 2. Type3 device does not support BI, but CFMW has BI restriction
>> ----------------------------------------------------------------
>> # echo decoder2.0 > $REG/target0
>> [    7.311927] cxl region0: mem0:decoder2.0 BI not enabled on device
>> [    7.313907] cxl_port endpoint2: failed to attach decoder2.0 to region0: -6
>>
>> 3. Type3 device supports BI but CFMW does not, create HDM-H region
>> ------------------------------------------------------------------
>> # cxl list -D
>> [
>>   {
>>     "decoder":"decoder0.0",
>>     "resource":6710886400,
>>     "size":4294967296,
>>     "interleave_ways":1,
>>     "max_available_extent":4294967296,
>>     "pmem_capable":true,
>>     "volatile_capable":true,
>>     "accelmem_capable":true,
>>     "nr_targets":1
>>   }
>> ]
>> # echo region0 > $ROOT/create_ram_region
>> [    7.679496] cxl_core:devm_cxl_add_region:2829: cxl_acpi ACPI0017:00: decoder0.0: created HDM-H region0
>> # cat $EP/bi
>> 0
>> # echo decoder2.0 > $REG/target0
>> [    8.165400] cxl_core:cxl_port_attach_region:1295: cxl region0: mem0:endpoint2 decoder2.0 add: mem0:decoder2.0 @ 0 next: none nr_eps: 1 nr_targets: 1
>> [    8.167128] cxl_core:cxl_port_attach_region:1295: cxl region0: pci0000:0c:port1 decoder1.0 add: mem0:decoder2.0 @ 0 next: mem0 nr_eps: 1 nr_targets: 1
>> [    8.168834] cxl_core:cxl_port_setup_targets:1630: cxl region0: pci0000:0c:port1 iw: 1 ig: 4096
>> [    8.169893] cxl_core:cxl_port_setup_targets:1638: cxl region0: pci0000:0c:port1 target[0] = 0000:0c:00.0 for mem0:decoder2.0 @ 0
>> [    8.171302] cxl_core:cxl_calc_interleave_pos:2046: cxl_mem mem0: decoder:decoder2.0 parent:0000:0d:00.0 port:endpoint2 range:0x190000000-0x1cfffffff pos:0
>> [    8.173036] cxl_core:cxl_region_attach:2270: cxl decoder2.0: Test cxl_calc_interleave_pos(): success test_pos:0 target->pos:0
>> # echo 1 > $REG/commit
>> # cat $EP/bi
>> 0
>>
>> 4. Unbind + Bind
>> ----------------
>> # echo mem0 > /sys/bus/cxl/drivers/cxl_mem/unbind
>> [    7.645330] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests disabled
>> [    7.648838] cxl_core:cxl_port_commit_reap:900: cxl_port endpoint2: reap: decoder2.0 commit_end: -1
>> [    7.651284] cxl_core:cxl_detach_ep:1556: cxl_mem mem0: disconnect mem0 from port1
>>
>> # echo mem0 > /sys/bus/cxl/drivers/cxl_mem/bind
>> [    8.909437] cxl_core:devm_cxl_enumerate_ports:1871: cxl_mem mem0: scan: iter: mem0 dport_dev: 0000:0c:00.0 parent: pci0000:0c
>> [    8.911170] cxl_core:devm_cxl_enumerate_ports:1877: cxl_mem mem0: found already registered port port1:pci0000:0c
>> [    8.945969] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x0-0xffffffffffffffff iw: 1 ig: 4096
>> [    8.949705] cxl_core:add_hdm_decoder:39: cxl_mem mem0: decoder2.0 added to endpoint2
>> [    8.960378] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests enabled
>> [    8.961196] cxl_core:cxl_bus_probe:2299: cxl_port endpoint2: probe: 0
>> [    8.962592] cxl_core:cxl_bus_probe:2299: cxl_mem mem0: probe: 0
>>
>> The same applies to the endpoint port, with the memdev rebind recovering the endpoint:
>>
>> # echo endpoint2 > /sys/bus/cxl/drivers/cxl_port/unbind
>> [   10.483509] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests disabled
>> [   10.487570] cxl_core:cxl_port_commit_reap:900: cxl_port endpoint2: reap: decoder2.0 commit_end: -1
>> [   10.491501] cxl_core:cxl_detach_ep:1556: cxl_mem mem0: disconnect mem0 from port1
>>
>> # echo mem0 > /sys/bus/cxl/drivers/cxl_mem/bind
>> [   11.754957] cxl_core:devm_cxl_enumerate_ports:1871: cxl_mem mem0: scan: iter: mem0 dport_dev: 0000:0c:00.0 parent: pci0000:0c
>> [   11.756343] cxl_core:devm_cxl_enumerate_ports:1877: cxl_mem mem0: found already registered port port1:pci0000:0c
>> [   11.789821] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x0-0xffffffffffffffff iw: 1 ig: 4096
>> [   11.794674] cxl_core:add_hdm_decoder:39: cxl_mem mem0: decoder2.0 added to endpoint2
>> [   11.805772] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests enabled
>> [   11.806810] cxl_core:cxl_bus_probe:2299: cxl_port endpoint2: probe: 0
>> [   11.808661] cxl_core:cxl_bus_probe:2299: cxl_mem mem0: probe: 0
>>
>> From a cold boot, without a region ever created, the endpoint port
>> unbind only disables BI - there is no committed decoder to reap:
>>
>> # echo endpoint2 > /sys/bus/cxl/drivers/cxl_port/unbind
>> [   22.046813] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests disabled
>> [   22.049676] cxl_core:cxl_detach_ep:1556: cxl_mem mem0: disconnect mem0 from port1
>>
>> # echo mem0 > /sys/bus/cxl/drivers/cxl_mem/bind
>> [   24.270628] cxl_core:devm_cxl_enumerate_ports:1871: cxl_mem mem0: scan: iter: mem0 dport_dev: 0000:0c:00.0 parent: pci0000:0c
>> [   24.273682] cxl_core:devm_cxl_enumerate_ports:1877: cxl_mem mem0: found already registered port port1:pci0000:0c
>> [   24.312426] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x0-0xffffffffffffffff iw: 1 ig: 256
>> [   24.315677] cxl_core:add_hdm_decoder:39: cxl_mem mem0: decoder2.0 added to endpoint2
>> [   24.332406] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests enabled
>> [   24.334427] cxl_core:cxl_bus_probe:2299: cxl_port endpoint2: probe: 0
>> [   24.337952] cxl_core:cxl_bus_probe:2299: cxl_mem mem0: probe: 0
>>
>> 5. Discovery behind a Switch
>> ----------------------------
>> [    0.782301] cxl_core:cxl_probe_component_regs:102: cxl_pci 0000:0f:00.0: found BI Decoder capability (0xab4)
>> [    0.851085] cxl_core:cxl_probe_component_regs:102: pcieport 0000:0c:00.0: found BI Decoder capability (0xab4)
>> [    0.866840] cxl_core:cxl_probe_component_regs:96: cxl_port port2: found BI RT capability (0xaa8)
>> [    0.902485] cxl_core:cxl_probe_component_regs:102: pcieport 0000:0e:00.0: found BI Decoder capability (0xab4)
>> [    1.221118] cxl_core:__cxl_bi_wait_commit:1032: pcieport 0000:0e:00.0: BI-ID commit wait took 250908us
>> [    1.368581] cxl_core:__cxl_bi_wait_commit:1032: cxl_port port2: BI-ID commit wait took 146455us
>> [    1.371579] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0f:00.0: BI requests enabled
>>
>> 6. Corrupted hw (commit timeout handling)
>> -----------------------------------------
>> [    1.003566] cxl_core:cxl_probe_component_regs:102: pcieport 0000:0e:00.0: found BI Decoder capability (0xab4)
>> [    3.203147] pcieport 0000:0e:00.0: BI-ID commit timed out (2000000us)
>> [    3.206048] cxl_port:cxl_endpoint_port_probe:190: cxl_port endpoint3: BI setup failed rc=-110
>>
>> 7. Mixed Configurations (BI-capable Type 3 but DSP 68b)
>> -------------------------------------------------------
>> [    0.837902] cxl_mem:cxl_mem_probe:155: cxl_mem mem0: BI setup failed rc=-22
>>
>> 8. Auto-discovered (committed) BI decoders
>> ------------------------------------------
>> For testing, qemu hack emulates auto-committed decoder:
>>
>> [    0.670374] cxl_core:devm_cxl_switch_port_decoders_setup:1282: cxl_port port1: Fallback to passthrough decoder
>> [    0.718374] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x190000000-0x19fffffff iw: 1 ig: 256
>> [    0.728498] cxl_core:__cxl_bi_ctrl_endpoint:1200: cxl_pci 0000:0d:00.0: adopting firmware-enabled BI
>> [    0.730880] cxl_core:devm_cxl_add_region:2829: cxl_acpi ACPI0017:00: decoder0.0: created HDM-DB region0
>> [    0.731906] cxl_core:__construct_region:3843: cxl_pci 0000:0d:00.0: mem0:decoder2.0: __construct_region region0 res: [mem 0x190000000-0x19fffffff flags 0x200] iw: 1 ig: 256
>> [    0.734473] cxl_core:cxl_region_sort_targets:2104: cxl region0: region sort successful
>> [    0.739452] cxl_core:devm_cxl_add_dax_region:101: cxl_region region0: region0: register dax_region0
>> [    0.740239] cxl_core:cxl_bus_probe:2299: cxl_region region0: probe: 0
>> # cat /sys/bus/cxl/devices/region0/commit
>> 1
>> # cat /sys/bus/cxl/devices/decoder2.0/bi
>> 1
>>
>> A committed BI decoder under a window without the BI restriction is
>> refused at region assembly:
>>
>> [    0.794477] cxl_core:__cxl_bi_ctrl_endpoint:1200: cxl_pci 0000:0d:00.0: adopting firmware-enabled BI
>> [    0.795396] cxl_pci 0000:0d:00.0: mem0:decoder2.0 BI decoder in a non-BI window
>> [    0.796050] cxl_port:discover_region:55: cxl decoder2.0: failed to add to region: 0x190000000-0x19fffffff
>>
>> Applies against v7.2-rc5. Please consider for v7.3.
>>
>> [0] https://lore.kernel.org/linux-cxl/20260428200410.705675-1-dave@stgolabs.net/
>>
>> Thanks!
>>
>> Davidlohr Bueso (9):
>>   cxl: Add BI register probing and port initialization
>>   cxl/pci: Add BI topology enable/disable
>>   cxl/hdm: Add BI coherency support for endpoint decoders
>>   cxl: Add HDM-DB region creation
>>   cxl/hdm: Rename decoder coherency flags
>>   cxl/region: Log the coherency model at region creation
>>   cxl: Move BI setup to endpoint port probe
>>   cxl/pci: Split BI capability probe from setup
>>   cxl: Allow auto-committed BI hdm decoders
>>
>>  Documentation/ABI/testing/sysfs-bus-cxl |  18 +-
>>  drivers/cxl/acpi.c                      |  19 +-
>>  drivers/cxl/core/core.h                 |   2 +
>>  drivers/cxl/core/hdm.c                  |  68 ++++-
>>  drivers/cxl/core/pci.c                  | 456 ++++++++++++++++++++++++++++++++
>>  drivers/cxl/core/port.c                 |  48 +++-
>>  drivers/cxl/core/region.c               |  97 ++++++-
>>  drivers/cxl/core/regs.c                 |  14 +
>>  drivers/cxl/cxl.h                       |  55 +++-
>>  drivers/cxl/cxlmem.h                    |   2 +
>>  drivers/cxl/port.c                      |  54 ++++
>>  include/cxl/cxl.h                       |  10 +
>>  12 files changed, 808 insertions(+), 35 deletions(-)
>>
>> --
>> 2.39.5
>

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

* Re: [PATCH v6 0/9] cxl: Support Back-Invalidate
  2026-07-27 21:26   ` Davidlohr Bueso
@ 2026-07-27 23:02     ` Dave Jiang
  2026-07-28  4:32       ` Davidlohr Bueso
  0 siblings, 1 reply; 14+ messages in thread
From: Dave Jiang @ 2026-07-27 23:02 UTC (permalink / raw)
  To: Davidlohr Bueso, Jonathan Cameron
  Cc: alison.schofield, icheng, benjamin.cheatham, alucerop,
	dongjoo.seo1, linux-kernel, linux-cxl



On 7/27/26 2:26 PM, Davidlohr Bueso wrote:
> On Mon, 27 Jul 2026, Jonathan Cameron wrote:
> 
>> On Mon, 27 Jul 2026 12:35:52 -0700
>> Davidlohr Bueso <dave@stgolabs.net> wrote:
>>
>>> Hello,
>>
>> Hi Davidlohr,
>>
>> You missed linux-cxl
> 
> bleh yeah that was a braino, I meant cxl not lkml - probably not worth another respin,
> but Cc'ing here.

You may want to resend if you want sashiko coverage.

> 
>>
>> J
>>>
>>> Changes from v5 (https://lore.kernel.org/all/20260615145529.13848-1-dave@stgolabs.net):
>>>   - Patch 1 documented the BI register block with the spec references
>>>     at the definitions. (Dave)
>>>   - Patch 2 split the enable/rollback into a helper so the unwind path
>>>     no longer mixes goto and scope-based cleanup (Sashiko).
>>>   - Patch 2 reworded the changelog around root port enablement.
>>>   - Patch 3 introduced cxled_default_type() so decoders present the
>>>     device's default target type when not attached to a region (Sashiko).
>>>   - Patch 4 defaults to host-only when firmware sets both CFMWS
>>>     coherency restrictions (Richard).
>>>   - Patch 4 restores the default target type on detach, fixing a stale
>>>     DEVMEM type leaking into a later HDM-H attach (Sashiko).
>>>   - Patch 4 'bi' sysfs now reports against the attached region's root
>>>     decoder rather than device state alone (Sashiko).
>>>   - Picked up review tags (thanks!).
>>>   - New patch 6: trivially log the coherency model at region creation dbg.
>>>   - New patches 7-9: move BI setup to endpoint port probe, split the
>>>     capability probe from BI-ID allocation, and allow for auto-committed
>>>     BI decoders instead of failing enumeration.
>>>
>>> This series is the initial plumbing to enable HDM-DB in Linux. The
>>> model allows Type 2 and Type 3 devices to expose their local memory
>>> to the host CPU in a coherent manner. In alignment with what was
>>> discussed at 2024 LPC type2 support session, this series takes the
>>> Type 3 memory expander approach, which is more direct. Further,
>>> afaik there is no Type 2 + BI hardware out there.
>>>
>>> A flagship use case of Type 3 + BI is coherent shared memory, and
>>> there is currently a big gap in this regard (ie: GFAM). Another
>>> is P2P via PCIe UIO, which is also lacking today. Media Operation
>>> (4402h) for ranged sanitize/zero also trigger snoops and there are
>>> some patches out there[0]. As such this series focuses on BI enablement
>>> in terms of discovery and configuration.
>>>
>>> The idea is for Type 3 memdevs and Type 2 devices to make use of
>>> cxlds->bi when committing HDM decoders, such that different device
>>> coherence models can be differentiated as:
>>>
>>>   type2 hdm-d:  cxlds->type == CXL_DEVTYPE_DEVMEM && cxlds->bi == false
>>>   type2 hdm-db: cxlds->type == CXL_DEVTYPE_DEVMEM && cxlds->bi == true
>>>   type3 hdm-h:  cxlds->type == CXL_DEVTYPE_CLASSMEM && cxlds->bi == false
>>>   type3 hdm-db: cxlds->type == CXL_DEVTYPE_CLASSMEM && cxlds->bi == true
>>>
>>> Unlike previous versions, an auto-committed BI decoder found during
>>> enumeration is no longer rejected: patches 7-9 adopt the inherited
>>> configuration when the device and path are BI capable, refusing only
>>> broken combinations. See the auto-discovery tests section below.
>>>
>>> o Patch 1 probes BI capabilities during register discovery, and maps BI
>>>   Decoder registers.
>>>
>>> o Patch 2 implements the BI-ID allocation (and deallocation).
>>>
>>> o Patch 3 adds coherency support for endpoint decoders based on what the
>>> root decoder restricts.
>>>
>>> o Patch 4 adds support for HDM-DB region creation.
>>>
>>> o Patch 5 trivially renames some coherency flags.
>>>
>>> o Patch 6 logs the coherency model (HDM-H, HDM-D, HDM-DB) when a
>>>   region is created.
>>>
>>> o Patch 7 moves BI setup to endpoint port probe, tying the BI-ID
>>>   lifetime to the endpoint port.
>>>
>>> o Patch 8 splits the BI capability walk from BI-ID allocation so the
>>>   answer is available when committed decoders are first parsed.
>>>
>>> o Patch 9 allows committed BI decoders. Overall this series
>>>   could be picked up with or without this patch.
>>>
>>> Please note that patch 7+8 could be consolidated into patch 2,
>>> instead of starting out with cxl_mem but I chose to add them
>>> incrementally because 1) want to see what sashiko says,
>>> 2) it isolates the requirements for the auto-committed support
>>> (patch 9); 3) details why endpoint lifecycle is safe and
>>> 4) reuses already valuable review times of the current state
>>> of the series. But I certainly see the reasons to avoid the
>>> additional patches.
>>>
>>> Testing
>>> -------
>>>
>>> Testing has been done on top of upstream qemu with the CFMW options series:
>>>
>>>   https://lore.kernel.org/all/20260720233242.901544-1-dave@stgolabs.net/
>>>
>>> A new qemu-based test suite has been added for full automation and pounding,
>>> covering many topologies and corner cases:
>>>
>>>   https://github.com/davidlohr/cxl-bi-tests
>>>
>>> This passes regression testing (nothing breaks) ndctl suite via cxl_test.
>>>
>>> 1. HDM Decoder with BI through ad-hoc region creation.
>>> ------------------------------------------------------
>>> # cxl list -D
>>> [
>>>   {
>>>     "decoder":"decoder0.0",
>>>     "resource":6710886400,
>>>     "size":4294967296,
>>>     "interleave_ways":1,
>>>     "accelmem_capable":true,
>>>     "nr_targets":1
>>>   }
>>> ]
>>>
>>> # ROOT=/sys/bus/cxl/devices/decoder0.0
>>> # EP=/sys/bus/cxl/devices/decoder2.0
>>> # echo region0 > $ROOT/create_ram_region
>>> [    7.662871] cxl_core:devm_cxl_add_region:2829: cxl_acpi ACPI0017:00: decoder0.0: created HDM-DB region0
>>> # REG=/sys/bus/cxl/devices/region0
>>> # echo ram > $EP/mode
>>> # echo 0x40000000 > $EP/dpa_size
>>> # echo 1 > $REG/interleave_ways
>>> # echo 4096 > $REG/interleave_granularity
>>> # echo 0x40000000 > $REG/size
>>> # cat $EP/bi
>>> 0
>>> # echo decoder2.0 > $REG/target0
>>> [    8.153566] cxl_core:cxl_port_attach_region:1295: cxl region0: mem0:endpoint2 decoder2.0 add: mem0:decoder2.0 @ 0 next: none nr_eps: 1 nr_targets: 1
>>> [    8.157683] cxl_core:cxl_port_attach_region:1295: cxl region0: pci0000:0c:port1 decoder1.0 add: mem0:decoder2.0 @ 0 next: mem0 nr_eps: 1 nr_targets: 1
>>> [    8.159570] cxl_core:cxl_port_setup_targets:1630: cxl region0: pci0000:0c:port1 iw: 1 ig: 4096
>>> [    8.160487] cxl_core:cxl_port_setup_targets:1638: cxl region0: pci0000:0c:port1 target[0] = 0000:0c:00.0 for mem0:decoder2.0 @ 0
>>> [    8.161759] cxl_core:cxl_calc_interleave_pos:2046: cxl_mem mem0: decoder:decoder2.0 parent:0000:0d:00.0 port:endpoint2 range:0x190000000-0x1cfffffff pos:0
>>> [    8.163681] cxl_core:cxl_region_attach:2270: cxl decoder2.0: Test cxl_calc_interleave_pos(): success test_pos:0 target->pos:0
>>> # cat $EP/bi
>>> 1
>>> # echo 1 > $REG/commit
>>> # cxl list -D
>>> [
>>>   {
>>>     "root decoders":[
>>>       {
>>>         "decoder":"decoder0.0",
>>>         "resource":6710886400,
>>>         "size":4294967296,
>>>         "interleave_ways":1,
>>>         "accelmem_capable":true,
>>>         "nr_targets":1
>>>       }
>>>     ]
>>>   },
>>>   {
>>>     "port decoders":[
>>>       {
>>>         "decoder":"decoder1.0",
>>>         "resource":6710886400,
>>>         "size":1073741824,
>>>         "interleave_ways":1,
>>>         "region":"region0",
>>>         "nr_targets":1
>>>       }
>>>     ]
>>>   },
>>>   {
>>>     "endpoint decoders":[
>>>       {
>>>         "decoder":"decoder2.0",
>>>         "resource":6710886400,
>>>         "size":1073741824,
>>>         "interleave_ways":1,
>>>         "region":"region0",
>>>         "dpa_resource":0,
>>>         "dpa_size":1073741824,
>>>         "mode":"ram"
>>>       }
>>>     ]
>>>   }
>>> ]
>>>
>>> 2. Type3 device does not support BI, but CFMW has BI restriction
>>> ----------------------------------------------------------------
>>> # echo decoder2.0 > $REG/target0
>>> [    7.311927] cxl region0: mem0:decoder2.0 BI not enabled on device
>>> [    7.313907] cxl_port endpoint2: failed to attach decoder2.0 to region0: -6
>>>
>>> 3. Type3 device supports BI but CFMW does not, create HDM-H region
>>> ------------------------------------------------------------------
>>> # cxl list -D
>>> [
>>>   {
>>>     "decoder":"decoder0.0",
>>>     "resource":6710886400,
>>>     "size":4294967296,
>>>     "interleave_ways":1,
>>>     "max_available_extent":4294967296,
>>>     "pmem_capable":true,
>>>     "volatile_capable":true,
>>>     "accelmem_capable":true,
>>>     "nr_targets":1
>>>   }
>>> ]
>>> # echo region0 > $ROOT/create_ram_region
>>> [    7.679496] cxl_core:devm_cxl_add_region:2829: cxl_acpi ACPI0017:00: decoder0.0: created HDM-H region0
>>> # cat $EP/bi
>>> 0
>>> # echo decoder2.0 > $REG/target0
>>> [    8.165400] cxl_core:cxl_port_attach_region:1295: cxl region0: mem0:endpoint2 decoder2.0 add: mem0:decoder2.0 @ 0 next: none nr_eps: 1 nr_targets: 1
>>> [    8.167128] cxl_core:cxl_port_attach_region:1295: cxl region0: pci0000:0c:port1 decoder1.0 add: mem0:decoder2.0 @ 0 next: mem0 nr_eps: 1 nr_targets: 1
>>> [    8.168834] cxl_core:cxl_port_setup_targets:1630: cxl region0: pci0000:0c:port1 iw: 1 ig: 4096
>>> [    8.169893] cxl_core:cxl_port_setup_targets:1638: cxl region0: pci0000:0c:port1 target[0] = 0000:0c:00.0 for mem0:decoder2.0 @ 0
>>> [    8.171302] cxl_core:cxl_calc_interleave_pos:2046: cxl_mem mem0: decoder:decoder2.0 parent:0000:0d:00.0 port:endpoint2 range:0x190000000-0x1cfffffff pos:0
>>> [    8.173036] cxl_core:cxl_region_attach:2270: cxl decoder2.0: Test cxl_calc_interleave_pos(): success test_pos:0 target->pos:0
>>> # echo 1 > $REG/commit
>>> # cat $EP/bi
>>> 0
>>>
>>> 4. Unbind + Bind
>>> ----------------
>>> # echo mem0 > /sys/bus/cxl/drivers/cxl_mem/unbind
>>> [    7.645330] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests disabled
>>> [    7.648838] cxl_core:cxl_port_commit_reap:900: cxl_port endpoint2: reap: decoder2.0 commit_end: -1
>>> [    7.651284] cxl_core:cxl_detach_ep:1556: cxl_mem mem0: disconnect mem0 from port1
>>>
>>> # echo mem0 > /sys/bus/cxl/drivers/cxl_mem/bind
>>> [    8.909437] cxl_core:devm_cxl_enumerate_ports:1871: cxl_mem mem0: scan: iter: mem0 dport_dev: 0000:0c:00.0 parent: pci0000:0c
>>> [    8.911170] cxl_core:devm_cxl_enumerate_ports:1877: cxl_mem mem0: found already registered port port1:pci0000:0c
>>> [    8.945969] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x0-0xffffffffffffffff iw: 1 ig: 4096
>>> [    8.949705] cxl_core:add_hdm_decoder:39: cxl_mem mem0: decoder2.0 added to endpoint2
>>> [    8.960378] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests enabled
>>> [    8.961196] cxl_core:cxl_bus_probe:2299: cxl_port endpoint2: probe: 0
>>> [    8.962592] cxl_core:cxl_bus_probe:2299: cxl_mem mem0: probe: 0
>>>
>>> The same applies to the endpoint port, with the memdev rebind recovering the endpoint:
>>>
>>> # echo endpoint2 > /sys/bus/cxl/drivers/cxl_port/unbind
>>> [   10.483509] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests disabled
>>> [   10.487570] cxl_core:cxl_port_commit_reap:900: cxl_port endpoint2: reap: decoder2.0 commit_end: -1
>>> [   10.491501] cxl_core:cxl_detach_ep:1556: cxl_mem mem0: disconnect mem0 from port1
>>>
>>> # echo mem0 > /sys/bus/cxl/drivers/cxl_mem/bind
>>> [   11.754957] cxl_core:devm_cxl_enumerate_ports:1871: cxl_mem mem0: scan: iter: mem0 dport_dev: 0000:0c:00.0 parent: pci0000:0c
>>> [   11.756343] cxl_core:devm_cxl_enumerate_ports:1877: cxl_mem mem0: found already registered port port1:pci0000:0c
>>> [   11.789821] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x0-0xffffffffffffffff iw: 1 ig: 4096
>>> [   11.794674] cxl_core:add_hdm_decoder:39: cxl_mem mem0: decoder2.0 added to endpoint2
>>> [   11.805772] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests enabled
>>> [   11.806810] cxl_core:cxl_bus_probe:2299: cxl_port endpoint2: probe: 0
>>> [   11.808661] cxl_core:cxl_bus_probe:2299: cxl_mem mem0: probe: 0
>>>
>>> From a cold boot, without a region ever created, the endpoint port
>>> unbind only disables BI - there is no committed decoder to reap:
>>>
>>> # echo endpoint2 > /sys/bus/cxl/drivers/cxl_port/unbind
>>> [   22.046813] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests disabled
>>> [   22.049676] cxl_core:cxl_detach_ep:1556: cxl_mem mem0: disconnect mem0 from port1
>>>
>>> # echo mem0 > /sys/bus/cxl/drivers/cxl_mem/bind
>>> [   24.270628] cxl_core:devm_cxl_enumerate_ports:1871: cxl_mem mem0: scan: iter: mem0 dport_dev: 0000:0c:00.0 parent: pci0000:0c
>>> [   24.273682] cxl_core:devm_cxl_enumerate_ports:1877: cxl_mem mem0: found already registered port port1:pci0000:0c
>>> [   24.312426] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x0-0xffffffffffffffff iw: 1 ig: 256
>>> [   24.315677] cxl_core:add_hdm_decoder:39: cxl_mem mem0: decoder2.0 added to endpoint2
>>> [   24.332406] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0d:00.0: BI requests enabled
>>> [   24.334427] cxl_core:cxl_bus_probe:2299: cxl_port endpoint2: probe: 0
>>> [   24.337952] cxl_core:cxl_bus_probe:2299: cxl_mem mem0: probe: 0
>>>
>>> 5. Discovery behind a Switch
>>> ----------------------------
>>> [    0.782301] cxl_core:cxl_probe_component_regs:102: cxl_pci 0000:0f:00.0: found BI Decoder capability (0xab4)
>>> [    0.851085] cxl_core:cxl_probe_component_regs:102: pcieport 0000:0c:00.0: found BI Decoder capability (0xab4)
>>> [    0.866840] cxl_core:cxl_probe_component_regs:96: cxl_port port2: found BI RT capability (0xaa8)
>>> [    0.902485] cxl_core:cxl_probe_component_regs:102: pcieport 0000:0e:00.0: found BI Decoder capability (0xab4)
>>> [    1.221118] cxl_core:__cxl_bi_wait_commit:1032: pcieport 0000:0e:00.0: BI-ID commit wait took 250908us
>>> [    1.368581] cxl_core:__cxl_bi_wait_commit:1032: cxl_port port2: BI-ID commit wait took 146455us
>>> [    1.371579] cxl_core:__cxl_bi_ctrl_endpoint:1218: cxl_pci 0000:0f:00.0: BI requests enabled
>>>
>>> 6. Corrupted hw (commit timeout handling)
>>> -----------------------------------------
>>> [    1.003566] cxl_core:cxl_probe_component_regs:102: pcieport 0000:0e:00.0: found BI Decoder capability (0xab4)
>>> [    3.203147] pcieport 0000:0e:00.0: BI-ID commit timed out (2000000us)
>>> [    3.206048] cxl_port:cxl_endpoint_port_probe:190: cxl_port endpoint3: BI setup failed rc=-110
>>>
>>> 7. Mixed Configurations (BI-capable Type 3 but DSP 68b)
>>> -------------------------------------------------------
>>> [    0.837902] cxl_mem:cxl_mem_probe:155: cxl_mem mem0: BI setup failed rc=-22
>>>
>>> 8. Auto-discovered (committed) BI decoders
>>> ------------------------------------------
>>> For testing, qemu hack emulates auto-committed decoder:
>>>
>>> [    0.670374] cxl_core:devm_cxl_switch_port_decoders_setup:1282: cxl_port port1: Fallback to passthrough decoder
>>> [    0.718374] cxl_core:init_hdm_decoder:1128: cxl_port endpoint2: decoder2.0: range: 0x190000000-0x19fffffff iw: 1 ig: 256
>>> [    0.728498] cxl_core:__cxl_bi_ctrl_endpoint:1200: cxl_pci 0000:0d:00.0: adopting firmware-enabled BI
>>> [    0.730880] cxl_core:devm_cxl_add_region:2829: cxl_acpi ACPI0017:00: decoder0.0: created HDM-DB region0
>>> [    0.731906] cxl_core:__construct_region:3843: cxl_pci 0000:0d:00.0: mem0:decoder2.0: __construct_region region0 res: [mem 0x190000000-0x19fffffff flags 0x200] iw: 1 ig: 256
>>> [    0.734473] cxl_core:cxl_region_sort_targets:2104: cxl region0: region sort successful
>>> [    0.739452] cxl_core:devm_cxl_add_dax_region:101: cxl_region region0: region0: register dax_region0
>>> [    0.740239] cxl_core:cxl_bus_probe:2299: cxl_region region0: probe: 0
>>> # cat /sys/bus/cxl/devices/region0/commit
>>> 1
>>> # cat /sys/bus/cxl/devices/decoder2.0/bi
>>> 1
>>>
>>> A committed BI decoder under a window without the BI restriction is
>>> refused at region assembly:
>>>
>>> [    0.794477] cxl_core:__cxl_bi_ctrl_endpoint:1200: cxl_pci 0000:0d:00.0: adopting firmware-enabled BI
>>> [    0.795396] cxl_pci 0000:0d:00.0: mem0:decoder2.0 BI decoder in a non-BI window
>>> [    0.796050] cxl_port:discover_region:55: cxl decoder2.0: failed to add to region: 0x190000000-0x19fffffff
>>>
>>> Applies against v7.2-rc5. Please consider for v7.3.
>>>
>>> [0] https://lore.kernel.org/linux-cxl/20260428200410.705675-1-dave@stgolabs.net/
>>>
>>> Thanks!
>>>
>>> Davidlohr Bueso (9):
>>>   cxl: Add BI register probing and port initialization
>>>   cxl/pci: Add BI topology enable/disable
>>>   cxl/hdm: Add BI coherency support for endpoint decoders
>>>   cxl: Add HDM-DB region creation
>>>   cxl/hdm: Rename decoder coherency flags
>>>   cxl/region: Log the coherency model at region creation
>>>   cxl: Move BI setup to endpoint port probe
>>>   cxl/pci: Split BI capability probe from setup
>>>   cxl: Allow auto-committed BI hdm decoders
>>>
>>>  Documentation/ABI/testing/sysfs-bus-cxl |  18 +-
>>>  drivers/cxl/acpi.c                      |  19 +-
>>>  drivers/cxl/core/core.h                 |   2 +
>>>  drivers/cxl/core/hdm.c                  |  68 ++++-
>>>  drivers/cxl/core/pci.c                  | 456 ++++++++++++++++++++++++++++++++
>>>  drivers/cxl/core/port.c                 |  48 +++-
>>>  drivers/cxl/core/region.c               |  97 ++++++-
>>>  drivers/cxl/core/regs.c                 |  14 +
>>>  drivers/cxl/cxl.h                       |  55 +++-
>>>  drivers/cxl/cxlmem.h                    |   2 +
>>>  drivers/cxl/port.c                      |  54 ++++
>>>  include/cxl/cxl.h                       |  10 +
>>>  12 files changed, 808 insertions(+), 35 deletions(-)
>>>
>>> -- 
>>> 2.39.5
>>


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

* Re: [PATCH v6 0/9] cxl: Support Back-Invalidate
  2026-07-27 23:02     ` Dave Jiang
@ 2026-07-28  4:32       ` Davidlohr Bueso
  0 siblings, 0 replies; 14+ messages in thread
From: Davidlohr Bueso @ 2026-07-28  4:32 UTC (permalink / raw)
  To: Dave Jiang
  Cc: Jonathan Cameron, alison.schofield, icheng, benjamin.cheatham,
	alucerop, dongjoo.seo1, linux-kernel, linux-cxl

On Mon, 27 Jul 2026, Dave Jiang wrote:

>You may want to resend if you want sashiko coverage.

So I think we just don't get the emails, I can see the coverage in
the dashboard:

   https://sashiko.dev/#/patchset/20260727193601.651871-1-dave%40stgolabs.net

And on that note most of the issues were duplicate false positives or
things that are fixed in later patches in the series. And the actual
patches 7-9 came out green, so it seems sashiko had no issues with
the endpoint port lifecycle or the auto-commit support.

So yeah will just resend altogether as a v7 and go ahead and fold patch 7
into patch 2, which is the most sensible way to break the series up, imo.

Thanks,
Davidlohr

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

end of thread, other threads:[~2026-07-28  4:32 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-07-27 19:35 [PATCH v6 0/9] cxl: Support Back-Invalidate Davidlohr Bueso
2026-07-27 19:35 ` [PATCH v6 1/9] cxl: Add BI register probing and port initialization Davidlohr Bueso
2026-07-27 19:35 ` [PATCH v6 2/9] cxl/pci: Add BI topology enable/disable Davidlohr Bueso
2026-07-27 19:35 ` [PATCH v6 3/9] cxl/hdm: Add BI coherency support for endpoint decoders Davidlohr Bueso
2026-07-27 19:35 ` [PATCH v6 4/9] cxl: Add HDM-DB region creation Davidlohr Bueso
2026-07-27 19:35 ` [PATCH v6 5/9] cxl/hdm: Rename decoder coherency flags Davidlohr Bueso
2026-07-27 19:35 ` [PATCH v6 6/9] cxl/region: Log the coherency model at region creation Davidlohr Bueso
2026-07-27 19:35 ` [PATCH v6 7/9] cxl: Move BI setup to endpoint port probe Davidlohr Bueso
2026-07-27 19:36 ` [PATCH v6 8/9] cxl/pci: Split BI capability probe from setup Davidlohr Bueso
2026-07-27 19:36 ` [PATCH v6 9/9] cxl: Allow auto-committed BI hdm decoders Davidlohr Bueso
2026-07-27 20:59 ` [PATCH v6 0/9] cxl: Support Back-Invalidate Jonathan Cameron
2026-07-27 21:26   ` Davidlohr Bueso
2026-07-27 23:02     ` Dave Jiang
2026-07-28  4:32       ` Davidlohr Bueso

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®