Commit | Line | Data |
---|---|---|
f5fc0f86 LC |
1 | /* |
2 | * This file is part of wl1271 | |
3 | * | |
4 | * Copyright (C) 2009 Nokia Corporation | |
5 | * | |
6 | * Contact: Luciano Coelho <luciano.coelho@nokia.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License | |
10 | * version 2 as published by the Free Software Foundation. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program; if not, write to the Free Software | |
19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
20 | * 02110-1301 USA | |
21 | * | |
22 | */ | |
23 | ||
24 | #include <linux/kernel.h> | |
25 | #include <linux/module.h> | |
5a0e3ad6 | 26 | #include <linux/slab.h> |
f5fc0f86 | 27 | |
00d20100 | 28 | #include "init.h" |
f5fc0f86 | 29 | #include "wl12xx_80211.h" |
00d20100 SL |
30 | #include "acx.h" |
31 | #include "cmd.h" | |
32 | #include "reg.h" | |
e0fe371b | 33 | #include "tx.h" |
48a61477 | 34 | #include "io.h" |
f5fc0f86 | 35 | |
e0fe371b | 36 | int wl1271_sta_init_templates_config(struct wl1271 *wl) |
f5fc0f86 | 37 | { |
bfb24c9e | 38 | int ret, i; |
f5fc0f86 LC |
39 | |
40 | /* send empty templates for fw memory reservation */ | |
41 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL, | |
154037d1 | 42 | WL1271_CMD_TEMPL_DFLT_SIZE, |
606c1487 | 43 | 0, WL1271_RATE_AUTOMATIC); |
f5fc0f86 LC |
44 | if (ret < 0) |
45 | return ret; | |
46 | ||
11eb5429 | 47 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, |
154037d1 | 48 | NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0, |
11eb5429 JO |
49 | WL1271_RATE_AUTOMATIC); |
50 | if (ret < 0) | |
51 | return ret; | |
abb0b3bf | 52 | |
f5fc0f86 | 53 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL, |
bfb24c9e | 54 | sizeof(struct wl12xx_null_data_template), |
606c1487 | 55 | 0, WL1271_RATE_AUTOMATIC); |
f5fc0f86 LC |
56 | if (ret < 0) |
57 | return ret; | |
58 | ||
59 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL, | |
bfb24c9e | 60 | sizeof(struct wl12xx_ps_poll_template), |
606c1487 | 61 | 0, WL1271_RATE_AUTOMATIC); |
f5fc0f86 LC |
62 | if (ret < 0) |
63 | return ret; | |
64 | ||
65 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL, | |
66 | sizeof | |
bfb24c9e | 67 | (struct wl12xx_qos_null_data_template), |
606c1487 | 68 | 0, WL1271_RATE_AUTOMATIC); |
f5fc0f86 LC |
69 | if (ret < 0) |
70 | return ret; | |
71 | ||
72 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL, | |
154037d1 | 73 | WL1271_CMD_TEMPL_DFLT_SIZE, |
606c1487 | 74 | 0, WL1271_RATE_AUTOMATIC); |
f5fc0f86 LC |
75 | if (ret < 0) |
76 | return ret; | |
77 | ||
78 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL, | |
154037d1 | 79 | WL1271_CMD_TEMPL_DFLT_SIZE, |
606c1487 | 80 | 0, WL1271_RATE_AUTOMATIC); |
f5fc0f86 LC |
81 | if (ret < 0) |
82 | return ret; | |
83 | ||
c5312772 EP |
84 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL, |
85 | sizeof | |
86 | (struct wl12xx_arp_rsp_template), | |
87 | 0, WL1271_RATE_AUTOMATIC); | |
88 | if (ret < 0) | |
89 | return ret; | |
90 | ||
bfb24c9e JO |
91 | for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { |
92 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL, | |
154037d1 | 93 | WL1271_CMD_TEMPL_DFLT_SIZE, i, |
606c1487 | 94 | WL1271_RATE_AUTOMATIC); |
bfb24c9e JO |
95 | if (ret < 0) |
96 | return ret; | |
97 | } | |
98 | ||
f5fc0f86 LC |
99 | return 0; |
100 | } | |
101 | ||
e0fe371b AN |
102 | static int wl1271_ap_init_deauth_template(struct wl1271 *wl) |
103 | { | |
104 | struct wl12xx_disconn_template *tmpl; | |
105 | int ret; | |
af7fbb28 | 106 | u32 rate; |
e0fe371b AN |
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 | ||
af7fbb28 | 117 | rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); |
e0fe371b | 118 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, |
af7fbb28 | 119 | tmpl, sizeof(*tmpl), 0, rate); |
e0fe371b AN |
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; | |
af7fbb28 | 130 | u32 rate; |
e0fe371b AN |
131 | |
132 | nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL); | |
133 | if (!nullfunc) { | |
134 | ret = -ENOMEM; | |
135 | goto out; | |
136 | } | |
137 | ||
138 | nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | |
139 | IEEE80211_STYPE_NULLFUNC | | |
140 | IEEE80211_FCTL_FROMDS); | |
141 | ||
142 | /* nullfunc->addr1 is filled by FW */ | |
143 | ||
144 | memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN); | |
145 | memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN); | |
146 | ||
af7fbb28 | 147 | rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); |
e0fe371b | 148 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc, |
af7fbb28 | 149 | sizeof(*nullfunc), 0, rate); |
e0fe371b AN |
150 | |
151 | out: | |
152 | kfree(nullfunc); | |
153 | return ret; | |
154 | } | |
155 | ||
156 | static int wl1271_ap_init_qos_null_template(struct wl1271 *wl) | |
157 | { | |
158 | struct ieee80211_qos_hdr *qosnull; | |
159 | int ret; | |
af7fbb28 | 160 | u32 rate; |
e0fe371b AN |
161 | |
162 | qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL); | |
163 | if (!qosnull) { | |
164 | ret = -ENOMEM; | |
165 | goto out; | |
166 | } | |
167 | ||
168 | qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | | |
169 | IEEE80211_STYPE_QOS_NULLFUNC | | |
170 | IEEE80211_FCTL_FROMDS); | |
171 | ||
172 | /* qosnull->addr1 is filled by FW */ | |
173 | ||
174 | memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN); | |
175 | memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN); | |
176 | ||
af7fbb28 | 177 | rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); |
e0fe371b | 178 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull, |
af7fbb28 | 179 | sizeof(*qosnull), 0, rate); |
e0fe371b AN |
180 | |
181 | out: | |
182 | kfree(qosnull); | |
183 | return ret; | |
184 | } | |
185 | ||
186 | static int wl1271_ap_init_templates_config(struct wl1271 *wl) | |
187 | { | |
188 | int ret; | |
189 | ||
190 | /* | |
191 | * Put very large empty placeholders for all templates. These | |
192 | * reserve memory for later. | |
193 | */ | |
194 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL, | |
154037d1 | 195 | WL1271_CMD_TEMPL_MAX_SIZE, |
e0fe371b AN |
196 | 0, WL1271_RATE_AUTOMATIC); |
197 | if (ret < 0) | |
198 | return ret; | |
199 | ||
200 | ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL, | |
154037d1 | 201 | WL1271_CMD_TEMPL_MAX_SIZE, |
e0fe371b AN |
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 | ||
08c1d1c7 | 229 | static int wl12xx_init_rx_config(struct wl1271 *wl) |
f5fc0f86 LC |
230 | { |
231 | int ret; | |
232 | ||
8793f9bb | 233 | ret = wl1271_acx_rx_msdu_life_time(wl); |
f5fc0f86 LC |
234 | if (ret < 0) |
235 | return ret; | |
236 | ||
f5fc0f86 LC |
237 | return 0; |
238 | } | |
239 | ||
12419cce | 240 | int wl1271_init_phy_config(struct wl1271 *wl) |
f5fc0f86 LC |
241 | { |
242 | int ret; | |
243 | ||
244 | ret = wl1271_acx_pd_threshold(wl); | |
245 | if (ret < 0) | |
246 | return ret; | |
247 | ||
248 | ret = wl1271_acx_slot(wl, DEFAULT_SLOT_TIME); | |
249 | if (ret < 0) | |
250 | return ret; | |
251 | ||
f5fc0f86 LC |
252 | ret = wl1271_acx_service_period_timeout(wl); |
253 | if (ret < 0) | |
254 | return ret; | |
255 | ||
5f704d18 | 256 | ret = wl1271_acx_rts_threshold(wl, wl->hw->wiphy->rts_threshold); |
f5fc0f86 LC |
257 | if (ret < 0) |
258 | return ret; | |
259 | ||
260 | return 0; | |
261 | } | |
262 | ||
263 | static int wl1271_init_beacon_filter(struct wl1271 *wl) | |
264 | { | |
265 | int ret; | |
266 | ||
1922167b JO |
267 | /* disable beacon filtering at this stage */ |
268 | ret = wl1271_acx_beacon_filter_opt(wl, false); | |
f5fc0f86 LC |
269 | if (ret < 0) |
270 | return ret; | |
271 | ||
272 | ret = wl1271_acx_beacon_filter_table(wl); | |
273 | if (ret < 0) | |
274 | return ret; | |
275 | ||
276 | return 0; | |
277 | } | |
278 | ||
12419cce | 279 | int wl1271_init_pta(struct wl1271 *wl) |
f5fc0f86 LC |
280 | { |
281 | int ret; | |
282 | ||
3be4112c | 283 | ret = wl12xx_acx_sg_cfg(wl); |
f5fc0f86 LC |
284 | if (ret < 0) |
285 | return ret; | |
286 | ||
7fc3a864 | 287 | ret = wl1271_acx_sg_enable(wl, wl->sg_enabled); |
f5fc0f86 LC |
288 | if (ret < 0) |
289 | return ret; | |
290 | ||
291 | return 0; | |
292 | } | |
293 | ||
12419cce | 294 | int wl1271_init_energy_detection(struct wl1271 *wl) |
f5fc0f86 LC |
295 | { |
296 | int ret; | |
297 | ||
298 | ret = wl1271_acx_cca_threshold(wl); | |
299 | if (ret < 0) | |
300 | return ret; | |
301 | ||
302 | return 0; | |
303 | } | |
304 | ||
305 | static int wl1271_init_beacon_broadcast(struct wl1271 *wl) | |
306 | { | |
307 | int ret; | |
308 | ||
309 | ret = wl1271_acx_bcn_dtim_options(wl); | |
310 | if (ret < 0) | |
311 | return ret; | |
312 | ||
313 | return 0; | |
314 | } | |
315 | ||
95dac04f IY |
316 | static int wl12xx_init_fwlog(struct wl1271 *wl) |
317 | { | |
318 | int ret; | |
319 | ||
320 | if (wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED) | |
321 | return 0; | |
322 | ||
323 | ret = wl12xx_cmd_config_fwlog(wl); | |
324 | if (ret < 0) | |
325 | return ret; | |
326 | ||
327 | return 0; | |
328 | } | |
329 | ||
e0fe371b AN |
330 | static int wl1271_sta_hw_init(struct wl1271 *wl) |
331 | { | |
332 | int ret; | |
333 | ||
49d750ca SL |
334 | if (wl->chip.id != CHIP_ID_1283_PG20) { |
335 | ret = wl1271_cmd_ext_radio_parms(wl); | |
336 | if (ret < 0) | |
337 | return ret; | |
338 | } | |
e0fe371b | 339 | |
c8bde243 EP |
340 | /* PS config */ |
341 | ret = wl1271_acx_config_ps(wl); | |
342 | if (ret < 0) | |
343 | return ret; | |
344 | ||
e0fe371b AN |
345 | ret = wl1271_sta_init_templates_config(wl); |
346 | if (ret < 0) | |
347 | return ret; | |
348 | ||
349 | ret = wl1271_acx_group_address_tbl(wl, true, NULL, 0); | |
350 | if (ret < 0) | |
351 | return ret; | |
352 | ||
353 | /* Initialize connection monitoring thresholds */ | |
354 | ret = wl1271_acx_conn_monit_params(wl, false); | |
355 | if (ret < 0) | |
356 | return ret; | |
357 | ||
358 | /* Beacon filtering */ | |
359 | ret = wl1271_init_beacon_filter(wl); | |
360 | if (ret < 0) | |
361 | return ret; | |
362 | ||
ff86843d SL |
363 | /* FM WLAN coexistence */ |
364 | ret = wl1271_acx_fm_coex(wl); | |
365 | if (ret < 0) | |
366 | return ret; | |
367 | ||
e0fe371b AN |
368 | /* Beacons and broadcast settings */ |
369 | ret = wl1271_init_beacon_broadcast(wl); | |
370 | if (ret < 0) | |
371 | return ret; | |
372 | ||
373 | /* Configure for ELP power saving */ | |
374 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); | |
375 | if (ret < 0) | |
376 | return ret; | |
377 | ||
378 | /* Configure rssi/snr averaging weights */ | |
379 | ret = wl1271_acx_rssi_snr_avg_weights(wl); | |
380 | if (ret < 0) | |
381 | return ret; | |
382 | ||
383 | ret = wl1271_acx_sta_rate_policies(wl); | |
384 | if (ret < 0) | |
385 | return ret; | |
386 | ||
7f097988 | 387 | ret = wl12xx_acx_mem_cfg(wl); |
c8bde243 EP |
388 | if (ret < 0) |
389 | return ret; | |
390 | ||
95dac04f IY |
391 | /* Configure the FW logger */ |
392 | ret = wl12xx_init_fwlog(wl); | |
393 | if (ret < 0) | |
394 | return ret; | |
395 | ||
e0fe371b AN |
396 | return 0; |
397 | } | |
398 | ||
399 | static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl) | |
400 | { | |
401 | int ret, i; | |
402 | ||
e0fe371b AN |
403 | /* disable all keep-alive templates */ |
404 | for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) { | |
405 | ret = wl1271_acx_keep_alive_config(wl, i, | |
406 | ACX_KEEP_ALIVE_TPL_INVALID); | |
407 | if (ret < 0) | |
408 | return ret; | |
409 | } | |
410 | ||
411 | /* disable the keep-alive feature */ | |
412 | ret = wl1271_acx_keep_alive_mode(wl, false); | |
413 | if (ret < 0) | |
414 | return ret; | |
415 | ||
416 | return 0; | |
417 | } | |
418 | ||
419 | static int wl1271_ap_hw_init(struct wl1271 *wl) | |
420 | { | |
70f47424 | 421 | int ret; |
e0fe371b AN |
422 | |
423 | ret = wl1271_ap_init_templates_config(wl); | |
424 | if (ret < 0) | |
425 | return ret; | |
426 | ||
427 | /* Configure for power always on */ | |
428 | ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); | |
429 | if (ret < 0) | |
430 | return ret; | |
431 | ||
70f47424 | 432 | ret = wl1271_init_ap_rates(wl); |
e0fe371b AN |
433 | if (ret < 0) |
434 | return ret; | |
435 | ||
3618f30f | 436 | ret = wl1271_acx_ap_max_tx_retry(wl); |
e0fe371b AN |
437 | if (ret < 0) |
438 | return ret; | |
439 | ||
7f097988 | 440 | ret = wl12xx_acx_mem_cfg(wl); |
c8bde243 EP |
441 | if (ret < 0) |
442 | return ret; | |
443 | ||
097f8821 AN |
444 | /* initialize Tx power */ |
445 | ret = wl1271_acx_tx_power(wl, wl->power_level); | |
446 | if (ret < 0) | |
447 | return ret; | |
448 | ||
e0fe371b AN |
449 | return 0; |
450 | } | |
451 | ||
c45a85b5 | 452 | int wl1271_ap_init_templates(struct wl1271 *wl) |
e0fe371b AN |
453 | { |
454 | int ret; | |
455 | ||
456 | ret = wl1271_ap_init_deauth_template(wl); | |
457 | if (ret < 0) | |
458 | return ret; | |
459 | ||
460 | ret = wl1271_ap_init_null_template(wl); | |
461 | if (ret < 0) | |
462 | return ret; | |
463 | ||
464 | ret = wl1271_ap_init_qos_null_template(wl); | |
465 | if (ret < 0) | |
466 | return ret; | |
467 | ||
521a4a23 AN |
468 | /* |
469 | * when operating as AP we want to receive external beacons for | |
470 | * configuring ERP protection. | |
471 | */ | |
f42bd2cb | 472 | ret = wl1271_acx_beacon_filter_opt(wl, false); |
521a4a23 AN |
473 | if (ret < 0) |
474 | return ret; | |
475 | ||
e0fe371b AN |
476 | return 0; |
477 | } | |
478 | ||
c45a85b5 AN |
479 | static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl) |
480 | { | |
481 | return wl1271_ap_init_templates(wl); | |
482 | } | |
483 | ||
70f47424 AN |
484 | int wl1271_init_ap_rates(struct wl1271 *wl) |
485 | { | |
486 | int i, ret; | |
487 | struct conf_tx_rate_class rc; | |
488 | u32 supported_rates; | |
489 | ||
490 | wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", wl->basic_rate_set); | |
491 | ||
492 | if (wl->basic_rate_set == 0) | |
493 | return -EINVAL; | |
494 | ||
495 | rc.enabled_rates = wl->basic_rate_set; | |
496 | rc.long_retry_limit = 10; | |
497 | rc.short_retry_limit = 10; | |
498 | rc.aflags = 0; | |
499 | ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_MGMT_RATE); | |
500 | if (ret < 0) | |
501 | return ret; | |
502 | ||
503 | /* use the min basic rate for AP broadcast/multicast */ | |
af7fbb28 | 504 | rc.enabled_rates = wl1271_tx_min_rate_get(wl, wl->basic_rate_set); |
70f47424 AN |
505 | rc.short_retry_limit = 10; |
506 | rc.long_retry_limit = 10; | |
507 | rc.aflags = 0; | |
508 | ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_BCST_RATE); | |
509 | if (ret < 0) | |
510 | return ret; | |
511 | ||
512 | /* | |
513 | * If the basic rates contain OFDM rates, use OFDM only | |
514 | * rates for unicast TX as well. Else use all supported rates. | |
515 | */ | |
516 | if ((wl->basic_rate_set & CONF_TX_OFDM_RATES)) | |
517 | supported_rates = CONF_TX_OFDM_RATES; | |
518 | else | |
519 | supported_rates = CONF_TX_AP_ENABLED_RATES; | |
520 | ||
1a8adb67 AN |
521 | /* unconditionally enable HT rates */ |
522 | supported_rates |= CONF_TX_MCS_RATES; | |
523 | ||
70f47424 AN |
524 | /* configure unicast TX rate classes */ |
525 | for (i = 0; i < wl->conf.tx.ac_conf_count; i++) { | |
526 | rc.enabled_rates = supported_rates; | |
527 | rc.short_retry_limit = 10; | |
528 | rc.long_retry_limit = 10; | |
529 | rc.aflags = 0; | |
530 | ret = wl1271_acx_ap_rate_policy(wl, &rc, i); | |
531 | if (ret < 0) | |
532 | return ret; | |
533 | } | |
534 | ||
535 | return 0; | |
536 | } | |
537 | ||
4b7fac77 LS |
538 | static int wl1271_set_ba_policies(struct wl1271 *wl) |
539 | { | |
4b7fac77 | 540 | /* Reset the BA RX indicators */ |
4b7fac77 | 541 | wl->ba_rx_bitmap = 0; |
70559a06 | 542 | wl->ba_allowed = true; |
0f9c8250 | 543 | wl->ba_rx_session_count = 0; |
4b7fac77 | 544 | |
0f9c8250 AN |
545 | /* BA is supported in STA/AP modes */ |
546 | if (wl->bss_type != BSS_TYPE_AP_BSS && | |
547 | wl->bss_type != BSS_TYPE_STA_BSS) { | |
548 | wl->ba_support = false; | |
549 | return 0; | |
550 | } | |
4b7fac77 | 551 | |
0f9c8250 | 552 | wl->ba_support = true; |
4b7fac77 | 553 | |
0f9c8250 AN |
554 | /* 802.11n initiator BA session setting */ |
555 | return wl12xx_acx_set_ba_initiator_policy(wl); | |
4b7fac77 LS |
556 | } |
557 | ||
48a61477 SL |
558 | int wl1271_chip_specific_init(struct wl1271 *wl) |
559 | { | |
560 | int ret = 0; | |
561 | ||
562 | if (wl->chip.id == CHIP_ID_1283_PG20) { | |
563 | u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE; | |
564 | ||
0da13da7 | 565 | if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT) |
48a61477 SL |
566 | /* Enable SDIO padding */ |
567 | host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK; | |
568 | ||
569 | /* Must be before wl1271_acx_init_mem_config() */ | |
570 | ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap); | |
571 | if (ret < 0) | |
572 | goto out; | |
573 | } | |
574 | out: | |
575 | return ret; | |
576 | } | |
577 | ||
578 | ||
f5fc0f86 LC |
579 | int wl1271_hw_init(struct wl1271 *wl) |
580 | { | |
243eeb51 | 581 | struct conf_tx_ac_category *conf_ac; |
f2054df5 | 582 | struct conf_tx_tid *conf_tid; |
243eeb51 | 583 | int ret, i; |
e0fe371b | 584 | bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); |
f5fc0f86 | 585 | |
49d750ca SL |
586 | if (wl->chip.id == CHIP_ID_1283_PG20) |
587 | ret = wl128x_cmd_general_parms(wl); | |
588 | else | |
589 | ret = wl1271_cmd_general_parms(wl); | |
4a90406b | 590 | if (ret < 0) |
f5fc0f86 LC |
591 | return ret; |
592 | ||
49d750ca SL |
593 | if (wl->chip.id == CHIP_ID_1283_PG20) |
594 | ret = wl128x_cmd_radio_parms(wl); | |
595 | else | |
596 | ret = wl1271_cmd_radio_parms(wl); | |
4a90406b | 597 | if (ret < 0) |
f5fc0f86 LC |
598 | return ret; |
599 | ||
48a61477 SL |
600 | /* Chip-specific init */ |
601 | ret = wl1271_chip_specific_init(wl); | |
602 | if (ret < 0) | |
603 | return ret; | |
604 | ||
e0fe371b AN |
605 | /* Mode specific init */ |
606 | if (is_ap) | |
607 | ret = wl1271_ap_hw_init(wl); | |
608 | else | |
609 | ret = wl1271_sta_hw_init(wl); | |
644a4860 | 610 | |
f5fc0f86 LC |
611 | if (ret < 0) |
612 | return ret; | |
613 | ||
801f870b AN |
614 | /* Bluetooth WLAN coexistence */ |
615 | ret = wl1271_init_pta(wl); | |
616 | if (ret < 0) | |
617 | return ret; | |
618 | ||
f5fc0f86 LC |
619 | /* Default memory configuration */ |
620 | ret = wl1271_acx_init_mem_config(wl); | |
621 | if (ret < 0) | |
622 | return ret; | |
623 | ||
624 | /* RX config */ | |
08c1d1c7 | 625 | ret = wl12xx_init_rx_config(wl); |
f5fc0f86 LC |
626 | if (ret < 0) |
627 | goto out_free_memmap; | |
628 | ||
629 | /* PHY layer config */ | |
630 | ret = wl1271_init_phy_config(wl); | |
631 | if (ret < 0) | |
632 | goto out_free_memmap; | |
633 | ||
6e92b416 LC |
634 | ret = wl1271_acx_dco_itrim_params(wl); |
635 | if (ret < 0) | |
636 | goto out_free_memmap; | |
637 | ||
f5fc0f86 LC |
638 | /* Configure TX patch complete interrupt behavior */ |
639 | ret = wl1271_acx_tx_config_options(wl); | |
640 | if (ret < 0) | |
641 | goto out_free_memmap; | |
642 | ||
643 | /* RX complete interrupt pacing */ | |
644 | ret = wl1271_acx_init_rx_interrupt(wl); | |
645 | if (ret < 0) | |
646 | goto out_free_memmap; | |
647 | ||
f5fc0f86 LC |
648 | /* Energy detection */ |
649 | ret = wl1271_init_energy_detection(wl); | |
650 | if (ret < 0) | |
651 | goto out_free_memmap; | |
652 | ||
f5fc0f86 | 653 | /* Default fragmentation threshold */ |
5f704d18 | 654 | ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold); |
f5fc0f86 LC |
655 | if (ret < 0) |
656 | goto out_free_memmap; | |
657 | ||
9987a9da JO |
658 | /* Default TID/AC configuration */ |
659 | BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count); | |
f2054df5 | 660 | for (i = 0; i < wl->conf.tx.tid_conf_count; i++) { |
9987a9da JO |
661 | conf_ac = &wl->conf.tx.ac_conf[i]; |
662 | ret = wl1271_acx_ac_cfg(wl, conf_ac->ac, conf_ac->cw_min, | |
663 | conf_ac->cw_max, conf_ac->aifsn, | |
664 | conf_ac->tx_op_limit); | |
665 | if (ret < 0) | |
666 | goto out_free_memmap; | |
667 | ||
f2054df5 KV |
668 | conf_tid = &wl->conf.tx.tid_conf[i]; |
669 | ret = wl1271_acx_tid_cfg(wl, conf_tid->queue_id, | |
670 | conf_tid->channel_type, | |
671 | conf_tid->tsid, | |
672 | conf_tid->ps_scheme, | |
673 | conf_tid->ack_policy, | |
674 | conf_tid->apsd_conf[0], | |
675 | conf_tid->apsd_conf[1]); | |
676 | if (ret < 0) | |
677 | goto out_free_memmap; | |
678 | } | |
f5fc0f86 | 679 | |
f5fc0f86 | 680 | /* Enable data path */ |
94210897 | 681 | ret = wl1271_cmd_data_path(wl, 1); |
f5fc0f86 LC |
682 | if (ret < 0) |
683 | goto out_free_memmap; | |
684 | ||
f5fc0f86 | 685 | /* Configure HW encryption */ |
e0fe371b | 686 | ret = wl1271_acx_feature_cfg(wl); |
f5fc0f86 LC |
687 | if (ret < 0) |
688 | goto out_free_memmap; | |
689 | ||
38ad2d87 JO |
690 | /* configure PM */ |
691 | ret = wl1271_acx_pm_config(wl); | |
692 | if (ret < 0) | |
693 | goto out_free_memmap; | |
694 | ||
e0fe371b AN |
695 | /* Mode specific init - post mem init */ |
696 | if (is_ap) | |
697 | ret = wl1271_ap_hw_init_post_mem(wl); | |
698 | else | |
699 | ret = wl1271_sta_hw_init_post_mem(wl); | |
c1899554 | 700 | |
00236aed JO |
701 | if (ret < 0) |
702 | goto out_free_memmap; | |
703 | ||
fa6ad9f0 EP |
704 | ret = wl12xx_acx_set_rate_mgmt_params(wl); |
705 | if (ret < 0) | |
706 | goto out_free_memmap; | |
707 | ||
4b7fac77 LS |
708 | /* Configure initiator BA sessions policies */ |
709 | ret = wl1271_set_ba_policies(wl); | |
710 | if (ret < 0) | |
711 | goto out_free_memmap; | |
712 | ||
9487775c EP |
713 | /* configure hangover */ |
714 | ret = wl12xx_acx_config_hangover(wl); | |
715 | if (ret < 0) | |
716 | goto out_free_memmap; | |
717 | ||
f5fc0f86 LC |
718 | return 0; |
719 | ||
720 | out_free_memmap: | |
721 | kfree(wl->target_mem_map); | |
34415236 | 722 | wl->target_mem_map = NULL; |
f5fc0f86 LC |
723 | |
724 | return ret; | |
725 | } |