]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/ath/wcn36xx/main.c
wcn36xx: remove powersaving for wcn3620
[karo-tx-linux.git] / drivers / net / wireless / ath / wcn36xx / main.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 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 "wcn36xx.h"
23
24 unsigned int wcn36xx_dbg_mask;
25 module_param_named(debug_mask, wcn36xx_dbg_mask, uint, 0644);
26 MODULE_PARM_DESC(debug_mask, "Debugging mask");
27
28 #define CHAN2G(_freq, _idx) { \
29         .band = IEEE80211_BAND_2GHZ, \
30         .center_freq = (_freq), \
31         .hw_value = (_idx), \
32         .max_power = 25, \
33 }
34
35 #define CHAN5G(_freq, _idx) { \
36         .band = IEEE80211_BAND_5GHZ, \
37         .center_freq = (_freq), \
38         .hw_value = (_idx), \
39         .max_power = 25, \
40 }
41
42 /* The wcn firmware expects channel values to matching
43  * their mnemonic values. So use these for .hw_value. */
44 static struct ieee80211_channel wcn_2ghz_channels[] = {
45         CHAN2G(2412, 1), /* Channel 1 */
46         CHAN2G(2417, 2), /* Channel 2 */
47         CHAN2G(2422, 3), /* Channel 3 */
48         CHAN2G(2427, 4), /* Channel 4 */
49         CHAN2G(2432, 5), /* Channel 5 */
50         CHAN2G(2437, 6), /* Channel 6 */
51         CHAN2G(2442, 7), /* Channel 7 */
52         CHAN2G(2447, 8), /* Channel 8 */
53         CHAN2G(2452, 9), /* Channel 9 */
54         CHAN2G(2457, 10), /* Channel 10 */
55         CHAN2G(2462, 11), /* Channel 11 */
56         CHAN2G(2467, 12), /* Channel 12 */
57         CHAN2G(2472, 13), /* Channel 13 */
58         CHAN2G(2484, 14)  /* Channel 14 */
59
60 };
61
62 static struct ieee80211_channel wcn_5ghz_channels[] = {
63         CHAN5G(5180, 36),
64         CHAN5G(5200, 40),
65         CHAN5G(5220, 44),
66         CHAN5G(5240, 48),
67         CHAN5G(5260, 52),
68         CHAN5G(5280, 56),
69         CHAN5G(5300, 60),
70         CHAN5G(5320, 64),
71         CHAN5G(5500, 100),
72         CHAN5G(5520, 104),
73         CHAN5G(5540, 108),
74         CHAN5G(5560, 112),
75         CHAN5G(5580, 116),
76         CHAN5G(5600, 120),
77         CHAN5G(5620, 124),
78         CHAN5G(5640, 128),
79         CHAN5G(5660, 132),
80         CHAN5G(5700, 140),
81         CHAN5G(5745, 149),
82         CHAN5G(5765, 153),
83         CHAN5G(5785, 157),
84         CHAN5G(5805, 161),
85         CHAN5G(5825, 165)
86 };
87
88 #define RATE(_bitrate, _hw_rate, _flags) { \
89         .bitrate        = (_bitrate),                   \
90         .flags          = (_flags),                     \
91         .hw_value       = (_hw_rate),                   \
92         .hw_value_short = (_hw_rate)  \
93 }
94
95 static struct ieee80211_rate wcn_2ghz_rates[] = {
96         RATE(10, HW_RATE_INDEX_1MBPS, 0),
97         RATE(20, HW_RATE_INDEX_2MBPS, IEEE80211_RATE_SHORT_PREAMBLE),
98         RATE(55, HW_RATE_INDEX_5_5MBPS, IEEE80211_RATE_SHORT_PREAMBLE),
99         RATE(110, HW_RATE_INDEX_11MBPS, IEEE80211_RATE_SHORT_PREAMBLE),
100         RATE(60, HW_RATE_INDEX_6MBPS, 0),
101         RATE(90, HW_RATE_INDEX_9MBPS, 0),
102         RATE(120, HW_RATE_INDEX_12MBPS, 0),
103         RATE(180, HW_RATE_INDEX_18MBPS, 0),
104         RATE(240, HW_RATE_INDEX_24MBPS, 0),
105         RATE(360, HW_RATE_INDEX_36MBPS, 0),
106         RATE(480, HW_RATE_INDEX_48MBPS, 0),
107         RATE(540, HW_RATE_INDEX_54MBPS, 0)
108 };
109
110 static struct ieee80211_rate wcn_5ghz_rates[] = {
111         RATE(60, HW_RATE_INDEX_6MBPS, 0),
112         RATE(90, HW_RATE_INDEX_9MBPS, 0),
113         RATE(120, HW_RATE_INDEX_12MBPS, 0),
114         RATE(180, HW_RATE_INDEX_18MBPS, 0),
115         RATE(240, HW_RATE_INDEX_24MBPS, 0),
116         RATE(360, HW_RATE_INDEX_36MBPS, 0),
117         RATE(480, HW_RATE_INDEX_48MBPS, 0),
118         RATE(540, HW_RATE_INDEX_54MBPS, 0)
119 };
120
121 static struct ieee80211_supported_band wcn_band_2ghz = {
122         .channels       = wcn_2ghz_channels,
123         .n_channels     = ARRAY_SIZE(wcn_2ghz_channels),
124         .bitrates       = wcn_2ghz_rates,
125         .n_bitrates     = ARRAY_SIZE(wcn_2ghz_rates),
126         .ht_cap         = {
127                 .cap =  IEEE80211_HT_CAP_GRN_FLD |
128                         IEEE80211_HT_CAP_SGI_20 |
129                         IEEE80211_HT_CAP_DSSSCCK40 |
130                         IEEE80211_HT_CAP_LSIG_TXOP_PROT,
131                 .ht_supported = true,
132                 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
133                 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
134                 .mcs = {
135                         .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
136                         .rx_highest = cpu_to_le16(72),
137                         .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
138                 }
139         }
140 };
141
142 static struct ieee80211_supported_band wcn_band_5ghz = {
143         .channels       = wcn_5ghz_channels,
144         .n_channels     = ARRAY_SIZE(wcn_5ghz_channels),
145         .bitrates       = wcn_5ghz_rates,
146         .n_bitrates     = ARRAY_SIZE(wcn_5ghz_rates),
147         .ht_cap         = {
148                 .cap =  IEEE80211_HT_CAP_GRN_FLD |
149                         IEEE80211_HT_CAP_SGI_20 |
150                         IEEE80211_HT_CAP_DSSSCCK40 |
151                         IEEE80211_HT_CAP_LSIG_TXOP_PROT |
152                         IEEE80211_HT_CAP_SGI_40 |
153                         IEEE80211_HT_CAP_SUP_WIDTH_20_40,
154                 .ht_supported = true,
155                 .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
156                 .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16,
157                 .mcs = {
158                         .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
159                         .rx_highest = cpu_to_le16(72),
160                         .tx_params = IEEE80211_HT_MCS_TX_DEFINED,
161                 }
162         }
163 };
164
165 #ifdef CONFIG_PM
166
167 static const struct wiphy_wowlan_support wowlan_support = {
168         .flags = WIPHY_WOWLAN_ANY
169 };
170
171 #endif
172
173 static inline u8 get_sta_index(struct ieee80211_vif *vif,
174                                struct wcn36xx_sta *sta_priv)
175 {
176         return NL80211_IFTYPE_STATION == vif->type ?
177                sta_priv->bss_sta_index :
178                sta_priv->sta_index;
179 }
180
181 static const char * const wcn36xx_caps_names[] = {
182         "MCC",                          /* 0 */
183         "P2P",                          /* 1 */
184         "DOT11AC",                      /* 2 */
185         "SLM_SESSIONIZATION",           /* 3 */
186         "DOT11AC_OPMODE",               /* 4 */
187         "SAP32STA",                     /* 5 */
188         "TDLS",                         /* 6 */
189         "P2P_GO_NOA_DECOUPLE_INIT_SCAN",/* 7 */
190         "WLANACTIVE_OFFLOAD",           /* 8 */
191         "BEACON_OFFLOAD",               /* 9 */
192         "SCAN_OFFLOAD",                 /* 10 */
193         "ROAM_OFFLOAD",                 /* 11 */
194         "BCN_MISS_OFFLOAD",             /* 12 */
195         "STA_POWERSAVE",                /* 13 */
196         "STA_ADVANCED_PWRSAVE",         /* 14 */
197         "AP_UAPSD",                     /* 15 */
198         "AP_DFS",                       /* 16 */
199         "BLOCKACK",                     /* 17 */
200         "PHY_ERR",                      /* 18 */
201         "BCN_FILTER",                   /* 19 */
202         "RTT",                          /* 20 */
203         "RATECTRL",                     /* 21 */
204         "WOW"                           /* 22 */
205 };
206
207 static const char *wcn36xx_get_cap_name(enum place_holder_in_cap_bitmap x)
208 {
209         if (x >= ARRAY_SIZE(wcn36xx_caps_names))
210                 return "UNKNOWN";
211         return wcn36xx_caps_names[x];
212 }
213
214 static void wcn36xx_feat_caps_info(struct wcn36xx *wcn)
215 {
216         int i;
217
218         for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) {
219                 if (get_feat_caps(wcn->fw_feat_caps, i))
220                         wcn36xx_info("FW Cap %s\n", wcn36xx_get_cap_name(i));
221         }
222 }
223
224 static int wcn36xx_start(struct ieee80211_hw *hw)
225 {
226         struct wcn36xx *wcn = hw->priv;
227         int ret;
228
229         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac start\n");
230
231         /* SMD initialization */
232         ret = wcn36xx_smd_open(wcn);
233         if (ret) {
234                 wcn36xx_err("Failed to open smd channel: %d\n", ret);
235                 goto out_err;
236         }
237
238         /* Allocate memory pools for Mgmt BD headers and Data BD headers */
239         ret = wcn36xx_dxe_allocate_mem_pools(wcn);
240         if (ret) {
241                 wcn36xx_err("Failed to alloc DXE mempool: %d\n", ret);
242                 goto out_smd_close;
243         }
244
245         ret = wcn36xx_dxe_alloc_ctl_blks(wcn);
246         if (ret) {
247                 wcn36xx_err("Failed to alloc DXE ctl blocks: %d\n", ret);
248                 goto out_free_dxe_pool;
249         }
250
251         wcn->hal_buf = kmalloc(WCN36XX_HAL_BUF_SIZE, GFP_KERNEL);
252         if (!wcn->hal_buf) {
253                 wcn36xx_err("Failed to allocate smd buf\n");
254                 ret = -ENOMEM;
255                 goto out_free_dxe_ctl;
256         }
257
258         ret = wcn36xx_smd_load_nv(wcn);
259         if (ret) {
260                 wcn36xx_err("Failed to push NV to chip\n");
261                 goto out_free_smd_buf;
262         }
263
264         ret = wcn36xx_smd_start(wcn);
265         if (ret) {
266                 wcn36xx_err("Failed to start chip\n");
267                 goto out_free_smd_buf;
268         }
269
270         if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
271                 ret = wcn36xx_smd_feature_caps_exchange(wcn);
272                 if (ret)
273                         wcn36xx_warn("Exchange feature caps failed\n");
274                 else
275                         wcn36xx_feat_caps_info(wcn);
276         }
277
278         /* DMA channel initialization */
279         ret = wcn36xx_dxe_init(wcn);
280         if (ret) {
281                 wcn36xx_err("DXE init failed\n");
282                 goto out_smd_stop;
283         }
284
285         wcn36xx_debugfs_init(wcn);
286
287         INIT_LIST_HEAD(&wcn->vif_list);
288         spin_lock_init(&wcn->dxe_lock);
289
290         return 0;
291
292 out_smd_stop:
293         wcn36xx_smd_stop(wcn);
294 out_free_smd_buf:
295         kfree(wcn->hal_buf);
296 out_free_dxe_pool:
297         wcn36xx_dxe_free_mem_pools(wcn);
298 out_free_dxe_ctl:
299         wcn36xx_dxe_free_ctl_blks(wcn);
300 out_smd_close:
301         wcn36xx_smd_close(wcn);
302 out_err:
303         return ret;
304 }
305
306 static void wcn36xx_stop(struct ieee80211_hw *hw)
307 {
308         struct wcn36xx *wcn = hw->priv;
309
310         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac stop\n");
311
312         wcn36xx_debugfs_exit(wcn);
313         wcn36xx_smd_stop(wcn);
314         wcn36xx_dxe_deinit(wcn);
315         wcn36xx_smd_close(wcn);
316
317         wcn36xx_dxe_free_mem_pools(wcn);
318         wcn36xx_dxe_free_ctl_blks(wcn);
319
320         kfree(wcn->hal_buf);
321 }
322
323 static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)
324 {
325         struct wcn36xx *wcn = hw->priv;
326         struct ieee80211_vif *vif = NULL;
327         struct wcn36xx_vif *tmp;
328
329         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac config changed 0x%08x\n", changed);
330
331         if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
332                 int ch = WCN36XX_HW_CHANNEL(wcn);
333                 wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n",
334                             ch);
335                 list_for_each_entry(tmp, &wcn->vif_list, list) {
336                         vif = container_of((void *)tmp,
337                                            struct ieee80211_vif,
338                                            drv_priv);
339                         wcn36xx_smd_switch_channel(wcn, vif, ch);
340                 }
341         }
342
343         return 0;
344 }
345
346 #define WCN36XX_SUPPORTED_FILTERS (0)
347
348 static void wcn36xx_configure_filter(struct ieee80211_hw *hw,
349                                      unsigned int changed,
350                                      unsigned int *total, u64 multicast)
351 {
352         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n");
353
354         *total &= WCN36XX_SUPPORTED_FILTERS;
355 }
356
357 static void wcn36xx_tx(struct ieee80211_hw *hw,
358                        struct ieee80211_tx_control *control,
359                        struct sk_buff *skb)
360 {
361         struct wcn36xx *wcn = hw->priv;
362         struct wcn36xx_sta *sta_priv = NULL;
363
364         if (control->sta)
365                 sta_priv = (struct wcn36xx_sta *)control->sta->drv_priv;
366
367         if (wcn36xx_start_tx(wcn, sta_priv, skb))
368                 ieee80211_free_txskb(wcn->hw, skb);
369 }
370
371 static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
372                            struct ieee80211_vif *vif,
373                            struct ieee80211_sta *sta,
374                            struct ieee80211_key_conf *key_conf)
375 {
376         struct wcn36xx *wcn = hw->priv;
377         struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
378         struct wcn36xx_sta *sta_priv = vif_priv->sta;
379         int ret = 0;
380         u8 key[WLAN_MAX_KEY_LEN];
381
382         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 set key\n");
383         wcn36xx_dbg(WCN36XX_DBG_MAC, "Key: cmd=0x%x algo:0x%x, id:%d, len:%d flags 0x%x\n",
384                     cmd, key_conf->cipher, key_conf->keyidx,
385                     key_conf->keylen, key_conf->flags);
386         wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "KEY: ",
387                          key_conf->key,
388                          key_conf->keylen);
389
390         switch (key_conf->cipher) {
391         case WLAN_CIPHER_SUITE_WEP40:
392                 vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40;
393                 break;
394         case WLAN_CIPHER_SUITE_WEP104:
395                 vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40;
396                 break;
397         case WLAN_CIPHER_SUITE_CCMP:
398                 vif_priv->encrypt_type = WCN36XX_HAL_ED_CCMP;
399                 break;
400         case WLAN_CIPHER_SUITE_TKIP:
401                 vif_priv->encrypt_type = WCN36XX_HAL_ED_TKIP;
402                 break;
403         default:
404                 wcn36xx_err("Unsupported key type 0x%x\n",
405                               key_conf->cipher);
406                 ret = -EOPNOTSUPP;
407                 goto out;
408         }
409
410         switch (cmd) {
411         case SET_KEY:
412                 if (WCN36XX_HAL_ED_TKIP == vif_priv->encrypt_type) {
413                         /*
414                          * Supplicant is sending key in the wrong order:
415                          * Temporal Key (16 b) - TX MIC (8 b) - RX MIC (8 b)
416                          * but HW expects it to be in the order as described in
417                          * IEEE 802.11 spec (see chapter 11.7) like this:
418                          * Temporal Key (16 b) - RX MIC (8 b) - TX MIC (8 b)
419                          */
420                         memcpy(key, key_conf->key, 16);
421                         memcpy(key + 16, key_conf->key + 24, 8);
422                         memcpy(key + 24, key_conf->key + 16, 8);
423                 } else {
424                         memcpy(key, key_conf->key, key_conf->keylen);
425                 }
426
427                 if (IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags) {
428                         sta_priv->is_data_encrypted = true;
429                         /* Reconfigure bss with encrypt_type */
430                         if (NL80211_IFTYPE_STATION == vif->type)
431                                 wcn36xx_smd_config_bss(wcn,
432                                                        vif,
433                                                        sta,
434                                                        sta->addr,
435                                                        true);
436
437                         wcn36xx_smd_set_stakey(wcn,
438                                 vif_priv->encrypt_type,
439                                 key_conf->keyidx,
440                                 key_conf->keylen,
441                                 key,
442                                 get_sta_index(vif, sta_priv));
443                 } else {
444                         wcn36xx_smd_set_bsskey(wcn,
445                                 vif_priv->encrypt_type,
446                                 key_conf->keyidx,
447                                 key_conf->keylen,
448                                 key);
449                         if ((WLAN_CIPHER_SUITE_WEP40 == key_conf->cipher) ||
450                             (WLAN_CIPHER_SUITE_WEP104 == key_conf->cipher)) {
451                                 sta_priv->is_data_encrypted = true;
452                                 wcn36xx_smd_set_stakey(wcn,
453                                         vif_priv->encrypt_type,
454                                         key_conf->keyidx,
455                                         key_conf->keylen,
456                                         key,
457                                         get_sta_index(vif, sta_priv));
458                         }
459                 }
460                 break;
461         case DISABLE_KEY:
462                 if (!(IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags)) {
463                         wcn36xx_smd_remove_bsskey(wcn,
464                                 vif_priv->encrypt_type,
465                                 key_conf->keyidx);
466                 } else {
467                         sta_priv->is_data_encrypted = false;
468                         /* do not remove key if disassociated */
469                         if (sta_priv->aid)
470                                 wcn36xx_smd_remove_stakey(wcn,
471                                         vif_priv->encrypt_type,
472                                         key_conf->keyidx,
473                                         get_sta_index(vif, sta_priv));
474                 }
475                 break;
476         default:
477                 wcn36xx_err("Unsupported key cmd 0x%x\n", cmd);
478                 ret = -EOPNOTSUPP;
479                 goto out;
480         }
481
482 out:
483         return ret;
484 }
485
486 static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw,
487                                   struct ieee80211_vif *vif,
488                                   const u8 *mac_addr)
489 {
490         struct wcn36xx *wcn = hw->priv;
491
492         wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN);
493         wcn36xx_smd_start_scan(wcn);
494 }
495
496 static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw,
497                                      struct ieee80211_vif *vif)
498 {
499         struct wcn36xx *wcn = hw->priv;
500
501         wcn36xx_smd_end_scan(wcn);
502         wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN);
503 }
504
505 static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
506                                          enum ieee80211_band band)
507 {
508         int i, size;
509         u16 *rates_table;
510         struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
511         u32 rates = sta->supp_rates[band];
512
513         memset(&sta_priv->supported_rates, 0,
514                 sizeof(sta_priv->supported_rates));
515         sta_priv->supported_rates.op_rate_mode = STA_11n;
516
517         size = ARRAY_SIZE(sta_priv->supported_rates.dsss_rates);
518         rates_table = sta_priv->supported_rates.dsss_rates;
519         if (band == IEEE80211_BAND_2GHZ) {
520                 for (i = 0; i < size; i++) {
521                         if (rates & 0x01) {
522                                 rates_table[i] = wcn_2ghz_rates[i].hw_value;
523                                 rates = rates >> 1;
524                         }
525                 }
526         }
527
528         size = ARRAY_SIZE(sta_priv->supported_rates.ofdm_rates);
529         rates_table = sta_priv->supported_rates.ofdm_rates;
530         for (i = 0; i < size; i++) {
531                 if (rates & 0x01) {
532                         rates_table[i] = wcn_5ghz_rates[i].hw_value;
533                         rates = rates >> 1;
534                 }
535         }
536
537         if (sta->ht_cap.ht_supported) {
538                 BUILD_BUG_ON(sizeof(sta->ht_cap.mcs.rx_mask) >
539                         sizeof(sta_priv->supported_rates.supported_mcs_set));
540                 memcpy(sta_priv->supported_rates.supported_mcs_set,
541                        sta->ht_cap.mcs.rx_mask,
542                        sizeof(sta->ht_cap.mcs.rx_mask));
543         }
544 }
545 void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates)
546 {
547         u16 ofdm_rates[WCN36XX_HAL_NUM_OFDM_RATES] = {
548                 HW_RATE_INDEX_6MBPS,
549                 HW_RATE_INDEX_9MBPS,
550                 HW_RATE_INDEX_12MBPS,
551                 HW_RATE_INDEX_18MBPS,
552                 HW_RATE_INDEX_24MBPS,
553                 HW_RATE_INDEX_36MBPS,
554                 HW_RATE_INDEX_48MBPS,
555                 HW_RATE_INDEX_54MBPS
556         };
557         u16 dsss_rates[WCN36XX_HAL_NUM_DSSS_RATES] = {
558                 HW_RATE_INDEX_1MBPS,
559                 HW_RATE_INDEX_2MBPS,
560                 HW_RATE_INDEX_5_5MBPS,
561                 HW_RATE_INDEX_11MBPS
562         };
563
564         rates->op_rate_mode = STA_11n;
565         memcpy(rates->dsss_rates, dsss_rates,
566                 sizeof(*dsss_rates) * WCN36XX_HAL_NUM_DSSS_RATES);
567         memcpy(rates->ofdm_rates, ofdm_rates,
568                 sizeof(*ofdm_rates) * WCN36XX_HAL_NUM_OFDM_RATES);
569         rates->supported_mcs_set[0] = 0xFF;
570 }
571 static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
572                                      struct ieee80211_vif *vif,
573                                      struct ieee80211_bss_conf *bss_conf,
574                                      u32 changed)
575 {
576         struct wcn36xx *wcn = hw->priv;
577         struct sk_buff *skb = NULL;
578         u16 tim_off, tim_len;
579         enum wcn36xx_hal_link_state link_state;
580         struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
581
582         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%08x\n",
583                     vif, changed);
584
585         if (changed & BSS_CHANGED_BEACON_INFO) {
586                 wcn36xx_dbg(WCN36XX_DBG_MAC,
587                             "mac bss changed dtim period %d\n",
588                             bss_conf->dtim_period);
589
590                 vif_priv->dtim_period = bss_conf->dtim_period;
591         }
592
593         if (changed & BSS_CHANGED_PS) {
594                 wcn36xx_dbg(WCN36XX_DBG_MAC,
595                             "mac bss PS set %d\n",
596                             bss_conf->ps);
597                 if (bss_conf->ps) {
598                         wcn36xx_pmc_enter_bmps_state(wcn, vif);
599                 } else {
600                         wcn36xx_pmc_exit_bmps_state(wcn, vif);
601                 }
602         }
603
604         if (changed & BSS_CHANGED_BSSID) {
605                 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed_bssid %pM\n",
606                             bss_conf->bssid);
607
608                 if (!is_zero_ether_addr(bss_conf->bssid)) {
609                         vif_priv->is_joining = true;
610                         vif_priv->bss_index = 0xff;
611                         wcn36xx_smd_join(wcn, bss_conf->bssid,
612                                          vif->addr, WCN36XX_HW_CHANNEL(wcn));
613                         wcn36xx_smd_config_bss(wcn, vif, NULL,
614                                                bss_conf->bssid, false);
615                 } else {
616                         vif_priv->is_joining = false;
617                         wcn36xx_smd_delete_bss(wcn, vif);
618                 }
619         }
620
621         if (changed & BSS_CHANGED_SSID) {
622                 wcn36xx_dbg(WCN36XX_DBG_MAC,
623                             "mac bss changed ssid\n");
624                 wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "ssid ",
625                                  bss_conf->ssid, bss_conf->ssid_len);
626
627                 vif_priv->ssid.length = bss_conf->ssid_len;
628                 memcpy(&vif_priv->ssid.ssid,
629                        bss_conf->ssid,
630                        bss_conf->ssid_len);
631         }
632
633         if (changed & BSS_CHANGED_ASSOC) {
634                 vif_priv->is_joining = false;
635                 if (bss_conf->assoc) {
636                         struct ieee80211_sta *sta;
637                         struct wcn36xx_sta *sta_priv;
638
639                         wcn36xx_dbg(WCN36XX_DBG_MAC,
640                                     "mac assoc bss %pM vif %pM AID=%d\n",
641                                      bss_conf->bssid,
642                                      vif->addr,
643                                      bss_conf->aid);
644
645                         rcu_read_lock();
646                         sta = ieee80211_find_sta(vif, bss_conf->bssid);
647                         if (!sta) {
648                                 wcn36xx_err("sta %pM is not found\n",
649                                               bss_conf->bssid);
650                                 rcu_read_unlock();
651                                 goto out;
652                         }
653                         sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
654
655                         wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn));
656
657                         wcn36xx_smd_set_link_st(wcn, bss_conf->bssid,
658                                 vif->addr,
659                                 WCN36XX_HAL_LINK_POSTASSOC_STATE);
660                         wcn36xx_smd_config_bss(wcn, vif, sta,
661                                                bss_conf->bssid,
662                                                true);
663                         sta_priv->aid = bss_conf->aid;
664                         /*
665                          * config_sta must be called from  because this is the
666                          * place where AID is available.
667                          */
668                         wcn36xx_smd_config_sta(wcn, vif, sta);
669                         rcu_read_unlock();
670                 } else {
671                         wcn36xx_dbg(WCN36XX_DBG_MAC,
672                                     "disassociated bss %pM vif %pM AID=%d\n",
673                                     bss_conf->bssid,
674                                     vif->addr,
675                                     bss_conf->aid);
676                         wcn36xx_smd_set_link_st(wcn,
677                                                 bss_conf->bssid,
678                                                 vif->addr,
679                                                 WCN36XX_HAL_LINK_IDLE_STATE);
680                 }
681         }
682
683         if (changed & BSS_CHANGED_AP_PROBE_RESP) {
684                 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed ap probe resp\n");
685                 skb = ieee80211_proberesp_get(hw, vif);
686                 if (!skb) {
687                         wcn36xx_err("failed to alloc probereq skb\n");
688                         goto out;
689                 }
690
691                 wcn36xx_smd_update_proberesp_tmpl(wcn, vif, skb);
692                 dev_kfree_skb(skb);
693         }
694
695         if (changed & BSS_CHANGED_BEACON_ENABLED ||
696             changed & BSS_CHANGED_BEACON) {
697                 wcn36xx_dbg(WCN36XX_DBG_MAC,
698                             "mac bss changed beacon enabled %d\n",
699                             bss_conf->enable_beacon);
700
701                 if (bss_conf->enable_beacon) {
702                         vif_priv->dtim_period = bss_conf->dtim_period;
703                         vif_priv->bss_index = 0xff;
704                         wcn36xx_smd_config_bss(wcn, vif, NULL,
705                                                vif->addr, false);
706                         skb = ieee80211_beacon_get_tim(hw, vif, &tim_off,
707                                                        &tim_len);
708                         if (!skb) {
709                                 wcn36xx_err("failed to alloc beacon skb\n");
710                                 goto out;
711                         }
712                         wcn36xx_smd_send_beacon(wcn, vif, skb, tim_off, 0);
713                         dev_kfree_skb(skb);
714
715                         if (vif->type == NL80211_IFTYPE_ADHOC ||
716                             vif->type == NL80211_IFTYPE_MESH_POINT)
717                                 link_state = WCN36XX_HAL_LINK_IBSS_STATE;
718                         else
719                                 link_state = WCN36XX_HAL_LINK_AP_STATE;
720
721                         wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,
722                                                 link_state);
723                 } else {
724                         wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,
725                                                 WCN36XX_HAL_LINK_IDLE_STATE);
726                         wcn36xx_smd_delete_bss(wcn, vif);
727                 }
728         }
729 out:
730         return;
731 }
732
733 /* this is required when using IEEE80211_HW_HAS_RATE_CONTROL */
734 static int wcn36xx_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
735 {
736         struct wcn36xx *wcn = hw->priv;
737         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac set RTS threshold %d\n", value);
738
739         wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_RTS_THRESHOLD, value);
740         return 0;
741 }
742
743 static void wcn36xx_remove_interface(struct ieee80211_hw *hw,
744                                      struct ieee80211_vif *vif)
745 {
746         struct wcn36xx *wcn = hw->priv;
747         struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
748         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac remove interface vif %p\n", vif);
749
750         list_del(&vif_priv->list);
751         wcn36xx_smd_delete_sta_self(wcn, vif->addr);
752 }
753
754 static int wcn36xx_add_interface(struct ieee80211_hw *hw,
755                                  struct ieee80211_vif *vif)
756 {
757         struct wcn36xx *wcn = hw->priv;
758         struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
759
760         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac add interface vif %p type %d\n",
761                     vif, vif->type);
762
763         if (!(NL80211_IFTYPE_STATION == vif->type ||
764               NL80211_IFTYPE_AP == vif->type ||
765               NL80211_IFTYPE_ADHOC == vif->type ||
766               NL80211_IFTYPE_MESH_POINT == vif->type)) {
767                 wcn36xx_warn("Unsupported interface type requested: %d\n",
768                              vif->type);
769                 return -EOPNOTSUPP;
770         }
771
772         list_add(&vif_priv->list, &wcn->vif_list);
773         wcn36xx_smd_add_sta_self(wcn, vif);
774
775         return 0;
776 }
777
778 static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
779                            struct ieee80211_sta *sta)
780 {
781         struct wcn36xx *wcn = hw->priv;
782         struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
783         struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
784         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n",
785                     vif, sta->addr);
786
787         spin_lock_init(&sta_priv->ampdu_lock);
788         vif_priv->sta = sta_priv;
789         sta_priv->vif = vif_priv;
790         /*
791          * For STA mode HW will be configured on BSS_CHANGED_ASSOC because
792          * at this stage AID is not available yet.
793          */
794         if (NL80211_IFTYPE_STATION != vif->type) {
795                 wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn));
796                 sta_priv->aid = sta->aid;
797                 wcn36xx_smd_config_sta(wcn, vif, sta);
798         }
799         return 0;
800 }
801
802 static int wcn36xx_sta_remove(struct ieee80211_hw *hw,
803                               struct ieee80211_vif *vif,
804                               struct ieee80211_sta *sta)
805 {
806         struct wcn36xx *wcn = hw->priv;
807         struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
808         struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
809
810         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta remove vif %p sta %pM index %d\n",
811                     vif, sta->addr, sta_priv->sta_index);
812
813         wcn36xx_smd_delete_sta(wcn, sta_priv->sta_index);
814         vif_priv->sta = NULL;
815         sta_priv->vif = NULL;
816         return 0;
817 }
818
819 #ifdef CONFIG_PM
820
821 static int wcn36xx_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow)
822 {
823         struct wcn36xx *wcn = hw->priv;
824
825         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac suspend\n");
826
827         flush_workqueue(wcn->hal_ind_wq);
828         wcn36xx_smd_set_power_params(wcn, true);
829         return 0;
830 }
831
832 static int wcn36xx_resume(struct ieee80211_hw *hw)
833 {
834         struct wcn36xx *wcn = hw->priv;
835
836         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac resume\n");
837
838         flush_workqueue(wcn->hal_ind_wq);
839         wcn36xx_smd_set_power_params(wcn, false);
840         return 0;
841 }
842
843 #endif
844
845 static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
846                     struct ieee80211_vif *vif,
847                     enum ieee80211_ampdu_mlme_action action,
848                     struct ieee80211_sta *sta, u16 tid, u16 *ssn,
849                     u8 buf_size, bool amsdu)
850 {
851         struct wcn36xx *wcn = hw->priv;
852         struct wcn36xx_sta *sta_priv = NULL;
853
854         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
855                     action, tid);
856
857         sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
858
859         switch (action) {
860         case IEEE80211_AMPDU_RX_START:
861                 sta_priv->tid = tid;
862                 wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0,
863                         get_sta_index(vif, sta_priv));
864                 wcn36xx_smd_add_ba(wcn);
865                 wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv));
866                 break;
867         case IEEE80211_AMPDU_RX_STOP:
868                 wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv));
869                 break;
870         case IEEE80211_AMPDU_TX_START:
871                 spin_lock_bh(&sta_priv->ampdu_lock);
872                 sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
873                 spin_unlock_bh(&sta_priv->ampdu_lock);
874
875                 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
876                 break;
877         case IEEE80211_AMPDU_TX_OPERATIONAL:
878                 spin_lock_bh(&sta_priv->ampdu_lock);
879                 sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL;
880                 spin_unlock_bh(&sta_priv->ampdu_lock);
881
882                 wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1,
883                         get_sta_index(vif, sta_priv));
884                 break;
885         case IEEE80211_AMPDU_TX_STOP_FLUSH:
886         case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
887         case IEEE80211_AMPDU_TX_STOP_CONT:
888                 spin_lock_bh(&sta_priv->ampdu_lock);
889                 sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_NONE;
890                 spin_unlock_bh(&sta_priv->ampdu_lock);
891
892                 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
893                 break;
894         default:
895                 wcn36xx_err("Unknown AMPDU action\n");
896         }
897
898         return 0;
899 }
900
901 static const struct ieee80211_ops wcn36xx_ops = {
902         .start                  = wcn36xx_start,
903         .stop                   = wcn36xx_stop,
904         .add_interface          = wcn36xx_add_interface,
905         .remove_interface       = wcn36xx_remove_interface,
906 #ifdef CONFIG_PM
907         .suspend                = wcn36xx_suspend,
908         .resume                 = wcn36xx_resume,
909 #endif
910         .config                 = wcn36xx_config,
911         .configure_filter       = wcn36xx_configure_filter,
912         .tx                     = wcn36xx_tx,
913         .set_key                = wcn36xx_set_key,
914         .sw_scan_start          = wcn36xx_sw_scan_start,
915         .sw_scan_complete       = wcn36xx_sw_scan_complete,
916         .bss_info_changed       = wcn36xx_bss_info_changed,
917         .set_rts_threshold      = wcn36xx_set_rts_threshold,
918         .sta_add                = wcn36xx_sta_add,
919         .sta_remove             = wcn36xx_sta_remove,
920         .ampdu_action           = wcn36xx_ampdu_action,
921 };
922
923 static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
924 {
925         int ret = 0;
926
927         static const u32 cipher_suites[] = {
928                 WLAN_CIPHER_SUITE_WEP40,
929                 WLAN_CIPHER_SUITE_WEP104,
930                 WLAN_CIPHER_SUITE_TKIP,
931                 WLAN_CIPHER_SUITE_CCMP,
932         };
933
934         ieee80211_hw_set(wcn->hw, TIMING_BEACON_ONLY);
935         ieee80211_hw_set(wcn->hw, AMPDU_AGGREGATION);
936         ieee80211_hw_set(wcn->hw, CONNECTION_MONITOR);
937         ieee80211_hw_set(wcn->hw, SUPPORTS_PS);
938         ieee80211_hw_set(wcn->hw, SIGNAL_DBM);
939         ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL);
940
941         /* 3620 powersaving currently unstable */
942         if (wcn->chip_version == WCN36XX_CHIP_3620)
943                 wcn->hw->flags &= ~IEEE80211_HW_SUPPORTS_PS;
944
945         wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
946                 BIT(NL80211_IFTYPE_AP) |
947                 BIT(NL80211_IFTYPE_ADHOC) |
948                 BIT(NL80211_IFTYPE_MESH_POINT);
949
950         wcn->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wcn_band_2ghz;
951         wcn->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wcn_band_5ghz;
952
953         wcn->hw->wiphy->cipher_suites = cipher_suites;
954         wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
955
956         wcn->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
957
958 #ifdef CONFIG_PM
959         wcn->hw->wiphy->wowlan = &wowlan_support;
960 #endif
961
962         wcn->hw->max_listen_interval = 200;
963
964         wcn->hw->queues = 4;
965
966         SET_IEEE80211_DEV(wcn->hw, wcn->dev);
967
968         wcn->hw->sta_data_size = sizeof(struct wcn36xx_sta);
969         wcn->hw->vif_data_size = sizeof(struct wcn36xx_vif);
970
971         return ret;
972 }
973
974 static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
975                                           struct platform_device *pdev)
976 {
977         struct resource *res;
978         /* Set TX IRQ */
979         res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
980                                            "wcnss_wlantx_irq");
981         if (!res) {
982                 wcn36xx_err("failed to get tx_irq\n");
983                 return -ENOENT;
984         }
985         wcn->tx_irq = res->start;
986
987         /* Set RX IRQ */
988         res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
989                                            "wcnss_wlanrx_irq");
990         if (!res) {
991                 wcn36xx_err("failed to get rx_irq\n");
992                 return -ENOENT;
993         }
994         wcn->rx_irq = res->start;
995
996         /* Map the memory */
997         res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
998                                                  "wcnss_mmio");
999         if (!res) {
1000                 wcn36xx_err("failed to get mmio\n");
1001                 return -ENOENT;
1002         }
1003         wcn->mmio = ioremap(res->start, resource_size(res));
1004         if (!wcn->mmio) {
1005                 wcn36xx_err("failed to map io memory\n");
1006                 return -ENOMEM;
1007         }
1008         return 0;
1009 }
1010
1011 static int wcn36xx_probe(struct platform_device *pdev)
1012 {
1013         struct ieee80211_hw *hw;
1014         struct wcn36xx *wcn;
1015         int ret;
1016         u8 addr[ETH_ALEN];
1017
1018         wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
1019
1020         hw = ieee80211_alloc_hw(sizeof(struct wcn36xx), &wcn36xx_ops);
1021         if (!hw) {
1022                 wcn36xx_err("failed to alloc hw\n");
1023                 ret = -ENOMEM;
1024                 goto out_err;
1025         }
1026         platform_set_drvdata(pdev, hw);
1027         wcn = hw->priv;
1028         wcn->hw = hw;
1029         wcn->dev = &pdev->dev;
1030         wcn->ctrl_ops = pdev->dev.platform_data;
1031         if (!wcn->ctrl_ops->get_chip_type) {
1032                 dev_err(&pdev->dev, "Missing ops->get_chip_type\n");
1033                 return -EINVAL;
1034         }
1035         wcn->chip_version = wcn->ctrl_ops->get_chip_type();
1036
1037         mutex_init(&wcn->hal_mutex);
1038
1039         if (!wcn->ctrl_ops->get_hw_mac(addr)) {
1040                 wcn36xx_info("mac address: %pM\n", addr);
1041                 SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
1042         }
1043
1044         ret = wcn36xx_platform_get_resources(wcn, pdev);
1045         if (ret)
1046                 goto out_wq;
1047
1048         wcn36xx_init_ieee80211(wcn);
1049         ret = ieee80211_register_hw(wcn->hw);
1050         if (ret)
1051                 goto out_unmap;
1052
1053         return 0;
1054
1055 out_unmap:
1056         iounmap(wcn->mmio);
1057 out_wq:
1058         ieee80211_free_hw(hw);
1059 out_err:
1060         return ret;
1061 }
1062 static int wcn36xx_remove(struct platform_device *pdev)
1063 {
1064         struct ieee80211_hw *hw = platform_get_drvdata(pdev);
1065         struct wcn36xx *wcn = hw->priv;
1066         wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");
1067
1068         release_firmware(wcn->nv);
1069         mutex_destroy(&wcn->hal_mutex);
1070
1071         ieee80211_unregister_hw(hw);
1072         iounmap(wcn->mmio);
1073         ieee80211_free_hw(hw);
1074
1075         return 0;
1076 }
1077 static const struct platform_device_id wcn36xx_platform_id_table[] = {
1078         {
1079                 .name = "wcn36xx",
1080                 .driver_data = 0
1081         },
1082         {}
1083 };
1084 MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table);
1085
1086 static struct platform_driver wcn36xx_driver = {
1087         .probe      = wcn36xx_probe,
1088         .remove     = wcn36xx_remove,
1089         .driver         = {
1090                 .name   = "wcn36xx",
1091         },
1092         .id_table    = wcn36xx_platform_id_table,
1093 };
1094
1095 static int __init wcn36xx_init(void)
1096 {
1097         platform_driver_register(&wcn36xx_driver);
1098         return 0;
1099 }
1100 module_init(wcn36xx_init);
1101
1102 static void __exit wcn36xx_exit(void)
1103 {
1104         platform_driver_unregister(&wcn36xx_driver);
1105 }
1106 module_exit(wcn36xx_exit);
1107
1108 MODULE_LICENSE("Dual BSD/GPL");
1109 MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
1110 MODULE_FIRMWARE(WLAN_NV_FILE);