Re: [PATCH v5 7/7] bus: mhi: Expose DDR training data via controller sysfs

From: Manivannan Sadhasivam

Date: Tue May 12 2026 - 11:04:57 EST


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 <kishore.batta@xxxxxxxxxxxxxxxx>
> ---
> .../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 <kishore.batta@xxxxxxxxxxxxxxxx>
> +
> +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().

> +
> +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

--
மணிவண்ணன் சதாசிவம்