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