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