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