Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: ISC
0002 /*
0003  * Copyright (c) 2012 Broadcom Corporation
0004  */
0005 
0006 /* FWIL is the Firmware Interface Layer. In this module the support functions
0007  * are located to set and get variables to and from the firmware.
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 /* DEBUG */
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     /* append data onto the end of the name string */
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; /* length of iovar  name + null */
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     /* copy prefix, no null */
0320     memcpy(p, prefix, prefixlen);
0321     p += prefixlen;
0322 
0323     /* copy iovar name including null */
0324     memcpy(p, name, namelen);
0325     p += namelen;
0326 
0327     /* bss config index as first data */
0328     bsscfgidx_le = cpu_to_le32(bsscfgidx);
0329     memcpy(p, &bsscfgidx_le, sizeof(bsscfgidx_le));
0330     p += sizeof(bsscfgidx_le);
0331 
0332     /* parameter buffer follows */
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