From: Felix Fietkau Date: Tue, 24 Nov 2015 19:09:45 +0000 (+0000) Subject: ath10k: fix memory allocation issues on platforms where DMA coherent memory is constr... X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=a4e234d278203e276ceb48dd4872aaa66bf777c9;p=openwrt%2Fstaging%2Fnbd.git ath10k: fix memory allocation issues on platforms where DMA coherent memory is constrained Signed-off-by: Felix Fietkau SVN-Revision: 47625 --- diff --git a/package/kernel/mac80211/patches/316-ath10k-do-not-use-coherent-memory-for-allocated-devi.patch b/package/kernel/mac80211/patches/316-ath10k-do-not-use-coherent-memory-for-allocated-devi.patch new file mode 100644 index 0000000000..66ebe7628e --- /dev/null +++ b/package/kernel/mac80211/patches/316-ath10k-do-not-use-coherent-memory-for-allocated-devi.patch @@ -0,0 +1,103 @@ +From: Felix Fietkau +Date: Sun, 22 Nov 2015 14:03:40 +0100 +Subject: [PATCH] ath10k: do not use coherent memory for allocated device + memory chunks + +Coherent memory is more expensive to allocate (and constrained on some +architectures where it has to be pre-allocated). It is also completely +unnecessary, since the host has no reason to even access these allocated +memory spaces + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/wireless/ath/ath10k/wmi.c ++++ b/drivers/net/wireless/ath/ath10k/wmi.c +@@ -4258,34 +4258,58 @@ void ath10k_wmi_event_vdev_resume_req(st + ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n"); + } + +-static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id, +- u32 num_units, u32 unit_len) ++static int ath10k_wmi_alloc_chunk(struct ath10k *ar, u32 req_id, ++ u32 num_units, u32 unit_len) + { + dma_addr_t paddr; + u32 pool_size; + int idx = ar->wmi.num_mem_chunks; ++ void *vaddr = NULL; + +- pool_size = num_units * round_up(unit_len, 4); ++ if (ar->wmi.num_mem_chunks == ARRAY_SIZE(ar->wmi.mem_chunks)) ++ return -ENOMEM; + +- if (!pool_size) +- return -EINVAL; ++ while (!vaddr && num_units) { ++ pool_size = num_units * round_up(unit_len, 4); ++ if (!pool_size) ++ return -EINVAL; + +- ar->wmi.mem_chunks[idx].vaddr = dma_alloc_coherent(ar->dev, +- pool_size, +- &paddr, +- GFP_KERNEL); +- if (!ar->wmi.mem_chunks[idx].vaddr) { +- ath10k_warn(ar, "failed to allocate memory chunk\n"); +- return -ENOMEM; ++ vaddr = kzalloc(pool_size, GFP_KERNEL | __GFP_NOWARN); ++ if (!vaddr) ++ num_units /= 2; + } + +- memset(ar->wmi.mem_chunks[idx].vaddr, 0, pool_size); ++ if (!num_units) ++ return -ENOMEM; + ++ paddr = dma_map_single(ar->dev, vaddr, pool_size, DMA_TO_DEVICE); ++ if (dma_mapping_error(ar->dev, paddr)) { ++ kfree(vaddr); ++ return -ENOMEM; ++ } ++ ++ ar->wmi.mem_chunks[idx].vaddr = vaddr; + ar->wmi.mem_chunks[idx].paddr = paddr; + ar->wmi.mem_chunks[idx].len = pool_size; + ar->wmi.mem_chunks[idx].req_id = req_id; + ar->wmi.num_mem_chunks++; + ++ return num_units; ++} ++ ++static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id, ++ u32 num_units, u32 unit_len) ++{ ++ int ret; ++ ++ while (num_units) { ++ ret = ath10k_wmi_alloc_chunk(ar, req_id, num_units, unit_len); ++ if (ret < 0) ++ return ret; ++ ++ num_units -= ret; ++ } ++ + return 0; + } + +@@ -7616,10 +7640,11 @@ void ath10k_wmi_free_host_mem(struct ath + + /* free the host memory chunks requested by firmware */ + for (i = 0; i < ar->wmi.num_mem_chunks; i++) { +- dma_free_coherent(ar->dev, +- ar->wmi.mem_chunks[i].len, +- ar->wmi.mem_chunks[i].vaddr, +- ar->wmi.mem_chunks[i].paddr); ++ dma_unmap_single(ar->dev, ++ ar->wmi.mem_chunks[i].paddr, ++ ar->wmi.mem_chunks[i].len, ++ DMA_TO_DEVICE); ++ kfree(ar->wmi.mem_chunks[i].vaddr); + } + + ar->wmi.num_mem_chunks = 0; diff --git a/package/kernel/mac80211/patches/317-ath10k-stop-abusing-GFP_DMA.patch b/package/kernel/mac80211/patches/317-ath10k-stop-abusing-GFP_DMA.patch new file mode 100644 index 0000000000..a229a1306a --- /dev/null +++ b/package/kernel/mac80211/patches/317-ath10k-stop-abusing-GFP_DMA.patch @@ -0,0 +1,54 @@ +From: Felix Fietkau +Date: Tue, 24 Nov 2015 11:33:54 +0100 +Subject: [PATCH] ath10k: stop abusing GFP_DMA + +Allocations from the DMA zone were originally added for legacy ISA +stuff, or PCI devices that have specific limitations in their DMA +addressing capabilities. It has no place in ath10k, which can do +full 32-bit DMA. + +Fixes memory allocation errors on some platforms. + +Signed-off-by: Felix Fietkau +--- + +--- a/drivers/net/wireless/ath/ath10k/htt_rx.c ++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c +@@ -536,7 +536,7 @@ int ath10k_htt_rx_alloc(struct ath10k_ht + + size = htt->rx_ring.size * sizeof(htt->rx_ring.paddrs_ring); + +- vaddr = dma_alloc_coherent(htt->ar->dev, size, &paddr, GFP_DMA); ++ vaddr = dma_alloc_coherent(htt->ar->dev, size, &paddr, GFP_KERNEL); + if (!vaddr) + goto err_dma_ring; + +@@ -545,7 +545,7 @@ int ath10k_htt_rx_alloc(struct ath10k_ht + + vaddr = dma_alloc_coherent(htt->ar->dev, + sizeof(*htt->rx_ring.alloc_idx.vaddr), +- &paddr, GFP_DMA); ++ &paddr, GFP_KERNEL); + if (!vaddr) + goto err_dma_idx; + +--- a/drivers/net/wireless/ath/ath10k/htt_tx.c ++++ b/drivers/net/wireless/ath/ath10k/htt_tx.c +@@ -111,7 +111,7 @@ int ath10k_htt_tx_alloc(struct ath10k_ht + size = htt->max_num_pending_tx * sizeof(struct ath10k_htt_txbuf); + htt->txbuf.vaddr = dma_alloc_coherent(ar->dev, size, + &htt->txbuf.paddr, +- GFP_DMA); ++ GFP_KERNEL); + if (!htt->txbuf.vaddr) { + ath10k_err(ar, "failed to alloc tx buffer\n"); + ret = -ENOMEM; +@@ -124,7 +124,7 @@ int ath10k_htt_tx_alloc(struct ath10k_ht + size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc); + htt->frag_desc.vaddr = dma_alloc_coherent(ar->dev, size, + &htt->frag_desc.paddr, +- GFP_DMA); ++ GFP_KERNEL); + if (!htt->frag_desc.vaddr) { + ath10k_warn(ar, "failed to alloc fragment desc memory\n"); + ret = -ENOMEM;