]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/brcm80211/brcmfmac/firmware.c
Merge tag 'sound-4.2-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[karo-tx-linux.git] / drivers / net / wireless / brcm80211 / brcmfmac / firmware.c
1 /*
2  * Copyright (c) 2013 Broadcom Corporation
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
11  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/slab.h>
19 #include <linux/device.h>
20 #include <linux/firmware.h>
21 #include <linux/module.h>
22
23 #include "debug.h"
24 #include "firmware.h"
25
26 #define BRCMF_FW_MAX_NVRAM_SIZE                 64000
27 #define BRCMF_FW_NVRAM_DEVPATH_LEN              19      /* devpath0=pcie/1/4/ */
28 #define BRCMF_FW_NVRAM_PCIEDEV_LEN              10      /* pcie/1/4/ + \0 */
29
30 char brcmf_firmware_path[BRCMF_FW_PATH_LEN];
31 module_param_string(firmware_path, brcmf_firmware_path,
32                     BRCMF_FW_PATH_LEN, 0440);
33
34 enum nvram_parser_state {
35         IDLE,
36         KEY,
37         VALUE,
38         COMMENT,
39         END
40 };
41
42 /**
43  * struct nvram_parser - internal info for parser.
44  *
45  * @state: current parser state.
46  * @data: input buffer being parsed.
47  * @nvram: output buffer with parse result.
48  * @nvram_len: lenght of parse result.
49  * @line: current line.
50  * @column: current column in line.
51  * @pos: byte offset in input buffer.
52  * @entry: start position of key,value entry.
53  * @multi_dev_v1: detect pcie multi device v1 (compressed).
54  * @multi_dev_v2: detect pcie multi device v2.
55  */
56 struct nvram_parser {
57         enum nvram_parser_state state;
58         const u8 *data;
59         u8 *nvram;
60         u32 nvram_len;
61         u32 line;
62         u32 column;
63         u32 pos;
64         u32 entry;
65         bool multi_dev_v1;
66         bool multi_dev_v2;
67 };
68
69 /**
70  * is_nvram_char() - check if char is a valid one for NVRAM entry
71  *
72  * It accepts all printable ASCII chars except for '#' which opens a comment.
73  * Please note that ' ' (space) while accepted is not a valid key name char.
74  */
75 static bool is_nvram_char(char c)
76 {
77         /* comment marker excluded */
78         if (c == '#')
79                 return false;
80
81         /* key and value may have any other readable character */
82         return (c >= 0x20 && c < 0x7f);
83 }
84
85 static bool is_whitespace(char c)
86 {
87         return (c == ' ' || c == '\r' || c == '\n' || c == '\t');
88 }
89
90 static enum nvram_parser_state brcmf_nvram_handle_idle(struct nvram_parser *nvp)
91 {
92         char c;
93
94         c = nvp->data[nvp->pos];
95         if (c == '\n')
96                 return COMMENT;
97         if (is_whitespace(c))
98                 goto proceed;
99         if (c == '#')
100                 return COMMENT;
101         if (is_nvram_char(c)) {
102                 nvp->entry = nvp->pos;
103                 return KEY;
104         }
105         brcmf_dbg(INFO, "warning: ln=%d:col=%d: ignoring invalid character\n",
106                   nvp->line, nvp->column);
107 proceed:
108         nvp->column++;
109         nvp->pos++;
110         return IDLE;
111 }
112
113 static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp)
114 {
115         enum nvram_parser_state st = nvp->state;
116         char c;
117
118         c = nvp->data[nvp->pos];
119         if (c == '=') {
120                 /* ignore RAW1 by treating as comment */
121                 if (strncmp(&nvp->data[nvp->entry], "RAW1", 4) == 0)
122                         st = COMMENT;
123                 else
124                         st = VALUE;
125                 if (strncmp(&nvp->data[nvp->entry], "devpath", 7) == 0)
126                         nvp->multi_dev_v1 = true;
127                 if (strncmp(&nvp->data[nvp->entry], "pcie/", 5) == 0)
128                         nvp->multi_dev_v2 = true;
129         } else if (!is_nvram_char(c) || c == ' ') {
130                 brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
131                           nvp->line, nvp->column);
132                 return COMMENT;
133         }
134
135         nvp->column++;
136         nvp->pos++;
137         return st;
138 }
139
140 static enum nvram_parser_state
141 brcmf_nvram_handle_value(struct nvram_parser *nvp)
142 {
143         char c;
144         char *skv;
145         char *ekv;
146         u32 cplen;
147
148         c = nvp->data[nvp->pos];
149         if (!is_nvram_char(c)) {
150                 /* key,value pair complete */
151                 ekv = (u8 *)&nvp->data[nvp->pos];
152                 skv = (u8 *)&nvp->data[nvp->entry];
153                 cplen = ekv - skv;
154                 if (nvp->nvram_len + cplen + 1 >= BRCMF_FW_MAX_NVRAM_SIZE)
155                         return END;
156                 /* copy to output buffer */
157                 memcpy(&nvp->nvram[nvp->nvram_len], skv, cplen);
158                 nvp->nvram_len += cplen;
159                 nvp->nvram[nvp->nvram_len] = '\0';
160                 nvp->nvram_len++;
161                 return IDLE;
162         }
163         nvp->pos++;
164         nvp->column++;
165         return VALUE;
166 }
167
168 static enum nvram_parser_state
169 brcmf_nvram_handle_comment(struct nvram_parser *nvp)
170 {
171         char *eoc, *sol;
172
173         sol = (char *)&nvp->data[nvp->pos];
174         eoc = strchr(sol, '\n');
175         if (!eoc) {
176                 eoc = strchr(sol, '\0');
177                 if (!eoc)
178                         return END;
179         }
180
181         /* eat all moving to next line */
182         nvp->line++;
183         nvp->column = 1;
184         nvp->pos += (eoc - sol) + 1;
185         return IDLE;
186 }
187
188 static enum nvram_parser_state brcmf_nvram_handle_end(struct nvram_parser *nvp)
189 {
190         /* final state */
191         return END;
192 }
193
194 static enum nvram_parser_state
195 (*nv_parser_states[])(struct nvram_parser *nvp) = {
196         brcmf_nvram_handle_idle,
197         brcmf_nvram_handle_key,
198         brcmf_nvram_handle_value,
199         brcmf_nvram_handle_comment,
200         brcmf_nvram_handle_end
201 };
202
203 static int brcmf_init_nvram_parser(struct nvram_parser *nvp,
204                                    const u8 *data, size_t data_len)
205 {
206         size_t size;
207
208         memset(nvp, 0, sizeof(*nvp));
209         nvp->data = data;
210         /* Limit size to MAX_NVRAM_SIZE, some files contain lot of comment */
211         if (data_len > BRCMF_FW_MAX_NVRAM_SIZE)
212                 size = BRCMF_FW_MAX_NVRAM_SIZE;
213         else
214                 size = data_len;
215         /* Alloc for extra 0 byte + roundup by 4 + length field */
216         size += 1 + 3 + sizeof(u32);
217         nvp->nvram = kzalloc(size, GFP_KERNEL);
218         if (!nvp->nvram)
219                 return -ENOMEM;
220
221         nvp->line = 1;
222         nvp->column = 1;
223         return 0;
224 }
225
226 /* brcmf_fw_strip_multi_v1 :Some nvram files contain settings for multiple
227  * devices. Strip it down for one device, use domain_nr/bus_nr to determine
228  * which data is to be returned. v1 is the version where nvram is stored
229  * compressed and "devpath" maps to index for valid entries.
230  */
231 static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr,
232                                     u16 bus_nr)
233 {
234         /* Device path with a leading '=' key-value separator */
235         char pci_path[] = "=pci/?/?";
236         size_t pci_len;
237         char pcie_path[] = "=pcie/?/?";
238         size_t pcie_len;
239
240         u32 i, j;
241         bool found;
242         u8 *nvram;
243         u8 id;
244
245         nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
246         if (!nvram)
247                 goto fail;
248
249         /* min length: devpath0=pcie/1/4/ + 0:x=y */
250         if (nvp->nvram_len < BRCMF_FW_NVRAM_DEVPATH_LEN + 6)
251                 goto fail;
252
253         /* First search for the devpathX and see if it is the configuration
254          * for domain_nr/bus_nr. Search complete nvp
255          */
256         snprintf(pci_path, sizeof(pci_path), "=pci/%d/%d", domain_nr,
257                  bus_nr);
258         pci_len = strlen(pci_path);
259         snprintf(pcie_path, sizeof(pcie_path), "=pcie/%d/%d", domain_nr,
260                  bus_nr);
261         pcie_len = strlen(pcie_path);
262         found = false;
263         i = 0;
264         while (i < nvp->nvram_len - BRCMF_FW_NVRAM_DEVPATH_LEN) {
265                 /* Format: devpathX=pcie/Y/Z/
266                  * Y = domain_nr, Z = bus_nr, X = virtual ID
267                  */
268                 if (strncmp(&nvp->nvram[i], "devpath", 7) == 0 &&
269                     (!strncmp(&nvp->nvram[i + 8], pci_path, pci_len) ||
270                      !strncmp(&nvp->nvram[i + 8], pcie_path, pcie_len))) {
271                         id = nvp->nvram[i + 7] - '0';
272                         found = true;
273                         break;
274                 }
275                 while (nvp->nvram[i] != 0)
276                         i++;
277                 i++;
278         }
279         if (!found)
280                 goto fail;
281
282         /* Now copy all valid entries, release old nvram and assign new one */
283         i = 0;
284         j = 0;
285         while (i < nvp->nvram_len) {
286                 if ((nvp->nvram[i] - '0' == id) && (nvp->nvram[i + 1] == ':')) {
287                         i += 2;
288                         while (nvp->nvram[i] != 0) {
289                                 nvram[j] = nvp->nvram[i];
290                                 i++;
291                                 j++;
292                         }
293                         nvram[j] = 0;
294                         j++;
295                 }
296                 while (nvp->nvram[i] != 0)
297                         i++;
298                 i++;
299         }
300         kfree(nvp->nvram);
301         nvp->nvram = nvram;
302         nvp->nvram_len = j;
303         return;
304
305 fail:
306         kfree(nvram);
307         nvp->nvram_len = 0;
308 }
309
310 /* brcmf_fw_strip_multi_v2 :Some nvram files contain settings for multiple
311  * devices. Strip it down for one device, use domain_nr/bus_nr to determine
312  * which data is to be returned. v2 is the version where nvram is stored
313  * uncompressed, all relevant valid entries are identified by
314  * pcie/domain_nr/bus_nr:
315  */
316 static void brcmf_fw_strip_multi_v2(struct nvram_parser *nvp, u16 domain_nr,
317                                     u16 bus_nr)
318 {
319         char prefix[BRCMF_FW_NVRAM_PCIEDEV_LEN];
320         size_t len;
321         u32 i, j;
322         u8 *nvram;
323
324         nvram = kzalloc(nvp->nvram_len + 1 + 3 + sizeof(u32), GFP_KERNEL);
325         if (!nvram)
326                 goto fail;
327
328         /* Copy all valid entries, release old nvram and assign new one.
329          * Valid entries are of type pcie/X/Y/ where X = domain_nr and
330          * Y = bus_nr.
331          */
332         snprintf(prefix, sizeof(prefix), "pcie/%d/%d/", domain_nr, bus_nr);
333         len = strlen(prefix);
334         i = 0;
335         j = 0;
336         while (i < nvp->nvram_len - len) {
337                 if (strncmp(&nvp->nvram[i], prefix, len) == 0) {
338                         i += len;
339                         while (nvp->nvram[i] != 0) {
340                                 nvram[j] = nvp->nvram[i];
341                                 i++;
342                                 j++;
343                         }
344                         nvram[j] = 0;
345                         j++;
346                 }
347                 while (nvp->nvram[i] != 0)
348                         i++;
349                 i++;
350         }
351         kfree(nvp->nvram);
352         nvp->nvram = nvram;
353         nvp->nvram_len = j;
354         return;
355 fail:
356         kfree(nvram);
357         nvp->nvram_len = 0;
358 }
359
360 /* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil
361  * and ending in a NUL. Removes carriage returns, empty lines, comment lines,
362  * and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
363  * End of buffer is completed with token identifying length of buffer.
364  */
365 static void *brcmf_fw_nvram_strip(const u8 *data, size_t data_len,
366                                   u32 *new_length, u16 domain_nr, u16 bus_nr)
367 {
368         struct nvram_parser nvp;
369         u32 pad;
370         u32 token;
371         __le32 token_le;
372
373         if (brcmf_init_nvram_parser(&nvp, data, data_len) < 0)
374                 return NULL;
375
376         while (nvp.pos < data_len) {
377                 nvp.state = nv_parser_states[nvp.state](&nvp);
378                 if (nvp.state == END)
379                         break;
380         }
381         if (nvp.multi_dev_v1)
382                 brcmf_fw_strip_multi_v1(&nvp, domain_nr, bus_nr);
383         else if (nvp.multi_dev_v2)
384                 brcmf_fw_strip_multi_v2(&nvp, domain_nr, bus_nr);
385
386         if (nvp.nvram_len == 0) {
387                 kfree(nvp.nvram);
388                 return NULL;
389         }
390
391         pad = nvp.nvram_len;
392         *new_length = roundup(nvp.nvram_len + 1, 4);
393         while (pad != *new_length) {
394                 nvp.nvram[pad] = 0;
395                 pad++;
396         }
397
398         token = *new_length / 4;
399         token = (~token << 16) | (token & 0x0000FFFF);
400         token_le = cpu_to_le32(token);
401
402         memcpy(&nvp.nvram[*new_length], &token_le, sizeof(token_le));
403         *new_length += sizeof(token_le);
404
405         return nvp.nvram;
406 }
407
408 void brcmf_fw_nvram_free(void *nvram)
409 {
410         kfree(nvram);
411 }
412
413 struct brcmf_fw {
414         struct device *dev;
415         u16 flags;
416         const struct firmware *code;
417         const char *nvram_name;
418         u16 domain_nr;
419         u16 bus_nr;
420         void (*done)(struct device *dev, const struct firmware *fw,
421                      void *nvram_image, u32 nvram_len);
422 };
423
424 static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
425 {
426         struct brcmf_fw *fwctx = ctx;
427         u32 nvram_length = 0;
428         void *nvram = NULL;
429
430         brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
431         if (!fw && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
432                 goto fail;
433
434         if (fw) {
435                 nvram = brcmf_fw_nvram_strip(fw->data, fw->size, &nvram_length,
436                                              fwctx->domain_nr, fwctx->bus_nr);
437                 release_firmware(fw);
438                 if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL))
439                         goto fail;
440         }
441
442         fwctx->done(fwctx->dev, fwctx->code, nvram, nvram_length);
443         kfree(fwctx);
444         return;
445
446 fail:
447         brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
448         release_firmware(fwctx->code);
449         device_release_driver(fwctx->dev);
450         kfree(fwctx);
451 }
452
453 static void brcmf_fw_request_code_done(const struct firmware *fw, void *ctx)
454 {
455         struct brcmf_fw *fwctx = ctx;
456         int ret;
457
458         brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
459         if (!fw)
460                 goto fail;
461
462         /* only requested code so done here */
463         if (!(fwctx->flags & BRCMF_FW_REQUEST_NVRAM)) {
464                 fwctx->done(fwctx->dev, fw, NULL, 0);
465                 kfree(fwctx);
466                 return;
467         }
468         fwctx->code = fw;
469         ret = request_firmware_nowait(THIS_MODULE, true, fwctx->nvram_name,
470                                       fwctx->dev, GFP_KERNEL, fwctx,
471                                       brcmf_fw_request_nvram_done);
472
473         if (!ret)
474                 return;
475
476         /* when nvram is optional call .done() callback here */
477         if (fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL) {
478                 fwctx->done(fwctx->dev, fw, NULL, 0);
479                 kfree(fwctx);
480                 return;
481         }
482
483         /* failed nvram request */
484         release_firmware(fw);
485 fail:
486         brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
487         device_release_driver(fwctx->dev);
488         kfree(fwctx);
489 }
490
491 int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
492                                 const char *code, const char *nvram,
493                                 void (*fw_cb)(struct device *dev,
494                                               const struct firmware *fw,
495                                               void *nvram_image, u32 nvram_len),
496                                 u16 domain_nr, u16 bus_nr)
497 {
498         struct brcmf_fw *fwctx;
499
500         brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
501         if (!fw_cb || !code)
502                 return -EINVAL;
503
504         if ((flags & BRCMF_FW_REQUEST_NVRAM) && !nvram)
505                 return -EINVAL;
506
507         fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL);
508         if (!fwctx)
509                 return -ENOMEM;
510
511         fwctx->dev = dev;
512         fwctx->flags = flags;
513         fwctx->done = fw_cb;
514         if (flags & BRCMF_FW_REQUEST_NVRAM)
515                 fwctx->nvram_name = nvram;
516         fwctx->domain_nr = domain_nr;
517         fwctx->bus_nr = bus_nr;
518
519         return request_firmware_nowait(THIS_MODULE, true, code, dev,
520                                        GFP_KERNEL, fwctx,
521                                        brcmf_fw_request_code_done);
522 }
523
524 int brcmf_fw_get_firmwares(struct device *dev, u16 flags,
525                            const char *code, const char *nvram,
526                            void (*fw_cb)(struct device *dev,
527                                          const struct firmware *fw,
528                                          void *nvram_image, u32 nvram_len))
529 {
530         return brcmf_fw_get_firmwares_pcie(dev, flags, code, nvram, fw_cb, 0,
531                                            0);
532 }
533