xref: /openbmc/linux/drivers/net/wireless/ti/wlcore/init.c (revision 2b27bdcc)
12b27bdccSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27b3115f2SLuciano Coelho /*
37b3115f2SLuciano Coelho  * This file is part of wl1271
47b3115f2SLuciano Coelho  *
57b3115f2SLuciano Coelho  * Copyright (C) 2009 Nokia Corporation
67b3115f2SLuciano Coelho  *
77b3115f2SLuciano Coelho  * Contact: Luciano Coelho <luciano.coelho@nokia.com>
87b3115f2SLuciano Coelho  */
97b3115f2SLuciano Coelho 
107b3115f2SLuciano Coelho #include <linux/kernel.h>
117b3115f2SLuciano Coelho #include <linux/module.h>
127b3115f2SLuciano Coelho #include <linux/slab.h>
137b3115f2SLuciano Coelho 
147b3115f2SLuciano Coelho #include "debug.h"
157b3115f2SLuciano Coelho #include "init.h"
167b3115f2SLuciano Coelho #include "wl12xx_80211.h"
177b3115f2SLuciano Coelho #include "acx.h"
187b3115f2SLuciano Coelho #include "cmd.h"
197b3115f2SLuciano Coelho #include "tx.h"
207b3115f2SLuciano Coelho #include "io.h"
218a9affc0SArik Nemtsov #include "hw_ops.h"
227b3115f2SLuciano Coelho 
wl1271_init_templates_config(struct wl1271 * wl)237b3115f2SLuciano Coelho int wl1271_init_templates_config(struct wl1271 *wl)
247b3115f2SLuciano Coelho {
257b3115f2SLuciano Coelho 	int ret, i;
267b3115f2SLuciano Coelho 	size_t max_size;
277b3115f2SLuciano Coelho 
287b3115f2SLuciano Coelho 	/* send empty templates for fw memory reservation */
297b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
3078e28062SEliad Peller 				      wl->scan_templ_id_2_4, NULL,
317b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_MAX_SIZE,
327b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
337b3115f2SLuciano Coelho 	if (ret < 0)
347b3115f2SLuciano Coelho 		return ret;
357b3115f2SLuciano Coelho 
367b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
3778e28062SEliad Peller 				      wl->scan_templ_id_5,
387b3115f2SLuciano Coelho 				      NULL, WL1271_CMD_TEMPL_MAX_SIZE, 0,
397b3115f2SLuciano Coelho 				      WL1271_RATE_AUTOMATIC);
407b3115f2SLuciano Coelho 	if (ret < 0)
417b3115f2SLuciano Coelho 		return ret;
427b3115f2SLuciano Coelho 
433df74f46SYoni Divinsky 	if (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL) {
443df74f46SYoni Divinsky 		ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
4578e28062SEliad Peller 					      wl->sched_scan_templ_id_2_4,
4678e28062SEliad Peller 					      NULL,
473df74f46SYoni Divinsky 					      WL1271_CMD_TEMPL_MAX_SIZE,
483df74f46SYoni Divinsky 					      0, WL1271_RATE_AUTOMATIC);
493df74f46SYoni Divinsky 		if (ret < 0)
503df74f46SYoni Divinsky 			return ret;
513df74f46SYoni Divinsky 
523df74f46SYoni Divinsky 		ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
5378e28062SEliad Peller 					      wl->sched_scan_templ_id_5,
5478e28062SEliad Peller 					      NULL,
553df74f46SYoni Divinsky 					      WL1271_CMD_TEMPL_MAX_SIZE,
563df74f46SYoni Divinsky 					      0, WL1271_RATE_AUTOMATIC);
573df74f46SYoni Divinsky 		if (ret < 0)
583df74f46SYoni Divinsky 			return ret;
593df74f46SYoni Divinsky 	}
603df74f46SYoni Divinsky 
617b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
627b3115f2SLuciano Coelho 				      CMD_TEMPL_NULL_DATA, NULL,
637b3115f2SLuciano Coelho 				      sizeof(struct wl12xx_null_data_template),
647b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
657b3115f2SLuciano Coelho 	if (ret < 0)
667b3115f2SLuciano Coelho 		return ret;
677b3115f2SLuciano Coelho 
687b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
697b3115f2SLuciano Coelho 				      CMD_TEMPL_PS_POLL, NULL,
707b3115f2SLuciano Coelho 				      sizeof(struct wl12xx_ps_poll_template),
717b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
727b3115f2SLuciano Coelho 	if (ret < 0)
737b3115f2SLuciano Coelho 		return ret;
747b3115f2SLuciano Coelho 
757b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
767b3115f2SLuciano Coelho 				      CMD_TEMPL_QOS_NULL_DATA, NULL,
777b3115f2SLuciano Coelho 				      sizeof
787b3115f2SLuciano Coelho 				      (struct ieee80211_qos_hdr),
797b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
807b3115f2SLuciano Coelho 	if (ret < 0)
817b3115f2SLuciano Coelho 		return ret;
827b3115f2SLuciano Coelho 
837b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
847b3115f2SLuciano Coelho 				      CMD_TEMPL_PROBE_RESPONSE, NULL,
857b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_DFLT_SIZE,
867b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
877b3115f2SLuciano Coelho 	if (ret < 0)
887b3115f2SLuciano Coelho 		return ret;
897b3115f2SLuciano Coelho 
907b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
917b3115f2SLuciano Coelho 				      CMD_TEMPL_BEACON, NULL,
927b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_DFLT_SIZE,
937b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
947b3115f2SLuciano Coelho 	if (ret < 0)
957b3115f2SLuciano Coelho 		return ret;
967b3115f2SLuciano Coelho 
977b3115f2SLuciano Coelho 	max_size = sizeof(struct wl12xx_arp_rsp_template) +
987b3115f2SLuciano Coelho 		   WL1271_EXTRA_SPACE_MAX;
997b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1007b3115f2SLuciano Coelho 				      CMD_TEMPL_ARP_RSP, NULL,
1017b3115f2SLuciano Coelho 				      max_size,
1027b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1037b3115f2SLuciano Coelho 	if (ret < 0)
1047b3115f2SLuciano Coelho 		return ret;
1057b3115f2SLuciano Coelho 
1067b3115f2SLuciano Coelho 	/*
1077b3115f2SLuciano Coelho 	 * Put very large empty placeholders for all templates. These
1087b3115f2SLuciano Coelho 	 * reserve memory for later.
1097b3115f2SLuciano Coelho 	 */
1107b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1117b3115f2SLuciano Coelho 				      CMD_TEMPL_AP_PROBE_RESPONSE, NULL,
1127b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_MAX_SIZE,
1137b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1147b3115f2SLuciano Coelho 	if (ret < 0)
1157b3115f2SLuciano Coelho 		return ret;
1167b3115f2SLuciano Coelho 
1177b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1187b3115f2SLuciano Coelho 				      CMD_TEMPL_AP_BEACON, NULL,
1197b3115f2SLuciano Coelho 				      WL1271_CMD_TEMPL_MAX_SIZE,
1207b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1217b3115f2SLuciano Coelho 	if (ret < 0)
1227b3115f2SLuciano Coelho 		return ret;
1237b3115f2SLuciano Coelho 
1247b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1257b3115f2SLuciano Coelho 				      CMD_TEMPL_DEAUTH_AP, NULL,
1267b3115f2SLuciano Coelho 				      sizeof
1277b3115f2SLuciano Coelho 				      (struct wl12xx_disconn_template),
1287b3115f2SLuciano Coelho 				      0, WL1271_RATE_AUTOMATIC);
1297b3115f2SLuciano Coelho 	if (ret < 0)
1307b3115f2SLuciano Coelho 		return ret;
1317b3115f2SLuciano Coelho 
132001e39a8SEliad Peller 	for (i = 0; i < WLCORE_MAX_KLV_TEMPLATES; i++) {
1337b3115f2SLuciano Coelho 		ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID,
1347b3115f2SLuciano Coelho 					      CMD_TEMPL_KLV, NULL,
1357b3115f2SLuciano Coelho 					      sizeof(struct ieee80211_qos_hdr),
1367b3115f2SLuciano Coelho 					      i, WL1271_RATE_AUTOMATIC);
1377b3115f2SLuciano Coelho 		if (ret < 0)
1387b3115f2SLuciano Coelho 			return ret;
1397b3115f2SLuciano Coelho 	}
1407b3115f2SLuciano Coelho 
1417b3115f2SLuciano Coelho 	return 0;
1427b3115f2SLuciano Coelho }
1437b3115f2SLuciano Coelho 
wl1271_ap_init_deauth_template(struct wl1271 * wl,struct wl12xx_vif * wlvif)1447b3115f2SLuciano Coelho static int wl1271_ap_init_deauth_template(struct wl1271 *wl,
1457b3115f2SLuciano Coelho 					  struct wl12xx_vif *wlvif)
1467b3115f2SLuciano Coelho {
1477b3115f2SLuciano Coelho 	struct wl12xx_disconn_template *tmpl;
1487b3115f2SLuciano Coelho 	int ret;
1497b3115f2SLuciano Coelho 	u32 rate;
1507b3115f2SLuciano Coelho 
1517b3115f2SLuciano Coelho 	tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
1527b3115f2SLuciano Coelho 	if (!tmpl) {
1537b3115f2SLuciano Coelho 		ret = -ENOMEM;
1547b3115f2SLuciano Coelho 		goto out;
1557b3115f2SLuciano Coelho 	}
1567b3115f2SLuciano Coelho 
1577b3115f2SLuciano Coelho 	tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
1587b3115f2SLuciano Coelho 					     IEEE80211_STYPE_DEAUTH);
1597b3115f2SLuciano Coelho 
1607b3115f2SLuciano Coelho 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
1617b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
1627b3115f2SLuciano Coelho 				      CMD_TEMPL_DEAUTH_AP,
1637b3115f2SLuciano Coelho 				      tmpl, sizeof(*tmpl), 0, rate);
1647b3115f2SLuciano Coelho 
1657b3115f2SLuciano Coelho out:
1667b3115f2SLuciano Coelho 	kfree(tmpl);
1677b3115f2SLuciano Coelho 	return ret;
1687b3115f2SLuciano Coelho }
1697b3115f2SLuciano Coelho 
wl1271_ap_init_null_template(struct wl1271 * wl,struct ieee80211_vif * vif)1707b3115f2SLuciano Coelho static int wl1271_ap_init_null_template(struct wl1271 *wl,
1717b3115f2SLuciano Coelho 					struct ieee80211_vif *vif)
1727b3115f2SLuciano Coelho {
1737b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
1747b3115f2SLuciano Coelho 	struct ieee80211_hdr_3addr *nullfunc;
1757b3115f2SLuciano Coelho 	int ret;
1767b3115f2SLuciano Coelho 	u32 rate;
1777b3115f2SLuciano Coelho 
1787b3115f2SLuciano Coelho 	nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
1797b3115f2SLuciano Coelho 	if (!nullfunc) {
1807b3115f2SLuciano Coelho 		ret = -ENOMEM;
1817b3115f2SLuciano Coelho 		goto out;
1827b3115f2SLuciano Coelho 	}
1837b3115f2SLuciano Coelho 
1847b3115f2SLuciano Coelho 	nullfunc->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
1857b3115f2SLuciano Coelho 					      IEEE80211_STYPE_NULLFUNC |
1867b3115f2SLuciano Coelho 					      IEEE80211_FCTL_FROMDS);
1877b3115f2SLuciano Coelho 
1887b3115f2SLuciano Coelho 	/* nullfunc->addr1 is filled by FW */
1897b3115f2SLuciano Coelho 
1907b3115f2SLuciano Coelho 	memcpy(nullfunc->addr2, vif->addr, ETH_ALEN);
1917b3115f2SLuciano Coelho 	memcpy(nullfunc->addr3, vif->addr, ETH_ALEN);
1927b3115f2SLuciano Coelho 
1937b3115f2SLuciano Coelho 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
1947b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
1957b3115f2SLuciano Coelho 				      CMD_TEMPL_NULL_DATA, nullfunc,
1967b3115f2SLuciano Coelho 				      sizeof(*nullfunc), 0, rate);
1977b3115f2SLuciano Coelho 
1987b3115f2SLuciano Coelho out:
1997b3115f2SLuciano Coelho 	kfree(nullfunc);
2007b3115f2SLuciano Coelho 	return ret;
2017b3115f2SLuciano Coelho }
2027b3115f2SLuciano Coelho 
wl1271_ap_init_qos_null_template(struct wl1271 * wl,struct ieee80211_vif * vif)2037b3115f2SLuciano Coelho static int wl1271_ap_init_qos_null_template(struct wl1271 *wl,
2047b3115f2SLuciano Coelho 					    struct ieee80211_vif *vif)
2057b3115f2SLuciano Coelho {
2067b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
2077b3115f2SLuciano Coelho 	struct ieee80211_qos_hdr *qosnull;
2087b3115f2SLuciano Coelho 	int ret;
2097b3115f2SLuciano Coelho 	u32 rate;
2107b3115f2SLuciano Coelho 
2117b3115f2SLuciano Coelho 	qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
2127b3115f2SLuciano Coelho 	if (!qosnull) {
2137b3115f2SLuciano Coelho 		ret = -ENOMEM;
2147b3115f2SLuciano Coelho 		goto out;
2157b3115f2SLuciano Coelho 	}
2167b3115f2SLuciano Coelho 
2177b3115f2SLuciano Coelho 	qosnull->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
2187b3115f2SLuciano Coelho 					     IEEE80211_STYPE_QOS_NULLFUNC |
2197b3115f2SLuciano Coelho 					     IEEE80211_FCTL_FROMDS);
2207b3115f2SLuciano Coelho 
2217b3115f2SLuciano Coelho 	/* qosnull->addr1 is filled by FW */
2227b3115f2SLuciano Coelho 
2237b3115f2SLuciano Coelho 	memcpy(qosnull->addr2, vif->addr, ETH_ALEN);
2247b3115f2SLuciano Coelho 	memcpy(qosnull->addr3, vif->addr, ETH_ALEN);
2257b3115f2SLuciano Coelho 
2267b3115f2SLuciano Coelho 	rate = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
2277b3115f2SLuciano Coelho 	ret = wl1271_cmd_template_set(wl, wlvif->role_id,
2287b3115f2SLuciano Coelho 				      CMD_TEMPL_QOS_NULL_DATA, qosnull,
2297b3115f2SLuciano Coelho 				      sizeof(*qosnull), 0, rate);
2307b3115f2SLuciano Coelho 
2317b3115f2SLuciano Coelho out:
2327b3115f2SLuciano Coelho 	kfree(qosnull);
2337b3115f2SLuciano Coelho 	return ret;
2347b3115f2SLuciano Coelho }
2357b3115f2SLuciano Coelho 
wl12xx_init_rx_config(struct wl1271 * wl)2367b3115f2SLuciano Coelho static int wl12xx_init_rx_config(struct wl1271 *wl)
2377b3115f2SLuciano Coelho {
2387b3115f2SLuciano Coelho 	int ret;
2397b3115f2SLuciano Coelho 
2407b3115f2SLuciano Coelho 	ret = wl1271_acx_rx_msdu_life_time(wl);
2417b3115f2SLuciano Coelho 	if (ret < 0)
2427b3115f2SLuciano Coelho 		return ret;
2437b3115f2SLuciano Coelho 
2447b3115f2SLuciano Coelho 	return 0;
2457b3115f2SLuciano Coelho }
2467b3115f2SLuciano Coelho 
wl12xx_init_phy_vif_config(struct wl1271 * wl,struct wl12xx_vif * wlvif)2477b3115f2SLuciano Coelho static int wl12xx_init_phy_vif_config(struct wl1271 *wl,
2487b3115f2SLuciano Coelho 					    struct wl12xx_vif *wlvif)
2497b3115f2SLuciano Coelho {
2507b3115f2SLuciano Coelho 	int ret;
2517b3115f2SLuciano Coelho 
2527b3115f2SLuciano Coelho 	ret = wl1271_acx_slot(wl, wlvif, DEFAULT_SLOT_TIME);
2537b3115f2SLuciano Coelho 	if (ret < 0)
2547b3115f2SLuciano Coelho 		return ret;
2557b3115f2SLuciano Coelho 
2567b3115f2SLuciano Coelho 	ret = wl1271_acx_service_period_timeout(wl, wlvif);
2577b3115f2SLuciano Coelho 	if (ret < 0)
2587b3115f2SLuciano Coelho 		return ret;
2597b3115f2SLuciano Coelho 
2607b3115f2SLuciano Coelho 	ret = wl1271_acx_rts_threshold(wl, wlvif, wl->hw->wiphy->rts_threshold);
2617b3115f2SLuciano Coelho 	if (ret < 0)
2627b3115f2SLuciano Coelho 		return ret;
2637b3115f2SLuciano Coelho 
2647b3115f2SLuciano Coelho 	return 0;
2657b3115f2SLuciano Coelho }
2667b3115f2SLuciano Coelho 
wl1271_init_sta_beacon_filter(struct wl1271 * wl,struct wl12xx_vif * wlvif)2677b3115f2SLuciano Coelho static int wl1271_init_sta_beacon_filter(struct wl1271 *wl,
2687b3115f2SLuciano Coelho 					 struct wl12xx_vif *wlvif)
2697b3115f2SLuciano Coelho {
2707b3115f2SLuciano Coelho 	int ret;
2717b3115f2SLuciano Coelho 
2727b3115f2SLuciano Coelho 	ret = wl1271_acx_beacon_filter_table(wl, wlvif);
2737b3115f2SLuciano Coelho 	if (ret < 0)
2747b3115f2SLuciano Coelho 		return ret;
2757b3115f2SLuciano Coelho 
276d881fa2cSEliad Peller 	/* disable beacon filtering until we get the first beacon */
277d881fa2cSEliad Peller 	ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
2787b3115f2SLuciano Coelho 	if (ret < 0)
2797b3115f2SLuciano Coelho 		return ret;
2807b3115f2SLuciano Coelho 
2817b3115f2SLuciano Coelho 	return 0;
2827b3115f2SLuciano Coelho }
2837b3115f2SLuciano Coelho 
wl1271_init_pta(struct wl1271 * wl)2847b3115f2SLuciano Coelho int wl1271_init_pta(struct wl1271 *wl)
2857b3115f2SLuciano Coelho {
2867b3115f2SLuciano Coelho 	int ret;
2877b3115f2SLuciano Coelho 
2887b3115f2SLuciano Coelho 	ret = wl12xx_acx_sg_cfg(wl);
2897b3115f2SLuciano Coelho 	if (ret < 0)
2907b3115f2SLuciano Coelho 		return ret;
2917b3115f2SLuciano Coelho 
2927b3115f2SLuciano Coelho 	ret = wl1271_acx_sg_enable(wl, wl->sg_enabled);
2937b3115f2SLuciano Coelho 	if (ret < 0)
2947b3115f2SLuciano Coelho 		return ret;
2957b3115f2SLuciano Coelho 
2967b3115f2SLuciano Coelho 	return 0;
2977b3115f2SLuciano Coelho }
2987b3115f2SLuciano Coelho 
wl1271_init_energy_detection(struct wl1271 * wl)2997b3115f2SLuciano Coelho int wl1271_init_energy_detection(struct wl1271 *wl)
3007b3115f2SLuciano Coelho {
3017b3115f2SLuciano Coelho 	int ret;
3027b3115f2SLuciano Coelho 
3037b3115f2SLuciano Coelho 	ret = wl1271_acx_cca_threshold(wl);
3047b3115f2SLuciano Coelho 	if (ret < 0)
3057b3115f2SLuciano Coelho 		return ret;
3067b3115f2SLuciano Coelho 
3077b3115f2SLuciano Coelho 	return 0;
3087b3115f2SLuciano Coelho }
3097b3115f2SLuciano Coelho 
wl1271_init_beacon_broadcast(struct wl1271 * wl,struct wl12xx_vif * wlvif)3107b3115f2SLuciano Coelho static int wl1271_init_beacon_broadcast(struct wl1271 *wl,
3117b3115f2SLuciano Coelho 					struct wl12xx_vif *wlvif)
3127b3115f2SLuciano Coelho {
3137b3115f2SLuciano Coelho 	int ret;
3147b3115f2SLuciano Coelho 
3157b3115f2SLuciano Coelho 	ret = wl1271_acx_bcn_dtim_options(wl, wlvif);
3167b3115f2SLuciano Coelho 	if (ret < 0)
3177b3115f2SLuciano Coelho 		return ret;
3187b3115f2SLuciano Coelho 
3197b3115f2SLuciano Coelho 	return 0;
3207b3115f2SLuciano Coelho }
3217b3115f2SLuciano Coelho 
wl12xx_init_fwlog(struct wl1271 * wl)3227b3115f2SLuciano Coelho static int wl12xx_init_fwlog(struct wl1271 *wl)
3237b3115f2SLuciano Coelho {
3247b3115f2SLuciano Coelho 	int ret;
3257b3115f2SLuciano Coelho 
3266f7dd16cSLuciano Coelho 	if (wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED)
3277b3115f2SLuciano Coelho 		return 0;
3287b3115f2SLuciano Coelho 
3297b3115f2SLuciano Coelho 	ret = wl12xx_cmd_config_fwlog(wl);
3307b3115f2SLuciano Coelho 	if (ret < 0)
3317b3115f2SLuciano Coelho 		return ret;
3327b3115f2SLuciano Coelho 
3337b3115f2SLuciano Coelho 	return 0;
3347b3115f2SLuciano Coelho }
3357b3115f2SLuciano Coelho 
3367b3115f2SLuciano Coelho /* generic sta initialization (non vif-specific) */
wl1271_sta_hw_init(struct wl1271 * wl,struct wl12xx_vif * wlvif)3377845af35SEliad Peller int wl1271_sta_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
3387b3115f2SLuciano Coelho {
3397b3115f2SLuciano Coelho 	int ret;
3407b3115f2SLuciano Coelho 
3417b3115f2SLuciano Coelho 	/* PS config */
3427b3115f2SLuciano Coelho 	ret = wl12xx_acx_config_ps(wl, wlvif);
3437b3115f2SLuciano Coelho 	if (ret < 0)
3447b3115f2SLuciano Coelho 		return ret;
3457b3115f2SLuciano Coelho 
3467b3115f2SLuciano Coelho 	/* FM WLAN coexistence */
3477b3115f2SLuciano Coelho 	ret = wl1271_acx_fm_coex(wl);
3487b3115f2SLuciano Coelho 	if (ret < 0)
3497b3115f2SLuciano Coelho 		return ret;
3507b3115f2SLuciano Coelho 
3517b3115f2SLuciano Coelho 	ret = wl1271_acx_sta_rate_policies(wl, wlvif);
3527b3115f2SLuciano Coelho 	if (ret < 0)
3537b3115f2SLuciano Coelho 		return ret;
3547b3115f2SLuciano Coelho 
3557b3115f2SLuciano Coelho 	return 0;
3567b3115f2SLuciano Coelho }
3577b3115f2SLuciano Coelho 
wl1271_sta_hw_init_post_mem(struct wl1271 * wl,struct ieee80211_vif * vif)3587b3115f2SLuciano Coelho static int wl1271_sta_hw_init_post_mem(struct wl1271 *wl,
3597b3115f2SLuciano Coelho 				       struct ieee80211_vif *vif)
3607b3115f2SLuciano Coelho {
3617b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
362001e39a8SEliad Peller 	int ret;
3637b3115f2SLuciano Coelho 
3647b3115f2SLuciano Coelho 	/* disable the keep-alive feature */
3657b3115f2SLuciano Coelho 	ret = wl1271_acx_keep_alive_mode(wl, wlvif, false);
3667b3115f2SLuciano Coelho 	if (ret < 0)
3677b3115f2SLuciano Coelho 		return ret;
3687b3115f2SLuciano Coelho 
3697b3115f2SLuciano Coelho 	return 0;
3707b3115f2SLuciano Coelho }
3717b3115f2SLuciano Coelho 
3727b3115f2SLuciano Coelho /* generic ap initialization (non vif-specific) */
wl1271_ap_hw_init(struct wl1271 * wl,struct wl12xx_vif * wlvif)3737b3115f2SLuciano Coelho static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
3747b3115f2SLuciano Coelho {
3757b3115f2SLuciano Coelho 	int ret;
3767b3115f2SLuciano Coelho 
3777b3115f2SLuciano Coelho 	ret = wl1271_init_ap_rates(wl, wlvif);
3787b3115f2SLuciano Coelho 	if (ret < 0)
3797b3115f2SLuciano Coelho 		return ret;
3807b3115f2SLuciano Coelho 
381e2f1e50fSKobi L 	/* configure AP sleep, if enabled */
382e2f1e50fSKobi L 	ret = wlcore_hw_ap_sleep(wl);
383e2f1e50fSKobi L 	if (ret < 0)
384e2f1e50fSKobi L 		return ret;
385e2f1e50fSKobi L 
3867b3115f2SLuciano Coelho 	return 0;
3877b3115f2SLuciano Coelho }
3887b3115f2SLuciano Coelho 
wl1271_ap_init_templates(struct wl1271 * wl,struct ieee80211_vif * vif)3897b3115f2SLuciano Coelho int wl1271_ap_init_templates(struct wl1271 *wl, struct ieee80211_vif *vif)
3907b3115f2SLuciano Coelho {
3917b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
3927b3115f2SLuciano Coelho 	int ret;
3937b3115f2SLuciano Coelho 
3947b3115f2SLuciano Coelho 	ret = wl1271_ap_init_deauth_template(wl, wlvif);
3957b3115f2SLuciano Coelho 	if (ret < 0)
3967b3115f2SLuciano Coelho 		return ret;
3977b3115f2SLuciano Coelho 
3987b3115f2SLuciano Coelho 	ret = wl1271_ap_init_null_template(wl, vif);
3997b3115f2SLuciano Coelho 	if (ret < 0)
4007b3115f2SLuciano Coelho 		return ret;
4017b3115f2SLuciano Coelho 
4027b3115f2SLuciano Coelho 	ret = wl1271_ap_init_qos_null_template(wl, vif);
4037b3115f2SLuciano Coelho 	if (ret < 0)
4047b3115f2SLuciano Coelho 		return ret;
4057b3115f2SLuciano Coelho 
4067b3115f2SLuciano Coelho 	/*
4077b3115f2SLuciano Coelho 	 * when operating as AP we want to receive external beacons for
4087b3115f2SLuciano Coelho 	 * configuring ERP protection.
4097b3115f2SLuciano Coelho 	 */
4107b3115f2SLuciano Coelho 	ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
4117b3115f2SLuciano Coelho 	if (ret < 0)
4127b3115f2SLuciano Coelho 		return ret;
4137b3115f2SLuciano Coelho 
4147b3115f2SLuciano Coelho 	return 0;
4157b3115f2SLuciano Coelho }
4167b3115f2SLuciano Coelho 
wl1271_ap_hw_init_post_mem(struct wl1271 * wl,struct ieee80211_vif * vif)4177b3115f2SLuciano Coelho static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl,
4187b3115f2SLuciano Coelho 				      struct ieee80211_vif *vif)
4197b3115f2SLuciano Coelho {
4207b3115f2SLuciano Coelho 	return wl1271_ap_init_templates(wl, vif);
4217b3115f2SLuciano Coelho }
4227b3115f2SLuciano Coelho 
wl1271_init_ap_rates(struct wl1271 * wl,struct wl12xx_vif * wlvif)4237b3115f2SLuciano Coelho int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif)
4247b3115f2SLuciano Coelho {
4257b3115f2SLuciano Coelho 	int i, ret;
4267b3115f2SLuciano Coelho 	struct conf_tx_rate_class rc;
4277b3115f2SLuciano Coelho 	u32 supported_rates;
4287b3115f2SLuciano Coelho 
4297b3115f2SLuciano Coelho 	wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x",
4307b3115f2SLuciano Coelho 		     wlvif->basic_rate_set);
4317b3115f2SLuciano Coelho 
4327b3115f2SLuciano Coelho 	if (wlvif->basic_rate_set == 0)
4337b3115f2SLuciano Coelho 		return -EINVAL;
4347b3115f2SLuciano Coelho 
4357b3115f2SLuciano Coelho 	rc.enabled_rates = wlvif->basic_rate_set;
4367b3115f2SLuciano Coelho 	rc.long_retry_limit = 10;
4377b3115f2SLuciano Coelho 	rc.short_retry_limit = 10;
4387b3115f2SLuciano Coelho 	rc.aflags = 0;
4397b3115f2SLuciano Coelho 	ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx);
4407b3115f2SLuciano Coelho 	if (ret < 0)
4417b3115f2SLuciano Coelho 		return ret;
4427b3115f2SLuciano Coelho 
4437b3115f2SLuciano Coelho 	/* use the min basic rate for AP broadcast/multicast */
4447b3115f2SLuciano Coelho 	rc.enabled_rates = wl1271_tx_min_rate_get(wl, wlvif->basic_rate_set);
4457b3115f2SLuciano Coelho 	rc.short_retry_limit = 10;
4467b3115f2SLuciano Coelho 	rc.long_retry_limit = 10;
4477b3115f2SLuciano Coelho 	rc.aflags = 0;
4487b3115f2SLuciano Coelho 	ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.bcast_rate_idx);
4497b3115f2SLuciano Coelho 	if (ret < 0)
4507b3115f2SLuciano Coelho 		return ret;
4517b3115f2SLuciano Coelho 
4527b3115f2SLuciano Coelho 	/*
4537b3115f2SLuciano Coelho 	 * If the basic rates contain OFDM rates, use OFDM only
4547b3115f2SLuciano Coelho 	 * rates for unicast TX as well. Else use all supported rates.
4557b3115f2SLuciano Coelho 	 */
456bc566f92SArik Nemtsov 	if (wl->ofdm_only_ap && (wlvif->basic_rate_set & CONF_TX_OFDM_RATES))
4577b3115f2SLuciano Coelho 		supported_rates = CONF_TX_OFDM_RATES;
4587b3115f2SLuciano Coelho 	else
45942ec1f82SEliad Peller 		supported_rates = CONF_TX_ENABLED_RATES;
4607b3115f2SLuciano Coelho 
4617b3115f2SLuciano Coelho 	/* unconditionally enable HT rates */
4627b3115f2SLuciano Coelho 	supported_rates |= CONF_TX_MCS_RATES;
4637b3115f2SLuciano Coelho 
464ebc7e57dSArik Nemtsov 	/* get extra MIMO or wide-chan rates where the HW supports it */
465ebc7e57dSArik Nemtsov 	supported_rates |= wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
466ebc7e57dSArik Nemtsov 
4677b3115f2SLuciano Coelho 	/* configure unicast TX rate classes */
4687b3115f2SLuciano Coelho 	for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
4697b3115f2SLuciano Coelho 		rc.enabled_rates = supported_rates;
4707b3115f2SLuciano Coelho 		rc.short_retry_limit = 10;
4717b3115f2SLuciano Coelho 		rc.long_retry_limit = 10;
4727b3115f2SLuciano Coelho 		rc.aflags = 0;
4737b3115f2SLuciano Coelho 		ret = wl1271_acx_ap_rate_policy(wl, &rc,
4747b3115f2SLuciano Coelho 						wlvif->ap.ucast_rate_idx[i]);
4757b3115f2SLuciano Coelho 		if (ret < 0)
4767b3115f2SLuciano Coelho 			return ret;
4777b3115f2SLuciano Coelho 	}
4787b3115f2SLuciano Coelho 
4797b3115f2SLuciano Coelho 	return 0;
4807b3115f2SLuciano Coelho }
4817b3115f2SLuciano Coelho 
wl1271_set_ba_policies(struct wl1271 * wl,struct wl12xx_vif * wlvif)4827b3115f2SLuciano Coelho static int wl1271_set_ba_policies(struct wl1271 *wl, struct wl12xx_vif *wlvif)
4837b3115f2SLuciano Coelho {
4847b3115f2SLuciano Coelho 	/* Reset the BA RX indicators */
4857b3115f2SLuciano Coelho 	wlvif->ba_allowed = true;
4867b3115f2SLuciano Coelho 	wl->ba_rx_session_count = 0;
4877b3115f2SLuciano Coelho 
4887b3115f2SLuciano Coelho 	/* BA is supported in STA/AP modes */
4897b3115f2SLuciano Coelho 	if (wlvif->bss_type != BSS_TYPE_AP_BSS &&
4907b3115f2SLuciano Coelho 	    wlvif->bss_type != BSS_TYPE_STA_BSS) {
4917b3115f2SLuciano Coelho 		wlvif->ba_support = false;
4927b3115f2SLuciano Coelho 		return 0;
4937b3115f2SLuciano Coelho 	}
4947b3115f2SLuciano Coelho 
4957b3115f2SLuciano Coelho 	wlvif->ba_support = true;
4967b3115f2SLuciano Coelho 
4977b3115f2SLuciano Coelho 	/* 802.11n initiator BA session setting */
4987b3115f2SLuciano Coelho 	return wl12xx_acx_set_ba_initiator_policy(wl, wlvif);
4997b3115f2SLuciano Coelho }
5007b3115f2SLuciano Coelho 
5017b3115f2SLuciano Coelho /* vif-specifc initialization */
wl12xx_init_sta_role(struct wl1271 * wl,struct wl12xx_vif * wlvif)5027b3115f2SLuciano Coelho static int wl12xx_init_sta_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
5037b3115f2SLuciano Coelho {
5047b3115f2SLuciano Coelho 	int ret;
5057b3115f2SLuciano Coelho 
5067b3115f2SLuciano Coelho 	ret = wl1271_acx_group_address_tbl(wl, wlvif, true, NULL, 0);
5077b3115f2SLuciano Coelho 	if (ret < 0)
5087b3115f2SLuciano Coelho 		return ret;
5097b3115f2SLuciano Coelho 
5107b3115f2SLuciano Coelho 	/* Initialize connection monitoring thresholds */
5117b3115f2SLuciano Coelho 	ret = wl1271_acx_conn_monit_params(wl, wlvif, false);
5127b3115f2SLuciano Coelho 	if (ret < 0)
5137b3115f2SLuciano Coelho 		return ret;
5147b3115f2SLuciano Coelho 
5157b3115f2SLuciano Coelho 	/* Beacon filtering */
5167b3115f2SLuciano Coelho 	ret = wl1271_init_sta_beacon_filter(wl, wlvif);
5177b3115f2SLuciano Coelho 	if (ret < 0)
5187b3115f2SLuciano Coelho 		return ret;
5197b3115f2SLuciano Coelho 
5207b3115f2SLuciano Coelho 	/* Beacons and broadcast settings */
5217b3115f2SLuciano Coelho 	ret = wl1271_init_beacon_broadcast(wl, wlvif);
5227b3115f2SLuciano Coelho 	if (ret < 0)
5237b3115f2SLuciano Coelho 		return ret;
5247b3115f2SLuciano Coelho 
5257b3115f2SLuciano Coelho 	/* Configure rssi/snr averaging weights */
5267b3115f2SLuciano Coelho 	ret = wl1271_acx_rssi_snr_avg_weights(wl, wlvif);
5277b3115f2SLuciano Coelho 	if (ret < 0)
5287b3115f2SLuciano Coelho 		return ret;
5297b3115f2SLuciano Coelho 
5307b3115f2SLuciano Coelho 	return 0;
5317b3115f2SLuciano Coelho }
5327b3115f2SLuciano Coelho 
533183b8021SMasahiro Yamada /* vif-specific initialization */
wl12xx_init_ap_role(struct wl1271 * wl,struct wl12xx_vif * wlvif)5347b3115f2SLuciano Coelho static int wl12xx_init_ap_role(struct wl1271 *wl, struct wl12xx_vif *wlvif)
5357b3115f2SLuciano Coelho {
5367b3115f2SLuciano Coelho 	int ret;
5377b3115f2SLuciano Coelho 
5387b3115f2SLuciano Coelho 	ret = wl1271_acx_ap_max_tx_retry(wl, wlvif);
5397b3115f2SLuciano Coelho 	if (ret < 0)
5407b3115f2SLuciano Coelho 		return ret;
5417b3115f2SLuciano Coelho 
5427b3115f2SLuciano Coelho 	/* initialize Tx power */
5437b3115f2SLuciano Coelho 	ret = wl1271_acx_tx_power(wl, wlvif, wlvif->power_level);
5447b3115f2SLuciano Coelho 	if (ret < 0)
5457b3115f2SLuciano Coelho 		return ret;
5467b3115f2SLuciano Coelho 
5478cf77e17SEliad Peller 	if (wl->radar_debug_mode)
5488cf77e17SEliad Peller 		wlcore_cmd_generic_cfg(wl, wlvif,
5498cf77e17SEliad Peller 				       WLCORE_CFG_FEATURE_RADAR_DEBUG,
5508cf77e17SEliad Peller 				       wl->radar_debug_mode, 0);
5518cf77e17SEliad Peller 
5527b3115f2SLuciano Coelho 	return 0;
5537b3115f2SLuciano Coelho }
5547b3115f2SLuciano Coelho 
wl1271_init_vif_specific(struct wl1271 * wl,struct ieee80211_vif * vif)5557b3115f2SLuciano Coelho int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
5567b3115f2SLuciano Coelho {
5577b3115f2SLuciano Coelho 	struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
5587b3115f2SLuciano Coelho 	struct conf_tx_ac_category *conf_ac;
5597b3115f2SLuciano Coelho 	struct conf_tx_tid *conf_tid;
5607b3115f2SLuciano Coelho 	bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
5617b3115f2SLuciano Coelho 	int ret, i;
5627b3115f2SLuciano Coelho 
5632f18cf7cSArik Nemtsov 	/* consider all existing roles before configuring psm. */
5642f18cf7cSArik Nemtsov 
5652f18cf7cSArik Nemtsov 	if (wl->ap_count == 0 && is_ap) { /* first AP */
566e2f1e50fSKobi L 		ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
5677b3115f2SLuciano Coelho 		if (ret < 0)
5687b3115f2SLuciano Coelho 			return ret;
56971e996beSEliad Peller 
57071e996beSEliad Peller 		/* unmask ap events */
57171e996beSEliad Peller 		wl->event_mask |= wl->ap_event_mask;
57271e996beSEliad Peller 		ret = wl1271_event_unmask(wl);
57371e996beSEliad Peller 		if (ret < 0)
57471e996beSEliad Peller 			return ret;
5752f18cf7cSArik Nemtsov 	/* first STA, no APs */
5762f18cf7cSArik Nemtsov 	} else if (wl->sta_count == 0 && wl->ap_count == 0 && !is_ap) {
57766340e5bSArik Nemtsov 		u8 sta_auth = wl->conf.conn.sta_sleep_auth;
57866340e5bSArik Nemtsov 		/* Configure for power according to debugfs */
5792f18cf7cSArik Nemtsov 		if (sta_auth != WL1271_PSM_ILLEGAL)
58066340e5bSArik Nemtsov 			ret = wl1271_acx_sleep_auth(wl, sta_auth);
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 
wl1271_hw_init(struct wl1271 * wl)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 
6826b70e7ebSVictor Goldenshtein 	ret = wlcore_cmd_regdomain_config_locked(wl);
6836b70e7ebSVictor Goldenshtein 	if (ret < 0)
6846b70e7ebSVictor Goldenshtein 		return ret;
6856b70e7ebSVictor Goldenshtein 
6867b3115f2SLuciano Coelho 	/* Bluetooth WLAN coexistence */
6877b3115f2SLuciano Coelho 	ret = wl1271_init_pta(wl);
6887b3115f2SLuciano Coelho 	if (ret < 0)
6897b3115f2SLuciano Coelho 		return ret;
6907b3115f2SLuciano Coelho 
6917b3115f2SLuciano Coelho 	/* Default memory configuration */
6927b3115f2SLuciano Coelho 	ret = wl1271_acx_init_mem_config(wl);
6937b3115f2SLuciano Coelho 	if (ret < 0)
6947b3115f2SLuciano Coelho 		return ret;
6957b3115f2SLuciano Coelho 
6967b3115f2SLuciano Coelho 	/* RX config */
6977b3115f2SLuciano Coelho 	ret = wl12xx_init_rx_config(wl);
6987b3115f2SLuciano Coelho 	if (ret < 0)
6997b3115f2SLuciano Coelho 		goto out_free_memmap;
7007b3115f2SLuciano Coelho 
7017b3115f2SLuciano Coelho 	ret = wl1271_acx_dco_itrim_params(wl);
7027b3115f2SLuciano Coelho 	if (ret < 0)
7037b3115f2SLuciano Coelho 		goto out_free_memmap;
7047b3115f2SLuciano Coelho 
7057b3115f2SLuciano Coelho 	/* Configure TX patch complete interrupt behavior */
7067b3115f2SLuciano Coelho 	ret = wl1271_acx_tx_config_options(wl);
7077b3115f2SLuciano Coelho 	if (ret < 0)
7087b3115f2SLuciano Coelho 		goto out_free_memmap;
7097b3115f2SLuciano Coelho 
7107b3115f2SLuciano Coelho 	/* RX complete interrupt pacing */
7117b3115f2SLuciano Coelho 	ret = wl1271_acx_init_rx_interrupt(wl);
7127b3115f2SLuciano Coelho 	if (ret < 0)
7137b3115f2SLuciano Coelho 		goto out_free_memmap;
7147b3115f2SLuciano Coelho 
7157b3115f2SLuciano Coelho 	/* Energy detection */
7167b3115f2SLuciano Coelho 	ret = wl1271_init_energy_detection(wl);
7177b3115f2SLuciano Coelho 	if (ret < 0)
7187b3115f2SLuciano Coelho 		goto out_free_memmap;
7197b3115f2SLuciano Coelho 
7207b3115f2SLuciano Coelho 	/* Default fragmentation threshold */
7217b3115f2SLuciano Coelho 	ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold);
7227b3115f2SLuciano Coelho 	if (ret < 0)
7237b3115f2SLuciano Coelho 		goto out_free_memmap;
7247b3115f2SLuciano Coelho 
7257b3115f2SLuciano Coelho 	/* Enable data path */
7267b3115f2SLuciano Coelho 	ret = wl1271_cmd_data_path(wl, 1);
7277b3115f2SLuciano Coelho 	if (ret < 0)
7287b3115f2SLuciano Coelho 		goto out_free_memmap;
7297b3115f2SLuciano Coelho 
7307b3115f2SLuciano Coelho 	/* configure PM */
7317b3115f2SLuciano Coelho 	ret = wl1271_acx_pm_config(wl);
7327b3115f2SLuciano Coelho 	if (ret < 0)
7337b3115f2SLuciano Coelho 		goto out_free_memmap;
7347b3115f2SLuciano Coelho 
7357b3115f2SLuciano Coelho 	ret = wl12xx_acx_set_rate_mgmt_params(wl);
7367b3115f2SLuciano Coelho 	if (ret < 0)
7377b3115f2SLuciano Coelho 		goto out_free_memmap;
7387b3115f2SLuciano Coelho 
7397b3115f2SLuciano Coelho 	/* configure hangover */
7407b3115f2SLuciano Coelho 	ret = wl12xx_acx_config_hangover(wl);
7417b3115f2SLuciano Coelho 	if (ret < 0)
7427b3115f2SLuciano Coelho 		goto out_free_memmap;
7437b3115f2SLuciano Coelho 
7447b3115f2SLuciano Coelho 	return 0;
7457b3115f2SLuciano Coelho 
7467b3115f2SLuciano Coelho  out_free_memmap:
7477b3115f2SLuciano Coelho 	kfree(wl->target_mem_map);
7487b3115f2SLuciano Coelho 	wl->target_mem_map = NULL;
7497b3115f2SLuciano Coelho 
7507b3115f2SLuciano Coelho 	return ret;
7517b3115f2SLuciano Coelho }
752