Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
   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 any
   5 * purpose with or without fee is hereby granted, provided that the above
   6 * copyright notice and this permission notice appear in all copies.
   7 *
   8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15 */
  16
  17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  18
  19#include <linux/module.h>
  20#include <linux/firmware.h>
  21#include <linux/platform_device.h>
  22#include <linux/of_address.h>
  23#include <linux/of_device.h>
  24#include <linux/of_irq.h>
  25#include <linux/rpmsg.h>
  26#include <linux/soc/qcom/smem_state.h>
  27#include <linux/soc/qcom/wcnss_ctrl.h>
  28#include "wcn36xx.h"
  29
  30unsigned int wcn36xx_dbg_mask;
  31module_param_named(debug_mask, wcn36xx_dbg_mask, uint, 0644);
  32MODULE_PARM_DESC(debug_mask, "Debugging mask");
  33
  34#define CHAN2G(_freq, _idx) { \
  35	.band = NL80211_BAND_2GHZ, \
  36	.center_freq = (_freq), \
  37	.hw_value = (_idx), \
  38	.max_power = 25, \
  39}
  40
  41#define CHAN5G(_freq, _idx) { \
  42	.band = NL80211_BAND_5GHZ, \
  43	.center_freq = (_freq), \
  44	.hw_value = (_idx), \
  45	.max_power = 25, \
  46}
  47
  48/* The wcn firmware expects channel values to matching
  49 * their mnemonic values. So use these for .hw_value. */
  50static struct ieee80211_channel wcn_2ghz_channels[] = {
  51	CHAN2G(2412, 1), /* Channel 1 */
  52	CHAN2G(2417, 2), /* Channel 2 */
  53	CHAN2G(2422, 3), /* Channel 3 */
  54	CHAN2G(2427, 4), /* Channel 4 */
  55	CHAN2G(2432, 5), /* Channel 5 */
  56	CHAN2G(2437, 6), /* Channel 6 */
  57	CHAN2G(2442, 7), /* Channel 7 */
  58	CHAN2G(2447, 8), /* Channel 8 */
  59	CHAN2G(2452, 9), /* Channel 9 */
  60	CHAN2G(2457, 10), /* Channel 10 */
  61	CHAN2G(2462, 11), /* Channel 11 */
  62	CHAN2G(2467, 12), /* Channel 12 */
  63	CHAN2G(2472, 13), /* Channel 13 */
  64	CHAN2G(2484, 14)  /* Channel 14 */
  65
  66};
  67
  68static struct ieee80211_channel wcn_5ghz_channels[] = {
  69	CHAN5G(5180, 36),
  70	CHAN5G(5200, 40),
  71	CHAN5G(5220, 44),
  72	CHAN5G(5240, 48),
  73	CHAN5G(5260, 52),
  74	CHAN5G(5280, 56),
  75	CHAN5G(5300, 60),
  76	CHAN5G(5320, 64),
  77	CHAN5G(5500, 100),
  78	CHAN5G(5520, 104),
  79	CHAN5G(5540, 108),
  80	CHAN5G(5560, 112),
  81	CHAN5G(5580, 116),
  82	CHAN5G(5600, 120),
  83	CHAN5G(5620, 124),
  84	CHAN5G(5640, 128),
  85	CHAN5G(5660, 132),
  86	CHAN5G(5700, 140),
  87	CHAN5G(5745, 149),
  88	CHAN5G(5765, 153),
  89	CHAN5G(5785, 157),
  90	CHAN5G(5805, 161),
  91	CHAN5G(5825, 165)
  92};
  93
  94#define RATE(_bitrate, _hw_rate, _flags) { \
  95	.bitrate        = (_bitrate),                   \
  96	.flags          = (_flags),                     \
  97	.hw_value       = (_hw_rate),                   \
  98	.hw_value_short = (_hw_rate)  \
  99}
 100
 101static struct ieee80211_rate wcn_2ghz_rates[] = {
 102	RATE(10, HW_RATE_INDEX_1MBPS, 0),
 103	RATE(20, HW_RATE_INDEX_2MBPS, IEEE80211_RATE_SHORT_PREAMBLE),
 104	RATE(55, HW_RATE_INDEX_5_5MBPS, IEEE80211_RATE_SHORT_PREAMBLE),
 105	RATE(110, HW_RATE_INDEX_11MBPS, IEEE80211_RATE_SHORT_PREAMBLE),
 106	RATE(60, HW_RATE_INDEX_6MBPS, 0),
 107	RATE(90, HW_RATE_INDEX_9MBPS, 0),
 108	RATE(120, HW_RATE_INDEX_12MBPS, 0),
 109	RATE(180, HW_RATE_INDEX_18MBPS, 0),
 110	RATE(240, HW_RATE_INDEX_24MBPS, 0),
 111	RATE(360, HW_RATE_INDEX_36MBPS, 0),
 112	RATE(480, HW_RATE_INDEX_48MBPS, 0),
 113	RATE(540, HW_RATE_INDEX_54MBPS, 0)
 114};
 115
 116static struct ieee80211_rate wcn_5ghz_rates[] = {
 117	RATE(60, HW_RATE_INDEX_6MBPS, 0),
 118	RATE(90, HW_RATE_INDEX_9MBPS, 0),
 119	RATE(120, HW_RATE_INDEX_12MBPS, 0),
 120	RATE(180, HW_RATE_INDEX_18MBPS, 0),
 121	RATE(240, HW_RATE_INDEX_24MBPS, 0),
 122	RATE(360, HW_RATE_INDEX_36MBPS, 0),
 123	RATE(480, HW_RATE_INDEX_48MBPS, 0),
 124	RATE(540, HW_RATE_INDEX_54MBPS, 0)
 125};
 126
 127static struct ieee80211_supported_band wcn_band_2ghz = {
 128	.channels	= wcn_2ghz_channels,
 129	.n_channels	= ARRAY_SIZE(wcn_2ghz_channels),
 130	.bitrates	= wcn_2ghz_rates,
 131	.n_bitrates	= ARRAY_SIZE(wcn_2ghz_rates),
 132	.ht_cap		= {
 133		.cap =	IEEE80211_HT_CAP_GRN_FLD |
 134			IEEE80211_HT_CAP_SGI_20 |
 135			IEEE80211_HT_CAP_DSSSCCK40 |
 136			IEEE80211_HT_CAP_LSIG_TXOP_PROT,
 137		.ht_supported = true,
 138		.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
 139		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
 140		.mcs = {
 141			.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
 142			.rx_highest = cpu_to_le16(72),
 143			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
 144		}
 145	}
 146};
 147
 148static struct ieee80211_supported_band wcn_band_5ghz = {
 149	.channels	= wcn_5ghz_channels,
 150	.n_channels	= ARRAY_SIZE(wcn_5ghz_channels),
 151	.bitrates	= wcn_5ghz_rates,
 152	.n_bitrates	= ARRAY_SIZE(wcn_5ghz_rates),
 153	.ht_cap		= {
 154		.cap =	IEEE80211_HT_CAP_GRN_FLD |
 155			IEEE80211_HT_CAP_SGI_20 |
 156			IEEE80211_HT_CAP_DSSSCCK40 |
 157			IEEE80211_HT_CAP_LSIG_TXOP_PROT |
 158			IEEE80211_HT_CAP_SGI_40 |
 159			IEEE80211_HT_CAP_SUP_WIDTH_20_40,
 160		.ht_supported = true,
 161		.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
 162		.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
 163		.mcs = {
 164			.rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
 165			.rx_highest = cpu_to_le16(72),
 166			.tx_params = IEEE80211_HT_MCS_TX_DEFINED,
 167		}
 168	}
 169};
 170
 171#ifdef CONFIG_PM
 172
 173static const struct wiphy_wowlan_support wowlan_support = {
 174	.flags = WIPHY_WOWLAN_ANY
 175};
 176
 177#endif
 178
 179static inline u8 get_sta_index(struct ieee80211_vif *vif,
 180			       struct wcn36xx_sta *sta_priv)
 181{
 182	return NL80211_IFTYPE_STATION == vif->type ?
 183	       sta_priv->bss_sta_index :
 184	       sta_priv->sta_index;
 185}
 186
 187static const char * const wcn36xx_caps_names[] = {
 188	"MCC",				/* 0 */
 189	"P2P",				/* 1 */
 190	"DOT11AC",			/* 2 */
 191	"SLM_SESSIONIZATION",		/* 3 */
 192	"DOT11AC_OPMODE",		/* 4 */
 193	"SAP32STA",			/* 5 */
 194	"TDLS",				/* 6 */
 195	"P2P_GO_NOA_DECOUPLE_INIT_SCAN",/* 7 */
 196	"WLANACTIVE_OFFLOAD",		/* 8 */
 197	"BEACON_OFFLOAD",		/* 9 */
 198	"SCAN_OFFLOAD",			/* 10 */
 199	"ROAM_OFFLOAD",			/* 11 */
 200	"BCN_MISS_OFFLOAD",		/* 12 */
 201	"STA_POWERSAVE",		/* 13 */
 202	"STA_ADVANCED_PWRSAVE",		/* 14 */
 203	"AP_UAPSD",			/* 15 */
 204	"AP_DFS",			/* 16 */
 205	"BLOCKACK",			/* 17 */
 206	"PHY_ERR",			/* 18 */
 207	"BCN_FILTER",			/* 19 */
 208	"RTT",				/* 20 */
 209	"RATECTRL",			/* 21 */
 210	"WOW",				/* 22 */
 211	"WLAN_ROAM_SCAN_OFFLOAD",	/* 23 */
 212	"SPECULATIVE_PS_POLL",		/* 24 */
 213	"SCAN_SCH",			/* 25 */
 214	"IBSS_HEARTBEAT_OFFLOAD",	/* 26 */
 215	"WLAN_SCAN_OFFLOAD",		/* 27 */
 216	"WLAN_PERIODIC_TX_PTRN",	/* 28 */
 217	"ADVANCE_TDLS",			/* 29 */
 218	"BATCH_SCAN",			/* 30 */
 219	"FW_IN_TX_PATH",		/* 31 */
 220	"EXTENDED_NSOFFLOAD_SLOT",	/* 32 */
 221	"CH_SWITCH_V1",			/* 33 */
 222	"HT40_OBSS_SCAN",		/* 34 */
 223	"UPDATE_CHANNEL_LIST",		/* 35 */
 224	"WLAN_MCADDR_FLT",		/* 36 */
 225	"WLAN_CH144",			/* 37 */
 226	"NAN",				/* 38 */
 227	"TDLS_SCAN_COEXISTENCE",	/* 39 */
 228	"LINK_LAYER_STATS_MEAS",	/* 40 */
 229	"MU_MIMO",			/* 41 */
 230	"EXTENDED_SCAN",		/* 42 */
 231	"DYNAMIC_WMM_PS",		/* 43 */
 232	"MAC_SPOOFED_SCAN",		/* 44 */
 233	"BMU_ERROR_GENERIC_RECOVERY",	/* 45 */
 234	"DISA",				/* 46 */
 235	"FW_STATS",			/* 47 */
 236	"WPS_PRBRSP_TMPL",		/* 48 */
 237	"BCN_IE_FLT_DELTA",		/* 49 */
 238	"TDLS_OFF_CHANNEL",		/* 51 */
 239	"RTT3",				/* 52 */
 240	"MGMT_FRAME_LOGGING",		/* 53 */
 241	"ENHANCED_TXBD_COMPLETION",	/* 54 */
 242	"LOGGING_ENHANCEMENT",		/* 55 */
 243	"EXT_SCAN_ENHANCED",		/* 56 */
 244	"MEMORY_DUMP_SUPPORTED",	/* 57 */
 245	"PER_PKT_STATS_SUPPORTED",	/* 58 */
 246	"EXT_LL_STAT",			/* 60 */
 247	"WIFI_CONFIG",			/* 61 */
 248	"ANTENNA_DIVERSITY_SELECTION",	/* 62 */
 249};
 250
 251static const char *wcn36xx_get_cap_name(enum place_holder_in_cap_bitmap x)
 252{
 253	if (x >= ARRAY_SIZE(wcn36xx_caps_names))
 254		return "UNKNOWN";
 255	return wcn36xx_caps_names[x];
 256}
 257
 258static void wcn36xx_feat_caps_info(struct wcn36xx *wcn)
 259{
 260	int i;
 261
 262	for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) {
 263		if (get_feat_caps(wcn->fw_feat_caps, i))
 264			wcn36xx_dbg(WCN36XX_DBG_MAC, "FW Cap %s\n", wcn36xx_get_cap_name(i));
 265	}
 266}
 267
 268static int wcn36xx_start(struct ieee80211_hw *hw)
 269{
 270	struct wcn36xx *wcn = hw->priv;
 271	int ret;
 272
 273	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac start\n");
 274
 275	/* SMD initialization */
 276	ret = wcn36xx_smd_open(wcn);
 277	if (ret) {
 278		wcn36xx_err("Failed to open smd channel: %d\n", ret);
 279		goto out_err;
 280	}
 281
 282	/* Allocate memory pools for Mgmt BD headers and Data BD headers */
 283	ret = wcn36xx_dxe_allocate_mem_pools(wcn);
 284	if (ret) {
 285		wcn36xx_err("Failed to alloc DXE mempool: %d\n", ret);
 286		goto out_smd_close;
 287	}
 288
 289	ret = wcn36xx_dxe_alloc_ctl_blks(wcn);
 290	if (ret) {
 291		wcn36xx_err("Failed to alloc DXE ctl blocks: %d\n", ret);
 292		goto out_free_dxe_pool;
 293	}
 294
 295	wcn->hal_buf = kmalloc(WCN36XX_HAL_BUF_SIZE, GFP_KERNEL);
 296	if (!wcn->hal_buf) {
 297		wcn36xx_err("Failed to allocate smd buf\n");
 298		ret = -ENOMEM;
 299		goto out_free_dxe_ctl;
 300	}
 301
 302	ret = wcn36xx_smd_load_nv(wcn);
 303	if (ret) {
 304		wcn36xx_err("Failed to push NV to chip\n");
 305		goto out_free_smd_buf;
 306	}
 307
 308	ret = wcn36xx_smd_start(wcn);
 309	if (ret) {
 310		wcn36xx_err("Failed to start chip\n");
 311		goto out_free_smd_buf;
 312	}
 313
 314	if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
 315		ret = wcn36xx_smd_feature_caps_exchange(wcn);
 316		if (ret)
 317			wcn36xx_warn("Exchange feature caps failed\n");
 318		else
 319			wcn36xx_feat_caps_info(wcn);
 320	}
 321
 322	/* DMA channel initialization */
 323	ret = wcn36xx_dxe_init(wcn);
 324	if (ret) {
 325		wcn36xx_err("DXE init failed\n");
 326		goto out_smd_stop;
 327	}
 328
 329	wcn36xx_debugfs_init(wcn);
 330
 331	INIT_LIST_HEAD(&wcn->vif_list);
 332	spin_lock_init(&wcn->dxe_lock);
 333
 334	return 0;
 335
 336out_smd_stop:
 337	wcn36xx_smd_stop(wcn);
 338out_free_smd_buf:
 339	kfree(wcn->hal_buf);
 340out_free_dxe_ctl:
 341	wcn36xx_dxe_free_ctl_blks(wcn);
 342out_free_dxe_pool:
 343	wcn36xx_dxe_free_mem_pools(wcn);
 344out_smd_close:
 345	wcn36xx_smd_close(wcn);
 346out_err:
 347	return ret;
 348}
 349
 350static void wcn36xx_stop(struct ieee80211_hw *hw)
 351{
 352	struct wcn36xx *wcn = hw->priv;
 353
 354	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac stop\n");
 355
 356	wcn36xx_debugfs_exit(wcn);
 357	wcn36xx_smd_stop(wcn);
 358	wcn36xx_dxe_deinit(wcn);
 359	wcn36xx_smd_close(wcn);
 360
 361	wcn36xx_dxe_free_mem_pools(wcn);
 362	wcn36xx_dxe_free_ctl_blks(wcn);
 363
 364	kfree(wcn->hal_buf);
 365}
 366
 367static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)
 368{
 369	struct wcn36xx *wcn = hw->priv;
 370	struct ieee80211_vif *vif = NULL;
 371	struct wcn36xx_vif *tmp;
 372
 373	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac config changed 0x%08x\n", changed);
 374
 375	mutex_lock(&wcn->conf_mutex);
 376
 377	if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
 378		int ch = WCN36XX_HW_CHANNEL(wcn);
 379		wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n",
 380			    ch);
 381		list_for_each_entry(tmp, &wcn->vif_list, list) {
 382			vif = wcn36xx_priv_to_vif(tmp);
 383			wcn36xx_smd_switch_channel(wcn, vif, ch);
 384		}
 385	}
 386
 387	if (changed & IEEE80211_CONF_CHANGE_PS) {
 388		list_for_each_entry(tmp, &wcn->vif_list, list) {
 389			vif = wcn36xx_priv_to_vif(tmp);
 390			if (hw->conf.flags & IEEE80211_CONF_PS) {
 391				if (vif->bss_conf.ps) /* ps allowed ? */
 392					wcn36xx_pmc_enter_bmps_state(wcn, vif);
 393			} else {
 394				wcn36xx_pmc_exit_bmps_state(wcn, vif);
 395			}
 396		}
 397	}
 398
 399	mutex_unlock(&wcn->conf_mutex);
 400
 401	return 0;
 402}
 403
 404static void wcn36xx_configure_filter(struct ieee80211_hw *hw,
 405				     unsigned int changed,
 406				     unsigned int *total, u64 multicast)
 407{
 408	struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp;
 409	struct wcn36xx *wcn = hw->priv;
 410	struct wcn36xx_vif *tmp;
 411	struct ieee80211_vif *vif = NULL;
 412
 413	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n");
 414
 415	mutex_lock(&wcn->conf_mutex);
 416
 417	*total &= FIF_ALLMULTI;
 418
 419	fp = (void *)(unsigned long)multicast;
 420	list_for_each_entry(tmp, &wcn->vif_list, list) {
 421		vif = wcn36xx_priv_to_vif(tmp);
 422
 423		/* FW handles MC filtering only when connected as STA */
 424		if (*total & FIF_ALLMULTI)
 425			wcn36xx_smd_set_mc_list(wcn, vif, NULL);
 426		else if (NL80211_IFTYPE_STATION == vif->type && tmp->sta_assoc)
 427			wcn36xx_smd_set_mc_list(wcn, vif, fp);
 428	}
 429
 430	mutex_unlock(&wcn->conf_mutex);
 431	kfree(fp);
 432}
 433
 434static u64 wcn36xx_prepare_multicast(struct ieee80211_hw *hw,
 435				     struct netdev_hw_addr_list *mc_list)
 436{
 437	struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp;
 438	struct netdev_hw_addr *ha;
 439
 440	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac prepare multicast list\n");
 441	fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
 442	if (!fp) {
 443		wcn36xx_err("Out of memory setting filters.\n");
 444		return 0;
 445	}
 446
 447	fp->mc_addr_count = 0;
 448	/* update multicast filtering parameters */
 449	if (netdev_hw_addr_list_count(mc_list) <=
 450	    WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS) {
 451		netdev_hw_addr_list_for_each(ha, mc_list) {
 452			memcpy(fp->mc_addr[fp->mc_addr_count],
 453					ha->addr, ETH_ALEN);
 454			fp->mc_addr_count++;
 455		}
 456	}
 457
 458	return (u64)(unsigned long)fp;
 459}
 460
 461static void wcn36xx_tx(struct ieee80211_hw *hw,
 462		       struct ieee80211_tx_control *control,
 463		       struct sk_buff *skb)
 464{
 465	struct wcn36xx *wcn = hw->priv;
 466	struct wcn36xx_sta *sta_priv = NULL;
 467
 468	if (control->sta)
 469		sta_priv = wcn36xx_sta_to_priv(control->sta);
 470
 471	if (wcn36xx_start_tx(wcn, sta_priv, skb))
 472		ieee80211_free_txskb(wcn->hw, skb);
 473}
 474
 475static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 476			   struct ieee80211_vif *vif,
 477			   struct ieee80211_sta *sta,
 478			   struct ieee80211_key_conf *key_conf)
 479{
 480	struct wcn36xx *wcn = hw->priv;
 481	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
 482	struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
 483	int ret = 0;
 484	u8 key[WLAN_MAX_KEY_LEN];
 485
 486	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 set key\n");
 487	wcn36xx_dbg(WCN36XX_DBG_MAC, "Key: cmd=0x%x algo:0x%x, id:%d, len:%d flags 0x%x\n",
 488		    cmd, key_conf->cipher, key_conf->keyidx,
 489		    key_conf->keylen, key_conf->flags);
 490	wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "KEY: ",
 491			 key_conf->key,
 492			 key_conf->keylen);
 493
 494	mutex_lock(&wcn->conf_mutex);
 495
 496	switch (key_conf->cipher) {
 497	case WLAN_CIPHER_SUITE_WEP40:
 498		vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40;
 499		break;
 500	case WLAN_CIPHER_SUITE_WEP104:
 501		vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40;
 502		break;
 503	case WLAN_CIPHER_SUITE_CCMP:
 504		vif_priv->encrypt_type = WCN36XX_HAL_ED_CCMP;
 505		break;
 506	case WLAN_CIPHER_SUITE_TKIP:
 507		vif_priv->encrypt_type = WCN36XX_HAL_ED_TKIP;
 508		break;
 509	default:
 510		wcn36xx_err("Unsupported key type 0x%x\n",
 511			      key_conf->cipher);
 512		ret = -EOPNOTSUPP;
 513		goto out;
 514	}
 515
 516	switch (cmd) {
 517	case SET_KEY:
 518		if (WCN36XX_HAL_ED_TKIP == vif_priv->encrypt_type) {
 519			/*
 520			 * Supplicant is sending key in the wrong order:
 521			 * Temporal Key (16 b) - TX MIC (8 b) - RX MIC (8 b)
 522			 * but HW expects it to be in the order as described in
 523			 * IEEE 802.11 spec (see chapter 11.7) like this:
 524			 * Temporal Key (16 b) - RX MIC (8 b) - TX MIC (8 b)
 525			 */
 526			memcpy(key, key_conf->key, 16);
 527			memcpy(key + 16, key_conf->key + 24, 8);
 528			memcpy(key + 24, key_conf->key + 16, 8);
 529		} else {
 530			memcpy(key, key_conf->key, key_conf->keylen);
 531		}
 532
 533		if (IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags) {
 534			sta_priv->is_data_encrypted = true;
 535			/* Reconfigure bss with encrypt_type */
 536			if (NL80211_IFTYPE_STATION == vif->type)
 537				wcn36xx_smd_config_bss(wcn,
 538						       vif,
 539						       sta,
 540						       sta->addr,
 541						       true);
 542
 543			wcn36xx_smd_set_stakey(wcn,
 544				vif_priv->encrypt_type,
 545				key_conf->keyidx,
 546				key_conf->keylen,
 547				key,
 548				get_sta_index(vif, sta_priv));
 549		} else {
 550			wcn36xx_smd_set_bsskey(wcn,
 551				vif_priv->encrypt_type,
 552				key_conf->keyidx,
 553				key_conf->keylen,
 554				key);
 555			if ((WLAN_CIPHER_SUITE_WEP40 == key_conf->cipher) ||
 556			    (WLAN_CIPHER_SUITE_WEP104 == key_conf->cipher)) {
 557				sta_priv->is_data_encrypted = true;
 558				wcn36xx_smd_set_stakey(wcn,
 559					vif_priv->encrypt_type,
 560					key_conf->keyidx,
 561					key_conf->keylen,
 562					key,
 563					get_sta_index(vif, sta_priv));
 564			}
 565		}
 566		break;
 567	case DISABLE_KEY:
 568		if (!(IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags)) {
 569			vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE;
 570			wcn36xx_smd_remove_bsskey(wcn,
 571				vif_priv->encrypt_type,
 572				key_conf->keyidx);
 573		} else {
 574			sta_priv->is_data_encrypted = false;
 575			/* do not remove key if disassociated */
 576			if (sta_priv->aid)
 577				wcn36xx_smd_remove_stakey(wcn,
 578					vif_priv->encrypt_type,
 579					key_conf->keyidx,
 580					get_sta_index(vif, sta_priv));
 581		}
 582		break;
 583	default:
 584		wcn36xx_err("Unsupported key cmd 0x%x\n", cmd);
 585		ret = -EOPNOTSUPP;
 586		goto out;
 587	}
 588
 589out:
 590	mutex_unlock(&wcn->conf_mutex);
 591
 592	return ret;
 593}
 594
 595static void wcn36xx_hw_scan_worker(struct work_struct *work)
 596{
 597	struct wcn36xx *wcn = container_of(work, struct wcn36xx, scan_work);
 598	struct cfg80211_scan_request *req = wcn->scan_req;
 599	u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS_EX];
 600	struct cfg80211_scan_info scan_info = {};
 601	bool aborted = false;
 602	int i;
 603
 604	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 scan %d channels worker\n", req->n_channels);
 605
 606	for (i = 0; i < req->n_channels; i++)
 607		channels[i] = req->channels[i]->hw_value;
 608
 609	wcn36xx_smd_update_scan_params(wcn, channels, req->n_channels);
 610
 611	wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN);
 612	for (i = 0; i < req->n_channels; i++) {
 613		mutex_lock(&wcn->scan_lock);
 614		aborted = wcn->scan_aborted;
 615		mutex_unlock(&wcn->scan_lock);
 616
 617		if (aborted)
 618			break;
 619
 620		wcn->scan_freq = req->channels[i]->center_freq;
 621		wcn->scan_band = req->channels[i]->band;
 622
 623		wcn36xx_smd_start_scan(wcn, req->channels[i]->hw_value);
 624		msleep(30);
 625		wcn36xx_smd_end_scan(wcn, req->channels[i]->hw_value);
 626
 627		wcn->scan_freq = 0;
 628	}
 629	wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN);
 630
 631	scan_info.aborted = aborted;
 632	ieee80211_scan_completed(wcn->hw, &scan_info);
 633
 634	mutex_lock(&wcn->scan_lock);
 635	wcn->scan_req = NULL;
 636	mutex_unlock(&wcn->scan_lock);
 637}
 638
 639static int wcn36xx_hw_scan(struct ieee80211_hw *hw,
 640			   struct ieee80211_vif *vif,
 641			   struct ieee80211_scan_request *hw_req)
 642{
 643	struct wcn36xx *wcn = hw->priv;
 644	mutex_lock(&wcn->scan_lock);
 645	if (wcn->scan_req) {
 646		mutex_unlock(&wcn->scan_lock);
 647		return -EBUSY;
 648	}
 649
 650	wcn->scan_aborted = false;
 651	wcn->scan_req = &hw_req->req;
 652
 653	mutex_unlock(&wcn->scan_lock);
 654
 655	if (!get_feat_caps(wcn->fw_feat_caps, SCAN_OFFLOAD)) {
 656		/* legacy manual/sw scan */
 657		schedule_work(&wcn->scan_work);
 658		return 0;
 659	}
 660
 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	/* ieee80211_scan_completed will be called on FW scan indication */
 674	wcn36xx_smd_stop_hw_scan(wcn);
 675
 676	cancel_work_sync(&wcn->scan_work);
 677}
 678
 679static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
 680					 enum nl80211_band band)
 681{
 682	int i, size;
 683	u16 *rates_table;
 684	struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
 685	u32 rates = sta->supp_rates[band];
 686
 687	memset(&sta_priv->supported_rates, 0,
 688		sizeof(sta_priv->supported_rates));
 689	sta_priv->supported_rates.op_rate_mode = STA_11n;
 690
 691	size = ARRAY_SIZE(sta_priv->supported_rates.dsss_rates);
 692	rates_table = sta_priv->supported_rates.dsss_rates;
 693	if (band == NL80211_BAND_2GHZ) {
 694		for (i = 0; i < size; i++) {
 695			if (rates & 0x01) {
 696				rates_table[i] = wcn_2ghz_rates[i].hw_value;
 697				rates = rates >> 1;
 698			}
 699		}
 700	}
 701
 702	size = ARRAY_SIZE(sta_priv->supported_rates.ofdm_rates);
 703	rates_table = sta_priv->supported_rates.ofdm_rates;
 704	for (i = 0; i < size; i++) {
 705		if (rates & 0x01) {
 706			rates_table[i] = wcn_5ghz_rates[i].hw_value;
 707			rates = rates >> 1;
 708		}
 709	}
 710
 711	if (sta->ht_cap.ht_supported) {
 712		BUILD_BUG_ON(sizeof(sta->ht_cap.mcs.rx_mask) >
 713			sizeof(sta_priv->supported_rates.supported_mcs_set));
 714		memcpy(sta_priv->supported_rates.supported_mcs_set,
 715		       sta->ht_cap.mcs.rx_mask,
 716		       sizeof(sta->ht_cap.mcs.rx_mask));
 717	}
 718}
 719void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates)
 720{
 721	u16 ofdm_rates[WCN36XX_HAL_NUM_OFDM_RATES] = {
 722		HW_RATE_INDEX_6MBPS,
 723		HW_RATE_INDEX_9MBPS,
 724		HW_RATE_INDEX_12MBPS,
 725		HW_RATE_INDEX_18MBPS,
 726		HW_RATE_INDEX_24MBPS,
 727		HW_RATE_INDEX_36MBPS,
 728		HW_RATE_INDEX_48MBPS,
 729		HW_RATE_INDEX_54MBPS
 730	};
 731	u16 dsss_rates[WCN36XX_HAL_NUM_DSSS_RATES] = {
 732		HW_RATE_INDEX_1MBPS,
 733		HW_RATE_INDEX_2MBPS,
 734		HW_RATE_INDEX_5_5MBPS,
 735		HW_RATE_INDEX_11MBPS
 736	};
 737
 738	rates->op_rate_mode = STA_11n;
 739	memcpy(rates->dsss_rates, dsss_rates,
 740		sizeof(*dsss_rates) * WCN36XX_HAL_NUM_DSSS_RATES);
 741	memcpy(rates->ofdm_rates, ofdm_rates,
 742		sizeof(*ofdm_rates) * WCN36XX_HAL_NUM_OFDM_RATES);
 743	rates->supported_mcs_set[0] = 0xFF;
 744}
 745static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
 746				     struct ieee80211_vif *vif,
 747				     struct ieee80211_bss_conf *bss_conf,
 748				     u32 changed)
 749{
 750	struct wcn36xx *wcn = hw->priv;
 751	struct sk_buff *skb = NULL;
 752	u16 tim_off, tim_len;
 753	enum wcn36xx_hal_link_state link_state;
 754	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
 755
 756	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%08x\n",
 757		    vif, changed);
 758
 759	mutex_lock(&wcn->conf_mutex);
 760
 761	if (changed & BSS_CHANGED_BEACON_INFO) {
 762		wcn36xx_dbg(WCN36XX_DBG_MAC,
 763			    "mac bss changed dtim period %d\n",
 764			    bss_conf->dtim_period);
 765
 766		vif_priv->dtim_period = bss_conf->dtim_period;
 767	}
 768
 769	if (changed & BSS_CHANGED_BSSID) {
 770		wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed_bssid %pM\n",
 771			    bss_conf->bssid);
 772
 773		if (!is_zero_ether_addr(bss_conf->bssid)) {
 774			vif_priv->is_joining = true;
 775			vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX;
 776			wcn36xx_smd_join(wcn, bss_conf->bssid,
 777					 vif->addr, WCN36XX_HW_CHANNEL(wcn));
 778			wcn36xx_smd_config_bss(wcn, vif, NULL,
 779					       bss_conf->bssid, false);
 780		} else {
 781			vif_priv->is_joining = false;
 782			wcn36xx_smd_delete_bss(wcn, vif);
 783			vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE;
 784		}
 785	}
 786
 787	if (changed & BSS_CHANGED_SSID) {
 788		wcn36xx_dbg(WCN36XX_DBG_MAC,
 789			    "mac bss changed ssid\n");
 790		wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "ssid ",
 791				 bss_conf->ssid, bss_conf->ssid_len);
 792
 793		vif_priv->ssid.length = bss_conf->ssid_len;
 794		memcpy(&vif_priv->ssid.ssid,
 795		       bss_conf->ssid,
 796		       bss_conf->ssid_len);
 797	}
 798
 799	if (changed & BSS_CHANGED_ASSOC) {
 800		vif_priv->is_joining = false;
 801		if (bss_conf->assoc) {
 802			struct ieee80211_sta *sta;
 803			struct wcn36xx_sta *sta_priv;
 804
 805			wcn36xx_dbg(WCN36XX_DBG_MAC,
 806				    "mac assoc bss %pM vif %pM AID=%d\n",
 807				     bss_conf->bssid,
 808				     vif->addr,
 809				     bss_conf->aid);
 810
 811			vif_priv->sta_assoc = true;
 812
 813			/*
 814			 * Holding conf_mutex ensures mutal exclusion with
 815			 * wcn36xx_sta_remove() and as such ensures that sta
 816			 * won't be freed while we're operating on it. As such
 817			 * we do not need to hold the rcu_read_lock().
 818			 */
 819			sta = ieee80211_find_sta(vif, bss_conf->bssid);
 820			if (!sta) {
 821				wcn36xx_err("sta %pM is not found\n",
 822					      bss_conf->bssid);
 823				goto out;
 824			}
 825			sta_priv = wcn36xx_sta_to_priv(sta);
 826
 827			wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn));
 828
 829			wcn36xx_smd_set_link_st(wcn, bss_conf->bssid,
 830				vif->addr,
 831				WCN36XX_HAL_LINK_POSTASSOC_STATE);
 832			wcn36xx_smd_config_bss(wcn, vif, sta,
 833					       bss_conf->bssid,
 834					       true);
 835			sta_priv->aid = bss_conf->aid;
 836			/*
 837			 * config_sta must be called from  because this is the
 838			 * place where AID is available.
 839			 */
 840			wcn36xx_smd_config_sta(wcn, vif, sta);
 841		} else {
 842			wcn36xx_dbg(WCN36XX_DBG_MAC,
 843				    "disassociated bss %pM vif %pM AID=%d\n",
 844				    bss_conf->bssid,
 845				    vif->addr,
 846				    bss_conf->aid);
 847			vif_priv->sta_assoc = false;
 848			wcn36xx_smd_set_link_st(wcn,
 849						bss_conf->bssid,
 850						vif->addr,
 851						WCN36XX_HAL_LINK_IDLE_STATE);
 852		}
 853	}
 854
 855	if (changed & BSS_CHANGED_AP_PROBE_RESP) {
 856		wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed ap probe resp\n");
 857		skb = ieee80211_proberesp_get(hw, vif);
 858		if (!skb) {
 859			wcn36xx_err("failed to alloc probereq skb\n");
 860			goto out;
 861		}
 862
 863		wcn36xx_smd_update_proberesp_tmpl(wcn, vif, skb);
 864		dev_kfree_skb(skb);
 865	}
 866
 867	if (changed & BSS_CHANGED_BEACON_ENABLED ||
 868	    changed & BSS_CHANGED_BEACON) {
 869		wcn36xx_dbg(WCN36XX_DBG_MAC,
 870			    "mac bss changed beacon enabled %d\n",
 871			    bss_conf->enable_beacon);
 872
 873		if (bss_conf->enable_beacon) {
 874			vif_priv->dtim_period = bss_conf->dtim_period;
 875			vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX;
 876			wcn36xx_smd_config_bss(wcn, vif, NULL,
 877					       vif->addr, false);
 878			skb = ieee80211_beacon_get_tim(hw, vif, &tim_off,
 879						       &tim_len);
 880			if (!skb) {
 881				wcn36xx_err("failed to alloc beacon skb\n");
 882				goto out;
 883			}
 884			wcn36xx_smd_send_beacon(wcn, vif, skb, tim_off, 0);
 885			dev_kfree_skb(skb);
 886
 887			if (vif->type == NL80211_IFTYPE_ADHOC ||
 888			    vif->type == NL80211_IFTYPE_MESH_POINT)
 889				link_state = WCN36XX_HAL_LINK_IBSS_STATE;
 890			else
 891				link_state = WCN36XX_HAL_LINK_AP_STATE;
 892
 893			wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,
 894						link_state);
 895		} else {
 896			wcn36xx_smd_delete_bss(wcn, vif);
 897			wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,
 898						WCN36XX_HAL_LINK_IDLE_STATE);
 899		}
 900	}
 901out:
 902
 903	mutex_unlock(&wcn->conf_mutex);
 904
 905	return;
 906}
 907
 908/* this is required when using IEEE80211_HW_HAS_RATE_CONTROL */
 909static int wcn36xx_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 910{
 911	struct wcn36xx *wcn = hw->priv;
 912	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac set RTS threshold %d\n", value);
 913
 914	mutex_lock(&wcn->conf_mutex);
 915	wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_RTS_THRESHOLD, value);
 916	mutex_unlock(&wcn->conf_mutex);
 917
 918	return 0;
 919}
 920
 921static void wcn36xx_remove_interface(struct ieee80211_hw *hw,
 922				     struct ieee80211_vif *vif)
 923{
 924	struct wcn36xx *wcn = hw->priv;
 925	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
 926	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac remove interface vif %p\n", vif);
 927
 928	mutex_lock(&wcn->conf_mutex);
 929
 930	list_del(&vif_priv->list);
 931	wcn36xx_smd_delete_sta_self(wcn, vif->addr);
 932
 933	mutex_unlock(&wcn->conf_mutex);
 934}
 935
 936static int wcn36xx_add_interface(struct ieee80211_hw *hw,
 937				 struct ieee80211_vif *vif)
 938{
 939	struct wcn36xx *wcn = hw->priv;
 940	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
 941
 942	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac add interface vif %p type %d\n",
 943		    vif, vif->type);
 944
 945	if (!(NL80211_IFTYPE_STATION == vif->type ||
 946	      NL80211_IFTYPE_AP == vif->type ||
 947	      NL80211_IFTYPE_ADHOC == vif->type ||
 948	      NL80211_IFTYPE_MESH_POINT == vif->type)) {
 949		wcn36xx_warn("Unsupported interface type requested: %d\n",
 950			     vif->type);
 951		return -EOPNOTSUPP;
 952	}
 953
 954	mutex_lock(&wcn->conf_mutex);
 955
 956	list_add(&vif_priv->list, &wcn->vif_list);
 957	wcn36xx_smd_add_sta_self(wcn, vif);
 958
 959	mutex_unlock(&wcn->conf_mutex);
 960
 961	return 0;
 962}
 963
 964static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 965			   struct ieee80211_sta *sta)
 966{
 967	struct wcn36xx *wcn = hw->priv;
 968	struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
 969	struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
 970	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n",
 971		    vif, sta->addr);
 972
 973	mutex_lock(&wcn->conf_mutex);
 974
 975	spin_lock_init(&sta_priv->ampdu_lock);
 976	sta_priv->vif = vif_priv;
 977	/*
 978	 * For STA mode HW will be configured on BSS_CHANGED_ASSOC because
 979	 * at this stage AID is not available yet.
 980	 */
 981	if (NL80211_IFTYPE_STATION != vif->type) {
 982		wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn));
 983		sta_priv->aid = sta->aid;
 984		wcn36xx_smd_config_sta(wcn, vif, sta);
 985	}
 986
 987	mutex_unlock(&wcn->conf_mutex);
 988
 989	return 0;
 990}
 991
 992static int wcn36xx_sta_remove(struct ieee80211_hw *hw,
 993			      struct ieee80211_vif *vif,
 994			      struct ieee80211_sta *sta)
 995{
 996	struct wcn36xx *wcn = hw->priv;
 997	struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
 998
 999	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta remove vif %p sta %pM index %d\n",
1000		    vif, sta->addr, sta_priv->sta_index);
1001
1002	mutex_lock(&wcn->conf_mutex);
1003
1004	wcn36xx_smd_delete_sta(wcn, sta_priv->sta_index);
1005	sta_priv->vif = NULL;
1006
1007	mutex_unlock(&wcn->conf_mutex);
1008
1009	return 0;
1010}
1011
1012#ifdef CONFIG_PM
1013
1014static int wcn36xx_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow)
1015{
1016	struct wcn36xx *wcn = hw->priv;
1017
1018	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac suspend\n");
1019
1020	flush_workqueue(wcn->hal_ind_wq);
1021	wcn36xx_smd_set_power_params(wcn, true);
1022	return 0;
1023}
1024
1025static int wcn36xx_resume(struct ieee80211_hw *hw)
1026{
1027	struct wcn36xx *wcn = hw->priv;
1028
1029	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac resume\n");
1030
1031	flush_workqueue(wcn->hal_ind_wq);
1032	wcn36xx_smd_set_power_params(wcn, false);
1033	return 0;
1034}
1035
1036#endif
1037
1038static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
1039		    struct ieee80211_vif *vif,
1040		    struct ieee80211_ampdu_params *params)
1041{
1042	struct wcn36xx *wcn = hw->priv;
1043	struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(params->sta);
1044	struct ieee80211_sta *sta = params->sta;
1045	enum ieee80211_ampdu_mlme_action action = params->action;
1046	u16 tid = params->tid;
1047	u16 *ssn = &params->ssn;
1048
1049	wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
1050		    action, tid);
1051
1052	mutex_lock(&wcn->conf_mutex);
1053
1054	switch (action) {
1055	case IEEE80211_AMPDU_RX_START:
1056		sta_priv->tid = tid;
1057		wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0,
1058			get_sta_index(vif, sta_priv));
1059		wcn36xx_smd_add_ba(wcn);
1060		wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv));
1061		break;
1062	case IEEE80211_AMPDU_RX_STOP:
1063		wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv));
1064		break;
1065	case IEEE80211_AMPDU_TX_START:
1066		spin_lock_bh(&sta_priv->ampdu_lock);
1067		sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
1068		spin_unlock_bh(&sta_priv->ampdu_lock);
1069
1070		ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1071		break;
1072	case IEEE80211_AMPDU_TX_OPERATIONAL:
1073		spin_lock_bh(&sta_priv->ampdu_lock);
1074		sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL;
1075		spin_unlock_bh(&sta_priv->ampdu_lock);
1076
1077		wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1,
1078			get_sta_index(vif, sta_priv));
1079		break;
1080	case IEEE80211_AMPDU_TX_STOP_FLUSH:
1081	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
1082	case IEEE80211_AMPDU_TX_STOP_CONT:
1083		spin_lock_bh(&sta_priv->ampdu_lock);
1084		sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_NONE;
1085		spin_unlock_bh(&sta_priv->ampdu_lock);
1086
1087		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1088		break;
1089	default:
1090		wcn36xx_err("Unknown AMPDU action\n");
1091	}
1092
1093	mutex_unlock(&wcn->conf_mutex);
1094
1095	return 0;
1096}
1097
1098static const struct ieee80211_ops wcn36xx_ops = {
1099	.start			= wcn36xx_start,
1100	.stop			= wcn36xx_stop,
1101	.add_interface		= wcn36xx_add_interface,
1102	.remove_interface	= wcn36xx_remove_interface,
1103#ifdef CONFIG_PM
1104	.suspend		= wcn36xx_suspend,
1105	.resume			= wcn36xx_resume,
1106#endif
1107	.config			= wcn36xx_config,
1108	.prepare_multicast	= wcn36xx_prepare_multicast,
1109	.configure_filter       = wcn36xx_configure_filter,
1110	.tx			= wcn36xx_tx,
1111	.set_key		= wcn36xx_set_key,
1112	.hw_scan		= wcn36xx_hw_scan,
1113	.cancel_hw_scan		= wcn36xx_cancel_hw_scan,
1114	.bss_info_changed	= wcn36xx_bss_info_changed,
1115	.set_rts_threshold	= wcn36xx_set_rts_threshold,
1116	.sta_add		= wcn36xx_sta_add,
1117	.sta_remove		= wcn36xx_sta_remove,
1118	.ampdu_action		= wcn36xx_ampdu_action,
1119};
1120
1121static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
1122{
1123	int ret = 0;
1124
1125	static const u32 cipher_suites[] = {
1126		WLAN_CIPHER_SUITE_WEP40,
1127		WLAN_CIPHER_SUITE_WEP104,
1128		WLAN_CIPHER_SUITE_TKIP,
1129		WLAN_CIPHER_SUITE_CCMP,
1130	};
1131
1132	ieee80211_hw_set(wcn->hw, TIMING_BEACON_ONLY);
1133	ieee80211_hw_set(wcn->hw, AMPDU_AGGREGATION);
1134	ieee80211_hw_set(wcn->hw, CONNECTION_MONITOR);
1135	ieee80211_hw_set(wcn->hw, SUPPORTS_PS);
1136	ieee80211_hw_set(wcn->hw, SIGNAL_DBM);
1137	ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL);
1138	ieee80211_hw_set(wcn->hw, SINGLE_SCAN_ON_ALL_BANDS);
1139
1140	wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1141		BIT(NL80211_IFTYPE_AP) |
1142		BIT(NL80211_IFTYPE_ADHOC) |
1143		BIT(NL80211_IFTYPE_MESH_POINT);
1144
1145	wcn->hw->wiphy->bands[NL80211_BAND_2GHZ] = &wcn_band_2ghz;
1146	if (wcn->rf_id != RF_IRIS_WCN3620)
1147		wcn->hw->wiphy->bands[NL80211_BAND_5GHZ] = &wcn_band_5ghz;
1148
1149	wcn->hw->wiphy->max_scan_ssids = WCN36XX_MAX_SCAN_SSIDS;
1150	wcn->hw->wiphy->max_scan_ie_len = WCN36XX_MAX_SCAN_IE_LEN;
1151
1152	wcn->hw->wiphy->cipher_suites = cipher_suites;
1153	wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
1154
1155#ifdef CONFIG_PM
1156	wcn->hw->wiphy->wowlan = &wowlan_support;
1157#endif
1158
1159	wcn->hw->max_listen_interval = 200;
1160
1161	wcn->hw->queues = 4;
1162
1163	SET_IEEE80211_DEV(wcn->hw, wcn->dev);
1164
1165	wcn->hw->sta_data_size = sizeof(struct wcn36xx_sta);
1166	wcn->hw->vif_data_size = sizeof(struct wcn36xx_vif);
1167
1168	wiphy_ext_feature_set(wcn->hw->wiphy,
1169			      NL80211_EXT_FEATURE_CQM_RSSI_LIST);
1170
1171	return ret;
1172}
1173
1174static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
1175					  struct platform_device *pdev)
1176{
1177	struct device_node *mmio_node;
1178	struct device_node *iris_node;
1179	struct resource *res;
1180	int index;
1181	int ret;
1182
1183	/* Set TX IRQ */
1184	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "tx");
1185	if (!res) {
1186		wcn36xx_err("failed to get tx_irq\n");
1187		return -ENOENT;
1188	}
1189	wcn->tx_irq = res->start;
1190
1191	/* Set RX IRQ */
1192	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "rx");
1193	if (!res) {
1194		wcn36xx_err("failed to get rx_irq\n");
1195		return -ENOENT;
1196	}
1197	wcn->rx_irq = res->start;
1198
1199	/* Acquire SMSM tx enable handle */
1200	wcn->tx_enable_state = qcom_smem_state_get(&pdev->dev,
1201			"tx-enable", &wcn->tx_enable_state_bit);
1202	if (IS_ERR(wcn->tx_enable_state)) {
1203		wcn36xx_err("failed to get tx-enable state\n");
1204		return PTR_ERR(wcn->tx_enable_state);
1205	}
1206
1207	/* Acquire SMSM tx rings empty handle */
1208	wcn->tx_rings_empty_state = qcom_smem_state_get(&pdev->dev,
1209			"tx-rings-empty", &wcn->tx_rings_empty_state_bit);
1210	if (IS_ERR(wcn->tx_rings_empty_state)) {
1211		wcn36xx_err("failed to get tx-rings-empty state\n");
1212		return PTR_ERR(wcn->tx_rings_empty_state);
1213	}
1214
1215	mmio_node = of_parse_phandle(pdev->dev.parent->of_node, "qcom,mmio", 0);
1216	if (!mmio_node) {
1217		wcn36xx_err("failed to acquire qcom,mmio reference\n");
1218		return -EINVAL;
1219	}
1220
1221	wcn->is_pronto = !!of_device_is_compatible(mmio_node, "qcom,pronto");
1222
1223	/* Map the CCU memory */
1224	index = of_property_match_string(mmio_node, "reg-names", "ccu");
1225	wcn->ccu_base = of_iomap(mmio_node, index);
1226	if (!wcn->ccu_base) {
1227		wcn36xx_err("failed to map ccu memory\n");
1228		ret = -ENOMEM;
1229		goto put_mmio_node;
1230	}
1231
1232	/* Map the DXE memory */
1233	index = of_property_match_string(mmio_node, "reg-names", "dxe");
1234	wcn->dxe_base = of_iomap(mmio_node, index);
1235	if (!wcn->dxe_base) {
1236		wcn36xx_err("failed to map dxe memory\n");
1237		ret = -ENOMEM;
1238		goto unmap_ccu;
1239	}
1240
1241	/* External RF module */
1242	iris_node = of_get_child_by_name(mmio_node, "iris");
1243	if (iris_node) {
1244		if (of_device_is_compatible(iris_node, "qcom,wcn3620"))
1245			wcn->rf_id = RF_IRIS_WCN3620;
1246		of_node_put(iris_node);
1247	}
1248
1249	of_node_put(mmio_node);
1250	return 0;
1251
1252unmap_ccu:
1253	iounmap(wcn->ccu_base);
1254put_mmio_node:
1255	of_node_put(mmio_node);
1256	return ret;
1257}
1258
1259static int wcn36xx_probe(struct platform_device *pdev)
1260{
1261	struct ieee80211_hw *hw;
1262	struct wcn36xx *wcn;
1263	void *wcnss;
1264	int ret;
1265	const u8 *addr;
1266
1267	wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
1268
1269	wcnss = dev_get_drvdata(pdev->dev.parent);
1270
1271	hw = ieee80211_alloc_hw(sizeof(struct wcn36xx), &wcn36xx_ops);
1272	if (!hw) {
1273		wcn36xx_err("failed to alloc hw\n");
1274		ret = -ENOMEM;
1275		goto out_err;
1276	}
1277	platform_set_drvdata(pdev, hw);
1278	wcn = hw->priv;
1279	wcn->hw = hw;
1280	wcn->dev = &pdev->dev;
1281	wcn->first_boot = true;
1282	mutex_init(&wcn->conf_mutex);
1283	mutex_init(&wcn->hal_mutex);
1284	mutex_init(&wcn->scan_lock);
1285
1286	INIT_WORK(&wcn->scan_work, wcn36xx_hw_scan_worker);
1287
1288	wcn->smd_channel = qcom_wcnss_open_channel(wcnss, "WLAN_CTRL", wcn36xx_smd_rsp_process, hw);
1289	if (IS_ERR(wcn->smd_channel)) {
1290		wcn36xx_err("failed to open WLAN_CTRL channel\n");
1291		ret = PTR_ERR(wcn->smd_channel);
1292		goto out_wq;
1293	}
1294
1295	addr = of_get_property(pdev->dev.of_node, "local-mac-address", &ret);
1296	if (addr && ret != ETH_ALEN) {
1297		wcn36xx_err("invalid local-mac-address\n");
1298		ret = -EINVAL;
1299		goto out_wq;
1300	} else if (addr) {
1301		wcn36xx_info("mac address: %pM\n", addr);
1302		SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
1303	}
1304
1305	ret = wcn36xx_platform_get_resources(wcn, pdev);
1306	if (ret)
1307		goto out_wq;
1308
1309	wcn36xx_init_ieee80211(wcn);
1310	ret = ieee80211_register_hw(wcn->hw);
1311	if (ret)
1312		goto out_unmap;
1313
1314	return 0;
1315
1316out_unmap:
1317	iounmap(wcn->ccu_base);
1318	iounmap(wcn->dxe_base);
1319out_wq:
1320	ieee80211_free_hw(hw);
1321out_err:
1322	return ret;
1323}
1324
1325static int wcn36xx_remove(struct platform_device *pdev)
1326{
1327	struct ieee80211_hw *hw = platform_get_drvdata(pdev);
1328	struct wcn36xx *wcn = hw->priv;
1329	wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");
1330
1331	release_firmware(wcn->nv);
1332
1333	ieee80211_unregister_hw(hw);
1334
1335	qcom_smem_state_put(wcn->tx_enable_state);
1336	qcom_smem_state_put(wcn->tx_rings_empty_state);
1337
1338	rpmsg_destroy_ept(wcn->smd_channel);
1339
1340	iounmap(wcn->dxe_base);
1341	iounmap(wcn->ccu_base);
1342
1343	mutex_destroy(&wcn->hal_mutex);
1344	ieee80211_free_hw(hw);
1345
1346	return 0;
1347}
1348
1349static const struct of_device_id wcn36xx_of_match[] = {
1350	{ .compatible = "qcom,wcnss-wlan" },
1351	{}
1352};
1353MODULE_DEVICE_TABLE(of, wcn36xx_of_match);
1354
1355static struct platform_driver wcn36xx_driver = {
1356	.probe      = wcn36xx_probe,
1357	.remove     = wcn36xx_remove,
1358	.driver         = {
1359		.name   = "wcn36xx",
1360		.of_match_table = wcn36xx_of_match,
1361	},
1362};
1363
1364module_platform_driver(wcn36xx_driver);
1365
1366MODULE_LICENSE("Dual BSD/GPL");
1367MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
1368MODULE_FIRMWARE(WLAN_NV_FILE);