aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/pcie/trans.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-09-10 05:50:18 -0400
committerJohannes Berg <johannes.berg@intel.com>2012-09-10 13:14:30 -0400
commit83f84d7bd49f9e4deea0a77a76c9882673ee1f3c (patch)
treefb2f84fa74450f89cbb429a7457ff0e80ece35b7 /drivers/net/wireless/iwlwifi/pcie/trans.c
parent7439046d9747966bb805ca8bfd1086a876a4b8fd (diff)
iwlwifi: load firmware in chunks
Instead of allocating one big chunk of DMA-coherent memory for the firmware and keeping it around, only vmalloc() the firmware and copy it into a single page of DMA-coherent memory for the upload. The advantage is that we don't need DMA memory for the firmware image that is stored while the driver is operating, we only need it while uploading. This will make it easier for the driver to work if the system has fragmented memory. Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/pcie/trans.c')
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index d44fa2a220f1..3cb4f858d4eb 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -923,13 +923,10 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans)
923/* 923/*
924 * ucode 924 * ucode
925 */ 925 */
926static int iwl_load_section(struct iwl_trans *trans, u8 section_num, 926static int iwl_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr,
927 const struct fw_desc *section) 927 dma_addr_t phy_addr, u32 byte_cnt)
928{ 928{
929 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); 929 struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
930 dma_addr_t phy_addr = section->p_addr;
931 u32 byte_cnt = section->len;
932 u32 dst_addr = section->offset;
933 int ret; 930 int ret;
934 931
935 trans_pcie->ucode_write_complete = false; 932 trans_pcie->ucode_write_complete = false;
@@ -943,8 +940,8 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
943 dst_addr); 940 dst_addr);
944 941
945 iwl_write_direct32(trans, 942 iwl_write_direct32(trans,
946 FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), 943 FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
947 phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); 944 phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
948 945
949 iwl_write_direct32(trans, 946 iwl_write_direct32(trans,
950 FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), 947 FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
@@ -963,26 +960,58 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
963 FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | 960 FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE |
964 FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); 961 FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
965 962
966 IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
967 section_num);
968 ret = wait_event_timeout(trans_pcie->ucode_write_waitq, 963 ret = wait_event_timeout(trans_pcie->ucode_write_waitq,
969 trans_pcie->ucode_write_complete, 5 * HZ); 964 trans_pcie->ucode_write_complete, 5 * HZ);
970 if (!ret) { 965 if (!ret) {
971 IWL_ERR(trans, "Could not load the [%d] uCode section\n", 966 IWL_ERR(trans, "Failed to load firmware chunk!\n");
972 section_num);
973 return -ETIMEDOUT; 967 return -ETIMEDOUT;
974 } 968 }
975 969
976 return 0; 970 return 0;
977} 971}
978 972
973static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
974 const struct fw_desc *section)
975{
976 u8 *v_addr;
977 dma_addr_t p_addr;
978 u32 offset;
979 int ret = 0;
980
981 IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
982 section_num);
983
984 v_addr = dma_alloc_coherent(trans->dev, PAGE_SIZE, &p_addr, GFP_KERNEL);
985 if (!v_addr)
986 return -ENOMEM;
987
988 for (offset = 0; offset < section->len; offset += PAGE_SIZE) {
989 u32 copy_size;
990
991 copy_size = min_t(u32, PAGE_SIZE, section->len - offset);
992
993 memcpy(v_addr, (u8 *)section->data + offset, copy_size);
994 ret = iwl_load_firmware_chunk(trans, section->offset + offset,
995 p_addr, copy_size);
996 if (ret) {
997 IWL_ERR(trans,
998 "Could not load the [%d] uCode section\n",
999 section_num);
1000 break;
1001 }
1002 }
1003
1004 dma_free_coherent(trans->dev, PAGE_SIZE, v_addr, p_addr);
1005 return ret;
1006}
1007
979static int iwl_load_given_ucode(struct iwl_trans *trans, 1008static int iwl_load_given_ucode(struct iwl_trans *trans,
980 const struct fw_img *image) 1009 const struct fw_img *image)
981{ 1010{
982 int i, ret = 0; 1011 int i, ret = 0;
983 1012
984 for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) { 1013 for (i = 0; i < IWL_UCODE_SECTION_MAX; i++) {
985 if (!image->sec[i].p_addr) 1014 if (!image->sec[i].data)
986 break; 1015 break;
987 1016
988 ret = iwl_load_section(trans, i, &image->sec[i]); 1017 ret = iwl_load_section(trans, i, &image->sec[i]);