mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support
@ 2026-09-14 11:29 Adrian Hunter
  2026-09-14 11:29 ` [PATCH 01/17] i3c: master: Fix out-of-bounds read in DMA bounce buffer setup Adrian Hunter
                   ` (16 more replies)
  0 siblings, 17 replies; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

Hi

This series brings a collection of fixes, specification-conformance
cleanups and feature additions to the I3C core and MIPI I3C HCI driver.

The first three patches are independent fixes tagged for stable. The
remaining patches address a mixture of correctness issues in the core
and HCI driver, improve conformance with the I3C and HCI
specifications, add support for configurable device NACK retries, and
finally add HDR-DDR support.

The series is organised as follows:

  Stable fixes (patches 1-3)
  --------------------------

  - Fix an out-of-bounds read in the core DMA bounce-buffer helper.

  - Fix a destination buffer overrun in the HCI DMA path for reads whose
    length is not a multiple of four bytes. The issue is independent of
    IOMMU usage, although the existing workaround was only applied when
    an IOMMU was present.

  - Close a probe-time race in the HCI PCI driver where the LTR sysfs
    attribute becomes visible before drvdata has been initialized.

  Core fixes (patches 4-5)
  ------------------------

  - Fix ACPI target enumeration on multi-instance controllers by
    extracting the bus-controller instance number and PID from the
    correct _ADR fields.

  - Remove a stale GETSTATUS response-length check that became obsolete
    when actual_len-based validation was introduced.

  HCI IBI and suspend fixes (patches 6-11)
  ----------------------------------------

  - Fix the IBI enable error path to unwind controller-side setup when
    ENEC fails.

  - Send DISEC before disabling IBIs in hardware so that an IBI racing
    with teardown is not silently dropped.

  - Avoid accessing controller hardware from ->free_ibi(), where runtime
    PM does not guarantee the device is resumed.

  - Drain all pending IBIs whenever INTR_IBI_READY is received instead
    of processing only the first queued entry.

  - Reorganize the DMA suspend/resume callbacks in preparation for the
    following change.

  - Rework DMA suspend handling to stop Ring Bundles according to the
    HCI specification, synchronize with the interrupt handler, and flush
    any pending IBI before disabling the rings.

  HCI specification cleanups (patches 12-14)
  -------------------------------------------

  - Correct the Response Descriptor DATA_LENGTH field definition.

  - Remove an invalid maximum-transfer-size capability derived from
    reserved HC_CAPABILITIES bits.

  - Remove HDR-BT and Fm/Fm+ definitions that are not defined by any
    released version of the HCI specification.

  Feature additions (patches 15-17)
  ---------------------------------

  - Implement the .set_dev_nack_retry() master operation using DAT
    support provided by HCI v1 controllers.

  - Restrict advertised and permitted HDR modes to the intersection of:
      * controller capabilities,
      * bus-configuration constraints, and
      * target capabilities.

  - Add HDR-DDR private-transfer support to the HCI driver, including
    descriptor generation and capability advertisement when supported by
    both the controller and the active command-descriptor format.


Adrian Hunter (17):
      i3c: master: Fix out-of-bounds read in DMA bounce buffer setup
      i3c: mipi-i3c-hci: Bounce short reads irrespective of the IOMMU
      i3c: mipi-i3c-hci-pci: Set drvdata before creating LTR sysfs attribute
      i3c: master: Match ACPI targets to the correct bus controller instance
      i3c: master: Remove stale GETSTATUS length check
      i3c: mipi-i3c-hci: Fix i3c_hci_enable_ibi() error path
      i3c: mipi-i3c-hci: Send DISEC before disabling IBIs in hardware
      i3c: mipi-i3c-hci: Fix runtime PM violation in i3c_hci_free_ibi()
      i3c: mipi-i3c-hci: Process multiple IBIs per interrupt
      i3c: mipi-i3c-hci: Move DMA suspend/resume callbacks
      i3c: mipi-i3c-hci: Stop rings gracefully when suspending
      i3c: mipi-i3c-hci: Fix Response Descriptor DATA_LENGTH mask
      i3c: mipi-i3c-hci: Remove invalid transfer size limit
      i3c: mipi-i3c-hci: Remove invalid HDR-BT and Fm/Fm+ definitions
      i3c: mipi-i3c-hci: Support configurable device NACK retries
      i3c: Restrict HDR modes to those supported by the bus and target
      i3c: mipi-i3c-hci: Add HDR-DDR support

 drivers/i3c/device.c                               |  15 ++-
 drivers/i3c/internals.h                            |   2 +
 drivers/i3c/master.c                               |  88 +++++++++++++--
 drivers/i3c/master/mipi-i3c-hci/cmd.h              |   4 +-
 drivers/i3c/master/mipi-i3c-hci/cmd_v1.c           |  28 ++++-
 drivers/i3c/master/mipi-i3c-hci/cmd_v2.c           |   4 +-
 drivers/i3c/master/mipi-i3c-hci/core.c             |  99 +++++++++++++---
 drivers/i3c/master/mipi-i3c-hci/dat.h              |   2 +
 drivers/i3c/master/mipi-i3c-hci/dat_v1.c           |  25 +++++
 drivers/i3c/master/mipi-i3c-hci/dma.c              | 125 ++++++++++++++-------
 drivers/i3c/master/mipi-i3c-hci/hci.h              |   9 +-
 drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c |   5 +-
 include/linux/i3c/device.h                         |   4 +
 include/linux/i3c/master.h                         |   3 +
 include/linux/platform_data/mipi-i3c-hci.h         |   4 +
 15 files changed, 330 insertions(+), 87 deletions(-)


Regards
Adrian

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

* [PATCH 01/17] i3c: master: Fix out-of-bounds read in DMA bounce buffer setup
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
@ 2026-09-14 11:29 ` Adrian Hunter
  2026-09-14 16:09   ` Frank Li
  2026-09-14 11:29 ` [PATCH 02/17] i3c: mipi-i3c-hci: Bounce short reads irrespective of the IOMMU Adrian Hunter
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

When a bounce buffer is required for DMA_TO_DEVICE transfers,
i3c_master_dma_map_single() rounds the DMA mapping length up to a
cache-line boundary:

	map_len = ALIGN(len, cache_line_size());

It then allocates the bounce buffer with:

	kmemdup(buf, map_len, GFP_KERNEL);

kmemdup() copies the full allocation size, causing it to read map_len
bytes from buf even though only len bytes are valid.  This results in an
out-of-bounds read of up to cache_line_size() - 1 bytes past the end of
the caller's buffer.

Fix the issue by allocating the bounce buffer with kzalloc() and copying
only len bytes from the original buffer.  The remaining bytes up to
map_len stay zero-filled, avoiding both the out-of-bounds read and
exposure of unrelated memory contents to the DMA engine.

Fixes: f8d9e56aeb87 ("i3c: master: Add helpers for DMA mapping and bounce buffer handling")
Cc: stable@vger.kernel.org
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index afcd7a21a3e6..f9a6c8560fab 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -2216,12 +2216,11 @@ struct i3c_dma *i3c_master_dma_map_single(struct device *dev, void *buf,
 
 	if (force_bounce) {
 		dma_xfer->map_len = ALIGN(len, cache_line_size());
-		if (dir == DMA_FROM_DEVICE)
-			bounce = kzalloc(dma_xfer->map_len, GFP_KERNEL);
-		else
-			bounce = kmemdup(buf, dma_xfer->map_len, GFP_KERNEL);
+		bounce = kzalloc(dma_xfer->map_len, GFP_KERNEL);
 		if (!bounce)
 			return NULL;
+		if (dir != DMA_FROM_DEVICE)
+			memcpy(bounce, buf, len);
 		dma_buf = bounce;
 	}
 
-- 
2.53.0


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

* [PATCH 02/17] i3c: mipi-i3c-hci: Bounce short reads irrespective of the IOMMU
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
  2026-09-14 11:29 ` [PATCH 01/17] i3c: master: Fix out-of-bounds read in DMA bounce buffer setup Adrian Hunter
@ 2026-09-14 11:29 ` Adrian Hunter
  2026-09-14 16:16   ` Frank Li
  2026-09-14 11:29 ` [PATCH 03/17] i3c: mipi-i3c-hci-pci: Set drvdata before creating LTR sysfs attribute Adrian Hunter
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

The controller writes whole DWORDs, so a read whose length is not a
multiple of 4 overwrites up to 3 bytes past the end of the destination
buffer. That is a property of the controller, not of the IOMMU, but the
bounce buffer that works around it was used only when the device was
IOMMU mapped. Everywhere else the buffer is left unprotected.

Drop the device_iommu_mapped() condition.

The overrun is easily seen with CONFIG_SLUB_DEBUG=y and kernel command
line options intel_iommu=off slub_debug=FZPU, which reports it as a
kmalloc redzone overwrite.

Fixes: 9e23897bca62 ("i3c: mipi-i3c-hci: Use physical device pointer with DMA API")
Cc: stable@vger.kernel.org
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/dma.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
index 7c2b20474130..5b195978f376 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
@@ -428,7 +428,7 @@ static void hci_dma_unmap_xfer(struct i3c_hci *hci,
 static struct i3c_dma *hci_dma_map_xfer(struct device *dev, struct hci_xfer *xfer)
 {
 	enum dma_data_direction dir = xfer->rnw ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
-	bool need_bounce = device_iommu_mapped(dev) && xfer->rnw && (xfer->data_len & 3);
+	bool need_bounce = xfer->rnw && (xfer->data_len & 3);
 
 	return i3c_master_dma_map_single(dev, xfer->data, xfer->data_len, need_bounce, dir);
 }
-- 
2.53.0


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

* [PATCH 03/17] i3c: mipi-i3c-hci-pci: Set drvdata before creating LTR sysfs attribute
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
  2026-09-14 11:29 ` [PATCH 01/17] i3c: master: Fix out-of-bounds read in DMA bounce buffer setup Adrian Hunter
  2026-09-14 11:29 ` [PATCH 02/17] i3c: mipi-i3c-hci: Bounce short reads irrespective of the IOMMU Adrian Hunter
@ 2026-09-14 11:29 ` Adrian Hunter
  2026-09-14 16:17   ` Frank Li
  2026-09-14 11:29 ` [PATCH 04/17] i3c: master: Match ACPI targets to the correct bus controller instance Adrian Hunter
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

intel_i3c_init() creates the pm_qos_latency_tolerance_us sysfs attribute
before probe calls pci_set_drvdata().  A userspace write to the attribute
can therefore invoke intel_ltr_set(), which uses pci_get_drvdata(),
before drvdata has been initialized.

Move pci_set_drvdata() before hci->info->init() so drvdata is available
before the sysfs attribute becomes accessible.

