mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Shubham Patil <shubhamsanjay.patil@amd.com>
To: Alexandre Belloni <alexandre.belloni@bootlin.com>,
	Frank Li <Frank.Li@nxp.com>
Cc: <linux-i3c@lists.infradead.org>, <devicetree@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>, <meaganlloyd@linux.microsoft.com>,
	<git@amd.com>, Shubham Patil <shubhamsanjay.patil@amd.com>
Subject: [PATCH v2 1/3] i3c: Add helpers to get the maximum transfer size for a device
Date: Thu, 5 Nov 2026 14:24:23 +0530	[thread overview]
Message-ID: <20261105085425.3418230-2-shubhamsanjay.patil@amd.com> (raw)
In-Reply-To: <20261105085425.3418230-1-shubhamsanjay.patil@amd.com>

A target's MRL and MWL, retrieved with GETMRL and GETMWL, describe only
what that target can accept. They say nothing about the controller
driving it, which may impose a smaller limit of its own: the DesignWare
controller, for example, rejects any private SDR transfer that does not
fit its data buffer. A device driver sizing a transfer from MRL alone
can therefore build one the controller has to refuse with -EOPNOTSUPP.

Add tx_fifo_bytes and rx_fifo_bytes to struct i3c_master_controller, to
be set by a controller driver before i3c_master_register() when it has
such a limit, together with two helpers returning the smaller of the
target and controller values for each direction.

Both inputs use 0 to mean "no limit reported", so the helpers combine
them with min_not_zero() and return 0 only when neither side reports
one, leaving each caller to apply its own default. struct
i3c_device_info keeps the raw target values untouched.

The returned value applies to a single message. A controller is free to
budget its buffer across every message in one i3c_device_do_xfers()
call, so a caller batching several messages in the same direction may
still be rejected.

Signed-off-by: Shubham Patil <shubhamsanjay.patil@amd.com>
---
 drivers/i3c/device.c       | 49 ++++++++++++++++++++++++++++++++++++++
 include/linux/i3c/device.h |  3 +++
 include/linux/i3c/master.h | 13 +++++++---
 3 files changed, 62 insertions(+), 3 deletions(-)

diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c
index 4df4682af150..588f66b3af6d 100644
--- a/drivers/i3c/device.c
+++ b/drivers/i3c/device.c
@@ -9,6 +9,7 @@
 #include <linux/bug.h>
 #include <linux/completion.h>
 #include <linux/device.h>
+#include <linux/minmax.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
 
@@ -106,6 +107,54 @@ void i3c_device_get_info(const struct i3c_device *dev,
 }
 EXPORT_SYMBOL_GPL(i3c_device_get_info);
 
