On Wed, Jul 01, 2026 at 04:07:41PM +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. >
If this training data is RO, then what is the use of exposing it to userspace? - Mani > 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 | 62 > ++++++++++++++++++++++ > 2 files changed, 81 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..72ac751c302a98448b5756c9feb438647bd0ce4b > 100644 > --- a/drivers/bus/mhi/host/clients/sahara/sahara.c > +++ b/drivers/bus/mhi/host/clients/sahara/sahara.c > @@ -273,6 +273,66 @@ 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 BIN_ATTR_RO(ddr_training_data, 0); > + > +static void sahara_sysfs_devres_release(struct device *dev, void *res) > +{ > + device_remove_bin_file(dev, &bin_attr_ddr_training_data); > +} > + > +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, &bin_attr_ddr_training_data); > + 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, &bin_attr_ddr_training_data); > + return; > + } > + > + devres_add(dev, cookie); > +} > + > static int sahara_find_image(struct sahara_context *context, u32 image_id) > { > char *fw_path; > @@ -1131,6 +1191,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 > -- மணிவண்ணன் சதாசிவம்
