1 // SPDX-License-Identifier: ISC 2 /* 3 * Copyright (c) 2014 Broadcom Corporation 4 */ 5 6 #include <linux/netdevice.h> 7 #include <linux/module.h> 8 9 #include <brcm_hw_ids.h> 10 #include <brcmu_wifi.h> 11 #include "core.h" 12 #include "bus.h" 13 #include "debug.h" 14 #include "fwil.h" 15 #include "fwil_types.h" 16 #include "fwvid.h" 17 #include "feature.h" 18 #include "common.h" 19 20 #define BRCMF_FW_UNSUPPORTED 23 21 22 /* 23 * expand feature list to array of feature strings. 24 */ 25 #define BRCMF_FEAT_DEF(_f) \ 26 #_f, 27 static const char *brcmf_feat_names[] = { 28 BRCMF_FEAT_LIST 29 }; 30 #undef BRCMF_FEAT_DEF 31 32 struct brcmf_feat_fwcap { 33 enum brcmf_feat_id feature; 34 const char * const fwcap_id; 35 }; 36 37 static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = { 38 { BRCMF_FEAT_MBSS, "mbss" }, 39 { BRCMF_FEAT_MCHAN, "mchan" }, 40 { BRCMF_FEAT_P2P, "p2p" }, 41 { BRCMF_FEAT_MONITOR, "monitor" }, 42 { BRCMF_FEAT_MONITOR_FLAG, "rtap" }, 43 { BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" }, 44 { BRCMF_FEAT_DOT11H, "802.11h" }, 45 { BRCMF_FEAT_SAE, "sae " }, 46 { BRCMF_FEAT_FWAUTH, "idauth" }, 47 { BRCMF_FEAT_SAE_EXT, "sae_ext" }, 48 }; 49 50 #ifdef DEBUG 51 /* 52 * expand quirk list to array of quirk strings. 53 */ 54 #define BRCMF_QUIRK_DEF(_q) \ 55 #_q, 56 static const char * const brcmf_quirk_names[] = { 57 BRCMF_QUIRK_LIST 58 }; 59 #undef BRCMF_QUIRK_DEF 60 61 /** 62 * brcmf_feat_debugfs_read() - expose feature info to debugfs. 63 * 64 * @seq: sequence for debugfs entry. 65 * @data: raw data pointer. 66 */ 67 static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data) 68 { 69 struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); 70 u32 feats = bus_if->drvr->feat_flags; 71 u32 quirks = bus_if->drvr->chip_quirks; 72 int id; 73 74 seq_printf(seq, "Features: %08x\n", feats); 75 for (id = 0; id < BRCMF_FEAT_LAST; id++) 76 if (feats & BIT(id)) 77 seq_printf(seq, "\t%s\n", brcmf_feat_names[id]); 78 seq_printf(seq, "\nQuirks: %08x\n", quirks); 79 for (id = 0; id < BRCMF_FEAT_QUIRK_LAST; id++) 80 if (quirks & BIT(id)) 81 seq_printf(seq, "\t%s\n", brcmf_quirk_names[id]); 82 return 0; 83 } 84 #else 85 static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data) 86 { 87 return 0; 88 } 89 #endif /* DEBUG */ 90 91 struct brcmf_feat_fwfeat { 92 const char * const fwid; 93 u32 feat_flags; 94 }; 95 96 static const struct brcmf_feat_fwfeat brcmf_feat_fwfeat_map[] = { 97 /* brcmfmac43602-pcie.ap.bin from linux-firmware.git commit ea1178515b88 */ 98 { "01-6cb8e269", BIT(BRCMF_FEAT_MONITOR) }, 99 /* brcmfmac4366b-pcie.bin from linux-firmware.git commit 52442afee990 */ 100 { "01-c47a91a4", BIT(BRCMF_FEAT_MONITOR) }, 101 /* brcmfmac4366b-pcie.bin from linux-firmware.git commit 211de1679a68 */ 102 { "01-801fb449", BIT(BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR) }, 103 /* brcmfmac4366c-pcie.bin from linux-firmware.git commit 211de1679a68 */ 104 { "01-d2cbb8fd", BIT(BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR) }, 105 }; 106 107 static void brcmf_feat_firmware_overrides(struct brcmf_pub *drv) 108 { 109 const struct brcmf_feat_fwfeat *e; 110 u32 feat_flags = 0; 111 int i; 112 113 for (i = 0; i < ARRAY_SIZE(brcmf_feat_fwfeat_map); i++) { 114 e = &brcmf_feat_fwfeat_map[i]; 115 if (!strcmp(e->fwid, drv->fwver)) { 116 feat_flags = e->feat_flags; 117 break; 118 } 119 } 120 121 if (!feat_flags) 122 return; 123 124 for (i = 0; i < BRCMF_FEAT_LAST; i++) 125 if (feat_flags & BIT(i)) 126 brcmf_dbg(INFO, "enabling firmware feature: %s\n", 127 brcmf_feat_names[i]); 128 drv->feat_flags |= feat_flags; 129 } 130 131 struct brcmf_feat_wlcfeat { 132 u16 min_ver_major; 133 u16 min_ver_minor; 134 u32 feat_flags; 135 }; 136 137 static const struct brcmf_feat_wlcfeat brcmf_feat_wlcfeat_map[] = { 138 { 12, 0, BIT(BRCMF_FEAT_PMKID_V2) }, 139 { 13, 0, BIT(BRCMF_FEAT_PMKID_V3) }, 140 }; 141 142 static void brcmf_feat_wlc_version_overrides(struct brcmf_pub *drv) 143 { 144 struct brcmf_if *ifp = brcmf_get_ifp(drv, 0); 145 const struct brcmf_feat_wlcfeat *e; 146 struct brcmf_wlc_version_le ver; 147 u32 feat_flags = 0; 148 int i, err, major, minor; 149 150 err = brcmf_fil_iovar_data_get(ifp, "wlc_ver", &ver, sizeof(ver)); 151 if (err) 152 return; 153 154 major = le16_to_cpu(ver.wlc_ver_major); 155 minor = le16_to_cpu(ver.wlc_ver_minor); 156 157 brcmf_dbg(INFO, "WLC version: %d.%d\n", major, minor); 158 159 for (i = 0; i < ARRAY_SIZE(brcmf_feat_wlcfeat_map); i++) { 160 e = &brcmf_feat_wlcfeat_map[i]; 161 if (major > e->min_ver_major || 162 (major == e->min_ver_major && 163 minor >= e->min_ver_minor)) { 164 feat_flags |= e->feat_flags; 165 } 166 } 167 168 if (!feat_flags) 169 return; 170 171 for (i = 0; i < BRCMF_FEAT_LAST; i++) 172 if (feat_flags & BIT(i)) 173 brcmf_dbg(INFO, "enabling firmware feature: %s\n", 174 brcmf_feat_names[i]); 175 drv->feat_flags |= feat_flags; 176 } 177 178 /** 179 * brcmf_feat_iovar_int_get() - determine feature through iovar query. 180 * 181 * @ifp: interface to query. 182 * @id: feature id. 183 * @name: iovar name. 184 */ 185 static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp, 186 enum brcmf_feat_id id, char *name) 187 { 188 u32 data; 189 int err; 190 191 /* we need to know firmware error */ 192 ifp->fwil_fwerr = true; 193 194 err = brcmf_fil_iovar_int_get(ifp, name, &data); 195 if (err != -BRCMF_FW_UNSUPPORTED) { 196 brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]); 197 ifp->drvr->feat_flags |= BIT(id); 198 } else { 199 brcmf_dbg(TRACE, "%s feature check failed: %d\n", 200 brcmf_feat_names[id], err); 201 } 202 203 ifp->fwil_fwerr = false; 204 } 205 206 static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp, 207 enum brcmf_feat_id id, char *name, 208 const void *data, size_t len) 209 { 210 int err; 211 212 /* we need to know firmware error */ 213 ifp->fwil_fwerr = true; 214 215 err = brcmf_fil_iovar_data_set(ifp, name, data, len); 216 if (err != -BRCMF_FW_UNSUPPORTED) { 217 brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]); 218 ifp->drvr->feat_flags |= BIT(id); 219 } else { 220 brcmf_dbg(TRACE, "%s feature check failed: %d\n", 221 brcmf_feat_names[id], err); 222 } 223 224 ifp->fwil_fwerr = false; 225 } 226 227 #define MAX_CAPS_BUFFER_SIZE 768 228 static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp) 229 { 230 struct brcmf_pub *drvr = ifp->drvr; 231 char caps[MAX_CAPS_BUFFER_SIZE]; 232 enum brcmf_feat_id id; 233 int i, err; 234 235 err = brcmf_fil_iovar_data_get(ifp, "cap", caps, sizeof(caps)); 236 if (err) { 237 bphy_err(drvr, "could not get firmware cap (%d)\n", err); 238 return; 239 } 240 241 brcmf_dbg(INFO, "[ %s]\n", caps); 242 243 for (i = 0; i < ARRAY_SIZE(brcmf_fwcap_map); i++) { 244 if (strnstr(caps, brcmf_fwcap_map[i].fwcap_id, sizeof(caps))) { 245 id = brcmf_fwcap_map[i].feature; 246 brcmf_dbg(INFO, "enabling feature: %s\n", 247 brcmf_feat_names[id]); 248 ifp->drvr->feat_flags |= BIT(id); 249 } 250 } 251 } 252 253 /** 254 * brcmf_feat_fwcap_debugfs_read() - expose firmware capabilities to debugfs. 255 * 256 * @seq: sequence for debugfs entry. 257 * @data: raw data pointer. 258 */ 259 static int brcmf_feat_fwcap_debugfs_read(struct seq_file *seq, void *data) 260 { 261 struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); 262 struct brcmf_pub *drvr = bus_if->drvr; 263 struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); 264 char caps[MAX_CAPS_BUFFER_SIZE + 1] = { }; 265 char *tmp; 266 int err; 267 268 err = brcmf_fil_iovar_data_get(ifp, "cap", caps, sizeof(caps)); 269 if (err) { 270 bphy_err(drvr, "could not get firmware cap (%d)\n", err); 271 return err; 272 } 273 274 /* Put every capability in a new line */ 275 for (tmp = caps; *tmp; tmp++) { 276 if (*tmp == ' ') 277 *tmp = '\n'; 278 } 279 280 /* Usually there is a space at the end of capabilities string */ 281 seq_printf(seq, "%s", caps); 282 /* So make sure we don't print two line breaks */ 283 if (tmp > caps && *(tmp - 1) != '\n') 284 seq_printf(seq, "\n"); 285 286 return 0; 287 } 288 289 void brcmf_feat_attach(struct brcmf_pub *drvr) 290 { 291 struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0); 292 struct brcmf_pno_macaddr_le pfn_mac; 293 struct brcmf_gscan_config gscan_cfg; 294 u32 wowl_cap; 295 s32 err; 296 297 brcmf_feat_firmware_capabilities(ifp); 298 memset(&gscan_cfg, 0, sizeof(gscan_cfg)); 299 if (drvr->bus_if->chip != BRCM_CC_43430_CHIP_ID && 300 drvr->bus_if->chip != BRCM_CC_4345_CHIP_ID && 301 drvr->bus_if->chip != BRCM_CC_43454_CHIP_ID && 302 drvr->bus_if->chip != CY_CC_43439_CHIP_ID) 303 brcmf_feat_iovar_data_set(ifp, BRCMF_FEAT_GSCAN, 304 "pfn_gscan_cfg", 305 &gscan_cfg, sizeof(gscan_cfg)); 306 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn"); 307 if (drvr->bus_if->wowl_supported) 308 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl"); 309 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) { 310 err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap); 311 if (!err) { 312 ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_WOWL_ARP_ND); 313 if (wowl_cap & BRCMF_WOWL_PFN_FOUND) 314 ifp->drvr->feat_flags |= 315 BIT(BRCMF_FEAT_WOWL_ND); 316 if (wowl_cap & BRCMF_WOWL_GTK_FAILURE) 317 ifp->drvr->feat_flags |= 318 BIT(BRCMF_FEAT_WOWL_GTK); 319 } 320 } 321 /* MBSS does not work for all chips */ 322 switch (drvr->bus_if->chip) { 323 case BRCM_CC_4330_CHIP_ID: 324 case BRCM_CC_43362_CHIP_ID: 325 ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS); 326 break; 327 default: 328 break; 329 } 330 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode"); 331 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable"); 332 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MFP, "mfp"); 333 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_DUMP_OBSS, "dump_obss"); 334 335 pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER; 336 err = brcmf_fil_iovar_data_get(ifp, "pfn_macaddr", &pfn_mac, 337 sizeof(pfn_mac)); 338 if (!err) 339 ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_SCAN_RANDOM_MAC); 340 341 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa"); 342 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_SCAN_V2, "scan_ver"); 343 344 brcmf_feat_wlc_version_overrides(drvr); 345 brcmf_feat_firmware_overrides(drvr); 346 347 brcmf_fwvid_feat_attach(ifp); 348 349 if (drvr->settings->feature_disable) { 350 brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n", 351 ifp->drvr->feat_flags, 352 drvr->settings->feature_disable); 353 ifp->drvr->feat_flags &= ~drvr->settings->feature_disable; 354 } 355 356 /* set chip related quirks */ 357 switch (drvr->bus_if->chip) { 358 case BRCM_CC_43236_CHIP_ID: 359 drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_AUTO_AUTH); 360 break; 361 case BRCM_CC_4329_CHIP_ID: 362 drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_NEED_MPC); 363 break; 364 default: 365 /* no quirks */ 366 break; 367 } 368 } 369 370 void brcmf_feat_debugfs_create(struct brcmf_pub *drvr) 371 { 372 brcmf_debugfs_add_entry(drvr, "features", brcmf_feat_debugfs_read); 373 brcmf_debugfs_add_entry(drvr, "fwcap", brcmf_feat_fwcap_debugfs_read); 374 } 375 376 bool brcmf_feat_is_enabled(struct brcmf_if *ifp, enum brcmf_feat_id id) 377 { 378 return (ifp->drvr->feat_flags & BIT(id)); 379 } 380 381 bool brcmf_feat_is_quirk_enabled(struct brcmf_if *ifp, 382 enum brcmf_feat_quirk quirk) 383 { 384 return (ifp->drvr->chip_quirks & BIT(quirk)); 385 } 386