Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: ISC
0002 /*
0003  * Copyright (c) 2014 Broadcom Corporation
0004  */
0005 
0006 #include <linux/netdevice.h>
0007 #include <linux/module.h>
0008 
0009 #include <brcm_hw_ids.h>
0010 #include <brcmu_wifi.h>
0011 #include "core.h"
0012 #include "bus.h"
0013 #include "debug.h"
0014 #include "fwil.h"
0015 #include "fwil_types.h"
0016 #include "feature.h"
0017 #include "common.h"
0018 
0019 #define BRCMF_FW_UNSUPPORTED    23
0020 
0021 /*
0022  * expand feature list to array of feature strings.
0023  */
0024 #define BRCMF_FEAT_DEF(_f) \
0025     #_f,
0026 static const char *brcmf_feat_names[] = {
0027     BRCMF_FEAT_LIST
0028 };
0029 #undef BRCMF_FEAT_DEF
0030 
0031 struct brcmf_feat_fwcap {
0032     enum brcmf_feat_id feature;
0033     const char * const fwcap_id;
0034 };
0035 
0036 static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = {
0037     { BRCMF_FEAT_MBSS, "mbss" },
0038     { BRCMF_FEAT_MCHAN, "mchan" },
0039     { BRCMF_FEAT_P2P, "p2p" },
0040     { BRCMF_FEAT_MONITOR, "monitor" },
0041     { BRCMF_FEAT_MONITOR_FLAG, "rtap" },
0042     { BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" },
0043     { BRCMF_FEAT_DOT11H, "802.11h" },
0044     { BRCMF_FEAT_SAE, "sae" },
0045     { BRCMF_FEAT_FWAUTH, "idauth" },
0046 };
0047 
0048 #ifdef DEBUG
0049 /*
0050  * expand quirk list to array of quirk strings.
0051  */
0052 #define BRCMF_QUIRK_DEF(_q) \
0053     #_q,
0054 static const char * const brcmf_quirk_names[] = {
0055     BRCMF_QUIRK_LIST
0056 };
0057 #undef BRCMF_QUIRK_DEF
0058 
0059 /**
0060  * brcmf_feat_debugfs_read() - expose feature info to debugfs.
0061  *
0062  * @seq: sequence for debugfs entry.
0063  * @data: raw data pointer.
0064  */
0065 static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data)
0066 {
0067     struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
0068     u32 feats = bus_if->drvr->feat_flags;
0069     u32 quirks = bus_if->drvr->chip_quirks;
0070     int id;
0071 
0072     seq_printf(seq, "Features: %08x\n", feats);
0073     for (id = 0; id < BRCMF_FEAT_LAST; id++)
0074         if (feats & BIT(id))
0075             seq_printf(seq, "\t%s\n", brcmf_feat_names[id]);
0076     seq_printf(seq, "\nQuirks:   %08x\n", quirks);
0077     for (id = 0; id < BRCMF_FEAT_QUIRK_LAST; id++)
0078         if (quirks & BIT(id))
0079             seq_printf(seq, "\t%s\n", brcmf_quirk_names[id]);
0080     return 0;
0081 }
0082 #else
0083 static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data)
0084 {
0085     return 0;
0086 }
0087 #endif /* DEBUG */
0088 
0089 struct brcmf_feat_fwfeat {
0090     const char * const fwid;
0091     u32 feat_flags;
0092 };
0093 
0094 static const struct brcmf_feat_fwfeat brcmf_feat_fwfeat_map[] = {
0095     /* brcmfmac43602-pcie.ap.bin from linux-firmware.git commit ea1178515b88 */
0096     { "01-6cb8e269", BIT(BRCMF_FEAT_MONITOR) },
0097     /* brcmfmac4366b-pcie.bin from linux-firmware.git commit 52442afee990 */
0098     { "01-c47a91a4", BIT(BRCMF_FEAT_MONITOR) },
0099     /* brcmfmac4366b-pcie.bin from linux-firmware.git commit 211de1679a68 */
0100     { "01-801fb449", BIT(BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR) },
0101     /* brcmfmac4366c-pcie.bin from linux-firmware.git commit 211de1679a68 */
0102     { "01-d2cbb8fd", BIT(BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR) },
0103 };
0104 
0105 static void brcmf_feat_firmware_overrides(struct brcmf_pub *drv)
0106 {
0107     const struct brcmf_feat_fwfeat *e;
0108     u32 feat_flags = 0;
0109     int i;
0110 
0111     for (i = 0; i < ARRAY_SIZE(brcmf_feat_fwfeat_map); i++) {
0112         e = &brcmf_feat_fwfeat_map[i];
0113         if (!strcmp(e->fwid, drv->fwver)) {
0114             feat_flags = e->feat_flags;
0115             break;
0116         }
0117     }
0118 
0119     if (!feat_flags)
0120         return;
0121 
0122     for (i = 0; i < BRCMF_FEAT_LAST; i++)
0123         if (feat_flags & BIT(i))
0124             brcmf_dbg(INFO, "enabling firmware feature: %s\n",
0125                   brcmf_feat_names[i]);
0126     drv->feat_flags |= feat_flags;
0127 }
0128 
0129 /**
0130  * brcmf_feat_iovar_int_get() - determine feature through iovar query.
0131  *
0132  * @ifp: interface to query.
0133  * @id: feature id.
0134  * @name: iovar name.
0135  */
0136 static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
0137                      enum brcmf_feat_id id, char *name)
0138 {
0139     u32 data;
0140     int err;
0141 
0142     /* we need to know firmware error */
0143     ifp->fwil_fwerr = true;
0144 
0145     err = brcmf_fil_iovar_int_get(ifp, name, &data);
0146     if (err == 0) {
0147         brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
0148         ifp->drvr->feat_flags |= BIT(id);
0149     } else {
0150         brcmf_dbg(TRACE, "%s feature check failed: %d\n",
0151               brcmf_feat_names[id], err);
0152     }
0153 
0154     ifp->fwil_fwerr = false;
0155 }
0156 
0157 static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,
0158                       enum brcmf_feat_id id, char *name,
0159                       const void *data, size_t len)
0160 {
0161     int err;
0162 
0163     /* we need to know firmware error */
0164     ifp->fwil_fwerr = true;
0165 
0166     err = brcmf_fil_iovar_data_set(ifp, name, data, len);
0167     if (err != -BRCMF_FW_UNSUPPORTED) {
0168         brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
0169         ifp->drvr->feat_flags |= BIT(id);
0170     } else {
0171         brcmf_dbg(TRACE, "%s feature check failed: %d\n",
0172               brcmf_feat_names[id], err);
0173     }
0174 
0175     ifp->fwil_fwerr = false;
0176 }
0177 
0178 #define MAX_CAPS_BUFFER_SIZE    768
0179 static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp)
0180 {
0181     struct brcmf_pub *drvr = ifp->drvr;
0182     char caps[MAX_CAPS_BUFFER_SIZE];
0183     enum brcmf_feat_id id;
0184     int i, err;
0185 
0186     err = brcmf_fil_iovar_data_get(ifp, "cap", caps, sizeof(caps));
0187     if (err) {
0188         bphy_err(drvr, "could not get firmware cap (%d)\n", err);
0189         return;
0190     }
0191 
0192     brcmf_dbg(INFO, "[ %s]\n", caps);
0193 
0194     for (i = 0; i < ARRAY_SIZE(brcmf_fwcap_map); i++) {
0195         if (strnstr(caps, brcmf_fwcap_map[i].fwcap_id, sizeof(caps))) {
0196             id = brcmf_fwcap_map[i].feature;
0197             brcmf_dbg(INFO, "enabling feature: %s\n",
0198                   brcmf_feat_names[id]);
0199             ifp->drvr->feat_flags |= BIT(id);
0200         }
0201     }
0202 }
0203 
0204 /**
0205  * brcmf_feat_fwcap_debugfs_read() - expose firmware capabilities to debugfs.
0206  *
0207  * @seq: sequence for debugfs entry.
0208  * @data: raw data pointer.
0209  */
0210 static int brcmf_feat_fwcap_debugfs_read(struct seq_file *seq, void *data)
0211 {
0212     struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
0213     struct brcmf_pub *drvr = bus_if->drvr;
0214     struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
0215     char caps[MAX_CAPS_BUFFER_SIZE + 1] = { };
0216     char *tmp;
0217     int err;
0218 
0219     err = brcmf_fil_iovar_data_get(ifp, "cap", caps, sizeof(caps));
0220     if (err) {
0221         bphy_err(drvr, "could not get firmware cap (%d)\n", err);
0222         return err;
0223     }
0224 
0225     /* Put every capability in a new line */
0226     for (tmp = caps; *tmp; tmp++) {
0227         if (*tmp == ' ')
0228             *tmp = '\n';
0229     }
0230 
0231     /* Usually there is a space at the end of capabilities string */
0232     seq_printf(seq, "%s", caps);
0233     /* So make sure we don't print two line breaks */
0234     if (tmp > caps && *(tmp - 1) != '\n')
0235         seq_printf(seq, "\n");
0236 
0237     return 0;
0238 }
0239 
0240 void brcmf_feat_attach(struct brcmf_pub *drvr)
0241 {
0242     struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
0243     struct brcmf_pno_macaddr_le pfn_mac;
0244     struct brcmf_gscan_config gscan_cfg;
0245     u32 wowl_cap;
0246     s32 err;
0247 
0248     brcmf_feat_firmware_capabilities(ifp);
0249     memset(&gscan_cfg, 0, sizeof(gscan_cfg));
0250     if (drvr->bus_if->chip != BRCM_CC_43430_CHIP_ID &&
0251         drvr->bus_if->chip != BRCM_CC_4345_CHIP_ID &&
0252         drvr->bus_if->chip != BRCM_CC_43454_CHIP_ID)
0253         brcmf_feat_iovar_data_set(ifp, BRCMF_FEAT_GSCAN,
0254                       "pfn_gscan_cfg",
0255                       &gscan_cfg, sizeof(gscan_cfg));
0256     brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
0257     if (drvr->bus_if->wowl_supported)
0258         brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
0259     if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) {
0260         err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap);
0261         if (!err) {
0262             ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_WOWL_ARP_ND);
0263             if (wowl_cap & BRCMF_WOWL_PFN_FOUND)
0264                 ifp->drvr->feat_flags |=
0265                     BIT(BRCMF_FEAT_WOWL_ND);
0266             if (wowl_cap & BRCMF_WOWL_GTK_FAILURE)
0267                 ifp->drvr->feat_flags |=
0268                     BIT(BRCMF_FEAT_WOWL_GTK);
0269         }
0270     }
0271     /* MBSS does not work for all chips */
0272     switch (drvr->bus_if->chip) {
0273     case BRCM_CC_4330_CHIP_ID:
0274     case BRCM_CC_43362_CHIP_ID:
0275         ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS);
0276         break;
0277     default:
0278         break;
0279     }
0280     brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode");
0281     brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable");
0282     brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MFP, "mfp");
0283 
0284     pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
0285     err = brcmf_fil_iovar_data_get(ifp, "pfn_macaddr", &pfn_mac,
0286                        sizeof(pfn_mac));
0287     if (!err)
0288         ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_SCAN_RANDOM_MAC);
0289 
0290     brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa");
0291 
0292     if (drvr->settings->feature_disable) {
0293         brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n",
0294               ifp->drvr->feat_flags,
0295               drvr->settings->feature_disable);
0296         ifp->drvr->feat_flags &= ~drvr->settings->feature_disable;
0297     }
0298 
0299     brcmf_feat_firmware_overrides(drvr);
0300 
0301     /* set chip related quirks */
0302     switch (drvr->bus_if->chip) {
0303     case BRCM_CC_43236_CHIP_ID:
0304         drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_AUTO_AUTH);
0305         break;
0306     case BRCM_CC_4329_CHIP_ID:
0307         drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_NEED_MPC);
0308         break;
0309     default:
0310         /* no quirks */
0311         break;
0312     }
0313 }
0314 
0315 void brcmf_feat_debugfs_create(struct brcmf_pub *drvr)
0316 {
0317     brcmf_debugfs_add_entry(drvr, "features", brcmf_feat_debugfs_read);
0318     brcmf_debugfs_add_entry(drvr, "fwcap", brcmf_feat_fwcap_debugfs_read);
0319 }
0320 
0321 bool brcmf_feat_is_enabled(struct brcmf_if *ifp, enum brcmf_feat_id id)
0322 {
0323     return (ifp->drvr->feat_flags & BIT(id));
0324 }
0325 
0326 bool brcmf_feat_is_quirk_enabled(struct brcmf_if *ifp,
0327                  enum brcmf_feat_quirk quirk)
0328 {
0329     return (ifp->drvr->chip_quirks & BIT(quirk));
0330 }