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