cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fwil.c (12243B)


      1// SPDX-License-Identifier: ISC
      2/*
      3 * Copyright (c) 2012 Broadcom Corporation
      4 */
      5
      6/* FWIL is the Firmware Interface Layer. In this module the support functions
      7 * are located to set and get variables to and from the firmware.
      8 */
      9
     10#include <linux/kernel.h>
     11#include <linux/netdevice.h>
     12#include <brcmu_utils.h>
     13#include <brcmu_wifi.h>
     14#include "core.h"
     15#include "bus.h"
     16#include "debug.h"
     17#include "tracepoint.h"
     18#include "xtlv.h"
     19#include "fwil.h"
     20#include "proto.h"
     21
     22
     23#define MAX_HEX_DUMP_LEN	64
     24
     25#ifdef DEBUG
     26static const char * const brcmf_fil_errstr[] = {
     27	"BCME_OK",
     28	"BCME_ERROR",
     29	"BCME_BADARG",
     30	"BCME_BADOPTION",
     31	"BCME_NOTUP",
     32	"BCME_NOTDOWN",
     33	"BCME_NOTAP",
     34	"BCME_NOTSTA",
     35	"BCME_BADKEYIDX",
     36	"BCME_RADIOOFF",
     37	"BCME_NOTBANDLOCKED",
     38	"BCME_NOCLK",
     39	"BCME_BADRATESET",
     40	"BCME_BADBAND",
     41	"BCME_BUFTOOSHORT",
     42	"BCME_BUFTOOLONG",
     43	"BCME_BUSY",
     44	"BCME_NOTASSOCIATED",
     45	"BCME_BADSSIDLEN",
     46	"BCME_OUTOFRANGECHAN",
     47	"BCME_BADCHAN",
     48	"BCME_BADADDR",
     49	"BCME_NORESOURCE",
     50	"BCME_UNSUPPORTED",
     51	"BCME_BADLEN",
     52	"BCME_NOTREADY",
     53	"BCME_EPERM",
     54	"BCME_NOMEM",
     55	"BCME_ASSOCIATED",
     56	"BCME_RANGE",
     57	"BCME_NOTFOUND",
     58	"BCME_WME_NOT_ENABLED",
     59	"BCME_TSPEC_NOTFOUND",
     60	"BCME_ACM_NOTSUPPORTED",
     61	"BCME_NOT_WME_ASSOCIATION",
     62	"BCME_SDIO_ERROR",
     63	"BCME_DONGLE_DOWN",
     64	"BCME_VERSION",
     65	"BCME_TXFAIL",
     66	"BCME_RXFAIL",
     67	"BCME_NODEVICE",
     68	"BCME_NMODE_DISABLED",
     69	"BCME_NONRESIDENT",
     70	"BCME_SCANREJECT",
     71	"BCME_USAGE_ERROR",
     72	"BCME_IOCTL_ERROR",
     73	"BCME_SERIAL_PORT_ERR",
     74	"BCME_DISABLED",
     75	"BCME_DECERR",
     76	"BCME_ENCERR",
     77	"BCME_MICERR",
     78	"BCME_REPLAY",
     79	"BCME_IE_NOTFOUND",
     80};
     81
     82static const char *brcmf_fil_get_errstr(u32 err)
     83{
     84	if (err >= ARRAY_SIZE(brcmf_fil_errstr))
     85		return "(unknown)";
     86
     87	return brcmf_fil_errstr[err];
     88}
     89#else
     90static const char *brcmf_fil_get_errstr(u32 err)
     91{
     92	return "";
     93}
     94#endif /* DEBUG */
     95
     96static s32
     97brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
     98{
     99	struct brcmf_pub *drvr = ifp->drvr;
    100	s32 err, fwerr;
    101
    102	if (drvr->bus_if->state != BRCMF_BUS_UP) {
    103		bphy_err(drvr, "bus is down. we have nothing to do.\n");
    104		return -EIO;
    105	}
    106
    107	if (data != NULL)
    108		len = min_t(uint, len, BRCMF_DCMD_MAXLEN);
    109	if (set)
    110		err = brcmf_proto_set_dcmd(drvr, ifp->ifidx, cmd,
    111					   data, len, &fwerr);
    112	else
    113		err = brcmf_proto_query_dcmd(drvr, ifp->ifidx, cmd,
    114					     data, len, &fwerr);
    115
    116	if (err) {
    117		brcmf_dbg(FIL, "Failed: error=%d\n", err);
    118	} else if (fwerr < 0) {
    119		brcmf_dbg(FIL, "Firmware error: %s (%d)\n",
    120			  brcmf_fil_get_errstr((u32)(-fwerr)), fwerr);
    121		err = -EBADE;
    122	}
    123	if (ifp->fwil_fwerr)
    124		return fwerr;
    125
    126	return err;
    127}
    128
    129s32
    130brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
    131{
    132	s32 err;
    133
    134	mutex_lock(&ifp->drvr->proto_block);
    135
    136	brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d\n", ifp->ifidx, cmd, len);
    137	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
    138			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
    139
    140	err = brcmf_fil_cmd_data(ifp, cmd, data, len, true);
    141	mutex_unlock(&ifp->drvr->proto_block);
    142
    143	return err;
    144}
    145
    146s32
    147brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
    148{
    149	s32 err;
    150
    151	mutex_lock(&ifp->drvr->proto_block);
    152	err = brcmf_fil_cmd_data(ifp, cmd, data, len, false);
    153
    154	brcmf_dbg(FIL, "ifidx=%d, cmd=%d, len=%d, err=%d\n", ifp->ifidx, cmd,
    155		  len, err);
    156	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
    157			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
    158
    159	mutex_unlock(&ifp->drvr->proto_block);
    160
    161	return err;
    162}
    163
    164
    165s32
    166brcmf_fil_cmd_int_set(struct brcmf_if *ifp, u32 cmd, u32 data)
    167{
    168	s32 err;
    169	__le32 data_le = cpu_to_le32(data);
    170
    171	mutex_lock(&ifp->drvr->proto_block);
    172	brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, data);
    173	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), true);
    174	mutex_unlock(&ifp->drvr->proto_block);
    175
    176	return err;
    177}
    178
    179s32
    180brcmf_fil_cmd_int_get(struct brcmf_if *ifp, u32 cmd, u32 *data)
    181{
    182	s32 err;
    183	__le32 data_le = cpu_to_le32(*data);
    184
    185	mutex_lock(&ifp->drvr->proto_block);
    186	err = brcmf_fil_cmd_data(ifp, cmd, &data_le, sizeof(data_le), false);
    187	mutex_unlock(&ifp->drvr->proto_block);
    188	*data = le32_to_cpu(data_le);
    189	brcmf_dbg(FIL, "ifidx=%d, cmd=%d, value=%d\n", ifp->ifidx, cmd, *data);
    190
    191	return err;
    192}
    193
    194static u32
    195brcmf_create_iovar(const char *name, const char *data, u32 datalen,
    196		   char *buf, u32 buflen)
    197{
    198	u32 len;
    199
    200	len = strlen(name) + 1;
    201
    202	if ((len + datalen) > buflen)
    203		return 0;
    204
    205	memcpy(buf, name, len);
    206
    207	/* append data onto the end of the name string */
    208	if (data && datalen)
    209		memcpy(&buf[len], data, datalen);
    210
    211	return len + datalen;
    212}
    213
    214
    215s32
    216brcmf_fil_iovar_data_set(struct brcmf_if *ifp, const char *name, const void *data,
    217			 u32 len)
    218{
    219	struct brcmf_pub *drvr = ifp->drvr;
    220	s32 err;
    221	u32 buflen;
    222
    223	mutex_lock(&drvr->proto_block);
    224
    225	brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d\n", ifp->ifidx, name, len);
    226	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
    227			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
    228
    229	buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
    230				    sizeof(drvr->proto_buf));
    231	if (buflen) {
    232		err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
    233					 buflen, true);
    234	} else {
    235		err = -EPERM;
    236		bphy_err(drvr, "Creating iovar failed\n");
    237	}
    238
    239	mutex_unlock(&drvr->proto_block);
    240	return err;
    241}
    242
    243s32
    244brcmf_fil_iovar_data_get(struct brcmf_if *ifp, const char *name, void *data,
    245			 u32 len)
    246{
    247	struct brcmf_pub *drvr = ifp->drvr;
    248	s32 err;
    249	u32 buflen;
    250
    251	mutex_lock(&drvr->proto_block);
    252
    253	buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
    254				    sizeof(drvr->proto_buf));
    255	if (buflen) {
    256		err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
    257					 buflen, false);
    258		if (err == 0)
    259			memcpy(data, drvr->proto_buf, len);
    260	} else {
    261		err = -EPERM;
    262		bphy_err(drvr, "Creating iovar failed\n");
    263	}
    264
    265	brcmf_dbg(FIL, "ifidx=%d, name=%s, len=%d, err=%d\n", ifp->ifidx, name,
    266		  len, err);
    267	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
    268			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
    269
    270	mutex_unlock(&drvr->proto_block);
    271	return err;
    272}
    273
    274s32
    275brcmf_fil_iovar_int_set(struct brcmf_if *ifp, const char *name, u32 data)
    276{
    277	__le32 data_le = cpu_to_le32(data);
    278
    279	return brcmf_fil_iovar_data_set(ifp, name, &data_le, sizeof(data_le));
    280}
    281
    282s32
    283brcmf_fil_iovar_int_get(struct brcmf_if *ifp, const char *name, u32 *data)
    284{
    285	__le32 data_le = cpu_to_le32(*data);
    286	s32 err;
    287
    288	err = brcmf_fil_iovar_data_get(ifp, name, &data_le, sizeof(data_le));
    289	if (err == 0)
    290		*data = le32_to_cpu(data_le);
    291	return err;
    292}
    293
    294static u32
    295brcmf_create_bsscfg(s32 bsscfgidx, const char *name, char *data, u32 datalen,
    296		    char *buf, u32 buflen)
    297{
    298	const s8 *prefix = "bsscfg:";
    299	s8 *p;
    300	u32 prefixlen;
    301	u32 namelen;
    302	u32 iolen;
    303	__le32 bsscfgidx_le;
    304
    305	if (bsscfgidx == 0)
    306		return brcmf_create_iovar(name, data, datalen, buf, buflen);
    307
    308	prefixlen = strlen(prefix);
    309	namelen = strlen(name) + 1; /* length of iovar  name + null */
    310	iolen = prefixlen + namelen + sizeof(bsscfgidx_le) + datalen;
    311
    312	if (buflen < iolen) {
    313		brcmf_err("buffer is too short\n");
    314		return 0;
    315	}
    316
    317	p = buf;
    318
    319	/* copy prefix, no null */
    320	memcpy(p, prefix, prefixlen);
    321	p += prefixlen;
    322
    323	/* copy iovar name including null */
    324	memcpy(p, name, namelen);
    325	p += namelen;
    326
    327	/* bss config index as first data */
    328	bsscfgidx_le = cpu_to_le32(bsscfgidx);
    329	memcpy(p, &bsscfgidx_le, sizeof(bsscfgidx_le));
    330	p += sizeof(bsscfgidx_le);
    331
    332	/* parameter buffer follows */
    333	if (datalen)
    334		memcpy(p, data, datalen);
    335
    336	return iolen;
    337}
    338
    339s32
    340brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, const char *name,
    341			  void *data, u32 len)
    342{
    343	struct brcmf_pub *drvr = ifp->drvr;
    344	s32 err;
    345	u32 buflen;
    346
    347	mutex_lock(&drvr->proto_block);
    348
    349	brcmf_dbg(FIL, "ifidx=%d, bsscfgidx=%d, name=%s, len=%d\n", ifp->ifidx,
    350		  ifp->bsscfgidx, name, len);
    351	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
    352			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
    353
    354	buflen = brcmf_create_bsscfg(ifp->bsscfgidx, name, data, len,
    355				     drvr->proto_buf, sizeof(drvr->proto_buf));
    356	if (buflen) {
    357		err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
    358					 buflen, true);
    359	} else {
    360		err = -EPERM;
    361		bphy_err(drvr, "Creating bsscfg failed\n");
    362	}
    363
    364	mutex_unlock(&drvr->proto_block);
    365	return err;
    366}
    367
    368s32
    369brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, const char *name,
    370			  void *data, u32 len)
    371{
    372	struct brcmf_pub *drvr = ifp->drvr;
    373	s32 err;
    374	u32 buflen;
    375
    376	mutex_lock(&drvr->proto_block);
    377
    378	buflen = brcmf_create_bsscfg(ifp->bsscfgidx, name, data, len,
    379				     drvr->proto_buf, sizeof(drvr->proto_buf));
    380	if (buflen) {
    381		err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
    382					 buflen, false);
    383		if (err == 0)
    384			memcpy(data, drvr->proto_buf, len);
    385	} else {
    386		err = -EPERM;
    387		bphy_err(drvr, "Creating bsscfg failed\n");
    388	}
    389	brcmf_dbg(FIL, "ifidx=%d, bsscfgidx=%d, name=%s, len=%d, err=%d\n",
    390		  ifp->ifidx, ifp->bsscfgidx, name, len, err);
    391	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
    392			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
    393
    394	mutex_unlock(&drvr->proto_block);
    395	return err;
    396}
    397
    398s32
    399brcmf_fil_bsscfg_int_set(struct brcmf_if *ifp, const char *name, u32 data)
    400{
    401	__le32 data_le = cpu_to_le32(data);
    402
    403	return brcmf_fil_bsscfg_data_set(ifp, name, &data_le,
    404					 sizeof(data_le));
    405}
    406
    407s32
    408brcmf_fil_bsscfg_int_get(struct brcmf_if *ifp, const char *name, u32 *data)
    409{
    410	__le32 data_le = cpu_to_le32(*data);
    411	s32 err;
    412
    413	err = brcmf_fil_bsscfg_data_get(ifp, name, &data_le,
    414					sizeof(data_le));
    415	if (err == 0)
    416		*data = le32_to_cpu(data_le);
    417	return err;
    418}
    419
    420static u32 brcmf_create_xtlv(const char *name, u16 id, char *data, u32 len,
    421			     char *buf, u32 buflen)
    422{
    423	u32 iolen;
    424	u32 nmlen;
    425
    426	nmlen = strlen(name) + 1;
    427	iolen = nmlen + brcmf_xtlv_data_size(len, BRCMF_XTLV_OPTION_ALIGN32);
    428
    429	if (iolen > buflen) {
    430		brcmf_err("buffer is too short\n");
    431		return 0;
    432	}
    433
    434	memcpy(buf, name, nmlen);
    435	brcmf_xtlv_pack_header((void *)(buf + nmlen), id, len, data,
    436			       BRCMF_XTLV_OPTION_ALIGN32);
    437
    438	return iolen;
    439}
    440
    441s32 brcmf_fil_xtlv_data_set(struct brcmf_if *ifp, const char *name, u16 id,
    442			    void *data, u32 len)
    443{
    444	struct brcmf_pub *drvr = ifp->drvr;
    445	s32 err;
    446	u32 buflen;
    447
    448	mutex_lock(&drvr->proto_block);
    449
    450	brcmf_dbg(FIL, "ifidx=%d, name=%s, id=%u, len=%u\n", ifp->ifidx, name,
    451		  id, len);
    452	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
    453			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
    454
    455	buflen = brcmf_create_xtlv(name, id, data, len,
    456				   drvr->proto_buf, sizeof(drvr->proto_buf));
    457	if (buflen) {
    458		err = brcmf_fil_cmd_data(ifp, BRCMF_C_SET_VAR, drvr->proto_buf,
    459					 buflen, true);
    460	} else {
    461		err = -EPERM;
    462		bphy_err(drvr, "Creating xtlv failed\n");
    463	}
    464
    465	mutex_unlock(&drvr->proto_block);
    466	return err;
    467}
    468
    469s32 brcmf_fil_xtlv_data_get(struct brcmf_if *ifp, const char *name, u16 id,
    470			    void *data, u32 len)
    471{
    472	struct brcmf_pub *drvr = ifp->drvr;
    473	s32 err;
    474	u32 buflen;
    475
    476	mutex_lock(&drvr->proto_block);
    477
    478	buflen = brcmf_create_xtlv(name, id, data, len,
    479				   drvr->proto_buf, sizeof(drvr->proto_buf));
    480	if (buflen) {
    481		err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
    482					 buflen, false);
    483		if (err == 0)
    484			memcpy(data, drvr->proto_buf, len);
    485	} else {
    486		err = -EPERM;
    487		bphy_err(drvr, "Creating bsscfg failed\n");
    488	}
    489	brcmf_dbg(FIL, "ifidx=%d, name=%s, id=%u, len=%u, err=%d\n",
    490		  ifp->ifidx, name, id, len, err);
    491	brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
    492			   min_t(uint, len, MAX_HEX_DUMP_LEN), "data\n");
    493
    494	mutex_unlock(&drvr->proto_block);
    495	return err;
    496}
    497
    498s32 brcmf_fil_xtlv_int_set(struct brcmf_if *ifp, const char *name, u16 id, u32 data)
    499{
    500	__le32 data_le = cpu_to_le32(data);
    501
    502	return brcmf_fil_xtlv_data_set(ifp, name, id, &data_le,
    503					 sizeof(data_le));
    504}
    505
    506s32 brcmf_fil_xtlv_int_get(struct brcmf_if *ifp, const char *name, u16 id, u32 *data)
    507{
    508	__le32 data_le = cpu_to_le32(*data);
    509	s32 err;
    510
    511	err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le));
    512	if (err == 0)
    513		*data = le32_to_cpu(data_le);
    514	return err;
    515}
    516
    517s32 brcmf_fil_xtlv_int8_get(struct brcmf_if *ifp, const char *name, u16 id, u8 *data)
    518{
    519	return brcmf_fil_xtlv_data_get(ifp, name, id, data, sizeof(*data));
    520}
    521
    522s32 brcmf_fil_xtlv_int16_get(struct brcmf_if *ifp, const char *name, u16 id, u16 *data)
    523{
    524	__le16 data_le = cpu_to_le16(*data);
    525	s32 err;
    526
    527	err = brcmf_fil_xtlv_data_get(ifp, name, id, &data_le, sizeof(data_le));
    528	if (err == 0)
    529		*data = le16_to_cpu(data_le);
    530	return err;
    531}
    532