ath10k: fix memory allocation issues on platforms where DMA coherent memory is constrained
Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 47625
This commit is contained in:
parent
bb1c915f1e
commit
a4e234d278
2 changed files with 157 additions and 0 deletions
|
@ -0,0 +1,103 @@
|
||||||
|
From: Felix Fietkau <nbd@openwrt.org>
|
||||||
|
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 <nbd@openwrt.org>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- 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;
|
|
@ -0,0 +1,54 @@
|
||||||
|
From: Felix Fietkau <nbd@openwrt.org>
|
||||||
|
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 <nbd@openwrt.org>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- 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;
|
Loading…
Reference in a new issue