Linux ARM-MSM sub-architecture
 help / color / mirror / Atom feed
From: "Thomas Weißschuh" <linux@weissschuh.net>
To: Hemant Kumar <hemantk@codeaurora.org>,
	Manivannan Sadhasivam <mani@kernel.org>
Cc: "Thomas Weißschuh" <linux@weissschuh.net>,
	linux-kernel@vger.kernel.org, mhi@lists.linux.dev,
	linux-arm-msm@vger.kernel.org,
	"Mario Limonciello" <Mario.Limonciello@amd.com>,
	"Richard Hughes" <hughsient@gmail.com>
Subject: [RFC] bus: mhi: core: Load firmware asynchronous
Date: Fri, 10 Dec 2021 17:16:45 +0100	[thread overview]
Message-ID: <20211210161645.10925-1-linux@weissschuh.net> (raw)

This gives userspace the possibility to provide the firehose bootloader
via the sysfs-firmware-API instead of having to modify the global
firmware loadpath.

Signed-off-by: Thomas Weißschuh <linux@weissschuh.net>

---

Please note that this is not tested yet, as I don't have access to a matching
firmware file.
This submission is to gather general feedback from the maintainers and then
Richard will do the actual testing, while I'll do the development.

This patch is should not have any impact beyond moving from request_firmware()
to request_firmware_nowait() and the involved code reshuffle.

---
 drivers/bus/mhi/core/boot.c | 159 +++++++++++++++++++++++-------------
 1 file changed, 101 insertions(+), 58 deletions(-)

diff --git a/drivers/bus/mhi/core/boot.c b/drivers/bus/mhi/core/boot.c
index 74295d3cc662..b0576ffc69c6 100644
--- a/drivers/bus/mhi/core/boot.c
+++ b/drivers/bus/mhi/core/boot.c
@@ -18,6 +18,17 @@
 #include <linux/wait.h>
 #include "internal.h"
 
+struct mhi_fw_load_callback_ctx {
+	const char *fw_name;
+	struct mhi_controller *mhi_cntrl;
+};
+
+enum mhi_fw_load_status {
+	MHI_FW_LOAD_READY_STATE,
+	MHI_FW_ERROR_READY_STATE,
+	MHI_FW_ERROR_FW_LOAD,
+};
+
 /* Setup RDDM vector table for RDDM transfer and program RXVEC */
 void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
 		      struct image_info *img_info)
@@ -386,55 +397,53 @@ static void mhi_firmware_copy(struct mhi_controller *mhi_cntrl,
 	}
 }
 
-void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
+static void mhi_fw_load_finish(struct mhi_controller *mhi_cntrl, enum mhi_fw_load_status status)
 {
-	const struct firmware *firmware = NULL;
 	struct device *dev = &mhi_cntrl->mhi_dev->dev;
-	const char *fw_name;
-	void *buf;
-	dma_addr_t dma_addr;
-	size_t size;
-	int i, ret;
+	int ret;
 
-	if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
-		dev_err(dev, "Device MHI is not in valid state\n");
-		return;
+	switch (status) {
+	case MHI_FW_LOAD_READY_STATE:
+		break;
+	case MHI_FW_ERROR_READY_STATE:
+		goto error_ready_state;
+	case MHI_FW_ERROR_FW_LOAD:
+		goto error_fw_load;
 	}
 
-	/* save hardware info from BHI */
-	ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_SERIALNU,
-			   &mhi_cntrl->serial_number);
-	if (ret)
-		dev_err(dev, "Could not capture serial number via BHI\n");
-
-	for (i = 0; i < ARRAY_SIZE(mhi_cntrl->oem_pk_hash); i++) {
-		ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_OEMPKHASH(i),
-				   &mhi_cntrl->oem_pk_hash[i]);
-		if (ret) {
-			dev_err(dev, "Could not capture OEM PK HASH via BHI\n");
-			break;
-		}
+	/* Transitioning into MHI RESET->READY state */
+	ret = mhi_ready_state_transition(mhi_cntrl);
+	if (ret) {
+		dev_err(dev, "MHI did not enter READY state\n");
+		goto error_ready_state;
 	}
 
-	/* wait for ready on pass through or any other execution environment */
-	if (!MHI_FW_LOAD_CAPABLE(mhi_cntrl->ee))
-		goto fw_load_ready_state;
-
-	fw_name = (mhi_cntrl->ee == MHI_EE_EDL) ?
-		mhi_cntrl->edl_image : mhi_cntrl->fw_image;
+	dev_info(dev, "Wait for device to enter SBL or Mission mode\n");
+	return;
 
-	if (!fw_name || (mhi_cntrl->fbc_download && (!mhi_cntrl->sbl_size ||
-						     !mhi_cntrl->seg_len))) {
-		dev_err(dev,
-			"No firmware image defined or !sbl_size || !seg_len\n");
-		goto error_fw_load;
+error_ready_state:
+	if (mhi_cntrl->fbc_download) {
+		mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image);
+		mhi_cntrl->fbc_image = NULL;
 	}
 
-	ret = request_firmware(&firmware, fw_name, dev);
-	if (ret) {
-		dev_err(dev, "Error loading firmware: %d\n", ret);
-		goto error_fw_load;
-	}
+error_fw_load:
+	mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR;
+	wake_up_all(&mhi_cntrl->state_event);
+}
+
+static void mhi_fw_load_callback(const struct firmware *firmware, void *context)
+{
+	struct mhi_fw_load_callback_ctx *ctx = context;
+	const char *fw_name = ctx->fw_name;
+	struct mhi_controller *mhi_cntrl = ctx->mhi_cntrl;
+	struct device *dev = &mhi_cntrl->mhi_dev->dev;
+	dma_addr_t dma_addr;
+	size_t size;
+	void *buf;
+	int ret;
+
+	kfree(context);
 
 	size = (mhi_cntrl->fbc_download) ? mhi_cntrl->sbl_size : firmware->size;
 
@@ -446,7 +455,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
 				 GFP_KERNEL);
 	if (!buf) {
 		release_firmware(firmware);
-		goto error_fw_load;
+		mhi_fw_load_finish(mhi_cntrl, MHI_FW_ERROR_FW_LOAD);
 	}
 
 	/* Download image using BHI */
