All of lore.kernel.org
 help / color / mirror / Atom feed
From: yi1.li@linux.intel.com
To: mcgrof@kernel.org, atull@kernel.org, gregkh@linuxfoundation.org,
	wagi@monom.org, dwmw2@infradead.org, rafal@milecki.pl,
	arend.vanspriel@broadcom.com, rjw@rjwysocki.net,
	moritz.fischer@ettus.com, pmladek@suse.com,
	johannes.berg@intel.com, emmanuel.grumbach@intel.com,
	luciano.coelho@intel.com, kvalo@codeaurora.org, luto@kernel.org,
	takahiro.akashi@linaro.org, dhowells@redhat.com,
	pjones@redhat.com
Cc: linux-kernel@vger.kernel.org, linux-fpga@vger.kernel.org,
	Yi Li <yi1.li@linux.intel.com>
Subject: [PATCHv2 1/3] firmware: Add streaming support for driver_data_request_sync API
Date: Sat, 20 May 2017 01:49:06 -0500	[thread overview]
Message-ID: <1495262948-1106-2-git-send-email-yi1.li@linux.intel.com> (raw)
In-Reply-To: <1495262948-1106-1-git-send-email-yi1.li@linux.intel.com>

From: Yi Li <yi1.li@linux.intel.com>

By setting the driver_data_req_params req flag of DRIVER_DATA_REQ_STREAMING
and DRIVER_DATA_REQ_NO_CACHE, caller can streaming firmware image to the
pre-allocated buffer in small trunks. Caller also need to setup the
img_offset pointer and firmware image **path to avoid searching the
firmware folders repeatly. Details and examples please refer to the
trigger_config_stream function of test_driver_data.c and
fpga_mgr_firmware_stream function of fpga_mgr.c.

Signed-off-by: Yi Li <yi1.li@linux.intel.com>
---
 drivers/base/firmware_class.c | 94 +++++++++++++++++++++++++++++++++++++------
 include/linux/driver_data.h   | 10 +++++
 2 files changed, 91 insertions(+), 13 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 461c7c2..9a63124 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -152,6 +152,20 @@ struct driver_data_params {
 			     DRIVER_DATA_PRIV_REQ_FALLBACK_UEVENT,	\
 	}
 
+#define __DATA_REQ_FIRMWARE_STREAM_BUF(buf, size, offset, path)		\
+	.req_params = {							\
+		.reqs = DRIVER_DATA_REQ_NO_CACHE |			\
+			DRIVER_DATA_REQ_STREAMING,			\
+		.alloc_buf = buf,					\
+		.alloc_buf_size = size,					\
+		.img_offset = offset,					\
+		.path = path,						\
+	},								\
+	.priv_params = {						\
+		.priv_reqs = DRIVER_DATA_PRIV_REQ_FALLBACK |		\
+			     DRIVER_DATA_PRIV_REQ_FALLBACK_UEVENT,	\
+	}
+
 #define __DATA_REQ_FIRMWARE_NOWAIT(module, uevent, gfp, async_cb, async_ctx) \
 	.req_params = {							\
 		.hold_module = module,					\
@@ -180,6 +194,8 @@ struct driver_data_params {
 	(!!((params)->priv_reqs & DRIVER_DATA_PRIV_REQ_FALLBACK_UEVENT))
 #define driver_data_param_nocache(params)	\
 	(!!((params)->reqs & DRIVER_DATA_REQ_NO_CACHE))
+#define driver_data_param_streaming(params)	\
+	(!!((params)->reqs & DRIVER_DATA_REQ_STREAMING))
 
 #define driver_data_param_optional(params)	\
 	(!!((params)->reqs & DRIVER_DATA_REQ_OPTIONAL))
@@ -625,14 +641,18 @@ module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644);
 MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path");
 
 static int
-fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
+fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf,
+			   struct driver_data_params *data_params)
 {
 	loff_t size;
 	int i, len;
 	int rc = -ENOENT;
-	char *path;
+	char **path;
+	char *local_path = NULL;
+	loff_t *offset = data_params->req_params.img_offset;
 	enum kernel_read_file_id id = READING_FIRMWARE;
 	size_t msize = INT_MAX;
+	struct file *file;
 
 	/* Already populated data member means we're loading into a buffer */
 	if (buf->data) {
@@ -640,16 +660,58 @@ fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
 		msize = buf->allocated_size;
 	}
 
-	path = __getname();
-	if (!path)
+	buf->size = 0;
+
+	/* Save path for streaming case */
+	if (driver_data_param_streaming(&data_params->req_params)) {
+		path = data_params->req_params.path;
+		if (!path) {
+			dev_err(device, "req_params.path not initialized\n");
+			rc = -ENOENT;
+			return rc;
+		}
+	} else {
+		path = &local_path;
+	}
+
+streaming:
+	/* Skip the repeating folder searching, direct to load*/
+	if (driver_data_param_streaming(&data_params->req_params) && *path) {
+		if (!offset) {
+			dev_err(device, "img_offset not initialized\n");
+			rc = -ENOENT;
+			return rc;
+		}
+
+		file = filp_open(*path, O_RDONLY, 0);
+		if (IS_ERR(file)) {
+			rc = -ENOENT;
+			return rc;
+		}
+
+		buf->size = kernel_read(file, *offset, (char *)buf->data,
+					msize);
+		fput(file);
+		if (buf->size < msize) {
+			fw_state_done(&buf->fw_st);
+			__putname(*path);
+		}
+		return 0;
+	}
+
+	/* First time to load the firmware */
+	*path = __getname();
+	if (!*path) {
+		dev_err(device, "cannot getname\n");
 		return -ENOMEM;
+	}
 
 	for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
 		/* skip the unset customized path */
 		if (!fw_path[i][0])
 			continue;
 
-		len = snprintf(path, PATH_MAX, "%s/%s",
+		len = snprintf(*path, PATH_MAX, "%s/%s",
 			       fw_path[i], buf->fw_id);
 		if (len >= PATH_MAX) {
 			rc = -ENAMETOOLONG;
@@ -657,23 +719,29 @@ fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
 		}
 
 		buf->size = 0;
-		rc = kernel_read_file_from_path(path, &buf->data, &size, msize,
-						id);
+		rc = kernel_read_file_from_path(*path, &buf->data, &size,
+						msize, id);
 		if (rc) {
-			if (rc == -ENOENT)
+			if (driver_data_param_streaming(&data_params->req_params)
+			    && (rc == -EFBIG)) {
+				rc = 0;
+				goto streaming;
+			} else if (rc == -ENOENT)
 				dev_dbg(device, "loading %s failed with error %d\n",
-					 path, rc);
+					*path, rc);
 			else
 				dev_warn(device, "loading %s failed with error %d\n",
-					 path, rc);
+					 *path, rc);
 			continue;
 		}
 		dev_dbg(device, "direct-loading %s\n", buf->fw_id);
 		buf->size = size;
