brintos

brintos / linux-shallow public Read only

0
0
Text · 46.1 KiB · 4087765 Raw
1696 lines · c
1/*2 * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>3 *4 * Permission to use, copy, modify, and/or distribute this software for any5 * purpose with or without fee is hereby granted, provided that the above6 * copyright notice and this permission notice appear in all copies.7 *8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.15 */16 17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt18 19#include <linux/module.h>20#include <linux/firmware.h>21#include <linux/platform_device.h>22#include <linux/of.h>23#include <linux/of_address.h>24#include <linux/rpmsg.h>25#include <linux/soc/qcom/smem_state.h>26#include <linux/soc/qcom/wcnss_ctrl.h>27#include <net/ipv6.h>28#include "wcn36xx.h"29#include "testmode.h"30#include "firmware.h"31 32unsigned int wcn36xx_dbg_mask;33module_param_named(debug_mask, wcn36xx_dbg_mask, uint, 0644);34MODULE_PARM_DESC(debug_mask, "Debugging mask");35 36#define CHAN2G(_freq, _idx) { \37	.band = NL80211_BAND_2GHZ, \38	.center_freq = (_freq), \39	.hw_value = (_idx), \40	.max_power = 25, \41}42 43#define CHAN5G(_freq, _idx, _phy_val) { \44	.band = NL80211_BAND_5GHZ, \45	.center_freq = (_freq), \46	.hw_value = (_phy_val) << HW_VALUE_PHY_SHIFT | HW_VALUE_CHANNEL(_idx), \47	.max_power = 25, \48}49 50/* The wcn firmware expects channel values to matching51 * their mnemonic values. So use these for .hw_value. */52static struct ieee80211_channel wcn_2ghz_channels[] = {53	CHAN2G(2412, 1), /* Channel 1 */54	CHAN2G(2417, 2), /* Channel 2 */55	CHAN2G(2422, 3), /* Channel 3 */56	CHAN2G(2427, 4), /* Channel 4 */57	CHAN2G(2432, 5), /* Channel 5 */58	CHAN2G(2437, 6), /* Channel 6 */59	CHAN2G(2442, 7), /* Channel 7 */60	CHAN2G(2447, 8), /* Channel 8 */61	CHAN2G(2452, 9), /* Channel 9 */62	CHAN2G(2457, 10), /* Channel 10 */63	CHAN2G(2462, 11), /* Channel 11 */64	CHAN2G(2467, 12), /* Channel 12 */65	CHAN2G(2472, 13), /* Channel 13 */66	CHAN2G(2484, 14)  /* Channel 14 */67 68};69 70static struct ieee80211_channel wcn_5ghz_channels[] = {71	CHAN5G(5180, 36, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW),72	CHAN5G(5200, 40, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW),73	CHAN5G(5220, 44, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH),74	CHAN5G(5240, 48, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH),75	CHAN5G(5260, 52, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW),76	CHAN5G(5280, 56, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW),77	CHAN5G(5300, 60, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH),78	CHAN5G(5320, 64, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH),79	CHAN5G(5500, 100, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW),80	CHAN5G(5520, 104, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW),81	CHAN5G(5540, 108, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH),82	CHAN5G(5560, 112, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH),83	CHAN5G(5580, 116, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW),84	CHAN5G(5600, 120, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW),85	CHAN5G(5620, 124, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH),86	CHAN5G(5640, 128, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH),87	CHAN5G(5660, 132, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW),88	CHAN5G(5680, 136, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW),89	CHAN5G(5700, 140, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH),90	CHAN5G(5720, 144, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH),91	CHAN5G(5745, 149, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW),92	CHAN5G(5765, 153, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW),93	CHAN5G(5785, 157, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH),94	CHAN5G(5805, 161, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH),95	CHAN5G(5825, 165, 0)96};97 98#define RATE(_bitrate, _hw_rate, _flags) { \99	.bitrate        = (_bitrate),                   \100	.flags          = (_flags),                     \101	.hw_value       = (_hw_rate),                   \102	.hw_value_short = (_hw_rate)  \103}104 105static struct ieee80211_rate wcn_2ghz_rates[] = {106	RATE(10, HW_RATE_INDEX_1MBPS, 0),107	RATE(20, HW_RATE_INDEX_2MBPS, IEEE80211_RATE_SHORT_PREAMBLE),108	RATE(55, HW_RATE_INDEX_5_5MBPS, IEEE80211_RATE_SHORT_PREAMBLE),109	RATE(110, HW_RATE_INDEX_11MBPS, IEEE80211_RATE_SHORT_PREAMBLE),110	RATE(60, HW_RATE_INDEX_6MBPS, 0),111	RATE(90, HW_RATE_INDEX_9MBPS, 0),112	RATE(120, HW_RATE_INDEX_12MBPS, 0),113	RATE(180, HW_RATE_INDEX_18MBPS, 0),114	RATE(240, HW_RATE_INDEX_24MBPS, 0),115	RATE(360, HW_RATE_INDEX_36MBPS, 0),116	RATE(480, HW_RATE_INDEX_48MBPS, 0),117	RATE(540, HW_RATE_INDEX_54MBPS, 0)118};119 120static struct ieee80211_rate wcn_5ghz_rates[] = {121	RATE(60, HW_RATE_INDEX_6MBPS, 0),122	RATE(90, HW_RATE_INDEX_9MBPS, 0),123	RATE(120, HW_RATE_INDEX_12MBPS, 0),124	RATE(180, HW_RATE_INDEX_18MBPS, 0),125	RATE(240, HW_RATE_INDEX_24MBPS, 0),126	RATE(360, HW_RATE_INDEX_36MBPS, 0),127	RATE(480, HW_RATE_INDEX_48MBPS, 0),128	RATE(540, HW_RATE_INDEX_54MBPS, 0)129};130 131static struct ieee80211_supported_band wcn_band_2ghz = {132	.channels	= wcn_2ghz_channels,133	.n_channels	= ARRAY_SIZE(wcn_2ghz_channels),134	.bitrates	= wcn_2ghz_rates,135	.n_bitrates	= ARRAY_SIZE(wcn_2ghz_rates),136	.ht_cap		= {137		.cap =	IEEE80211_HT_CAP_GRN_FLD |138			IEEE80211_HT_CAP_SGI_20 |139			IEEE80211_HT_CAP_DSSSCCK40 |140			IEEE80211_HT_CAP_LSIG_TXOP_PROT |141			IEEE80211_HT_CAP_SGI_40 |142			IEEE80211_HT_CAP_SUP_WIDTH_20_40,143		.ht_supported = true,144		.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,145		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,146		.mcs = {147			.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },148			.rx_highest = cpu_to_le16(72),149			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,150		}151	}152};153 154static struct ieee80211_supported_band wcn_band_5ghz = {155	.channels	= wcn_5ghz_channels,156	.n_channels	= ARRAY_SIZE(wcn_5ghz_channels),157	.bitrates	= wcn_5ghz_rates,158	.n_bitrates	= ARRAY_SIZE(wcn_5ghz_rates),159	.ht_cap		= {160		.cap =	IEEE80211_HT_CAP_GRN_FLD |161			IEEE80211_HT_CAP_SGI_20 |162			IEEE80211_HT_CAP_DSSSCCK40 |163			IEEE80211_HT_CAP_LSIG_TXOP_PROT |164			IEEE80211_HT_CAP_SGI_40 |165			IEEE80211_HT_CAP_SUP_WIDTH_20_40,166		.ht_supported = true,167		.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,168		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,169		.mcs = {170			.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },171			.rx_highest = cpu_to_le16(150),172			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,173		}174	}175};176 177#ifdef CONFIG_PM178 179static const struct wiphy_wowlan_support wowlan_support = {180	.flags = WIPHY_WOWLAN_ANY	|181		 WIPHY_WOWLAN_MAGIC_PKT	|182		 WIPHY_WOWLAN_SUPPORTS_GTK_REKEY183};184 185#endif186 187static inline u8 get_sta_index(struct ieee80211_vif *vif,188			       struct wcn36xx_sta *sta_priv)189{190	return NL80211_IFTYPE_STATION == vif->type ?191	       sta_priv->bss_sta_index :192	       sta_priv->sta_index;193}194 195static void wcn36xx_feat_caps_info(struct wcn36xx *wcn)196{197	int i;198 199	for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) {200		if (wcn36xx_firmware_get_feat_caps(wcn->fw_feat_caps, i)) {201			wcn36xx_dbg(WCN36XX_DBG_MAC, "FW Cap %s\n",202				    wcn36xx_firmware_get_cap_name(i));203		}204	}205}206 207static int wcn36xx_start(struct ieee80211_hw *hw)208{209	struct wcn36xx *wcn = hw->priv;210	int ret;211 212	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac start\n");213 214	/* SMD initialization */215	ret = wcn36xx_smd_open(wcn);216	if (ret) {217		wcn36xx_err("Failed to open smd channel: %d\n", ret);218		goto out_err;219	}220 221	/* Allocate memory pools for Mgmt BD headers and Data BD headers */222	ret = wcn36xx_dxe_allocate_mem_pools(wcn);223	if (ret) {224		wcn36xx_err("Failed to alloc DXE mempool: %d\n", ret);225		goto out_smd_close;226	}227 228	ret = wcn36xx_dxe_alloc_ctl_blks(wcn);229	if (ret) {230		wcn36xx_err("Failed to alloc DXE ctl blocks: %d\n", ret);231		goto out_free_dxe_pool;232	}233 234	ret = wcn36xx_smd_load_nv(wcn);235	if (ret) {236		wcn36xx_err("Failed to push NV to chip\n");237		goto out_free_dxe_ctl;238	}239 240	ret = wcn36xx_smd_start(wcn);241	if (ret) {242		wcn36xx_err("Failed to start chip\n");243		goto out_free_dxe_ctl;244	}245 246	if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {247		ret = wcn36xx_smd_feature_caps_exchange(wcn);248		if (ret)249			wcn36xx_warn("Exchange feature caps failed\n");250		else251			wcn36xx_feat_caps_info(wcn);252	}253 254	/* DMA channel initialization */255	ret = wcn36xx_dxe_init(wcn);256	if (ret) {257		wcn36xx_err("DXE init failed\n");258		goto out_smd_stop;259	}260 261	wcn36xx_debugfs_init(wcn);262 263	INIT_LIST_HEAD(&wcn->vif_list);264	spin_lock_init(&wcn->dxe_lock);265	spin_lock_init(&wcn->survey_lock);266 267	return 0;268 269out_smd_stop:270	wcn36xx_smd_stop(wcn);271out_free_dxe_ctl:272	wcn36xx_dxe_free_ctl_blks(wcn);273out_free_dxe_pool:274	wcn36xx_dxe_free_mem_pools(wcn);275out_smd_close:276	wcn36xx_smd_close(wcn);277out_err:278	return ret;279}280 281static void wcn36xx_stop(struct ieee80211_hw *hw, bool suspend)282{283	struct wcn36xx *wcn = hw->priv;284 285	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac stop\n");286 287	mutex_lock(&wcn->scan_lock);288	if (wcn->scan_req) {289		struct cfg80211_scan_info scan_info = {290			.aborted = true,291		};292 293		ieee80211_scan_completed(wcn->hw, &scan_info);294	}295	wcn->scan_req = NULL;296	mutex_unlock(&wcn->scan_lock);297 298	wcn36xx_debugfs_exit(wcn);299	wcn36xx_smd_stop(wcn);300	wcn36xx_dxe_deinit(wcn);301	wcn36xx_smd_close(wcn);302 303	wcn36xx_dxe_free_mem_pools(wcn);304	wcn36xx_dxe_free_ctl_blks(wcn);305}306 307static void wcn36xx_change_ps(struct wcn36xx *wcn, bool enable)308{309	struct ieee80211_vif *vif = NULL;310	struct wcn36xx_vif *tmp;311 312	list_for_each_entry(tmp, &wcn->vif_list, list) {313		vif = wcn36xx_priv_to_vif(tmp);314		if (enable && !wcn->sw_scan) {315			if (vif->cfg.ps) /* ps allowed ? */316				wcn36xx_pmc_enter_bmps_state(wcn, vif);317		} else {318			wcn36xx_pmc_exit_bmps_state(wcn, vif);319		}320	}321}322 323static void wcn36xx_change_opchannel(struct wcn36xx *wcn, int ch)324{325	struct ieee80211_vif *vif = NULL;326	struct wcn36xx_vif *tmp;327	struct ieee80211_supported_band *band;328	struct ieee80211_channel *channel = NULL;329	unsigned long flags;330	int i, j;331 332	for (i = 0; i < ARRAY_SIZE(wcn->hw->wiphy->bands); i++) {333		band = wcn->hw->wiphy->bands[i];334		if (!band)335			break;336		for (j = 0; j < band->n_channels; j++) {337			if (HW_VALUE_CHANNEL(band->channels[j].hw_value) == ch) {338				channel = &band->channels[j];339				break;340			}341		}342		if (channel)343			break;344	}345 346	if (!channel) {347		wcn36xx_err("Cannot tune to channel %d\n", ch);348		return;349	}350 351	spin_lock_irqsave(&wcn->survey_lock, flags);352	wcn->band = band;353	wcn->channel = channel;354	spin_unlock_irqrestore(&wcn->survey_lock, flags);355 356	list_for_each_entry(tmp, &wcn->vif_list, list) {357		vif = wcn36xx_priv_to_vif(tmp);358		wcn36xx_smd_switch_channel(wcn, vif, ch);359	}360 361	return;362}363 364static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)365{366	struct wcn36xx *wcn = hw->priv;367	int ret;368 369	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac config changed 0x%08x\n", changed);370 371	mutex_lock(&wcn->conf_mutex);372 373	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {374		int ch = WCN36XX_HW_CHANNEL(wcn);375		wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n",376			    ch);377 378		if (wcn->sw_scan_opchannel == ch && wcn->sw_scan_channel) {379			/* If channel is the initial operating channel, we may380			 * want to receive/transmit regular data packets, then381			 * simply stop the scan session and exit PS mode.382			 */383			if (wcn->sw_scan_channel)384				wcn36xx_smd_end_scan(wcn, wcn->sw_scan_channel);385			if (wcn->sw_scan_init) {386				wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN,387							wcn->sw_scan_vif);388			}389		} else if (wcn->sw_scan) {390			/* A scan is ongoing, do not change the operating391			 * channel, but start a scan session on the channel.392			 */393			if (wcn->sw_scan_channel)394				wcn36xx_smd_end_scan(wcn, wcn->sw_scan_channel);395			if (!wcn->sw_scan_init) {396				/* This can fail if we are unable to notify the397				 * operating channel.398				 */399				ret = wcn36xx_smd_init_scan(wcn,400							    HAL_SYS_MODE_SCAN,401							    wcn->sw_scan_vif);402				if (ret) {403					mutex_unlock(&wcn->conf_mutex);404					return -EIO;405				}406			}407			wcn36xx_smd_start_scan(wcn, ch);408		} else {409			wcn36xx_change_opchannel(wcn, ch);410		}411	}412 413	if (changed & IEEE80211_CONF_CHANGE_PS)414		wcn36xx_change_ps(wcn, hw->conf.flags & IEEE80211_CONF_PS);415 416	if (changed & IEEE80211_CONF_CHANGE_IDLE) {417		if (hw->conf.flags & IEEE80211_CONF_IDLE)418			wcn36xx_smd_enter_imps(wcn);419		else420			wcn36xx_smd_exit_imps(wcn);421	}422 423	mutex_unlock(&wcn->conf_mutex);424 425	return 0;426}427 428static void wcn36xx_configure_filter(struct ieee80211_hw *hw,429				     unsigned int changed,430				     unsigned int *total, u64 multicast)431{432	struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp;433	struct wcn36xx *wcn = hw->priv;434	struct wcn36xx_vif *tmp;435	struct ieee80211_vif *vif = NULL;436 437	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n");438 439	mutex_lock(&wcn->conf_mutex);440 441	*total &= FIF_ALLMULTI;442 443	fp = (void *)(unsigned long)multicast;444	list_for_each_entry(tmp, &wcn->vif_list, list) {445		vif = wcn36xx_priv_to_vif(tmp);446 447		/* FW handles MC filtering only when connected as STA */448		if (*total & FIF_ALLMULTI)449			wcn36xx_smd_set_mc_list(wcn, vif, NULL);450		else if (NL80211_IFTYPE_STATION == vif->type && tmp->sta_assoc)451			wcn36xx_smd_set_mc_list(wcn, vif, fp);452	}453 454	mutex_unlock(&wcn->conf_mutex);455	kfree(fp);456}457 458static u64 wcn36xx_prepare_multicast(struct ieee80211_hw *hw,459				     struct netdev_hw_addr_list *mc_list)460{461	struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp;462	struct netdev_hw_addr *ha;463 464	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac prepare multicast list\n");465	fp = kzalloc(sizeof(*fp), GFP_ATOMIC);466	if (!fp) {467		wcn36xx_err("Out of memory setting filters.\n");468		return 0;469	}470 471	fp->mc_addr_count = 0;472	/* update multicast filtering parameters */473	if (netdev_hw_addr_list_count(mc_list) <=474	    WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS) {475		netdev_hw_addr_list_for_each(ha, mc_list) {476			memcpy(fp->mc_addr[fp->mc_addr_count],477					ha->addr, ETH_ALEN);478			fp->mc_addr_count++;479		}480	}481 482	return (u64)(unsigned long)fp;483}484 485static void wcn36xx_tx(struct ieee80211_hw *hw,486		       struct ieee80211_tx_control *control,487		       struct sk_buff *skb)488{489	struct wcn36xx *wcn = hw->priv;490	struct wcn36xx_sta *sta_priv = NULL;491 492	if (control->sta)493		sta_priv = wcn36xx_sta_to_priv(control->sta);494 495	if (wcn36xx_start_tx(wcn, sta_priv, skb))496		ieee80211_free_txskb(wcn->hw, skb);497}498 499static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,500			   struct ieee80211_vif *vif,501			   struct ieee80211_sta *sta,502			   struct ieee80211_key_conf *key_conf)503{504	struct wcn36xx *wcn = hw->priv;505	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);506	struct wcn36xx_sta *sta_priv = sta ? wcn36xx_sta_to_priv(sta) : NULL;507	int ret = 0;508	u8 key[WLAN_MAX_KEY_LEN];509 510	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 set key\n");511	wcn36xx_dbg(WCN36XX_DBG_MAC, "Key: cmd=0x%x algo:0x%x, id:%d, len:%d flags 0x%x\n",512		    cmd, key_conf->cipher, key_conf->keyidx,513		    key_conf->keylen, key_conf->flags);514	wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "KEY: ",515			 key_conf->key,516			 key_conf->keylen);517 518	mutex_lock(&wcn->conf_mutex);519 520	switch (key_conf->cipher) {521	case WLAN_CIPHER_SUITE_WEP40:522		vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40;523		break;524	case WLAN_CIPHER_SUITE_WEP104:525		vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP104;526		break;527	case WLAN_CIPHER_SUITE_CCMP:528		vif_priv->encrypt_type = WCN36XX_HAL_ED_CCMP;529		break;530	case WLAN_CIPHER_SUITE_TKIP:531		vif_priv->encrypt_type = WCN36XX_HAL_ED_TKIP;532		break;533	default:534		wcn36xx_err("Unsupported key type 0x%x\n",535			      key_conf->cipher);536		ret = -EOPNOTSUPP;537		goto out;538	}539 540	switch (cmd) {541	case SET_KEY:542		if (WCN36XX_HAL_ED_TKIP == vif_priv->encrypt_type) {543			/*544			 * Supplicant is sending key in the wrong order:545			 * Temporal Key (16 b) - TX MIC (8 b) - RX MIC (8 b)546			 * but HW expects it to be in the order as described in547			 * IEEE 802.11 spec (see chapter 11.7) like this:548			 * Temporal Key (16 b) - RX MIC (8 b) - TX MIC (8 b)549			 */550			memcpy(key, key_conf->key, 16);551			memcpy(key + 16, key_conf->key + 24, 8);552			memcpy(key + 24, key_conf->key + 16, 8);553		} else {554			memcpy(key, key_conf->key, key_conf->keylen);555		}556 557		if (IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags) {558			sta_priv->is_data_encrypted = true;559			/* Reconfigure bss with encrypt_type */560			if (NL80211_IFTYPE_STATION == vif->type) {561				wcn36xx_smd_config_bss(wcn,562						       vif,563						       sta,564						       sta->addr,565						       true);566				wcn36xx_smd_config_sta(wcn, vif, sta);567			}568 569			wcn36xx_smd_set_stakey(wcn,570				vif_priv->encrypt_type,571				key_conf->keyidx,572				key_conf->keylen,573				key,574				get_sta_index(vif, sta_priv));575		} else {576			wcn36xx_smd_set_bsskey(wcn,577				vif_priv->encrypt_type,578				vif_priv->bss_index,579				key_conf->keyidx,580				key_conf->keylen,581				key);582 583			if ((WLAN_CIPHER_SUITE_WEP40 == key_conf->cipher) ||584			    (WLAN_CIPHER_SUITE_WEP104 == key_conf->cipher)) {585				list_for_each_entry(sta_priv,586						    &vif_priv->sta_list, list) {587					sta_priv->is_data_encrypted = true;588					wcn36xx_smd_set_stakey(wcn,589						vif_priv->encrypt_type,590						key_conf->keyidx,591						key_conf->keylen,592						key,593						get_sta_index(vif, sta_priv));594				}595			}596		}597		break;598	case DISABLE_KEY:599		if (!(IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags)) {600			if (vif_priv->bss_index != WCN36XX_HAL_BSS_INVALID_IDX)601				wcn36xx_smd_remove_bsskey(wcn,602					vif_priv->encrypt_type,603					vif_priv->bss_index,604					key_conf->keyidx);605 606			vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE;607		} else {608			sta_priv->is_data_encrypted = false;609			/* do not remove key if disassociated */610			if (sta_priv->aid)611				wcn36xx_smd_remove_stakey(wcn,612					vif_priv->encrypt_type,613					key_conf->keyidx,614					get_sta_index(vif, sta_priv));615		}616		break;617	default:618		wcn36xx_err("Unsupported key cmd 0x%x\n", cmd);619		ret = -EOPNOTSUPP;620		goto out;621	}622 623out:624	mutex_unlock(&wcn->conf_mutex);625 626	return ret;627}628 629static int wcn36xx_hw_scan(struct ieee80211_hw *hw,630			   struct ieee80211_vif *vif,631			   struct ieee80211_scan_request *hw_req)632{633	struct wcn36xx *wcn = hw->priv;634 635	if (!wcn36xx_firmware_get_feat_caps(wcn->fw_feat_caps, SCAN_OFFLOAD)) {636		/* fallback to mac80211 software scan */637		return 1;638	}639 640	/* Firmware scan offload is limited to 48 channels, fallback to641	 * software driven scanning otherwise.642	 */643	if (hw_req->req.n_channels > 48) {644		wcn36xx_warn("Offload scan aborted, n_channels=%u",645			     hw_req->req.n_channels);646		return 1;647	}648 649	mutex_lock(&wcn->scan_lock);650	if (wcn->scan_req) {651		mutex_unlock(&wcn->scan_lock);652		return -EBUSY;653	}654 655	wcn->scan_aborted = false;656	wcn->scan_req = &hw_req->req;657 658	mutex_unlock(&wcn->scan_lock);659 660	wcn36xx_smd_update_channel_list(wcn, &hw_req->req);661	return wcn36xx_smd_start_hw_scan(wcn, vif, &hw_req->req);662}663 664static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw,665				   struct ieee80211_vif *vif)666{667	struct wcn36xx *wcn = hw->priv;668 669	mutex_lock(&wcn->scan_lock);670	wcn->scan_aborted = true;671	mutex_unlock(&wcn->scan_lock);672 673	if (wcn36xx_firmware_get_feat_caps(wcn->fw_feat_caps, SCAN_OFFLOAD)) {674		/* ieee80211_scan_completed will be called on FW scan675		 * indication */676		wcn36xx_smd_stop_hw_scan(wcn);677	}678}679 680static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw,681				  struct ieee80211_vif *vif,682				  const u8 *mac_addr)683{684	struct wcn36xx *wcn = hw->priv;685	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);686 687	wcn36xx_dbg(WCN36XX_DBG_MAC, "sw_scan_start");688 689	wcn->sw_scan = true;690	wcn->sw_scan_vif = vif;691	wcn->sw_scan_channel = 0;692	if (vif_priv->sta_assoc)693		wcn->sw_scan_opchannel = WCN36XX_HW_CHANNEL(wcn);694	else695		wcn->sw_scan_opchannel = 0;696}697 698static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw,699				     struct ieee80211_vif *vif)700{701	struct wcn36xx *wcn = hw->priv;702 703	wcn36xx_dbg(WCN36XX_DBG_MAC, "sw_scan_complete");704 705	/* ensure that any scan session is finished */706	if (wcn->sw_scan_channel)707		wcn36xx_smd_end_scan(wcn, wcn->sw_scan_channel);708	if (wcn->sw_scan_init) {709		wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN,710					wcn->sw_scan_vif);711	}712	wcn->sw_scan = false;713	wcn->sw_scan_opchannel = 0;714}715 716static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,717					 enum nl80211_band band)718{719	int i, size;720	u16 *rates_table;721	struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);722	u32 rates = sta->deflink.supp_rates[band];723 724	memset(&sta_priv->supported_rates, 0,725		sizeof(sta_priv->supported_rates));726	sta_priv->supported_rates.op_rate_mode = STA_11n;727 728	size = ARRAY_SIZE(sta_priv->supported_rates.dsss_rates);729	rates_table = sta_priv->supported_rates.dsss_rates;730	if (band == NL80211_BAND_2GHZ) {731		for (i = 0; i < size; i++) {732			if (rates & 0x01) {733				rates_table[i] = wcn_2ghz_rates[i].hw_value;734				rates = rates >> 1;735			}736		}737	}738 739	size = ARRAY_SIZE(sta_priv->supported_rates.ofdm_rates);740	rates_table = sta_priv->supported_rates.ofdm_rates;741	for (i = 0; i < size; i++) {742		if (rates & 0x01) {743			rates_table[i] = wcn_5ghz_rates[i].hw_value;744			rates = rates >> 1;745		}746	}747 748	if (sta->deflink.ht_cap.ht_supported) {749		BUILD_BUG_ON(sizeof(sta->deflink.ht_cap.mcs.rx_mask) >750			     sizeof(sta_priv->supported_rates.supported_mcs_set));751		memcpy(sta_priv->supported_rates.supported_mcs_set,752		       sta->deflink.ht_cap.mcs.rx_mask,753		       sizeof(sta->deflink.ht_cap.mcs.rx_mask));754	}755 756	if (sta->deflink.vht_cap.vht_supported) {757		sta_priv->supported_rates.op_rate_mode = STA_11ac;758		sta_priv->supported_rates.vht_rx_mcs_map =759			le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map);760		sta_priv->supported_rates.vht_tx_mcs_map =761			le16_to_cpu(sta->deflink.vht_cap.vht_mcs.tx_mcs_map);762	}763}764 765void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates)766{767	u16 ofdm_rates[WCN36XX_HAL_NUM_OFDM_RATES] = {768		HW_RATE_INDEX_6MBPS,769		HW_RATE_INDEX_9MBPS,770		HW_RATE_INDEX_12MBPS,771		HW_RATE_INDEX_18MBPS,772		HW_RATE_INDEX_24MBPS,773		HW_RATE_INDEX_36MBPS,774		HW_RATE_INDEX_48MBPS,775		HW_RATE_INDEX_54MBPS776	};777	u16 dsss_rates[WCN36XX_HAL_NUM_DSSS_RATES] = {778		HW_RATE_INDEX_1MBPS,779		HW_RATE_INDEX_2MBPS,780		HW_RATE_INDEX_5_5MBPS,781		HW_RATE_INDEX_11MBPS782	};783 784	rates->op_rate_mode = STA_11n;785	memcpy(rates->dsss_rates, dsss_rates,786		sizeof(*dsss_rates) * WCN36XX_HAL_NUM_DSSS_RATES);787	memcpy(rates->ofdm_rates, ofdm_rates,788		sizeof(*ofdm_rates) * WCN36XX_HAL_NUM_OFDM_RATES);789	rates->supported_mcs_set[0] = 0xFF;790}791 792void wcn36xx_set_default_rates_v1(struct wcn36xx_hal_supported_rates_v1 *rates)793{794	rates->op_rate_mode = STA_11ac;795	rates->vht_rx_mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9;796	rates->vht_tx_mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9;797}798 799static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,800				     struct ieee80211_vif *vif,801				     struct ieee80211_bss_conf *bss_conf,802				     u64 changed)803{804	struct wcn36xx *wcn = hw->priv;805	struct sk_buff *skb = NULL;806	u16 tim_off, tim_len;807	enum wcn36xx_hal_link_state link_state;808	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);809 810	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%llx\n",811		    vif, changed);812 813	mutex_lock(&wcn->conf_mutex);814 815	if (changed & BSS_CHANGED_BEACON_INFO) {816		wcn36xx_dbg(WCN36XX_DBG_MAC,817			    "mac bss changed dtim period %d\n",818			    bss_conf->dtim_period);819 820		vif_priv->dtim_period = bss_conf->dtim_period;821	}822 823	if (changed & BSS_CHANGED_BSSID) {824		wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed_bssid %pM\n",825			    bss_conf->bssid);826 827		if (!is_zero_ether_addr(bss_conf->bssid)) {828			vif_priv->is_joining = true;829			vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX;830			wcn36xx_smd_set_link_st(wcn, bss_conf->bssid, vif->addr,831						WCN36XX_HAL_LINK_PREASSOC_STATE);832			wcn36xx_smd_join(wcn, bss_conf->bssid,833					 vif->addr, WCN36XX_HW_CHANNEL(wcn));834			wcn36xx_smd_config_bss(wcn, vif, NULL,835					       bss_conf->bssid, false);836		} else {837			vif_priv->is_joining = false;838			wcn36xx_smd_delete_bss(wcn, vif);839			wcn36xx_smd_set_link_st(wcn, bss_conf->bssid, vif->addr,840						WCN36XX_HAL_LINK_IDLE_STATE);841			vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE;842		}843	}844 845	if (changed & BSS_CHANGED_SSID) {846		wcn36xx_dbg(WCN36XX_DBG_MAC,847			    "mac bss changed ssid\n");848		wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "ssid ",849				 vif->cfg.ssid, vif->cfg.ssid_len);850 851		vif_priv->ssid.length = vif->cfg.ssid_len;852		memcpy(&vif_priv->ssid.ssid,853		       vif->cfg.ssid,854		       vif->cfg.ssid_len);855	}856 857	if (changed & BSS_CHANGED_ASSOC) {858		vif_priv->is_joining = false;859		if (vif->cfg.assoc) {860			struct ieee80211_sta *sta;861			struct wcn36xx_sta *sta_priv;862 863			wcn36xx_dbg(WCN36XX_DBG_MAC,864				    "mac assoc bss %pM vif %pM AID=%d\n",865				     bss_conf->bssid,866				     vif->addr,867				     vif->cfg.aid);868 869			vif_priv->sta_assoc = true;870 871			/*872			 * Holding conf_mutex ensures mutal exclusion with873			 * wcn36xx_sta_remove() and as such ensures that sta874			 * won't be freed while we're operating on it. As such875			 * we do not need to hold the rcu_read_lock().876			 */877			sta = ieee80211_find_sta(vif, bss_conf->bssid);878			if (!sta) {879				wcn36xx_err("sta %pM is not found\n",880					      bss_conf->bssid);881				goto out;882			}883			sta_priv = wcn36xx_sta_to_priv(sta);884 885			wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn));886 887			wcn36xx_smd_set_link_st(wcn, bss_conf->bssid,888				vif->addr,889				WCN36XX_HAL_LINK_POSTASSOC_STATE);890			wcn36xx_smd_config_bss(wcn, vif, sta,891					       bss_conf->bssid,892					       true);893			sta_priv->aid = vif->cfg.aid;894			/*895			 * config_sta must be called from  because this is the896			 * place where AID is available.897			 */898			wcn36xx_smd_config_sta(wcn, vif, sta);899			if (vif->type == NL80211_IFTYPE_STATION)900				wcn36xx_smd_add_beacon_filter(wcn, vif);901			wcn36xx_enable_keep_alive_null_packet(wcn, vif);902		} else {903			wcn36xx_dbg(WCN36XX_DBG_MAC,904				    "disassociated bss %pM vif %pM AID=%d\n",905				    bss_conf->bssid,906				    vif->addr,907				    vif->cfg.aid);908			vif_priv->sta_assoc = false;909			wcn36xx_smd_set_link_st(wcn,910						bss_conf->bssid,911						vif->addr,912						WCN36XX_HAL_LINK_IDLE_STATE);913		}914	}915 916	if (changed & BSS_CHANGED_AP_PROBE_RESP) {917		wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed ap probe resp\n");918		skb = ieee80211_proberesp_get(hw, vif);919		if (!skb) {920			wcn36xx_err("failed to alloc probereq skb\n");921			goto out;922		}923 924		wcn36xx_smd_update_proberesp_tmpl(wcn, vif, skb);925		dev_kfree_skb(skb);926	}927 928	if (changed & BSS_CHANGED_BEACON_ENABLED ||929	    changed & BSS_CHANGED_BEACON) {930		wcn36xx_dbg(WCN36XX_DBG_MAC,931			    "mac bss changed beacon enabled %d\n",932			    bss_conf->enable_beacon);933 934		if (bss_conf->enable_beacon) {935			vif_priv->dtim_period = bss_conf->dtim_period;936			vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX;937			wcn36xx_smd_config_bss(wcn, vif, NULL,938					       vif->addr, false);939			skb = ieee80211_beacon_get_tim(hw, vif, &tim_off,940						       &tim_len, 0);941			if (!skb) {942				wcn36xx_err("failed to alloc beacon skb\n");943				goto out;944			}945			wcn36xx_smd_send_beacon(wcn, vif, skb, tim_off, 0);946			dev_kfree_skb(skb);947 948			if (vif->type == NL80211_IFTYPE_ADHOC ||949			    vif->type == NL80211_IFTYPE_MESH_POINT)950				link_state = WCN36XX_HAL_LINK_IBSS_STATE;951			else952				link_state = WCN36XX_HAL_LINK_AP_STATE;953 954			wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,955						link_state);956		} else {957			wcn36xx_smd_delete_bss(wcn, vif);958			wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,959						WCN36XX_HAL_LINK_IDLE_STATE);960		}961	}962out:963 964	mutex_unlock(&wcn->conf_mutex);965}966 967/* this is required when using IEEE80211_HW_HAS_RATE_CONTROL */968static int wcn36xx_set_rts_threshold(struct ieee80211_hw *hw, u32 value)969{970	struct wcn36xx *wcn = hw->priv;971	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac set RTS threshold %d\n", value);972 973	mutex_lock(&wcn->conf_mutex);974	wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_RTS_THRESHOLD, value);975	mutex_unlock(&wcn->conf_mutex);976 977	return 0;978}979 980static void wcn36xx_remove_interface(struct ieee80211_hw *hw,981				     struct ieee80211_vif *vif)982{983	struct wcn36xx *wcn = hw->priv;984	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);985	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac remove interface vif %p\n", vif);986 987	mutex_lock(&wcn->conf_mutex);988 989	list_del(&vif_priv->list);990	wcn36xx_smd_delete_sta_self(wcn, vif->addr);991 992	mutex_unlock(&wcn->conf_mutex);993}994 995static int wcn36xx_add_interface(struct ieee80211_hw *hw,996				 struct ieee80211_vif *vif)997{998	struct wcn36xx *wcn = hw->priv;999	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);1000 1001	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac add interface vif %p type %d\n",1002		    vif, vif->type);1003 1004	if (!(NL80211_IFTYPE_STATION == vif->type ||1005	      NL80211_IFTYPE_AP == vif->type ||1006	      NL80211_IFTYPE_ADHOC == vif->type ||1007	      NL80211_IFTYPE_MESH_POINT == vif->type)) {1008		wcn36xx_warn("Unsupported interface type requested: %d\n",1009			     vif->type);1010		return -EOPNOTSUPP;1011	}1012 1013	mutex_lock(&wcn->conf_mutex);1014 1015	vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX;1016	INIT_LIST_HEAD(&vif_priv->sta_list);1017	list_add(&vif_priv->list, &wcn->vif_list);1018	wcn36xx_smd_add_sta_self(wcn, vif);1019 1020	mutex_unlock(&wcn->conf_mutex);1021 1022	return 0;1023}1024 1025static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,1026			   struct ieee80211_sta *sta)1027{1028	struct wcn36xx *wcn = hw->priv;1029	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);1030	struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);1031	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n",1032		    vif, sta->addr);1033 1034	mutex_lock(&wcn->conf_mutex);1035 1036	spin_lock_init(&sta_priv->ampdu_lock);1037	sta_priv->vif = vif_priv;1038	list_add(&sta_priv->list, &vif_priv->sta_list);1039 1040	/*1041	 * For STA mode HW will be configured on BSS_CHANGED_ASSOC because1042	 * at this stage AID is not available yet.1043	 */1044	if (NL80211_IFTYPE_STATION != vif->type) {1045		wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn));1046		sta_priv->aid = sta->aid;1047		wcn36xx_smd_config_sta(wcn, vif, sta);1048	}1049 1050	mutex_unlock(&wcn->conf_mutex);1051 1052	return 0;1053}1054 1055static int wcn36xx_sta_remove(struct ieee80211_hw *hw,1056			      struct ieee80211_vif *vif,1057			      struct ieee80211_sta *sta)1058{1059	struct wcn36xx *wcn = hw->priv;1060	struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);1061 1062	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta remove vif %p sta %pM index %d\n",1063		    vif, sta->addr, sta_priv->sta_index);1064 1065	mutex_lock(&wcn->conf_mutex);1066 1067	list_del(&sta_priv->list);1068	wcn36xx_smd_delete_sta(wcn, sta_priv->sta_index);1069	sta_priv->vif = NULL;1070 1071	mutex_unlock(&wcn->conf_mutex);1072 1073	return 0;1074}1075 1076#ifdef CONFIG_PM1077 1078static struct ieee80211_vif *wcn36xx_get_first_assoc_vif(struct wcn36xx *wcn)1079{1080	struct wcn36xx_vif *vif_priv = NULL;1081	struct ieee80211_vif *vif = NULL;1082 1083	list_for_each_entry(vif_priv, &wcn->vif_list, list) {1084		if (vif_priv->sta_assoc) {1085			vif = wcn36xx_priv_to_vif(vif_priv);1086			break;1087		}1088	}1089	return vif;1090}1091 1092static int wcn36xx_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow)1093{1094	struct wcn36xx *wcn = hw->priv;1095	struct ieee80211_vif *vif = NULL;1096	int ret = 0;1097 1098	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac suspend\n");1099 1100	mutex_lock(&wcn->conf_mutex);1101 1102	vif = wcn36xx_get_first_assoc_vif(wcn);1103	if (vif) {1104		ret = wcn36xx_smd_arp_offload(wcn, vif, true);1105		if (ret)1106			goto out;1107		ret = wcn36xx_smd_ipv6_ns_offload(wcn, vif, true);1108		if (ret)1109			goto out;1110		ret = wcn36xx_smd_gtk_offload(wcn, vif, true);1111		if (ret)1112			goto out;1113		ret = wcn36xx_smd_set_power_params(wcn, true);1114		if (ret)1115			goto out;1116		ret = wcn36xx_smd_wlan_host_suspend_ind(wcn);1117	}1118 1119	/* Disable IRQ, we don't want to handle any packet before mac80211 is1120	 * resumed and ready to receive packets.1121	 */1122	disable_irq(wcn->tx_irq);1123	disable_irq(wcn->rx_irq);1124 1125out:1126	mutex_unlock(&wcn->conf_mutex);1127	return ret;1128}1129 1130static int wcn36xx_resume(struct ieee80211_hw *hw)1131{1132	struct wcn36xx *wcn = hw->priv;1133	struct ieee80211_vif *vif = NULL;1134 1135	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac resume\n");1136 1137	mutex_lock(&wcn->conf_mutex);1138	vif = wcn36xx_get_first_assoc_vif(wcn);1139	if (vif) {1140		wcn36xx_smd_host_resume(wcn);1141		wcn36xx_smd_set_power_params(wcn, false);1142		wcn36xx_smd_gtk_offload_get_info(wcn, vif);1143		wcn36xx_smd_gtk_offload(wcn, vif, false);1144		wcn36xx_smd_ipv6_ns_offload(wcn, vif, false);1145		wcn36xx_smd_arp_offload(wcn, vif, false);1146	}1147 1148	enable_irq(wcn->tx_irq);1149	enable_irq(wcn->rx_irq);1150 1151	mutex_unlock(&wcn->conf_mutex);1152 1153	return 0;1154}1155 1156static void wcn36xx_set_rekey_data(struct ieee80211_hw *hw,1157				   struct ieee80211_vif *vif,1158				   struct cfg80211_gtk_rekey_data *data)1159{1160	struct wcn36xx *wcn = hw->priv;1161	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);1162 1163	mutex_lock(&wcn->conf_mutex);1164 1165	memcpy(vif_priv->rekey_data.kek, data->kek, NL80211_KEK_LEN);1166	memcpy(vif_priv->rekey_data.kck, data->kck, NL80211_KCK_LEN);1167	vif_priv->rekey_data.replay_ctr =1168		cpu_to_le64(be64_to_cpup((__be64 *)data->replay_ctr));1169	vif_priv->rekey_data.valid = true;1170 1171	mutex_unlock(&wcn->conf_mutex);1172}1173 1174#endif1175 1176static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,1177		    struct ieee80211_vif *vif,1178		    struct ieee80211_ampdu_params *params)1179{1180	struct wcn36xx *wcn = hw->priv;1181	struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(params->sta);1182	struct ieee80211_sta *sta = params->sta;1183	enum ieee80211_ampdu_mlme_action action = params->action;1184	u16 tid = params->tid;1185	u16 *ssn = &params->ssn;1186	int ret = 0;1187	int session;1188 1189	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",1190		    action, tid);1191 1192	mutex_lock(&wcn->conf_mutex);1193 1194	switch (action) {1195	case IEEE80211_AMPDU_RX_START:1196		sta_priv->tid = tid;1197		session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0,1198						     get_sta_index(vif, sta_priv));1199		if (session < 0) {1200			ret = session;1201			goto out;1202		}1203		wcn36xx_smd_add_ba(wcn, session);1204		break;1205	case IEEE80211_AMPDU_RX_STOP:1206		wcn36xx_smd_del_ba(wcn, tid, 0, get_sta_index(vif, sta_priv));1207		break;1208	case IEEE80211_AMPDU_TX_START:1209		spin_lock_bh(&sta_priv->ampdu_lock);1210		sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;1211		spin_unlock_bh(&sta_priv->ampdu_lock);1212 1213		/* Replace the mac80211 ssn with the firmware one */1214		wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu ssn = %u\n", *ssn);1215		wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv), tid, ssn);1216		wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu fw-ssn = %u\n", *ssn);1217 1218		/* Start BA session */1219		session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1,1220						     get_sta_index(vif, sta_priv));1221		if (session < 0) {1222			ret = session;1223			goto out;1224		}1225		ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;1226		break;1227	case IEEE80211_AMPDU_TX_OPERATIONAL:1228		spin_lock_bh(&sta_priv->ampdu_lock);1229		sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL;1230		spin_unlock_bh(&sta_priv->ampdu_lock);1231 1232		break;1233	case IEEE80211_AMPDU_TX_STOP_FLUSH:1234	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:1235	case IEEE80211_AMPDU_TX_STOP_CONT:1236		spin_lock_bh(&sta_priv->ampdu_lock);1237		sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_NONE;1238		spin_unlock_bh(&sta_priv->ampdu_lock);1239 1240		wcn36xx_smd_del_ba(wcn, tid, 1, get_sta_index(vif, sta_priv));1241		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);1242		break;1243	default:1244		wcn36xx_err("Unknown AMPDU action\n");1245	}1246 1247out:1248	mutex_unlock(&wcn->conf_mutex);1249 1250	return ret;1251}1252 1253#if IS_ENABLED(CONFIG_IPV6)1254static void wcn36xx_ipv6_addr_change(struct ieee80211_hw *hw,1255				     struct ieee80211_vif *vif,1256				     struct inet6_dev *idev)1257{1258	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);1259	struct inet6_ifaddr *ifa;1260	int idx = 0;1261 1262	memset(vif_priv->tentative_addrs, 0, sizeof(vif_priv->tentative_addrs));1263 1264	read_lock_bh(&idev->lock);1265	list_for_each_entry(ifa, &idev->addr_list, if_list) {1266		vif_priv->target_ipv6_addrs[idx] = ifa->addr;1267		if (ifa->flags & IFA_F_TENTATIVE)1268			__set_bit(idx, vif_priv->tentative_addrs);1269		idx++;1270		if (idx >= WCN36XX_HAL_IPV6_OFFLOAD_ADDR_MAX)1271			break;1272		wcn36xx_dbg(WCN36XX_DBG_MAC, "%pI6 %s\n", &ifa->addr,1273			    (ifa->flags & IFA_F_TENTATIVE) ? "tentative" : NULL);1274	}1275	read_unlock_bh(&idev->lock);1276 1277	vif_priv->num_target_ipv6_addrs = idx;1278}1279#endif1280 1281static void wcn36xx_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,1282			  u32 queues, bool drop)1283{1284	struct wcn36xx *wcn = hw->priv;1285 1286	if (wcn36xx_dxe_tx_flush(wcn)) {1287		wcn36xx_err("Failed to flush hardware tx queues\n");1288	}1289}1290 1291static int wcn36xx_get_survey(struct ieee80211_hw *hw, int idx,1292			      struct survey_info *survey)1293{1294	struct wcn36xx *wcn = hw->priv;1295	struct ieee80211_supported_band *sband;1296	struct wcn36xx_chan_survey *chan_survey;1297	int band_idx;1298	unsigned long flags;1299 1300	sband = wcn->hw->wiphy->bands[NL80211_BAND_2GHZ];1301	band_idx = idx;1302	if (band_idx >= sband->n_channels) {1303		band_idx -= sband->n_channels;1304		sband = wcn->hw->wiphy->bands[NL80211_BAND_5GHZ];1305	}1306 1307	if (!sband || band_idx >= sband->n_channels)1308		return -ENOENT;1309 1310	spin_lock_irqsave(&wcn->survey_lock, flags);1311 1312	chan_survey = &wcn->chan_survey[idx];1313	survey->channel = &sband->channels[band_idx];1314	survey->noise = chan_survey->rssi - chan_survey->snr;1315	survey->filled = 0;1316 1317	if (chan_survey->rssi > -100 && chan_survey->rssi < 0)1318		survey->filled |= SURVEY_INFO_NOISE_DBM;1319 1320	if (survey->channel == wcn->channel)1321		survey->filled |= SURVEY_INFO_IN_USE;1322 1323	spin_unlock_irqrestore(&wcn->survey_lock, flags);1324 1325	wcn36xx_dbg(WCN36XX_DBG_MAC,1326		    "ch %d rssi %d snr %d noise %d filled %x freq %d\n",1327		    HW_VALUE_CHANNEL(survey->channel->hw_value),1328		    chan_survey->rssi, chan_survey->snr, survey->noise,1329		    survey->filled, survey->channel->center_freq);1330 1331	return 0;1332}1333 1334static void wcn36xx_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif,1335				   struct ieee80211_sta *sta, struct station_info *sinfo)1336{1337	struct wcn36xx *wcn;1338	u8 sta_index;1339	int status;1340 1341	wcn = hw->priv;1342	sta_index = get_sta_index(vif, wcn36xx_sta_to_priv(sta));1343	status = wcn36xx_smd_get_stats(wcn, sta_index, HAL_GLOBAL_CLASS_A_STATS_INFO, sinfo);1344 1345	if (status)1346		wcn36xx_err("wcn36xx_smd_get_stats failed\n");1347}1348 1349static const struct ieee80211_ops wcn36xx_ops = {1350	.add_chanctx = ieee80211_emulate_add_chanctx,1351	.remove_chanctx = ieee80211_emulate_remove_chanctx,1352	.change_chanctx = ieee80211_emulate_change_chanctx,1353	.switch_vif_chanctx = ieee80211_emulate_switch_vif_chanctx,1354	.start			= wcn36xx_start,1355	.stop			= wcn36xx_stop,1356	.add_interface		= wcn36xx_add_interface,1357	.remove_interface	= wcn36xx_remove_interface,1358#ifdef CONFIG_PM1359	.suspend		= wcn36xx_suspend,1360	.resume			= wcn36xx_resume,1361	.set_rekey_data		= wcn36xx_set_rekey_data,1362#endif1363	.config			= wcn36xx_config,1364	.prepare_multicast	= wcn36xx_prepare_multicast,1365	.configure_filter       = wcn36xx_configure_filter,1366	.tx			= wcn36xx_tx,1367	.wake_tx_queue		= ieee80211_handle_wake_tx_queue,1368	.set_key		= wcn36xx_set_key,1369	.hw_scan		= wcn36xx_hw_scan,1370	.cancel_hw_scan		= wcn36xx_cancel_hw_scan,1371	.sw_scan_start		= wcn36xx_sw_scan_start,1372	.sw_scan_complete	= wcn36xx_sw_scan_complete,1373	.bss_info_changed	= wcn36xx_bss_info_changed,1374	.set_rts_threshold	= wcn36xx_set_rts_threshold,1375	.sta_add		= wcn36xx_sta_add,1376	.sta_remove		= wcn36xx_sta_remove,1377	.sta_statistics		= wcn36xx_sta_statistics,1378	.ampdu_action		= wcn36xx_ampdu_action,1379#if IS_ENABLED(CONFIG_IPV6)1380	.ipv6_addr_change	= wcn36xx_ipv6_addr_change,1381#endif1382	.flush			= wcn36xx_flush,1383	.get_survey		= wcn36xx_get_survey,1384 1385	CFG80211_TESTMODE_CMD(wcn36xx_tm_cmd)1386};1387 1388static void1389wcn36xx_set_ieee80211_vht_caps(struct ieee80211_sta_vht_cap *vht_cap)1390{1391	vht_cap->vht_supported = true;1392 1393	vht_cap->cap = (IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 |1394			IEEE80211_VHT_CAP_SHORT_GI_80 |1395			IEEE80211_VHT_CAP_RXSTBC_1 |1396			IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |1397			IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |1398			3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT |1399			7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT);1400 1401	vht_cap->vht_mcs.rx_mcs_map =1402		cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 |1403			    IEEE80211_VHT_MCS_NOT_SUPPORTED << 2 |1404			    IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 |1405			    IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 |1406			    IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 |1407			    IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 |1408			    IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 |1409			    IEEE80211_VHT_MCS_NOT_SUPPORTED << 14);1410 1411	vht_cap->vht_mcs.rx_highest = cpu_to_le16(433);1412	vht_cap->vht_mcs.tx_highest = vht_cap->vht_mcs.rx_highest;1413 1414	vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map;1415}1416 1417static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)1418{1419	static const u32 cipher_suites[] = {1420		WLAN_CIPHER_SUITE_WEP40,1421		WLAN_CIPHER_SUITE_WEP104,1422		WLAN_CIPHER_SUITE_TKIP,1423		WLAN_CIPHER_SUITE_CCMP,1424	};1425 1426	ieee80211_hw_set(wcn->hw, TIMING_BEACON_ONLY);1427	ieee80211_hw_set(wcn->hw, AMPDU_AGGREGATION);1428	ieee80211_hw_set(wcn->hw, SUPPORTS_PS);1429	ieee80211_hw_set(wcn->hw, SIGNAL_DBM);1430	ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL);1431	ieee80211_hw_set(wcn->hw, SINGLE_SCAN_ON_ALL_BANDS);1432	ieee80211_hw_set(wcn->hw, REPORTS_TX_ACK_STATUS);1433 1434	wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |1435		BIT(NL80211_IFTYPE_AP) |1436		BIT(NL80211_IFTYPE_ADHOC) |1437		BIT(NL80211_IFTYPE_MESH_POINT);1438 1439	wcn->hw->wiphy->bands[NL80211_BAND_2GHZ] = &wcn_band_2ghz;1440	if (wcn->rf_id != RF_IRIS_WCN3620)1441		wcn->hw->wiphy->bands[NL80211_BAND_5GHZ] = &wcn_band_5ghz;1442 1443	if (wcn->rf_id == RF_IRIS_WCN3680)1444		wcn36xx_set_ieee80211_vht_caps(&wcn_band_5ghz.vht_cap);1445 1446	wcn->hw->wiphy->max_scan_ssids = WCN36XX_MAX_SCAN_SSIDS;1447	wcn->hw->wiphy->max_scan_ie_len = WCN36XX_MAX_SCAN_IE_LEN;1448 1449	wcn->hw->wiphy->cipher_suites = cipher_suites;1450	wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);1451 1452#ifdef CONFIG_PM1453	wcn->hw->wiphy->wowlan = &wowlan_support;1454#endif1455 1456	wcn->hw->max_listen_interval = 200;1457 1458	wcn->hw->queues = 4;1459 1460	SET_IEEE80211_DEV(wcn->hw, wcn->dev);1461 1462	wcn->hw->sta_data_size = sizeof(struct wcn36xx_sta);1463	wcn->hw->vif_data_size = sizeof(struct wcn36xx_vif);1464 1465	wiphy_ext_feature_set(wcn->hw->wiphy,1466			      NL80211_EXT_FEATURE_CQM_RSSI_LIST);1467 1468	return 0;1469}1470 1471static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,1472					  struct platform_device *pdev)1473{1474	struct device_node *mmio_node;1475	struct device_node *iris_node;1476	int index;1477	int ret;1478 1479	/* Set TX IRQ */1480	ret = platform_get_irq_byname(pdev, "tx");1481	if (ret < 0)1482		return ret;1483	wcn->tx_irq = ret;1484 1485	/* Set RX IRQ */1486	ret = platform_get_irq_byname(pdev, "rx");1487	if (ret < 0)1488		return ret;1489	wcn->rx_irq = ret;1490 1491	/* Acquire SMSM tx enable handle */1492	wcn->tx_enable_state = qcom_smem_state_get(&pdev->dev,1493			"tx-enable", &wcn->tx_enable_state_bit);1494	if (IS_ERR(wcn->tx_enable_state)) {1495		wcn36xx_err("failed to get tx-enable state\n");1496		return PTR_ERR(wcn->tx_enable_state);1497	}1498 1499	/* Acquire SMSM tx rings empty handle */1500	wcn->tx_rings_empty_state = qcom_smem_state_get(&pdev->dev,1501			"tx-rings-empty", &wcn->tx_rings_empty_state_bit);1502	if (IS_ERR(wcn->tx_rings_empty_state)) {1503		wcn36xx_err("failed to get tx-rings-empty state\n");1504		return PTR_ERR(wcn->tx_rings_empty_state);1505	}1506 1507	mmio_node = of_parse_phandle(pdev->dev.parent->of_node, "qcom,mmio", 0);1508	if (!mmio_node) {1509		wcn36xx_err("failed to acquire qcom,mmio reference\n");1510		return -EINVAL;1511	}1512 1513	wcn->is_pronto = !!of_device_is_compatible(mmio_node, "qcom,pronto");1514	wcn->is_pronto_v3 = !!of_device_is_compatible(mmio_node, "qcom,pronto-v3-pil");1515 1516	/* Map the CCU memory */1517	index = of_property_match_string(mmio_node, "reg-names", "ccu");1518	wcn->ccu_base = of_iomap(mmio_node, index);1519	if (!wcn->ccu_base) {1520		wcn36xx_err("failed to map ccu memory\n");1521		ret = -ENOMEM;1522		goto put_mmio_node;1523	}1524 1525	/* Map the DXE memory */1526	index = of_property_match_string(mmio_node, "reg-names", "dxe");1527	wcn->dxe_base = of_iomap(mmio_node, index);1528	if (!wcn->dxe_base) {1529		wcn36xx_err("failed to map dxe memory\n");1530		ret = -ENOMEM;1531		goto unmap_ccu;1532	}1533 1534	/* External RF module */1535	iris_node = of_get_child_by_name(mmio_node, "iris");1536	if (iris_node) {1537		if (of_device_is_compatible(iris_node, "qcom,wcn3620"))1538			wcn->rf_id = RF_IRIS_WCN3620;1539		if (of_device_is_compatible(iris_node, "qcom,wcn3660") ||1540		    of_device_is_compatible(iris_node, "qcom,wcn3660b"))1541			wcn->rf_id = RF_IRIS_WCN3660;1542		if (of_device_is_compatible(iris_node, "qcom,wcn3680"))1543			wcn->rf_id = RF_IRIS_WCN3680;1544		of_node_put(iris_node);1545	}1546 1547	of_node_put(mmio_node);1548	return 0;1549 1550unmap_ccu:1551	iounmap(wcn->ccu_base);1552put_mmio_node:1553	of_node_put(mmio_node);1554	return ret;1555}1556 1557static int wcn36xx_probe(struct platform_device *pdev)1558{1559	struct ieee80211_hw *hw;1560	struct wcn36xx *wcn;1561	void *wcnss;1562	int ret;1563	const u8 *addr;1564	int n_channels;1565 1566	wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");1567 1568	wcnss = dev_get_drvdata(pdev->dev.parent);1569 1570	hw = ieee80211_alloc_hw(sizeof(struct wcn36xx), &wcn36xx_ops);1571	if (!hw) {1572		wcn36xx_err("failed to alloc hw\n");1573		ret = -ENOMEM;1574		goto out_err;1575	}1576	platform_set_drvdata(pdev, hw);1577	wcn = hw->priv;1578	wcn->hw = hw;1579	wcn->dev = &pdev->dev;1580	wcn->first_boot = true;1581	mutex_init(&wcn->conf_mutex);1582	mutex_init(&wcn->hal_mutex);1583	mutex_init(&wcn->scan_lock);1584	__skb_queue_head_init(&wcn->amsdu);1585 1586	wcn->hal_buf = devm_kmalloc(wcn->dev, WCN36XX_HAL_BUF_SIZE, GFP_KERNEL);1587	if (!wcn->hal_buf) {1588		ret = -ENOMEM;1589		goto out_wq;1590	}1591 1592	n_channels = wcn_band_2ghz.n_channels + wcn_band_5ghz.n_channels;1593	wcn->chan_survey = devm_kmalloc(wcn->dev, n_channels, GFP_KERNEL);1594	if (!wcn->chan_survey) {1595		ret = -ENOMEM;1596		goto out_wq;1597	}1598 1599	ret = dma_set_mask_and_coherent(wcn->dev, DMA_BIT_MASK(32));1600	if (ret < 0) {1601		wcn36xx_err("failed to set DMA mask: %d\n", ret);1602		goto out_wq;1603	}1604 1605	wcn->nv_file = WLAN_NV_FILE;1606	ret = of_property_read_string(wcn->dev->parent->of_node, "firmware-name", &wcn->nv_file);1607	if (ret < 0 && ret != -EINVAL) {1608		wcn36xx_err("failed to read \"firmware-name\" property: %d\n", ret);1609		goto out_wq;1610	}1611 1612	wcn->smd_channel = qcom_wcnss_open_channel(wcnss, "WLAN_CTRL", wcn36xx_smd_rsp_process, hw);1613	if (IS_ERR(wcn->smd_channel)) {1614		wcn36xx_err("failed to open WLAN_CTRL channel\n");1615		ret = PTR_ERR(wcn->smd_channel);1616		goto out_wq;1617	}1618 1619	addr = of_get_property(pdev->dev.of_node, "local-mac-address", &ret);1620	if (addr && ret != ETH_ALEN) {1621		wcn36xx_err("invalid local-mac-address\n");1622		ret = -EINVAL;1623		goto out_destroy_ept;1624	} else if (addr) {1625		wcn36xx_info("mac address: %pM\n", addr);1626		SET_IEEE80211_PERM_ADDR(wcn->hw, addr);1627	}1628 1629	ret = wcn36xx_platform_get_resources(wcn, pdev);1630	if (ret)1631		goto out_destroy_ept;1632 1633	wcn36xx_init_ieee80211(wcn);1634	ret = ieee80211_register_hw(wcn->hw);1635	if (ret)1636		goto out_unmap;1637 1638	return 0;1639 1640out_unmap:1641	iounmap(wcn->ccu_base);1642	iounmap(wcn->dxe_base);1643out_destroy_ept:1644	rpmsg_destroy_ept(wcn->smd_channel);1645out_wq:1646	ieee80211_free_hw(hw);1647out_err:1648	return ret;1649}1650 1651static void wcn36xx_remove(struct platform_device *pdev)1652{1653	struct ieee80211_hw *hw = platform_get_drvdata(pdev);1654	struct wcn36xx *wcn = hw->priv;1655	wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");1656 1657	release_firmware(wcn->nv);1658 1659	ieee80211_unregister_hw(hw);1660 1661	qcom_smem_state_put(wcn->tx_enable_state);1662	qcom_smem_state_put(wcn->tx_rings_empty_state);1663 1664	rpmsg_destroy_ept(wcn->smd_channel);1665 1666	iounmap(wcn->dxe_base);1667	iounmap(wcn->ccu_base);1668 1669	__skb_queue_purge(&wcn->amsdu);1670 1671	mutex_destroy(&wcn->hal_mutex);1672	ieee80211_free_hw(hw);1673}1674 1675static const struct of_device_id wcn36xx_of_match[] = {1676	{ .compatible = "qcom,wcnss-wlan" },1677	{}1678};1679MODULE_DEVICE_TABLE(of, wcn36xx_of_match);1680 1681static struct platform_driver wcn36xx_driver = {1682	.probe      = wcn36xx_probe,1683	.remove_new = wcn36xx_remove,1684	.driver         = {1685		.name   = "wcn36xx",1686		.of_match_table = wcn36xx_of_match,1687	},1688};1689 1690module_platform_driver(wcn36xx_driver);1691 1692MODULE_DESCRIPTION("Qualcomm Atheros WCN3660/3680 wireless driver");1693MODULE_LICENSE("Dual BSD/GPL");1694MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");1695MODULE_FIRMWARE(WLAN_NV_FILE);1696