Re: [PATCH v4 8/9] bus: mhi: Expose DDR training data via controller sysfs
From: Kishore Batta
Date: Tue Apr 14 2026 - 05:57:03 EST
On 4/13/2026 5:28 PM, Manivannan Sadhasivam wrote:
On Thu, Mar 19, 2026 at 12:01:48PM +0530, Kishore Batta wrote:Sure. will update the commit message with the required details in the next version.
DDR training data captured during Sahara command mode needs to beMaybe share some steps on how the userspace is expected to use this calibration
accessible to userspace so it can be persisted and reused on subsequent
boots. Currently, the training data is stored internally in the driver
but has no external visibility once the sahara channel is torn down.
data.
The userspace will store the calibration data in "mdmddr_0x<serial_no>.mbn format. In the next boot, Sahara driver loads the real DDR calibration data and training data will be restored. No repeated DDR training is performed at target end.Expose the captured DDR training data via a read-only binary sysfsSo once the calibration data is read, how it can be used further?
attribute on the MHI controller device. The sysfs file is created under
the controller node, allowing userspace to read the training data even
after the sahara channel device has been removed.
Currently i have added in a separate patch(9/9). I will squash it with this patch in the next version.
The sysfs attribute reads directly from controller-scoped storage andMissing ABI documentation.
relies on device managed resources for cleanup when the controller
device is destroyed. No explicit sysfs removal is required, avoiding
lifetime dependencies on the Sahara channel device.
- Mani
Signed-off-by: Kishore Batta <kishore.batta@xxxxxxxxxxxxxxxx>
---
drivers/bus/mhi/sahara/sahara.c | 69 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 69 insertions(+)
diff --git a/drivers/bus/mhi/sahara/sahara.c b/drivers/bus/mhi/sahara/sahara.c
index c88f1220199ac4373d3552167870c19a0d5f23b9..b7208738df10fc3c3895acd46873412818dc1730 100644
--- a/drivers/bus/mhi/sahara/sahara.c
+++ b/drivers/bus/mhi/sahara/sahara.c
@@ -415,6 +415,73 @@ static struct sahara_ctrl_trng_data *sahara_ctrl_trng_get(struct device *dev)
return ct;
}
+static ssize_t ddr_training_data_read(struct file *filp, struct kobject *kobj,
+ const struct bin_attribute *attr, char *buf,
+ loff_t offset, size_t count)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct sahara_ctrl_trng_data *ct;
+ size_t available;
+
+ ct = sahara_ctrl_trng_get(dev);
+ if (!ct)
+ return -ENODEV;
+
+ mutex_lock(&ct->lock);
+
+ /* No data yet or offset past end */
+ if (!ct->data || offset >= ct->size) {
+ mutex_unlock(&ct->lock);
+ return 0;
+ }
+
+ available = ct->size - offset;
+ count = min(count, available);
+ memcpy(buf, (u8 *)ct->data + offset, count);
+
+ mutex_unlock(&ct->lock);
+
+ return count;
+}
+
+static const struct bin_attribute ddr_training_data_attr = {
+ .attr = {
+ .name = "ddr_training_data",
+ .mode = 0444,
+ },
+ .read = ddr_training_data_read,
+};
+
+static void sahara_sysfs_devres_release(struct device *dev, void *res)
+{
+ device_remove_bin_file(dev, &ddr_training_data_attr);
+}
+
+static void sahara_sysfs_create(struct mhi_device *mhi_dev)
+{
+ struct device *dev = &mhi_dev->mhi_cntrl->mhi_dev->dev;
+ void *cookie;
+ int ret;
+
+ if (devres_find(dev, sahara_sysfs_devres_release, NULL, NULL))
+ return;
+
+ ret = device_create_bin_file(dev, &ddr_training_data_attr);
+ if (ret) {
+ dev_warn(&mhi_dev->dev,
+ "Failed to create DDR training sysfs node (%d)\n", ret);
+ return;
+ }
+
+ cookie = devres_alloc(sahara_sysfs_devres_release, 1, GFP_KERNEL);
+ if (!cookie) {
+ device_remove_bin_file(dev, &ddr_training_data_attr);
+ return;
+ }
+
+ devres_add(dev, cookie);
+}
+
static int sahara_find_image(struct sahara_context *context, u32 image_id)
{
char *fw_path;
@@ -1272,6 +1339,8 @@ static int sahara_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_
return ret;
}
+ sahara_sysfs_create(mhi_dev);
+
return 0;
}
--
2.34.1