-		fw_state_done(&buf->fw_st);
+		if (buf->size < msize) {
+			fw_state_done(&buf->fw_st);
+			__putname(*path);
+		}
 		break;
 	}
-	__putname(path);
 
 	return rc;
 }
@@ -1466,7 +1534,7 @@ _request_firmware(const struct firmware **firmware_p, const char *name,
 		goto out;
 	}
 
-	ret = fw_get_filesystem_firmware(device, fw->priv);
+	ret = fw_get_filesystem_firmware(device, fw->priv, data_params);
 	if (ret) {
 		if (!driver_data_param_optional(&data_params->req_params))
 			dev_warn(device,
diff --git a/include/linux/driver_data.h b/include/linux/driver_data.h
index a3a5fbe..e9e828a 100644
--- a/include/linux/driver_data.h
+++ b/include/linux/driver_data.h
@@ -120,12 +120,16 @@ union driver_data_cbs {
  * @DRIVER_DATA_REQ_NO_CACHE: indicates that the driver data request
  *	should not set up and use the internal caching mechanism to assist
  *	drivers from fetching driver data at resume time after suspend.
+ * @DRIVER_DATA_REQ_STREAMING: indicates that the driver data request
+ *	is in the streaming mode, the buffer is allocated outside the
+ *	firmware driver.
  */
 enum driver_data_reqs {
 	DRIVER_DATA_REQ_OPTIONAL			= 1 << 0,
 	DRIVER_DATA_REQ_KEEP				= 1 << 1,
 	DRIVER_DATA_REQ_USE_API_VERSIONING		= 1 << 2,
 	DRIVER_DATA_REQ_NO_CACHE			= 1 << 3,
+	DRIVER_DATA_REQ_STREAMING			= 1 << 4,
 };
 
 /**
@@ -147,6 +151,10 @@ enum driver_data_reqs {
  * @alloc_buf: pointer of pointer to the buffer area allocated by the caller
  *	so we can place the respective driver data
  * @alloc_buf_size: size of the @alloc_buf
+ * @img_offset: optional for streaming mode, define which offset address the
+ *	firmware should be read from
+ * @path: optional for streaming mode, save the file path to avoid search over
+ *	and over again
  *
  * This data structure is intended to carry all requirements and specifications
  * required to complete the task to get the requested driver date file to the
@@ -162,6 +170,8 @@ struct driver_data_req_params {
 	const union driver_data_cbs cbs;
 	void **alloc_buf;
 	size_t alloc_buf_size;
+	loff_t *img_offset;
+	char **path;
 };
 
 /*
-- 
2.7.4

  reply	other threads:[~2017-05-20  6:55 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-05-20  6:49 [PATCHv2 0/3] Add streaming support to driver_data API yi1.li
2017-05-20  6:49 ` yi1.li [this message]
2017-05-20  6:49 ` [PATCHv2 2/3] test: add streaming test to driver_data tester yi1.li
2017-05-20  6:49 ` [PATCHv2 3/3] fpga_mgr: Add streaming support through the new driver_data API yi1.li
2017-05-22 21:09   ` Alan Tull
2017-05-23  4:11     ` Li, Yi
2017-05-23 15:21       ` Alan Tull
2017-05-23 15:25         ` Alan Tull
2017-05-24 13:25           ` Li, Yi
2017-05-24 13:45           ` Li, Yi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1495262948-1106-2-git-send-email-yi1.li@linux.intel.com \
    --to=yi1.li@linux.intel.com \
    --cc=arend.vanspriel@broadcom.com \
    --cc=atull@kernel.org \
    --cc=dhowells@redhat.com \
    --cc=dwmw2@infradead.org \
    --cc=emmanuel.grumbach@intel.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=johannes.berg@intel.com \
    --cc=kvalo@codeaurora.org \
    --cc=linux-fpga@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luciano.coelho@intel.com \
    --cc=luto@kernel.org \
    --cc=mcgrof@kernel.org \
    --cc=moritz.fischer@ettus.com \
    --cc=pjones@redhat.com \
    --cc=pmladek@suse.com \
    --cc=rafal@milecki.pl \
    --cc=rjw@rjwysocki.net \
    --cc=takahiro.akashi@linaro.org \
    --cc=wagi@monom.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.