0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/kernel.h>
0011 #include <linux/netdevice.h>
0012 #include <brcmu_utils.h>
0013 #include <brcmu_wifi.h>
0014 #include "core.h"
0015 #include "bus.h"
0016 #include "debug.h"
0017 #include "tracepoint.h"
0018 #include "xtlv.h"
0019 #include "fwil.h"
0020 #include "proto.h"
0021
0022
0023 #define MAX_HEX_DUMP_LEN 64
0024
0025 #ifdef DEBUG
0026 static const char * const brcmf_fil_errstr[] = {
0027 "BCME_OK",
0028 "BCME_ERROR",
0029 "BCME_BADARG",
0030 "BCME_BADOPTION",
0031 "BCME_NOTUP",
0032 "BCME_NOTDOWN",
0033 "BCME_NOTAP",
0034 "BCME_NOTSTA",
0035 "BCME_BADKEYIDX",
0036 "BCME_RADIOOFF",
0037 "BCME_NOTBANDLOCKED",
0038 "BCME_NOCLK",
0039 "BCME_BADRATESET",
0040 "BCME_BADBAND",
0041 "BCME_BUFTOOSHORT",
0042 "BCME_BUFTOOLONG",
0043 "BCME_BUSY",
0044 "BCME_NOTASSOCIATED",
0045 "BCME_BADSSIDLEN",
0046 "BCME_OUTOFRANGECHAN",
0047 "BCME_BADCHAN",
0048 "BCME_BADADDR",
0049 "BCME_NORESOURCE",
0050 "BCME_UNSUPPORTED",
0051 "BCME_BADLEN",
0052 "BCME_NOTREADY",
0053 "BCME_EPERM",
0054 "BCME_NOMEM",
0055 "BCME_ASSOCIATED",
0056 "BCME_RANGE",
0057 "BCME_NOTFOUND",
0058 "BCME_WME_NOT_ENABLED",
0059 "BCME_TSPEC_NOTFOUND",
0060 "BCME_ACM_NOTSUPPORTED",
0061 "BCME_NOT_WME_ASSOCIATION",
0062 "BCME_SDIO_ERROR",
0063 "BCME_DONGLE_DOWN",
0064 "BCME_VERSION",
0065 "BCME_TXFAIL",
0066 "BCME_RXFAIL",
0067 "BCME_NODEVICE",
0068 "BCME_NMODE_DISABLED",
0069 "BCME_NONRESIDENT",
0070 "BCME_SCANREJECT",
0071 "BCME_USAGE_ERROR",
0072 "BCME_IOCTL_ERROR",
0073 "BCME_SERIAL_PORT_ERR",
0074 "BCME_DISABLED",
0075 "BCME_DECERR",
0076 "BCME_ENCERR",
0077 "BCME_MICERR",
0078 "BCME_REPLAY",
0079 "BCME_IE_NOTFOUND",
0080 };
0081
0082 static const char *brcmf_fil_get_errstr(u32 err)
0083 {
0084 if (err >= ARRAY_SIZE(brcmf_fil_errstr))
0085 return "(unknown)";
0086
0087 return brcmf_fil_errstr[err];
0088 }
0089 #else
0090 static const char *brcmf_fil_get_errstr(u32 err)
0091 {
0092 return "";
0093 }
0094 #endif
0095
0096 static s32
0097 brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
0098 {
0099 struct brcmf_pub *drvr = ifp->drvr;
0100 s32 err, fwerr;
0101
0102 if (drvr->bus_if->state != BRCMF_BUS_UP) {
0103 bphy_err(drvr, "bus is down. we have nothing to do.\n");
0104 return -EIO;
0105 }
0106
0107 if (data != NULL)
0108 len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
0109 if (set)
0110 err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd,
0111 data, len, &fwerr);
0112 else
0113 err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd,
0114 data, len, &fwerr);
0115
0116 if (err) {
0117 brcmf_dbg(FIL, "Failed: error=%d\n", err);
0118 } else if (fwerr < 0) {
0119 brcmf_dbg(FIL, "Firmware error: %s (%d)\n",
0120 brcmf_fil_get_errstr((u32)(-fwerr)), fwerr);
0121 err = -EBADE;
0122 }
0123 if (ifp->fwil_fwerr)
0124 return fwerr;
0125
0126 return err;
0127 }
0128
0129 s32
0130 brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
0131 {
0132 s32 err;
0133
0134 mutex_lock(&ifp->drvr->proto_block);
0135
0136 brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len);
0137 brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
0138 min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
0139
0140 err = brcmf_fil_cmd_data(ifp, cmd, data, len, true);
0141 mutex_unlock(&ifp->drvr->proto_block);
0142
0143 return err;
0144 }
0145
0146 s32
0147 brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
0148 {
0149 s32 err;
0150
0151 mutex_lock(&ifp->drvr->proto_block);
0152 err = brcmf_fil_cmd_data(ifp, cmd, data, len, false);
0153
0154 brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d, err=%d\n", ifp->ifidx, cmd,
0155 len, err);
0156 brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
0157 min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
0158
0159 mutex_unlock(&ifp->drvr->proto_block);
0160
0161 return err;
0162 }
0163
0164
0165 s32
0166 brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data)
0167 {
0168 s32 err;
0169 __le32 data_le = cpu_to_le32(data);
0170
0171 mutex_lock(&ifp->drvr->proto_block);
0172 brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, data);
0173 err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true);
0174 mutex_unlock(&ifp->drvr->proto_block);
0175
0176 return err;
0177 }
0178
0179 s32
0180 brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)
0181 {
0182 s32 err;
0183 __le32 data_le = cpu_to_le32(*data);
0184
0185 mutex_lock(&ifp->drvr->proto_block);
0186 err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false);
0187 mutex_unlock(&ifp->drvr->proto_block);
0188 *data = le32_to_cpu(data_le);
0189 brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, *data);
0190
0191 return err;
0192 }
0193
0194 static u32
0195 brcmf_create_iovar(const char *name, const char *data, u32 datalen,
0196 char *buf, u32 buflen)
0197 {
0198 u32 len;
0199
0200 len = strlen(name) + 1;
0201
0202 if ((len + datalen) > buflen)
0203 return 0;
0204
0205 memcpy(buf, name, len);
0206
0207
0208 if (data && datalen)
0209 memcpy(&buf[len], data, datalen);
0210
0211 return len + datalen;
0212 }
0213
0214
0215 s32
0216 brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, const void *data,
0217 u32 len)
0218 {
0219 struct brcmf_pub *drvr = ifp->drvr;
0220 s32 err;
0221 u32 buflen;
0222
0223 mutex_lock(&drvr->proto_block);
0224
0225 brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len);
0226 brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
0227 min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
0228
0229 buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
0230 sizeof(drvr->proto_buf));
0231 if (buflen) {
0232 err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
0233 buflen, true);
0234 } else {
0235 err = -EPERM;
0236 bphy_err(drvr, "Creating iovar failed\n");
0237 }
0238
0239 mutex_unlock(&drvr->proto_block);
0240 return err;
0241 }
0242
0243 s32
0244 brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data,
0245 u32 len)
0246 {
0247 struct brcmf_pub *drvr = ifp->drvr;
0248 s32 err;
0249 u32 buflen;
0250
0251 mutex_lock(&drvr->proto_block);
0252
0253 buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
0254 sizeof(drvr->proto_buf));
0255 if (buflen) {
0256 err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
0257 buflen, false);
0258 if (err == 0)
0259 memcpy(data, drvr->proto_buf, len);
0260 } else {
0261 err = -EPERM;
0262 bphy_err(drvr, "Creating iovar failed\n");
0263 }
0264
0265 brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d, err=%d\n", ifp->ifidx, name,
0266 len, err);
0267 brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
0268 min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
0269
0270 mutex_unlock(&drvr->proto_block);
0271 return err;
0272 }
0273
0274 s32
0275 brcmf_fil_iovar_int_set(struct brcmf_if *ifp, const char *name, u32 data)
0276 {
0277 __le32 data_le = cpu_to_le32(data);
0278
0279 return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le));
0280 }
0281
0282 s32
0283 brcmf_fil_iovar_int_get(struct brcmf_if *ifp, const char *name, u32 *data)
0284 {
0285 __le32 data_le = cpu_to_le32(*data);
0286 s32 err;
0287
0288 err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le));
0289 if (err == 0)
0290 *data = le32_to_cpu(data_le);
0291 return err;
0292 }
0293
0294 static u32
0295 brcmf_create_bsscfg(s32 bsscfgidx, const char *name, char *data, u32 datalen,
0296 char *buf, u32 buflen)
0297 {
0298 const s8 *prefix = "bsscfg:";
0299 s8 *p;
0300 u32 prefixlen;
0301 u32 namelen;
0302 u32 iolen;
0303 __le32 bsscfgidx_le;
0304
0305 if (bsscfgidx == 0)
0306 return brcmf_create_iovar(name, data, datalen, buf, buflen);
0307
0308 prefixlen = strlen(prefix);
0309 namelen = strlen(name) + 1;
0310 iolen = prefixlen + namelen + sizeof(bsscfgidx_le) + datalen;
0311
0312 if (buflen < iolen) {
0313 brcmf_err("buffer is too short\n");
0314 return 0;
0315 }
0316
0317 p = buf;
0318
0319
0320 memcpy(p, prefix, prefixlen);
0321 p += prefixlen;
0322
0323
0324 memcpy(p, name, namelen);
0325 p += namelen;
0326
0327
0328 bsscfgidx_le = cpu_to_le32(bsscfgidx);
0329 memcpy(p, &bsscfgidx_le, sizeof(bsscfgidx_le));
0330 p += sizeof(bsscfgidx_le);
0331
0332
0333 if (datalen)
0334 memcpy(p, data, datalen);
0335
0336 return iolen;
0337 }
0338
0339 s32
0340 brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name,
0341 void *data, u32 len)
0342 {
0343 struct brcmf_pub *drvr = ifp->drvr;
0344 s32 err;
0345 u32 buflen;
0346
0347 mutex_lock(&drvr->proto_block);
0348
0349 brcmf_dbg(FIL, "ifidx=%d, bsscfgidx=%d, name=%s, len=%d\n", ifp->ifidx,
0350 ifp->bsscfgidx, name, len);
0351 brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
0352 min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
0353
0354 buflen = brcmf_create_bsscfg(ifp->bsscfgidx, name, data, len,
0355 drvr->proto_buf, sizeof(drvr->proto_buf));
0356 if (buflen) {
0357 err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
0358 buflen, true);
0359 } else {
0360 err = -EPERM;
0361 bphy_err(drvr, "Creating bsscfg failed\n");
0362 }
0363
0364 mutex_unlock(&drvr->proto_block);
0365 return err;
0366 }
0367
0368 s32
0369 brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name,
0370 void *data, u32 len)
0371 {
0372 struct brcmf_pub *drvr = ifp->drvr;
0373 s32 err;
0374 u32 buflen;
0375
0376 mutex_lock(&drvr->proto_block);
0377
0378 buflen = brcmf_create_bsscfg(ifp->bsscfgidx, name, data, len,
0379 drvr->proto_buf, sizeof(drvr->proto_buf));
0380 if (buflen) {
0381 err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
0382 buflen, false);
0383 if (err == 0)
0384 memcpy(data, drvr->proto_buf, len);
0385 } else {
0386 err = -EPERM;
0387 bphy_err(drvr, "Creating bsscfg failed\n");
0388 }
0389 brcmf_dbg(FIL, "ifidx=%d, bsscfgidx=%d, name=%s, len=%d, err=%d\n",
0390 ifp->ifidx, ifp->bsscfgidx, name, len, err);
0391 brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
0392 min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
0393
0394 mutex_unlock(&drvr->proto_block);
0395 return err;
0396 }
0397
0398 s32
0399 brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, const char *name, u32 data)
0400 {
0401 __le32 data_le = cpu_to_le32(data);
0402
0403 return brcmf_fil_bsscfg_data_set(ifp, name, &data_le,
0404 sizeof(data_le));
0405 }
0406
0407 s32
0408 brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, const char *name, u32 *data)
0409 {
0410 __le32 data_le = cpu_to_le32(*data);
0411 s32 err;
0412
0413 err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le,
0414 sizeof(data_le));
0415 if (err == 0)
0416 *data = le32_to_cpu(data_le);
0417 return err;
0418 }
0419
0420 static u32 brcmf_create_xtlv(const char *name, u16 id, char *data, u32 len,
0421 char *buf, u32 buflen)
0422 {
0423 u32 iolen;
0424 u32 nmlen;
0425
0426 nmlen = strlen(name) + 1;
0427 iolen = nmlen + brcmf_xtlv_data_size(len, BRCMF_XTLV_OPTION_ALIGN32);
0428
0429 if (iolen > buflen) {
0430 brcmf_err("buffer is too short\n");
0431 return 0;
0432 }
0433
0434 memcpy(buf, name, nmlen);
0435 brcmf_xtlv_pack_header((void *)(buf + nmlen), id, len, data,
0436 BRCMF_XTLV_OPTION_ALIGN32);
0437
0438 return iolen;
0439 }
0440
0441 s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, const char *name, u16 id,
0442 void *data, u32 len)
0443 {
0444 struct brcmf_pub *drvr = ifp->drvr;
0445 s32 err;
0446 u32 buflen;
0447
0448 mutex_lock(&drvr->proto_block);
0449
0450 brcmf_dbg(FIL, "ifidx=%d, name=%s, id=%u, len=%u\n", ifp->ifidx, name,
0451 id, len);
0452 brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
0453 min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
0454
0455 buflen = brcmf_create_xtlv(name, id, data, len,
0456 drvr->proto_buf, sizeof(drvr->proto_buf));
0457 if (buflen) {
0458 err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
0459 buflen, true);
0460 } else {
0461 err = -EPERM;
0462 bphy_err(drvr, "Creating xtlv failed\n");
0463 }
0464
0465 mutex_unlock(&drvr->proto_block);
0466 return err;
0467 }
0468
0469 s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id,
0470 void *data, u32 len)
0471 {
0472 struct brcmf_pub *drvr = ifp->drvr;
0473 s32 err;
0474 u32 buflen;
0475
0476 mutex_lock(&drvr->proto_block);
0477
0478 buflen = brcmf_create_xtlv(name, id, data, len,
0479 drvr->proto_buf, sizeof(drvr->proto_buf));
0480 if (buflen) {
0481 err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
0482 buflen, false);
0483 if (err == 0)
0484 memcpy(data, drvr->proto_buf, len);
0485 } else {
0486 err = -EPERM;
0487 bphy_err(drvr, "Creating bsscfg failed\n");
0488 }
0489 brcmf_dbg(FIL, "ifidx=%d, name=%s, id=%u, len=%u, err=%d\n",
0490 ifp->ifidx, name, id, len, err);
0491 brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
0492 min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
0493
0494 mutex_unlock(&drvr->proto_block);
0495 return err;
0496 }
0497
0498 s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, const char *name, u16 id, u32 data)
0499 {
0500 __le32 data_le = cpu_to_le32(data);
0501
0502 return brcmf_fil_xtlv_data_set(ifp, name, id, &data_le,
0503 sizeof(data_le));
0504 }
0505
0506 s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, const char *name, u16 id, u32 *data)
0507 {
0508 __le32 data_le = cpu_to_le32(*data);
0509 s32 err;
0510
0511 err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le));
0512 if (err == 0)
0513 *data = le32_to_cpu(data_le);
0514 return err;
0515 }
0516
0517 s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, const char *name, u16 id, u8 *data)
0518 {
0519 return brcmf_fil_xtlv_data_get(ifp, name, id, data, sizeof(*data));
0520 }
0521
0522 s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, const char *name, u16 id, u16 *data)
0523 {
0524 __le16 data_le = cpu_to_le16(*data);
0525 s32 err;
0526
0527 err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le));
0528 if (err == 0)
0529 *data = le16_to_cpu(data_le);
0530 return err;
0531 }
0532