lantiq: fix a race condition in the SPI driver leading to rx FIFO overflows (and...
[openwrt/staging/mkresin.git] / package / kernel / mac80211 / patches / 316-ath10k-do-not-use-coherent-memory-for-allocated-devi.patch
1 From: Felix Fietkau <nbd@openwrt.org>
2 Date: Sun, 22 Nov 2015 14:03:40 +0100
3 Subject: [PATCH] ath10k: do not use coherent memory for allocated device
4 memory chunks
5
6 Coherent memory is more expensive to allocate (and constrained on some
7 architectures where it has to be pre-allocated). It is also completely
8 unnecessary, since the host has no reason to even access these allocated
9 memory spaces
10
11 Signed-off-by: Felix Fietkau <nbd@openwrt.org>
12 ---
13
14 --- a/drivers/net/wireless/ath/ath10k/wmi.c
15 +++ b/drivers/net/wireless/ath/ath10k/wmi.c
16 @@ -4258,34 +4258,58 @@ void ath10k_wmi_event_vdev_resume_req(st
17 ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
18 }
19
20 -static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
21 - u32 num_units, u32 unit_len)
22 +static int ath10k_wmi_alloc_chunk(struct ath10k *ar, u32 req_id,
23 + u32 num_units, u32 unit_len)
24 {
25 dma_addr_t paddr;
26 u32 pool_size;
27 int idx = ar->wmi.num_mem_chunks;
28 + void *vaddr = NULL;
29
30 - pool_size = num_units * round_up(unit_len, 4);
31 + if (ar->wmi.num_mem_chunks == ARRAY_SIZE(ar->wmi.mem_chunks))
32 + return -ENOMEM;
33
34 - if (!pool_size)
35 - return -EINVAL;
36 + while (!vaddr && num_units) {
37 + pool_size = num_units * round_up(unit_len, 4);
38 + if (!pool_size)
39 + return -EINVAL;
40
41 - ar->wmi.mem_chunks[idx].vaddr = dma_alloc_coherent(ar->dev,
42 - pool_size,
43 - &paddr,
44 - GFP_KERNEL);
45 - if (!ar->wmi.mem_chunks[idx].vaddr) {
46 - ath10k_warn(ar, "failed to allocate memory chunk\n");
47 - return -ENOMEM;
48 + vaddr = kzalloc(pool_size, GFP_KERNEL | __GFP_NOWARN);
49 + if (!vaddr)
50 + num_units /= 2;
51 }
52
53 - memset(ar->wmi.mem_chunks[idx].vaddr, 0, pool_size);
54 + if (!num_units)
55 + return -ENOMEM;
56
57 + paddr = dma_map_single(ar->dev, vaddr, pool_size, DMA_TO_DEVICE);
58 + if (dma_mapping_error(ar->dev, paddr)) {
59 + kfree(vaddr);
60 + return -ENOMEM;
61 + }
62 +
63 + ar->wmi.mem_chunks[idx].vaddr = vaddr;
64 ar->wmi.mem_chunks[idx].paddr = paddr;
65 ar->wmi.mem_chunks[idx].len = pool_size;
66 ar->wmi.mem_chunks[idx].req_id = req_id;
67 ar->wmi.num_mem_chunks++;
68
69 + return num_units;
70 +}
71 +
72 +static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
73 + u32 num_units, u32 unit_len)
74 +{
75 + int ret;
76 +
77 + while (num_units) {
78 + ret = ath10k_wmi_alloc_chunk(ar, req_id, num_units, unit_len);
79 + if (ret < 0)
80 + return ret;
81 +
82 + num_units -= ret;
83 + }
84 +
85 return 0;
86 }
87
88 @@ -7616,10 +7640,11 @@ void ath10k_wmi_free_host_mem(struct ath
89
90 /* free the host memory chunks requested by firmware */
91 for (i = 0; i < ar->wmi.num_mem_chunks; i++) {
92 - dma_free_coherent(ar->dev,
93 - ar->wmi.mem_chunks[i].len,
94 - ar->wmi.mem_chunks[i].vaddr,
95 - ar->wmi.mem_chunks[i].paddr);
96 + dma_unmap_single(ar->dev,
97 + ar->wmi.mem_chunks[i].paddr,
98 + ar->wmi.mem_chunks[i].len,
99 + DMA_TO_DEVICE);
100 + kfree(ar->wmi.mem_chunks[i].vaddr);
101 }
102
103 ar->wmi.num_mem_chunks = 0;