Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bus: mhi: host: allow MHI client drivers to provide the firmware via a pointer

Currently MHI loads the firmware image from the path provided by client
devices. ath11k needs to support firmware image embedded along with meta
data (named as firmware-2.bin). So allow the client driver to request the
firmware file from user space on it's own and provide the firmware image
data and size to MHI via a pointer struct mhi_controller::fw_data.

This is an optional feature, if fw_data is NULL MHI load the firmware using
the name from struct mhi_controller::fw_image string as before.

Tested with ath11k and WCN6855 hw2.0.

Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Reviewed-by: Jeffrey Hugo <quic_jhugo@quicinc.com>
Link: https://lore.kernel.org/r/20230727100430.3603551-2-kvalo@kernel.org
[mani: wrapped commit message to 75 columns]
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

authored by

Kalle Valo and committed by
Manivannan Sadhasivam
efe47a18 14a27140

+31 -9
+25 -9
drivers/bus/mhi/host/boot.c
··· 365 365 } 366 366 367 367 static void mhi_firmware_copy(struct mhi_controller *mhi_cntrl, 368 - const struct firmware *firmware, 368 + const u8 *buf, size_t remainder, 369 369 struct image_info *img_info) 370 370 { 371 - size_t remainder = firmware->size; 372 371 size_t to_cpy; 373 - const u8 *buf = firmware->data; 374 372 struct mhi_buf *mhi_buf = img_info->mhi_buf; 375 373 struct bhi_vec_entry *bhi_vec = img_info->bhi_vec; 376 374 ··· 391 393 struct device *dev = &mhi_cntrl->mhi_dev->dev; 392 394 enum mhi_pm_state new_state; 393 395 const char *fw_name; 396 + const u8 *fw_data; 394 397 void *buf; 395 398 dma_addr_t dma_addr; 396 - size_t size; 399 + size_t size, fw_sz; 397 400 int i, ret; 398 401 399 402 if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { ··· 424 425 fw_name = (mhi_cntrl->ee == MHI_EE_EDL) ? 425 426 mhi_cntrl->edl_image : mhi_cntrl->fw_image; 426 427 428 + /* check if the driver has already provided the firmware data */ 429 + if (!fw_name && mhi_cntrl->fbc_download && 430 + mhi_cntrl->fw_data && mhi_cntrl->fw_sz) { 431 + if (!mhi_cntrl->sbl_size) { 432 + dev_err(dev, "fw_data provided but no sbl_size\n"); 433 + goto error_fw_load; 434 + } 435 + 436 + size = mhi_cntrl->sbl_size; 437 + fw_data = mhi_cntrl->fw_data; 438 + fw_sz = mhi_cntrl->fw_sz; 439 + goto skip_req_fw; 440 + } 441 + 427 442 if (!fw_name || (mhi_cntrl->fbc_download && (!mhi_cntrl->sbl_size || 428 443 !mhi_cntrl->seg_len))) { 429 444 dev_err(dev, ··· 457 444 if (size > firmware->size) 458 445 size = firmware->size; 459 446 447 + fw_data = firmware->data; 448 + fw_sz = firmware->size; 449 + 450 + skip_req_fw: 460 451 buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, size, &dma_addr, 461 452 GFP_KERNEL); 462 453 if (!buf) { ··· 469 452 } 470 453 471 454 /* Download image using BHI */ 472 - memcpy(buf, firmware->data, size); 455 + memcpy(buf, fw_data, size); 473 456 ret = mhi_fw_load_bhi(mhi_cntrl, dma_addr, size); 474 457 dma_free_coherent(mhi_cntrl->cntrl_dev, size, buf, dma_addr); 475 458 ··· 481 464 } 482 465 483 466 /* Wait for ready since EDL image was loaded */ 484 - if (fw_name == mhi_cntrl->edl_image) { 467 + if (fw_name && fw_name == mhi_cntrl->edl_image) { 485 468 release_firmware(firmware); 486 469 goto fw_load_ready_state; 487 470 } ··· 495 478 * device transitioning into MHI READY state 496 479 */ 497 480 if (mhi_cntrl->fbc_download) { 498 - ret = mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->fbc_image, 499 - firmware->size); 481 + ret = mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->fbc_image, fw_sz); 500 482 if (ret) { 501 483 release_firmware(firmware); 502 484 goto error_fw_load; 503 485 } 504 486 505 487 /* Load the firmware into BHIE vec table */ 506 - mhi_firmware_copy(mhi_cntrl, firmware, mhi_cntrl->fbc_image); 488 + mhi_firmware_copy(mhi_cntrl, fw_data, fw_sz, mhi_cntrl->fbc_image); 507 489 } 508 490 509 491 release_firmware(firmware);
+6
include/linux/mhi.h
··· 299 299 * @iova_start: IOMMU starting address for data (required) 300 300 * @iova_stop: IOMMU stop address for data (required) 301 301 * @fw_image: Firmware image name for normal booting (optional) 302 + * @fw_data: Firmware image data content for normal booting, used only 303 + * if fw_image is NULL and fbc_download is true (optional) 304 + * @fw_sz: Firmware image data size for normal booting, used only if fw_image 305 + * is NULL and fbc_download is true (optional) 302 306 * @edl_image: Firmware image name for emergency download mode (optional) 303 307 * @rddm_size: RAM dump size that host should allocate for debugging purpose 304 308 * @sbl_size: SBL image size downloaded through BHIe (optional) ··· 388 384 dma_addr_t iova_start; 389 385 dma_addr_t iova_stop; 390 386 const char *fw_image; 387 + const u8 *fw_data; 388 + size_t fw_sz; 391 389 const char *edl_image; 392 390 size_t rddm_size; 393 391 size_t sbl_size;