All of lore.kernel.org
 help / color / mirror / Atom feed
From: yi1.li@linux.intel.com
To: 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, mcgrof@kernel.org, atull@kernel.org
Cc: linux-kernel@vger.kernel.org, linux-fpga@vger.kernel.org,
	Yi Li <yi1.li@linux.intel.com>
Subject: [PATCHv1 1/2] firmware: Add streaming support
Date: Fri, 21 Apr 2017 14:22:21 -0500	[thread overview]
Message-ID: <1492802542-1408-2-git-send-email-yi1.li@linux.intel.com> (raw)
In-Reply-To: <1492802542-1408-1-git-send-email-yi1.li@linux.intel.com>

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

Load firmware in multiple chucks(4KB) instead of the whole big firmware file
at once. The streaming support is added in the driver_data_request_sync API
based on Luis R. Rodriguez's 20170329-driver-data-v2-try3 branch.

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

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index cc3c224..beecbf5 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -569,6 +569,73 @@ fw_get_filesystem_firmware(struct device *device, struct firmware_buf *buf)
 	return rc;
 }
 
+static int
+fw_stream_filesystem_firmware(struct device *device, struct firmware_buf *buf,
+			      size_t offset, size_t length, char **path)
+{
+	int i, len;
+	int rc = 0;
+	struct file *file;
+
+	buf->size = 0;
+	if (!buf->data) {
+		buf->data = vmalloc(length);
+		if (!buf->data) {
+			rc = -ENOMEM;
+			return rc;
+		}
+	}
+
+	/* skip the repeating folder searching */
+	if (*path) {
+		file = filp_open(*path, O_RDONLY, 0);
+		if (IS_ERR(file)) {
+			rc = -ENOENT;
+			return rc;
+		}
+
+		buf->size = kernel_read(file, offset, (char *)buf->data,
+					length);
+		fput(file);
+		return rc;
+	}
+
+	dev_info(device, "search %s in the folder\n", buf->fw_id);
+	*path = __getname();
+	if (!*path)
+		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",
+			       fw_path[i], buf->fw_id);
+		if (len >= PATH_MAX) {
+			rc = -ENAMETOOLONG;
+			break;
+		}
+
+		file = filp_open(*path, O_RDONLY, 0);
+		if (IS_ERR(file)) {
+			rc = -ENOENT;
+			continue;
+		}
+
+		buf->size = kernel_read(file, offset, (char *)buf->data,
+					length);
+		rc = 0;
+		fput(file);
+		break;
+	}
+
+	if (rc)
+		dev_err(device, "loading %s failed with error %d\n",
+			*path, rc);
+	return rc;
+}
+
 /* firmware holds the ownership of pages */
 static void firmware_free_data(const struct firmware *fw)
 {
@@ -1310,6 +1377,46 @@ _request_firmware_prepare(struct firmware **firmware_p, const char *name,
 	return 1; /* need to load */
 }
 
+static int
+_stream_firmware(const struct firmware **firmware_p, const char *name,
+		 struct driver_data_params *data_params,
+		 struct device *device)
+{
+	int ret;
+	struct firmware *fw = NULL;
+	size_t offset = data_params->req_params.streaming_reqs.offset;
+	size_t buf_size = data_params->req_params.streaming_reqs.buf_size;
+
+	if ((!firmware_p) || (!name || name[0] == '\0')) {
+		dev_err(device, "invalid firmware pointer or file name\n");
+		return -EINVAL;
+	}
+
+	if (!*firmware_p) {
+		ret = _request_firmware_prepare(&fw, name, device, data_params);
+		if (ret <= 0) {
+			dev_err(device, "%s: failed %d\n",
+				__func__, ret);
+		}
+	} else {
+		fw = (struct firmware *)*firmware_p;
+	}
+
+	ret = fw_stream_filesystem_firmware(device, fw->priv, offset, buf_size,
+				data_params->req_params.streaming_reqs.path);
+	if (ret) {
+		if (!driver_data_param_optional(&data_params->req_params))
+			dev_warn(device,
+				 "streaming %s failed with error %d\n",
+				 name, ret);
+	} else {
+		ret = assign_firmware_buf(fw, device, data_params);
+	}
+	*firmware_p = fw;
+
+	return ret;
+}
+
 /* called from request_firmware() and request_firmware_work_func() */
 static int
 _request_firmware(const struct firmware **firmware_p, const char *name,
@@ -1577,7 +1684,17 @@ int driver_data_request_sync(const char *name,
 	__module_get(sync_reqs->module);
 	get_device(device);
 
-	ret = _request_firmware(&driver_data, name, &params, device);
+	if (req_params->streaming_reqs.streaming) {
+		/* For streaming, driver_data is recycled and kept */
+		if (!req_params->keep)
+			return -EINVAL;
+
+		ret = _stream_firmware(req_params->streaming_reqs.driver_data,
+				       name, &params, device);
+		driver_data = *req_params->streaming_reqs.driver_data;
+	} else {
+		ret = _request_firmware(&driver_data, name, &params, device);
+	}
 	if (ret && driver_data_param_optional(req_params))
 		ret = driver_data_sync_opt_call_cb(req_params);
 	else
diff --git a/include/linux/driver_data.h b/include/linux/driver_data.h
index fda1e71..ee485a5 100644
--- a/include/linux/driver_data.h
+++ b/include/linux/driver_data.h
@@ -62,6 +62,16 @@ struct driver_data_reqs {
 	gfp_t gfp;
 };
 
+struct driver_data_streaming_reqs {
+	bool streaming;
+	char **path;
+	size_t offset;
+	size_t buf_size;
+	const struct firmware **driver_data;
+	void *opt_ctx1;
+	void *opt_ctx2;
+};
+
 /**
  * struct driver_data_req_params - driver data request parameters
  * @optional: if true it is not a hard requirement by the caller that this
@@ -93,6 +103,8 @@ struct driver_data_reqs {
  *	digit will be placed in the middle, followed by the @api_name_postfix.
  * @sync_reqs: synchronization requirements
  *
+ * @streaming_reqs: streaming requirements
+ *
  * 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
  * caller.
@@ -107,6 +119,7 @@ struct driver_data_req_params {
 	const char *api_name_postfix;
 	struct driver_data_reqs sync_reqs;
 	const union driver_data_cbs cbs;
+	struct driver_data_streaming_reqs streaming_reqs;
 };
 
 /*
-- 
2.7.4

  reply	other threads:[~2017-04-21 19:27 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-04-21 19:22 [PATCHv1 0/2] Add streaming support for base firmware and fpga-mgr yi1.li
2017-04-21 19:22 ` yi1.li [this message]
2017-04-21 19:22 ` [PATCHv1 2/2] fpga-mgr: add streaming support yi1.li

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=1492802542-1408-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.