nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 | |||
130 | return err; |
||
131 | } |
||
132 | |||
133 | s32 |
||
134 | brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) |
||
135 | { |
||
136 | s32 err; |
||
137 | |||
138 | mutex_lock(&ifp->drvr->proto_block); |
||
139 | |||
140 | brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len); |
||
141 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, |
||
142 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); |
||
143 | |||
144 | err = brcmf_fil_cmd_data(ifp, cmd, data, len, true); |
||
145 | mutex_unlock(&ifp->drvr->proto_block); |
||
146 | |||
147 | return err; |
||
148 | } |
||
149 | |||
150 | s32 |
||
151 | brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len) |
||
152 | { |
||
153 | s32 err; |
||
154 | |||
155 | mutex_lock(&ifp->drvr->proto_block); |
||
156 | err = brcmf_fil_cmd_data(ifp, cmd, data, len, false); |
||
157 | |||
158 | brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len); |
||
159 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, |
||
160 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); |
||
161 | |||
162 | mutex_unlock(&ifp->drvr->proto_block); |
||
163 | |||
164 | return err; |
||
165 | } |
||
166 | |||
167 | |||
168 | s32 |
||
169 | brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data) |
||
170 | { |
||
171 | s32 err; |
||
172 | __le32 data_le = cpu_to_le32(data); |
||
173 | |||
174 | mutex_lock(&ifp->drvr->proto_block); |
||
175 | brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, data); |
||
176 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true); |
||
177 | mutex_unlock(&ifp->drvr->proto_block); |
||
178 | |||
179 | return err; |
||
180 | } |
||
181 | |||
182 | s32 |
||
183 | brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data) |
||
184 | { |
||
185 | s32 err; |
||
186 | __le32 data_le = cpu_to_le32(*data); |
||
187 | |||
188 | mutex_lock(&ifp->drvr->proto_block); |
||
189 | err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false); |
||
190 | mutex_unlock(&ifp->drvr->proto_block); |
||
191 | *data = le32_to_cpu(data_le); |
||
192 | brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, *data); |
||
193 | |||
194 | return err; |
||
195 | } |
||
196 | |||
197 | static u32 |
||
198 | brcmf_create_iovar(char *name, const char *data, u32 datalen, |
||
199 | char *buf, u32 buflen) |
||
200 | { |
||
201 | u32 len; |
||
202 | |||
203 | len = strlen(name) + 1; |
||
204 | |||
205 | if ((len + datalen) > buflen) |
||
206 | return 0; |
||
207 | |||
208 | memcpy(buf, name, len); |
||
209 | |||
210 | /* append data onto the end of the name string */ |
||
211 | if (data && datalen) |
||
212 | memcpy(&buf[len], data, datalen); |
||
213 | |||
214 | return len + datalen; |
||
215 | } |
||
216 | |||
217 | |||
218 | s32 |
||
219 | brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, const void *data, |
||
220 | u32 len) |
||
221 | { |
||
222 | struct brcmf_pub *drvr = ifp->drvr; |
||
223 | s32 err; |
||
224 | u32 buflen; |
||
225 | |||
226 | mutex_lock(&drvr->proto_block); |
||
227 | |||
228 | brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len); |
||
229 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, |
||
230 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); |
||
231 | |||
232 | buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf, |
||
233 | sizeof(drvr->proto_buf)); |
||
234 | if (buflen) { |
||
235 | err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf, |
||
236 | buflen, true); |
||
237 | } else { |
||
238 | err = -EPERM; |
||
239 | brcmf_err("Creating iovar failed\n"); |
||
240 | } |
||
241 | |||
242 | mutex_unlock(&drvr->proto_block); |
||
243 | return err; |
||
244 | } |
||
245 | |||
246 | s32 |
||
247 | brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data, |
||
248 | u32 len) |
||
249 | { |
||
250 | struct brcmf_pub *drvr = ifp->drvr; |
||
251 | s32 err; |
||
252 | u32 buflen; |
||
253 | |||
254 | mutex_lock(&drvr->proto_block); |
||
255 | |||
256 | buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf, |
||
257 | sizeof(drvr->proto_buf)); |
||
258 | if (buflen) { |
||
259 | err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf, |
||
260 | buflen, false); |
||
261 | if (err == 0) |
||
262 | memcpy(data, drvr->proto_buf, len); |
||
263 | } else { |
||
264 | err = -EPERM; |
||
265 | brcmf_err("Creating iovar failed\n"); |
||
266 | } |
||
267 | |||
268 | brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len); |
||
269 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, |
||
270 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); |
||
271 | |||
272 | mutex_unlock(&drvr->proto_block); |
||
273 | return err; |
||
274 | } |
||
275 | |||
276 | s32 |
||
277 | brcmf_fil_iovar_int_set(struct brcmf_if *ifp, char *name, u32 data) |
||
278 | { |
||
279 | __le32 data_le = cpu_to_le32(data); |
||
280 | |||
281 | return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le)); |
||
282 | } |
||
283 | |||
284 | s32 |
||
285 | brcmf_fil_iovar_int_get(struct brcmf_if *ifp, char *name, u32 *data) |
||
286 | { |
||
287 | __le32 data_le = cpu_to_le32(*data); |
||
288 | s32 err; |
||
289 | |||
290 | err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le)); |
||
291 | if (err == 0) |
||
292 | *data = le32_to_cpu(data_le); |
||
293 | return err; |
||
294 | } |
||
295 | |||
296 | static u32 |
||
297 | brcmf_create_bsscfg(s32 bsscfgidx, char *name, char *data, u32 datalen, |
||
298 | char *buf, u32 buflen) |
||
299 | { |
||
300 | const s8 *prefix = "bsscfg:"; |
||
301 | s8 *p; |
||
302 | u32 prefixlen; |
||
303 | u32 namelen; |
||
304 | u32 iolen; |
||
305 | __le32 bsscfgidx_le; |
||
306 | |||
307 | if (bsscfgidx == 0) |
||
308 | return brcmf_create_iovar(name, data, datalen, buf, buflen); |
||
309 | |||
310 | prefixlen = strlen(prefix); |
||
311 | namelen = strlen(name) + 1; /* lengh of iovar name + null */ |
||
312 | iolen = prefixlen + namelen + sizeof(bsscfgidx_le) + datalen; |
||
313 | |||
314 | if (buflen < iolen) { |
||
315 | brcmf_err("buffer is too short\n"); |
||
316 | return 0; |
||
317 | } |
||
318 | |||
319 | p = buf; |
||
320 | |||
321 | /* copy prefix, no null */ |
||
322 | memcpy(p, prefix, prefixlen); |
||
323 | p += prefixlen; |
||
324 | |||
325 | /* copy iovar name including null */ |
||
326 | memcpy(p, name, namelen); |
||
327 | p += namelen; |
||
328 | |||
329 | /* bss config index as first data */ |
||
330 | bsscfgidx_le = cpu_to_le32(bsscfgidx); |
||
331 | memcpy(p, &bsscfgidx_le, sizeof(bsscfgidx_le)); |
||
332 | p += sizeof(bsscfgidx_le); |
||
333 | |||
334 | /* parameter buffer follows */ |
||
335 | if (datalen) |
||
336 | memcpy(p, data, datalen); |
||
337 | |||
338 | return iolen; |
||
339 | } |
||
340 | |||
341 | s32 |
||
342 | brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name, |
||
343 | void *data, u32 len) |
||
344 | { |
||
345 | struct brcmf_pub *drvr = ifp->drvr; |
||
346 | s32 err; |
||
347 | u32 buflen; |
||
348 | |||
349 | mutex_lock(&drvr->proto_block); |
||
350 | |||
351 | brcmf_dbg(FIL, "ifidx=%d, bsscfgidx=%d, name=%s, len=%d\n", ifp->ifidx, |
||
352 | ifp->bsscfgidx, name, len); |
||
353 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, |
||
354 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); |
||
355 | |||
356 | buflen = brcmf_create_bsscfg(ifp->bsscfgidx, name, data, len, |
||
357 | drvr->proto_buf, sizeof(drvr->proto_buf)); |
||
358 | if (buflen) { |
||
359 | err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf, |
||
360 | buflen, true); |
||
361 | } else { |
||
362 | err = -EPERM; |
||
363 | brcmf_err("Creating bsscfg failed\n"); |
||
364 | } |
||
365 | |||
366 | mutex_unlock(&drvr->proto_block); |
||
367 | return err; |
||
368 | } |
||
369 | |||
370 | s32 |
||
371 | brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name, |
||
372 | void *data, u32 len) |
||
373 | { |
||
374 | struct brcmf_pub *drvr = ifp->drvr; |
||
375 | s32 err; |
||
376 | u32 buflen; |
||
377 | |||
378 | mutex_lock(&drvr->proto_block); |
||
379 | |||
380 | buflen = brcmf_create_bsscfg(ifp->bsscfgidx, name, data, len, |
||
381 | drvr->proto_buf, sizeof(drvr->proto_buf)); |
||
382 | if (buflen) { |
||
383 | err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf, |
||
384 | buflen, false); |
||
385 | if (err == 0) |
||
386 | memcpy(data, drvr->proto_buf, len); |
||
387 | } else { |
||
388 | err = -EPERM; |
||
389 | brcmf_err("Creating bsscfg failed\n"); |
||
390 | } |
||
391 | brcmf_dbg(FIL, "ifidx=%d, bsscfgidx=%d, name=%s, len=%d\n", ifp->ifidx, |
||
392 | ifp->bsscfgidx, name, len); |
||
393 | brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, |
||
394 | min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n"); |
||
395 | |||
396 | mutex_unlock(&drvr->proto_block); |
||
397 | return err; |
||
398 | |||
399 | } |
||
400 | |||
401 | s32 |
||
402 | brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, char *name, u32 data) |
||
403 | { |
||
404 | __le32 data_le = cpu_to_le32(data); |
||
405 | |||
406 | return brcmf_fil_bsscfg_data_set(ifp, name, &data_le, |
||
407 | sizeof(data_le)); |
||
408 | } |
||
409 | |||
410 | s32 |
||
411 | brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, char *name, u32 *data) |
||
412 | { |
||
413 | __le32 data_le = cpu_to_le32(*data); |
||
414 | s32 err; |
||
415 | |||
416 | err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le, |
||
417 | sizeof(data_le)); |
||
418 | if (err == 0) |
||
419 | *data = le32_to_cpu(data_le); |
||
420 | return err; |
||
421 | } |