]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/net/wireless/brcm80211/brcmfmac/fwil.c
Merge remote-tracking branches 'spi/fix/doc', 'spi/fix/nuc900' and 'spi/fix/rspi...
[karo-tx-linux.git] / 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 "dhd.h"
26 #include "dhd_bus.h"
27 #include "dhd_dbg.h"
28 #include "tracepoint.h"
29 #include "fwil.h"
30 #include "proto.h"
31
32
33 #define MAX_HEX_DUMP_LEN        64
34
35
36 static s32
37 brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
38 {
39         struct brcmf_pub *drvr = ifp->drvr;
40         s32 err;
41
42         if (drvr->bus_if->state != BRCMF_BUS_DATA) {
43                 brcmf_err("bus is down. we have nothing to do.\n");
44                 return -EIO;
45         }
46
47         if (data != NULL)
48                 len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
49         if (set)
50                 err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd, data, len);
51         else
52                 err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd, data, len);
53
54         if (err >= 0)
55                 err = 0;
56         else
57                 brcmf_err("Failed err=%d\n", err);
58
59         return err;
60 }
61
62 s32
63 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
64 {
65         s32 err;
66
67         mutex_lock(&ifp->drvr->proto_block);
68
69         brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
70         brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
71                            min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
72
73         err = brcmf_fil_cmd_data(ifp, cmd, data, len, true);
74         mutex_unlock(&ifp->drvr->proto_block);
75
76         return err;
77 }
78
79 s32
80 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
81 {
82         s32 err;
83
84         mutex_lock(&ifp->drvr->proto_block);
85         err = brcmf_fil_cmd_data(ifp, cmd, data, len, false);
86
87         brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
88         brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
89                            min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
90
91         mutex_unlock(&ifp->drvr->proto_block);
92
93         return err;
94 }
95
96
97 s32
98 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data)
99 {
100         s32 err;
101         __le32 data_le = cpu_to_le32(data);
102
103         mutex_lock(&ifp->drvr->proto_block);
104         brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, data);
105         err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true);
106         mutex_unlock(&ifp->drvr->proto_block);
107
108         return err;
109 }
110
111 s32
112 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)
113 {
114         s32 err;
115         __le32 data_le = cpu_to_le32(*data);
116
117         mutex_lock(&ifp->drvr->proto_block);
118         err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false);
119         mutex_unlock(&ifp->drvr->proto_block);
120         *data = le32_to_cpu(data_le);
121         brcmf_dbg(FIL, "cmd=%d, value=%d\n", cmd, *data);
122
123         return err;
124 }
125
126 static u32
127 brcmf_create_iovar(char *name, char *data, u32 datalen, char *buf, u32 buflen)
128 {
129         u32 len;
130
131         len = strlen(name) + 1;
132
133         if ((len + datalen) > buflen)
134                 return 0;
135
136         memcpy(buf, name, len);
137
138         /* append data onto the end of the name string */
139         if (data && datalen)
140                 memcpy(&buf[len], data, datalen);
141
142         return len + datalen;
143 }
144
145
146 s32
147 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,
148                          u32 len)
149 {
150         struct brcmf_pub *drvr = ifp->drvr;
151         s32 err;
152         u32 buflen;
153
154         mutex_lock(&drvr->proto_block);
155
156         brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
157         brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
158                            min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
159
160         buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
161                                     sizeof(drvr->proto_buf));
162         if (buflen) {
163                 err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
164                                          buflen, true);
165         } else {
166                 err = -EPERM;
167                 brcmf_err("Creating iovar failed\n");
168         }
169
170         mutex_unlock(&drvr->proto_block);
171         return err;
172 }
173
174 s32
175 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
176                          u32 len)
177 {
178         struct brcmf_pub *drvr = ifp->drvr;
179         s32 err;
180         u32 buflen;
181
182         mutex_lock(&drvr->proto_block);
183
184         buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
185                                     sizeof(drvr->proto_buf));
186         if (buflen) {
187                 err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
188                                          buflen, false);
189                 if (err == 0)
190                         memcpy(data, drvr->proto_buf, len);
191         } else {
192                 err = -EPERM;
193                 brcmf_err("Creating iovar failed\n");
194         }
195
196         brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
197         brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
198                            min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
199
200         mutex_unlock(&drvr->proto_block);
201         return err;
202 }
203
204 s32
205 brcmf_fil_iovar_int_set(struct brcmf_if *ifp, char *name, u32 data)
206 {
207         __le32 data_le = cpu_to_le32(data);
208
209         return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le));
210 }
211
212 s32
213 brcmf_fil_iovar_int_get(struct brcmf_if *ifp, char *name, u32 *data)
214 {
215         __le32 data_le = cpu_to_le32(*data);
216         s32 err;
217
218         err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le));
219         if (err == 0)
220                 *data = le32_to_cpu(data_le);
221         return err;
222 }
223
224 static u32
225 brcmf_create_bsscfg(s32 bssidx, char *name, char *data, u32 datalen, char *buf,
226                     u32 buflen)
227 {
228         const s8 *prefix = "bsscfg:";
229         s8 *p;
230         u32 prefixlen;
231         u32 namelen;
232         u32 iolen;
233         __le32 bssidx_le;
234
235         if (bssidx == 0)
236                 return brcmf_create_iovar(name, data, datalen, buf, buflen);
237
238         prefixlen = strlen(prefix);
239         namelen = strlen(name) + 1; /* lengh of iovar  name + null */
240         iolen = prefixlen + namelen + sizeof(bssidx_le) + datalen;
241
242         if (buflen < iolen) {
243                 brcmf_err("buffer is too short\n");
244                 return 0;
245         }
246
247         p = buf;
248
249         /* copy prefix, no null */
250         memcpy(p, prefix, prefixlen);
251         p += prefixlen;
252
253         /* copy iovar name including null */
254         memcpy(p, name, namelen);
255         p += namelen;
256
257         /* bss config index as first data */
258         bssidx_le = cpu_to_le32(bssidx);
259         memcpy(p, &bssidx_le, sizeof(bssidx_le));
260         p += sizeof(bssidx_le);
261
262         /* parameter buffer follows */
263         if (datalen)
264                 memcpy(p, data, datalen);
265
266         return iolen;
267 }
268
269 s32
270 brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name,
271                           void *data, u32 len)
272 {
273         struct brcmf_pub *drvr = ifp->drvr;
274         s32 err;
275         u32 buflen;
276
277         mutex_lock(&drvr->proto_block);
278
279         brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
280         brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
281                            min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
282
283         buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,
284                                      drvr->proto_buf, sizeof(drvr->proto_buf));
285         if (buflen) {
286                 err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
287                                          buflen, true);
288         } else {
289                 err = -EPERM;
290                 brcmf_err("Creating bsscfg failed\n");
291         }
292
293         mutex_unlock(&drvr->proto_block);
294         return err;
295 }
296
297 s32
298 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,
299                           void *data, u32 len)
300 {
301         struct brcmf_pub *drvr = ifp->drvr;
302         s32 err;
303         u32 buflen;
304
305         mutex_lock(&drvr->proto_block);
306
307         buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,
308                                      drvr->proto_buf, sizeof(drvr->proto_buf));
309         if (buflen) {
310                 err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
311                                          buflen, false);
312                 if (err == 0)
313                         memcpy(data, drvr->proto_buf, len);
314         } else {
315                 err = -EPERM;
316                 brcmf_err("Creating bsscfg failed\n");
317         }
318         brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
319         brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
320                            min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
321
322         mutex_unlock(&drvr->proto_block);
323         return err;
324
325 }
326
327 s32
328 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, char *name, u32 data)
329 {
330         __le32 data_le = cpu_to_le32(data);
331
332         return brcmf_fil_bsscfg_data_set(ifp, name, &data_le,
333                                          sizeof(data_le));
334 }
335
336 s32
337 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, char *name, u32 *data)
338 {
339         __le32 data_le = cpu_to_le32(*data);
340         s32 err;
341
342         err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le,
343                                         sizeof(data_le));
344         if (err == 0)
345                 *data = le32_to_cpu(data_le);
346         return err;
347 }