+/**
+ * i3c_device_get_max_read_xfer_bytes() - get the maximum readable message size
+ *
+ * @dev: device the transfers would be directed to
+ *
+ * Return: the smaller of @dev's MRL and the controller's receive limit for a
+ * single message, or 0 if neither reports a limit.
+ */
+u16 i3c_device_get_max_read_xfer_bytes(const struct i3c_device *dev)
+{
+	u16 mrl = 0, rx_fifo_bytes = 0;
+
+	i3c_bus_normaluse_lock(dev->bus);
+	if (dev->desc) {
+		mrl = dev->desc->info.max_read_len;
+		rx_fifo_bytes = i3c_dev_get_master(dev->desc)->rx_fifo_bytes;
+	}
+	i3c_bus_normaluse_unlock(dev->bus);
+
+	/* 0 means "no limit reported" on either side. */
+	return min_not_zero(mrl, rx_fifo_bytes);
+}
+EXPORT_SYMBOL_GPL(i3c_device_get_max_read_xfer_bytes);
+
+/**
+ * i3c_device_get_max_write_xfer_bytes() - get the maximum writable message size
+ *
+ * @dev: device the transfers would be directed to
+ *
+ * Return: the smaller of @dev's MWL and the controller's transmit limit for a
+ * single message, or 0 if neither reports a limit.
+ */
+u16 i3c_device_get_max_write_xfer_bytes(const struct i3c_device *dev)
+{
+	u16 mwl = 0, tx_fifo_bytes = 0;
+
+	i3c_bus_normaluse_lock(dev->bus);
+	if (dev->desc) {
+		mwl = dev->desc->info.max_write_len;
+		tx_fifo_bytes = i3c_dev_get_master(dev->desc)->tx_fifo_bytes;
+	}
+	i3c_bus_normaluse_unlock(dev->bus);
+
+	/* 0 means "no limit reported" on either side. */
+	return min_not_zero(mwl, tx_fifo_bytes);
+}
+EXPORT_SYMBOL_GPL(i3c_device_get_max_write_xfer_bytes);
+
 /**
  * i3c_device_disable_ibi() - Disable IBIs coming from a specific device
  * @dev: device on which IBIs should be disabled
diff --git a/include/linux/i3c/device.h b/include/linux/i3c/device.h
index e30ea2cb13cb..cb3374e4f9fa 100644
--- a/include/linux/i3c/device.h
+++ b/include/linux/i3c/device.h
@@ -331,6 +331,9 @@ int i3c_device_do_setdasa(struct i3c_device *dev);
 
 void i3c_device_get_info(const struct i3c_device *dev, struct i3c_device_info *info);
 
+u16 i3c_device_get_max_read_xfer_bytes(const struct i3c_device *dev);
+u16 i3c_device_get_max_write_xfer_bytes(const struct i3c_device *dev);
+
 struct i3c_ibi_payload {
 	unsigned int len;
 	const void *data;
diff --git a/include/linux/i3c/master.h b/include/linux/i3c/master.h
index d58070a72a49..3084cc7a21be 100644
--- a/include/linux/i3c/master.h
+++ b/include/linux/i3c/master.h
@@ -551,11 +551,16 @@ struct i3c_master_controller_ops {
  *            context (notably the resume path), and is skipped if the
  *            controller is shutting down
  * @dev_nack_retry_count: retry count when slave device nack
+ * @tx_fifo_bytes: maximum number of bytes this controller can transmit in a
+ *		   single message, or 0 if it has no such limit
+ * @rx_fifo_bytes: maximum number of bytes this controller can receive in a
+ *		   single message, or 0 if it has no such limit
  *
  * A &struct i3c_master_controller has to be registered to the I3C subsystem
- * through i3c_master_register(). None of &struct i3c_master_controller fields
- * should be set manually, just pass appropriate values to
- * i3c_master_register().
+ * through i3c_master_register(). Except for @tx_fifo_bytes and
+ * @rx_fifo_bytes, which a controller driver may set before registering, none
+ * of &struct i3c_master_controller fields should be set manually, just pass
+ * appropriate values to i3c_master_register().
  */
 struct i3c_master_controller {
 	struct device dev;
@@ -580,6 +585,8 @@ struct i3c_master_controller {
 	struct work_struct hj_work;
 	struct work_struct reg_work;
 	unsigned int dev_nack_retry_count;
+	u16 tx_fifo_bytes;
+	u16 rx_fifo_bytes;
 };
 
 /**
-- 
2.34.1


  reply	other threads:[~2026-11-05  8:54 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-05  8:54 [PATCH v2 0/3] i3c: account for controller transfer limits Shubham Patil
2026-11-05  8:54 ` Shubham Patil [this message]
2026-11-05 22:04   ` [PATCH v2 1/3] i3c: Add helpers to get the maximum transfer size for a device Frank Li
2026-11-05  8:54 ` [PATCH v2 2/3] i3c: dw: Track the transmit and receive buffer depths separately Shubham Patil
2026-11-05  8:54 ` [PATCH v2 3/3] mctp i3c: Clamp transfer lengths to the controller limits Shubham Patil
2026-11-05 22:10   ` Frank Li

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261105085425.3418230-2-shubhamsanjay.patil@amd.com \
    --to=shubhamsanjay.patil@amd.com \
    --cc=Frank.Li@nxp.com \
    --cc=alexandre.belloni@bootlin.com \
    --cc=devicetree@vger.kernel.org \
    --cc=git@amd.com \
    --cc=linux-i3c@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=meaganlloyd@linux.microsoft.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®