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