@@ -458,13 +467,13 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
 	if (ret) {
 		dev_err(dev, "MHI did not load image over BHI, ret: %d\n", ret);
 		release_firmware(firmware);
-		goto error_fw_load;
+		mhi_fw_load_finish(mhi_cntrl, MHI_FW_ERROR_FW_LOAD);
 	}
 
 	/* Wait for ready since EDL image was loaded */
 	if (fw_name == mhi_cntrl->edl_image) {
 		release_firmware(firmware);
-		goto fw_load_ready_state;
+		mhi_fw_load_finish(mhi_cntrl, MHI_FW_LOAD_READY_STATE);
 	}
 
 	write_lock_irq(&mhi_cntrl->pm_lock);
@@ -480,7 +489,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
 					   firmware->size);
 		if (ret) {
 			release_firmware(firmware);
-			goto error_fw_load;
+			mhi_fw_load_finish(mhi_cntrl, MHI_FW_ERROR_FW_LOAD);
 		}
 
 		/* Load the firmware into BHIE vec table */
@@ -489,26 +498,60 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
 
 	release_firmware(firmware);
 
-fw_load_ready_state:
-	/* Transitioning into MHI RESET->READY state */
-	ret = mhi_ready_state_transition(mhi_cntrl);
-	if (ret) {
-		dev_err(dev, "MHI did not enter READY state\n");
-		goto error_ready_state;
+	mhi_fw_load_finish(mhi_cntrl, MHI_FW_LOAD_READY_STATE);
+}
+
+void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl)
+{
+	struct device *dev = &mhi_cntrl->mhi_dev->dev;
+	struct mhi_fw_load_callback_ctx *cb_ctx;
+	const char *fw_name;
+	int i, ret;
+
+	if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
+		dev_err(dev, "Device MHI is not in valid state\n");
+		return;
 	}
 
-	dev_info(dev, "Wait for device to enter SBL or Mission mode\n");
-	return;
+	/* save hardware info from BHI */
+	ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_SERIALNU,
+			   &mhi_cntrl->serial_number);
+	if (ret)
+		dev_err(dev, "Could not capture serial number via BHI\n");
 
-error_ready_state:
-	if (mhi_cntrl->fbc_download) {
-		mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image);
-		mhi_cntrl->fbc_image = NULL;
+	for (i = 0; i < ARRAY_SIZE(mhi_cntrl->oem_pk_hash); i++) {
+		ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, BHI_OEMPKHASH(i),
+				   &mhi_cntrl->oem_pk_hash[i]);
+		if (ret) {
+			dev_err(dev, "Could not capture OEM PK HASH via BHI\n");
+			break;
+		}
 	}
 
-error_fw_load:
-	mhi_cntrl->pm_state = MHI_PM_FW_DL_ERR;
-	wake_up_all(&mhi_cntrl->state_event);
+	/* wait for ready on pass through or any other execution environment */
+	if (!MHI_FW_LOAD_CAPABLE(mhi_cntrl->ee))
+		mhi_fw_load_finish(mhi_cntrl, MHI_FW_LOAD_READY_STATE);
+
+	fw_name = (mhi_cntrl->ee == MHI_EE_EDL) ?
+		mhi_cntrl->edl_image : mhi_cntrl->fw_image;
+
+	if (!fw_name || (mhi_cntrl->fbc_download && (!mhi_cntrl->sbl_size ||
+						     !mhi_cntrl->seg_len))) {
+		dev_err(dev,
+			"No firmware image defined or !sbl_size || !seg_len\n");
+		mhi_fw_load_finish(mhi_cntrl, MHI_FW_ERROR_FW_LOAD);
+	}
+
+	cb_ctx = kzalloc(sizeof(*cb_ctx), GFP_KERNEL);
+	if (!cb_ctx)
+		return;
+
+	ret = request_firmware_nowait(THIS_MODULE, true, fw_name, dev, GFP_KERNEL, cb_ctx,
+				      mhi_fw_load_callback);
+	if (ret) {
+		dev_err(dev, "Error loading firmware: %d\n", ret);
+		mhi_fw_load_finish(mhi_cntrl, MHI_FW_ERROR_FW_LOAD);
+	}
 }
 
 int mhi_download_amss_image(struct mhi_controller *mhi_cntrl)

base-commit: 622e96fb58d63985b028abc2cb9a873124bdac1e
-- 
2.34.1


             reply	other threads:[~2021-12-10 16:16 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-10 16:16 Thomas Weißschuh [this message]
2021-12-14  0:07 ` [RFC] bus: mhi: core: Load firmware asynchronous Hemant Kumar
2021-12-14  6:32   ` Thomas Weißschuh
2021-12-14 22:55     ` Hemant Kumar
2021-12-14 23:28       ` Thomas Weißschuh
2021-12-16 10:19 ` Kalle Valo

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=20211210161645.10925-1-linux@weissschuh.net \
    --to=linux@weissschuh.net \
    --cc=Mario.Limonciello@amd.com \
    --cc=hemantk@codeaurora.org \
    --cc=hughsient@gmail.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mani@kernel.org \
    --cc=mhi@lists.linux.dev \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox