Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / net / wireless / brcm80211 / brcmfmac / fwil.c
1 /*
2  * Copyright (c) 2012 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 /* FWIL is the Firmware Interface Layer. In this module the support functions
18  * are located to set and get variables to and from the firmware.
19  */
20
21 #include <linux/kernel.h>
22 #include <linux/netdevice.h>
23 #include <brcmu_utils.h>
24 #include <brcmu_wifi.h>
25 #include "core.h"
26 #include "bus.h"
27 #include "debug.h"
28 #include "tracepoint.h"
29 #include "fwil.h"
30 #include "proto.h"
31
32
33 #define MAX_HEX_DUMP_LEN        64
34
35 #ifdef DEBUG
36 static const char * const brcmf_fil_errstr[] = {
37         "BCME_OK",
38         "BCME_ERROR",
39         "BCME_BADARG",
40         "BCME_BADOPTION",
41         "BCME_NOTUP",
42         "BCME_NOTDOWN",
43         "BCME_NOTAP",
44         "BCME_NOTSTA",
45         "BCME_BADKEYIDX",
46         "BCME_RADIOOFF",
47         "BCME_NOTBANDLOCKED",
48         "BCME_NOCLK",
49         "BCME_BADRATESET",
50         "BCME_BADBAND",
51         "BCME_BUFTOOSHORT",
52         "BCME_BUFTOOLONG",
53         "BCME_BUSY",
54         "BCME_NOTASSOCIATED",
55         "BCME_BADSSIDLEN",
56         "BCME_OUTOFRANGECHAN",
57         "BCME_BADCHAN",
58         "BCME_BADADDR",
59         "BCME_NORESOURCE",
60         "BCME_UNSUPPORTED",
61         "BCME_BADLEN",
62         "BCME_NOTREADY",
63         "BCME_EPERM",
64         "BCME_NOMEM",
65         "BCME_ASSOCIATED",
66         "BCME_RANGE",
67         "BCME_NOTFOUND",
68         "BCME_WME_NOT_ENABLED",
69         "BCME_TSPEC_NOTFOUND",
70         "BCME_ACM_NOTSUPPORTED",
71         "BCME_NOT_WME_ASSOCIATION",
72         "BCME_SDIO_ERROR",
73         "BCME_DONGLE_DOWN",
74         "BCME_VERSION",
75         "BCME_TXFAIL",
76         "BCME_RXFAIL",
77         "BCME_NODEVICE",
78         "BCME_NMODE_DISABLED",
79         "BCME_NONRESIDENT",
80         "BCME_SCANREJECT",
81         "BCME_USAGE_ERROR",
82         "BCME_IOCTL_ERROR",
83         "BCME_SERIAL_PORT_ERR",
84         "BCME_DISABLED",
85         "BCME_DECERR",
86         "BCME_ENCERR",
87         "BCME_MICERR",
88         "BCME_REPLAY",
89         "BCME_IE_NOTFOUND",
90 };
91
92 static const char *brcmf_fil_get_errstr(u32 err)
93 {
94         if (err >= ARRAY_SIZE(brcmf_fil_errstr))
95                 return "(unknown)";
96
97         return brcmf_fil_errstr[err];
98 }
99 #else
100 static const char *brcmf_fil_get_errstr(u32 err)
101 {
102         return "";
103 }
104 #endif /* DEBUG */
105
106 static s32
107 brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
108 {
109         struct brcmf_pub *drvr = ifp->drvr;
110         s32 err;
111
112         if (drvr->bus_if->state != BRCMF_BUS_UP) {
113                 brcmf_err("bus is down. we have nothing to do.\n");
114                 return -EIO;
115         }
116
117         if (data != NULL)
118                 len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
119         if (set)
120                 err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd, data, len);
121         else
122                 err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len);
123
124         if (err >= 0)
125                 return 0;
126
127         brcmf_dbg(FIL, "Failed: %s (%d)\n",
128                   brcmf_fil_get_errstr((u32)(-err)), err);
129         return -EBADE;
130 }
131
132 s32
133 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
134 {
135         s32 err;
136
137         mutex_lock(&ifp->drvr->proto_block);
138
139         brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len);
140         brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
141                            min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
142
143         err = brcmf_fil_cmd_data(ifp, cmd, data, len, true);
144         mutex_unlock(&ifp->drvr->proto_block);
145
146         return err;
147 }
148
149 s32
150 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
151 {
152         s32 err;
153
154         mutex_lock(&ifp->drvr->proto_block);
155         err = brcmf_fil_cmd_data(ifp, cmd, data, len, false);
156
157         brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len);
158         brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
159                            min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
160
161         mutex_unlock(&ifp->drvr->proto_block);
162
163         return err;
164 }
165
166
167 s32
168 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data)
169 {
170         s32 err;
171         __le32 data_le = cpu_to_le32(data);
172
173         mutex_lock(&ifp->drvr->proto_block);
174         brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, data);
175         err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true);
176         mutex_unlock(&ifp->drvr->proto_block);
177
178         return err;
179 }
180
181 s32
182 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)
183 {
184         s32 err;
185         __le32 data_le = cpu_to_le32(*data);
186
187         mutex_lock(&ifp->drvr->proto_block);
188         err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false);
189         mutex_unlock(&ifp->drvr->proto_block);
190         *data = le32_to_cpu(data_le);
191         brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, *data);
192
193         return err;
194 }
195
196 static u32
197 brcmf_create_iovar(char *name, const char *data, u32 datalen,
198                    char *buf, u32 buflen)
199 {
200         u32 len;
201
202         len = strlen(name) + 1;
203
204         if ((len + datalen) > buflen)
205                 return 0;
206
207         memcpy(buf, name, len);
208
209         /* append data onto the end of the name string */
210         if (data && datalen)
211                 memcpy(&buf[len], data, datalen);
212
213         return len + datalen;
214 }
215
216
217 s32
218 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data,
219                          u32 len)
220 {
221         struct brcmf_pub *drvr = ifp->drvr;
222         s32 err;
223         u32 buflen;
224
225         mutex_lock(&drvr->proto_block);
226
227         brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len);
228         brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
229                            min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
230
231         buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
232                                     sizeof(drvr->proto_buf));
233         if (buflen) {
234                 err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
235                                          buflen, true);
236         } else {
237                 err = -EPERM;
238                 brcmf_err("Creating iovar failed\n");
239         }
240
241         mutex_unlock(&drvr->proto_block);
242         return err;
243 }
244
245 s32
246 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
247                          u32 len)
248 {
249         struct brcmf_pub *drvr = ifp->drvr;
250         s32 err;
251         u32 buflen;
252
253         mutex_lock(&drvr->proto_block);
254
255         buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
256                                     sizeof(drvr->proto_buf));
257         if (buflen) {
258                 err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
259                                          buflen, false);
260                 if (err == 0)
261                         memcpy(data, drvr->proto_buf, len);
262         } else {
263                 err = -EPERM;
264                 brcmf_err("Creating iovar failed\n");
265         }
266
267         brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len);
268         brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
269                            min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
270
271         mutex_unlock(&drvr->proto_block);
272         return err;
273 }
274
275 s32
276 brcmf_fil_iovar_int_set(struct brcmf_if *ifp, char *name, u32 data)
277 {
278         __le32 data_le = cpu_to_le32(data);
279
280         return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le));
281 }
282
283 s32
284 brcmf_fil_iovar_int_get(struct brcmf_if *ifp, char *name, u32 *data)
285 {
286         __le32 data_le = cpu_to_le32(*data);
287         s32 err;
288
289         err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le));
290         if (err == 0)
291                 *data = le32_to_cpu(data_le);
292         return err;
293 }
294
295 static u32
296 brcmf_create_bsscfg(s32 bssidx, char *name, char *data, u32 datalen, char *buf,
297                     u32 buflen)
298 {
299         const s8 *prefix = "bsscfg:";
300         s8 *p;
301         u32 prefixlen;
302         u32 namelen;
303         u32 iolen;
304         __le32 bssidx_le;
305
306         if (bssidx == 0)
307                 return brcmf_create_iovar(name, data, datalen, buf, buflen);
308
309         prefixlen = strlen(prefix);
310         namelen = strlen(name) + 1; /* lengh of iovar  name + null */
311         iolen = prefixlen + namelen + sizeof(bssidx_le) + datalen;
312
313         if (buflen < iolen) {
314                 brcmf_err("buffer is too short\n");
315                 return 0;
316         }
317
318         p = buf;
319
320         /* copy prefix, no null */
321         memcpy(p, prefix, prefixlen);
322         p += prefixlen;
323
324         /* copy iovar name including null */
325         memcpy(p, name, namelen);
326         p += namelen;
327
328         /* bss config index as first data */
329         bssidx_le = cpu_to_le32(bssidx);
330         memcpy(p, &bssidx_le, sizeof(bssidx_le));
331         p += sizeof(bssidx_le);
332
333         /* parameter buffer follows */
334         if (datalen)
335                 memcpy(p, data, datalen);
336
337         return iolen;
338 }
339
340 s32
341 brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name,
342                           void *data, u32 len)
343 {
344         struct brcmf_pub *drvr = ifp->drvr;
345         s32 err;
346         u32 buflen;
347
348         mutex_lock(&drvr->proto_block);
349
350         brcmf_dbg(FIL, "ifidx=%d, bssidx=%d, name=%s, len=%d\n", ifp->ifidx,
351                   ifp->bssidx, name, len);
352         brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
353                            min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
354
355         buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,
356                                      drvr->proto_buf, sizeof(drvr->proto_buf));
357         if (buflen) {
358                 err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
359                                          buflen, true);
360         } else {
361                 err = -EPERM;
362                 brcmf_err("Creating bsscfg failed\n");
363         }
364
365         mutex_unlock(&drvr->proto_block);
366         return err;
367 }
368
369 s32
370 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,
371                           void *data, u32 len)
372 {
373         struct brcmf_pub *drvr = ifp->drvr;
374         s32 err;
375         u32 buflen;
376
377         mutex_lock(&drvr->proto_block);
378
379         buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,
380                                      drvr->proto_buf, sizeof(drvr->proto_buf));
381         if (buflen) {
382                 err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
383                                          buflen, false);
384                 if (err == 0)
385                         memcpy(data, drvr->proto_buf, len);
386         } else {
387                 err = -EPERM;
388                 brcmf_err("Creating bsscfg failed\n");
389         }
390         brcmf_dbg(FIL, "ifidx=%d, bssidx=%d, name=%s, len=%d\n", ifp->ifidx,
391                   ifp->bssidx, name, len);
392         brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
393                            min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
394
395         mutex_unlock(&drvr->proto_block);
396         return err;
397
398 }
399
400 s32
401 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, char *name, u32 data)
402 {
403         __le32 data_le = cpu_to_le32(data);
404
405         return brcmf_fil_bsscfg_data_set(ifp, name, &data_le,
406                                          sizeof(data_le));
407 }
408
409 s32
410 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, char *name, u32 *data)
411 {
412         __le32 data_le = cpu_to_le32(*data);
413         s32 err;
414
415         err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le,
416                                         sizeof(data_le));
417         if (err == 0)
418                 *data = le32_to_cpu(data_le);
419         return err;
420 }