summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2019-12-05 09:31:07 +0100
committerLuca Coelho <luciano.coelho@intel.com>2019-12-23 11:33:04 +0200
commitd84a7a654a66eead599cfd4f436d1f921e01074f (patch)
tree7cae2d5b2e73c5b2981c71d82519210880881e9d /drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
parent2763bba6328c53c455d8f7f5302b80030551c31b (diff)
downloadlinux-d84a7a654a66eead599cfd4f436d1f921e01074f.tar.bz2
iwlwifi: pcie: extend hardware workaround to context-info
After more investigation on the hardware side, it appears that the hardware bug regarding 2^32 boundary reaching/crossing also affects other uses of the DMA engine, in particular the ones triggered by the context-info (image loader) mechanism. It also turns out that the bug only affects devices with gen2 TX hardware engine, so we don't need to change context info for gen3. The TX path workarounds are simpler to still keep for both though. Add the workaround to that code as well; this is a lot simpler as we have just a single way to allocate DMA memory there. I made the algorithm recursive (with a small limit) since it's actually (almost) impossible to hit this today - dma_alloc_coherent is currently documented to always return 32-bit addressable memory regardless of the DMA mask for it, and so we could only get REALLY unlucky to get the very last page in that area. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c45
1 files changed, 42 insertions, 3 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
index d38cefbb779e..e249e3fd14c6 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c
@@ -57,6 +57,42 @@
#include "internal.h"
#include "iwl-prph.h"
+static void *_iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans,
+ size_t size,
+ dma_addr_t *phys,
+ int depth)
+{
+ void *result;
+
+ if (WARN(depth > 2,
+ "failed to allocate DMA memory not crossing 2^32 boundary"))
+ return NULL;
+
+ result = dma_alloc_coherent(trans->dev, size, phys, GFP_KERNEL);
+
+ if (!result)
+ return NULL;
+
+ if (unlikely(iwl_pcie_crosses_4g_boundary(*phys, size))) {
+ void *old = result;
+ dma_addr_t oldphys = *phys;
+
+ result = _iwl_pcie_ctxt_info_dma_alloc_coherent(trans, size,
+ phys,
+ depth + 1);
+ dma_free_coherent(trans->dev, size, old, oldphys);
+ }
+
+ return result;
+}
+
+static void *iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans,
+ size_t size,
+ dma_addr_t *phys)
+{
+ return _iwl_pcie_ctxt_info_dma_alloc_coherent(trans, size, phys, 0);
+}
+
void iwl_pcie_ctxt_info_free_paging(struct iwl_trans *trans)
{
struct iwl_self_init_dram *dram = &trans->init_dram;
@@ -161,14 +197,17 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans,
struct iwl_context_info *ctxt_info;
struct iwl_context_info_rbd_cfg *rx_cfg;
u32 control_flags = 0, rb_size;
+ dma_addr_t phys;
int ret;
- ctxt_info = dma_alloc_coherent(trans->dev, sizeof(*ctxt_info),
- &trans_pcie->ctxt_info_dma_addr,
- GFP_KERNEL);
+ ctxt_info = iwl_pcie_ctxt_info_dma_alloc_coherent(trans,
+ sizeof(*ctxt_info),
+ &phys);
if (!ctxt_info)
return -ENOMEM;
+ trans_pcie->ctxt_info_dma_addr = phys;
+
ctxt_info->version.version = 0;
ctxt_info->version.mac_id =
cpu_to_le16((u16)iwl_read32(trans, CSR_HW_REV));