ath10k: fix memory allocation issues on platforms where DMA coherent memory is constr...
[librecmc/librecmc.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;