On 5/12/2026 7:49 PM, Manivannan Sadhasivam wrote:
On Thu, Apr 16, 2026 at 07:39:48PM +0530, Kishore Batta wrote:
DDR training data captured during Sahara command mode needs to be
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.

Expose the captured DDR training data via a read-only binary sysfs
attribute on the MHI controller device:

/sys/bus/mhi/devices/<mhi_cntrl>/ddr_training_data

The sysfs read callback serves data directly from controller scoped storage
and protects access with the controller training data lock. The attribute
lifetime is tied to the controller device via devres, allowing the data to
remain readable after Sahara channel teardown and ensuring automatic
cleanup when controller device is removed.

Userspace flow:
1. For each controller device, userspace reads the ddr_training_data sysfs
    attribute.
2. If the read returns non-zero data, userspace persists it using a
    serial specific filename (for example, mdmddr_0x<serial_no>.mbn).
3. On subsequent boots, the Sahara driver attempts to load this serial
    specific DDR training image before falling back to the default
    training image, restoring DDR calibration data and avoiding retraining.

Add ABI documentation for the DDR training data sysfs attribute exposed by
Sahara MHI driver.

Signed-off-by: Kishore Batta <[email protected]>
---
  .../ABI/testing/sysfs-bus-mhi-ddr_training_data    | 19 ++++++
  drivers/bus/mhi/host/clients/sahara/sahara.c       | 69 ++++++++++++++++++++++
  2 files changed, 88 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-bus-mhi-ddr_training_data 
b/Documentation/ABI/testing/sysfs-bus-mhi-ddr_training_data
new file mode 100644
index 
0000000000000000000000000000000000000000..810b487b5a5fdba133d81255f9879844e3938a10
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-mhi-ddr_training_data
@@ -0,0 +1,19 @@
+What:                   /sys/bus/mhi/devices/<mhi-cntrl>/ddr_training_data
+
+Date:                   March 2026
+
+Contact:                Kishore Batta <[email protected]>
+
+Description:            Contains the DDR training data for the Qualcomm device
+                        connected. MHI driver populates different controller
+                        nodes for each device. The DDR training data is exposed
+                        to userspace to read and save the training data file to
+                        the filesystem. In the subsequent boot up of the 
device,
+                        the training data is restored from host to device
+                        optimizing the boot up time of the device.
+
+Usage:                  Example for reading DDR training data:
+                        cat /sys/bus/mhi/devices/mhi0/ddr_training_data
+
+Permissions:            The file permissions are set to 0444 allowing read
+                        access.
diff --git a/drivers/bus/mhi/host/clients/sahara/sahara.c 
b/drivers/bus/mhi/host/clients/sahara/sahara.c
index 
07bc743aa061dd2fa85638067d494562152474e3..fef5dc1d8884133397d204f23361584fd1d9b075
 100644
--- a/drivers/bus/mhi/host/clients/sahara/sahara.c
+++ b/drivers/bus/mhi/host/clients/sahara/sahara.c
@@ -273,6 +273,73 @@ static struct sahara_cntrl_training_data 
*sahara_cntrl_training_get(struct devic
        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_cntrl_training_data *ct;
+       size_t available;
+
+       ct = sahara_cntrl_training_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,
+};
You can simplify the attribute creation with BIN_ATTR_RO().
ACK. Will use BIN_ATTR_RO() in v6 patch series.

+
+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;
So you are expecting this helper to be called mutiple times without teardown?

- Mani
Yes. This helper can be invoked multiple times for the same controller device without a full teardown. In this case, Sahara probe can be re-entered across events like subsystem restart/warm resets, while underlying controller device(mhi_cntrl->mhi_dev->dev) persists and is not re-created. Since this sysfs node is associated with the controller device (not a single probe instance), it should only be created once per controller lifetime. The devres_find() check is used to make the helper idempotent and avoid duplicate sysfs creation when probe path is re-entered. The sysfs lifetime is intentionally tied to the controller device, so it is only removed when the device itself is released.

Reply via email to