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>
26 #include <linux/slab.h>
27 
28 #include "debug.h"
29 #include "init.h"
30 #include "wl12xx_80211.h"
31 #include "acx.h"
32 #include "cmd.h"
33 #include "reg.h"
34 #include "tx.h"
35 #include "io.h"
36 
wl1271_init_templates_config(struct wl1271 * wl)37 int wl1271_init_templates_config(struct wl1271 *wl)
38 {
39 	int ret, i;
40 
41 	/* send empty templates for fw memory reservation */
42 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, NULL,
43 				      WL1271_CMD_TEMPL_DFLT_SIZE,
44 				      0, WL1271_RATE_AUTOMATIC);
45 	if (ret < 0)
46 		return ret;
47 
48 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
49 				      NULL, WL1271_CMD_TEMPL_DFLT_SIZE, 0,
50 				      WL1271_RATE_AUTOMATIC);
51 	if (ret < 0)
52 		return ret;
53 
54 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, NULL,
55 				      sizeof(struct wl12xx_null_data_template),
56 				      0, WL1271_RATE_AUTOMATIC);
57 	if (ret < 0)
58 		return ret;
59 
60 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, NULL,
61 				      sizeof(struct wl12xx_ps_poll_template),
62 				      0, WL1271_RATE_AUTOMATIC);
63 	if (ret < 0)
64 		return ret;
65 
66 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, NULL,
67 				      sizeof
68 				      (struct ieee80211_qos_hdr),
69 				      0, WL1271_RATE_AUTOMATIC);
70 	if (ret < 0)
71 		return ret;
72 
73 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PROBE_RESPONSE, NULL,
74 				      WL1271_CMD_TEMPL_DFLT_SIZE,
75 				      0, WL1271_RATE_AUTOMATIC);
76 	if (ret < 0)
77 		return ret;
78 
79 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_BEACON, NULL,
80 				      WL1271_CMD_TEMPL_DFLT_SIZE,
81 				      0, WL1271_RATE_AUTOMATIC);
82 	if (ret < 0)
83 		return ret;
84 
85 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP, NULL,
86 				      sizeof
87 				      (struct wl12xx_arp_rsp_template),
88 				      0, WL1271_RATE_AUTOMATIC);
89 	if (ret < 0)
90 		return ret;
91 
92 	/*
93 	 * Put very large empty placeholders for all templates. These
94 	 * reserve memory for later.
95 	 */
96 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
97 				      WL1271_CMD_TEMPL_MAX_SIZE,
98 				      0, WL1271_RATE_AUTOMATIC);
99 	if (ret < 0)
100 		return ret;
101 
102 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_AP_BEACON, NULL,
103 				      WL1271_CMD_TEMPL_MAX_SIZE,
104 				      0, WL1271_RATE_AUTOMATIC);
105 	if (ret < 0)
106 		return ret;
107 
108 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP, NULL,
109 				      sizeof
110 				      (struct wl12xx_disconn_template),
111 				      0, WL1271_RATE_AUTOMATIC);
112 	if (ret < 0)
113 		return ret;
114 
115 	for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
116 		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV, NULL,
117 					      sizeof(struct ieee80211_qos_hdr),
118 					      i, WL1271_RATE_AUTOMATIC);
119 		if (ret < 0)
120 			return ret;
121 	}
122 
123 	return 0;
124 }
125 
wl1271_ap_init_deauth_template(struct wl1271 * wl,struct wl12xx_vif * wlvif)126 static int wl1271_ap_init_deauth_template(struct wl1271 *wl,
127 					  struct wl12xx_vif *wlvif)
128 {
129 	struct wl12xx_disconn_template *tmpl;
130 	int ret;
131 	u32 rate;
132 
133 	tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
134 	if (!tmpl) {
135 		ret = -ENOMEM;
136 		goto out;
137 	}
138 
139 	tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
140 					     IEEE80211_STYPE_DEAUTH);
141 
142 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
143 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP,
144 				      tmpl, sizeof(*tmpl), 0, rate);
145 
146 out:
147 	kfree(tmpl);
148 	return ret;
149 }
150 
wl1271_ap_init_null_template(struct wl1271 * wl,struct ieee80211_vif * vif)151 static int wl1271_ap_init_null_template(struct wl1271 *wl,
152 					struct ieee80211_vif *vif)
153 {
154 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
155 	struct ieee80211_hdr_3addr *nullfunc;
156 	int ret;
157 	u32 rate;
158 
159 	nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
160 	if (!nullfunc) {
161 		ret = -ENOMEM;
162 		goto out;
163 	}
164 
165 	nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
166 					      IEEE80211_STYPE_NULLFUNC |
167 					      IEEE80211_FCTL_FROMDS);
168 
169 	/* nullfunc->addr1 is filled by FW */
170 
171 	memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
172 	memcpy(nullfunc->addr3, vif->addr, ETH_ALEN);
173 
174 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
175 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc,
176 				      sizeof(*nullfunc), 0, rate);
177 
178 out:
179 	kfree(nullfunc);
180 	return ret;
181 }
182 
wl1271_ap_init_qos_null_template(struct wl1271 * wl,struct ieee80211_vif * vif)183 static int wl1271_ap_init_qos_null_template(struct wl1271 *wl,
184 					    struct ieee80211_vif *vif)
185 {
186 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
187 	struct ieee80211_qos_hdr *qosnull;
188 	int ret;
189 	u32 rate;
190 
191 	qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
192 	if (!qosnull) {
193 		ret = -ENOMEM;
194 		goto out;
195 	}
196 
197 	qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
198 					     IEEE80211_STYPE_QOS_NULLFUNC |
199 					     IEEE80211_FCTL_FROMDS);
200 
201 	/* qosnull->addr1 is filled by FW */
202 
203 	memcpy(qosnull->addr2, vif->addr, ETH_ALEN);
204 	memcpy(qosnull->addr3, vif->addr, ETH_ALEN);
205 
206 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
207 	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull,
208 				      sizeof(*qosnull), 0, rate);
209 
210 out:
211 	kfree(qosnull);
212 	return ret;
213 }
214 
wl12xx_init_rx_config(struct wl1271 * wl)215 static int wl12xx_init_rx_config(struct wl1271 *wl)
216 {
217 	int ret;
218 
219 	ret = wl1271_acx_rx_msdu_life_time(wl);
220 	if (ret < 0)
221 		return ret;
222 
223 	return 0;
224 }
225 
wl12xx_init_phy_vif_config(struct wl1271 * wl,struct wl12xx_vif * wlvif)226 static int wl12xx_init_phy_vif_config(struct wl1271 *wl,
227 					    struct wl12xx_vif *wlvif)
228 {
229 	int ret;
230 
231 	ret = wl1271_acx_slot(wl, wlvif, DEFAULT_SLOT_TIME);
232 	if (ret < 0)
233 		return ret;
234 
235 	ret = wl1271_acx_service_period_timeout(wl, wlvif);
236 	if (ret < 0)
237 		return ret;
238 
239 	ret = wl1271_acx_rts_threshold(wl, wlvif, wl->hw->wiphy->rts_threshold);
240 	if (ret < 0)
241 		return ret;
242 
243 	return 0;
244 }
245 
wl1271_init_sta_beacon_filter(struct wl1271 * wl,struct wl12xx_vif * wlvif)246 static int wl1271_init_sta_beacon_filter(struct wl1271 *wl,
247 					 struct wl12xx_vif *wlvif)
248 {
249 	int ret;
250 
251 	ret = wl1271_acx_beacon_filter_table(wl, wlvif);
252 	if (ret < 0)
253 		return ret;
254 
255 	/* enable beacon filtering */
256 	ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
257 	if (ret < 0)
258 		return ret;
259 
260 	return 0;
261 }
262 
wl1271_init_pta(struct wl1271 * wl)263 int wl1271_init_pta(struct wl1271 *wl)
264 {
265 	int ret;
266 
267 	ret = wl12xx_acx_sg_cfg(wl);
268 	if (ret < 0)
269 		return ret;
270 
271 	ret = wl1271_acx_sg_enable(wl, wl->sg_enabled);
272 	if (ret < 0)
273 		return ret;
274 
275 	return 0;
276 }
277 
wl1271_init_energy_detection(struct wl1271 * wl)278 int wl1271_init_energy_detection(struct wl1271 *wl)
279 {
280 	int ret;
281 
282 	ret = wl1271_acx_cca_threshold(wl);
283 	if (ret < 0)
284 		return ret;
285 
286 	return 0;
287 }
288 
wl1271_init_beacon_broadcast(struct wl1271 * wl,struct wl12xx_vif * wlvif)289 static int wl1271_init_beacon_broadcast(struct wl1271 *wl,
290 					struct wl12xx_vif *wlvif)
291 {
292 	int ret;
293 
294 	ret = wl1271_acx_bcn_dtim_options(wl, wlvif);
295 	if (ret < 0)
296 		return ret;
297 
298 	return 0;
299 }
300 
wl12xx_init_fwlog(struct wl1271 * wl)301 static int wl12xx_init_fwlog(struct wl1271 *wl)
302 {
303 	int ret;
304 
305 	if (wl->quirks & WL12XX_QUIRK_FWLOG_NOT_IMPLEMENTED)
306 		return 0;
307 
308 	ret = wl12xx_cmd_config_fwlog(wl);
309 	if (ret < 0)
310 		return ret;
311 
312 	return 0;
313 }
314 
315 /* generic sta initialization (non vif-specific) */
wl1271_sta_hw_init(struct wl1271 * wl,struct wl12xx_vif * wlvif)316 static int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
317 {
318 	int ret;
319 
320 	/* PS config */
321 	ret = wl12xx_acx_config_ps(wl, wlvif);
322 	if (ret < 0)
323 		return ret;
324 
325 	/* FM WLAN coexistence */
326 	ret = wl1271_acx_fm_coex(wl);
327 	if (ret < 0)
328 		return ret;
329 
330 	ret = wl1271_acx_sta_rate_policies(wl, wlvif);
331 	if (ret < 0)
332 		return ret;
333 
334 	return 0;
335 }
336 
wl1271_sta_hw_init_post_mem(struct wl1271 * wl,struct ieee80211_vif * vif)337 static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl,
338 				       struct ieee80211_vif *vif)
339 {
340 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
341 	int ret, i;
342 
343 	/* disable all keep-alive templates */
344 	for (i = 0; i < CMD_TEMPL_KLV_IDX_MAX; i++) {
345 		ret = wl1271_acx_keep_alive_config(wl, wlvif, i,
346 						   ACX_KEEP_ALIVE_TPL_INVALID);
347 		if (ret < 0)
348 			return ret;
349 	}
350 
351 	/* disable the keep-alive feature */
352 	ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
353 	if (ret < 0)
354 		return ret;
355 
356 	return 0;
357 }
358 
359 /* generic ap initialization (non vif-specific) */
wl1271_ap_hw_init(struct wl1271 * wl,struct wl12xx_vif * wlvif)360 static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
361 {
362 	int ret;
363 
364 	ret = wl1271_init_ap_rates(wl, wlvif);
365 	if (ret < 0)
366 		return ret;
367 
368 	return 0;
369 }
370 
wl1271_ap_init_templates(struct wl1271 * wl,struct ieee80211_vif * vif)371 int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif)
372 {
373 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
374 	int ret;
375 
376 	ret = wl1271_ap_init_deauth_template(wl, wlvif);
377 	if (ret < 0)
378 		return ret;
379 
380 	ret = wl1271_ap_init_null_template(wl, vif);
381 	if (ret < 0)
382 		return ret;
383 
384 	ret = wl1271_ap_init_qos_null_template(wl, vif);
385 	if (ret < 0)
386 		return ret;
387 
388 	/*
389 	 * when operating as AP we want to receive external beacons for
390 	 * configuring ERP protection.
391 	 */
392 	ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
393 	if (ret < 0)
394 		return ret;
395 
396 	return 0;
397 }
398 
wl1271_ap_hw_init_post_mem(struct wl1271 * wl,struct ieee80211_vif * vif)399 static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl,
400 				      struct ieee80211_vif *vif)
401 {
402 	return wl1271_ap_init_templates(wl, vif);
403 }
404 
wl1271_init_ap_rates(struct wl1271 * wl,struct wl12xx_vif * wlvif)405 int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
406 {
407 	int i, ret;
408 	struct conf_tx_rate_class rc;
409 	u32 supported_rates;
410 
411 	wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x",
412 		     wlvif->basic_rate_set);
413 
414 	if (wlvif->basic_rate_set == 0)
415 		return -EINVAL;
416 
417 	rc.enabled_rates = wlvif->basic_rate_set;
418 	rc.long_retry_limit = 10;
419 	rc.short_retry_limit = 10;
420 	rc.aflags = 0;
421 	ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx);
422 	if (ret < 0)
423 		return ret;
424 
425 	/* use the min basic rate for AP broadcast/multicast */
426 	rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
427 	rc.short_retry_limit = 10;
428 	rc.long_retry_limit = 10;
429 	rc.aflags = 0;
430 	ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.bcast_rate_idx);
431 	if (ret < 0)
432 		return ret;
433 
434 	/*
435 	 * If the basic rates contain OFDM rates, use OFDM only
436 	 * rates for unicast TX as well. Else use all supported rates.
437 	 */
438 	if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
439 		supported_rates = CONF_TX_OFDM_RATES;
440 	else
441 		supported_rates = CONF_TX_AP_ENABLED_RATES;
442 
443 	/* unconditionally enable HT rates */
444 	supported_rates |= CONF_TX_MCS_RATES;
445 
446 	/* configure unicast TX rate classes */
447 	for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
448 		rc.enabled_rates = supported_rates;
449 		rc.short_retry_limit = 10;
450 		rc.long_retry_limit = 10;
451 		rc.aflags = 0;
452 		ret = wl1271_acx_ap_rate_policy(wl, &rc,
453 						wlvif->ap.ucast_rate_idx[i]);
454 		if (ret < 0)
455 			return ret;
456 	}
457 
458 	return 0;
459 }
460 
wl1271_set_ba_policies(struct wl1271 * wl,struct wl12xx_vif * wlvif)461 static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
462 {
463 	/* Reset the BA RX indicators */
464 	wlvif->ba_allowed = true;
465 	wl->ba_rx_session_count = 0;
466 
467 	/* BA is supported in STA/AP modes */
468 	if (wlvif->bss_type != BSS_TYPE_AP_BSS &&
469 	    wlvif->bss_type != BSS_TYPE_STA_BSS) {
470 		wlvif->ba_support = false;
471 		return 0;
472 	}
473 
474 	wlvif->ba_support = true;
475 
476 	/* 802.11n initiator BA session setting */
477 	return wl12xx_acx_set_ba_initiator_policy(wl, wlvif);
478 }
479 
wl1271_chip_specific_init(struct wl1271 * wl)480 int wl1271_chip_specific_init(struct wl1271 *wl)
481 {
482 	int ret = 0;
483 
484 	if (wl->chip.id == CHIP_ID_1283_PG20) {
485 		u32 host_cfg_bitmap = HOST_IF_CFG_RX_FIFO_ENABLE;
486 
487 		if (!(wl->quirks & WL12XX_QUIRK_NO_BLOCKSIZE_ALIGNMENT))
488 			/* Enable SDIO padding */
489 			host_cfg_bitmap |= HOST_IF_CFG_TX_PAD_TO_SDIO_BLK;
490 
491 		/* Must be before wl1271_acx_init_mem_config() */
492 		ret = wl1271_acx_host_if_cfg_bitmap(wl, host_cfg_bitmap);
493 		if (ret < 0)
494 			goto out;
495 	}
496 out:
497 	return ret;
498 }
499 
500 /* vif-specifc initialization */
wl12xx_init_sta_role(struct wl1271 * wl,struct wl12xx_vif * wlvif)501 static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
502 {
503 	int ret;
504 
505 	ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0);
506 	if (ret < 0)
507 		return ret;
508 
509 	/* Initialize connection monitoring thresholds */
510 	ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
511 	if (ret < 0)
512 		return ret;
513 
514 	/* Beacon filtering */
515 	ret = wl1271_init_sta_beacon_filter(wl, wlvif);
516 	if (ret < 0)
517 		return ret;
518 
519 	/* Beacons and broadcast settings */
520 	ret = wl1271_init_beacon_broadcast(wl, wlvif);
521 	if (ret < 0)
522 		return ret;
523 
524 	/* Configure rssi/snr averaging weights */
525 	ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif);
526 	if (ret < 0)
527 		return ret;
528 
529 	return 0;
530 }
531 
532 /* vif-specific intialization */
wl12xx_init_ap_role(struct wl1271 * wl,struct wl12xx_vif * wlvif)533 static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
534 {
535 	int ret;
536 
537 	ret = wl1271_acx_ap_max_tx_retry(wl, wlvif);
538 	if (ret < 0)
539 		return ret;
540 
541 	/* initialize Tx power */
542 	ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level);
543 	if (ret < 0)
544 		return ret;
545 
546 	return 0;
547 }
548 
wl1271_init_vif_specific(struct wl1271 * wl,struct ieee80211_vif * vif)549 int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
550 {
551 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
552 	struct conf_tx_ac_category *conf_ac;
553 	struct conf_tx_tid *conf_tid;
554 	bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
555 	int ret, i;
556 
557 	/*
558 	 * consider all existing roles before configuring psm.
559 	 * TODO: reconfigure on interface removal.
560 	 */
561 	if (!wl->ap_count) {
562 		if (is_ap) {
563 			/* Configure for power always on */
564 			ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
565 			if (ret < 0)
566 				return ret;
567 		} else if (!wl->sta_count) {
568 			/* Configure for ELP power saving */
569 			ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
570 			if (ret < 0)
571 				return ret;
572 		}
573 	}
574 
575 	/* Mode specific init */
576 	if (is_ap) {
577 		ret = wl1271_ap_hw_init(wl, wlvif);
578 		if (ret < 0)
579 			return ret;
580 
581 		ret = wl12xx_init_ap_role(wl, wlvif);
582 		if (ret < 0)
583 			return ret;
584 	} else {
585 		ret = wl1271_sta_hw_init(wl, wlvif);
586 		if (ret < 0)
587 			return ret;
588 
589 		ret = wl12xx_init_sta_role(wl, wlvif);
590 		if (ret < 0)
591 			return ret;
592 	}
593 
594 	wl12xx_init_phy_vif_config(wl, wlvif);
595 
596 	/* Default TID/AC configuration */
597 	BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
598 	for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
599 		conf_ac = &wl->conf.tx.ac_conf[i];
600 		ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac,
601 					conf_ac->cw_min, conf_ac->cw_max,
602 					conf_ac->aifsn, conf_ac->tx_op_limit);
603 		if (ret < 0)
604 			return ret;
605 
606 		conf_tid = &wl->conf.tx.tid_conf[i];
607 		ret = wl1271_acx_tid_cfg(wl, wlvif,
608 					 conf_tid->queue_id,
609 					 conf_tid->channel_type,
610 					 conf_tid->tsid,
611 					 conf_tid->ps_scheme,
612 					 conf_tid->ack_policy,
613 					 conf_tid->apsd_conf[0],
614 					 conf_tid->apsd_conf[1]);
615 		if (ret < 0)
616 			return ret;
617 	}
618 
619 	/* Configure HW encryption */
620 	ret = wl1271_acx_feature_cfg(wl, wlvif);
621 	if (ret < 0)
622 		return ret;
623 
624 	/* Mode specific init - post mem init */
625 	if (is_ap)
626 		ret = wl1271_ap_hw_init_post_mem(wl, vif);
627 	else
628 		ret = wl1271_sta_hw_init_post_mem(wl, vif);
629 
630 	if (ret < 0)
631 		return ret;
632 
633 	/* Configure initiator BA sessions policies */
634 	ret = wl1271_set_ba_policies(wl, wlvif);
635 	if (ret < 0)
636 		return ret;
637 
638 	return 0;
639 }
640 
wl1271_hw_init(struct wl1271 * wl)641 int wl1271_hw_init(struct wl1271 *wl)
642 {
643 	int ret;
644 
645 	if (wl->chip.id == CHIP_ID_1283_PG20) {
646 		ret = wl128x_cmd_general_parms(wl);
647 		if (ret < 0)
648 			return ret;
649 		ret = wl128x_cmd_radio_parms(wl);
650 		if (ret < 0)
651 			return ret;
652 	} else {
653 		ret = wl1271_cmd_general_parms(wl);
654 		if (ret < 0)
655 			return ret;
656 		ret = wl1271_cmd_radio_parms(wl);
657 		if (ret < 0)
658 			return ret;
659 		ret = wl1271_cmd_ext_radio_parms(wl);
660 		if (ret < 0)
661 			return ret;
662 	}
663 
664 	/* Chip-specific init */
665 	ret = wl1271_chip_specific_init(wl);
666 	if (ret < 0)
667 		return ret;
668 
669 	/* Init templates */
670 	ret = wl1271_init_templates_config(wl);
671 	if (ret < 0)
672 		return ret;
673 
674 	ret = wl12xx_acx_mem_cfg(wl);
675 	if (ret < 0)
676 		return ret;
677 
678 	/* Configure the FW logger */
679 	ret = wl12xx_init_fwlog(wl);
680 	if (ret < 0)
681 		return ret;
682 
683 	/* Bluetooth WLAN coexistence */
684 	ret = wl1271_init_pta(wl);
685 	if (ret < 0)
686 		return ret;
687 
688 	/* Default memory configuration */
689 	ret = wl1271_acx_init_mem_config(wl);
690 	if (ret < 0)
691 		return ret;
692 
693 	/* RX config */
694 	ret = wl12xx_init_rx_config(wl);
695 	if (ret < 0)
696 		goto out_free_memmap;
697 
698 	ret = wl1271_acx_dco_itrim_params(wl);
699 	if (ret < 0)
700 		goto out_free_memmap;
701 
702 	/* Configure TX patch complete interrupt behavior */
703 	ret = wl1271_acx_tx_config_options(wl);
704 	if (ret < 0)
705 		goto out_free_memmap;
706 
707 	/* RX complete interrupt pacing */
708 	ret = wl1271_acx_init_rx_interrupt(wl);
709 	if (ret < 0)
710 		goto out_free_memmap;
711 
712 	/* Energy detection */
713 	ret = wl1271_init_energy_detection(wl);
714 	if (ret < 0)
715 		goto out_free_memmap;
716 
717 	/* Default fragmentation threshold */
718 	ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold);
719 	if (ret < 0)
720 		goto out_free_memmap;
721 
722 	/* Enable data path */
723 	ret = wl1271_cmd_data_path(wl, 1);
724 	if (ret < 0)
725 		goto out_free_memmap;
726 
727 	/* configure PM */
728 	ret = wl1271_acx_pm_config(wl);
729 	if (ret < 0)
730 		goto out_free_memmap;
731 
732 	ret = wl12xx_acx_set_rate_mgmt_params(wl);
733 	if (ret < 0)
734 		goto out_free_memmap;
735 
736 	/* configure hangover */
737 	ret = wl12xx_acx_config_hangover(wl);
738 	if (ret < 0)
739 		goto out_free_memmap;
740 
741 	return 0;
742 
743  out_free_memmap:
744 	kfree(wl->target_mem_map);
745 	wl->target_mem_map = NULL;
746 
747 	return ret;
748 }
749