iwlwifi: mvm: synchronize firmware DMA paging memory
authorSara Sharon <sara.sharon@intel.com>
Wed, 30 Nov 2016 14:49:11 +0000 (16:49 +0200)
committerLuca Coelho <luciano.coelho@intel.com>
Fri, 3 Feb 2017 14:26:42 +0000 (16:26 +0200)
When driver needs to access the contents of a streaming DMA buffer
without unmapping it it should call dma_sync_single_for_cpu().
Once the call has been made, the CPU "owns" the DMA buffer and can
work with it as needed.
Before the device accesses the buffer, however, ownership should be
transferred back to it with dma_sync_single_for_device().
Both calls weren't performed by the driver, resulting with odd paging
errors on some platforms. Fix it.

Fixes: a6c4fb4441f4 ("iwlwifi: mvm: Add FW paging mechanism for the UMAC on PCI")
Signed-off-by: Sara Sharon <sara.sharon@intel.com>
Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c

index e7b3b712d77833ee7ef079bbac9ec158e1afe90d..a027b11bbdb38b5040d679982762959c03df97d2 100644 (file)
@@ -811,12 +811,16 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
                        struct iwl_fw_error_dump_paging *paging;
                        struct page *pages =
                                mvm->fw_paging_db[i].fw_paging_block;
+                       dma_addr_t addr = mvm->fw_paging_db[i].fw_paging_phys;
 
                        dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_PAGING);
                        dump_data->len = cpu_to_le32(sizeof(*paging) +
                                                     PAGING_BLOCK_SIZE);
                        paging = (void *)dump_data->data;
                        paging->index = cpu_to_le32(i);
+                       dma_sync_single_for_cpu(mvm->trans->dev, addr,
+                                               PAGING_BLOCK_SIZE,
+                                               DMA_BIDIRECTIONAL);
                        memcpy(paging->data, page_address(pages),
                               PAGING_BLOCK_SIZE);
                        dump_data = iwl_fw_error_next_data(dump_data);
index 8fd3c2b12ea2a5d8eb7e3ce4a7014af0eb97df83..c42ef8681b75292667847692c59513ade5cf49f3 100644 (file)
@@ -214,6 +214,10 @@ static int iwl_fill_paging_mem(struct iwl_mvm *mvm, const struct fw_img *image)
        memcpy(page_address(mvm->fw_paging_db[0].fw_paging_block),
               image->sec[sec_idx].data,
               mvm->fw_paging_db[0].fw_paging_size);
+       dma_sync_single_for_device(mvm->trans->dev,
+                                  mvm->fw_paging_db[0].fw_paging_phys,
+                                  mvm->fw_paging_db[0].fw_paging_size,
+                                  DMA_BIDIRECTIONAL);
 
        IWL_DEBUG_FW(mvm,
                     "Paging: copied %d CSS bytes to first block\n",
@@ -228,9 +232,16 @@ static int iwl_fill_paging_mem(struct iwl_mvm *mvm, const struct fw_img *image)
         * loop stop at num_of_paging_blk since that last block is not full.
         */
        for (idx = 1; idx < mvm->num_of_paging_blk; idx++) {
-               memcpy(page_address(mvm->fw_paging_db[idx].fw_paging_block),
+               struct iwl_fw_paging *block = &mvm->fw_paging_db[idx];
+
+               memcpy(page_address(block->fw_paging_block),
                       image->sec[sec_idx].data + offset,
-                      mvm->fw_paging_db[idx].fw_paging_size);
+                      block->fw_paging_size);
+               dma_sync_single_for_device(mvm->trans->dev,
+                                          block->fw_paging_phys,
+                                          block->fw_paging_size,
+                                          DMA_BIDIRECTIONAL);
+
 
                IWL_DEBUG_FW(mvm,
                             "Paging: copied %d paging bytes to block %d\n",
@@ -242,9 +253,15 @@ static int iwl_fill_paging_mem(struct iwl_mvm *mvm, const struct fw_img *image)
 
        /* copy the last paging block */
        if (mvm->num_of_pages_in_last_blk > 0) {
-               memcpy(page_address(mvm->fw_paging_db[idx].fw_paging_block),
+               struct iwl_fw_paging *block = &mvm->fw_paging_db[idx];
+
+               memcpy(page_address(block->fw_paging_block),
                       image->sec[sec_idx].data + offset,
                       FW_PAGING_SIZE * mvm->num_of_pages_in_last_blk);
+               dma_sync_single_for_device(mvm->trans->dev,
+                                          block->fw_paging_phys,
+                                          block->fw_paging_size,
+                                          DMA_BIDIRECTIONAL);
 
                IWL_DEBUG_FW(mvm,
                             "Paging: copied %d pages in the last block %d\n",