Fixes: 884a33131f2a ("i3c: mipi-i3c-hci-pci: Add LTR support for Intel controllers")
Cc: stable@vger.kernel.org
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
index ab595661db1e..af9595009b03 100644
--- a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
+++ b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
@@ -445,6 +445,8 @@ static int mipi_i3c_hci_pci_probe(struct pci_dev *pci,
 	if (ret < 0)
 		return ret;
 
+	pci_set_drvdata(pci, hci);
+
 	hci->info = (const struct mipi_i3c_hci_pci_info *)id->driver_data;
 
 	ret = hci->info->init ? hci->info->init(hci) : 0;
@@ -455,8 +457,6 @@ static int mipi_i3c_hci_pci_probe(struct pci_dev *pci,
 	if (ret)
 		goto err_exit;
 
-	pci_set_drvdata(pci, hci);
-
 	mipi_i3c_hci_pci_rpm_allow(&pci->dev);
 
 	return 0;
-- 
2.53.0


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

* [PATCH 04/17] i3c: master: Match ACPI targets to the correct bus controller instance
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (2 preceding siblings ...)
  2026-09-14 11:29 ` [PATCH 03/17] i3c: mipi-i3c-hci-pci: Set drvdata before creating LTR sysfs attribute Adrian Hunter
@ 2026-09-14 11:29 ` Adrian Hunter
  2026-09-14 16:19   ` Frank Li
  2026-09-14 11:29 ` [PATCH 05/17] i3c: master: Remove stale GETSTATUS length check Adrian Hunter
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

For ACPI-enumerated I3C targets, _ADR encodes both the zero-based bus
controller instance number in bits 51:48 and the Provisioned ID (PID)
in bits 47:0, as defined by ACPI 6.6 Table 6.2 and MIPI DisCo for I3C
v1.1 section 5.2.

However, i3c_master_add_acpi_dev() treats the entire _ADR value as the
PID. On multi-instance controllers this folds the instance number into
the PID, causing i3c_master_add_i3c_boardinfo() to reject devices on
instance 1 and above with -EINVAL.

The problem is exposed by the MIPI I3C HCI PCI driver, which creates one
MFD child device per bus controller instance. Since the child devices do
not have their own ACPI companions, they all inherit the parent's ACPI
node and therefore enumerate the same set of child devices. As a result,
a target belonging to any instance other than 0 prevents registration of
all controller instances.

Add an instance number to struct i3c_master_controller, propagate it
from the HCI PCI driver, extract the PID from bits 47:0 of _ADR, and
ignore ACPI child nodes that belong to a different controller instance.

ACPI-enumerated I2C devices are unaffected. Their controller instance is
encoded in the Resource Source Index of the I2cSerialBusV2 descriptor
rather than in _ADR and will require separate handling.

Fixes: b46a4b3c5d1e ("i3c: master: Support ACPI enumeration of child devices")
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master.c                          | 19 +++++++++++++++++--
 drivers/i3c/master/mipi-i3c-hci/core.c        |  4 +++-
 .../master/mipi-i3c-hci/mipi-i3c-hci-pci.c    |  1 +
 include/linux/i3c/master.h                    |  3 +++
 include/linux/platform_data/mipi-i3c-hci.h    |  4 ++++
 5 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index f9a6c8560fab..215a22f2c7b6 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -8,6 +8,7 @@
 #include <dt-bindings/i3c/i3c.h>
 #include <linux/acpi.h>
 #include <linux/atomic.h>
+#include <linux/bitfield.h>
 #include <linux/bitmap.h>
 #include <linux/bug.h>
 #include <linux/delay.h>
@@ -3076,6 +3077,13 @@ static int i3c_master_add_of_dev(struct i3c_master_controller *master,
 	return ret;
 }
 
+#define I3C_ACPI_ADR_PID GENMASK_U64(47, 0)
+/*
+ * Zero-based instance number of the Bus Controller to which the Target is
+ * connected.
+ */
+#define I3C_ACPI_ADR_INSTANCE GENMASK_U64(51, 48)
+
 #ifdef CONFIG_ACPI
 static int i3c_master_add_acpi_dev(struct i3c_master_controller *master,
 				   struct fwnode_handle *fwnode)
@@ -3083,6 +3091,7 @@ static int i3c_master_add_acpi_dev(struct i3c_master_controller *master,
 	struct acpi_device *adev = to_acpi_device_node(fwnode);
 	acpi_bus_address adr;
 	u32 reg[3] = { 0 };
+	u64 pid;
 	int ret;
 
 	/*
@@ -3100,9 +3109,15 @@ static int i3c_master_add_acpi_dev(struct i3c_master_controller *master,
 
 	adr = acpi_device_adr(adev);
 
+	/* Match the multi-bus instance number */
+	if (FIELD_GET(I3C_ACPI_ADR_INSTANCE, adr) != master->instance)
+		return 0;
+
 	/* For I3C devices, _ADR will have the 48 bit PID of the device  */
-	reg[1] = upper_32_bits(adr);
-	reg[2] = lower_32_bits(adr);
+	pid = FIELD_GET(I3C_ACPI_ADR_PID, adr);
+
+	reg[1] = upper_32_bits(pid);
+	reg[2] = lower_32_bits(pid);
 
 	fwnode_property_read_u32(fwnode, "mipi-i3c-static-address", &reg[0]);
 
diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index dadf049bd4b5..8b3a87d8a8bb 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -1142,8 +1142,10 @@ static int i3c_hci_probe(struct platform_device *pdev)
 	 * necessarily in separate contiguous sub-ranges. To avoid overlapping
 	 * mappings, provide base_regs from the parent mapping.
 	 */
-	if (pdata)
+	if (pdata) {
 		hci->base_regs = pdata->base_regs;
+		hci->master.instance = pdata->instance;
+	}
 
 	if (!hci->base_regs) {
 		hci->base_regs = devm_platform_ioremap_resource(pdev, 0);
diff --git a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
index af9595009b03..5b8e10d05cee 100644
--- a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
+++ b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
@@ -390,6 +390,7 @@ static void mipi_i3c_hci_pci_setup_cell(struct mipi_i3c_hci_pci *hci, int idx,
 					struct mfd_cell *cell)
 {
 	data->pdata.base_regs = hci->base + hci->info->instance_offset[idx];
+	data->pdata.instance = idx;
 
 	data->res = DEFINE_RES_IRQ(0);
 
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index f7ceec2b4477..72065715feee 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -536,6 +536,8 @@ struct i3c_master_controller_ops {
  *		 Bit 0: SETDASA
  *		 Bit 1: SETAASA
  *		 All other bits are reserved.
+ * @instance: Zero-based instance number of the Bus Controller as defined by the
+ *            DisCo specification I3C Target Address (_ADR) Encoding
  * @wq: freezable workqueue which can be used by master
  *	drivers if they need to postpone operations that need to take place
  *	in a thread context. Typical examples are Hot Join processing which
@@ -573,6 +575,7 @@ struct i3c_master_controller {
 	} boardinfo;
 	struct i3c_bus bus;
 	u8 addr_method;
+	u8 instance;
 	struct workqueue_struct *wq;
 	struct work_struct hj_work;
 	struct work_struct reg_work;
diff --git a/include/linux/platform_data/mipi-i3c-hci.h b/include/linux/platform_data/mipi-i3c-hci.h
index ab7395f455f9..6f61d8a02378 100644
--- a/include/linux/platform_data/mipi-i3c-hci.h
+++ b/include/linux/platform_data/mipi-i3c-hci.h
@@ -3,13 +3,17 @@
 #define INCLUDE_PLATFORM_DATA_MIPI_I3C_HCI_H
 
 #include <linux/compiler_types.h>
+#include <linux/types.h>
 
 /**
  * struct mipi_i3c_hci_platform_data - Platform-dependent data for mipi_i3c_hci
  * @base_regs: Register set base address (to support multi-bus instances)
+ * @instance: Zero-based instance number of the Bus Controller as defined by the
+ *            DisCo specification I3C Target Address (_ADR) Encoding
  */
 struct mipi_i3c_hci_platform_data {
 	void __iomem *base_regs;
+	u8 instance;
 };
 
 #endif
-- 
2.53.0


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

* [PATCH 05/17] i3c: master: Remove stale GETSTATUS length check
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (3 preceding siblings ...)
  2026-09-14 11:29 ` [PATCH 04/17] i3c: master: Match ACPI targets to the correct bus controller instance Adrian Hunter
@ 2026-09-14 11:29 ` Adrian Hunter
  2026-09-14 16:23   ` Frank Li
  2026-09-14 11:29 ` [PATCH 06/17] i3c: mipi-i3c-hci: Fix i3c_hci_enable_ibi() error path Adrian Hunter
                   ` (11 subsequent siblings)
  16 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

i3c_master_getstatus_locked() verifies dest.payload.len against
sizeof(*getstatus) after issuing a GETSTATUS CCC.

This check predates the introduction of dest.payload.actual_len. Since
then, dest.payload.len has held the requested transfer length and
dest.payload.actual_len has held the received length, so the check is
always false and can never detect a short response.

It also predates the addition of generic read CCC response length
validation in i3c_master_send_ccc_cmd_locked(), which now performs the
necessary check before returning success.

Remove the stale check.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master.c | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 215a22f2c7b6..4296c51a9537 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -1777,11 +1777,6 @@ static int i3c_master_getstatus_locked(struct i3c_master_controller *master,
 	if (ret)
 		goto out;
 
-	if (dest.payload.len != sizeof(*getstatus)) {
-		ret = -EIO;
-		goto out;
-	}
-
 	if (status)
 		*status = be16_to_cpu(getstatus->status);
 out:
-- 
2.53.0


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

* [PATCH 06/17] i3c: mipi-i3c-hci: Fix i3c_hci_enable_ibi() error path
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (4 preceding siblings ...)
  2026-09-14 11:29 ` [PATCH 05/17] i3c: master: Remove stale GETSTATUS length check Adrian Hunter
@ 2026-09-14 11:29 ` Adrian Hunter
  2026-09-14 16:27   ` Frank Li
  2026-09-14 11:29 ` [PATCH 07/17] i3c: mipi-i3c-hci: Send DISEC before disabling IBIs in hardware Adrian Hunter
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

i3c_hci_enable_ibi() performs controller-side setup before sending the
ENEC CCC to enable IBIs on the target.  If the ENEC CCC fails, the
function returns an error but leaves the controller configured as if IBI
enabling had succeeded.

Fix the error path by undoing the earlier setup when the ENEC CCC fails,
ensuring the controller state remains consistent with the failed enable
operation.

Fixes: 9ad9a52cce282 ("i3c/master: introduce the mipi-i3c-hci driver")
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/core.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 8b3a87d8a8bb..166d9f70f435 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -703,11 +703,15 @@ static int i3c_hci_enable_ibi(struct i3c_dev_desc *dev)
 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
 	struct i3c_hci *hci = to_i3c_hci(m);
 	struct i3c_hci_dev_data *dev_data = i3c_dev_get_master_data(dev);
+	int ret;
 
 	mipi_i3c_hci_dat_v1.clear_flags(hci, dev_data->dat_idx, DAT_0_SIR_REJECT, 0);
 	scoped_guard(spinlock_irqsave, &hci->lock)
 		hci->ibi_devs[dev_data->dat_idx] = dev;
-	return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
+	ret = i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
+	if (ret)
+		__i3c_hci_disable_ibi(hci, dev);
+	return ret;
 }
 
 static int i3c_hci_disable_ibi(struct i3c_dev_desc *dev)
-- 
2.53.0


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

* [PATCH 07/17] i3c: mipi-i3c-hci: Send DISEC before disabling IBIs in hardware
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (5 preceding siblings ...)
  2026-09-14 11:29 ` [PATCH 06/17] i3c: mipi-i3c-hci: Fix i3c_hci_enable_ibi() error path Adrian Hunter
@ 2026-09-14 11:29 ` Adrian Hunter
  2026-09-14 16:29   ` Frank Li
  2026-09-14 11:29 ` [PATCH 08/17] i3c: mipi-i3c-hci: Fix runtime PM violation in i3c_hci_free_ibi() Adrian Hunter
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

Reorder i3c_hci_disable_ibi() so that DISEC is sent before IBIs are
disabled at the controller.

This matches the sequence used by other I3C controller drivers.  It also
avoids dropping an IBI that races with the disable operation: an IBI
received after DISEC is issued but before the controller disables IBIs
can still be processed normally.  Once DISEC has been sent, the hardware
can be updated to NACK subsequent IBIs and complete the teardown.

No functional change is intended beyond aligning the ordering with other
drivers and handling the race window consistently.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/core.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 166d9f70f435..f6a34ce7a295 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -719,13 +719,14 @@ static int i3c_hci_disable_ibi(struct i3c_dev_desc *dev)
 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
 	struct i3c_hci *hci = to_i3c_hci(m);
 
-	__i3c_hci_disable_ibi(hci, dev);
 	/*
-	 * The DAT entry is now set to NACK and DISEC this target's IBIs, so
+	 * The DAT entry will be set to NACK and DISEC this target's IBIs, so
 	 * the IBI teardown can proceed even if DISEC below fails, so ignore
 	 * errors.
 	 */
 	i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
+
+	__i3c_hci_disable_ibi(hci, dev);
 	return 0;
 }
 
-- 
2.53.0


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

* [PATCH 08/17] i3c: mipi-i3c-hci: Fix runtime PM violation in i3c_hci_free_ibi()
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (6 preceding siblings ...)
  2026-09-14 11:29 ` [PATCH 07/17] i3c: mipi-i3c-hci: Send DISEC before disabling IBIs in hardware Adrian Hunter
@ 2026-09-14 11:29 ` Adrian Hunter
  2026-09-14 11:29 ` [PATCH 09/17] i3c: mipi-i3c-hci: Process multiple IBIs per interrupt Adrian Hunter
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

i3c_hci_free_ibi() calls __i3c_hci_disable_ibi(), but the latter
requires runtime PM to be resumed.  The ->free_ibi() callback does not
guarantee that condition.

The cases where ->free_ibi() may be called without a preceding
->disable_ibi() do not require re-enabling runtime PM handling:

- runtime resume failed in i3c_dev_free_ibi_locked(), so it skips the
  IBI disable but still proceeds to call ->free_ibi()
- the device has been re-enumerated under a new dynamic address in
  __i3c_master_add_i3c_dev_locked(), which tears down the old device
  descriptor and deliberately clears olddev->ibi->enabled (to avoid
  sending a DISEC to the stale old address) before calling
  i3c_dev_free_ibi_locked().  As a result ->free_ibi() is reached with
  neither a hardware IBI disable nor runtime PM resumed.

In both cases the important requirement is to prevent further IBI
processing for the device.  That can be done without accessing hardware
by removing the device from the ibi_devs[] table.

Replace the call to __i3c_hci_disable_ibi() with clearing the
corresponding ibi_devs[] entry under the controller lock.

Fixes: 650716f23eac4 ("i3c: mipi-i3c-hci: Fix race in i3c_hci_addr_to_dev()")
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/core.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index f6a34ce7a295..b9b20797d045 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -675,11 +675,13 @@ static void __i3c_hci_disable_ibi(struct i3c_hci *hci, struct i3c_dev_desc *dev)
 
 static void i3c_hci_free_ibi(struct i3c_dev_desc *dev)
 {
+	struct i3c_hci_dev_data *dev_data = i3c_dev_get_master_data(dev);
 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
 	struct i3c_hci *hci = to_i3c_hci(m);
 
-	/* Must ensure the IBI has been disabled */
-	__i3c_hci_disable_ibi(hci, dev);
+	/* Must ensure IBIs for this device will no longer be processed */
+	scoped_guard(spinlock_irqsave, &hci->lock)
+		hci->ibi_devs[dev_data->dat_idx] = NULL;
 	hci->io->free_ibi(hci, dev);
 }
 
-- 
2.53.0


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

* [PATCH 09/17] i3c: mipi-i3c-hci: Process multiple IBIs per interrupt
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (7 preceding siblings ...)
  2026-09-14 11:29 ` [PATCH 08/17] i3c: mipi-i3c-hci: Fix runtime PM violation in i3c_hci_free_ibi() Adrian Hunter
@ 2026-09-14 11:29 ` Adrian Hunter
  2026-09-14 16:45   ` Frank Li
  2026-09-14 11:29 ` [PATCH 10/17] i3c: mipi-i3c-hci: Move DMA suspend/resume callbacks Adrian Hunter
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

INTR_IBI_READY indicates that one or more IBI Status Descriptors are
present in the IBI ring.  After clearing interrupt status, the interrupt
handler processes only a single IBI even though additional IBIs may
already be queued.

The controller does not reassert INTR_IBI_READY solely because entries
remain in the ring after interrupt status has been cleared.  Consequently,
the remaining IBIs are not processed until some later interrupt occurs,
and can accumulate if IBIs arrive more often than the interrupt handler
runs.

Process all IBIs that are pending when the handler runs: capture the IBI
enqueue pointer up front and continue until the dequeue pointer reaches
that position.

Fixes: 9ad9a52cce28 ("i3c/master: introduce the mipi-i3c-hci driver")
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/dma.c | 39 +++++++++++++++++----------
 1 file changed, 25 insertions(+), 14 deletions(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
index 5b195978f376..a798b0648922 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
@@ -868,25 +868,24 @@ static void hci_dma_recycle_ibi_slot(struct i3c_hci *hci,
 	i3c_generic_ibi_recycle_slot(dev_ibi->pool, slot);
 }
 
-static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
+static bool hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh,
+				u32 *op1_val, unsigned int enq_ptr)
 {
 	struct hci_rings_data *rings = hci->io_data;
 	struct i3c_dev_desc *dev;
 	struct i3c_hci_dev_data *dev_data;
 	struct hci_dma_dev_ibi_data *dev_ibi;
 	struct i3c_ibi_slot *slot;
-	u32 op1_val, op2_val, ibi_status_error;
-	unsigned int ptr, enq_ptr, deq_ptr;
+	u32 ibi_status_error;
+	unsigned int ptr, deq_ptr;
 	unsigned int ibi_size, ibi_chunks, ibi_data_offset, first_part;
 	int ibi_addr, last_ptr;
 	void *ring_ibi_data;
 	dma_addr_t ring_ibi_data_dma;
 
-	op1_val = rh_reg_read(RING_OPERATION1);
-	deq_ptr = FIELD_GET(RING_OP1_IBI_DEQ_PTR, op1_val);
-
-	op2_val = rh_reg_read(RING_OPERATION2);
-	enq_ptr = FIELD_GET(RING_OP2_IBI_ENQ_PTR, op2_val);
+	deq_ptr = FIELD_GET(RING_OP1_IBI_DEQ_PTR, *op1_val);
+	if (deq_ptr == enq_ptr)
+		return false;
 
 	ibi_status_error = 0;
 	ibi_addr = -1;
@@ -936,7 +935,7 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
 		dev_dbg(&hci->master.dev,
 			"no LAST_STATUS available (e=%d d=%d)",
 			enq_ptr, deq_ptr);
-		return;
+		return false;
 	}
 	deq_ptr = last_ptr + 1;
 	deq_ptr %= rh->ibi_status_entries;
@@ -1015,10 +1014,9 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
 	i3c_master_queue_ibi(dev, slot);
 
 done:
-	op1_val = rh_reg_read(RING_OPERATION1);
-	op1_val &= ~RING_OP1_IBI_DEQ_PTR;
-	op1_val |= FIELD_PREP(RING_OP1_IBI_DEQ_PTR, deq_ptr);
-	rh_reg_write(RING_OPERATION1, op1_val);
+	*op1_val &= ~RING_OP1_IBI_DEQ_PTR;
+	*op1_val |= FIELD_PREP(RING_OP1_IBI_DEQ_PTR, deq_ptr);
+	rh_reg_write(RING_OPERATION1, *op1_val);
 
 	/* update the chunk pointer */
 	rh->ibi_chunk_ptr += ibi_chunks;
@@ -1026,6 +1024,19 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
 
 	/* and tell the hardware about freed chunks */
 	rh_reg_write(CHUNK_CONTROL, rh_reg_read(CHUNK_CONTROL) + ibi_chunks);
+
+	return true;
+}
+
+static void hci_dma_drain_ibi_ring(struct i3c_hci *hci, struct hci_rh_data *rh)
+{
+	u32 op1_val = rh_reg_read(RING_OPERATION1);
+	u32 op2_val = rh_reg_read(RING_OPERATION2);
+	unsigned int enq_ptr = FIELD_GET(RING_OP2_IBI_ENQ_PTR, op2_val);
+
+	/* Loop is bounded by enq_ptr. Further IBIs will re-assert INTR_IBI_READY */
+	while (hci_dma_process_ibi(hci, rh, &op1_val, enq_ptr))
+		;
 }
 
 static bool hci_dma_irq_handler(struct i3c_hci *hci)
@@ -1047,7 +1058,7 @@ static bool hci_dma_irq_handler(struct i3c_hci *hci)
 		rh_reg_write(INTR_STATUS, status);
 
 		if (status & INTR_IBI_READY)
-			hci_dma_process_ibi(hci, rh);
+			hci_dma_drain_ibi_ring(hci, rh);
 		if (status & (INTR_TRANSFER_COMPLETION | INTR_TRANSFER_ERR))
 			hci_dma_xfer_done(hci, rh);
 		if (status & INTR_RING_OP)
-- 
2.53.0


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

* [PATCH 10/17] i3c: mipi-i3c-hci: Move DMA suspend/resume callbacks
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (8 preceding siblings ...)
  2026-09-14 11:29 ` [PATCH 09/17] i3c: mipi-i3c-hci: Process multiple IBIs per interrupt Adrian Hunter
@ 2026-09-14 11:29 ` Adrian Hunter
  2026-09-14 16:46   ` Frank Li
  2026-09-14 11:29 ` [PATCH 11/17] i3c: mipi-i3c-hci: Stop rings gracefully when suspending Adrian Hunter
                   ` (6 subsequent siblings)
  16 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

Relocate hci_dma_suspend() and hci_dma_resume() closer to the DMA IO
operations table in preparation for upcoming changes.

No functional change.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/dma.c | 46 +++++++++++++--------------
 1 file changed, 23 insertions(+), 23 deletions(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
index a798b0648922..ec4b469abd33 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
@@ -273,29 +273,6 @@ static void hci_dma_init_rings(struct i3c_hci *hci)
 		hci_dma_init_rh(hci, &rings->headers[i], i);
 }
 
-static void hci_dma_suspend(struct i3c_hci *hci)
-{
-	struct hci_rings_data *rings = hci->io_data;
-	int n = rings ? rings->total : 0;
-
-	for (int i = 0; i < n; i++) {
-		struct hci_rh_data *rh = &rings->headers[i];
-
-		rh_reg_write(INTR_SIGNAL_ENABLE, 0);
-		rh_reg_write(RING_CONTROL, 0);
-	}
-
-	i3c_hci_sync_irq_inactive(hci);
-}
-
-static void hci_dma_resume(struct i3c_hci *hci)
-{
-	struct hci_rings_data *rings = hci->io_data;
-
-	if (rings)
-		hci_dma_init_rings(hci);
-}
-
 static int hci_dma_init(struct i3c_hci *hci)
 {
 	struct hci_rings_data *rings;
@@ -1075,6 +1052,29 @@ static bool hci_dma_irq_handler(struct i3c_hci *hci)
 	return handled;
 }
 
+static void hci_dma_suspend(struct i3c_hci *hci)
+{
+	struct hci_rings_data *rings = hci->io_data;
+	int n = rings ? rings->total : 0;
+
+	for (int i = 0; i < n; i++) {
+		struct hci_rh_data *rh = &rings->headers[i];
+
+		rh_reg_write(INTR_SIGNAL_ENABLE, 0);
+		rh_reg_write(RING_CONTROL, 0);
+	}
+
+	i3c_hci_sync_irq_inactive(hci);
+}
+
+static void hci_dma_resume(struct i3c_hci *hci)
+{
+	struct hci_rings_data *rings = hci->io_data;
+
+	if (rings)
+		hci_dma_init_rings(hci);
+}
+
 const struct hci_io_ops mipi_i3c_hci_dma = {
 	.init			= hci_dma_init,
 	.cleanup		= hci_dma_cleanup,
-- 
2.53.0


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

* [PATCH 11/17] i3c: mipi-i3c-hci: Stop rings gracefully when suspending
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (9 preceding siblings ...)
  2026-09-14 11:29 ` [PATCH 10/17] i3c: mipi-i3c-hci: Move DMA suspend/resume callbacks Adrian Hunter
@ 2026-09-14 11:29 ` Adrian Hunter
  2026-09-14 16:51   ` Frank Li
  2026-09-14 11:29 ` [PATCH 12/17] i3c: mipi-i3c-hci: Fix Response Descriptor DATA_LENGTH mask Adrian Hunter
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

hci_dma_suspend() tore the rings down with a single write of zero to
RH_RING_CONTROL, clearing the RS and ENABLE fields together and without
waiting for the ring to stop.  I3C HCI v1.1 section 6.1.2 separates those
steps: clear RS for all running Ring Bundles, and only then clear ENABLE
for all enabled Ring Bundles.

The ring registers were also written outside hci->lock, while the
interrupt handler, which takes that lock, could still be running on
another CPU.  i3c_hci_sync_irq_inactive() was called only afterwards.

Finally, an IBI can still be sitting in the IBI Status Ring when suspend
runs.  Clearing HC_CONTROL.BUS_ENABLE is deferred: per the description of
that field, if a disable request occurs while receiving an IBI, the
actual disabling does not occur until reception of the IBI is complete.

Instead, clear RS under hci->lock, wait for RING_STATUS_RUNNING to clear,
and make the interrupt handler inactive.  Only then disable the ring
interrupt signals, drain anything left in the IBI ring, and clear ENABLE.

Fixes: 816958720443 ("i3c: mipi-i3c-hci: Add DMA suspend and resume support")
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/dma.c | 46 ++++++++++++++++++++++++---
 1 file changed, 42 insertions(+), 4 deletions(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
index ec4b469abd33..9c163ee4d215 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
@@ -15,6 +15,7 @@
 #include <linux/errno.h>
 #include <linux/i3c/master.h>
 #include <linux/io.h>
+#include <linux/iopoll.h>
 
 #include "hci.h"
 #include "cmd.h"
@@ -1052,19 +1053,56 @@ static bool hci_dma_irq_handler(struct i3c_hci *hci)
 	return handled;
 }
 
+#define RING_STOP_TIMEOUT_US	(100 * USEC_PER_MSEC)
+#define RING_STOP_SLEEP_US	100
+
 static void hci_dma_suspend(struct i3c_hci *hci)
 {
 	struct hci_rings_data *rings = hci->io_data;
 	int n = rings ? rings->total : 0;
+	struct hci_rh_data *rh;
+	u32 regval;
 
-	for (int i = 0; i < n; i++) {
-		struct hci_rh_data *rh = &rings->headers[i];
+	/* Gracefully stop the rings */
+	scoped_guard(spinlock_irqsave, &hci->lock) {
+		for (int i = 0; i < n; i++) {
+			rh = &rings->headers[i];
+			regval = rh_reg_read(RING_CONTROL);
+			if (regval & RING_CTRL_RUN_STOP)
+				rh_reg_write(RING_CONTROL, regval & ~RING_CTRL_RUN_STOP);
+		}
+	}
 
-		rh_reg_write(INTR_SIGNAL_ENABLE, 0);
-		rh_reg_write(RING_CONTROL, 0);
+	/* Wait for actual stop */
+	for (int i = 0; i < n; i++) {
+		rh = &rings->headers[i];
+		if (readx_poll_timeout(readl, rh->regs + RH_RING_STATUS, regval,
+				       !(regval & RING_STATUS_RUNNING),
+				       RING_STOP_SLEEP_US, RING_STOP_TIMEOUT_US))
+			dev_err(&hci->master.dev, "%s: Ring did not stop, status %#x\n",
+				__func__, regval);
 	}
 
+	/*
+	 * With the rings stopped, no more IBIs can be received. Flush and make
+	 * the interrupt handler inactive.
+	 */
 	i3c_hci_sync_irq_inactive(hci);
+
+	/* Disable interrupt signals and disable the rings */
+	scoped_guard(spinlock_irqsave, &hci->lock)
+		for (int i = 0; i < n; i++) {
+			rh = &rings->headers[i];
+			rh_reg_write(INTR_SIGNAL_ENABLE, 0);
+			/*
+			 * Be absolutely certain there is no unprocessed IBI.
+			 * hci_dma_drain_ibi_ring() will do nothing if there is
+			 * none.
+			 */
+			if (i < IBI_RINGS)
+				hci_dma_drain_ibi_ring(hci, rh);
+			rh_reg_write(RING_CONTROL, 0);
+		}
 }
 
 static void hci_dma_resume(struct i3c_hci *hci)
-- 
2.53.0


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

* [PATCH 12/17] i3c: mipi-i3c-hci: Fix Response Descriptor DATA_LENGTH mask
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (10 preceding siblings ...)
  2026-09-14 11:29 ` [PATCH 11/17] i3c: mipi-i3c-hci: Stop rings gracefully when suspending Adrian Hunter
@ 2026-09-14 11:29 ` Adrian Hunter
  2026-09-14 16:55   ` Frank Li
  2026-09-14 11:29 ` [PATCH 13/17] i3c: mipi-i3c-hci: Remove invalid transfer size limit Adrian Hunter
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

The I3C HCI Response Descriptor defines DATA_LENGTH in Bits[15:0],
with Bits[23:16] reserved in all published HCI specification versions:
v1.0 (Table 91) and v1.1/v1.2 (Section 8.5). However,
RESP_DATA_LENGTH extracts Bits[21:0], incorrectly including six
reserved bits.

Update the mask to match the defined field width.

No functional change is expected because compliant controllers return
zero in reserved fields.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/cmd.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd.h b/drivers/i3c/master/mipi-i3c-hci/cmd.h
index 7bada7b4b2de..e0d4a6e0e319 100644
--- a/drivers/i3c/master/mipi-i3c-hci/cmd.h
+++ b/drivers/i3c/master/mipi-i3c-hci/cmd.h
@@ -24,7 +24,7 @@
  */
 #define RESP_STATUS(resp)		FIELD_GET(GENMASK(31, 28), resp)
 #define RESP_TID(resp)			FIELD_GET(GENMASK(27, 24), resp)
-#define RESP_DATA_LENGTH(resp)		FIELD_GET(GENMASK(21,  0), resp)
+#define RESP_DATA_LENGTH(resp)		FIELD_GET(GENMASK(15,  0), resp)
 
 #define RESP_ERR_FIELD			GENMASK(31, 28)
 
-- 
2.53.0


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

* [PATCH 13/17] i3c: mipi-i3c-hci: Remove invalid transfer size limit
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (11 preceding siblings ...)
  2026-09-14 11:29 ` [PATCH 12/17] i3c: mipi-i3c-hci: Fix Response Descriptor DATA_LENGTH mask Adrian Hunter
@ 2026-09-14 11:29 ` Adrian Hunter
  2026-09-14 16:58   ` Frank Li
  2026-09-14 11:30 ` [PATCH 14/17] i3c: mipi-i3c-hci: Remove invalid HDR-BT and Fm/Fm+ definitions Adrian Hunter
                   ` (3 subsequent siblings)
  16 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:29 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

The driver derives a maximum transfer size from
HC_CAP_MAX_DATA_LENGTH in HC_CAPABILITIES, but no published version of
the I3C HCI specification defines such a field.

HC_CAPABILITIES reserves Bits[31:8] in HCI v1.0 and Bits[27:22] in HCI
v1.1 and v1.2, so the bits used by HC_CAP_MAX_DATA_LENGTH are reserved
in all released HCI versions.  Neither the HCI nor the I3C TCRI
specifications define a maximum data length capability.

On compliant controllers reserved bits read as zero, making the
computed limit 65536 bytes.  Since struct i3c_xfer.len is u16,
transfers can never reach that size and the resulting -EFBIG check can
never trigger.

Remove the unused capability definition and the dead size check.

The driver's effective limit remains unchanged. HCI specifications
define DATA_LENGTH as a 16-bit field and require larger transfers to be
split across multiple Transfer Descriptors.  The driver already relies
on the core's 16-bit length types elsewhere when constructing
descriptors.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/core.c | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index b9b20797d045..4629a16debc9 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -51,7 +51,6 @@
 #define HC_CAP_SG_DC_EN			BIT(30)
 #define HC_CAP_SG_IBI_EN		BIT(29)
 #define HC_CAP_SG_CR_EN			BIT(28)
-#define HC_CAP_MAX_DATA_LENGTH		GENMASK(24, 22)
 #define HC_CAP_CMD_SIZE			GENMASK(21, 20)
 #define HC_CAP_DIRECT_COMMANDS_EN	BIT(18)
 #define HC_CAP_MULTI_LANE_EN		BIT(15)
@@ -473,7 +472,6 @@ static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
 	struct i3c_hci *hci = to_i3c_hci(m);
 	struct hci_xfer *xfer;
 	DECLARE_COMPLETION_ONSTACK(done);
-	unsigned int size_limit;
 	int i, last, ret = 0;
 
 	dev_dbg(&hci->master.dev, "nxfers = %d", nxfers);
@@ -482,13 +480,8 @@ static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
 	if (!xfer)
 		return -ENOMEM;
 
-	size_limit = 1U << (16 + FIELD_GET(HC_CAP_MAX_DATA_LENGTH, hci->caps));
-
 	for (i = 0; i < nxfers; i++) {
 		xfer[i].data_len = i3c_xfers[i].len;
-		ret = -EFBIG;
-		if (xfer[i].data_len >= size_limit)
-			goto out;
 		xfer[i].rnw = i3c_xfers[i].rnw;
 		if (i3c_xfers[i].rnw) {
 			xfer[i].data = i3c_xfers[i].data.in;
-- 
2.53.0


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

* [PATCH 14/17] i3c: mipi-i3c-hci: Remove invalid HDR-BT and Fm/Fm+ definitions
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (12 preceding siblings ...)
  2026-09-14 11:29 ` [PATCH 13/17] i3c: mipi-i3c-hci: Remove invalid transfer size limit Adrian Hunter
@ 2026-09-14 11:30 ` Adrian Hunter
  2026-09-14 17:00   ` Frank Li
  2026-09-14 11:30 ` [PATCH 15/17] i3c: mipi-i3c-hci: Support configurable device NACK retries Adrian Hunter
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:30 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

Several HCI definitions describe capabilities or modes that are not
defined by any released version of the I3C HCI specification.

HC_CAP_HDR_BT_EN uses a reserved HC_CAPABILITIES bit. Similarly,
MODE_I3C_HDR_BT uses a MODE value reserved for I3C transfers, while
MODE_I3C_Fm_FmP cannot be encoded in the 3-bit Command Descriptor MODE
field.

These definitions are currently unused, so there is no functional
change.  Remove them to avoid implying support for non-existent HCI
features and to prevent future misuse.

Assisted-by: GitHub-Copilot:claude-opus-5
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/cmd_v1.c | 2 --
 drivers/i3c/master/mipi-i3c-hci/core.c   | 1 -
 2 files changed, 3 deletions(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
index 3b9345718d27..9910df53c013 100644
--- a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
+++ b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
@@ -108,8 +108,6 @@ enum hci_cmd_mode {
 	MODE_I3C_SDR4		= 0x4,
 	MODE_I3C_HDR_TSx	= 0x5,
 	MODE_I3C_HDR_DDR	= 0x6,
-	MODE_I3C_HDR_BT		= 0x7,
-	MODE_I3C_Fm_FmP		= 0x8,
 	MODE_I2C_Fm		= 0x0,
 	MODE_I2C_FmP		= 0x1,
 	MODE_I2C_UD1		= 0x2,
diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 4629a16debc9..7a39be64c4e1 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -55,7 +55,6 @@
 #define HC_CAP_DIRECT_COMMANDS_EN	BIT(18)
 #define HC_CAP_MULTI_LANE_EN		BIT(15)
 #define HC_CAP_CMD_CCC_DEFBYTE		BIT(10)
-#define HC_CAP_HDR_BT_EN		BIT(8)
 #define HC_CAP_HDR_TS_EN		BIT(7)
 #define HC_CAP_HDR_DDR_EN		BIT(6)
 #define HC_CAP_NON_CURRENT_MASTER_CAP	BIT(5)	/* master handoff capable */
-- 
2.53.0


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

* [PATCH 15/17] i3c: mipi-i3c-hci: Support configurable device NACK retries
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (13 preceding siblings ...)
  2026-09-14 11:30 ` [PATCH 14/17] i3c: mipi-i3c-hci: Remove invalid HDR-BT and Fm/Fm+ definitions Adrian Hunter
@ 2026-09-14 11:30 ` Adrian Hunter
  2026-09-14 11:30 ` [PATCH 16/17] i3c: Restrict HDR modes to those supported by the bus and target Adrian Hunter
  2026-09-14 11:30 ` [PATCH 17/17] i3c: mipi-i3c-hci: Add HDR-DDR support Adrian Hunter
  16 siblings, 0 replies; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:30 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

Implement the .set_dev_nack_retry() master operation using the
DAT_0_DEV_NACK_RETRY_CNT field in Device Address Table entries.

Since the retry count is programmed per DAT entry, update all allocated
entries when the setting changes and initialize newly allocated entries
with the current value so that a consistent retry policy is applied
across all devices.

Add DAT helper operations to update individual entries and all allocated
entries.  Return -ERANGE if the requested retry count exceeds the
hardware field width and -EOPNOTSUPP when the active command descriptor
model does not use DAT entries.

In addition, default the retry count to 1.  The I3C specification
mandates a retry when a Target NACKs its Dynamic Address.  HCI v1.1
explicitly preserves that behaviour for Direct CCCs even when
DEV_NACK_RETRY_CNT is programmed to 0, but HCI v1.0 defines the field
only as a device-specific retry count and does not provide the same
exception.  As a result, a v1.0 controller left at the reset value of 0
may perform no retry whereas a v1.1 controller will retry once.
Promoting 0 to 1 at probe time makes the behaviour consistent across
controller versions.  Userspace can still select 0 retries explicitly
via dev_nack_retry_count.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/core.c   | 25 ++++++++++++++++++++++++
 drivers/i3c/master/mipi-i3c-hci/dat.h    |  2 ++
 drivers/i3c/master/mipi-i3c-hci/dat_v1.c | 25 ++++++++++++++++++++++++
 3 files changed, 52 insertions(+)

diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 7a39be64c4e1..57d84d7682d7 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -555,6 +555,11 @@ static int i3c_hci_i2c_xfers(struct i2c_dev_desc *dev,
 	return ret;
 }
 
+static void i3c_hci_dat_v1_set_curr_nack_retry(struct i3c_hci *hci, unsigned int dat_idx)
+{
+	mipi_i3c_hci_dat_v1.set_nack_retry(hci, dat_idx, hci->master.dev_nack_retry_count);
+}
+
 static int i3c_hci_attach_i3c_dev(struct i3c_dev_desc *dev)
 {
 	struct i3c_master_controller *m = i3c_dev_get_master(dev);
@@ -573,6 +578,7 @@ static int i3c_hci_attach_i3c_dev(struct i3c_dev_desc *dev)
 		}
 		mipi_i3c_hci_dat_v1.set_dynamic_addr(hci, ret,
 						     dev->info.dyn_addr ?: dev->info.static_addr);
+		i3c_hci_dat_v1_set_curr_nack_retry(hci, ret);
 		dev_data->dat_idx = ret;
 	}
 	i3c_dev_set_master_data(dev, dev_data);
@@ -622,6 +628,7 @@ static int i3c_hci_attach_i2c_dev(struct i2c_dev_desc *dev)
 	}
 	mipi_i3c_hci_dat_v1.set_static_addr(hci, ret, dev->addr);
 	mipi_i3c_hci_dat_v1.set_flags(hci, ret, DAT_0_I2C_DEVICE, 0);
+	i3c_hci_dat_v1_set_curr_nack_retry(hci, ret);
 	dev_data->dat_idx = ret;
 	i2c_dev_set_master_data(dev, dev_data);
 	return 0;
@@ -733,6 +740,16 @@ static void i3c_hci_recycle_ibi_slot(struct i3c_dev_desc *dev,
 	hci->io->recycle_ibi_slot(hci, dev, slot);
 }
 
+static int i3c_hci_set_dev_nack_retry(struct i3c_master_controller *m, unsigned int cnt)
+{
+	struct i3c_hci *hci = to_i3c_hci(m);
+
+	if (hci->cmd != &mipi_i3c_hci_cmd_v1)
+		return -EOPNOTSUPP;
+
+	return mipi_i3c_hci_dat_v1.set_all_nack_retry(hci, cnt);
+}
+
 static const struct i3c_master_controller_ops i3c_hci_ops = {
 	.bus_init		= i3c_hci_bus_init,
 	.bus_cleanup		= i3c_hci_bus_cleanup,
@@ -752,6 +769,7 @@ static const struct i3c_master_controller_ops i3c_hci_ops = {
 	.recycle_ibi_slot	= i3c_hci_recycle_ibi_slot,
 	.enable_hotjoin		= i3c_hci_enable_hotjoin,
 	.disable_hotjoin	= i3c_hci_disable_hotjoin,
+	.set_dev_nack_retry	= i3c_hci_set_dev_nack_retry,
 };
 
 static irqreturn_t i3c_hci_irq_handler(int irq, void *dev_id)
@@ -1186,6 +1204,13 @@ static int i3c_hci_probe(struct platform_device *pdev)
 	if (device_can_wakeup(i3c_hci_sysdev(&pdev->dev)))
 		hci->master.ibi_wakeup = true;
 
+	/*
+	 * HCI v1.1 onward does 1 retry for Direct CCCs anyway, so for v1.0 to
+	 * be consistent, promote 0 to 1.
+	 */
+	if (!hci->master.dev_nack_retry_count)
+		hci->master.dev_nack_retry_count = 1;
+
 	return i3c_master_register(&hci->master, &pdev->dev, &i3c_hci_ops, false);
 }
 
diff --git a/drivers/i3c/master/mipi-i3c-hci/dat.h b/drivers/i3c/master/mipi-i3c-hci/dat.h
index 6881f19da77f..a07086bf717a 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dat.h
+++ b/drivers/i3c/master/mipi-i3c-hci/dat.h
@@ -25,6 +25,8 @@ struct hci_dat_ops {
 	void (*clear_flags)(struct i3c_hci *hci, unsigned int dat_idx, u32 w0, u32 w1);
 	int (*get_index)(struct i3c_hci *hci, u8 address);
 	void (*restore)(struct i3c_hci *hci);
+	void (*set_nack_retry)(struct i3c_hci *hci, unsigned int dat_idx, unsigned int cnt);
+	int (*set_all_nack_retry)(struct i3c_hci *hci, unsigned int cnt);
 };
 
 extern const struct hci_dat_ops mipi_i3c_hci_dat_v1;
diff --git a/drivers/i3c/master/mipi-i3c-hci/dat_v1.c b/drivers/i3c/master/mipi-i3c-hci/dat_v1.c
index 852966aa20d9..cb9aa43e69fb 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dat_v1.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dat_v1.c
@@ -189,6 +189,29 @@ static void hci_dat_v1_restore(struct i3c_hci *hci)
 	}
 }
 
+static void hci_dat_v1_set_nack_retry(struct i3c_hci *hci, unsigned int dat_idx, unsigned int cnt)
+{
+	u32 dat_w0;
+
+	dat_w0 = dat_w0_read(dat_idx);
+	dat_w0 &= ~DAT_0_DEV_NACK_RETRY_CNT;
+	dat_w0 |= FIELD_PREP(DAT_0_DEV_NACK_RETRY_CNT, cnt);
+	dat_w0_write(dat_idx, dat_w0);
+}
+
+static int hci_dat_v1_set_all_nack_retry(struct i3c_hci *hci, unsigned int cnt)
+{
+	unsigned int dat_idx;
+
+	if (cnt > FIELD_MAX(DAT_0_DEV_NACK_RETRY_CNT))
+		return -ERANGE;
+
+	for_each_set_bit(dat_idx, hci->DAT_data, hci->DAT_entries)
+		hci_dat_v1_set_nack_retry(hci, dat_idx, cnt);
+
+	return 0;
+}
+
 const struct hci_dat_ops mipi_i3c_hci_dat_v1 = {
 	.init			= hci_dat_v1_init,
 	.alloc_entry		= hci_dat_v1_alloc_entry,
@@ -199,4 +222,6 @@ const struct hci_dat_ops mipi_i3c_hci_dat_v1 = {
 	.clear_flags		= hci_dat_v1_clear_flags,
 	.get_index		= hci_dat_v1_get_index,
 	.restore		= hci_dat_v1_restore,
+	.set_nack_retry		= hci_dat_v1_set_nack_retry,
+	.set_all_nack_retry	= hci_dat_v1_set_all_nack_retry,
 };
-- 
2.53.0


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

* [PATCH 16/17] i3c: Restrict HDR modes to those supported by the bus and target
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (14 preceding siblings ...)
  2026-09-14 11:30 ` [PATCH 15/17] i3c: mipi-i3c-hci: Support configurable device NACK retries Adrian Hunter
@ 2026-09-14 11:30 ` Adrian Hunter
  2026-09-14 11:30 ` [PATCH 17/17] i3c: mipi-i3c-hci: Add HDR-DDR support Adrian Hunter
  16 siblings, 0 replies; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:30 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

I3C v1.1.1 Table 9 defines which HDR Modes are permitted for each Bus
Configuration.  A Mixed Slow / Limited Bus permits no HDR Modes because
Legacy I2C Devices without a 50 ns SCL spike filter cannot be shielded
from HDR traffic.  A Mixed Fast Bus permits HDR-DDR and HDR-TSL, but not
HDR-TSP, since of the two Ternary Modes only HDR-TSL is defined for a Bus
that also has Legacy I2C Devices.

However, both i3c_device_get_supported_xfer_mode() and the transfer
validation in i3c_dev_do_xfers_locked() currently consider only the
controller's hdr_cap.  Since hdr_cap reflects controller capability
rather than bus or target constraints, HDR Modes can be advertised and
used even when the bus configuration forbids them.  Likewise, HDR Modes
unsupported by the target may be reported as available.

Add i3c_dev_supported_xfer_modes_locked(), which derives the usable
transfer modes from the intersection of:

  - HDR Modes supported by the controller
  - HDR Modes allowed by the bus configuration
  - HDR Modes supported by the target

Use this helper both when reporting supported transfer modes and when
validating transfers, ensuring that the advertised and permitted modes
remain consistent.

GETHDRCAP is queried only when I3C_BCR_HDR_CAP is set, so a target
without that bit is treated as supporting no HDR Modes.

i3c_device_get_supported_xfer_mode() now takes the normal-use bus lock
in order to access the device descriptor, matching
i3c_device_get_info().

Also fix the kernel-doc reference to enum i3c_xfer_mode.

Fixes: 256a21743d91 ("i3c: Add HDR API support")
Assisted-by: GitHub-Copilot:claude-opus-5
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/device.c    | 15 ++++++++---
 drivers/i3c/internals.h |  2 ++
 drivers/i3c/master.c    | 57 ++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 69 insertions(+), 5 deletions(-)

diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
index f1ba363b22a1..4df4682af150 100644
--- a/drivers/i3c/device.c
+++ b/drivers/i3c/device.c
@@ -301,16 +301,23 @@ i3c_device_match_id(struct i3c_device *i3cdev,
 EXPORT_SYMBOL_GPL(i3c_device_match_id);
 
 /**
- * i3c_device_get_supported_xfer_mode - Returns the supported transfer mode by
- *					connected master controller.
+ * i3c_device_get_supported_xfer_mode - Returns the transfer modes supported by
+ *					the connected master controller and @dev,
+ *					and allowed by the bus configuration.
  * @dev: I3C device
  *
  * Return: a bit mask, which supported transfer mode, bit position is defined at
- *	   enum i3c_hdr_mode
+ *	   enum i3c_xfer_mode
  */
 u32 i3c_device_get_supported_xfer_mode(struct i3c_device *dev)
 {
-	return i3c_bus_to_i3c_master(dev->bus)->this->info.hdr_cap | BIT(I3C_SDR);
+	u32 modes;
+
+	i3c_bus_normaluse_lock(dev->bus);
+	modes = i3c_dev_supported_xfer_modes_locked(dev->desc);
+	i3c_bus_normaluse_unlock(dev->bus);
+
+	return modes;
 }
 EXPORT_SYMBOL_GPL(i3c_device_get_supported_xfer_mode);
 
diff --git a/drivers/i3c/internals.h b/drivers/i3c/internals.h
index 86a36b951e0d..9a6936e2c660 100644
--- a/drivers/i3c/internals.h
+++ b/drivers/i3c/internals.h
@@ -18,6 +18,8 @@ bool i3c_bus_rpm_ibi_allowed(struct i3c_bus *bus);
 void i3c_bus_normaluse_lock(struct i3c_bus *bus);
 void i3c_bus_normaluse_unlock(struct i3c_bus *bus);
 
+u32 i3c_dev_supported_xfer_modes_locked(struct i3c_dev_desc *dev);
+
 int i3c_dev_setdasa_locked(struct i3c_dev_desc *dev);
 int i3c_dev_do_xfers_locked(struct i3c_dev_desc *dev,
 			    struct i3c_xfer *xfers,
diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
index 4296c51a9537..c8093708807c 100644
--- a/drivers/i3c/master.c
+++ b/drivers/i3c/master.c
@@ -938,6 +938,61 @@ static int i3c_bus_set_mode(struct i3c_bus *i3cbus, enum i3c_bus_mode mode,
 	return 0;
 }
 
+/*
+ * I3C v1.1.1 Section 5.1.2.4 Table 9 lists the HDR Modes each Bus
+ * Configuration allows.  A Mixed Slow / Limited Bus has Legacy I2C Devices
+ * without a 50 ns spike filter, so there is no way to hide any HDR Mode from
+ * them.  Of the two Ternary Modes, only HDR-TSL is defined for a Bus that
+ * also has Legacy I2C Devices; HDR-TSP is defined for a Pure Bus.
+ */
+static u32 i3c_bus_hdr_modes(struct i3c_bus *bus)
+{
+	switch (bus->mode) {
+	case I3C_BUS_MODE_PURE:
+		return BIT(I3C_HDR_DDR) | BIT(I3C_HDR_TSP) | BIT(I3C_HDR_TSL);
+	case I3C_BUS_MODE_MIXED_FAST:
+		return BIT(I3C_HDR_DDR) | BIT(I3C_HDR_TSL);
+	case I3C_BUS_MODE_MIXED_LIMITED:
+	case I3C_BUS_MODE_MIXED_SLOW:
+		break;
+	}
+
+	return 0;
+}
+
+static u32 i3c_dev_hdr_modes(struct i3c_dev_desc *dev)
+{
+	if (!(dev->info.bcr & I3C_BCR_HDR_CAP))
+		return 0;
+
+	return dev->info.hdr_cap;
+}
+
+/**
+ * i3c_dev_supported_xfer_modes_locked() - Get the transfer modes usable with a
+ *					   device
+ * @dev: I3C device descriptor
+ *
+ * The HDR Modes the controller and @dev both support, restricted to those the
+ * bus configuration allows.  SDR is always supported.
+ *
+ * The bus lock must be held in normal use mode.
+ *
+ * Return: a bit mask of &enum i3c_xfer_mode values.
+ */
+u32 i3c_dev_supported_xfer_modes_locked(struct i3c_dev_desc *dev)
+{
+	struct i3c_master_controller *master = i3c_dev_get_master(dev);
+
+	/*
+	 * master->this->info.bcr is ignored because it describes the master's
+	 * target capability, not its controller capability.
+	 */
+	return (master->this->info.hdr_cap &
+		i3c_bus_hdr_modes(&master->bus) &
+		i3c_dev_hdr_modes(dev)) | BIT(I3C_SDR);
+}
+
 static struct i3c_master_controller *
 i2c_adapter_to_i3c_master(struct i2c_adapter *adap)
 {
@@ -3856,7 +3911,7 @@ int i3c_dev_do_xfers_locked(struct i3c_dev_desc *dev, struct i3c_xfer *xfers,
 	if (!master || !xfers)
 		return -EINVAL;
 
-	if (mode != I3C_SDR && !(master->this->info.hdr_cap & BIT(mode)))
+	if (mode != I3C_SDR && !(i3c_dev_supported_xfer_modes_locked(dev) & BIT(mode)))
 		return -EOPNOTSUPP;
 
 	return master->ops->i3c_xfers(dev, xfers, nxfers, mode);
-- 
2.53.0


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

* [PATCH 17/17] i3c: mipi-i3c-hci: Add HDR-DDR support
  2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
                   ` (15 preceding siblings ...)
  2026-09-14 11:30 ` [PATCH 16/17] i3c: Restrict HDR modes to those supported by the bus and target Adrian Hunter
@ 2026-09-14 11:30 ` Adrian Hunter
  16 siblings, 0 replies; 31+ messages in thread
From: Adrian Hunter @ 2026-09-14 11:30 UTC (permalink / raw)
  To: alexandre.belloni; +Cc: Frank.Li, billy_tsai, linux-i3c, linux-kernel

Add support for HDR-DDR private transfers.  Encode HDR-DDR Command
Descriptors and advertise HDR-DDR capability when supported by the
controller.

Carry the HDR Command Code in the descriptor CP, CMD and RNW fields.
Use the Immediate Data Transfer Command for writes of up to four bytes,
as is already done for SDR, and the Regular Data Transfer Command
otherwise.  The Immediate Data Transfer Command is write-only, which
suits HDR because the eighth bit of the HDR Command Code is field RNW,
so a write Command Code leaves that field zero as required.

Reject transfers shorter than one Data Word or with an odd byte count,
as HDR-DDR transfers are defined in whole Data Words and the I3C
specification requires at least one Data Word to follow the Command
Word.

Only advertise HDR-DDR capability when the driver can generate the
required descriptor format.

Assisted-by: GitHub-Copilot:claude-opus-5
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
---
 drivers/i3c/master/mipi-i3c-hci/cmd.h    |  2 +-
 drivers/i3c/master/mipi-i3c-hci/cmd_v1.c | 26 +++++++++++---
 drivers/i3c/master/mipi-i3c-hci/cmd_v2.c |  4 ++-
 drivers/i3c/master/mipi-i3c-hci/core.c   | 45 +++++++++++++++++++++---
 drivers/i3c/master/mipi-i3c-hci/hci.h    |  9 ++---
 include/linux/i3c/device.h               |  4 +++
 6 files changed, 76 insertions(+), 14 deletions(-)

diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd.h b/drivers/i3c/master/mipi-i3c-hci/cmd.h
index e0d4a6e0e319..fa3107df7c51 100644
--- a/drivers/i3c/master/mipi-i3c-hci/cmd.h
+++ b/drivers/i3c/master/mipi-i3c-hci/cmd.h
@@ -55,7 +55,7 @@ struct hci_cmd_ops {
 	int (*prep_ccc)(struct i3c_hci *hci, struct hci_xfer *xfer,
 			u8 ccc_addr, u8 ccc_cmd, bool raw);
 	void (*prep_i3c_xfer)(struct i3c_hci *hci, struct i3c_dev_desc *dev,
-			      struct hci_xfer *xfer);
+			      struct hci_xfer *xfer, enum i3c_xfer_mode mode);
 	void (*prep_i2c_xfer)(struct i3c_hci *hci, struct i2c_dev_desc *dev,
 			      struct hci_xfer *xfer);
 	int (*perform_daa)(struct i3c_hci *hci);
diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
index 9910df53c013..78ad2ec2bd93 100644
--- a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
+++ b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
@@ -215,14 +215,30 @@ static int hci_cmd_v1_prep_ccc(struct i3c_hci *hci,
 
 static void hci_cmd_v1_prep_i3c_xfer(struct i3c_hci *hci,
 				     struct i3c_dev_desc *dev,
-				     struct hci_xfer *xfer)
+				     struct hci_xfer *xfer,
+				     enum i3c_xfer_mode xfer_mode)
 {
 	struct i3c_hci_dev_data *dev_data = i3c_dev_get_master_data(dev);
 	unsigned int dat_idx = dev_data->dat_idx;
-	enum hci_cmd_mode mode = get_i3c_mode(hci);
+	enum hci_cmd_mode mode;
 	u8 *data = xfer->data;
 	unsigned int data_len = xfer->data_len;
 	bool rnw = xfer->rnw;
+	u32 cp_cmd = 0;
+
+	if (xfer_mode == I3C_SDR) {
+		mode = get_i3c_mode(hci);
+	} else {
+		/*
+		 * HDR-DDR is the only advertised HDR Mode, so a non-SDR
+		 * transfer uses the HDR-DDR Command Code encoding: CP marks CMD
+		 * as valid, CMD carries bits[6:0], and RNW carries bit[7]. CP
+		 * and CMD occupy the same descriptor bits in both command
+		 * formats.
+		 */
+		mode = MODE_I3C_HDR_DDR;
+		cp_cmd = CMD_R0_CP | CMD_R0_CMD(xfer->hdr_cmd & I3C_HDR_CMD_CODE);
+	}
 
 	xfer->cmd_tid = hci_get_tid();
 
@@ -233,7 +249,8 @@ static void hci_cmd_v1_prep_i3c_xfer(struct i3c_hci *hci,
 			CMD_I0_TID(xfer->cmd_tid) |
 			CMD_I0_DEV_INDEX(dat_idx) |
 			CMD_I0_DTT(data_len) |
-			CMD_I0_MODE(mode);
+			CMD_I0_MODE(mode) |
+			cp_cmd;
 		fill_data_bytes(xfer, data, data_len);
 	} else {
 		/* we use a Regular Data Transfer Command */
@@ -242,7 +259,8 @@ static void hci_cmd_v1_prep_i3c_xfer(struct i3c_hci *hci,
 			CMD_R0_TID(xfer->cmd_tid) |
 			CMD_R0_DEV_INDEX(dat_idx) |
 			CMD_R0_MODE(mode) |
-			(rnw ? CMD_R0_RNW : 0);
+			(rnw ? CMD_R0_RNW : 0) |
+			cp_cmd;
 		xfer->cmd_desc[1] =
 			CMD_R1_DATA_LENGTH(data_len);
 	}
diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c b/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c
index 8d93748e858d..b5e25f05f03e 100644
--- a/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c
+++ b/drivers/i3c/master/mipi-i3c-hci/cmd_v2.c
@@ -212,9 +212,11 @@ static int hci_cmd_v2_prep_ccc(struct i3c_hci *hci, struct hci_xfer *xfer,
 	return 0;
 }
 
+/* For cmd_v2, only SDR capability is advertised */
 static void hci_cmd_v2_prep_i3c_xfer(struct i3c_hci *hci,
 				     struct i3c_dev_desc *dev,
-				     struct hci_xfer *xfer)
+				     struct hci_xfer *xfer,
+				     enum i3c_xfer_mode xfer_mode)
 {
 	unsigned int mode = XFERMODE_IDX_I3C_SDR;
 	unsigned int rate = get_i3c_rate_idx(hci);
diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
index 57d84d7682d7..c72522f702bb 100644
--- a/drivers/i3c/master/mipi-i3c-hci/core.c
+++ b/drivers/i3c/master/mipi-i3c-hci/core.c
@@ -116,6 +116,13 @@ static inline struct i3c_hci *to_i3c_hci(struct i3c_master_controller *m)
 	return container_of(m, struct i3c_hci, master);
 }
 
+/* HDR support has been added for cmd_v1 only */
+static bool i3c_hci_hdr_ddr_capable(struct i3c_hci *hci)
+{
+	return hci->cmd == &mipi_i3c_hci_cmd_v1 &&
+	       hci->caps & HC_CAP_HDR_DDR_EN;
+}
+
 /**
  * i3c_hci_sysdev() - Get the device to use for DMA and system PM
  * @dev: Device the HCI controller is bound to
@@ -158,6 +165,8 @@ static int i3c_hci_bus_init(struct i3c_master_controller *m)
 	i3c_hci_set_master_dyn_addr(hci);
 	memset(&info, 0, sizeof(info));
 	info.dyn_addr = hci->dyn_addr;
+	if (i3c_hci_hdr_ddr_capable(hci))
+		info.hdr_cap = BIT(I3C_HDR_DDR);
 	ret = i3c_master_set_info(m, &info);
 	if (ret)
 		return ret;
@@ -463,6 +472,27 @@ static int i3c_hci_daa(struct i3c_master_controller *m)
 	return ret;
 }
 
+static bool i3c_hci_rnw(struct i3c_xfer *i3c_xfer, enum i3c_xfer_mode mode)
+{
+	if (mode == I3C_SDR)
+		return i3c_xfer->rnw;
+
+	return i3c_xfer->cmd & I3C_HDR_CMD_RNW;
+}
+
+static int i3c_hci_check_hdr_ddr_xfers(struct i3c_xfer *i3c_xfers, int nxfers)
+{
+	/*
+	 * HDR-DDR frames 16-bit Data Words, and at least one Data Word must
+	 * follow the Command Word.
+	 */
+	for (int i = 0; i < nxfers; i++)
+		if (i3c_xfers[i].len < 2 || i3c_xfers[i].len % 2)
+			return -EINVAL;
+
+	return 0;
+}
+
 static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
 			     struct i3c_xfer *i3c_xfers, int nxfers,
 			     enum i3c_xfer_mode mode)
@@ -475,20 +505,27 @@ static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
 
 	dev_dbg(&hci->master.dev, "nxfers = %d", nxfers);
 
+	if (mode == I3C_HDR_DDR) {
+		ret = i3c_hci_check_hdr_ddr_xfers(i3c_xfers, nxfers);
+		if (ret)
+			return ret;
+	}
+
 	xfer = hci_alloc_xfer(nxfers);
 	if (!xfer)
 		return -ENOMEM;
 
 	for (i = 0; i < nxfers; i++) {
 		xfer[i].data_len = i3c_xfers[i].len;
-		xfer[i].rnw = i3c_xfers[i].rnw;
-		if (i3c_xfers[i].rnw) {
+		xfer[i].rnw = i3c_hci_rnw(i3c_xfers + i, mode);
+		xfer[i].hdr_cmd = i3c_xfers[i].cmd;
+		if (xfer[i].rnw) {
 			xfer[i].data = i3c_xfers[i].data.in;
 		} else {
 			/* silence the const qualifier warning with a cast */
 			xfer[i].data = (void *) i3c_xfers[i].data.out;
 		}
-		hci->cmd->prep_i3c_xfer(hci, dev, &xfer[i]);
+		hci->cmd->prep_i3c_xfer(hci, dev, &xfer[i], mode);
 		xfer[i].cmd_desc[0] |= CMD_0_ROC;
 	}
 	last = i - 1;
@@ -500,7 +537,7 @@ static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
 	if (ret)
 		goto out;
 	for (i = 0; i < nxfers; i++) {
-		if (i3c_xfers[i].rnw)
+		if (xfer[i].rnw)
 			i3c_xfers[i].len = RESP_DATA_LENGTH(xfer[i].response);
 		if (RESP_STATUS(xfer[i].response) != RESP_SUCCESS) {
 			ret = -EIO;
diff --git a/drivers/i3c/master/mipi-i3c-hci/hci.h b/drivers/i3c/master/mipi-i3c-hci/hci.h
index ee73f6e6756a..4288a1b5b491 100644
--- a/drivers/i3c/master/mipi-i3c-hci/hci.h
+++ b/drivers/i3c/master/mipi-i3c-hci/hci.h
@@ -85,10 +85,10 @@ struct i3c_hci {
 
 /*
  * Structure to represent a master initiated transfer.
- * The rnw, data and data_len fields must be initialized before calling any
- * hci->cmd->*() method. The cmd method will initialize cmd_desc[] and
- * possibly modify (clear) the data field. Then xfer->cmd_desc[0] can
- * be augmented with CMD_0_ROC and/or CMD_0_TOC.
+ * The rnw, data and data_len (and hdr_cmd for HDR) fields must be initialized
+ * before calling any hci->cmd->*() method. The cmd method will initialize
+ * cmd_desc[] and possibly modify (clear) the data field. Then xfer->cmd_desc[0]
+ * can be augmented with CMD_0_ROC and/or CMD_0_TOC.
  * The completion field needs to be initialized before queueing with
  * hci->io->queue_xfer(), and requires CMD_0_ROC to be set.
  */
@@ -97,6 +97,7 @@ struct hci_xfer {
 	u32 response;
 	bool rnw;
 	bool started;
+	u8 hdr_cmd;
 	void *data;
 	unsigned int data_len;
 	unsigned int cmd_tid;
diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h
index 0f065b883ee0..e30ea2cb13cb 100644
--- a/include/linux/i3c/device.h
+++ b/include/linux/i3c/device.h
@@ -79,6 +79,10 @@ struct i3c_xfer {
 	enum i3c_error_code err;
 };
 
+/* For splitting 'cmd' from struct i3c_xfer */
+#define I3C_HDR_CMD_RNW			BIT(7)
+#define I3C_HDR_CMD_CODE		GENMASK(6, 0)
+
 /**
  * enum i3c_dcr - I3C DCR values
  * @I3C_DCR_GENERIC_DEVICE: generic I3C device
-- 
2.53.0


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

* Re: [PATCH 01/17] i3c: master: Fix out-of-bounds read in DMA bounce buffer setup
  2026-09-14 11:29 ` [PATCH 01/17] i3c: master: Fix out-of-bounds read in DMA bounce buffer setup Adrian Hunter
@ 2026-09-14 16:09   ` Frank Li
  0 siblings, 0 replies; 31+ messages in thread
From: Frank Li @ 2026-09-14 16:09 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: alexandre.belloni, Frank.Li, billy_tsai, linux-i3c, linux-kernel

On Mon, Sep 14, 2026 at 02:29:47PM +0300, Adrian Hunter wrote:
> When a bounce buffer is required for DMA_TO_DEVICE transfers,
> i3c_master_dma_map_single() rounds the DMA mapping length up to a
> cache-line boundary:
>
> 	map_len = ALIGN(len, cache_line_size());
>
> It then allocates the bounce buffer with:
>
> 	kmemdup(buf, map_len, GFP_KERNEL);
>
> kmemdup() copies the full allocation size, causing it to read map_len
> bytes from buf even though only len bytes are valid.  This results in an
> out-of-bounds read of up to cache_line_size() - 1 bytes past the end of
> the caller's buffer.
>
> Fix the issue by allocating the bounce buffer with kzalloc() and copying
> only len bytes from the original buffer.  The remaining bytes up to
> map_len stay zero-filled, avoiding both the out-of-bounds read and
> exposure of unrelated memory contents to the DMA engine.
>
> Fixes: f8d9e56aeb87 ("i3c: master: Add helpers for DMA mapping and bounce buffer handling")
> Cc: stable@vger.kernel.org
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/i3c/master.c | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> index afcd7a21a3e6..f9a6c8560fab 100644
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
> @@ -2216,12 +2216,11 @@ struct i3c_dma *i3c_master_dma_map_single(struct device *dev, void *buf,
>
>  	if (force_bounce) {
>  		dma_xfer->map_len = ALIGN(len, cache_line_size());
> -		if (dir == DMA_FROM_DEVICE)
> -			bounce = kzalloc(dma_xfer->map_len, GFP_KERNEL);
> -		else
> -			bounce = kmemdup(buf, dma_xfer->map_len, GFP_KERNEL);
> +		bounce = kzalloc(dma_xfer->map_len, GFP_KERNEL);
>  		if (!bounce)
>  			return NULL;
> +		if (dir != DMA_FROM_DEVICE)
> +			memcpy(bounce, buf, len);
>  		dma_buf = bounce;
>  	}
>
> --
> 2.53.0
>

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

* Re: [PATCH 02/17] i3c: mipi-i3c-hci: Bounce short reads irrespective of the IOMMU
  2026-09-14 11:29 ` [PATCH 02/17] i3c: mipi-i3c-hci: Bounce short reads irrespective of the IOMMU Adrian Hunter
@ 2026-09-14 16:16   ` Frank Li
  0 siblings, 0 replies; 31+ messages in thread
From: Frank Li @ 2026-09-14 16:16 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: alexandre.belloni, Frank.Li, billy_tsai, linux-i3c, linux-kernel

On Mon, Sep 14, 2026 at 02:29:48PM +0300, Adrian Hunter wrote:
> The controller writes whole DWORDs, so a read whose length is not a
                                         an i3c read

> multiple of 4 overwrites up to 3 bytes past the end of the destination
> buffer. That is a property of the controller, not of the IOMMU, but the
> bounce buffer that works around it was used only when the device was
> IOMMU mapped. Everywhere else the buffer is left unprotected.
>
> Drop the device_iommu_mapped() condition.
>
> The overrun is easily seen with CONFIG_SLUB_DEBUG=y and kernel command
> line options intel_iommu=off slub_debug=FZPU, which reports it as a
> kmalloc redzone overwrite.

Can you put a line kernel msg here ?


Frank
>
> Fixes: 9e23897bca62 ("i3c: mipi-i3c-hci: Use physical device pointer with DMA API")
> Cc: stable@vger.kernel.org
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  drivers/i3c/master/mipi-i3c-hci/dma.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
> index 7c2b20474130..5b195978f376 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/dma.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
> @@ -428,7 +428,7 @@ static void hci_dma_unmap_xfer(struct i3c_hci *hci,
>  static struct i3c_dma *hci_dma_map_xfer(struct device *dev, struct hci_xfer *xfer)
>  {
>  	enum dma_data_direction dir = xfer->rnw ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
> -	bool need_bounce = device_iommu_mapped(dev) && xfer->rnw && (xfer->data_len & 3);
> +	bool need_bounce = xfer->rnw && (xfer->data_len & 3);
>
>  	return i3c_master_dma_map_single(dev, xfer->data, xfer->data_len, need_bounce, dir);
>  }
> --
> 2.53.0
>

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

* Re: [PATCH 03/17] i3c: mipi-i3c-hci-pci: Set drvdata before creating LTR sysfs attribute
  2026-09-14 11:29 ` [PATCH 03/17] i3c: mipi-i3c-hci-pci: Set drvdata before creating LTR sysfs attribute Adrian Hunter
@ 2026-09-14 16:17   ` Frank Li
  0 siblings, 0 replies; 31+ messages in thread
From: Frank Li @ 2026-09-14 16:17 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: alexandre.belloni, Frank.Li, billy_tsai, linux-i3c, linux-kernel

On Mon, Sep 14, 2026 at 02:29:49PM +0300, Adrian Hunter wrote:
> intel_i3c_init() creates the pm_qos_latency_tolerance_us sysfs attribute
> before probe calls pci_set_drvdata().  A userspace write to the attribute
> can therefore invoke intel_ltr_set(), which uses pci_get_drvdata(),
> before drvdata has been initialized.
>
> Move pci_set_drvdata() before hci->info->init() so drvdata is available
> before the sysfs attribute becomes accessible.
>
> Fixes: 884a33131f2a ("i3c: mipi-i3c-hci-pci: Add LTR support for Intel controllers")
> Cc: stable@vger.kernel.org
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
> index ab595661db1e..af9595009b03 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
> @@ -445,6 +445,8 @@ static int mipi_i3c_hci_pci_probe(struct pci_dev *pci,
>  	if (ret < 0)
>  		return ret;
>
> +	pci_set_drvdata(pci, hci);
> +
>  	hci->info = (const struct mipi_i3c_hci_pci_info *)id->driver_data;
>
>  	ret = hci->info->init ? hci->info->init(hci) : 0;
> @@ -455,8 +457,6 @@ static int mipi_i3c_hci_pci_probe(struct pci_dev *pci,
>  	if (ret)
>  		goto err_exit;
>
> -	pci_set_drvdata(pci, hci);
> -
>  	mipi_i3c_hci_pci_rpm_allow(&pci->dev);
>
>  	return 0;
> --
> 2.53.0
>

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

* Re: [PATCH 04/17] i3c: master: Match ACPI targets to the correct bus controller instance
  2026-09-14 11:29 ` [PATCH 04/17] i3c: master: Match ACPI targets to the correct bus controller instance Adrian Hunter
@ 2026-09-14 16:19   ` Frank Li
  0 siblings, 0 replies; 31+ messages in thread
From: Frank Li @ 2026-09-14 16:19 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: alexandre.belloni, Frank.Li, billy_tsai, linux-i3c, linux-kernel

On Mon, Sep 14, 2026 at 02:29:50PM +0300, Adrian Hunter wrote:
> For ACPI-enumerated I3C targets, _ADR encodes both the zero-based bus
> controller instance number in bits 51:48 and the Provisioned ID (PID)
> in bits 47:0, as defined by ACPI 6.6 Table 6.2 and MIPI DisCo for I3C
> v1.1 section 5.2.
>
> However, i3c_master_add_acpi_dev() treats the entire _ADR value as the
> PID. On multi-instance controllers this folds the instance number into
> the PID, causing i3c_master_add_i3c_boardinfo() to reject devices on
> instance 1 and above with -EINVAL.
>
> The problem is exposed by the MIPI I3C HCI PCI driver, which creates one
> MFD child device per bus controller instance. Since the child devices do
> not have their own ACPI companions, they all inherit the parent's ACPI
> node and therefore enumerate the same set of child devices. As a result,
> a target belonging to any instance other than 0 prevents registration of
> all controller instances.
>
> Add an instance number to struct i3c_master_controller, propagate it
> from the HCI PCI driver, extract the PID from bits 47:0 of _ADR, and
> ignore ACPI child nodes that belong to a different controller instance.
>
> ACPI-enumerated I2C devices are unaffected. Their controller instance is
> encoded in the Resource Source Index of the I2cSerialBusV2 descriptor
> rather than in _ADR and will require separate handling.
>
> Fixes: b46a4b3c5d1e ("i3c: master: Support ACPI enumeration of child devices")
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/i3c/master.c                          | 19 +++++++++++++++++--
>  drivers/i3c/master/mipi-i3c-hci/core.c        |  4 +++-
>  .../master/mipi-i3c-hci/mipi-i3c-hci-pci.c    |  1 +
>  include/linux/i3c/master.h                    |  3 +++
>  include/linux/platform_data/mipi-i3c-hci.h    |  4 ++++
>  5 files changed, 28 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> index f9a6c8560fab..215a22f2c7b6 100644
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
> @@ -8,6 +8,7 @@
>  #include <dt-bindings/i3c/i3c.h>
>  #include <linux/acpi.h>
>  #include <linux/atomic.h>
> +#include <linux/bitfield.h>
>  #include <linux/bitmap.h>
>  #include <linux/bug.h>
>  #include <linux/delay.h>
> @@ -3076,6 +3077,13 @@ static int i3c_master_add_of_dev(struct i3c_master_controller *master,
>  	return ret;
>  }
>
> +#define I3C_ACPI_ADR_PID GENMASK_U64(47, 0)
> +/*
> + * Zero-based instance number of the Bus Controller to which the Target is
> + * connected.
> + */
> +#define I3C_ACPI_ADR_INSTANCE GENMASK_U64(51, 48)
> +
>  #ifdef CONFIG_ACPI
>  static int i3c_master_add_acpi_dev(struct i3c_master_controller *master,
>  				   struct fwnode_handle *fwnode)
> @@ -3083,6 +3091,7 @@ static int i3c_master_add_acpi_dev(struct i3c_master_controller *master,
>  	struct acpi_device *adev = to_acpi_device_node(fwnode);
>  	acpi_bus_address adr;
>  	u32 reg[3] = { 0 };
> +	u64 pid;
>  	int ret;
>
>  	/*
> @@ -3100,9 +3109,15 @@ static int i3c_master_add_acpi_dev(struct i3c_master_controller *master,
>
>  	adr = acpi_device_adr(adev);
>
> +	/* Match the multi-bus instance number */
> +	if (FIELD_GET(I3C_ACPI_ADR_INSTANCE, adr) != master->instance)
> +		return 0;
> +
>  	/* For I3C devices, _ADR will have the 48 bit PID of the device  */
> -	reg[1] = upper_32_bits(adr);
> -	reg[2] = lower_32_bits(adr);
> +	pid = FIELD_GET(I3C_ACPI_ADR_PID, adr);
> +
> +	reg[1] = upper_32_bits(pid);
> +	reg[2] = lower_32_bits(pid);
>
>  	fwnode_property_read_u32(fwnode, "mipi-i3c-static-address", &reg[0]);
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
> index dadf049bd4b5..8b3a87d8a8bb 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/core.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/core.c
> @@ -1142,8 +1142,10 @@ static int i3c_hci_probe(struct platform_device *pdev)
>  	 * necessarily in separate contiguous sub-ranges. To avoid overlapping
>  	 * mappings, provide base_regs from the parent mapping.
>  	 */
> -	if (pdata)
> +	if (pdata) {
>  		hci->base_regs = pdata->base_regs;
> +		hci->master.instance = pdata->instance;
> +	}
>
>  	if (!hci->base_regs) {
>  		hci->base_regs = devm_platform_ioremap_resource(pdev, 0);
> diff --git a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
> index af9595009b03..5b8e10d05cee 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/mipi-i3c-hci-pci.c
> @@ -390,6 +390,7 @@ static void mipi_i3c_hci_pci_setup_cell(struct mipi_i3c_hci_pci *hci, int idx,
>  					struct mfd_cell *cell)
>  {
>  	data->pdata.base_regs = hci->base + hci->info->instance_offset[idx];
> +	data->pdata.instance = idx;
>
>  	data->res = DEFINE_RES_IRQ(0);
>
> diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
> index f7ceec2b4477..72065715feee 100644
> --- a/include/linux/i3c/master.h
> +++ b/include/linux/i3c/master.h
> @@ -536,6 +536,8 @@ struct i3c_master_controller_ops {
>   *		 Bit 0: SETDASA
>   *		 Bit 1: SETAASA
>   *		 All other bits are reserved.
> + * @instance: Zero-based instance number of the Bus Controller as defined by the
> + *            DisCo specification I3C Target Address (_ADR) Encoding
>   * @wq: freezable workqueue which can be used by master
>   *	drivers if they need to postpone operations that need to take place
>   *	in a thread context. Typical examples are Hot Join processing which
> @@ -573,6 +575,7 @@ struct i3c_master_controller {
>  	} boardinfo;
>  	struct i3c_bus bus;
>  	u8 addr_method;
> +	u8 instance;
>  	struct workqueue_struct *wq;
>  	struct work_struct hj_work;
>  	struct work_struct reg_work;
> diff --git a/include/linux/platform_data/mipi-i3c-hci.h b/include/linux/platform_data/mipi-i3c-hci.h
> index ab7395f455f9..6f61d8a02378 100644
> --- a/include/linux/platform_data/mipi-i3c-hci.h
> +++ b/include/linux/platform_data/mipi-i3c-hci.h
> @@ -3,13 +3,17 @@
>  #define INCLUDE_PLATFORM_DATA_MIPI_I3C_HCI_H
>
>  #include <linux/compiler_types.h>
> +#include <linux/types.h>
>
>  /**
>   * struct mipi_i3c_hci_platform_data - Platform-dependent data for mipi_i3c_hci
>   * @base_regs: Register set base address (to support multi-bus instances)
> + * @instance: Zero-based instance number of the Bus Controller as defined by the
> + *            DisCo specification I3C Target Address (_ADR) Encoding
>   */
>  struct mipi_i3c_hci_platform_data {
>  	void __iomem *base_regs;
> +	u8 instance;
>  };
>
>  #endif
> --
> 2.53.0
>

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

* Re: [PATCH 05/17] i3c: master: Remove stale GETSTATUS length check
  2026-09-14 11:29 ` [PATCH 05/17] i3c: master: Remove stale GETSTATUS length check Adrian Hunter
@ 2026-09-14 16:23   ` Frank Li
  0 siblings, 0 replies; 31+ messages in thread
From: Frank Li @ 2026-09-14 16:23 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: alexandre.belloni, Frank.Li, billy_tsai, linux-i3c, linux-kernel

On Mon, Sep 14, 2026 at 02:29:51PM +0300, Adrian Hunter wrote:
> i3c_master_getstatus_locked() verifies dest.payload.len against
> sizeof(*getstatus) after issuing a GETSTATUS CCC.
>
> This check predates the introduction of dest.payload.actual_len. Since
> then, dest.payload.len has held the requested transfer length and
> dest.payload.actual_len has held the received length, so the check is
> always false and can never detect a short response.
>
> It also predates the addition of generic read CCC response length
> validation in i3c_master_send_ccc_cmd_locked(), which now performs the
> necessary check before returning success.
>
> Remove the stale check.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/i3c/master.c | 5 -----
>  1 file changed, 5 deletions(-)
>
> diff --git a/drivers/i3c/master.c b/drivers/i3c/master.c
> index 215a22f2c7b6..4296c51a9537 100644
> --- a/drivers/i3c/master.c
> +++ b/drivers/i3c/master.c
> @@ -1777,11 +1777,6 @@ static int i3c_master_getstatus_locked(struct i3c_master_controller *master,
>  	if (ret)
>  		goto out;
>
> -	if (dest.payload.len != sizeof(*getstatus)) {
> -		ret = -EIO;
> -		goto out;
> -	}
> -
>  	if (status)
>  		*status = be16_to_cpu(getstatus->status);
>  out:
> --
> 2.53.0
>

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

* Re: [PATCH 06/17] i3c: mipi-i3c-hci: Fix i3c_hci_enable_ibi() error path
  2026-09-14 11:29 ` [PATCH 06/17] i3c: mipi-i3c-hci: Fix i3c_hci_enable_ibi() error path Adrian Hunter
@ 2026-09-14 16:27   ` Frank Li
  0 siblings, 0 replies; 31+ messages in thread
From: Frank Li @ 2026-09-14 16:27 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: alexandre.belloni, Frank.Li, billy_tsai, linux-i3c, linux-kernel

On Mon, Sep 14, 2026 at 02:29:52PM +0300, Adrian Hunter wrote:

suggested subject:
  i3c: mipi-i3c-hci: restore controller state if i3c_hci_enable_ibi() return error

Frank

> i3c_hci_enable_ibi() performs controller-side setup before sending the
> ENEC CCC to enable IBIs on the target.  If the ENEC CCC fails, the
> function returns an error but leaves the controller configured as if IBI
> enabling had succeeded.
>
> Fix the error path by undoing the earlier setup when the ENEC CCC fails,
> ensuring the controller state remains consistent with the failed enable
> operation.
>
> Fixes: 9ad9a52cce282 ("i3c/master: introduce the mipi-i3c-hci driver")
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  drivers/i3c/master/mipi-i3c-hci/core.c | 6 +++++-
>  1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
> index 8b3a87d8a8bb..166d9f70f435 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/core.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/core.c
> @@ -703,11 +703,15 @@ static int i3c_hci_enable_ibi(struct i3c_dev_desc *dev)
>  	struct i3c_master_controller *m = i3c_dev_get_master(dev);
>  	struct i3c_hci *hci = to_i3c_hci(m);
>  	struct i3c_hci_dev_data *dev_data = i3c_dev_get_master_data(dev);
> +	int ret;
>
>  	mipi_i3c_hci_dat_v1.clear_flags(hci, dev_data->dat_idx, DAT_0_SIR_REJECT, 0);
>  	scoped_guard(spinlock_irqsave, &hci->lock)
>  		hci->ibi_devs[dev_data->dat_idx] = dev;
> -	return i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
> +	ret = i3c_master_enec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
> +	if (ret)
> +		__i3c_hci_disable_ibi(hci, dev);
> +	return ret;
>  }
>
>  static int i3c_hci_disable_ibi(struct i3c_dev_desc *dev)
> --
> 2.53.0
>

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

* Re: [PATCH 07/17] i3c: mipi-i3c-hci: Send DISEC before disabling IBIs in hardware
  2026-09-14 11:29 ` [PATCH 07/17] i3c: mipi-i3c-hci: Send DISEC before disabling IBIs in hardware Adrian Hunter
@ 2026-09-14 16:29   ` Frank Li
  0 siblings, 0 replies; 31+ messages in thread
From: Frank Li @ 2026-09-14 16:29 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: alexandre.belloni, Frank.Li, billy_tsai, linux-i3c, linux-kernel

On Mon, Sep 14, 2026 at 02:29:53PM +0300, Adrian Hunter wrote:
> Reorder i3c_hci_disable_ibi() so that DISEC is sent before IBIs are
> disabled at the controller.
>
> This matches the sequence used by other I3C controller drivers.  It also
> avoids dropping an IBI that races with the disable operation: an IBI
> received after DISEC is issued but before the controller disables IBIs
> can still be processed normally.  Once DISEC has been sent, the hardware
> can be updated to NACK subsequent IBIs and complete the teardown.
>
> No functional change is intended beyond aligning the ordering with other
> drivers and handling the race window consistently.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/i3c/master/mipi-i3c-hci/core.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
> index 166d9f70f435..f6a34ce7a295 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/core.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/core.c
> @@ -719,13 +719,14 @@ static int i3c_hci_disable_ibi(struct i3c_dev_desc *dev)
>  	struct i3c_master_controller *m = i3c_dev_get_master(dev);
>  	struct i3c_hci *hci = to_i3c_hci(m);
>
> -	__i3c_hci_disable_ibi(hci, dev);
>  	/*
> -	 * The DAT entry is now set to NACK and DISEC this target's IBIs, so
> +	 * The DAT entry will be set to NACK and DISEC this target's IBIs, so
>  	 * the IBI teardown can proceed even if DISEC below fails, so ignore
>  	 * errors.
>  	 */
>  	i3c_master_disec_locked(m, dev->info.dyn_addr, I3C_CCC_EVENT_SIR);
> +
> +	__i3c_hci_disable_ibi(hci, dev);
>  	return 0;
>  }
>
> --
> 2.53.0
>

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

* Re: [PATCH 09/17] i3c: mipi-i3c-hci: Process multiple IBIs per interrupt
  2026-09-14 11:29 ` [PATCH 09/17] i3c: mipi-i3c-hci: Process multiple IBIs per interrupt Adrian Hunter
@ 2026-09-14 16:45   ` Frank Li
  0 siblings, 0 replies; 31+ messages in thread
From: Frank Li @ 2026-09-14 16:45 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: alexandre.belloni, Frank.Li, billy_tsai, linux-i3c, linux-kernel

On Mon, Sep 14, 2026 at 02:29:55PM +0300, Adrian Hunter wrote:
> INTR_IBI_READY indicates that one or more IBI Status Descriptors are
> present in the IBI ring.  After clearing interrupt status, the interrupt
> handler processes only a single IBI even though additional IBIs may
> already be queued.
>
> The controller does not reassert INTR_IBI_READY solely because entries
> remain in the ring after interrupt status has been cleared.  Consequently,
> the remaining IBIs are not processed until some later interrupt occurs,
> and can accumulate if IBIs arrive more often than the interrupt handler
> runs.
>
> Process all IBIs that are pending when the handler runs: capture the IBI
> enqueue pointer up front and continue until the dequeue pointer reaches
> that position.
>
> Fixes: 9ad9a52cce28 ("i3c/master: introduce the mipi-i3c-hci driver")
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  drivers/i3c/master/mipi-i3c-hci/dma.c | 39 +++++++++++++++++----------
>  1 file changed, 25 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
> index 5b195978f376..a798b0648922 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/dma.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
> @@ -868,25 +868,24 @@ static void hci_dma_recycle_ibi_slot(struct i3c_hci *hci,
>  	i3c_generic_ibi_recycle_slot(dev_ibi->pool, slot);
>  }
>
> -static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
> +static bool hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh,
> +				u32 *op1_val, unsigned int enq_ptr)
>  {
>  	struct hci_rings_data *rings = hci->io_data;
>  	struct i3c_dev_desc *dev;
>  	struct i3c_hci_dev_data *dev_data;
>  	struct hci_dma_dev_ibi_data *dev_ibi;
>  	struct i3c_ibi_slot *slot;
> -	u32 op1_val, op2_val, ibi_status_error;
> -	unsigned int ptr, enq_ptr, deq_ptr;
> +	u32 ibi_status_error;
> +	unsigned int ptr, deq_ptr;
>  	unsigned int ibi_size, ibi_chunks, ibi_data_offset, first_part;
>  	int ibi_addr, last_ptr;
>  	void *ring_ibi_data;
>  	dma_addr_t ring_ibi_data_dma;
>
> -	op1_val = rh_reg_read(RING_OPERATION1);
> -	deq_ptr = FIELD_GET(RING_OP1_IBI_DEQ_PTR, op1_val);
> -
> -	op2_val = rh_reg_read(RING_OPERATION2);
> -	enq_ptr = FIELD_GET(RING_OP2_IBI_ENQ_PTR, op2_val);
> +	deq_ptr = FIELD_GET(RING_OP1_IBI_DEQ_PTR, *op1_val);
> +	if (deq_ptr == enq_ptr)
> +		return false;
>
>  	ibi_status_error = 0;
>  	ibi_addr = -1;
> @@ -936,7 +935,7 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
>  		dev_dbg(&hci->master.dev,
>  			"no LAST_STATUS available (e=%d d=%d)",
>  			enq_ptr, deq_ptr);
> -		return;
> +		return false;
>  	}
>  	deq_ptr = last_ptr + 1;
>  	deq_ptr %= rh->ibi_status_entries;
> @@ -1015,10 +1014,9 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
>  	i3c_master_queue_ibi(dev, slot);
>
>  done:
> -	op1_val = rh_reg_read(RING_OPERATION1);
> -	op1_val &= ~RING_OP1_IBI_DEQ_PTR;
> -	op1_val |= FIELD_PREP(RING_OP1_IBI_DEQ_PTR, deq_ptr);
> -	rh_reg_write(RING_OPERATION1, op1_val);
> +	*op1_val &= ~RING_OP1_IBI_DEQ_PTR;
> +	*op1_val |= FIELD_PREP(RING_OP1_IBI_DEQ_PTR, deq_ptr);
> +	rh_reg_write(RING_OPERATION1, *op1_val);
>
>  	/* update the chunk pointer */
>  	rh->ibi_chunk_ptr += ibi_chunks;
> @@ -1026,6 +1024,19 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
>
>  	/* and tell the hardware about freed chunks */
>  	rh_reg_write(CHUNK_CONTROL, rh_reg_read(CHUNK_CONTROL) + ibi_chunks);
> +
> +	return true;
> +}
> +
> +static void hci_dma_drain_ibi_ring(struct i3c_hci *hci, struct hci_rh_data *rh)
> +{
> +	u32 op1_val = rh_reg_read(RING_OPERATION1);
> +	u32 op2_val = rh_reg_read(RING_OPERATION2);
> +	unsigned int enq_ptr = FIELD_GET(RING_OP2_IBI_ENQ_PTR, op2_val);
> +
> +	/* Loop is bounded by enq_ptr. Further IBIs will re-assert INTR_IBI_READY */
> +	while (hci_dma_process_ibi(hci, rh, &op1_val, enq_ptr))
> +		;

You just read once RING_OPERATION1, I think you can read in RING_OPERATION1
loop, utils hardware not pending irqs.

And I am not sure if op2_val is always mach op1_val by two 32bit read.
is it possible op1_value changed, when read op2_val?

A new irq status may be trigger later, but it become empty ops at irq
handle.

Frank

>  }
>
>  static bool hci_dma_irq_handler(struct i3c_hci *hci)
> @@ -1047,7 +1058,7 @@ static bool hci_dma_irq_handler(struct i3c_hci *hci)
>  		rh_reg_write(INTR_STATUS, status);
>
>  		if (status & INTR_IBI_READY)
> -			hci_dma_process_ibi(hci, rh);
> +			hci_dma_drain_ibi_ring(hci, rh);
>  		if (status & (INTR_TRANSFER_COMPLETION | INTR_TRANSFER_ERR))
>  			hci_dma_xfer_done(hci, rh);
>  		if (status & INTR_RING_OP)
> --
> 2.53.0
>

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

* Re: [PATCH 10/17] i3c: mipi-i3c-hci: Move DMA suspend/resume callbacks
  2026-09-14 11:29 ` [PATCH 10/17] i3c: mipi-i3c-hci: Move DMA suspend/resume callbacks Adrian Hunter
@ 2026-09-14 16:46   ` Frank Li
  0 siblings, 0 replies; 31+ messages in thread
From: Frank Li @ 2026-09-14 16:46 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: alexandre.belloni, Frank.Li, billy_tsai, linux-i3c, linux-kernel

On Mon, Sep 14, 2026 at 02:29:56PM +0300, Adrian Hunter wrote:
> Relocate hci_dma_suspend() and hci_dma_resume() closer to the DMA IO
> operations table in preparation for upcoming changes.
>
> No functional change.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/i3c/master/mipi-i3c-hci/dma.c | 46 +++++++++++++--------------
>  1 file changed, 23 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
> index a798b0648922..ec4b469abd33 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/dma.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
> @@ -273,29 +273,6 @@ static void hci_dma_init_rings(struct i3c_hci *hci)
>  		hci_dma_init_rh(hci, &rings->headers[i], i);
>  }
>
> -static void hci_dma_suspend(struct i3c_hci *hci)
> -{
> -	struct hci_rings_data *rings = hci->io_data;
> -	int n = rings ? rings->total : 0;
> -
> -	for (int i = 0; i < n; i++) {
> -		struct hci_rh_data *rh = &rings->headers[i];
> -
> -		rh_reg_write(INTR_SIGNAL_ENABLE, 0);
> -		rh_reg_write(RING_CONTROL, 0);
> -	}
> -
> -	i3c_hci_sync_irq_inactive(hci);
> -}
> -
> -static void hci_dma_resume(struct i3c_hci *hci)
> -{
> -	struct hci_rings_data *rings = hci->io_data;
> -
> -	if (rings)
> -		hci_dma_init_rings(hci);
> -}
> -
>  static int hci_dma_init(struct i3c_hci *hci)
>  {
>  	struct hci_rings_data *rings;
> @@ -1075,6 +1052,29 @@ static bool hci_dma_irq_handler(struct i3c_hci *hci)
>  	return handled;
>  }
>
> +static void hci_dma_suspend(struct i3c_hci *hci)
> +{
> +	struct hci_rings_data *rings = hci->io_data;
> +	int n = rings ? rings->total : 0;
> +
> +	for (int i = 0; i < n; i++) {
> +		struct hci_rh_data *rh = &rings->headers[i];
> +
> +		rh_reg_write(INTR_SIGNAL_ENABLE, 0);
> +		rh_reg_write(RING_CONTROL, 0);
> +	}
> +
> +	i3c_hci_sync_irq_inactive(hci);
> +}
> +
> +static void hci_dma_resume(struct i3c_hci *hci)
> +{
> +	struct hci_rings_data *rings = hci->io_data;
> +
> +	if (rings)
> +		hci_dma_init_rings(hci);
> +}
> +
>  const struct hci_io_ops mipi_i3c_hci_dma = {
>  	.init			= hci_dma_init,
>  	.cleanup		= hci_dma_cleanup,
> --
> 2.53.0
>

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

* Re: [PATCH 11/17] i3c: mipi-i3c-hci: Stop rings gracefully when suspending
  2026-09-14 11:29 ` [PATCH 11/17] i3c: mipi-i3c-hci: Stop rings gracefully when suspending Adrian Hunter
@ 2026-09-14 16:51   ` Frank Li
  0 siblings, 0 replies; 31+ messages in thread
From: Frank Li @ 2026-09-14 16:51 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: alexandre.belloni, Frank.Li, billy_tsai, linux-i3c, linux-kernel

On Mon, Sep 14, 2026 at 02:29:57PM +0300, Adrian Hunter wrote:
> hci_dma_suspend() tore the rings down with a single write of zero to
> RH_RING_CONTROL, clearing the RS and ENABLE fields together and without
> waiting for the ring to stop.  I3C HCI v1.1 section 6.1.2 separates those
> steps: clear RS for all running Ring Bundles, and only then clear ENABLE
> for all enabled Ring Bundles.
>
> The ring registers were also written outside hci->lock, while the
> interrupt handler, which takes that lock, could still be running on
> another CPU.  i3c_hci_sync_irq_inactive() was called only afterwards.
>
> Finally, an IBI can still be sitting in the IBI Status Ring when suspend
> runs.  Clearing HC_CONTROL.BUS_ENABLE is deferred: per the description of
> that field, if a disable request occurs while receiving an IBI, the
> actual disabling does not occur until reception of the IBI is complete.
>
> Instead, clear RS under hci->lock, wait for RING_STATUS_RUNNING to clear,
> and make the interrupt handler inactive.  Only then disable the ring
> interrupt signals, drain anything left in the IBI ring, and clear ENABLE.
>
> Fixes: 816958720443 ("i3c: mipi-i3c-hci: Add DMA suspend and resume support")
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  drivers/i3c/master/mipi-i3c-hci/dma.c | 46 ++++++++++++++++++++++++---
>  1 file changed, 42 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
> index ec4b469abd33..9c163ee4d215 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/dma.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
> @@ -15,6 +15,7 @@
>  #include <linux/errno.h>
>  #include <linux/i3c/master.h>
>  #include <linux/io.h>
> +#include <linux/iopoll.h>
>
>  #include "hci.h"
>  #include "cmd.h"
> @@ -1052,19 +1053,56 @@ static bool hci_dma_irq_handler(struct i3c_hci *hci)
>  	return handled;
>  }
>
> +#define RING_STOP_TIMEOUT_US	(100 * USEC_PER_MSEC)
> +#define RING_STOP_SLEEP_US	100
> +

Can you add comments where these timeout value from? standard spec or
you just engineerring choice.

Frank
>  static void hci_dma_suspend(struct i3c_hci *hci)
>  {
>  	struct hci_rings_data *rings = hci->io_data;
>  	int n = rings ? rings->total : 0;
> +	struct hci_rh_data *rh;
> +	u32 regval;
>
> -	for (int i = 0; i < n; i++) {
> -		struct hci_rh_data *rh = &rings->headers[i];
> +	/* Gracefully stop the rings */
> +	scoped_guard(spinlock_irqsave, &hci->lock) {
> +		for (int i = 0; i < n; i++) {
> +			rh = &rings->headers[i];
> +			regval = rh_reg_read(RING_CONTROL);
> +			if (regval & RING_CTRL_RUN_STOP)
> +				rh_reg_write(RING_CONTROL, regval & ~RING_CTRL_RUN_STOP);
> +		}
> +	}
>
> -		rh_reg_write(INTR_SIGNAL_ENABLE, 0);
> -		rh_reg_write(RING_CONTROL, 0);
> +	/* Wait for actual stop */
> +	for (int i = 0; i < n; i++) {
> +		rh = &rings->headers[i];
> +		if (readx_poll_timeout(readl, rh->regs + RH_RING_STATUS, regval,
> +				       !(regval & RING_STATUS_RUNNING),
> +				       RING_STOP_SLEEP_US, RING_STOP_TIMEOUT_US))
> +			dev_err(&hci->master.dev, "%s: Ring did not stop, status %#x\n",
> +				__func__, regval);
>  	}
>
> +	/*
> +	 * With the rings stopped, no more IBIs can be received. Flush and make
> +	 * the interrupt handler inactive.
> +	 */
>  	i3c_hci_sync_irq_inactive(hci);
> +
> +	/* Disable interrupt signals and disable the rings */
> +	scoped_guard(spinlock_irqsave, &hci->lock)
> +		for (int i = 0; i < n; i++) {
> +			rh = &rings->headers[i];
> +			rh_reg_write(INTR_SIGNAL_ENABLE, 0);
> +			/*
> +			 * Be absolutely certain there is no unprocessed IBI.
> +			 * hci_dma_drain_ibi_ring() will do nothing if there is
> +			 * none.
> +			 */
> +			if (i < IBI_RINGS)
> +				hci_dma_drain_ibi_ring(hci, rh);
> +			rh_reg_write(RING_CONTROL, 0);
> +		}
>  }
>
>  static void hci_dma_resume(struct i3c_hci *hci)
> --
> 2.53.0
>

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

* Re: [PATCH 12/17] i3c: mipi-i3c-hci: Fix Response Descriptor DATA_LENGTH mask
  2026-09-14 11:29 ` [PATCH 12/17] i3c: mipi-i3c-hci: Fix Response Descriptor DATA_LENGTH mask Adrian Hunter
@ 2026-09-14 16:55   ` Frank Li
  0 siblings, 0 replies; 31+ messages in thread
From: Frank Li @ 2026-09-14 16:55 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: alexandre.belloni, Frank.Li, billy_tsai, linux-i3c, linux-kernel

On Mon, Sep 14, 2026 at 02:29:58PM +0300, Adrian Hunter wrote:

i3c: mipi-i3c-hci: Correct RESP_DATA_LENGTH to bits 15:0

Frank

> The I3C HCI Response Descriptor defines DATA_LENGTH in Bits[15:0],
> with Bits[23:16] reserved in all published HCI specification versions:
> v1.0 (Table 91) and v1.1/v1.2 (Section 8.5). However,
> RESP_DATA_LENGTH extracts Bits[21:0], incorrectly including six
> reserved bits.
>
> Update the mask to match the defined field width.
>
> No functional change is expected because compliant controllers return
> zero in reserved fields.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---
>  drivers/i3c/master/mipi-i3c-hci/cmd.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd.h b/drivers/i3c/master/mipi-i3c-hci/cmd.h
> index 7bada7b4b2de..e0d4a6e0e319 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/cmd.h
> +++ b/drivers/i3c/master/mipi-i3c-hci/cmd.h
> @@ -24,7 +24,7 @@
>   */
>  #define RESP_STATUS(resp)		FIELD_GET(GENMASK(31, 28), resp)
>  #define RESP_TID(resp)			FIELD_GET(GENMASK(27, 24), resp)
> -#define RESP_DATA_LENGTH(resp)		FIELD_GET(GENMASK(21,  0), resp)
> +#define RESP_DATA_LENGTH(resp)		FIELD_GET(GENMASK(15,  0), resp)
>
>  #define RESP_ERR_FIELD			GENMASK(31, 28)
>
> --
> 2.53.0
>

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

* Re: [PATCH 13/17] i3c: mipi-i3c-hci: Remove invalid transfer size limit
  2026-09-14 11:29 ` [PATCH 13/17] i3c: mipi-i3c-hci: Remove invalid transfer size limit Adrian Hunter
@ 2026-09-14 16:58   ` Frank Li
  0 siblings, 0 replies; 31+ messages in thread
From: Frank Li @ 2026-09-14 16:58 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: alexandre.belloni, Frank.Li, billy_tsai, linux-i3c, linux-kernel

On Mon, Sep 14, 2026 at 02:29:59PM +0300, Adrian Hunter wrote:
> The driver derives a maximum transfer size from
> HC_CAP_MAX_DATA_LENGTH in HC_CAPABILITIES, but no published version of
> the I3C HCI specification defines such a field.
>
> HC_CAPABILITIES reserves Bits[31:8] in HCI v1.0 and Bits[27:22] in HCI
> v1.1 and v1.2, so the bits used by HC_CAP_MAX_DATA_LENGTH are reserved
> in all released HCI versions.  Neither the HCI nor the I3C TCRI
> specifications define a maximum data length capability.
>
> On compliant controllers reserved bits read as zero, making the
> computed limit 65536 bytes.  Since struct i3c_xfer.len is u16,
> transfers can never reach that size and the resulting -EFBIG check can
> never trigger.
>
> Remove the unused capability definition and the dead size check.
>
> The driver's effective limit remains unchanged. HCI specifications
> define DATA_LENGTH as a 16-bit field and require larger transfers to be
> split across multiple Transfer Descriptors.  The driver already relies
> on the core's 16-bit length types elsewhere when constructing
> descriptors.
>
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/i3c/master/mipi-i3c-hci/core.c | 7 -------
>  1 file changed, 7 deletions(-)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
> index b9b20797d045..4629a16debc9 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/core.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/core.c
> @@ -51,7 +51,6 @@
>  #define HC_CAP_SG_DC_EN			BIT(30)
>  #define HC_CAP_SG_IBI_EN		BIT(29)
>  #define HC_CAP_SG_CR_EN			BIT(28)
> -#define HC_CAP_MAX_DATA_LENGTH		GENMASK(24, 22)
>  #define HC_CAP_CMD_SIZE			GENMASK(21, 20)
>  #define HC_CAP_DIRECT_COMMANDS_EN	BIT(18)
>  #define HC_CAP_MULTI_LANE_EN		BIT(15)
> @@ -473,7 +472,6 @@ static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
>  	struct i3c_hci *hci = to_i3c_hci(m);
>  	struct hci_xfer *xfer;
>  	DECLARE_COMPLETION_ONSTACK(done);
> -	unsigned int size_limit;
>  	int i, last, ret = 0;
>
>  	dev_dbg(&hci->master.dev, "nxfers = %d", nxfers);
> @@ -482,13 +480,8 @@ static int i3c_hci_i3c_xfers(struct i3c_dev_desc *dev,
>  	if (!xfer)
>  		return -ENOMEM;
>
> -	size_limit = 1U << (16 + FIELD_GET(HC_CAP_MAX_DATA_LENGTH, hci->caps));
> -
>  	for (i = 0; i < nxfers; i++) {
>  		xfer[i].data_len = i3c_xfers[i].len;
> -		ret = -EFBIG;
> -		if (xfer[i].data_len >= size_limit)
> -			goto out;
>  		xfer[i].rnw = i3c_xfers[i].rnw;
>  		if (i3c_xfers[i].rnw) {
>  			xfer[i].data = i3c_xfers[i].data.in;
> --
> 2.53.0
>

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

* Re: [PATCH 14/17] i3c: mipi-i3c-hci: Remove invalid HDR-BT and Fm/Fm+ definitions
  2026-09-14 11:30 ` [PATCH 14/17] i3c: mipi-i3c-hci: Remove invalid HDR-BT and Fm/Fm+ definitions Adrian Hunter
@ 2026-09-14 17:00   ` Frank Li
  0 siblings, 0 replies; 31+ messages in thread
From: Frank Li @ 2026-09-14 17:00 UTC (permalink / raw)
  To: Adrian Hunter
  Cc: alexandre.belloni, Frank.Li, billy_tsai, linux-i3c, linux-kernel

On Mon, Sep 14, 2026 at 02:30:00PM +0300, Adrian Hunter wrote:
> Several HCI definitions describe capabilities or modes that are not
> defined by any released version of the I3C HCI specification.
>
> HC_CAP_HDR_BT_EN uses a reserved HC_CAPABILITIES bit. Similarly,
> MODE_I3C_HDR_BT uses a MODE value reserved for I3C transfers, while
> MODE_I3C_Fm_FmP cannot be encoded in the 3-bit Command Descriptor MODE
> field.
>
> These definitions are currently unused, so there is no functional
> change.  Remove them to avoid implying support for non-existent HCI
> features and to prevent future misuse.
>
> Assisted-by: GitHub-Copilot:claude-opus-5
> Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/i3c/master/mipi-i3c-hci/cmd_v1.c | 2 --
>  drivers/i3c/master/mipi-i3c-hci/core.c   | 1 -
>  2 files changed, 3 deletions(-)
>
> diff --git a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
> index 3b9345718d27..9910df53c013 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/cmd_v1.c
> @@ -108,8 +108,6 @@ enum hci_cmd_mode {
>  	MODE_I3C_SDR4		= 0x4,
>  	MODE_I3C_HDR_TSx	= 0x5,
>  	MODE_I3C_HDR_DDR	= 0x6,
> -	MODE_I3C_HDR_BT		= 0x7,
> -	MODE_I3C_Fm_FmP		= 0x8,
>  	MODE_I2C_Fm		= 0x0,
>  	MODE_I2C_FmP		= 0x1,
>  	MODE_I2C_UD1		= 0x2,
> diff --git a/drivers/i3c/master/mipi-i3c-hci/core.c b/drivers/i3c/master/mipi-i3c-hci/core.c
> index 4629a16debc9..7a39be64c4e1 100644
> --- a/drivers/i3c/master/mipi-i3c-hci/core.c
> +++ b/drivers/i3c/master/mipi-i3c-hci/core.c
> @@ -55,7 +55,6 @@
>  #define HC_CAP_DIRECT_COMMANDS_EN	BIT(18)
>  #define HC_CAP_MULTI_LANE_EN		BIT(15)
>  #define HC_CAP_CMD_CCC_DEFBYTE		BIT(10)
> -#define HC_CAP_HDR_BT_EN		BIT(8)
>  #define HC_CAP_HDR_TS_EN		BIT(7)
>  #define HC_CAP_HDR_DDR_EN		BIT(6)
>  #define HC_CAP_NON_CURRENT_MASTER_CAP	BIT(5)	/* master handoff capable */
> --
> 2.53.0
>

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

end of thread, other threads:[~2026-09-14 17:00 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-14 11:29 [PATCH 00/17] i3c: Fixes, cleanups and HDR-DDR support Adrian Hunter
2026-09-14 11:29 ` [PATCH 01/17] i3c: master: Fix out-of-bounds read in DMA bounce buffer setup Adrian Hunter
2026-09-14 16:09   ` Frank Li
2026-09-14 11:29 ` [PATCH 02/17] i3c: mipi-i3c-hci: Bounce short reads irrespective of the IOMMU Adrian Hunter
2026-09-14 16:16   ` Frank Li
2026-09-14 11:29 ` [PATCH 03/17] i3c: mipi-i3c-hci-pci: Set drvdata before creating LTR sysfs attribute Adrian Hunter
2026-09-14 16:17   ` Frank Li
2026-09-14 11:29 ` [PATCH 04/17] i3c: master: Match ACPI targets to the correct bus controller instance Adrian Hunter
2026-09-14 16:19   ` Frank Li
2026-09-14 11:29 ` [PATCH 05/17] i3c: master: Remove stale GETSTATUS length check Adrian Hunter
2026-09-14 16:23   ` Frank Li
2026-09-14 11:29 ` [PATCH 06/17] i3c: mipi-i3c-hci: Fix i3c_hci_enable_ibi() error path Adrian Hunter
2026-09-14 16:27   ` Frank Li
2026-09-14 11:29 ` [PATCH 07/17] i3c: mipi-i3c-hci: Send DISEC before disabling IBIs in hardware Adrian Hunter
2026-09-14 16:29   ` Frank Li
2026-09-14 11:29 ` [PATCH 08/17] i3c: mipi-i3c-hci: Fix runtime PM violation in i3c_hci_free_ibi() Adrian Hunter
2026-09-14 11:29 ` [PATCH 09/17] i3c: mipi-i3c-hci: Process multiple IBIs per interrupt Adrian Hunter
2026-09-14 16:45   ` Frank Li
2026-09-14 11:29 ` [PATCH 10/17] i3c: mipi-i3c-hci: Move DMA suspend/resume callbacks Adrian Hunter
2026-09-14 16:46   ` Frank Li
2026-09-14 11:29 ` [PATCH 11/17] i3c: mipi-i3c-hci: Stop rings gracefully when suspending Adrian Hunter
2026-09-14 16:51   ` Frank Li
2026-09-14 11:29 ` [PATCH 12/17] i3c: mipi-i3c-hci: Fix Response Descriptor DATA_LENGTH mask Adrian Hunter
2026-09-14 16:55   ` Frank Li
2026-09-14 11:29 ` [PATCH 13/17] i3c: mipi-i3c-hci: Remove invalid transfer size limit Adrian Hunter
2026-09-14 16:58   ` Frank Li
2026-09-14 11:30 ` [PATCH 14/17] i3c: mipi-i3c-hci: Remove invalid HDR-BT and Fm/Fm+ definitions Adrian Hunter
2026-09-14 17:00   ` Frank Li
2026-09-14 11:30 ` [PATCH 15/17] i3c: mipi-i3c-hci: Support configurable device NACK retries Adrian Hunter
2026-09-14 11:30 ` [PATCH 16/17] i3c: Restrict HDR modes to those supported by the bus and target Adrian Hunter
2026-09-14 11:30 ` [PATCH 17/17] i3c: mipi-i3c-hci: Add HDR-DDR support Adrian Hunter

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®