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