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 = ¶ms->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