From patchwork Wed Mar 8 15:25:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kalle Valo X-Patchwork-Id: 13165996 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AB531C64EC4 for ; Wed, 8 Mar 2023 15:25:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231811AbjCHPZg (ORCPT ); Wed, 8 Mar 2023 10:25:36 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41518 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231929AbjCHPZb (ORCPT ); Wed, 8 Mar 2023 10:25:31 -0500 Received: from ams.source.kernel.org (ams.source.kernel.org [145.40.68.75]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 94C4AC5616 for ; Wed, 8 Mar 2023 07:25:29 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ams.source.kernel.org (Postfix) with ESMTPS id 3CB39B81C4D for ; Wed, 8 Mar 2023 15:25:28 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 22FFBC433D2; Wed, 8 Mar 2023 15:25:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1678289126; bh=SrAq+DDewNQuaVVmmMK7PUrDAUggwmxqEZ7rN80AGB0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WmHjS0oIiOPyujluEn8Xug0isgdipJ4IuIuERhik4Yy6ZdzSGbgndhEIClphaWcXP WSVyZn7T1SsPq0lzOZw0atkDjNJsk06ywjipjHKLxiMuiEiylJtrBcQyxTHtLBpgc0 mOHtHYRcUmLX0ShCxRS6y8Fp9CqXM6InpwbWnuVnyfiWlF8vORdjxYukXETH0boTpv 9twG8gyVretuQ179pispswO8l5IpOGUzvzrcebGZo1I3HbQ+mBTntqC2e2NK0ULrLp UpJZjw+a5rsq/TZOyH4DR6k6ThYGlxkx39T3UZC8SLWaRZwmTkJy5CeN+yizk+baLu DSR7Gq1GsfJ5Q== From: Kalle Valo To: mhi@lists.linux.dev Cc: ath11k@lists.infradead.org, linux-wireless@vger.kernel.org Subject: [PATCH v2 1/3] mhi: allow MHI client drivers to provide the firmware via a pointer Date: Wed, 8 Mar 2023 17:25:20 +0200 Message-Id: <20230308152522.6728-2-kvalo@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230308152522.6728-1-kvalo@kernel.org> References: <20230308152522.6728-1-kvalo@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Kalle Valo 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 --- drivers/bus/mhi/host/boot.c | 28 +++++++++++++++++++--------- include/linux/mhi.h | 6 ++++++ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/bus/mhi/host/boot.c b/drivers/bus/mhi/host/boot.c index 1c69feee1703..5e6e1e340057 100644 --- a/drivers/bus/mhi/host/boot.c +++ b/drivers/bus/mhi/host/boot.c @@ -365,12 +365,10 @@ int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl, } static void mhi_firmware_copy(struct mhi_controller *mhi_cntrl, - const struct firmware *firmware, + const u8 *buf, size_t remainder, struct image_info *img_info) { - size_t remainder = firmware->size; size_t to_cpy; - const u8 *buf = firmware->data; struct mhi_buf *mhi_buf = img_info->mhi_buf; struct bhi_vec_entry *bhi_vec = img_info->bhi_vec; @@ -392,9 +390,10 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) const struct firmware *firmware = NULL; struct device *dev = &mhi_cntrl->mhi_dev->dev; const char *fw_name; + const u8 *fw_data; void *buf; dma_addr_t dma_addr; - size_t size; + size_t size, fw_sz; int i, ret; if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) { @@ -424,6 +423,14 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) 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->fw_data && mhi_cntrl->fw_sz) { + size = mhi_cntrl->sbl_size; + fw_data = mhi_cntrl->fw_data; + fw_sz = mhi_cntrl->fw_sz; + goto skip_req_fw; + } + if (!fw_name || (mhi_cntrl->fbc_download && (!mhi_cntrl->sbl_size || !mhi_cntrl->seg_len))) { dev_err(dev, @@ -443,6 +450,10 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) if (size > firmware->size) size = firmware->size; + fw_data = firmware->data; + fw_sz = firmware->size; + +skip_req_fw: buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, size, &dma_addr, GFP_KERNEL); if (!buf) { @@ -451,7 +462,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) } /* Download image using BHI */ - memcpy(buf, firmware->data, size); + memcpy(buf, fw_data, size); ret = mhi_fw_load_bhi(mhi_cntrl, dma_addr, size); dma_free_coherent(mhi_cntrl->cntrl_dev, size, buf, dma_addr); @@ -463,7 +474,7 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) } /* Wait for ready since EDL image was loaded */ - if (fw_name == mhi_cntrl->edl_image) { + if (fw_name && fw_name == mhi_cntrl->edl_image) { release_firmware(firmware); goto fw_load_ready_state; } @@ -477,15 +488,14 @@ void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) * device transitioning into MHI READY state */ if (mhi_cntrl->fbc_download) { - ret = mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->fbc_image, - firmware->size); + ret = mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->fbc_image, fw_sz); if (ret) { release_firmware(firmware); goto error_fw_load; } /* Load the firmware into BHIE vec table */ - mhi_firmware_copy(mhi_cntrl, firmware, mhi_cntrl->fbc_image); + mhi_firmware_copy(mhi_cntrl, fw_data, fw_sz, mhi_cntrl->fbc_image); } release_firmware(firmware); diff --git a/include/linux/mhi.h b/include/linux/mhi.h index a5441ad33c74..72eef7309736 100644 --- a/include/linux/mhi.h +++ b/include/linux/mhi.h @@ -299,6 +299,10 @@ struct mhi_controller_config { * @iova_start: IOMMU starting address for data (required) * @iova_stop: IOMMU stop address for data (required) * @fw_image: Firmware image name for normal booting (optional) + * @fw_data: Firmware image data content for normal booting, used only + * if fw_image is NULL (optional) + * @fw_sz: Firmware image data size for normal booting, used only if fw_image + * is NULL and fbc_download is true (optional) * @edl_image: Firmware image name for emergency download mode (optional) * @rddm_size: RAM dump size that host should allocate for debugging purpose * @sbl_size: SBL image size downloaded through BHIe (optional) @@ -384,6 +388,8 @@ struct mhi_controller { dma_addr_t iova_start; dma_addr_t iova_stop; const char *fw_image; + const u8 *fw_data; + size_t fw_sz; const char *edl_image; size_t rddm_size; size_t sbl_size; From patchwork Wed Mar 8 15:25:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kalle Valo X-Patchwork-Id: 13165995 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C1527C74A44 for ; Wed, 8 Mar 2023 15:25:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231793AbjCHPZf (ORCPT ); Wed, 8 Mar 2023 10:25:35 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41598 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231712AbjCHPZb (ORCPT ); Wed, 8 Mar 2023 10:25:31 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 31776D08D0 for ; Wed, 8 Mar 2023 07:25:29 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id AB26E61868 for ; Wed, 8 Mar 2023 15:25:28 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 5986CC4339B; Wed, 8 Mar 2023 15:25:27 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1678289128; bh=yPbKVKAGApGaOsxSfqbfmPNFgWvzf0UqkFIDaNWkG9I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WrYb1iI4/l6U8ChMdiGRhJnj6wxAOr6Elm7ZI6m8b9HWJ6vZdcbdjRoF1xniCXwQB /M7VRvn/hkSD+a87xa45v2C4qlGd9yuNjBU52Ahsj224OSzPEuGar1e1lsV0P5AdLH Eudbto2Y5Iaw9lpNUIBM2Jl5z10qel0zQzqBMOkq10oLePAQHkvvb26ZFPvcv8HSJP lLZ0r5pIWFG7RHxF0BJWXsKv8AgoD9fPYC1GEu0MV7jgNPvDUuEZJtbHE6Cz6cVbBI 3+EJg2BIzsG12Dnzeo70wwq+Qdx9NcUiwPfta4euLShSCOirBD7ri9Q1pLOzDSc+v4 I14eB1a+8+JOA== From: Kalle Valo To: mhi@lists.linux.dev Cc: ath11k@lists.infradead.org, linux-wireless@vger.kernel.org Subject: [PATCH v2 2/3] wifi: ath11k: qmi: refactor ath11k_qmi_m3_load() Date: Wed, 8 Mar 2023 17:25:21 +0200 Message-Id: <20230308152522.6728-3-kvalo@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230308152522.6728-1-kvalo@kernel.org> References: <20230308152522.6728-1-kvalo@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Kalle Valo Simple refactoring to make it easier to add firmware-2.bin support in the following patch. Earlier ath11k_qmi_m3_load() supported changing m3.bin contents while ath11k is running. But that's not going to actually work, m3.bin is supposed to the be same during the lifetime of ath11k, for example we don't support changing the firmware capabilities on the fly. Due to this ath11k requests m3.bin firmware file first and only then checks m3_mem->vaddr, so we are basically requesting the firmware file even if it's not needed. Reverse the code so that m3_mem buffer is checked first, and only if it doesn't exist, then m3.bin is requested from user space. Checking for m3_mem->size is redundant when m3_mem->vaddr is NULL, we would not be able to use the buffer in that case. So remove the check for size. Simplify the exit handling and use 'goto out'. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.9 Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath11k/qmi.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index ab923e24b0a9..5bc98180aed4 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2493,6 +2493,10 @@ static int ath11k_qmi_m3_load(struct ath11k_base *ab) char path[100]; int ret; + if (m3_mem->vaddr) + /* m3 firmware buffer is already available in the DMA buffer */ + return 0; + fw = ath11k_core_firmware_request(ab, ATH11K_M3_FILE); if (IS_ERR(fw)) { ret = PTR_ERR(fw); @@ -2502,25 +2506,25 @@ static int ath11k_qmi_m3_load(struct ath11k_base *ab) return ret; } - if (m3_mem->vaddr || m3_mem->size) - goto skip_m3_alloc; - m3_mem->vaddr = dma_alloc_coherent(ab->dev, fw->size, &m3_mem->paddr, GFP_KERNEL); if (!m3_mem->vaddr) { ath11k_err(ab, "failed to allocate memory for M3 with size %zu\n", fw->size); - release_firmware(fw); - return -ENOMEM; + ret = -ENOMEM; + goto out; } -skip_m3_alloc: memcpy(m3_mem->vaddr, fw->data, fw->size); m3_mem->size = fw->size; + + ret = 0; + +out: release_firmware(fw); - return 0; + return ret; } static void ath11k_qmi_m3_free(struct ath11k_base *ab) From patchwork Wed Mar 8 15:25:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kalle Valo X-Patchwork-Id: 13165997 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BC7F8C6FD1E for ; Wed, 8 Mar 2023 15:25:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231812AbjCHPZh (ORCPT ); Wed, 8 Mar 2023 10:25:37 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41542 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231758AbjCHPZc (ORCPT ); Wed, 8 Mar 2023 10:25:32 -0500 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7D907CD649 for ; Wed, 8 Mar 2023 07:25:30 -0800 (PST) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 0889D6170C for ; Wed, 8 Mar 2023 15:25:30 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8FEE1C4339E; Wed, 8 Mar 2023 15:25:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1678289129; bh=BvZjeD1O4JT6aQjDbJe/oGS8l7XTH1xOzJEGjb/fKUM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VwawK6HLOItzLj32Hj5J1gy08o6qP2Q5jvGOeiTJOwiRYrFI/yAoQwJL18aUgI/nj rKROiwfbSjXMd02MOEdAiq2mJu5DxSrgo1+D4xtUFpr2PC3xKROIGAxw+N5WSc8v/o lpU5HRtPBA+PKo3U+ejp9N7V9L4m9TLaHGrY8h0x/5ezObrYz4HYn60Lr54g57s6f3 cAxOP9JJp0fOGg+472aMlpXsbFXu2hEn17bO6R7uhaSp/7SXiBlRW6ONjvntq0dmww hTIJCAaGo+/Iqq3lR7YSWuLDf0ITVDdju45fFWUd+qdUzSLmwazGLgZ9iKIB0w2xwB OUc8Z5snQov7A== From: Kalle Valo To: mhi@lists.linux.dev Cc: ath11k@lists.infradead.org, linux-wireless@vger.kernel.org Subject: [PATCH v2 3/3] wifi: ath11k: add firmware-2.bin support Date: Wed, 8 Mar 2023 17:25:22 +0200 Message-Id: <20230308152522.6728-4-kvalo@kernel.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230308152522.6728-1-kvalo@kernel.org> References: <20230308152522.6728-1-kvalo@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org From: Anilkumar Kolli Firmware IE containers can dynamically provide various information what firmware supports. Also it can embed more than one image so updating firmware is easy, user just needs to update one file in /lib/firmware/. The firmware API 2 or higher will use the IE container format, the current API 1 will not use the new format but it still is supported for some time. Firmware API 2 files are named as firmware-2.bin (which contains both amss.bin and m3.bin images) and API 1 files are amss.bin and m3.bin. Currently ath11k PCI driver provides firmware binary (amss.bin) path to MHI driver, MHI driver reads firmware from filesystem and boots it. Add provision to read firmware files from ath11k driver and provide the amss.bin firmware data and size to MHI using a pointer. Currently enum ath11k_fw_features is empty, the patches adding features will add the flags. With AHB devices there's no amss.bin or m3.bin, so no changes in how AHB firmware files are used. But AHB devices can use future additions to the meta data, for example in enum ath11k_fw_features. Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.9 Co-developed-by: P Praneesh Signed-off-by: P Praneesh Signed-off-by: Anilkumar Kolli Co-developed-by: Kalle Valo Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath11k/Makefile | 3 +- drivers/net/wireless/ath/ath11k/core.c | 8 ++ drivers/net/wireless/ath/ath11k/core.h | 15 +++ drivers/net/wireless/ath/ath11k/fw.c | 157 +++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/fw.h | 27 ++++ drivers/net/wireless/ath/ath11k/mhi.c | 18 ++- drivers/net/wireless/ath/ath11k/qmi.c | 36 ++++-- 7 files changed, 247 insertions(+), 17 deletions(-) create mode 100644 drivers/net/wireless/ath/ath11k/fw.c create mode 100644 drivers/net/wireless/ath/ath11k/fw.h diff --git a/drivers/net/wireless/ath/ath11k/Makefile b/drivers/net/wireless/ath/ath11k/Makefile index cc47e0114595..2c94d50ae36f 100644 --- a/drivers/net/wireless/ath/ath11k/Makefile +++ b/drivers/net/wireless/ath/ath11k/Makefile @@ -17,7 +17,8 @@ ath11k-y += core.o \ peer.o \ dbring.o \ hw.o \ - pcic.o + pcic.o \ + fw.o ath11k-$(CONFIG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 75fdbe4ef83a..d411598ecd8c 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -16,6 +16,7 @@ #include "debug.h" #include "hif.h" #include "wow.h" +#include "fw.h" unsigned int ath11k_debug_mask; EXPORT_SYMBOL(ath11k_debug_mask); @@ -1950,6 +1951,12 @@ int ath11k_core_pre_init(struct ath11k_base *ab) return ret; } + ret = ath11k_fw_pre_init(ab); + if (ret) { + ath11k_err(ab, "failed to pre init firmware: %d", ret); + return ret; + } + return 0; } EXPORT_SYMBOL(ath11k_core_pre_init); @@ -1980,6 +1987,7 @@ void ath11k_core_deinit(struct ath11k_base *ab) ath11k_hif_power_down(ab); ath11k_mac_destroy(ab); ath11k_core_soc_destroy(ab); + ath11k_fw_destroy(ab); } EXPORT_SYMBOL(ath11k_core_deinit); diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 0830276e5028..5ada78f4b9ec 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -15,6 +15,8 @@ #include #include #include +#include + #include "qmi.h" #include "htc.h" #include "wmi.h" @@ -29,6 +31,7 @@ #include "dbring.h" #include "spectral.h" #include "wow.h" +#include "fw.h" #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -978,6 +981,18 @@ struct ath11k_base { const struct ath11k_pci_ops *ops; } pci; + struct { + u32 api_version; + + const struct firmware *fw; + const u8 *amss_data; + size_t amss_len; + const u8 *m3_data; + size_t m3_len; + + DECLARE_BITMAP(fw_features, ATH11K_FW_FEATURE_COUNT); + } fw; + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath11k/fw.c b/drivers/net/wireless/ath/ath11k/fw.c new file mode 100644 index 000000000000..339b2b3bed84 --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/fw.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "core.h" + +#include "debug.h" + +static int ath11k_fw_request_firmware_api_n(struct ath11k_base *ab, + const char *name) +{ + size_t magic_len, len, ie_len; + int ie_id, i, index, bit, ret; + struct ath11k_fw_ie *hdr; + const u8 *data; + __le32 *timestamp; + + ab->fw.fw = ath11k_core_firmware_request(ab, name); + if (IS_ERR(ab->fw.fw)) { + ret = PTR_ERR(ab->fw.fw); + ath11k_err(ab, "failed to load %s: %d\n", name, ret); + ab->fw.fw = NULL; + return ret; + } + + data = ab->fw.fw->data; + len = ab->fw.fw->size; + + /* magic also includes the null byte, check that as well */ + magic_len = strlen(ATH11K_FIRMWARE_MAGIC) + 1; + + if (len < magic_len) { + ath11k_err(ab, "firmware image too small to contain magic: %zu\n", + len); + ret = -EINVAL; + goto err; + } + + if (memcmp(data, ATH11K_FIRMWARE_MAGIC, magic_len) != 0) { + ath11k_err(ab, "Invalid firmware magic\n"); + ret = -EINVAL; + goto err; + } + + /* jump over the padding */ + magic_len = ALIGN(magic_len, 4); + + len -= magic_len; + data += magic_len; + + /* loop elements */ + while (len > sizeof(struct ath11k_fw_ie)) { + hdr = (struct ath11k_fw_ie *)data; + + ie_id = le32_to_cpu(hdr->id); + ie_len = le32_to_cpu(hdr->len); + + len -= sizeof(*hdr); + data += sizeof(*hdr); + + if (len < ie_len) { + ath11k_err(ab, "Invalid length for FW IE %d (%zu < %zu)\n", + ie_id, len, ie_len); + ret = -EINVAL; + goto err; + } + + switch (ie_id) { + case ATH11K_FW_IE_TIMESTAMP: + if (ie_len != sizeof(u32)) + break; + + timestamp = (__le32 *)data; + + ath11k_dbg(ab, ATH11K_DBG_BOOT, "found fw timestamp %d\n", + le32_to_cpup(timestamp)); + break; + case ATH11K_FW_IE_FEATURES: + ath11k_dbg(ab, ATH11K_DBG_BOOT, + "found firmware features ie (%zd B)\n", + ie_len); + + for (i = 0; i < ATH11K_FW_FEATURE_COUNT; i++) { + index = i / 8; + bit = i % 8; + + if (index == ie_len) + break; + + if (data[index] & (1 << bit)) + __set_bit(i, ab->fw.fw_features); + } + + ath11k_dbg_dump(ab, ATH11K_DBG_BOOT, "features", "", + ab->fw.fw_features, + sizeof(ab->fw.fw_features)); + break; + case ATH11K_FW_IE_AMSS_IMAGE: + ath11k_dbg(ab, ATH11K_DBG_BOOT, + "found fw image ie (%zd B)\n", + ie_len); + + ab->fw.amss_data = data; + ab->fw.amss_len = ie_len; + break; + case ATH11K_FW_IE_M3_IMAGE: + ath11k_dbg(ab, ATH11K_DBG_BOOT, + "found m3 image ie (%zd B)\n", + ie_len); + + ab->fw.m3_data = data; + ab->fw.m3_len = ie_len; + break; + default: + ath11k_warn(ab, "Unknown FW IE: %u\n", ie_id); + break; + } + + /* jump over the padding */ + ie_len = ALIGN(ie_len, 4); + + len -= ie_len; + data += ie_len; + }; + + return 0; + +err: + release_firmware(ab->fw.fw); + ab->fw.fw = NULL; + return ret; +} + +int ath11k_fw_pre_init(struct ath11k_base *ab) +{ + int ret; + + ret = ath11k_fw_request_firmware_api_n(ab, ATH11K_FW_API2_FILE); + if (ret == 0) { + ab->fw.api_version = 2; + goto out; + } + + ab->fw.api_version = 1; + +out: + ath11k_dbg(ab, ATH11K_DBG_BOOT, "using fw api %d\n", + ab->fw.api_version); + + return 0; +} + +void ath11k_fw_destroy(struct ath11k_base *ab) +{ + release_firmware(ab->fw.fw); +} diff --git a/drivers/net/wireless/ath/ath11k/fw.h b/drivers/net/wireless/ath/ath11k/fw.h new file mode 100644 index 000000000000..e33b0f78b571 --- /dev/null +++ b/drivers/net/wireless/ath/ath11k/fw.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef ATH11K_FW_H +#define ATH11K_FW_H + +#define ATH11K_FW_API2_FILE "firmware-2.bin" +#define ATH11K_FIRMWARE_MAGIC "QCOM-ATH11K-FW" + +enum ath11k_fw_ie_type { + ATH11K_FW_IE_TIMESTAMP = 0, + ATH11K_FW_IE_FEATURES = 1, + ATH11K_FW_IE_AMSS_IMAGE = 2, + ATH11K_FW_IE_M3_IMAGE = 3, +}; + +enum ath11k_fw_features { + /* keep last */ + ATH11K_FW_FEATURE_COUNT, +}; + +int ath11k_fw_pre_init(struct ath11k_base *ab); +void ath11k_fw_destroy(struct ath11k_base *ab); + +#endif /* ATH11K_FW_H */ diff --git a/drivers/net/wireless/ath/ath11k/mhi.c b/drivers/net/wireless/ath/ath11k/mhi.c index 86995e8dc913..40c43f63ebdd 100644 --- a/drivers/net/wireless/ath/ath11k/mhi.c +++ b/drivers/net/wireless/ath/ath11k/mhi.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -389,16 +390,23 @@ int ath11k_mhi_register(struct ath11k_pci *ab_pci) if (!mhi_ctrl) return -ENOMEM; - ath11k_core_create_firmware_path(ab, ATH11K_AMSS_FILE, - ab_pci->amss_path, - sizeof(ab_pci->amss_path)); - ab_pci->mhi_ctrl = mhi_ctrl; mhi_ctrl->cntrl_dev = ab->dev; - mhi_ctrl->fw_image = ab_pci->amss_path; mhi_ctrl->regs = ab->mem; mhi_ctrl->reg_len = ab->mem_len; + if (ab->fw.amss_data && ab->fw.amss_len > 0) { + /* use MHI firmware file from firmware-N.bin */ + mhi_ctrl->fw_data = ab->fw.amss_data; + mhi_ctrl->fw_sz = ab->fw.amss_len; + } else { + /* use the old separate mhi.bin MHI firmware file */ + ath11k_core_create_firmware_path(ab, ATH11K_AMSS_FILE, + ab_pci->amss_path, + sizeof(ab_pci->amss_path)); + mhi_ctrl->fw_image = ab_pci->amss_path; + } + ret = ath11k_mhi_get_msi(ab_pci); if (ret) { ath11k_err(ab, "failed to get msi for mhi\n"); diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 5bc98180aed4..426d047ff1d5 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2489,25 +2489,39 @@ static int ath11k_qmi_load_bdf_qmi(struct ath11k_base *ab, static int ath11k_qmi_m3_load(struct ath11k_base *ab) { struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; - const struct firmware *fw; + const struct firmware *fw = NULL; + const void *m3_data; char path[100]; + size_t m3_len; int ret; if (m3_mem->vaddr) /* m3 firmware buffer is already available in the DMA buffer */ return 0; - fw = ath11k_core_firmware_request(ab, ATH11K_M3_FILE); - if (IS_ERR(fw)) { - ret = PTR_ERR(fw); - ath11k_core_create_firmware_path(ab, ATH11K_M3_FILE, - path, sizeof(path)); - ath11k_err(ab, "failed to load %s: %d\n", path, ret); - return ret; + if (ab->fw.m3_data && ab->fw.m3_len > 0) { + /* firmware-N.bin had a m3 firmware file so use that */ + m3_data = ab->fw.m3_data; + m3_len = ab->fw.m3_len; + } else { + /* No m3 file in firmware-N.bin so try to request old + * separate m3.bin. + */ + fw = ath11k_core_firmware_request(ab, ATH11K_M3_FILE); + if (IS_ERR(fw)) { + ret = PTR_ERR(fw); + ath11k_core_create_firmware_path(ab, ATH11K_M3_FILE, + path, sizeof(path)); + ath11k_err(ab, "failed to load %s: %d\n", path, ret); + return ret; + } + + m3_data = fw->data; + m3_len = fw->size; } m3_mem->vaddr = dma_alloc_coherent(ab->dev, - fw->size, &m3_mem->paddr, + m3_len, &m3_mem->paddr, GFP_KERNEL); if (!m3_mem->vaddr) { ath11k_err(ab, "failed to allocate memory for M3 with size %zu\n", @@ -2516,8 +2530,8 @@ static int ath11k_qmi_m3_load(struct ath11k_base *ab) goto out; } - memcpy(m3_mem->vaddr, fw->data, fw->size); - m3_mem->size = fw->size; + memcpy(m3_mem->vaddr, m3_data, m3_len); + m3_mem->size = m3_len; ret = 0;