[PATCH v1 07/12] drivers: soc: qcom: Add sysfs support for DDR training data in Sahara.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add the Sahara training data structure and populate the DDR training data
sysfs node. During device boot, the device performs DDR training and sends
the training data back to the host once complete. The host exposes this
data to userspace via the sysfs interface. The "ddr_training_data" sysfs
node will be present in the MHI controller node (e.g., mhi0, mhi1) along
with other existing sysfs nodes at /sys/bus/mhi/devices/mhi*/.

When the host reboots, a userspace service is triggered via an udev rule to
read the training data from the sysfs entry. The service then copies the
valid training data to the image firmware filesystem. This change includes
the structures added for DDR training data and embeds them in the
sahara_dev_driver_data structure. It also populates the sysfs attributes
for DDR training data.

Userspace service - https://github.com/qualcomm/csm-utils

Signed-off-by: Kishore Batta <kishore.batta@xxxxxxxxxxxxxxxx>
---
 drivers/soc/qcom/sahara/sahara.c | 109 ++++++++++++++++++++++++++++++-
 1 file changed, 108 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/qcom/sahara/sahara.c b/drivers/soc/qcom/sahara/sahara.c
index b07f6bd0e19f..df103473af3a 100644
--- a/drivers/soc/qcom/sahara/sahara.c
+++ b/drivers/soc/qcom/sahara/sahara.c
@@ -60,6 +60,12 @@
 #define SAHARA_MEM_DEBUG64_LENGTH	0x18
 #define SAHARA_MEM_READ64_LENGTH	0x18
 
+struct sahara_dev_trng_data {
+	void *trng_data;
+	u64 trng_data_sz;
+	bool receiving_trng_data;
+};
+
 struct sahara_packet {
 	__le32 cmd;
 	__le32 length;
@@ -177,6 +183,58 @@ struct sahara_context {
 	bool				is_mem_dump_mode;
 };
 
+struct sahara_dev_driver_data {
+	struct bin_attribute ddr_attr;
+	struct sahara_dev_trng_data *sdev;
+	struct sahara_context *context;
+};
+
+/* Exposes DDR training data via sysfs binary attribute for user-space access */
+static ssize_t ddr_training_read(struct file *filp, struct kobject *kobj,
+				 const struct bin_attribute *attr, char *buf,
+				 loff_t offset, size_t count)
+{
+	struct sahara_dev_driver_data *sahara_data;
+	struct sahara_dev_trng_data *sdev;
+	size_t data_size;
+
+	sahara_data = container_of(attr, struct sahara_dev_driver_data, ddr_attr);
+
+	if (!sahara_data)
+		return -EIO;
+
+	sdev = sahara_data->sdev;
+
+	if (!sdev || !sdev->trng_data)
+		return -EIO;
+
+	data_size = attr->size;
+
+	if (data_size == 0)
+		return 0;
+
+	if (offset >= data_size)
+		return -EINVAL;
+
+	if (count > data_size - offset)
+		count = data_size - offset;
+
+	/* Copy the training data into the buffer */
+	memcpy(buf, (sdev->trng_data + offset), count);
+
+	/* Free memory after last read */
+	if (offset + count >= data_size) {
+		kfree(sdev->trng_data);
+		sdev->trng_data = NULL;
+		kfree(sdev);
+		sdev = NULL;
+		kfree(sahara_data);
+		sahara_data = NULL;
+	}
+
+	return count;
+}
+
 static int sahara_find_image(struct sahara_context *context, u32 image_id)
 {
 	int ret;
@@ -703,11 +761,42 @@ static void sahara_dump_processing(struct work_struct *work)
 	sahara_send_reset(context);
 }
 
+static int sahara_dev_populate_attribute(struct sahara_dev_driver_data *sahara_data)
+{
+	int ret;
+	struct sahara_context *context = sahara_data->context;
+
+	/* DDR training data attribute */
+	sahara_data->ddr_attr.attr.name = "ddr_training_data";
+	sahara_data->ddr_attr.attr.mode = 0444;
+	sahara_data->ddr_attr.read = ddr_training_read;
+
+	/* Size is populated during device bootup */
+	sahara_data->ddr_attr.size = 0;
+	sahara_data->ddr_attr.write = NULL;
+
+	/*
+	 * Remove any existing sysfs binary attribute to avoid stale entries
+	 * during warm boot or reinitialization. This ensures clean state before
+	 * re-creating the attribute.
+	 */
+	device_remove_bin_file(&context->mhi_dev->mhi_cntrl->mhi_dev->dev,
+			       &sahara_data->ddr_attr);
+
+	/* Create the binary attribute */
+	ret = device_create_bin_file(&context->mhi_dev->mhi_cntrl->mhi_dev->dev,
+				     &sahara_data->ddr_attr);
+
+	return ret;
+}
+
 static int sahara_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id)
 {
 	struct sahara_context *context;
 	int ret;
 	int i;
+	struct sahara_dev_driver_data *sahara_data;
+	struct sahara_dev_trng_data *sdev;
 
 	context = devm_kzalloc(&mhi_dev->dev, sizeof(*context), GFP_KERNEL);
 	if (!context)
@@ -717,6 +806,17 @@ static int sahara_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_
 	if (!context->rx)
 		return -ENOMEM;
 
+	sahara_data = kzalloc(sizeof(*sahara_data), GFP_KERNEL);
+	if (!sahara_data)
+		return -ENOMEM;
+
+	sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
+	if (!sdev)
+		return -ENOMEM;
+
+	sahara_data->context = context;
+	sahara_data->sdev = sdev;
+
 	/*
 	 * AIC100 defines SAHARA_TRANSFER_MAX_SIZE as the largest value it
 	 * will request for READ_DATA. This is larger than
@@ -749,7 +849,14 @@ static int sahara_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_
 		return -EINVAL;
 
 	context->active_image_id = SAHARA_IMAGE_ID_NONE;
-	dev_set_drvdata(&mhi_dev->dev, context);
+	dev_set_drvdata(&mhi_dev->dev, sahara_data);
+
+	ret = sahara_dev_populate_attribute(sahara_data);
+	if (ret) {
+		dev_err(&context->mhi_dev->dev,
+			"Failed to populate bin attribute: %d\n", ret);
+		return ret;
+	}
 
 	ret = mhi_prepare_for_transfer(mhi_dev);
 	if (ret)
-- 
2.34.1





[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [Linux for Sparc]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux