xref: /openbmc/linux/drivers/net/wireless/ti/wlcore/init.c (revision 42ec1f82)
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,
447b3115f2SLuciano Coelho 				      CMD_TEMPL_CFG_PROBE_REQ_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,
517b3115f2SLuciano Coelho 				      CMD_TEMPL_CFG_PROBE_REQ_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,
593df74f46SYoni Divinsky 					      CMD_TEMPL_APP_PROBE_REQ_2_4, NULL,
603df74f46SYoni Divinsky 					      WL1271_CMD_TEMPL_MAX_SIZE,
613df74f46SYoni Divinsky 					      0, WL1271_RATE_AUTOMATIC);
623df74f46SYoni Divinsky 		if (ret < 0)
633df74f46SYoni Divinsky 			return ret;
643df74f46SYoni Divinsky 
653df74f46SYoni Divinsky 		ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
663df74f46SYoni Divinsky 					      CMD_TEMPL_APP_PROBE_REQ_5, NULL,
673df74f46SYoni Divinsky 					      WL1271_CMD_TEMPL_MAX_SIZE,
683df74f46SYoni Divinsky 					      0, WL1271_RATE_AUTOMATIC);
693df74f46SYoni Divinsky 		if (ret < 0)
703df74f46SYoni Divinsky 			return ret;
713df74f46SYoni Divinsky 	}
723df74f46SYoni Divinsky 
737b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
747b3115f2SLuciano Coelho 				      CMD_TEMPL_NULL_DATA, NULL,
757b3115f2SLuciano Coelho 				      sizeof(struct wl12xx_null_data_template),
767b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
777b3115f2SLuciano Coelho 	if (ret < 0)
787b3115f2SLuciano Coelho 		return ret;
797b3115f2SLuciano Coelho 
807b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
817b3115f2SLuciano Coelho 				      CMD_TEMPL_PS_POLL, NULL,
827b3115f2SLuciano Coelho 				      sizeof(struct wl12xx_ps_poll_template),
837b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
847b3115f2SLuciano Coelho 	if (ret < 0)
857b3115f2SLuciano Coelho 		return ret;
867b3115f2SLuciano Coelho 
877b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
887b3115f2SLuciano Coelho 				      CMD_TEMPL_QOS_NULL_DATA, NULL,
897b3115f2SLuciano Coelho 				      sizeof
907b3115f2SLuciano Coelho 				      (struct ieee80211_qos_hdr),
917b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
927b3115f2SLuciano Coelho 	if (ret < 0)
937b3115f2SLuciano Coelho 		return ret;
947b3115f2SLuciano Coelho 
957b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
967b3115f2SLuciano Coelho 				      CMD_TEMPL_PROBE_RESPONSE, NULL,
977b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_DFLT_SIZE,
987b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
997b3115f2SLuciano Coelho 	if (ret < 0)
1007b3115f2SLuciano Coelho 		return ret;
1017b3115f2SLuciano Coelho 
1027b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1037b3115f2SLuciano Coelho 				      CMD_TEMPL_BEACON, NULL,
1047b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_DFLT_SIZE,
1057b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1067b3115f2SLuciano Coelho 	if (ret < 0)
1077b3115f2SLuciano Coelho 		return ret;
1087b3115f2SLuciano Coelho 
1097b3115f2SLuciano Coelho 	max_size = sizeof(struct wl12xx_arp_rsp_template) +
1107b3115f2SLuciano Coelho 		   WL1271_EXTRA_SPACE_MAX;
1117b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1127b3115f2SLuciano Coelho 				      CMD_TEMPL_ARP_RSP, NULL,
1137b3115f2SLuciano Coelho 				      max_size,
1147b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1157b3115f2SLuciano Coelho 	if (ret < 0)
1167b3115f2SLuciano Coelho 		return ret;
1177b3115f2SLuciano Coelho 
1187b3115f2SLuciano Coelho 	/*
1197b3115f2SLuciano Coelho 	 * Put very large empty placeholders for all templates. These
1207b3115f2SLuciano Coelho 	 * reserve memory for later.
1217b3115f2SLuciano Coelho 	 */
1227b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1237b3115f2SLuciano Coelho 				      CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
1247b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_MAX_SIZE,
1257b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1267b3115f2SLuciano Coelho 	if (ret < 0)
1277b3115f2SLuciano Coelho 		return ret;
1287b3115f2SLuciano Coelho 
1297b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1307b3115f2SLuciano Coelho 				      CMD_TEMPL_AP_BEACON, NULL,
1317b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_MAX_SIZE,
1327b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1337b3115f2SLuciano Coelho 	if (ret < 0)
1347b3115f2SLuciano Coelho 		return ret;
1357b3115f2SLuciano Coelho 
1367b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1377b3115f2SLuciano Coelho 				      CMD_TEMPL_DEAUTH_AP, NULL,
1387b3115f2SLuciano Coelho 				      sizeof
1397b3115f2SLuciano Coelho 				      (struct wl12xx_disconn_template),
1407b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1417b3115f2SLuciano Coelho 	if (ret < 0)
1427b3115f2SLuciano Coelho 		return ret;
1437b3115f2SLuciano Coelho 
144001e39a8SEliad Peller 	for (i = 0; i < WLCORE_MAX_KLV_TEMPLATES; i++) {
1457b3115f2SLuciano Coelho 		ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1467b3115f2SLuciano Coelho 					      CMD_TEMPL_KLV, NULL,
1477b3115f2SLuciano Coelho 					      sizeof(struct ieee80211_qos_hdr),
1487b3115f2SLuciano Coelho 					      i, WL1271_RATE_AUTOMATIC);
1497b3115f2SLuciano Coelho 		if (ret < 0)
1507b3115f2SLuciano Coelho 			return ret;
1517b3115f2SLuciano Coelho 	}
1527b3115f2SLuciano Coelho 
1537b3115f2SLuciano Coelho 	return 0;
1547b3115f2SLuciano Coelho }
1557b3115f2SLuciano Coelho 
1567b3115f2SLuciano Coelho static int wl1271_ap_init_deauth_template(struct wl1271 *wl,
1577b3115f2SLuciano Coelho 					  struct wl12xx_vif *wlvif)
1587b3115f2SLuciano Coelho {
1597b3115f2SLuciano Coelho 	struct wl12xx_disconn_template *tmpl;
1607b3115f2SLuciano Coelho 	int ret;
1617b3115f2SLuciano Coelho 	u32 rate;
1627b3115f2SLuciano Coelho 
1637b3115f2SLuciano Coelho 	tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
1647b3115f2SLuciano Coelho 	if (!tmpl) {
1657b3115f2SLuciano Coelho 		ret = -ENOMEM;
1667b3115f2SLuciano Coelho 		goto out;
1677b3115f2SLuciano Coelho 	}
1687b3115f2SLuciano Coelho 
1697b3115f2SLuciano Coelho 	tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
1707b3115f2SLuciano Coelho 					     IEEE80211_STYPE_DEAUTH);
1717b3115f2SLuciano Coelho 
1727b3115f2SLuciano Coelho 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
1737b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
1747b3115f2SLuciano Coelho 				      CMD_TEMPL_DEAUTH_AP,
1757b3115f2SLuciano Coelho 				      tmpl, sizeof(*tmpl), 0, rate);
1767b3115f2SLuciano Coelho 
1777b3115f2SLuciano Coelho out:
1787b3115f2SLuciano Coelho 	kfree(tmpl);
1797b3115f2SLuciano Coelho 	return ret;
1807b3115f2SLuciano Coelho }
1817b3115f2SLuciano Coelho 
1827b3115f2SLuciano Coelho static int wl1271_ap_init_null_template(struct wl1271 *wl,
1837b3115f2SLuciano Coelho 					struct ieee80211_vif *vif)
1847b3115f2SLuciano Coelho {
1857b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
1867b3115f2SLuciano Coelho 	struct ieee80211_hdr_3addr *nullfunc;
1877b3115f2SLuciano Coelho 	int ret;
1887b3115f2SLuciano Coelho 	u32 rate;
1897b3115f2SLuciano Coelho 
1907b3115f2SLuciano Coelho 	nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
1917b3115f2SLuciano Coelho 	if (!nullfunc) {
1927b3115f2SLuciano Coelho 		ret = -ENOMEM;
1937b3115f2SLuciano Coelho 		goto out;
1947b3115f2SLuciano Coelho 	}
1957b3115f2SLuciano Coelho 
1967b3115f2SLuciano Coelho 	nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
1977b3115f2SLuciano Coelho 					      IEEE80211_STYPE_NULLFUNC |
1987b3115f2SLuciano Coelho 					      IEEE80211_FCTL_FROMDS);
1997b3115f2SLuciano Coelho 
2007b3115f2SLuciano Coelho 	/* nullfunc->addr1 is filled by FW */
2017b3115f2SLuciano Coelho 
2027b3115f2SLuciano Coelho 	memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
2037b3115f2SLuciano Coelho 	memcpy(nullfunc->addr3, vif->addr, ETH_ALEN);
2047b3115f2SLuciano Coelho 
2057b3115f2SLuciano Coelho 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2067b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
2077b3115f2SLuciano Coelho 				      CMD_TEMPL_NULL_DATA, nullfunc,
2087b3115f2SLuciano Coelho 				      sizeof(*nullfunc), 0, rate);
2097b3115f2SLuciano Coelho 
2107b3115f2SLuciano Coelho out:
2117b3115f2SLuciano Coelho 	kfree(nullfunc);
2127b3115f2SLuciano Coelho 	return ret;
2137b3115f2SLuciano Coelho }
2147b3115f2SLuciano Coelho 
2157b3115f2SLuciano Coelho static int wl1271_ap_init_qos_null_template(struct wl1271 *wl,
2167b3115f2SLuciano Coelho 					    struct ieee80211_vif *vif)
2177b3115f2SLuciano Coelho {
2187b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2197b3115f2SLuciano Coelho 	struct ieee80211_qos_hdr *qosnull;
2207b3115f2SLuciano Coelho 	int ret;
2217b3115f2SLuciano Coelho 	u32 rate;
2227b3115f2SLuciano Coelho 
2237b3115f2SLuciano Coelho 	qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
2247b3115f2SLuciano Coelho 	if (!qosnull) {
2257b3115f2SLuciano Coelho 		ret = -ENOMEM;
2267b3115f2SLuciano Coelho 		goto out;
2277b3115f2SLuciano Coelho 	}
2287b3115f2SLuciano Coelho 
2297b3115f2SLuciano Coelho 	qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
2307b3115f2SLuciano Coelho 					     IEEE80211_STYPE_QOS_NULLFUNC |
2317b3115f2SLuciano Coelho 					     IEEE80211_FCTL_FROMDS);
2327b3115f2SLuciano Coelho 
2337b3115f2SLuciano Coelho 	/* qosnull->addr1 is filled by FW */
2347b3115f2SLuciano Coelho 
2357b3115f2SLuciano Coelho 	memcpy(qosnull->addr2, vif->addr, ETH_ALEN);
2367b3115f2SLuciano Coelho 	memcpy(qosnull->addr3, vif->addr, ETH_ALEN);
2377b3115f2SLuciano Coelho 
2387b3115f2SLuciano Coelho 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2397b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
2407b3115f2SLuciano Coelho 				      CMD_TEMPL_QOS_NULL_DATA, qosnull,
2417b3115f2SLuciano Coelho 				      sizeof(*qosnull), 0, rate);
2427b3115f2SLuciano Coelho 
2437b3115f2SLuciano Coelho out:
2447b3115f2SLuciano Coelho 	kfree(qosnull);
2457b3115f2SLuciano Coelho 	return ret;
2467b3115f2SLuciano Coelho }
2477b3115f2SLuciano Coelho 
2487b3115f2SLuciano Coelho static int wl12xx_init_rx_config(struct wl1271 *wl)
2497b3115f2SLuciano Coelho {
2507b3115f2SLuciano Coelho 	int ret;
2517b3115f2SLuciano Coelho 
2527b3115f2SLuciano Coelho 	ret = wl1271_acx_rx_msdu_life_time(wl);
2537b3115f2SLuciano Coelho 	if (ret < 0)
2547b3115f2SLuciano Coelho 		return ret;
2557b3115f2SLuciano Coelho 
2567b3115f2SLuciano Coelho 	return 0;
2577b3115f2SLuciano Coelho }
2587b3115f2SLuciano Coelho 
2597b3115f2SLuciano Coelho static int wl12xx_init_phy_vif_config(struct wl1271 *wl,
2607b3115f2SLuciano Coelho 					    struct wl12xx_vif *wlvif)
2617b3115f2SLuciano Coelho {
2627b3115f2SLuciano Coelho 	int ret;
2637b3115f2SLuciano Coelho 
2647b3115f2SLuciano Coelho 	ret = wl1271_acx_slot(wl, wlvif, DEFAULT_SLOT_TIME);
2657b3115f2SLuciano Coelho 	if (ret < 0)
2667b3115f2SLuciano Coelho 		return ret;
2677b3115f2SLuciano Coelho 
2687b3115f2SLuciano Coelho 	ret = wl1271_acx_service_period_timeout(wl, wlvif);
2697b3115f2SLuciano Coelho 	if (ret < 0)
2707b3115f2SLuciano Coelho 		return ret;
2717b3115f2SLuciano Coelho 
2727b3115f2SLuciano Coelho 	ret = wl1271_acx_rts_threshold(wl, wlvif, wl->hw->wiphy->rts_threshold);
2737b3115f2SLuciano Coelho 	if (ret < 0)
2747b3115f2SLuciano Coelho 		return ret;
2757b3115f2SLuciano Coelho 
2767b3115f2SLuciano Coelho 	return 0;
2777b3115f2SLuciano Coelho }
2787b3115f2SLuciano Coelho 
2797b3115f2SLuciano Coelho static int wl1271_init_sta_beacon_filter(struct wl1271 *wl,
2807b3115f2SLuciano Coelho 					 struct wl12xx_vif *wlvif)
2817b3115f2SLuciano Coelho {
2827b3115f2SLuciano Coelho 	int ret;
2837b3115f2SLuciano Coelho 
2847b3115f2SLuciano Coelho 	ret = wl1271_acx_beacon_filter_table(wl, wlvif);
2857b3115f2SLuciano Coelho 	if (ret < 0)
2867b3115f2SLuciano Coelho 		return ret;
2877b3115f2SLuciano Coelho 
2887b3115f2SLuciano Coelho 	/* enable beacon filtering */
2897b3115f2SLuciano Coelho 	ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
2907b3115f2SLuciano Coelho 	if (ret < 0)
2917b3115f2SLuciano Coelho 		return ret;
2927b3115f2SLuciano Coelho 
2937b3115f2SLuciano Coelho 	return 0;
2947b3115f2SLuciano Coelho }
2957b3115f2SLuciano Coelho 
2967b3115f2SLuciano Coelho int wl1271_init_pta(struct wl1271 *wl)
2977b3115f2SLuciano Coelho {
2987b3115f2SLuciano Coelho 	int ret;
2997b3115f2SLuciano Coelho 
3007b3115f2SLuciano Coelho 	ret = wl12xx_acx_sg_cfg(wl);
3017b3115f2SLuciano Coelho 	if (ret < 0)
3027b3115f2SLuciano Coelho 		return ret;
3037b3115f2SLuciano Coelho 
3047b3115f2SLuciano Coelho 	ret = wl1271_acx_sg_enable(wl, wl->sg_enabled);
3057b3115f2SLuciano Coelho 	if (ret < 0)
3067b3115f2SLuciano Coelho 		return ret;
3077b3115f2SLuciano Coelho 
3087b3115f2SLuciano Coelho 	return 0;
3097b3115f2SLuciano Coelho }
3107b3115f2SLuciano Coelho 
3117b3115f2SLuciano Coelho int wl1271_init_energy_detection(struct wl1271 *wl)
3127b3115f2SLuciano Coelho {
3137b3115f2SLuciano Coelho 	int ret;
3147b3115f2SLuciano Coelho 
3157b3115f2SLuciano Coelho 	ret = wl1271_acx_cca_threshold(wl);
3167b3115f2SLuciano Coelho 	if (ret < 0)
3177b3115f2SLuciano Coelho 		return ret;
3187b3115f2SLuciano Coelho 
3197b3115f2SLuciano Coelho 	return 0;
3207b3115f2SLuciano Coelho }
3217b3115f2SLuciano Coelho 
3227b3115f2SLuciano Coelho static int wl1271_init_beacon_broadcast(struct wl1271 *wl,
3237b3115f2SLuciano Coelho 					struct wl12xx_vif *wlvif)
3247b3115f2SLuciano Coelho {
3257b3115f2SLuciano Coelho 	int ret;
3267b3115f2SLuciano Coelho 
3277b3115f2SLuciano Coelho 	ret = wl1271_acx_bcn_dtim_options(wl, wlvif);
3287b3115f2SLuciano Coelho 	if (ret < 0)
3297b3115f2SLuciano Coelho 		return ret;
3307b3115f2SLuciano Coelho 
3317b3115f2SLuciano Coelho 	return 0;
3327b3115f2SLuciano Coelho }
3337b3115f2SLuciano Coelho 
3347b3115f2SLuciano Coelho static int wl12xx_init_fwlog(struct wl1271 *wl)
3357b3115f2SLuciano Coelho {
3367b3115f2SLuciano Coelho 	int ret;
3377b3115f2SLuciano Coelho 
3386f7dd16cSLuciano Coelho 	if (wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED)
3397b3115f2SLuciano Coelho 		return 0;
3407b3115f2SLuciano Coelho 
3417b3115f2SLuciano Coelho 	ret = wl12xx_cmd_config_fwlog(wl);
3427b3115f2SLuciano Coelho 	if (ret < 0)
3437b3115f2SLuciano Coelho 		return ret;
3447b3115f2SLuciano Coelho 
3457b3115f2SLuciano Coelho 	return 0;
3467b3115f2SLuciano Coelho }
3477b3115f2SLuciano Coelho 
3487b3115f2SLuciano Coelho /* generic sta initialization (non vif-specific) */
3497b3115f2SLuciano Coelho static int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
3507b3115f2SLuciano Coelho {
3517b3115f2SLuciano Coelho 	int ret;
3527b3115f2SLuciano Coelho 
3537b3115f2SLuciano Coelho 	/* PS config */
3547b3115f2SLuciano Coelho 	ret = wl12xx_acx_config_ps(wl, wlvif);
3557b3115f2SLuciano Coelho 	if (ret < 0)
3567b3115f2SLuciano Coelho 		return ret;
3577b3115f2SLuciano Coelho 
3587b3115f2SLuciano Coelho 	/* FM WLAN coexistence */
3597b3115f2SLuciano Coelho 	ret = wl1271_acx_fm_coex(wl);
3607b3115f2SLuciano Coelho 	if (ret < 0)
3617b3115f2SLuciano Coelho 		return ret;
3627b3115f2SLuciano Coelho 
3637b3115f2SLuciano Coelho 	ret = wl1271_acx_sta_rate_policies(wl, wlvif);
3647b3115f2SLuciano Coelho 	if (ret < 0)
3657b3115f2SLuciano Coelho 		return ret;
3667b3115f2SLuciano Coelho 
3677b3115f2SLuciano Coelho 	return 0;
3687b3115f2SLuciano Coelho }
3697b3115f2SLuciano Coelho 
3707b3115f2SLuciano Coelho static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl,
3717b3115f2SLuciano Coelho 				       struct ieee80211_vif *vif)
3727b3115f2SLuciano Coelho {
3737b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
374001e39a8SEliad Peller 	int ret;
3757b3115f2SLuciano Coelho 
3767b3115f2SLuciano Coelho 	/* disable the keep-alive feature */
3777b3115f2SLuciano Coelho 	ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
3787b3115f2SLuciano Coelho 	if (ret < 0)
3797b3115f2SLuciano Coelho 		return ret;
3807b3115f2SLuciano Coelho 
3817b3115f2SLuciano Coelho 	return 0;
3827b3115f2SLuciano Coelho }
3837b3115f2SLuciano Coelho 
3847b3115f2SLuciano Coelho /* generic ap initialization (non vif-specific) */
3857b3115f2SLuciano Coelho static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
3867b3115f2SLuciano Coelho {
3877b3115f2SLuciano Coelho 	int ret;
3887b3115f2SLuciano Coelho 
3897b3115f2SLuciano Coelho 	ret = wl1271_init_ap_rates(wl, wlvif);
3907b3115f2SLuciano Coelho 	if (ret < 0)
3917b3115f2SLuciano Coelho 		return ret;
3927b3115f2SLuciano Coelho 
3937b3115f2SLuciano Coelho 	return 0;
3947b3115f2SLuciano Coelho }
3957b3115f2SLuciano Coelho 
3967b3115f2SLuciano Coelho int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif)
3977b3115f2SLuciano Coelho {
3987b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3997b3115f2SLuciano Coelho 	int ret;
4007b3115f2SLuciano Coelho 
4017b3115f2SLuciano Coelho 	ret = wl1271_ap_init_deauth_template(wl, wlvif);
4027b3115f2SLuciano Coelho 	if (ret < 0)
4037b3115f2SLuciano Coelho 		return ret;
4047b3115f2SLuciano Coelho 
4057b3115f2SLuciano Coelho 	ret = wl1271_ap_init_null_template(wl, vif);
4067b3115f2SLuciano Coelho 	if (ret < 0)
4077b3115f2SLuciano Coelho 		return ret;
4087b3115f2SLuciano Coelho 
4097b3115f2SLuciano Coelho 	ret = wl1271_ap_init_qos_null_template(wl, vif);
4107b3115f2SLuciano Coelho 	if (ret < 0)
4117b3115f2SLuciano Coelho 		return ret;
4127b3115f2SLuciano Coelho 
4137b3115f2SLuciano Coelho 	/*
4147b3115f2SLuciano Coelho 	 * when operating as AP we want to receive external beacons for
4157b3115f2SLuciano Coelho 	 * configuring ERP protection.
4167b3115f2SLuciano Coelho 	 */
4177b3115f2SLuciano Coelho 	ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
4187b3115f2SLuciano Coelho 	if (ret < 0)
4197b3115f2SLuciano Coelho 		return ret;
4207b3115f2SLuciano Coelho 
4217b3115f2SLuciano Coelho 	return 0;
4227b3115f2SLuciano Coelho }
4237b3115f2SLuciano Coelho 
4247b3115f2SLuciano Coelho static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl,
4257b3115f2SLuciano Coelho 				      struct ieee80211_vif *vif)
4267b3115f2SLuciano Coelho {
4277b3115f2SLuciano Coelho 	return wl1271_ap_init_templates(wl, vif);
4287b3115f2SLuciano Coelho }
4297b3115f2SLuciano Coelho 
4307b3115f2SLuciano Coelho int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
4317b3115f2SLuciano Coelho {
4327b3115f2SLuciano Coelho 	int i, ret;
4337b3115f2SLuciano Coelho 	struct conf_tx_rate_class rc;
4347b3115f2SLuciano Coelho 	u32 supported_rates;
4357b3115f2SLuciano Coelho 
4367b3115f2SLuciano Coelho 	wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x",
4377b3115f2SLuciano Coelho 		     wlvif->basic_rate_set);
4387b3115f2SLuciano Coelho 
4397b3115f2SLuciano Coelho 	if (wlvif->basic_rate_set == 0)
4407b3115f2SLuciano Coelho 		return -EINVAL;
4417b3115f2SLuciano Coelho 
4427b3115f2SLuciano Coelho 	rc.enabled_rates = wlvif->basic_rate_set;
4437b3115f2SLuciano Coelho 	rc.long_retry_limit = 10;
4447b3115f2SLuciano Coelho 	rc.short_retry_limit = 10;
4457b3115f2SLuciano Coelho 	rc.aflags = 0;
4467b3115f2SLuciano Coelho 	ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx);
4477b3115f2SLuciano Coelho 	if (ret < 0)
4487b3115f2SLuciano Coelho 		return ret;
4497b3115f2SLuciano Coelho 
4507b3115f2SLuciano Coelho 	/* use the min basic rate for AP broadcast/multicast */
4517b3115f2SLuciano Coelho 	rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4527b3115f2SLuciano Coelho 	rc.short_retry_limit = 10;
4537b3115f2SLuciano Coelho 	rc.long_retry_limit = 10;
4547b3115f2SLuciano Coelho 	rc.aflags = 0;
4557b3115f2SLuciano Coelho 	ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.bcast_rate_idx);
4567b3115f2SLuciano Coelho 	if (ret < 0)
4577b3115f2SLuciano Coelho 		return ret;
4587b3115f2SLuciano Coelho 
4597b3115f2SLuciano Coelho 	/*
4607b3115f2SLuciano Coelho 	 * If the basic rates contain OFDM rates, use OFDM only
4617b3115f2SLuciano Coelho 	 * rates for unicast TX as well. Else use all supported rates.
4627b3115f2SLuciano Coelho 	 */
4637b3115f2SLuciano Coelho 	if ((wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
4647b3115f2SLuciano Coelho 		supported_rates = CONF_TX_OFDM_RATES;
4657b3115f2SLuciano Coelho 	else
46642ec1f82SEliad Peller 		supported_rates = CONF_TX_ENABLED_RATES;
4677b3115f2SLuciano Coelho 
4687b3115f2SLuciano Coelho 	/* unconditionally enable HT rates */
4697b3115f2SLuciano Coelho 	supported_rates |= CONF_TX_MCS_RATES;
4707b3115f2SLuciano Coelho 
471ebc7e57dSArik Nemtsov 	/* get extra MIMO or wide-chan rates where the HW supports it */
472ebc7e57dSArik Nemtsov 	supported_rates |= wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
473ebc7e57dSArik Nemtsov 
4747b3115f2SLuciano Coelho 	/* configure unicast TX rate classes */
4757b3115f2SLuciano Coelho 	for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
4767b3115f2SLuciano Coelho 		rc.enabled_rates = supported_rates;
4777b3115f2SLuciano Coelho 		rc.short_retry_limit = 10;
4787b3115f2SLuciano Coelho 		rc.long_retry_limit = 10;
4797b3115f2SLuciano Coelho 		rc.aflags = 0;
4807b3115f2SLuciano Coelho 		ret = wl1271_acx_ap_rate_policy(wl, &rc,
4817b3115f2SLuciano Coelho 						wlvif->ap.ucast_rate_idx[i]);
4827b3115f2SLuciano Coelho 		if (ret < 0)
4837b3115f2SLuciano Coelho 			return ret;
4847b3115f2SLuciano Coelho 	}
4857b3115f2SLuciano Coelho 
4867b3115f2SLuciano Coelho 	return 0;
4877b3115f2SLuciano Coelho }
4887b3115f2SLuciano Coelho 
4897b3115f2SLuciano Coelho static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
4907b3115f2SLuciano Coelho {
4917b3115f2SLuciano Coelho 	/* Reset the BA RX indicators */
4927b3115f2SLuciano Coelho 	wlvif->ba_allowed = true;
4937b3115f2SLuciano Coelho 	wl->ba_rx_session_count = 0;
4947b3115f2SLuciano Coelho 
4957b3115f2SLuciano Coelho 	/* BA is supported in STA/AP modes */
4967b3115f2SLuciano Coelho 	if (wlvif->bss_type != BSS_TYPE_AP_BSS &&
4977b3115f2SLuciano Coelho 	    wlvif->bss_type != BSS_TYPE_STA_BSS) {
4987b3115f2SLuciano Coelho 		wlvif->ba_support = false;
4997b3115f2SLuciano Coelho 		return 0;
5007b3115f2SLuciano Coelho 	}
5017b3115f2SLuciano Coelho 
5027b3115f2SLuciano Coelho 	wlvif->ba_support = true;
5037b3115f2SLuciano Coelho 
5047b3115f2SLuciano Coelho 	/* 802.11n initiator BA session setting */
5057b3115f2SLuciano Coelho 	return wl12xx_acx_set_ba_initiator_policy(wl, wlvif);
5067b3115f2SLuciano Coelho }
5077b3115f2SLuciano Coelho 
5087b3115f2SLuciano Coelho /* vif-specifc initialization */
5097b3115f2SLuciano Coelho static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
5107b3115f2SLuciano Coelho {
5117b3115f2SLuciano Coelho 	int ret;
5127b3115f2SLuciano Coelho 
5137b3115f2SLuciano Coelho 	ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0);
5147b3115f2SLuciano Coelho 	if (ret < 0)
5157b3115f2SLuciano Coelho 		return ret;
5167b3115f2SLuciano Coelho 
5177b3115f2SLuciano Coelho 	/* Initialize connection monitoring thresholds */
5187b3115f2SLuciano Coelho 	ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
5197b3115f2SLuciano Coelho 	if (ret < 0)
5207b3115f2SLuciano Coelho 		return ret;
5217b3115f2SLuciano Coelho 
5227b3115f2SLuciano Coelho 	/* Beacon filtering */
5237b3115f2SLuciano Coelho 	ret = wl1271_init_sta_beacon_filter(wl, wlvif);
5247b3115f2SLuciano Coelho 	if (ret < 0)
5257b3115f2SLuciano Coelho 		return ret;
5267b3115f2SLuciano Coelho 
5277b3115f2SLuciano Coelho 	/* Beacons and broadcast settings */
5287b3115f2SLuciano Coelho 	ret = wl1271_init_beacon_broadcast(wl, wlvif);
5297b3115f2SLuciano Coelho 	if (ret < 0)
5307b3115f2SLuciano Coelho 		return ret;
5317b3115f2SLuciano Coelho 
5327b3115f2SLuciano Coelho 	/* Configure rssi/snr averaging weights */
5337b3115f2SLuciano Coelho 	ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif);
5347b3115f2SLuciano Coelho 	if (ret < 0)
5357b3115f2SLuciano Coelho 		return ret;
5367b3115f2SLuciano Coelho 
5377b3115f2SLuciano Coelho 	return 0;
5387b3115f2SLuciano Coelho }
5397b3115f2SLuciano Coelho 
5407b3115f2SLuciano Coelho /* vif-specific intialization */
5417b3115f2SLuciano Coelho static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
5427b3115f2SLuciano Coelho {
5437b3115f2SLuciano Coelho 	int ret;
5447b3115f2SLuciano Coelho 
5457b3115f2SLuciano Coelho 	ret = wl1271_acx_ap_max_tx_retry(wl, wlvif);
5467b3115f2SLuciano Coelho 	if (ret < 0)
5477b3115f2SLuciano Coelho 		return ret;
5487b3115f2SLuciano Coelho 
5497b3115f2SLuciano Coelho 	/* initialize Tx power */
5507b3115f2SLuciano Coelho 	ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level);
5517b3115f2SLuciano Coelho 	if (ret < 0)
5527b3115f2SLuciano Coelho 		return ret;
5537b3115f2SLuciano Coelho 
5547b3115f2SLuciano Coelho 	return 0;
5557b3115f2SLuciano Coelho }
5567b3115f2SLuciano Coelho 
5577b3115f2SLuciano Coelho int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
5587b3115f2SLuciano Coelho {
5597b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
5607b3115f2SLuciano Coelho 	struct conf_tx_ac_category *conf_ac;
5617b3115f2SLuciano Coelho 	struct conf_tx_tid *conf_tid;
5627b3115f2SLuciano Coelho 	bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
5637b3115f2SLuciano Coelho 	int ret, i;
5647b3115f2SLuciano Coelho 
5652f18cf7cSArik Nemtsov 	/* consider all existing roles before configuring psm. */
5662f18cf7cSArik Nemtsov 
5672f18cf7cSArik Nemtsov 	if (wl->ap_count == 0 && is_ap) { /* first AP */
5687b3115f2SLuciano Coelho 		/* Configure for power always on */
5697b3115f2SLuciano Coelho 		ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
5707b3115f2SLuciano Coelho 		if (ret < 0)
5717b3115f2SLuciano Coelho 			return ret;
5722f18cf7cSArik Nemtsov 	/* first STA, no APs */
5732f18cf7cSArik Nemtsov 	} else if (wl->sta_count == 0 && wl->ap_count == 0 && !is_ap) {
57466340e5bSArik Nemtsov 		u8 sta_auth = wl->conf.conn.sta_sleep_auth;
57566340e5bSArik Nemtsov 		/* Configure for power according to debugfs */
5762f18cf7cSArik Nemtsov 		if (sta_auth != WL1271_PSM_ILLEGAL)
57766340e5bSArik Nemtsov 			ret = wl1271_acx_sleep_auth(wl, sta_auth);
578441101f6SLuciano Coelho 		/* Configure for power always on */
5792f18cf7cSArik Nemtsov 		else if (wl->quirks & WLCORE_QUIRK_NO_ELP)
580441101f6SLuciano Coelho 			ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
5817b3115f2SLuciano Coelho 		/* Configure for ELP power saving */
5822f18cf7cSArik Nemtsov 		else
5837b3115f2SLuciano Coelho 			ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
5842f18cf7cSArik Nemtsov 
5857b3115f2SLuciano Coelho 		if (ret < 0)
5867b3115f2SLuciano Coelho 			return ret;
5877b3115f2SLuciano Coelho 	}
5887b3115f2SLuciano Coelho 
5897b3115f2SLuciano Coelho 	/* Mode specific init */
5907b3115f2SLuciano Coelho 	if (is_ap) {
5917b3115f2SLuciano Coelho 		ret = wl1271_ap_hw_init(wl, wlvif);
5927b3115f2SLuciano Coelho 		if (ret < 0)
5937b3115f2SLuciano Coelho 			return ret;
5947b3115f2SLuciano Coelho 
5957b3115f2SLuciano Coelho 		ret = wl12xx_init_ap_role(wl, wlvif);
5967b3115f2SLuciano Coelho 		if (ret < 0)
5977b3115f2SLuciano Coelho 			return ret;
5987b3115f2SLuciano Coelho 	} else {
5997b3115f2SLuciano Coelho 		ret = wl1271_sta_hw_init(wl, wlvif);
6007b3115f2SLuciano Coelho 		if (ret < 0)
6017b3115f2SLuciano Coelho 			return ret;
6027b3115f2SLuciano Coelho 
6037b3115f2SLuciano Coelho 		ret = wl12xx_init_sta_role(wl, wlvif);
6047b3115f2SLuciano Coelho 		if (ret < 0)
6057b3115f2SLuciano Coelho 			return ret;
6067b3115f2SLuciano Coelho 	}
6077b3115f2SLuciano Coelho 
6087b3115f2SLuciano Coelho 	wl12xx_init_phy_vif_config(wl, wlvif);
6097b3115f2SLuciano Coelho 
6107b3115f2SLuciano Coelho 	/* Default TID/AC configuration */
6117b3115f2SLuciano Coelho 	BUG_ON(wl->conf.tx.tid_conf_count != wl->conf.tx.ac_conf_count);
6127b3115f2SLuciano Coelho 	for (i = 0; i < wl->conf.tx.tid_conf_count; i++) {
6137b3115f2SLuciano Coelho 		conf_ac = &wl->conf.tx.ac_conf[i];
6147b3115f2SLuciano Coelho 		ret = wl1271_acx_ac_cfg(wl, wlvif, conf_ac->ac,
6157b3115f2SLuciano Coelho 					conf_ac->cw_min, conf_ac->cw_max,
6167b3115f2SLuciano Coelho 					conf_ac->aifsn, conf_ac->tx_op_limit);
6177b3115f2SLuciano Coelho 		if (ret < 0)
6187b3115f2SLuciano Coelho 			return ret;
6197b3115f2SLuciano Coelho 
6207b3115f2SLuciano Coelho 		conf_tid = &wl->conf.tx.tid_conf[i];
6217b3115f2SLuciano Coelho 		ret = wl1271_acx_tid_cfg(wl, wlvif,
6227b3115f2SLuciano Coelho 					 conf_tid->queue_id,
6237b3115f2SLuciano Coelho 					 conf_tid->channel_type,
6247b3115f2SLuciano Coelho 					 conf_tid->tsid,
6257b3115f2SLuciano Coelho 					 conf_tid->ps_scheme,
6267b3115f2SLuciano Coelho 					 conf_tid->ack_policy,
6277b3115f2SLuciano Coelho 					 conf_tid->apsd_conf[0],
6287b3115f2SLuciano Coelho 					 conf_tid->apsd_conf[1]);
6297b3115f2SLuciano Coelho 		if (ret < 0)
6307b3115f2SLuciano Coelho 			return ret;
6317b3115f2SLuciano Coelho 	}
6327b3115f2SLuciano Coelho 
6337b3115f2SLuciano Coelho 	/* Configure HW encryption */
6347b3115f2SLuciano Coelho 	ret = wl1271_acx_feature_cfg(wl, wlvif);
6357b3115f2SLuciano Coelho 	if (ret < 0)
6367b3115f2SLuciano Coelho 		return ret;
6377b3115f2SLuciano Coelho 
6387b3115f2SLuciano Coelho 	/* Mode specific init - post mem init */
6397b3115f2SLuciano Coelho 	if (is_ap)
6407b3115f2SLuciano Coelho 		ret = wl1271_ap_hw_init_post_mem(wl, vif);
6417b3115f2SLuciano Coelho 	else
6427b3115f2SLuciano Coelho 		ret = wl1271_sta_hw_init_post_mem(wl, vif);
6437b3115f2SLuciano Coelho 
6447b3115f2SLuciano Coelho 	if (ret < 0)
6457b3115f2SLuciano Coelho 		return ret;
6467b3115f2SLuciano Coelho 
6477b3115f2SLuciano Coelho 	/* Configure initiator BA sessions policies */
6487b3115f2SLuciano Coelho 	ret = wl1271_set_ba_policies(wl, wlvif);
6497b3115f2SLuciano Coelho 	if (ret < 0)
6507b3115f2SLuciano Coelho 		return ret;
6517b3115f2SLuciano Coelho 
6528a9affc0SArik Nemtsov 	ret = wlcore_hw_init_vif(wl, wlvif);
6538a9affc0SArik Nemtsov 	if (ret < 0)
6548a9affc0SArik Nemtsov 		return ret;
6558a9affc0SArik Nemtsov 
6567b3115f2SLuciano Coelho 	return 0;
6577b3115f2SLuciano Coelho }
6587b3115f2SLuciano Coelho 
6597b3115f2SLuciano Coelho int wl1271_hw_init(struct wl1271 *wl)
6607b3115f2SLuciano Coelho {
6617b3115f2SLuciano Coelho 	int ret;
6627b3115f2SLuciano Coelho 
6639d68d1eeSLuciano Coelho 	/* Chip-specific hw init */
6649d68d1eeSLuciano Coelho 	ret = wl->ops->hw_init(wl);
6657b3115f2SLuciano Coelho 	if (ret < 0)
6667b3115f2SLuciano Coelho 		return ret;
6677b3115f2SLuciano Coelho 
6687b3115f2SLuciano Coelho 	/* Init templates */
6697b3115f2SLuciano Coelho 	ret = wl1271_init_templates_config(wl);
6707b3115f2SLuciano Coelho 	if (ret < 0)
6717b3115f2SLuciano Coelho 		return ret;
6727b3115f2SLuciano Coelho 
6737b3115f2SLuciano Coelho 	ret = wl12xx_acx_mem_cfg(wl);
6747b3115f2SLuciano Coelho 	if (ret < 0)
6757b3115f2SLuciano Coelho 		return ret;
6767b3115f2SLuciano Coelho 
6777b3115f2SLuciano Coelho 	/* Configure the FW logger */
6787b3115f2SLuciano Coelho 	ret = wl12xx_init_fwlog(wl);
6797b3115f2SLuciano Coelho 	if (ret < 0)
6807b3115f2SLuciano Coelho 		return ret;
6817b3115f2SLuciano Coelho 
6827b3115f2SLuciano Coelho 	/* Bluetooth WLAN coexistence */
6837b3115f2SLuciano Coelho 	ret = wl1271_init_pta(wl);
6847b3115f2SLuciano Coelho 	if (ret < 0)
6857b3115f2SLuciano Coelho 		return ret;
6867b3115f2SLuciano Coelho 
6877b3115f2SLuciano Coelho 	/* Default memory configuration */
6887b3115f2SLuciano Coelho 	ret = wl1271_acx_init_mem_config(wl);
6897b3115f2SLuciano Coelho 	if (ret < 0)
6907b3115f2SLuciano Coelho 		return ret;
6917b3115f2SLuciano Coelho 
6927b3115f2SLuciano Coelho 	/* RX config */
6937b3115f2SLuciano Coelho 	ret = wl12xx_init_rx_config(wl);
6947b3115f2SLuciano Coelho 	if (ret < 0)
6957b3115f2SLuciano Coelho 		goto out_free_memmap;
6967b3115f2SLuciano Coelho 
6977b3115f2SLuciano Coelho 	ret = wl1271_acx_dco_itrim_params(wl);
6987b3115f2SLuciano Coelho 	if (ret < 0)
6997b3115f2SLuciano Coelho 		goto out_free_memmap;
7007b3115f2SLuciano Coelho 
7017b3115f2SLuciano Coelho 	/* Configure TX patch complete interrupt behavior */
7027b3115f2SLuciano Coelho 	ret = wl1271_acx_tx_config_options(wl);
7037b3115f2SLuciano Coelho 	if (ret < 0)
7047b3115f2SLuciano Coelho 		goto out_free_memmap;
7057b3115f2SLuciano Coelho 
7067b3115f2SLuciano Coelho 	/* RX complete interrupt pacing */
7077b3115f2SLuciano Coelho 	ret = wl1271_acx_init_rx_interrupt(wl);
7087b3115f2SLuciano Coelho 	if (ret < 0)
7097b3115f2SLuciano Coelho 		goto out_free_memmap;
7107b3115f2SLuciano Coelho 
7117b3115f2SLuciano Coelho 	/* Energy detection */
7127b3115f2SLuciano Coelho 	ret = wl1271_init_energy_detection(wl);
7137b3115f2SLuciano Coelho 	if (ret < 0)
7147b3115f2SLuciano Coelho 		goto out_free_memmap;
7157b3115f2SLuciano Coelho 
7167b3115f2SLuciano Coelho 	/* Default fragmentation threshold */
7177b3115f2SLuciano Coelho 	ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold);
7187b3115f2SLuciano Coelho 	if (ret < 0)
7197b3115f2SLuciano Coelho 		goto out_free_memmap;
7207b3115f2SLuciano Coelho 
7217b3115f2SLuciano Coelho 	/* Enable data path */
7227b3115f2SLuciano Coelho 	ret = wl1271_cmd_data_path(wl, 1);
7237b3115f2SLuciano Coelho 	if (ret < 0)
7247b3115f2SLuciano Coelho 		goto out_free_memmap;
7257b3115f2SLuciano Coelho 
7267b3115f2SLuciano Coelho 	/* configure PM */
7277b3115f2SLuciano Coelho 	ret = wl1271_acx_pm_config(wl);
7287b3115f2SLuciano Coelho 	if (ret < 0)
7297b3115f2SLuciano Coelho 		goto out_free_memmap;
7307b3115f2SLuciano Coelho 
7317b3115f2SLuciano Coelho 	ret = wl12xx_acx_set_rate_mgmt_params(wl);
7327b3115f2SLuciano Coelho 	if (ret < 0)
7337b3115f2SLuciano Coelho 		goto out_free_memmap;
7347b3115f2SLuciano Coelho 
7357b3115f2SLuciano Coelho 	/* configure hangover */
7367b3115f2SLuciano Coelho 	ret = wl12xx_acx_config_hangover(wl);
7377b3115f2SLuciano Coelho 	if (ret < 0)
7387b3115f2SLuciano Coelho 		goto out_free_memmap;
7397b3115f2SLuciano Coelho 
7407b3115f2SLuciano Coelho 	return 0;
7417b3115f2SLuciano Coelho 
7427b3115f2SLuciano Coelho  out_free_memmap:
7437b3115f2SLuciano Coelho 	kfree(wl->target_mem_map);
7447b3115f2SLuciano Coelho 	wl->target_mem_map = NULL;
7457b3115f2SLuciano Coelho 
7467b3115f2SLuciano Coelho 	return ret;
7477b3115f2SLuciano Coelho }
748