iwlwifi: pcie: prefer to load the firmware in one shot
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Tue, 30 Apr 2013 11:33:04 +0000 (14:33 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 13 May 2013 16:12:01 +0000 (18:12 +0200)
Users complained about allocation failures, so we loaded
the firmware in small chunks (PAGE_SIZE). This makes the
firmware restart considerably slower.
So, always prefer to load it in one shot allocating a big
chunk of coherent, and use smaller chunks as a fallback
solution.

On my laptop, this reduces the fw loading time from 120ms
to 20ms.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Reviewed-by: Moshe Island <moshe.island@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/iwlwifi/pcie/trans.c

index 50ba0a468f94baa59dede7d4c50c8a3a2f960b35..e5365196e5fe8975535de59d81aa141e4b9e5cf7 100644 (file)
@@ -405,20 +405,27 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
 {
        u8 *v_addr;
        dma_addr_t p_addr;
-       u32 offset;
+       u32 offset, chunk_sz = section->len;
        int ret = 0;
 
        IWL_DEBUG_FW(trans, "[%d] uCode section being loaded...\n",
                     section_num);
 
-       v_addr = dma_alloc_coherent(trans->dev, PAGE_SIZE, &p_addr, GFP_KERNEL);
-       if (!v_addr)
-               return -ENOMEM;
+       v_addr = dma_alloc_coherent(trans->dev, chunk_sz, &p_addr,
+                                   GFP_KERNEL | __GFP_NOWARN);
+       if (!v_addr) {
+               IWL_DEBUG_INFO(trans, "Falling back to small chunks of DMA\n");
+               chunk_sz = PAGE_SIZE;
+               v_addr = dma_alloc_coherent(trans->dev, chunk_sz,
+                                           &p_addr, GFP_KERNEL);
+               if (!v_addr)
+                       return -ENOMEM;
+       }
 
-       for (offset = 0; offset < section->len; offset += PAGE_SIZE) {
+       for (offset = 0; offset < section->len; offset += chunk_sz) {
                u32 copy_size;
 
-               copy_size = min_t(u32, PAGE_SIZE, section->len - offset);
+               copy_size = min_t(u32, chunk_sz, section->len - offset);
 
                memcpy(v_addr, (u8 *)section->data + offset, copy_size);
                ret = iwl_pcie_load_firmware_chunk(trans,
@@ -432,7 +439,7 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
                }
        }
 
-       dma_free_coherent(trans->dev, PAGE_SIZE, v_addr, p_addr);
+       dma_free_coherent(trans->dev, chunk_sz, v_addr, p_addr);
        return ret;
 }
 
This page took 0.026673 seconds and 5 git commands to generate.