lkml.org 
[lkml]   [2021]   [Dec]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[RFC] bus: mhi: core: Load firmware asynchronous
Date
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

\
 
 \ /
  Last update: 2021-12-10 17:17    [W:0.101 / U:3.656 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site