This source file includes following definitions.
- brcmf_feat_debugfs_read
- brcmf_feat_debugfs_read
- brcmf_feat_firmware_overrides
- brcmf_feat_iovar_int_get
- brcmf_feat_iovar_data_set
- brcmf_feat_firmware_capabilities
- brcmf_feat_fwcap_debugfs_read
- brcmf_feat_attach
- brcmf_feat_debugfs_create
- brcmf_feat_is_enabled
- brcmf_feat_is_quirk_enabled
1
2
3
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
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_FMT_RADIOTAP, "rtap" },
42 { BRCMF_FEAT_DOT11H, "802.11h" }
43 };
44
45 #ifdef DEBUG
46
47
48
49 #define BRCMF_QUIRK_DEF(_q) \
50 #_q,
51 static const char * const brcmf_quirk_names[] = {
52 BRCMF_QUIRK_LIST
53 };
54 #undef BRCMF_QUIRK_DEF
55
56
57
58
59
60
61
62 static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data)
63 {
64 struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
65 u32 feats = bus_if->drvr->feat_flags;
66 u32 quirks = bus_if->drvr->chip_quirks;
67 int id;
68
69 seq_printf(seq, "Features: %08x\n", feats);
70 for (id = 0; id < BRCMF_FEAT_LAST; id++)
71 if (feats & BIT(id))
72 seq_printf(seq, "\t%s\n", brcmf_feat_names[id]);
73 seq_printf(seq, "\nQuirks: %08x\n", quirks);
74 for (id = 0; id < BRCMF_FEAT_QUIRK_LAST; id++)
75 if (quirks & BIT(id))
76 seq_printf(seq, "\t%s\n", brcmf_quirk_names[id]);
77 return 0;
78 }
79 #else
80 static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data)
81 {
82 return 0;
83 }
84 #endif
85
86 struct brcmf_feat_fwfeat {
87 const char * const fwid;
88 u32 feat_flags;
89 };
90
91 static const struct brcmf_feat_fwfeat brcmf_feat_fwfeat_map[] = {
92
93 { "01-6cb8e269", BIT(BRCMF_FEAT_MONITOR) },
94
95 { "01-c47a91a4", BIT(BRCMF_FEAT_MONITOR) },
96
97 { "01-801fb449", BIT(BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR) },
98
99 { "01-d2cbb8fd", BIT(BRCMF_FEAT_MONITOR_FMT_HW_RX_HDR) },
100 };
101
102 static void brcmf_feat_firmware_overrides(struct brcmf_pub *drv)
103 {
104 const struct brcmf_feat_fwfeat *e;
105 u32 feat_flags = 0;
106 int i;
107
108 for (i = 0; i < ARRAY_SIZE(brcmf_feat_fwfeat_map); i++) {
109 e = &brcmf_feat_fwfeat_map[i];
110 if (!strcmp(e->fwid, drv->fwver)) {
111 feat_flags = e->feat_flags;
112 break;
113 }
114 }
115
116 if (!feat_flags)
117 return;
118
119 for (i = 0; i < BRCMF_FEAT_LAST; i++)
120 if (feat_flags & BIT(i))
121 brcmf_dbg(INFO, "enabling firmware feature: %s\n",
122 brcmf_feat_names[i]);
123 drv->feat_flags |= feat_flags;
124 }
125
126
127
128
129
130
131
132
133 static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp,
134 enum brcmf_feat_id id, char *name)
135 {
136 u32 data;
137 int err;
138
139
140 ifp->fwil_fwerr = true;
141
142 err = brcmf_fil_iovar_int_get(ifp, name, &data);
143 if (err == 0) {
144 brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
145 ifp->drvr->feat_flags |= BIT(id);
146 } else {
147 brcmf_dbg(TRACE, "%s feature check failed: %d\n",
148 brcmf_feat_names[id], err);
149 }
150
151 ifp->fwil_fwerr = false;
152 }
153
154 static void brcmf_feat_iovar_data_set(struct brcmf_if *ifp,
155 enum brcmf_feat_id id, char *name,
156 const void *data, size_t len)
157 {
158 int err;
159
160
161 ifp->fwil_fwerr = true;
162
163 err = brcmf_fil_iovar_data_set(ifp, name, data, len);
164 if (err != -BRCMF_FW_UNSUPPORTED) {
165 brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]);
166 ifp->drvr->feat_flags |= BIT(id);
167 } else {
168 brcmf_dbg(TRACE, "%s feature check failed: %d\n",
169 brcmf_feat_names[id], err);
170 }
171
172 ifp->fwil_fwerr = false;
173 }
174
175 #define MAX_CAPS_BUFFER_SIZE 768
176 static void brcmf_feat_firmware_capabilities(struct brcmf_if *ifp)
177 {
178 struct brcmf_pub *drvr = ifp->drvr;
179 char caps[MAX_CAPS_BUFFER_SIZE];
180 enum brcmf_feat_id id;
181 int i, err;
182
183 err = brcmf_fil_iovar_data_get(ifp, "cap", caps, sizeof(caps));
184 if (err) {
185 bphy_err(drvr, "could not get firmware cap (%d)\n", err);
186 return;
187 }
188
189 brcmf_dbg(INFO, "[ %s]\n", caps);
190
191 for (i = 0; i < ARRAY_SIZE(brcmf_fwcap_map); i++) {
192 if (strnstr(caps, brcmf_fwcap_map[i].fwcap_id, sizeof(caps))) {
193 id = brcmf_fwcap_map[i].feature;
194 brcmf_dbg(INFO, "enabling feature: %s\n",
195 brcmf_feat_names[id]);
196 ifp->drvr->feat_flags |= BIT(id);
197 }
198 }
199 }
200
201
202
203
204
205
206
207 static int brcmf_feat_fwcap_debugfs_read(struct seq_file *seq, void *data)
208 {
209 struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
210 struct brcmf_pub *drvr = bus_if->drvr;
211 struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
212 char caps[MAX_CAPS_BUFFER_SIZE + 1] = { };
213 char *tmp;
214 int err;
215
216 err = brcmf_fil_iovar_data_get(ifp, "cap", caps, sizeof(caps));
217 if (err) {
218 bphy_err(drvr, "could not get firmware cap (%d)\n", err);
219 return err;
220 }
221
222
223 for (tmp = caps; *tmp; tmp++) {
224 if (*tmp == ' ')
225 *tmp = '\n';
226 }
227
228
229 seq_printf(seq, "%s", caps);
230
231 if (tmp > caps && *(tmp - 1) != '\n')
232 seq_printf(seq, "\n");
233
234 return 0;
235 }
236
237 void brcmf_feat_attach(struct brcmf_pub *drvr)
238 {
239 struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
240 struct brcmf_pno_macaddr_le pfn_mac;
241 struct brcmf_gscan_config gscan_cfg;
242 u32 wowl_cap;
243 s32 err;
244
245 brcmf_feat_firmware_capabilities(ifp);
246 memset(&gscan_cfg, 0, sizeof(gscan_cfg));
247 if (drvr->bus_if->chip != BRCM_CC_43430_CHIP_ID &&
248 drvr->bus_if->chip != BRCM_CC_4345_CHIP_ID)
249 brcmf_feat_iovar_data_set(ifp, BRCMF_FEAT_GSCAN,
250 "pfn_gscan_cfg",
251 &gscan_cfg, sizeof(gscan_cfg));
252 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
253 if (drvr->bus_if->wowl_supported)
254 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
255 if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) {
256 err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap);
257 if (!err) {
258 ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_WOWL_ARP_ND);
259 if (wowl_cap & BRCMF_WOWL_PFN_FOUND)
260 ifp->drvr->feat_flags |=
261 BIT(BRCMF_FEAT_WOWL_ND);
262 if (wowl_cap & BRCMF_WOWL_GTK_FAILURE)
263 ifp->drvr->feat_flags |=
264 BIT(BRCMF_FEAT_WOWL_GTK);
265 }
266 }
267
268 switch (drvr->bus_if->chip) {
269 case BRCM_CC_4330_CHIP_ID:
270 case BRCM_CC_43362_CHIP_ID:
271 ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS);
272 break;
273 default:
274 break;
275 }
276 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode");
277 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable");
278 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MFP, "mfp");
279
280 pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
281 err = brcmf_fil_iovar_data_get(ifp, "pfn_macaddr", &pfn_mac,
282 sizeof(pfn_mac));
283 if (!err)
284 ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_SCAN_RANDOM_MAC);
285
286 if (drvr->settings->feature_disable) {
287 brcmf_dbg(INFO, "Features: 0x%02x, disable: 0x%02x\n",
288 ifp->drvr->feat_flags,
289 drvr->settings->feature_disable);
290 ifp->drvr->feat_flags &= ~drvr->settings->feature_disable;
291 }
292 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_FWSUP, "sup_wpa");
293
294 brcmf_feat_firmware_overrides(drvr);
295
296
297 switch (drvr->bus_if->chip) {
298 case BRCM_CC_43236_CHIP_ID:
299 drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_AUTO_AUTH);
300 break;
301 case BRCM_CC_4329_CHIP_ID:
302 drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_NEED_MPC);
303 break;
304 default:
305
306 break;
307 }
308 }
309
310 void brcmf_feat_debugfs_create(struct brcmf_pub *drvr)
311 {
312 brcmf_debugfs_add_entry(drvr, "features", brcmf_feat_debugfs_read);
313 brcmf_debugfs_add_entry(drvr, "fwcap", brcmf_feat_fwcap_debugfs_read);
314 }
315
316 bool brcmf_feat_is_enabled(struct brcmf_if *ifp, enum brcmf_feat_id id)
317 {
318 return (ifp->drvr->feat_flags & BIT(id));
319 }
320
321 bool brcmf_feat_is_quirk_enabled(struct brcmf_if *ifp,
322 enum brcmf_feat_quirk quirk)
323 {
324 return (ifp->drvr->chip_quirks & BIT(quirk));
325 }