xref: /openbmc/linux/drivers/net/wireless/ti/wlcore/init.c (revision 8cf77e17)
17b3115f2SLuciano Coelho /*
27b3115f2SLuciano Coelho  * This file is part of wl1271
37b3115f2SLuciano Coelho  *
47b3115f2SLuciano Coelho  * Copyright (C) 2009 Nokia Corporation
57b3115f2SLuciano Coelho  *
67b3115f2SLuciano Coelho  * Contact: Luciano Coelho <luciano.coelho@nokia.com>
77b3115f2SLuciano Coelho  *
87b3115f2SLuciano Coelho  * This program is free software; you can redistribute it and/or
97b3115f2SLuciano Coelho  * modify it under the terms of the GNU General Public License
107b3115f2SLuciano Coelho  * version 2 as published by the Free Software Foundation.
117b3115f2SLuciano Coelho  *
127b3115f2SLuciano Coelho  * This program is distributed in the hope that it will be useful, but
137b3115f2SLuciano Coelho  * WITHOUT ANY WARRANTY; without even the implied warranty of
147b3115f2SLuciano Coelho  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
157b3115f2SLuciano Coelho  * General Public License for more details.
167b3115f2SLuciano Coelho  *
177b3115f2SLuciano Coelho  * You should have received a copy of the GNU General Public License
187b3115f2SLuciano Coelho  * along with this program; if not, write to the Free Software
197b3115f2SLuciano Coelho  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
207b3115f2SLuciano Coelho  * 02110-1301 USA
217b3115f2SLuciano Coelho  *
227b3115f2SLuciano Coelho  */
237b3115f2SLuciano Coelho 
247b3115f2SLuciano Coelho #include <linux/kernel.h>
257b3115f2SLuciano Coelho #include <linux/module.h>
267b3115f2SLuciano Coelho #include <linux/slab.h>
277b3115f2SLuciano Coelho 
287b3115f2SLuciano Coelho #include "debug.h"
297b3115f2SLuciano Coelho #include "init.h"
307b3115f2SLuciano Coelho #include "wl12xx_80211.h"
317b3115f2SLuciano Coelho #include "acx.h"
327b3115f2SLuciano Coelho #include "cmd.h"
337b3115f2SLuciano Coelho #include "tx.h"
347b3115f2SLuciano Coelho #include "io.h"
358a9affc0SArik Nemtsov #include "hw_ops.h"
367b3115f2SLuciano Coelho 
377b3115f2SLuciano Coelho int wl1271_init_templates_config(struct wl1271 *wl)
387b3115f2SLuciano Coelho {
397b3115f2SLuciano Coelho 	int ret, i;
407b3115f2SLuciano Coelho 	size_t max_size;
417b3115f2SLuciano Coelho 
427b3115f2SLuciano Coelho 	/* send empty templates for fw memory reservation */
437b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
4478e28062SEliad Peller 				      wl->scan_templ_id_2_4, NULL,
457b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_MAX_SIZE,
467b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
477b3115f2SLuciano Coelho 	if (ret < 0)
487b3115f2SLuciano Coelho 		return ret;
497b3115f2SLuciano Coelho 
507b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
5178e28062SEliad Peller 				      wl->scan_templ_id_5,
527b3115f2SLuciano Coelho 				      NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
537b3115f2SLuciano Coelho 				      WL1271_RATE_AUTOMATIC);
547b3115f2SLuciano Coelho 	if (ret < 0)
557b3115f2SLuciano Coelho 		return ret;
567b3115f2SLuciano Coelho 
573df74f46SYoni Divinsky 	if (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL) {
583df74f46SYoni Divinsky 		ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
5978e28062SEliad Peller 					      wl->sched_scan_templ_id_2_4,
6078e28062SEliad Peller 					      NULL,
613df74f46SYoni Divinsky 					      WL1271_CMD_TEMPL_MAX_SIZE,
623df74f46SYoni Divinsky 					      0, WL1271_RATE_AUTOMATIC);
633df74f46SYoni Divinsky 		if (ret < 0)
643df74f46SYoni Divinsky 			return ret;
653df74f46SYoni Divinsky 
663df74f46SYoni Divinsky 		ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
6778e28062SEliad Peller 					      wl->sched_scan_templ_id_5,
6878e28062SEliad Peller 					      NULL,
693df74f46SYoni Divinsky 					      WL1271_CMD_TEMPL_MAX_SIZE,
703df74f46SYoni Divinsky 					      0, WL1271_RATE_AUTOMATIC);
713df74f46SYoni Divinsky 		if (ret < 0)
723df74f46SYoni Divinsky 			return ret;
733df74f46SYoni Divinsky 	}
743df74f46SYoni Divinsky 
757b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
767b3115f2SLuciano Coelho 				      CMD_TEMPL_NULL_DATA, NULL,
777b3115f2SLuciano Coelho 				      sizeof(struct wl12xx_null_data_template),
787b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
797b3115f2SLuciano Coelho 	if (ret < 0)
807b3115f2SLuciano Coelho 		return ret;
817b3115f2SLuciano Coelho 
827b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
837b3115f2SLuciano Coelho 				      CMD_TEMPL_PS_POLL, NULL,
847b3115f2SLuciano Coelho 				      sizeof(struct wl12xx_ps_poll_template),
857b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
867b3115f2SLuciano Coelho 	if (ret < 0)
877b3115f2SLuciano Coelho 		return ret;
887b3115f2SLuciano Coelho 
897b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
907b3115f2SLuciano Coelho 				      CMD_TEMPL_QOS_NULL_DATA, NULL,
917b3115f2SLuciano Coelho 				      sizeof
927b3115f2SLuciano Coelho 				      (struct ieee80211_qos_hdr),
937b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
947b3115f2SLuciano Coelho 	if (ret < 0)
957b3115f2SLuciano Coelho 		return ret;
967b3115f2SLuciano Coelho 
977b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
987b3115f2SLuciano Coelho 				      CMD_TEMPL_PROBE_RESPONSE, NULL,
997b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_DFLT_SIZE,
1007b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1017b3115f2SLuciano Coelho 	if (ret < 0)
1027b3115f2SLuciano Coelho 		return ret;
1037b3115f2SLuciano Coelho 
1047b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1057b3115f2SLuciano Coelho 				      CMD_TEMPL_BEACON, NULL,
1067b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_DFLT_SIZE,
1077b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1087b3115f2SLuciano Coelho 	if (ret < 0)
1097b3115f2SLuciano Coelho 		return ret;
1107b3115f2SLuciano Coelho 
1117b3115f2SLuciano Coelho 	max_size = sizeof(struct wl12xx_arp_rsp_template) +
1127b3115f2SLuciano Coelho 		   WL1271_EXTRA_SPACE_MAX;
1137b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1147b3115f2SLuciano Coelho 				      CMD_TEMPL_ARP_RSP, NULL,
1157b3115f2SLuciano Coelho 				      max_size,
1167b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1177b3115f2SLuciano Coelho 	if (ret < 0)
1187b3115f2SLuciano Coelho 		return ret;
1197b3115f2SLuciano Coelho 
1207b3115f2SLuciano Coelho 	/*
1217b3115f2SLuciano Coelho 	 * Put very large empty placeholders for all templates. These
1227b3115f2SLuciano Coelho 	 * reserve memory for later.
1237b3115f2SLuciano Coelho 	 */
1247b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1257b3115f2SLuciano Coelho 				      CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
1267b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_MAX_SIZE,
1277b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1287b3115f2SLuciano Coelho 	if (ret < 0)
1297b3115f2SLuciano Coelho 		return ret;
1307b3115f2SLuciano Coelho 
1317b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1327b3115f2SLuciano Coelho 				      CMD_TEMPL_AP_BEACON, NULL,
1337b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_MAX_SIZE,
1347b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1357b3115f2SLuciano Coelho 	if (ret < 0)
1367b3115f2SLuciano Coelho 		return ret;
1377b3115f2SLuciano Coelho 
1387b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1397b3115f2SLuciano Coelho 				      CMD_TEMPL_DEAUTH_AP, NULL,
1407b3115f2SLuciano Coelho 				      sizeof
1417b3115f2SLuciano Coelho 				      (struct wl12xx_disconn_template),
1427b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1437b3115f2SLuciano Coelho 	if (ret < 0)
1447b3115f2SLuciano Coelho 		return ret;
1457b3115f2SLuciano Coelho 
146001e39a8SEliad Peller 	for (i = 0; i < WLCORE_MAX_KLV_TEMPLATES; i++) {
1477b3115f2SLuciano Coelho 		ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1487b3115f2SLuciano Coelho 					      CMD_TEMPL_KLV, NULL,
1497b3115f2SLuciano Coelho 					      sizeof(struct ieee80211_qos_hdr),
1507b3115f2SLuciano Coelho 					      i, WL1271_RATE_AUTOMATIC);
1517b3115f2SLuciano Coelho 		if (ret < 0)
1527b3115f2SLuciano Coelho 			return ret;
1537b3115f2SLuciano Coelho 	}
1547b3115f2SLuciano Coelho 
1557b3115f2SLuciano Coelho 	return 0;
1567b3115f2SLuciano Coelho }
1577b3115f2SLuciano Coelho 
1587b3115f2SLuciano Coelho static int wl1271_ap_init_deauth_template(struct wl1271 *wl,
1597b3115f2SLuciano Coelho 					  struct wl12xx_vif *wlvif)
1607b3115f2SLuciano Coelho {
1617b3115f2SLuciano Coelho 	struct wl12xx_disconn_template *tmpl;
1627b3115f2SLuciano Coelho 	int ret;
1637b3115f2SLuciano Coelho 	u32 rate;
1647b3115f2SLuciano Coelho 
1657b3115f2SLuciano Coelho 	tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
1667b3115f2SLuciano Coelho 	if (!tmpl) {
1677b3115f2SLuciano Coelho 		ret = -ENOMEM;
1687b3115f2SLuciano Coelho 		goto out;
1697b3115f2SLuciano Coelho 	}
1707b3115f2SLuciano Coelho 
1717b3115f2SLuciano Coelho 	tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
1727b3115f2SLuciano Coelho 					     IEEE80211_STYPE_DEAUTH);
1737b3115f2SLuciano Coelho 
1747b3115f2SLuciano Coelho 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
1757b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
1767b3115f2SLuciano Coelho 				      CMD_TEMPL_DEAUTH_AP,
1777b3115f2SLuciano Coelho 				      tmpl, sizeof(*tmpl), 0, rate);
1787b3115f2SLuciano Coelho 
1797b3115f2SLuciano Coelho out:
1807b3115f2SLuciano Coelho 	kfree(tmpl);
1817b3115f2SLuciano Coelho 	return ret;
1827b3115f2SLuciano Coelho }
1837b3115f2SLuciano Coelho 
1847b3115f2SLuciano Coelho static int wl1271_ap_init_null_template(struct wl1271 *wl,
1857b3115f2SLuciano Coelho 					struct ieee80211_vif *vif)
1867b3115f2SLuciano Coelho {
1877b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
1887b3115f2SLuciano Coelho 	struct ieee80211_hdr_3addr *nullfunc;
1897b3115f2SLuciano Coelho 	int ret;
1907b3115f2SLuciano Coelho 	u32 rate;
1917b3115f2SLuciano Coelho 
1927b3115f2SLuciano Coelho 	nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
1937b3115f2SLuciano Coelho 	if (!nullfunc) {
1947b3115f2SLuciano Coelho 		ret = -ENOMEM;
1957b3115f2SLuciano Coelho 		goto out;
1967b3115f2SLuciano Coelho 	}
1977b3115f2SLuciano Coelho 
1987b3115f2SLuciano Coelho 	nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
1997b3115f2SLuciano Coelho 					      IEEE80211_STYPE_NULLFUNC |
2007b3115f2SLuciano Coelho 					      IEEE80211_FCTL_FROMDS);
2017b3115f2SLuciano Coelho 
2027b3115f2SLuciano Coelho 	/* nullfunc->addr1 is filled by FW */
2037b3115f2SLuciano Coelho 
2047b3115f2SLuciano Coelho 	memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
2057b3115f2SLuciano Coelho 	memcpy(nullfunc->addr3, vif->addr, ETH_ALEN);
2067b3115f2SLuciano Coelho 
2077b3115f2SLuciano Coelho 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2087b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
2097b3115f2SLuciano Coelho 				      CMD_TEMPL_NULL_DATA, nullfunc,
2107b3115f2SLuciano Coelho 				      sizeof(*nullfunc), 0, rate);
2117b3115f2SLuciano Coelho 
2127b3115f2SLuciano Coelho out:
2137b3115f2SLuciano Coelho 	kfree(nullfunc);
2147b3115f2SLuciano Coelho 	return ret;
2157b3115f2SLuciano Coelho }
2167b3115f2SLuciano Coelho 
2177b3115f2SLuciano Coelho static int wl1271_ap_init_qos_null_template(struct wl1271 *wl,
2187b3115f2SLuciano Coelho 					    struct ieee80211_vif *vif)
2197b3115f2SLuciano Coelho {
2207b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2217b3115f2SLuciano Coelho 	struct ieee80211_qos_hdr *qosnull;
2227b3115f2SLuciano Coelho 	int ret;
2237b3115f2SLuciano Coelho 	u32 rate;
2247b3115f2SLuciano Coelho 
2257b3115f2SLuciano Coelho 	qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
2267b3115f2SLuciano Coelho 	if (!qosnull) {
2277b3115f2SLuciano Coelho 		ret = -ENOMEM;
2287b3115f2SLuciano Coelho 		goto out;
2297b3115f2SLuciano Coelho 	}
2307b3115f2SLuciano Coelho 
2317b3115f2SLuciano Coelho 	qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
2327b3115f2SLuciano Coelho 					     IEEE80211_STYPE_QOS_NULLFUNC |
2337b3115f2SLuciano Coelho 					     IEEE80211_FCTL_FROMDS);
2347b3115f2SLuciano Coelho 
2357b3115f2SLuciano Coelho 	/* qosnull->addr1 is filled by FW */
2367b3115f2SLuciano Coelho 
2377b3115f2SLuciano Coelho 	memcpy(qosnull->addr2, vif->addr, ETH_ALEN);
2387b3115f2SLuciano Coelho 	memcpy(qosnull->addr3, vif->addr, ETH_ALEN);
2397b3115f2SLuciano Coelho 
2407b3115f2SLuciano Coelho 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2417b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
2427b3115f2SLuciano Coelho 				      CMD_TEMPL_QOS_NULL_DATA, qosnull,
2437b3115f2SLuciano Coelho 				      sizeof(*qosnull), 0, rate);
2447b3115f2SLuciano Coelho 
2457b3115f2SLuciano Coelho out:
2467b3115f2SLuciano Coelho 	kfree(qosnull);
2477b3115f2SLuciano Coelho 	return ret;
2487b3115f2SLuciano Coelho }
2497b3115f2SLuciano Coelho 
2507b3115f2SLuciano Coelho static int wl12xx_init_rx_config(struct wl1271 *wl)
2517b3115f2SLuciano Coelho {
2527b3115f2SLuciano Coelho 	int ret;
2537b3115f2SLuciano Coelho 
2547b3115f2SLuciano Coelho 	ret = wl1271_acx_rx_msdu_life_time(wl);
2557b3115f2SLuciano Coelho 	if (ret < 0)
2567b3115f2SLuciano Coelho 		return ret;
2577b3115f2SLuciano Coelho 
2587b3115f2SLuciano Coelho 	return 0;
2597b3115f2SLuciano Coelho }
2607b3115f2SLuciano Coelho 
2617b3115f2SLuciano Coelho static int wl12xx_init_phy_vif_config(struct wl1271 *wl,
2627b3115f2SLuciano Coelho 					    struct wl12xx_vif *wlvif)
2637b3115f2SLuciano Coelho {
2647b3115f2SLuciano Coelho 	int ret;
2657b3115f2SLuciano Coelho 
2667b3115f2SLuciano Coelho 	ret = wl1271_acx_slot(wl, wlvif, DEFAULT_SLOT_TIME);
2677b3115f2SLuciano Coelho 	if (ret < 0)
2687b3115f2SLuciano Coelho 		return ret;
2697b3115f2SLuciano Coelho 
2707b3115f2SLuciano Coelho 	ret = wl1271_acx_service_period_timeout(wl, wlvif);
2717b3115f2SLuciano Coelho 	if (ret < 0)
2727b3115f2SLuciano Coelho 		return ret;
2737b3115f2SLuciano Coelho 
2747b3115f2SLuciano Coelho 	ret = wl1271_acx_rts_threshold(wl, wlvif, wl->hw->wiphy->rts_threshold);
2757b3115f2SLuciano Coelho 	if (ret < 0)
2767b3115f2SLuciano Coelho 		return ret;
2777b3115f2SLuciano Coelho 
2787b3115f2SLuciano Coelho 	return 0;
2797b3115f2SLuciano Coelho }
2807b3115f2SLuciano Coelho 
2817b3115f2SLuciano Coelho static int wl1271_init_sta_beacon_filter(struct wl1271 *wl,
2827b3115f2SLuciano Coelho 					 struct wl12xx_vif *wlvif)
2837b3115f2SLuciano Coelho {
2847b3115f2SLuciano Coelho 	int ret;
2857b3115f2SLuciano Coelho 
2867b3115f2SLuciano Coelho 	ret = wl1271_acx_beacon_filter_table(wl, wlvif);
2877b3115f2SLuciano Coelho 	if (ret < 0)
2887b3115f2SLuciano Coelho 		return ret;
2897b3115f2SLuciano Coelho 
290d881fa2cSEliad Peller 	/* disable beacon filtering until we get the first beacon */
291d881fa2cSEliad Peller 	ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
2927b3115f2SLuciano Coelho 	if (ret < 0)
2937b3115f2SLuciano Coelho 		return ret;
2947b3115f2SLuciano Coelho 
2957b3115f2SLuciano Coelho 	return 0;
2967b3115f2SLuciano Coelho }
2977b3115f2SLuciano Coelho 
2987b3115f2SLuciano Coelho int wl1271_init_pta(struct wl1271 *wl)
2997b3115f2SLuciano Coelho {
3007b3115f2SLuciano Coelho 	int ret;
3017b3115f2SLuciano Coelho 
3027b3115f2SLuciano Coelho 	ret = wl12xx_acx_sg_cfg(wl);
3037b3115f2SLuciano Coelho 	if (ret < 0)
3047b3115f2SLuciano Coelho 		return ret;
3057b3115f2SLuciano Coelho 
3067b3115f2SLuciano Coelho 	ret = wl1271_acx_sg_enable(wl, wl->sg_enabled);
3077b3115f2SLuciano Coelho 	if (ret < 0)
3087b3115f2SLuciano Coelho 		return ret;
3097b3115f2SLuciano Coelho 
3107b3115f2SLuciano Coelho 	return 0;
3117b3115f2SLuciano Coelho }
3127b3115f2SLuciano Coelho 
3137b3115f2SLuciano Coelho int wl1271_init_energy_detection(struct wl1271 *wl)
3147b3115f2SLuciano Coelho {
3157b3115f2SLuciano Coelho 	int ret;
3167b3115f2SLuciano Coelho 
3177b3115f2SLuciano Coelho 	ret = wl1271_acx_cca_threshold(wl);
3187b3115f2SLuciano Coelho 	if (ret < 0)
3197b3115f2SLuciano Coelho 		return ret;
3207b3115f2SLuciano Coelho 
3217b3115f2SLuciano Coelho 	return 0;
3227b3115f2SLuciano Coelho }
3237b3115f2SLuciano Coelho 
3247b3115f2SLuciano Coelho static int wl1271_init_beacon_broadcast(struct wl1271 *wl,
3257b3115f2SLuciano Coelho 					struct wl12xx_vif *wlvif)
3267b3115f2SLuciano Coelho {
3277b3115f2SLuciano Coelho 	int ret;
3287b3115f2SLuciano Coelho 
3297b3115f2SLuciano Coelho 	ret = wl1271_acx_bcn_dtim_options(wl, wlvif);
3307b3115f2SLuciano Coelho 	if (ret < 0)
3317b3115f2SLuciano Coelho 		return ret;
3327b3115f2SLuciano Coelho 
3337b3115f2SLuciano Coelho 	return 0;
3347b3115f2SLuciano Coelho }
3357b3115f2SLuciano Coelho 
3367b3115f2SLuciano Coelho static int wl12xx_init_fwlog(struct wl1271 *wl)
3377b3115f2SLuciano Coelho {
3387b3115f2SLuciano Coelho 	int ret;
3397b3115f2SLuciano Coelho 
3406f7dd16cSLuciano Coelho 	if (wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED)
3417b3115f2SLuciano Coelho 		return 0;
3427b3115f2SLuciano Coelho 
3437b3115f2SLuciano Coelho 	ret = wl12xx_cmd_config_fwlog(wl);
3447b3115f2SLuciano Coelho 	if (ret < 0)
3457b3115f2SLuciano Coelho 		return ret;
3467b3115f2SLuciano Coelho 
3477b3115f2SLuciano Coelho 	return 0;
3487b3115f2SLuciano Coelho }
3497b3115f2SLuciano Coelho 
3507b3115f2SLuciano Coelho /* generic sta initialization (non vif-specific) */
3517845af35SEliad Peller int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
3527b3115f2SLuciano Coelho {
3537b3115f2SLuciano Coelho 	int ret;
3547b3115f2SLuciano Coelho 
3557b3115f2SLuciano Coelho 	/* PS config */
3567b3115f2SLuciano Coelho 	ret = wl12xx_acx_config_ps(wl, wlvif);
3577b3115f2SLuciano Coelho 	if (ret < 0)
3587b3115f2SLuciano Coelho 		return ret;
3597b3115f2SLuciano Coelho 
3607b3115f2SLuciano Coelho 	/* FM WLAN coexistence */
3617b3115f2SLuciano Coelho 	ret = wl1271_acx_fm_coex(wl);
3627b3115f2SLuciano Coelho 	if (ret < 0)
3637b3115f2SLuciano Coelho 		return ret;
3647b3115f2SLuciano Coelho 
3657b3115f2SLuciano Coelho 	ret = wl1271_acx_sta_rate_policies(wl, wlvif);
3667b3115f2SLuciano Coelho 	if (ret < 0)
3677b3115f2SLuciano Coelho 		return ret;
3687b3115f2SLuciano Coelho 
3697b3115f2SLuciano Coelho 	return 0;
3707b3115f2SLuciano Coelho }
3717b3115f2SLuciano Coelho 
3727b3115f2SLuciano Coelho static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl,
3737b3115f2SLuciano Coelho 				       struct ieee80211_vif *vif)
3747b3115f2SLuciano Coelho {
3757b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
376001e39a8SEliad Peller 	int ret;
3777b3115f2SLuciano Coelho 
3787b3115f2SLuciano Coelho 	/* disable the keep-alive feature */
3797b3115f2SLuciano Coelho 	ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
3807b3115f2SLuciano Coelho 	if (ret < 0)
3817b3115f2SLuciano Coelho 		return ret;
3827b3115f2SLuciano Coelho 
3837b3115f2SLuciano Coelho 	return 0;
3847b3115f2SLuciano Coelho }
3857b3115f2SLuciano Coelho 
3867b3115f2SLuciano Coelho /* generic ap initialization (non vif-specific) */
3877b3115f2SLuciano Coelho static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
3887b3115f2SLuciano Coelho {
3897b3115f2SLuciano Coelho 	int ret;
3907b3115f2SLuciano Coelho 
3917b3115f2SLuciano Coelho 	ret = wl1271_init_ap_rates(wl, wlvif);
3927b3115f2SLuciano Coelho 	if (ret < 0)
3937b3115f2SLuciano Coelho 		return ret;
3947b3115f2SLuciano Coelho 
395e2f1e50fSKobi L 	/* configure AP sleep, if enabled */
396e2f1e50fSKobi L 	ret = wlcore_hw_ap_sleep(wl);
397e2f1e50fSKobi L 	if (ret < 0)
398e2f1e50fSKobi L 		return ret;
399e2f1e50fSKobi L 
4007b3115f2SLuciano Coelho 	return 0;
4017b3115f2SLuciano Coelho }
4027b3115f2SLuciano Coelho 
4037b3115f2SLuciano Coelho int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif)
4047b3115f2SLuciano Coelho {
4057b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
4067b3115f2SLuciano Coelho 	int ret;
4077b3115f2SLuciano Coelho 
4087b3115f2SLuciano Coelho 	ret = wl1271_ap_init_deauth_template(wl, wlvif);
4097b3115f2SLuciano Coelho 	if (ret < 0)
4107b3115f2SLuciano Coelho 		return ret;
4117b3115f2SLuciano Coelho 
4127b3115f2SLuciano Coelho 	ret = wl1271_ap_init_null_template(wl, vif);
4137b3115f2SLuciano Coelho 	if (ret < 0)
4147b3115f2SLuciano Coelho 		return ret;
4157b3115f2SLuciano Coelho 
4167b3115f2SLuciano Coelho 	ret = wl1271_ap_init_qos_null_template(wl, vif);
4177b3115f2SLuciano Coelho 	if (ret < 0)
4187b3115f2SLuciano Coelho 		return ret;
4197b3115f2SLuciano Coelho 
4207b3115f2SLuciano Coelho 	/*
4217b3115f2SLuciano Coelho 	 * when operating as AP we want to receive external beacons for
4227b3115f2SLuciano Coelho 	 * configuring ERP protection.
4237b3115f2SLuciano Coelho 	 */
4247b3115f2SLuciano Coelho 	ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
4257b3115f2SLuciano Coelho 	if (ret < 0)
4267b3115f2SLuciano Coelho 		return ret;
4277b3115f2SLuciano Coelho 
4287b3115f2SLuciano Coelho 	return 0;
4297b3115f2SLuciano Coelho }
4307b3115f2SLuciano Coelho 
4317b3115f2SLuciano Coelho static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl,
4327b3115f2SLuciano Coelho 				      struct ieee80211_vif *vif)
4337b3115f2SLuciano Coelho {
4347b3115f2SLuciano Coelho 	return wl1271_ap_init_templates(wl, vif);
4357b3115f2SLuciano Coelho }
4367b3115f2SLuciano Coelho 
4377b3115f2SLuciano Coelho int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
4387b3115f2SLuciano Coelho {
4397b3115f2SLuciano Coelho 	int i, ret;
4407b3115f2SLuciano Coelho 	struct conf_tx_rate_class rc;
4417b3115f2SLuciano Coelho 	u32 supported_rates;
4427b3115f2SLuciano Coelho 
4437b3115f2SLuciano Coelho 	wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x",
4447b3115f2SLuciano Coelho 		     wlvif->basic_rate_set);
4457b3115f2SLuciano Coelho 
4467b3115f2SLuciano Coelho 	if (wlvif->basic_rate_set == 0)
4477b3115f2SLuciano Coelho 		return -EINVAL;
4487b3115f2SLuciano Coelho 
4497b3115f2SLuciano Coelho 	rc.enabled_rates = wlvif->basic_rate_set;
4507b3115f2SLuciano Coelho 	rc.long_retry_limit = 10;
4517b3115f2SLuciano Coelho 	rc.short_retry_limit = 10;
4527b3115f2SLuciano Coelho 	rc.aflags = 0;
4537b3115f2SLuciano Coelho 	ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx);
4547b3115f2SLuciano Coelho 	if (ret < 0)
4557b3115f2SLuciano Coelho 		return ret;
4567b3115f2SLuciano Coelho 
4577b3115f2SLuciano Coelho 	/* use the min basic rate for AP broadcast/multicast */
4587b3115f2SLuciano Coelho 	rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4597b3115f2SLuciano Coelho 	rc.short_retry_limit = 10;
4607b3115f2SLuciano Coelho 	rc.long_retry_limit = 10;
4617b3115f2SLuciano Coelho 	rc.aflags = 0;
4627b3115f2SLuciano Coelho 	ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.bcast_rate_idx);
4637b3115f2SLuciano Coelho 	if (ret < 0)
4647b3115f2SLuciano Coelho 		return ret;
4657b3115f2SLuciano Coelho 
4667b3115f2SLuciano Coelho 	/*
4677b3115f2SLuciano Coelho 	 * If the basic rates contain OFDM rates, use OFDM only
4687b3115f2SLuciano Coelho 	 * rates for unicast TX as well. Else use all supported rates.
4697b3115f2SLuciano Coelho 	 */
470bc566f92SArik Nemtsov 	if (wl->ofdm_only_ap && (wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
4717b3115f2SLuciano Coelho 		supported_rates = CONF_TX_OFDM_RATES;
4727b3115f2SLuciano Coelho 	else
47342ec1f82SEliad Peller 		supported_rates = CONF_TX_ENABLED_RATES;
4747b3115f2SLuciano Coelho 
4757b3115f2SLuciano Coelho 	/* unconditionally enable HT rates */
4767b3115f2SLuciano Coelho 	supported_rates |= CONF_TX_MCS_RATES;
4777b3115f2SLuciano Coelho 
478ebc7e57dSArik Nemtsov 	/* get extra MIMO or wide-chan rates where the HW supports it */
479ebc7e57dSArik Nemtsov 	supported_rates |= wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
480ebc7e57dSArik Nemtsov 
4817b3115f2SLuciano Coelho 	/* configure unicast TX rate classes */
4827b3115f2SLuciano Coelho 	for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
4837b3115f2SLuciano Coelho 		rc.enabled_rates = supported_rates;
4847b3115f2SLuciano Coelho 		rc.short_retry_limit = 10;
4857b3115f2SLuciano Coelho 		rc.long_retry_limit = 10;
4867b3115f2SLuciano Coelho 		rc.aflags = 0;
4877b3115f2SLuciano Coelho 		ret = wl1271_acx_ap_rate_policy(wl, &rc,
4887b3115f2SLuciano Coelho 						wlvif->ap.ucast_rate_idx[i]);
4897b3115f2SLuciano Coelho 		if (ret < 0)
4907b3115f2SLuciano Coelho 			return ret;
4917b3115f2SLuciano Coelho 	}
4927b3115f2SLuciano Coelho 
4937b3115f2SLuciano Coelho 	return 0;
4947b3115f2SLuciano Coelho }
4957b3115f2SLuciano Coelho 
4967b3115f2SLuciano Coelho static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
4977b3115f2SLuciano Coelho {
4987b3115f2SLuciano Coelho 	/* Reset the BA RX indicators */
4997b3115f2SLuciano Coelho 	wlvif->ba_allowed = true;
5007b3115f2SLuciano Coelho 	wl->ba_rx_session_count = 0;
5017b3115f2SLuciano Coelho 
5027b3115f2SLuciano Coelho 	/* BA is supported in STA/AP modes */
5037b3115f2SLuciano Coelho 	if (wlvif->bss_type != BSS_TYPE_AP_BSS &&
5047b3115f2SLuciano Coelho 	    wlvif->bss_type != BSS_TYPE_STA_BSS) {
5057b3115f2SLuciano Coelho 		wlvif->ba_support = false;
5067b3115f2SLuciano Coelho 		return 0;
5077b3115f2SLuciano Coelho 	}
5087b3115f2SLuciano Coelho 
5097b3115f2SLuciano Coelho 	wlvif->ba_support = true;
5107b3115f2SLuciano Coelho 
5117b3115f2SLuciano Coelho 	/* 802.11n initiator BA session setting */
5127b3115f2SLuciano Coelho 	return wl12xx_acx_set_ba_initiator_policy(wl, wlvif);
5137b3115f2SLuciano Coelho }
5147b3115f2SLuciano Coelho 
5157b3115f2SLuciano Coelho /* vif-specifc initialization */
5167b3115f2SLuciano Coelho static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
5177b3115f2SLuciano Coelho {
5187b3115f2SLuciano Coelho 	int ret;
5197b3115f2SLuciano Coelho 
5207b3115f2SLuciano Coelho 	ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0);
5217b3115f2SLuciano Coelho 	if (ret < 0)
5227b3115f2SLuciano Coelho 		return ret;
5237b3115f2SLuciano Coelho 
5247b3115f2SLuciano Coelho 	/* Initialize connection monitoring thresholds */
5257b3115f2SLuciano Coelho 	ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
5267b3115f2SLuciano Coelho 	if (ret < 0)
5277b3115f2SLuciano Coelho 		return ret;
5287b3115f2SLuciano Coelho 
5297b3115f2SLuciano Coelho 	/* Beacon filtering */
5307b3115f2SLuciano Coelho 	ret = wl1271_init_sta_beacon_filter(wl, wlvif);
5317b3115f2SLuciano Coelho 	if (ret < 0)
5327b3115f2SLuciano Coelho 		return ret;
5337b3115f2SLuciano Coelho 
5347b3115f2SLuciano Coelho 	/* Beacons and broadcast settings */
5357b3115f2SLuciano Coelho 	ret = wl1271_init_beacon_broadcast(wl, wlvif);
5367b3115f2SLuciano Coelho 	if (ret < 0)
5377b3115f2SLuciano Coelho 		return ret;
5387b3115f2SLuciano Coelho 
5397b3115f2SLuciano Coelho 	/* Configure rssi/snr averaging weights */
5407b3115f2SLuciano Coelho 	ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif);
5417b3115f2SLuciano Coelho 	if (ret < 0)
5427b3115f2SLuciano Coelho 		return ret;
5437b3115f2SLuciano Coelho 
5447b3115f2SLuciano Coelho 	return 0;
5457b3115f2SLuciano Coelho }
5467b3115f2SLuciano Coelho 
5477b3115f2SLuciano Coelho /* vif-specific intialization */
5487b3115f2SLuciano Coelho static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
5497b3115f2SLuciano Coelho {
5507b3115f2SLuciano Coelho 	int ret;
5517b3115f2SLuciano Coelho 
5527b3115f2SLuciano Coelho 	ret = wl1271_acx_ap_max_tx_retry(wl, wlvif);
5537b3115f2SLuciano Coelho 	if (ret < 0)
5547b3115f2SLuciano Coelho 		return ret;
5557b3115f2SLuciano Coelho 
5567b3115f2SLuciano Coelho 	/* initialize Tx power */
5577b3115f2SLuciano Coelho 	ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level);
5587b3115f2SLuciano Coelho 	if (ret < 0)
5597b3115f2SLuciano Coelho 		return ret;
5607b3115f2SLuciano Coelho 
5618cf77e17SEliad Peller 	if (wl->radar_debug_mode)
5628cf77e17SEliad Peller 		wlcore_cmd_generic_cfg(wl, wlvif,
5638cf77e17SEliad Peller 				       WLCORE_CFG_FEATURE_RADAR_DEBUG,
5648cf77e17SEliad Peller 				       wl->radar_debug_mode, 0);
5658cf77e17SEliad Peller 
5667b3115f2SLuciano Coelho 	return 0;
5677b3115f2SLuciano Coelho }
5687b3115f2SLuciano Coelho 
5697b3115f2SLuciano Coelho int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
5707b3115f2SLuciano Coelho {
5717b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
5727b3115f2SLuciano Coelho 	struct conf_tx_ac_category *conf_ac;
5737b3115f2SLuciano Coelho 	struct conf_tx_tid *conf_tid;
5747b3115f2SLuciano Coelho 	bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
5757b3115f2SLuciano Coelho 	int ret, i;
5767b3115f2SLuciano Coelho 
5772f18cf7cSArik Nemtsov 	/* consider all existing roles before configuring psm. */
5782f18cf7cSArik Nemtsov 
5792f18cf7cSArik Nemtsov 	if (wl->ap_count == 0 && is_ap) { /* first AP */
580e2f1e50fSKobi L 		ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
5817b3115f2SLuciano Coelho 		if (ret < 0)
5827b3115f2SLuciano Coelho 			return ret;
58371e996beSEliad Peller 
58471e996beSEliad Peller 		/* unmask ap events */
58571e996beSEliad Peller 		wl->event_mask |= wl->ap_event_mask;
58671e996beSEliad Peller 		ret = wl1271_event_unmask(wl);
58771e996beSEliad Peller 		if (ret < 0)
58871e996beSEliad Peller 			return ret;
5892f18cf7cSArik Nemtsov 	/* first STA, no APs */
5902f18cf7cSArik Nemtsov 	} else if (wl->sta_count == 0 && wl->ap_count == 0 && !is_ap) {
59166340e5bSArik Nemtsov 		u8 sta_auth = wl->conf.conn.sta_sleep_auth;
59266340e5bSArik Nemtsov 		/* Configure for power according to debugfs */
5932f18cf7cSArik Nemtsov 		if (sta_auth != WL1271_PSM_ILLEGAL)
59466340e5bSArik Nemtsov 			ret = wl1271_acx_sleep_auth(wl, sta_auth);
5957b3115f2SLuciano Coelho 		/* Configure for ELP power saving */
5962f18cf7cSArik Nemtsov 		else
5977b3115f2SLuciano Coelho 			ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
5982f18cf7cSArik Nemtsov 
5997b3115f2SLuciano Coelho 		if (ret < 0)
6007b3115f2SLuciano Coelho 			return ret;
6017b3115f2SLuciano Coelho 	}
6027b3115f2SLuciano Coelho 
6037b3115f2SLuciano Coelho 	/* Mode specific init */
6047b3115f2SLuciano Coelho 	if (is_ap) {
6057b3115f2SLuciano Coelho 		ret = wl1271_ap_hw_init(wl, wlvif);
6067b3115f2SLuciano Coelho 		if (ret < 0)
6077b3115f2SLuciano Coelho 			return ret;
6087b3115f2SLuciano Coelho 
6097b3115f2SLuciano Coelho 		ret = wl12xx_init_ap_role(wl, wlvif);
6107b3115f2SLuciano Coelho 		if (ret < 0)
6117b3115f2SLuciano Coelho 			return ret;
6127b3115f2SLuciano Coelho 	} else {
6137b3115f2SLuciano Coelho 		ret = wl1271_sta_hw_init(wl, wlvif);
6147b3115f2SLuciano Coelho 		if (ret < 0)
6157b3115f2SLuciano Coelho 			return ret;
6167b3115f2SLuciano Coelho 
6177b3115f2SLuciano Coelho 		ret = wl12xx_init_sta_role(wl, wlvif);
6187b3115f2SLuciano Coelho 		if (ret < 0)
6197b3115f2SLuciano Coelho 			return ret;
6207b3115f2SLuciano Coelho 	}
6217b3115f2SLuciano Coelho 
6227b3115f2SLuciano Coelho 	wl12xx_init_phy_vif_config(wl, wlvif);
6237b3115f2SLuciano Coelho 
6247b3115f2SLuciano Coelho 	/* Default TID/AC configuration */
6257b3115f2SLuciano Coelho 	BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
6267b3115f2SLuciano Coelho 	for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
6277b3115f2SLuciano Coelho 		conf_ac = &wl->conf.tx.ac_conf[i];
6287b3115f2SLuciano Coelho 		ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac,
6297b3115f2SLuciano Coelho 					conf_ac->cw_min, conf_ac->cw_max,
6307b3115f2SLuciano Coelho 					conf_ac->aifsn, conf_ac->tx_op_limit);
6317b3115f2SLuciano Coelho 		if (ret < 0)
6327b3115f2SLuciano Coelho 			return ret;
6337b3115f2SLuciano Coelho 
6347b3115f2SLuciano Coelho 		conf_tid = &wl->conf.tx.tid_conf[i];
6357b3115f2SLuciano Coelho 		ret = wl1271_acx_tid_cfg(wl, wlvif,
6367b3115f2SLuciano Coelho 					 conf_tid->queue_id,
6377b3115f2SLuciano Coelho 					 conf_tid->channel_type,
6387b3115f2SLuciano Coelho 					 conf_tid->tsid,
6397b3115f2SLuciano Coelho 					 conf_tid->ps_scheme,
6407b3115f2SLuciano Coelho 					 conf_tid->ack_policy,
6417b3115f2SLuciano Coelho 					 conf_tid->apsd_conf[0],
6427b3115f2SLuciano Coelho 					 conf_tid->apsd_conf[1]);
6437b3115f2SLuciano Coelho 		if (ret < 0)
6447b3115f2SLuciano Coelho 			return ret;
6457b3115f2SLuciano Coelho 	}
6467b3115f2SLuciano Coelho 
6477b3115f2SLuciano Coelho 	/* Configure HW encryption */
6487b3115f2SLuciano Coelho 	ret = wl1271_acx_feature_cfg(wl, wlvif);
6497b3115f2SLuciano Coelho 	if (ret < 0)
6507b3115f2SLuciano Coelho 		return ret;
6517b3115f2SLuciano Coelho 
6527b3115f2SLuciano Coelho 	/* Mode specific init - post mem init */
6537b3115f2SLuciano Coelho 	if (is_ap)
6547b3115f2SLuciano Coelho 		ret = wl1271_ap_hw_init_post_mem(wl, vif);
6557b3115f2SLuciano Coelho 	else
6567b3115f2SLuciano Coelho 		ret = wl1271_sta_hw_init_post_mem(wl, vif);
6577b3115f2SLuciano Coelho 
6587b3115f2SLuciano Coelho 	if (ret < 0)
6597b3115f2SLuciano Coelho 		return ret;
6607b3115f2SLuciano Coelho 
6617b3115f2SLuciano Coelho 	/* Configure initiator BA sessions policies */
6627b3115f2SLuciano Coelho 	ret = wl1271_set_ba_policies(wl, wlvif);
6637b3115f2SLuciano Coelho 	if (ret < 0)
6647b3115f2SLuciano Coelho 		return ret;
6657b3115f2SLuciano Coelho 
6668a9affc0SArik Nemtsov 	ret = wlcore_hw_init_vif(wl, wlvif);
6678a9affc0SArik Nemtsov 	if (ret < 0)
6688a9affc0SArik Nemtsov 		return ret;
6698a9affc0SArik Nemtsov 
6707b3115f2SLuciano Coelho 	return 0;
6717b3115f2SLuciano Coelho }
6727b3115f2SLuciano Coelho 
6737b3115f2SLuciano Coelho int wl1271_hw_init(struct wl1271 *wl)
6747b3115f2SLuciano Coelho {
6757b3115f2SLuciano Coelho 	int ret;
6767b3115f2SLuciano Coelho 
6779d68d1eeSLuciano Coelho 	/* Chip-specific hw init */
6789d68d1eeSLuciano Coelho 	ret = wl->ops->hw_init(wl);
6797b3115f2SLuciano Coelho 	if (ret < 0)
6807b3115f2SLuciano Coelho 		return ret;
6817b3115f2SLuciano Coelho 
6827b3115f2SLuciano Coelho 	/* Init templates */
6837b3115f2SLuciano Coelho 	ret = wl1271_init_templates_config(wl);
6847b3115f2SLuciano Coelho 	if (ret < 0)
6857b3115f2SLuciano Coelho 		return ret;
6867b3115f2SLuciano Coelho 
6877b3115f2SLuciano Coelho 	ret = wl12xx_acx_mem_cfg(wl);
6887b3115f2SLuciano Coelho 	if (ret < 0)
6897b3115f2SLuciano Coelho 		return ret;
6907b3115f2SLuciano Coelho 
6917b3115f2SLuciano Coelho 	/* Configure the FW logger */
6927b3115f2SLuciano Coelho 	ret = wl12xx_init_fwlog(wl);
6937b3115f2SLuciano Coelho 	if (ret < 0)
6947b3115f2SLuciano Coelho 		return ret;
6957b3115f2SLuciano Coelho 
6966b70e7ebSVictor Goldenshtein 	ret = wlcore_cmd_regdomain_config_locked(wl);
6976b70e7ebSVictor Goldenshtein 	if (ret < 0)
6986b70e7ebSVictor Goldenshtein 		return ret;
6996b70e7ebSVictor Goldenshtein 
7007b3115f2SLuciano Coelho 	/* Bluetooth WLAN coexistence */
7017b3115f2SLuciano Coelho 	ret = wl1271_init_pta(wl);
7027b3115f2SLuciano Coelho 	if (ret < 0)
7037b3115f2SLuciano Coelho 		return ret;
7047b3115f2SLuciano Coelho 
7057b3115f2SLuciano Coelho 	/* Default memory configuration */
7067b3115f2SLuciano Coelho 	ret = wl1271_acx_init_mem_config(wl);
7077b3115f2SLuciano Coelho 	if (ret < 0)
7087b3115f2SLuciano Coelho 		return ret;
7097b3115f2SLuciano Coelho 
7107b3115f2SLuciano Coelho 	/* RX config */
7117b3115f2SLuciano Coelho 	ret = wl12xx_init_rx_config(wl);
7127b3115f2SLuciano Coelho 	if (ret < 0)
7137b3115f2SLuciano Coelho 		goto out_free_memmap;
7147b3115f2SLuciano Coelho 
7157b3115f2SLuciano Coelho 	ret = wl1271_acx_dco_itrim_params(wl);
7167b3115f2SLuciano Coelho 	if (ret < 0)
7177b3115f2SLuciano Coelho 		goto out_free_memmap;
7187b3115f2SLuciano Coelho 
7197b3115f2SLuciano Coelho 	/* Configure TX patch complete interrupt behavior */
7207b3115f2SLuciano Coelho 	ret = wl1271_acx_tx_config_options(wl);
7217b3115f2SLuciano Coelho 	if (ret < 0)
7227b3115f2SLuciano Coelho 		goto out_free_memmap;
7237b3115f2SLuciano Coelho 
7247b3115f2SLuciano Coelho 	/* RX complete interrupt pacing */
7257b3115f2SLuciano Coelho 	ret = wl1271_acx_init_rx_interrupt(wl);
7267b3115f2SLuciano Coelho 	if (ret < 0)
7277b3115f2SLuciano Coelho 		goto out_free_memmap;
7287b3115f2SLuciano Coelho 
7297b3115f2SLuciano Coelho 	/* Energy detection */
7307b3115f2SLuciano Coelho 	ret = wl1271_init_energy_detection(wl);
7317b3115f2SLuciano Coelho 	if (ret < 0)
7327b3115f2SLuciano Coelho 		goto out_free_memmap;
7337b3115f2SLuciano Coelho 
7347b3115f2SLuciano Coelho 	/* Default fragmentation threshold */
7357b3115f2SLuciano Coelho 	ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold);
7367b3115f2SLuciano Coelho 	if (ret < 0)
7377b3115f2SLuciano Coelho 		goto out_free_memmap;
7387b3115f2SLuciano Coelho 
7397b3115f2SLuciano Coelho 	/* Enable data path */
7407b3115f2SLuciano Coelho 	ret = wl1271_cmd_data_path(wl, 1);
7417b3115f2SLuciano Coelho 	if (ret < 0)
7427b3115f2SLuciano Coelho 		goto out_free_memmap;
7437b3115f2SLuciano Coelho 
7447b3115f2SLuciano Coelho 	/* configure PM */
7457b3115f2SLuciano Coelho 	ret = wl1271_acx_pm_config(wl);
7467b3115f2SLuciano Coelho 	if (ret < 0)
7477b3115f2SLuciano Coelho 		goto out_free_memmap;
7487b3115f2SLuciano Coelho 
7497b3115f2SLuciano Coelho 	ret = wl12xx_acx_set_rate_mgmt_params(wl);
7507b3115f2SLuciano Coelho 	if (ret < 0)
7517b3115f2SLuciano Coelho 		goto out_free_memmap;
7527b3115f2SLuciano Coelho 
7537b3115f2SLuciano Coelho 	/* configure hangover */
7547b3115f2SLuciano Coelho 	ret = wl12xx_acx_config_hangover(wl);
7557b3115f2SLuciano Coelho 	if (ret < 0)
7567b3115f2SLuciano Coelho 		goto out_free_memmap;
7577b3115f2SLuciano Coelho 
7587b3115f2SLuciano Coelho 	return 0;
7597b3115f2SLuciano Coelho 
7607b3115f2SLuciano Coelho  out_free_memmap:
7617b3115f2SLuciano Coelho 	kfree(wl->target_mem_map);
7627b3115f2SLuciano Coelho 	wl->target_mem_map = NULL;
7637b3115f2SLuciano Coelho 
7647b3115f2SLuciano Coelho 	return ret;
7657b3115f2SLuciano Coelho }
766