ath10k-firmware: remove dependency on kmod-ath10k so that it can be selected instead
[15.05/openwrt.git] / package / kernel / mac80211 / patches / 372-0001-brcmfmac-expose-device-memory-to-devcoredump-subsyst.patch
1 From: Arend van Spriel <arend@broadcom.com>
2 Date: Thu, 8 Oct 2015 20:33:11 +0200
3 Subject: [PATCH] brcmfmac: expose device memory to devcoredump subsystem
4
5 Upon PSM watchdog event received from firmware the driver will obtain
6 a memory snapshot of the device and expose it to user-space through
7 the devcoredump framework. This will trigger a uevent.
8
9 Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
10 Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
11 Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
12 Signed-off-by: Arend van Spriel <arend@broadcom.com>
13 Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
14 ---
15
16 --- a/drivers/net/wireless/brcm80211/Kconfig
17 +++ b/drivers/net/wireless/brcm80211/Kconfig
18 @@ -85,5 +85,6 @@ config BRCM_TRACING
19  config BRCMDBG
20         bool "Broadcom driver debug functions"
21         depends on BRCMSMAC || BRCMFMAC
22 +       select WANT_DEV_COREDUMP
23         ---help---
24           Selecting this enables additional code for debug purposes.
25 --- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h
26 +++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h
27 @@ -65,6 +65,8 @@ struct brcmf_bus_dcmd {
28   * @rxctl: receive a control response message from dongle.
29   * @gettxq: obtain a reference of bus transmit queue (optional).
30   * @wowl_config: specify if dongle is configured for wowl when going to suspend
31 + * @get_ramsize: obtain size of device memory.
32 + * @get_memdump: obtain device memory dump in provided buffer.
33   *
34   * This structure provides an abstract interface towards the
35   * bus specific driver. For control messages to common driver
36 @@ -79,6 +81,8 @@ struct brcmf_bus_ops {
37         int (*rxctl)(struct device *dev, unsigned char *msg, uint len);
38         struct pktq * (*gettxq)(struct device *dev);
39         void (*wowl_config)(struct device *dev, bool enabled);
40 +       size_t (*get_ramsize)(struct device *dev);
41 +       int (*get_memdump)(struct device *dev, void *data, size_t len);
42  };
43  
44  
45 @@ -185,6 +189,23 @@ void brcmf_bus_wowl_config(struct brcmf_
46                 bus->ops->wowl_config(bus->dev, enabled);
47  }
48  
49 +static inline size_t brcmf_bus_get_ramsize(struct brcmf_bus *bus)
50 +{
51 +       if (!bus->ops->get_ramsize)
52 +               return 0;
53 +
54 +       return bus->ops->get_ramsize(bus->dev);
55 +}
56 +
57 +static inline
58 +int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len)
59 +{
60 +       if (!bus->ops->get_memdump)
61 +               return -EOPNOTSUPP;
62 +
63 +       return bus->ops->get_memdump(bus->dev, data, len);
64 +}
65 +
66  /*
67   * interface functions from common layer
68   */
69 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
70 +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
71 @@ -957,8 +957,8 @@ int brcmf_attach(struct device *dev)
72         drvr->bus_if = dev_get_drvdata(dev);
73         drvr->bus_if->drvr = drvr;
74  
75 -       /* create device debugfs folder */
76 -       brcmf_debugfs_attach(drvr);
77 +       /* attach debug facilities */
78 +       brcmf_debug_attach(drvr);
79  
80         /* Attach and link in the protocol */
81         ret = brcmf_proto_attach(drvr);
82 @@ -1155,7 +1155,7 @@ void brcmf_detach(struct device *dev)
83  
84         brcmf_proto_detach(drvr);
85  
86 -       brcmf_debugfs_detach(drvr);
87 +       brcmf_debug_detach(drvr);
88         bus_if->drvr = NULL;
89         kfree(drvr);
90  }
91 --- a/drivers/net/wireless/brcm80211/brcmfmac/debug.c
92 +++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.c
93 @@ -16,15 +16,45 @@
94  #include <linux/debugfs.h>
95  #include <linux/netdevice.h>
96  #include <linux/module.h>
97 +#include <linux/devcoredump.h>
98  
99  #include <brcmu_wifi.h>
100  #include <brcmu_utils.h>
101  #include "core.h"
102  #include "bus.h"
103 +#include "fweh.h"
104  #include "debug.h"
105  
106  static struct dentry *root_folder;
107  
108 +static int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
109 +                                     size_t len)
110 +{
111 +       void *dump;
112 +       size_t ramsize;
113 +
114 +       ramsize = brcmf_bus_get_ramsize(bus);
115 +       if (ramsize) {
116 +               dump = vzalloc(len + ramsize);
117 +               if (!dump)
118 +                       return -ENOMEM;
119 +               memcpy(dump, data, len);
120 +               brcmf_bus_get_memdump(bus, dump + len, ramsize);
121 +               dev_coredumpv(bus->dev, dump, len + ramsize, GFP_KERNEL);
122 +       }
123 +       return 0;
124 +}
125 +
126 +static int brcmf_debug_psm_watchdog_notify(struct brcmf_if *ifp,
127 +                                          const struct brcmf_event_msg *evtmsg,
128 +                                          void *data)
129 +{
130 +       brcmf_dbg(TRACE, "enter: idx=%d\n", ifp->bssidx);
131 +
132 +       return brcmf_debug_create_memdump(ifp->drvr->bus_if, data,
133 +                                         evtmsg->datalen);
134 +}
135 +
136  void brcmf_debugfs_init(void)
137  {
138         root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL);
139 @@ -41,7 +71,7 @@ void brcmf_debugfs_exit(void)
140         root_folder = NULL;
141  }
142  
143 -int brcmf_debugfs_attach(struct brcmf_pub *drvr)
144 +int brcmf_debug_attach(struct brcmf_pub *drvr)
145  {
146         struct device *dev = drvr->bus_if->dev;
147  
148 @@ -49,12 +79,18 @@ int brcmf_debugfs_attach(struct brcmf_pu
149                 return -ENODEV;
150  
151         drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder);
152 +       if (IS_ERR(drvr->dbgfs_dir))
153 +               return PTR_ERR(drvr->dbgfs_dir);
154  
155 -       return PTR_ERR_OR_ZERO(drvr->dbgfs_dir);
156 +
157 +       return brcmf_fweh_register(drvr, BRCMF_E_PSM_WATCHDOG,
158 +                                  brcmf_debug_psm_watchdog_notify);
159  }
160  
161 -void brcmf_debugfs_detach(struct brcmf_pub *drvr)
162 +void brcmf_debug_detach(struct brcmf_pub *drvr)
163  {
164 +       brcmf_fweh_unregister(drvr, BRCMF_E_PSM_WATCHDOG);
165 +
166         if (!IS_ERR_OR_NULL(drvr->dbgfs_dir))
167                 debugfs_remove_recursive(drvr->dbgfs_dir);
168  }
169 --- a/drivers/net/wireless/brcm80211/brcmfmac/debug.h
170 +++ b/drivers/net/wireless/brcm80211/brcmfmac/debug.h
171 @@ -109,8 +109,8 @@ struct brcmf_pub;
172  #ifdef DEBUG
173  void brcmf_debugfs_init(void);
174  void brcmf_debugfs_exit(void);
175 -int brcmf_debugfs_attach(struct brcmf_pub *drvr);
176 -void brcmf_debugfs_detach(struct brcmf_pub *drvr);
177 +int brcmf_debug_attach(struct brcmf_pub *drvr);
178 +void brcmf_debug_detach(struct brcmf_pub *drvr);
179  struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
180  int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
181                             int (*read_fn)(struct seq_file *seq, void *data));
182 @@ -121,11 +121,11 @@ static inline void brcmf_debugfs_init(vo
183  static inline void brcmf_debugfs_exit(void)
184  {
185  }
186 -static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr)
187 +static inline int brcmf_debug_attach(struct brcmf_pub *drvr)
188  {
189         return 0;
190  }
191 -static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr)
192 +static inline void brcmf_debug_detach(struct brcmf_pub *drvr)
193  {
194  }
195  static inline
196 --- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
197 +++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
198 @@ -448,6 +448,47 @@ brcmf_pcie_copy_mem_todev(struct brcmf_p
199  }
200  
201  
202 +static void
203 +brcmf_pcie_copy_dev_tomem(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
204 +                         void *dstaddr, u32 len)
205 +{
206 +       void __iomem *address = devinfo->tcm + mem_offset;
207 +       __le32 *dst32;
208 +       __le16 *dst16;
209 +       u8 *dst8;
210 +
211 +       if (((ulong)address & 4) || ((ulong)dstaddr & 4) || (len & 4)) {
212 +               if (((ulong)address & 2) || ((ulong)dstaddr & 2) || (len & 2)) {
213 +                       dst8 = (u8 *)dstaddr;
214 +                       while (len) {
215 +                               *dst8 = ioread8(address);
216 +                               address++;
217 +                               dst8++;
218 +                               len--;
219 +                       }
220 +               } else {
221 +                       len = len / 2;
222 +                       dst16 = (__le16 *)dstaddr;
223 +                       while (len) {
224 +                               *dst16 = cpu_to_le16(ioread16(address));
225 +                               address += 2;
226 +                               dst16++;
227 +                               len--;
228 +                       }
229 +               }
230 +       } else {
231 +               len = len / 4;
232 +               dst32 = (__le32 *)dstaddr;
233 +               while (len) {
234 +                       *dst32 = cpu_to_le32(ioread32(address));
235 +                       address += 4;
236 +                       dst32++;
237 +                       len--;
238 +               }
239 +       }
240 +}
241 +
242 +
243  #define WRITECC32(devinfo, reg, value) brcmf_pcie_write_reg32(devinfo, \
244                 CHIPCREGOFFS(reg), value)
245  
246 @@ -1352,12 +1393,36 @@ static void brcmf_pcie_wowl_config(struc
247  }
248  
249  
250 +static size_t brcmf_pcie_get_ramsize(struct device *dev)
251 +{
252 +       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
253 +       struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
254 +       struct brcmf_pciedev_info *devinfo = buspub->devinfo;
255 +
256 +       return devinfo->ci->ramsize - devinfo->ci->srsize;
257 +}
258 +
259 +
260 +static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len)
261 +{
262 +       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
263 +       struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie;
264 +       struct brcmf_pciedev_info *devinfo = buspub->devinfo;
265 +
266 +       brcmf_dbg(PCIE, "dump at 0x%08X: len=%zu\n", devinfo->ci->rambase, len);
267 +       brcmf_pcie_copy_dev_tomem(devinfo, devinfo->ci->rambase, data, len);
268 +       return 0;
269 +}
270 +
271 +
272  static struct brcmf_bus_ops brcmf_pcie_bus_ops = {
273         .txdata = brcmf_pcie_tx,
274         .stop = brcmf_pcie_down,
275         .txctl = brcmf_pcie_tx_ctlpkt,
276         .rxctl = brcmf_pcie_rx_ctlpkt,
277         .wowl_config = brcmf_pcie_wowl_config,
278 +       .get_ramsize = brcmf_pcie_get_ramsize,
279 +       .get_memdump = brcmf_pcie_get_memdump,
280  };
281  
282  
283 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
284 +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
285 @@ -3539,6 +3539,51 @@ done:
286         return err;
287  }
288  
289 +static size_t brcmf_sdio_bus_get_ramsize(struct device *dev)
290 +{
291 +       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
292 +       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
293 +       struct brcmf_sdio *bus = sdiodev->bus;
294 +
295 +       return bus->ci->ramsize - bus->ci->srsize;
296 +}
297 +
298 +static int brcmf_sdio_bus_get_memdump(struct device *dev, void *data,
299 +                                     size_t mem_size)
300 +{
301 +       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
302 +       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
303 +       struct brcmf_sdio *bus = sdiodev->bus;
304 +       int err;
305 +       int address;
306 +       int offset;
307 +       int len;
308 +
309 +       brcmf_dbg(INFO, "dump at 0x%08x: size=%zu\n", bus->ci->rambase,
310 +                 mem_size);
311 +
312 +       address = bus->ci->rambase;
313 +       offset = err = 0;
314 +       sdio_claim_host(sdiodev->func[1]);
315 +       while (offset < mem_size) {
316 +               len = ((offset + MEMBLOCK) < mem_size) ? MEMBLOCK :
317 +                     mem_size - offset;
318 +               err = brcmf_sdiod_ramrw(sdiodev, false, address, data, len);
319 +               if (err) {
320 +                       brcmf_err("error %d on reading %d membytes at 0x%08x\n",
321 +                                 err, len, address);
322 +                       goto done;
323 +               }
324 +               data += len;
325 +               offset += len;
326 +               address += len;
327 +       }
328 +
329 +done:
330 +       sdio_release_host(sdiodev->func[1]);
331 +       return err;
332 +}
333 +
334  void brcmf_sdio_trigger_dpc(struct brcmf_sdio *bus)
335  {
336         if (!bus->dpc_triggered) {
337 @@ -3987,7 +4032,9 @@ static struct brcmf_bus_ops brcmf_sdio_b
338         .txctl = brcmf_sdio_bus_txctl,
339         .rxctl = brcmf_sdio_bus_rxctl,
340         .gettxq = brcmf_sdio_bus_gettxq,
341 -       .wowl_config = brcmf_sdio_wowl_config
342 +       .wowl_config = brcmf_sdio_wowl_config,
343 +       .get_ramsize = brcmf_sdio_bus_get_ramsize,
344 +       .get_memdump = brcmf_sdio_bus_get_memdump,
345  };
346  
347  static void brcmf_sdio_firmware_callback(struct device *dev,