diff options
Diffstat (limited to 'drivers/net/wireless/wl12xx/init.c')
-rw-r--r-- | drivers/net/wireless/wl12xx/init.c | 387 |
1 files changed, 316 insertions, 71 deletions
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c index 785a5304bfc4..70b3dc88a219 100644 --- a/drivers/net/wireless/wl12xx/init.c +++ b/drivers/net/wireless/wl12xx/init.c | |||
@@ -30,27 +30,9 @@ | |||
30 | #include "acx.h" | 30 | #include "acx.h" |
31 | #include "cmd.h" | 31 | #include "cmd.h" |
32 | #include "reg.h" | 32 | #include "reg.h" |
33 | #include "tx.h" | ||
33 | 34 | ||
34 | static int wl1271_init_hwenc_config(struct wl1271 *wl) | 35 | int wl1271_sta_init_templates_config(struct wl1271 *wl) |
35 | { | ||
36 | int ret; | ||
37 | |||
38 | ret = wl1271_acx_feature_cfg(wl); | ||
39 | if (ret < 0) { | ||
40 | wl1271_warning("couldn't set feature config"); | ||
41 | return ret; | ||
42 | } | ||
43 | |||
44 | ret = wl1271_cmd_set_default_wep_key(wl, wl->default_key); | ||
45 | if (ret < 0) { | ||
46 | wl1271_warning("couldn't set default key"); | ||
47 | return ret; | ||
48 | } | ||
49 | |||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | int wl1271_init_templates_config(struct wl1271 *wl) | ||
54 | { | 36 | { |
55 | int ret, i; | 37 | int ret, i; |
56 | 38 | ||
@@ -118,6 +100,132 @@ int wl1271_init_templates_config(struct wl1271 *wl) | |||
118 | return 0; | 100 | return 0; |
119 | } | 101 | } |
120 | 102 | ||
103 | static int wl1271_ap_init_deauth_template(struct wl1271 *wl) | ||
104 | { | ||
105 | struct wl12xx_disconn_template *tmpl; | ||
106 | int ret; | ||
107 | |||
108 | tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL); | ||
109 | if (!tmpl) { | ||
110 | ret = -ENOMEM; | ||
111 | goto out; | ||
112 | } | ||
113 | |||
114 | tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
115 | IEEE80211_STYPE_DEAUTH); | ||
116 | |||
117 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, | ||
118 | tmpl, sizeof(*tmpl), 0, | ||
119 | wl1271_tx_min_rate_get(wl)); | ||
120 | |||
121 | out: | ||
122 | kfree(tmpl); | ||
123 | return ret; | ||
124 | } | ||
125 | |||
126 | static int wl1271_ap_init_null_template(struct wl1271 *wl) | ||
127 | { | ||
128 | struct ieee80211_hdr_3addr *nullfunc; | ||
129 | int ret; | ||
130 | |||
131 | nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL); | ||
132 | if (!nullfunc) { | ||
133 | ret = -ENOMEM; | ||
134 | goto out; | ||
135 | } | ||
136 | |||
137 | nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
138 | IEEE80211_STYPE_NULLFUNC | | ||
139 | IEEE80211_FCTL_FROMDS); | ||
140 | |||
141 | /* nullfunc->addr1 is filled by FW */ | ||
142 | |||
143 | memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN); | ||
144 | memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN); | ||
145 | |||
146 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc, | ||
147 | sizeof(*nullfunc), 0, | ||
148 | wl1271_tx_min_rate_get(wl)); | ||
149 | |||
150 | out: | ||
151 | kfree(nullfunc); | ||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | static int wl1271_ap_init_qos_null_template(struct wl1271 *wl) | ||
156 | { | ||
157 | struct ieee80211_qos_hdr *qosnull; | ||
158 | int ret; | ||
159 | |||
160 | qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL); | ||
161 | if (!qosnull) { | ||
162 | ret = -ENOMEM; | ||
163 | goto out; | ||
164 | } | ||
165 | |||
166 | qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | ||
167 | IEEE80211_STYPE_QOS_NULLFUNC | | ||
168 | IEEE80211_FCTL_FROMDS); | ||
169 | |||
170 | /* qosnull->addr1 is filled by FW */ | ||
171 | |||
172 | memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN); | ||
173 | memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN); | ||
174 | |||
175 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull, | ||
176 | sizeof(*qosnull), 0, | ||
177 | wl1271_tx_min_rate_get(wl)); | ||
178 | |||
179 | out: | ||
180 | kfree(qosnull); | ||
181 | return ret; | ||
182 | } | ||
183 | |||
184 | static int wl1271_ap_init_templates_config(struct wl1271 *wl) | ||
185 | { | ||
186 | int ret; | ||
187 | |||
188 | /* | ||
189 | * Put very large empty placeholders for all templates. These | ||
190 | * reserve memory for later. | ||
191 | */ | ||
192 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL, | ||
193 | sizeof | ||
194 | (struct wl12xx_probe_resp_template), | ||
195 | 0, WL1271_RATE_AUTOMATIC); | ||
196 | if (ret < 0) | ||
197 | return ret; | ||
198 | |||
199 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL, | ||
200 | sizeof | ||
201 | (struct wl12xx_beacon_template), | ||
202 | 0, WL1271_RATE_AUTOMATIC); | ||
203 | if (ret < 0) | ||
204 | return ret; | ||
205 | |||
206 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, NULL, | ||
207 | sizeof | ||
208 | (struct wl12xx_disconn_template), | ||
209 | 0, WL1271_RATE_AUTOMATIC); | ||
210 | if (ret < 0) | ||
211 | return ret; | ||
212 | |||
213 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, | ||
214 | sizeof(struct wl12xx_null_data_template), | ||
215 | 0, WL1271_RATE_AUTOMATIC); | ||
216 | if (ret < 0) | ||
217 | return ret; | ||
218 | |||
219 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, | ||
220 | sizeof | ||
221 | (struct wl12xx_qos_null_data_template), | ||
222 | 0, WL1271_RATE_AUTOMATIC); | ||
223 | if (ret < 0) | ||
224 | return ret; | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
121 | static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) | 229 | static int wl1271_init_rx_config(struct wl1271 *wl, u32 config, u32 filter) |
122 | { | 230 | { |
123 | int ret; | 231 | int ret; |
@@ -145,10 +253,6 @@ int wl1271_init_phy_config(struct wl1271 *wl) | |||
145 | if (ret < 0) | 253 | if (ret < 0) |
146 | return ret; | 254 | return ret; |
147 | 255 | ||
148 | ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0); | ||
149 | if (ret < 0) | ||
150 | return ret; | ||
151 | |||
152 | ret = wl1271_acx_service_period_timeout(wl); | 256 | ret = wl1271_acx_service_period_timeout(wl); |
153 | if (ret < 0) | 257 | if (ret < 0) |
154 | return ret; | 258 | return ret; |
@@ -213,11 +317,186 @@ static int wl1271_init_beacon_broadcast(struct wl1271 *wl) | |||
213 | return 0; | 317 | return 0; |
214 | } | 318 | } |
215 | 319 | ||
320 | static int wl1271_sta_hw_init(struct wl1271 *wl) | ||
321 | { | ||
322 | int ret; | ||
323 | |||
324 | ret = wl1271_cmd_ext_radio_parms(wl); | ||
325 | if (ret < 0) | ||
326 | return ret; | ||
327 | |||
328 | ret = wl1271_sta_init_templates_config(wl); | ||
329 | if (ret < 0) | ||
330 | return ret; | ||
331 | |||
332 | ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0); | ||
333 | if (ret < 0) | ||
334 | return ret; | ||
335 | |||
336 | /* Initialize connection monitoring thresholds */ | ||
337 | ret = wl1271_acx_conn_monit_params(wl, false); | ||
338 | if (ret < 0) | ||
339 | return ret; | ||
340 | |||
341 | /* Beacon filtering */ | ||
342 | ret = wl1271_init_beacon_filter(wl); | ||
343 | if (ret < 0) | ||
344 | return ret; | ||
345 | |||
346 | /* Bluetooth WLAN coexistence */ | ||
347 | ret = wl1271_init_pta(wl); | ||
348 | if (ret < 0) | ||
349 | return ret; | ||
350 | |||
351 | /* Beacons and broadcast settings */ | ||
352 | ret = wl1271_init_beacon_broadcast(wl); | ||
353 | if (ret < 0) | ||
354 | return ret; | ||
355 | |||
356 | /* Configure for ELP power saving */ | ||
357 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); | ||
358 | if (ret < 0) | ||
359 | return ret; | ||
360 | |||
361 | /* Configure rssi/snr averaging weights */ | ||
362 | ret = wl1271_acx_rssi_snr_avg_weights(wl); | ||
363 | if (ret < 0) | ||
364 | return ret; | ||
365 | |||
366 | ret = wl1271_acx_sta_rate_policies(wl); | ||
367 | if (ret < 0) | ||
368 | return ret; | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl) | ||
374 | { | ||
375 | int ret, i; | ||
376 | |||
377 | ret = wl1271_cmd_set_sta_default_wep_key(wl, wl->default_key); | ||
378 | if (ret < 0) { | ||
379 | wl1271_warning("couldn't set default key"); | ||
380 | return ret; | ||
381 | } | ||
382 | |||
383 | /* disable all keep-alive templates */ | ||
384 | for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { | ||
385 | ret = wl1271_acx_keep_alive_config(wl, i, | ||
386 | ACX_KEEP_ALIVE_TPL_INVALID); | ||
387 | if (ret < 0) | ||
388 | return ret; | ||
389 | } | ||
390 | |||
391 | /* disable the keep-alive feature */ | ||
392 | ret = wl1271_acx_keep_alive_mode(wl, false); | ||
393 | if (ret < 0) | ||
394 | return ret; | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static int wl1271_ap_hw_init(struct wl1271 *wl) | ||
400 | { | ||
401 | int ret, i; | ||
402 | |||
403 | ret = wl1271_ap_init_templates_config(wl); | ||
404 | if (ret < 0) | ||
405 | return ret; | ||
406 | |||
407 | /* Configure for power always on */ | ||
408 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); | ||
409 | if (ret < 0) | ||
410 | return ret; | ||
411 | |||
412 | /* Configure initial TX rate classes */ | ||
413 | for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { | ||
414 | ret = wl1271_acx_ap_rate_policy(wl, | ||
415 | &wl->conf.tx.ap_rc_conf[i], i); | ||
416 | if (ret < 0) | ||
417 | return ret; | ||
418 | } | ||
419 | |||
420 | ret = wl1271_acx_ap_rate_policy(wl, | ||
421 | &wl->conf.tx.ap_mgmt_conf, | ||
422 | ACX_TX_AP_MODE_MGMT_RATE); | ||
423 | if (ret < 0) | ||
424 | return ret; | ||
425 | |||
426 | ret = wl1271_acx_ap_rate_policy(wl, | ||
427 | &wl->conf.tx.ap_bcst_conf, | ||
428 | ACX_TX_AP_MODE_BCST_RATE); | ||
429 | if (ret < 0) | ||
430 | return ret; | ||
431 | |||
432 | ret = wl1271_acx_max_tx_retry(wl); | ||
433 | if (ret < 0) | ||
434 | return ret; | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl) | ||
440 | { | ||
441 | int ret; | ||
442 | |||
443 | ret = wl1271_ap_init_deauth_template(wl); | ||
444 | if (ret < 0) | ||
445 | return ret; | ||
446 | |||
447 | ret = wl1271_ap_init_null_template(wl); | ||
448 | if (ret < 0) | ||
449 | return ret; | ||
450 | |||
451 | ret = wl1271_ap_init_qos_null_template(wl); | ||
452 | if (ret < 0) | ||
453 | return ret; | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | static void wl1271_check_ba_support(struct wl1271 *wl) | ||
459 | { | ||
460 | /* validate FW cose ver x.x.x.50-60.x */ | ||
461 | if ((wl->chip.fw_ver[3] >= WL12XX_BA_SUPPORT_FW_COST_VER2_START) && | ||
462 | (wl->chip.fw_ver[3] < WL12XX_BA_SUPPORT_FW_COST_VER2_END)) { | ||
463 | wl->ba_support = true; | ||
464 | return; | ||
465 | } | ||
466 | |||
467 | wl->ba_support = false; | ||
468 | } | ||
469 | |||
470 | static int wl1271_set_ba_policies(struct wl1271 *wl) | ||
471 | { | ||
472 | u8 tid_index; | ||
473 | u8 ret = 0; | ||
474 | |||
475 | /* Reset the BA RX indicators */ | ||
476 | wl->ba_rx_bitmap = 0; | ||
477 | |||
478 | /* validate that FW support BA */ | ||
479 | wl1271_check_ba_support(wl); | ||
480 | |||
481 | if (wl->ba_support) | ||
482 | /* 802.11n initiator BA session setting */ | ||
483 | for (tid_index = 0; tid_index < CONF_TX_MAX_TID_COUNT; | ||
484 | ++tid_index) { | ||
485 | ret = wl1271_acx_set_ba_session(wl, WLAN_BACK_INITIATOR, | ||
486 | tid_index, true); | ||
487 | if (ret < 0) | ||
488 | break; | ||
489 | } | ||
490 | |||
491 | return ret; | ||
492 | } | ||
493 | |||
216 | int wl1271_hw_init(struct wl1271 *wl) | 494 | int wl1271_hw_init(struct wl1271 *wl) |
217 | { | 495 | { |
218 | struct conf_tx_ac_category *conf_ac; | 496 | struct conf_tx_ac_category *conf_ac; |
219 | struct conf_tx_tid *conf_tid; | 497 | struct conf_tx_tid *conf_tid; |
220 | int ret, i; | 498 | int ret, i; |
499 | bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); | ||
221 | 500 | ||
222 | ret = wl1271_cmd_general_parms(wl); | 501 | ret = wl1271_cmd_general_parms(wl); |
223 | if (ret < 0) | 502 | if (ret < 0) |
@@ -227,12 +506,12 @@ int wl1271_hw_init(struct wl1271 *wl) | |||
227 | if (ret < 0) | 506 | if (ret < 0) |
228 | return ret; | 507 | return ret; |
229 | 508 | ||
230 | ret = wl1271_cmd_ext_radio_parms(wl); | 509 | /* Mode specific init */ |
231 | if (ret < 0) | 510 | if (is_ap) |
232 | return ret; | 511 | ret = wl1271_ap_hw_init(wl); |
512 | else | ||
513 | ret = wl1271_sta_hw_init(wl); | ||
233 | 514 | ||
234 | /* Template settings */ | ||
235 | ret = wl1271_init_templates_config(wl); | ||
236 | if (ret < 0) | 515 | if (ret < 0) |
237 | return ret; | 516 | return ret; |
238 | 517 | ||
@@ -259,16 +538,6 @@ int wl1271_hw_init(struct wl1271 *wl) | |||
259 | if (ret < 0) | 538 | if (ret < 0) |
260 | goto out_free_memmap; | 539 | goto out_free_memmap; |
261 | 540 | ||
262 | /* Initialize connection monitoring thresholds */ | ||
263 | ret = wl1271_acx_conn_monit_params(wl, false); | ||
264 | if (ret < 0) | ||
265 | goto out_free_memmap; | ||
266 | |||
267 | /* Beacon filtering */ | ||
268 | ret = wl1271_init_beacon_filter(wl); | ||
269 | if (ret < 0) | ||
270 | goto out_free_memmap; | ||
271 | |||
272 | /* Configure TX patch complete interrupt behavior */ | 541 | /* Configure TX patch complete interrupt behavior */ |
273 | ret = wl1271_acx_tx_config_options(wl); | 542 | ret = wl1271_acx_tx_config_options(wl); |
274 | if (ret < 0) | 543 | if (ret < 0) |
@@ -279,21 +548,11 @@ int wl1271_hw_init(struct wl1271 *wl) | |||
279 | if (ret < 0) | 548 | if (ret < 0) |
280 | goto out_free_memmap; | 549 | goto out_free_memmap; |
281 | 550 | ||
282 | /* Bluetooth WLAN coexistence */ | ||
283 | ret = wl1271_init_pta(wl); | ||
284 | if (ret < 0) | ||
285 | goto out_free_memmap; | ||
286 | |||
287 | /* Energy detection */ | 551 | /* Energy detection */ |
288 | ret = wl1271_init_energy_detection(wl); | 552 | ret = wl1271_init_energy_detection(wl); |
289 | if (ret < 0) | 553 | if (ret < 0) |
290 | goto out_free_memmap; | 554 | goto out_free_memmap; |
291 | 555 | ||
292 | /* Beacons and boradcast settings */ | ||
293 | ret = wl1271_init_beacon_broadcast(wl); | ||
294 | if (ret < 0) | ||
295 | goto out_free_memmap; | ||
296 | |||
297 | /* Default fragmentation threshold */ | 556 | /* Default fragmentation threshold */ |
298 | ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold); | 557 | ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold); |
299 | if (ret < 0) | 558 | if (ret < 0) |
@@ -321,23 +580,13 @@ int wl1271_hw_init(struct wl1271 *wl) | |||
321 | goto out_free_memmap; | 580 | goto out_free_memmap; |
322 | } | 581 | } |
323 | 582 | ||
324 | /* Configure TX rate classes */ | ||
325 | ret = wl1271_acx_rate_policies(wl); | ||
326 | if (ret < 0) | ||
327 | goto out_free_memmap; | ||
328 | |||
329 | /* Enable data path */ | 583 | /* Enable data path */ |
330 | ret = wl1271_cmd_data_path(wl, 1); | 584 | ret = wl1271_cmd_data_path(wl, 1); |
331 | if (ret < 0) | 585 | if (ret < 0) |
332 | goto out_free_memmap; | 586 | goto out_free_memmap; |
333 | 587 | ||
334 | /* Configure for ELP power saving */ | ||
335 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); | ||
336 | if (ret < 0) | ||
337 | goto out_free_memmap; | ||
338 | |||
339 | /* Configure HW encryption */ | 588 | /* Configure HW encryption */ |
340 | ret = wl1271_init_hwenc_config(wl); | 589 | ret = wl1271_acx_feature_cfg(wl); |
341 | if (ret < 0) | 590 | if (ret < 0) |
342 | goto out_free_memmap; | 591 | goto out_free_memmap; |
343 | 592 | ||
@@ -346,21 +595,17 @@ int wl1271_hw_init(struct wl1271 *wl) | |||
346 | if (ret < 0) | 595 | if (ret < 0) |
347 | goto out_free_memmap; | 596 | goto out_free_memmap; |
348 | 597 | ||
349 | /* disable all keep-alive templates */ | 598 | /* Mode specific init - post mem init */ |
350 | for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { | 599 | if (is_ap) |
351 | ret = wl1271_acx_keep_alive_config(wl, i, | 600 | ret = wl1271_ap_hw_init_post_mem(wl); |
352 | ACX_KEEP_ALIVE_TPL_INVALID); | 601 | else |
353 | if (ret < 0) | 602 | ret = wl1271_sta_hw_init_post_mem(wl); |
354 | goto out_free_memmap; | ||
355 | } | ||
356 | 603 | ||
357 | /* disable the keep-alive feature */ | ||
358 | ret = wl1271_acx_keep_alive_mode(wl, false); | ||
359 | if (ret < 0) | 604 | if (ret < 0) |
360 | goto out_free_memmap; | 605 | goto out_free_memmap; |
361 | 606 | ||
362 | /* Configure rssi/snr averaging weights */ | 607 | /* Configure initiator BA sessions policies */ |
363 | ret = wl1271_acx_rssi_snr_avg_weights(wl); | 608 | ret = wl1271_set_ba_policies(wl); |
364 | if (ret < 0) | 609 | if (ret < 0) |
365 | goto out_free_memmap; | 610 | goto out_free_memmap; |
366 | 611 | ||