]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/wireless/ath/wcn36xx/main.c
7d0dd76395b6563030fab9b61a35744c76e0951f
[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         "WLAN_ROAM_SCAN_OFFLOAD",       /* 23 */
206         "SPECULATIVE_PS_POLL",          /* 24 */
207         "SCAN_SCH",                     /* 25 */
208         "IBSS_HEARTBEAT_OFFLOAD",       /* 26 */
209         "WLAN_SCAN_OFFLOAD",            /* 27 */
210         "WLAN_PERIODIC_TX_PTRN",        /* 28 */
211         "ADVANCE_TDLS",                 /* 29 */
212         "BATCH_SCAN",                   /* 30 */
213         "FW_IN_TX_PATH",                /* 31 */
214         "EXTENDED_NSOFFLOAD_SLOT",      /* 32 */
215         "CH_SWITCH_V1",                 /* 33 */
216         "HT40_OBSS_SCAN",               /* 34 */
217         "UPDATE_CHANNEL_LIST",          /* 35 */
218
219 };
220
221 static const char *wcn36xx_get_cap_name(enum place_holder_in_cap_bitmap x)
222 {
223         if (x >= ARRAY_SIZE(wcn36xx_caps_names))
224                 return "UNKNOWN";
225         return wcn36xx_caps_names[x];
226 }
227
228 static void wcn36xx_feat_caps_info(struct wcn36xx *wcn)
229 {
230         int i;
231
232         for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) {
233                 if (get_feat_caps(wcn->fw_feat_caps, i))
234                         wcn36xx_info("FW Cap %s\n", wcn36xx_get_cap_name(i));
235         }
236 }
237
238 static int wcn36xx_start(struct ieee80211_hw *hw)
239 {
240         struct wcn36xx *wcn = hw->priv;
241         int ret;
242
243         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac start\n");
244
245         /* SMD initialization */
246         ret = wcn36xx_smd_open(wcn);
247         if (ret) {
248                 wcn36xx_err("Failed to open smd channel: %d\n", ret);
249                 goto out_err;
250         }
251
252         /* Allocate memory pools for Mgmt BD headers and Data BD headers */
253         ret = wcn36xx_dxe_allocate_mem_pools(wcn);
254         if (ret) {
255                 wcn36xx_err("Failed to alloc DXE mempool: %d\n", ret);
256                 goto out_smd_close;
257         }
258
259         ret = wcn36xx_dxe_alloc_ctl_blks(wcn);
260         if (ret) {
261                 wcn36xx_err("Failed to alloc DXE ctl blocks: %d\n", ret);
262                 goto out_free_dxe_pool;
263         }
264
265         wcn->hal_buf = kmalloc(WCN36XX_HAL_BUF_SIZE, GFP_KERNEL);
266         if (!wcn->hal_buf) {
267                 wcn36xx_err("Failed to allocate smd buf\n");
268                 ret = -ENOMEM;
269                 goto out_free_dxe_ctl;
270         }
271
272         ret = wcn36xx_smd_load_nv(wcn);
273         if (ret) {
274                 wcn36xx_err("Failed to push NV to chip\n");
275                 goto out_free_smd_buf;
276         }
277
278         ret = wcn36xx_smd_start(wcn);
279         if (ret) {
280                 wcn36xx_err("Failed to start chip\n");
281                 goto out_free_smd_buf;
282         }
283
284         if (!wcn36xx_is_fw_version(wcn, 1, 2, 2, 24)) {
285                 ret = wcn36xx_smd_feature_caps_exchange(wcn);
286                 if (ret)
287                         wcn36xx_warn("Exchange feature caps failed\n");
288                 else
289                         wcn36xx_feat_caps_info(wcn);
290         }
291
292         wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_ENABLE_MC_ADDR_LIST, 1);
293
294         /* DMA channel initialization */
295         ret = wcn36xx_dxe_init(wcn);
296         if (ret) {
297                 wcn36xx_err("DXE init failed\n");
298                 goto out_smd_stop;
299         }
300
301         wcn36xx_debugfs_init(wcn);
302
303         INIT_LIST_HEAD(&wcn->vif_list);
304         spin_lock_init(&wcn->dxe_lock);
305
306         return 0;
307
308 out_smd_stop:
309         wcn36xx_smd_stop(wcn);
310 out_free_smd_buf:
311         kfree(wcn->hal_buf);
312 out_free_dxe_pool:
313         wcn36xx_dxe_free_mem_pools(wcn);
314 out_free_dxe_ctl:
315         wcn36xx_dxe_free_ctl_blks(wcn);
316 out_smd_close:
317         wcn36xx_smd_close(wcn);
318 out_err:
319         return ret;
320 }
321
322 static void wcn36xx_stop(struct ieee80211_hw *hw)
323 {
324         struct wcn36xx *wcn = hw->priv;
325
326         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac stop\n");
327
328         wcn36xx_debugfs_exit(wcn);
329         wcn36xx_smd_stop(wcn);
330         wcn36xx_dxe_deinit(wcn);
331         wcn36xx_smd_close(wcn);
332
333         wcn36xx_dxe_free_mem_pools(wcn);
334         wcn36xx_dxe_free_ctl_blks(wcn);
335
336         kfree(wcn->hal_buf);
337 }
338
339 static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)
340 {
341         struct wcn36xx *wcn = hw->priv;
342         struct ieee80211_vif *vif = NULL;
343         struct wcn36xx_vif *tmp;
344
345         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac config changed 0x%08x\n", changed);
346
347         if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
348                 int ch = WCN36XX_HW_CHANNEL(wcn);
349                 wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n",
350                             ch);
351                 list_for_each_entry(tmp, &wcn->vif_list, list) {
352                         vif = wcn36xx_priv_to_vif(tmp);
353                         wcn36xx_smd_switch_channel(wcn, vif, ch);
354                 }
355         }
356
357         return 0;
358 }
359
360 #define WCN36XX_SUPPORTED_FILTERS (FIF_ALLMULTI)
361
362 static void wcn36xx_configure_filter(struct ieee80211_hw *hw,
363                                      unsigned int changed,
364                                      unsigned int *total, u64 multicast)
365 {
366         struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp;
367         struct wcn36xx *wcn = hw->priv;
368         struct wcn36xx_vif *tmp;
369         struct ieee80211_vif *vif = NULL;
370
371         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n");
372
373         *total &= WCN36XX_SUPPORTED_FILTERS;
374
375         fp = (void *)(unsigned long)multicast;
376         list_for_each_entry(tmp, &wcn->vif_list, list) {
377                 vif = wcn36xx_priv_to_vif(tmp);
378
379                 /* FW handles MC filtering only when connected as STA */
380                 if (*total & FIF_ALLMULTI)
381                         wcn36xx_smd_set_mc_list(wcn, vif, NULL);
382                 else if (NL80211_IFTYPE_STATION == vif->type && tmp->sta_assoc)
383                         wcn36xx_smd_set_mc_list(wcn, vif, fp);
384         }
385         kfree(fp);
386 }
387
388 static u64 wcn36xx_prepare_multicast(struct ieee80211_hw *hw,
389                                      struct netdev_hw_addr_list *mc_list)
390 {
391         struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp;
392         struct netdev_hw_addr *ha;
393
394         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac prepare multicast list\n");
395         fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
396         if (!fp) {
397                 wcn36xx_err("Out of memory setting filters.\n");
398                 return 0;
399         }
400
401         fp->mc_addr_count = 0;
402         /* update multicast filtering parameters */
403         if (netdev_hw_addr_list_count(mc_list) <=
404             WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS) {
405                 netdev_hw_addr_list_for_each(ha, mc_list) {
406                         memcpy(fp->mc_addr[fp->mc_addr_count],
407                                         ha->addr, ETH_ALEN);
408                         fp->mc_addr_count++;
409                 }
410         }
411
412         return (u64)(unsigned long)fp;
413 }
414
415 static void wcn36xx_tx(struct ieee80211_hw *hw,
416                        struct ieee80211_tx_control *control,
417                        struct sk_buff *skb)
418 {
419         struct wcn36xx *wcn = hw->priv;
420         struct wcn36xx_sta *sta_priv = NULL;
421
422         if (control->sta)
423                 sta_priv = wcn36xx_sta_to_priv(control->sta);
424
425         if (wcn36xx_start_tx(wcn, sta_priv, skb))
426                 ieee80211_free_txskb(wcn->hw, skb);
427 }
428
429 static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
430                            struct ieee80211_vif *vif,
431                            struct ieee80211_sta *sta,
432                            struct ieee80211_key_conf *key_conf)
433 {
434         struct wcn36xx *wcn = hw->priv;
435         struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
436         struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
437         int ret = 0;
438         u8 key[WLAN_MAX_KEY_LEN];
439
440         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 set key\n");
441         wcn36xx_dbg(WCN36XX_DBG_MAC, "Key: cmd=0x%x algo:0x%x, id:%d, len:%d flags 0x%x\n",
442                     cmd, key_conf->cipher, key_conf->keyidx,
443                     key_conf->keylen, key_conf->flags);
444         wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "KEY: ",
445                          key_conf->key,
446                          key_conf->keylen);
447
448         switch (key_conf->cipher) {
449         case WLAN_CIPHER_SUITE_WEP40:
450                 vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40;
451                 break;
452         case WLAN_CIPHER_SUITE_WEP104:
453                 vif_priv->encrypt_type = WCN36XX_HAL_ED_WEP40;
454                 break;
455         case WLAN_CIPHER_SUITE_CCMP:
456                 vif_priv->encrypt_type = WCN36XX_HAL_ED_CCMP;
457                 break;
458         case WLAN_CIPHER_SUITE_TKIP:
459                 vif_priv->encrypt_type = WCN36XX_HAL_ED_TKIP;
460                 break;
461         default:
462                 wcn36xx_err("Unsupported key type 0x%x\n",
463                               key_conf->cipher);
464                 ret = -EOPNOTSUPP;
465                 goto out;
466         }
467
468         switch (cmd) {
469         case SET_KEY:
470                 if (WCN36XX_HAL_ED_TKIP == vif_priv->encrypt_type) {
471                         /*
472                          * Supplicant is sending key in the wrong order:
473                          * Temporal Key (16 b) - TX MIC (8 b) - RX MIC (8 b)
474                          * but HW expects it to be in the order as described in
475                          * IEEE 802.11 spec (see chapter 11.7) like this:
476                          * Temporal Key (16 b) - RX MIC (8 b) - TX MIC (8 b)
477                          */
478                         memcpy(key, key_conf->key, 16);
479                         memcpy(key + 16, key_conf->key + 24, 8);
480                         memcpy(key + 24, key_conf->key + 16, 8);
481                 } else {
482                         memcpy(key, key_conf->key, key_conf->keylen);
483                 }
484
485                 if (IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags) {
486                         sta_priv->is_data_encrypted = true;
487                         /* Reconfigure bss with encrypt_type */
488                         if (NL80211_IFTYPE_STATION == vif->type)
489                                 wcn36xx_smd_config_bss(wcn,
490                                                        vif,
491                                                        sta,
492                                                        sta->addr,
493                                                        true);
494
495                         wcn36xx_smd_set_stakey(wcn,
496                                 vif_priv->encrypt_type,
497                                 key_conf->keyidx,
498                                 key_conf->keylen,
499                                 key,
500                                 get_sta_index(vif, sta_priv));
501                 } else {
502                         wcn36xx_smd_set_bsskey(wcn,
503                                 vif_priv->encrypt_type,
504                                 key_conf->keyidx,
505                                 key_conf->keylen,
506                                 key);
507                         if ((WLAN_CIPHER_SUITE_WEP40 == key_conf->cipher) ||
508                             (WLAN_CIPHER_SUITE_WEP104 == key_conf->cipher)) {
509                                 sta_priv->is_data_encrypted = true;
510                                 wcn36xx_smd_set_stakey(wcn,
511                                         vif_priv->encrypt_type,
512                                         key_conf->keyidx,
513                                         key_conf->keylen,
514                                         key,
515                                         get_sta_index(vif, sta_priv));
516                         }
517                 }
518                 break;
519         case DISABLE_KEY:
520                 if (!(IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags)) {
521                         vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE;
522                         wcn36xx_smd_remove_bsskey(wcn,
523                                 vif_priv->encrypt_type,
524                                 key_conf->keyidx);
525                 } else {
526                         sta_priv->is_data_encrypted = false;
527                         /* do not remove key if disassociated */
528                         if (sta_priv->aid)
529                                 wcn36xx_smd_remove_stakey(wcn,
530                                         vif_priv->encrypt_type,
531                                         key_conf->keyidx,
532                                         get_sta_index(vif, sta_priv));
533                 }
534                 break;
535         default:
536                 wcn36xx_err("Unsupported key cmd 0x%x\n", cmd);
537                 ret = -EOPNOTSUPP;
538                 goto out;
539         }
540
541 out:
542         return ret;
543 }
544
545 static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw,
546                                   struct ieee80211_vif *vif,
547                                   const u8 *mac_addr)
548 {
549         struct wcn36xx *wcn = hw->priv;
550
551         wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN);
552         wcn36xx_smd_start_scan(wcn);
553 }
554
555 static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw,
556                                      struct ieee80211_vif *vif)
557 {
558         struct wcn36xx *wcn = hw->priv;
559
560         wcn36xx_smd_end_scan(wcn);
561         wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN);
562 }
563
564 static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
565                                          enum ieee80211_band band)
566 {
567         int i, size;
568         u16 *rates_table;
569         struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
570         u32 rates = sta->supp_rates[band];
571
572         memset(&sta_priv->supported_rates, 0,
573                 sizeof(sta_priv->supported_rates));
574         sta_priv->supported_rates.op_rate_mode = STA_11n;
575
576         size = ARRAY_SIZE(sta_priv->supported_rates.dsss_rates);
577         rates_table = sta_priv->supported_rates.dsss_rates;
578         if (band == IEEE80211_BAND_2GHZ) {
579                 for (i = 0; i < size; i++) {
580                         if (rates & 0x01) {
581                                 rates_table[i] = wcn_2ghz_rates[i].hw_value;
582                                 rates = rates >> 1;
583                         }
584                 }
585         }
586
587         size = ARRAY_SIZE(sta_priv->supported_rates.ofdm_rates);
588         rates_table = sta_priv->supported_rates.ofdm_rates;
589         for (i = 0; i < size; i++) {
590                 if (rates & 0x01) {
591                         rates_table[i] = wcn_5ghz_rates[i].hw_value;
592                         rates = rates >> 1;
593                 }
594         }
595
596         if (sta->ht_cap.ht_supported) {
597                 BUILD_BUG_ON(sizeof(sta->ht_cap.mcs.rx_mask) >
598                         sizeof(sta_priv->supported_rates.supported_mcs_set));
599                 memcpy(sta_priv->supported_rates.supported_mcs_set,
600                        sta->ht_cap.mcs.rx_mask,
601                        sizeof(sta->ht_cap.mcs.rx_mask));
602         }
603 }
604 void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates)
605 {
606         u16 ofdm_rates[WCN36XX_HAL_NUM_OFDM_RATES] = {
607                 HW_RATE_INDEX_6MBPS,
608                 HW_RATE_INDEX_9MBPS,
609                 HW_RATE_INDEX_12MBPS,
610                 HW_RATE_INDEX_18MBPS,
611                 HW_RATE_INDEX_24MBPS,
612                 HW_RATE_INDEX_36MBPS,
613                 HW_RATE_INDEX_48MBPS,
614                 HW_RATE_INDEX_54MBPS
615         };
616         u16 dsss_rates[WCN36XX_HAL_NUM_DSSS_RATES] = {
617                 HW_RATE_INDEX_1MBPS,
618                 HW_RATE_INDEX_2MBPS,
619                 HW_RATE_INDEX_5_5MBPS,
620                 HW_RATE_INDEX_11MBPS
621         };
622
623         rates->op_rate_mode = STA_11n;
624         memcpy(rates->dsss_rates, dsss_rates,
625                 sizeof(*dsss_rates) * WCN36XX_HAL_NUM_DSSS_RATES);
626         memcpy(rates->ofdm_rates, ofdm_rates,
627                 sizeof(*ofdm_rates) * WCN36XX_HAL_NUM_OFDM_RATES);
628         rates->supported_mcs_set[0] = 0xFF;
629 }
630 static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
631                                      struct ieee80211_vif *vif,
632                                      struct ieee80211_bss_conf *bss_conf,
633                                      u32 changed)
634 {
635         struct wcn36xx *wcn = hw->priv;
636         struct sk_buff *skb = NULL;
637         u16 tim_off, tim_len;
638         enum wcn36xx_hal_link_state link_state;
639         struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
640
641         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%08x\n",
642                     vif, changed);
643
644         if (changed & BSS_CHANGED_BEACON_INFO) {
645                 wcn36xx_dbg(WCN36XX_DBG_MAC,
646                             "mac bss changed dtim period %d\n",
647                             bss_conf->dtim_period);
648
649                 vif_priv->dtim_period = bss_conf->dtim_period;
650         }
651
652         if (changed & BSS_CHANGED_PS) {
653                 wcn36xx_dbg(WCN36XX_DBG_MAC,
654                             "mac bss PS set %d\n",
655                             bss_conf->ps);
656                 if (bss_conf->ps) {
657                         wcn36xx_pmc_enter_bmps_state(wcn, vif);
658                 } else {
659                         wcn36xx_pmc_exit_bmps_state(wcn, vif);
660                 }
661         }
662
663         if (changed & BSS_CHANGED_BSSID) {
664                 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed_bssid %pM\n",
665                             bss_conf->bssid);
666
667                 if (!is_zero_ether_addr(bss_conf->bssid)) {
668                         vif_priv->is_joining = true;
669                         vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX;
670                         wcn36xx_smd_join(wcn, bss_conf->bssid,
671                                          vif->addr, WCN36XX_HW_CHANNEL(wcn));
672                         wcn36xx_smd_config_bss(wcn, vif, NULL,
673                                                bss_conf->bssid, false);
674                 } else {
675                         vif_priv->is_joining = false;
676                         wcn36xx_smd_delete_bss(wcn, vif);
677                         vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE;
678                 }
679         }
680
681         if (changed & BSS_CHANGED_SSID) {
682                 wcn36xx_dbg(WCN36XX_DBG_MAC,
683                             "mac bss changed ssid\n");
684                 wcn36xx_dbg_dump(WCN36XX_DBG_MAC, "ssid ",
685                                  bss_conf->ssid, bss_conf->ssid_len);
686
687                 vif_priv->ssid.length = bss_conf->ssid_len;
688                 memcpy(&vif_priv->ssid.ssid,
689                        bss_conf->ssid,
690                        bss_conf->ssid_len);
691         }
692
693         if (changed & BSS_CHANGED_ASSOC) {
694                 vif_priv->is_joining = false;
695                 if (bss_conf->assoc) {
696                         struct ieee80211_sta *sta;
697                         struct wcn36xx_sta *sta_priv;
698
699                         wcn36xx_dbg(WCN36XX_DBG_MAC,
700                                     "mac assoc bss %pM vif %pM AID=%d\n",
701                                      bss_conf->bssid,
702                                      vif->addr,
703                                      bss_conf->aid);
704
705                         vif_priv->sta_assoc = true;
706                         rcu_read_lock();
707                         sta = ieee80211_find_sta(vif, bss_conf->bssid);
708                         if (!sta) {
709                                 wcn36xx_err("sta %pM is not found\n",
710                                               bss_conf->bssid);
711                                 rcu_read_unlock();
712                                 goto out;
713                         }
714                         sta_priv = wcn36xx_sta_to_priv(sta);
715
716                         wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn));
717
718                         wcn36xx_smd_set_link_st(wcn, bss_conf->bssid,
719                                 vif->addr,
720                                 WCN36XX_HAL_LINK_POSTASSOC_STATE);
721                         wcn36xx_smd_config_bss(wcn, vif, sta,
722                                                bss_conf->bssid,
723                                                true);
724                         sta_priv->aid = bss_conf->aid;
725                         /*
726                          * config_sta must be called from  because this is the
727                          * place where AID is available.
728                          */
729                         wcn36xx_smd_config_sta(wcn, vif, sta);
730                         rcu_read_unlock();
731                 } else {
732                         wcn36xx_dbg(WCN36XX_DBG_MAC,
733                                     "disassociated bss %pM vif %pM AID=%d\n",
734                                     bss_conf->bssid,
735                                     vif->addr,
736                                     bss_conf->aid);
737                         vif_priv->sta_assoc = false;
738                         wcn36xx_smd_set_link_st(wcn,
739                                                 bss_conf->bssid,
740                                                 vif->addr,
741                                                 WCN36XX_HAL_LINK_IDLE_STATE);
742                 }
743         }
744
745         if (changed & BSS_CHANGED_AP_PROBE_RESP) {
746                 wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss changed ap probe resp\n");
747                 skb = ieee80211_proberesp_get(hw, vif);
748                 if (!skb) {
749                         wcn36xx_err("failed to alloc probereq skb\n");
750                         goto out;
751                 }
752
753                 wcn36xx_smd_update_proberesp_tmpl(wcn, vif, skb);
754                 dev_kfree_skb(skb);
755         }
756
757         if (changed & BSS_CHANGED_BEACON_ENABLED ||
758             changed & BSS_CHANGED_BEACON) {
759                 wcn36xx_dbg(WCN36XX_DBG_MAC,
760                             "mac bss changed beacon enabled %d\n",
761                             bss_conf->enable_beacon);
762
763                 if (bss_conf->enable_beacon) {
764                         vif_priv->dtim_period = bss_conf->dtim_period;
765                         vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX;
766                         wcn36xx_smd_config_bss(wcn, vif, NULL,
767                                                vif->addr, false);
768                         skb = ieee80211_beacon_get_tim(hw, vif, &tim_off,
769                                                        &tim_len);
770                         if (!skb) {
771                                 wcn36xx_err("failed to alloc beacon skb\n");
772                                 goto out;
773                         }
774                         wcn36xx_smd_send_beacon(wcn, vif, skb, tim_off, 0);
775                         dev_kfree_skb(skb);
776
777                         if (vif->type == NL80211_IFTYPE_ADHOC ||
778                             vif->type == NL80211_IFTYPE_MESH_POINT)
779                                 link_state = WCN36XX_HAL_LINK_IBSS_STATE;
780                         else
781                                 link_state = WCN36XX_HAL_LINK_AP_STATE;
782
783                         wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,
784                                                 link_state);
785                 } else {
786                         wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,
787                                                 WCN36XX_HAL_LINK_IDLE_STATE);
788                         wcn36xx_smd_delete_bss(wcn, vif);
789                 }
790         }
791 out:
792         return;
793 }
794
795 /* this is required when using IEEE80211_HW_HAS_RATE_CONTROL */
796 static int wcn36xx_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
797 {
798         struct wcn36xx *wcn = hw->priv;
799         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac set RTS threshold %d\n", value);
800
801         wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_RTS_THRESHOLD, value);
802         return 0;
803 }
804
805 static void wcn36xx_remove_interface(struct ieee80211_hw *hw,
806                                      struct ieee80211_vif *vif)
807 {
808         struct wcn36xx *wcn = hw->priv;
809         struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
810         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac remove interface vif %p\n", vif);
811
812         list_del(&vif_priv->list);
813         wcn36xx_smd_delete_sta_self(wcn, vif->addr);
814 }
815
816 static int wcn36xx_add_interface(struct ieee80211_hw *hw,
817                                  struct ieee80211_vif *vif)
818 {
819         struct wcn36xx *wcn = hw->priv;
820         struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
821
822         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac add interface vif %p type %d\n",
823                     vif, vif->type);
824
825         if (!(NL80211_IFTYPE_STATION == vif->type ||
826               NL80211_IFTYPE_AP == vif->type ||
827               NL80211_IFTYPE_ADHOC == vif->type ||
828               NL80211_IFTYPE_MESH_POINT == vif->type)) {
829                 wcn36xx_warn("Unsupported interface type requested: %d\n",
830                              vif->type);
831                 return -EOPNOTSUPP;
832         }
833
834         list_add(&vif_priv->list, &wcn->vif_list);
835         wcn36xx_smd_add_sta_self(wcn, vif);
836
837         return 0;
838 }
839
840 static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
841                            struct ieee80211_sta *sta)
842 {
843         struct wcn36xx *wcn = hw->priv;
844         struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
845         struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
846         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n",
847                     vif, sta->addr);
848
849         spin_lock_init(&sta_priv->ampdu_lock);
850         sta_priv->vif = vif_priv;
851         /*
852          * For STA mode HW will be configured on BSS_CHANGED_ASSOC because
853          * at this stage AID is not available yet.
854          */
855         if (NL80211_IFTYPE_STATION != vif->type) {
856                 wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn));
857                 sta_priv->aid = sta->aid;
858                 wcn36xx_smd_config_sta(wcn, vif, sta);
859         }
860         return 0;
861 }
862
863 static int wcn36xx_sta_remove(struct ieee80211_hw *hw,
864                               struct ieee80211_vif *vif,
865                               struct ieee80211_sta *sta)
866 {
867         struct wcn36xx *wcn = hw->priv;
868         struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
869
870         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta remove vif %p sta %pM index %d\n",
871                     vif, sta->addr, sta_priv->sta_index);
872
873         wcn36xx_smd_delete_sta(wcn, sta_priv->sta_index);
874         sta_priv->vif = NULL;
875         return 0;
876 }
877
878 #ifdef CONFIG_PM
879
880 static int wcn36xx_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wow)
881 {
882         struct wcn36xx *wcn = hw->priv;
883
884         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac suspend\n");
885
886         flush_workqueue(wcn->hal_ind_wq);
887         wcn36xx_smd_set_power_params(wcn, true);
888         return 0;
889 }
890
891 static int wcn36xx_resume(struct ieee80211_hw *hw)
892 {
893         struct wcn36xx *wcn = hw->priv;
894
895         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac resume\n");
896
897         flush_workqueue(wcn->hal_ind_wq);
898         wcn36xx_smd_set_power_params(wcn, false);
899         return 0;
900 }
901
902 #endif
903
904 static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
905                     struct ieee80211_vif *vif,
906                     enum ieee80211_ampdu_mlme_action action,
907                     struct ieee80211_sta *sta, u16 tid, u16 *ssn,
908                     u8 buf_size, bool amsdu)
909 {
910         struct wcn36xx *wcn = hw->priv;
911         struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
912
913         wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
914                     action, tid);
915
916         switch (action) {
917         case IEEE80211_AMPDU_RX_START:
918                 sta_priv->tid = tid;
919                 wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0,
920                         get_sta_index(vif, sta_priv));
921                 wcn36xx_smd_add_ba(wcn);
922                 wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv));
923                 break;
924         case IEEE80211_AMPDU_RX_STOP:
925                 wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv));
926                 break;
927         case IEEE80211_AMPDU_TX_START:
928                 spin_lock_bh(&sta_priv->ampdu_lock);
929                 sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
930                 spin_unlock_bh(&sta_priv->ampdu_lock);
931
932                 ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
933                 break;
934         case IEEE80211_AMPDU_TX_OPERATIONAL:
935                 spin_lock_bh(&sta_priv->ampdu_lock);
936                 sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL;
937                 spin_unlock_bh(&sta_priv->ampdu_lock);
938
939                 wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1,
940                         get_sta_index(vif, sta_priv));
941                 break;
942         case IEEE80211_AMPDU_TX_STOP_FLUSH:
943         case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
944         case IEEE80211_AMPDU_TX_STOP_CONT:
945                 spin_lock_bh(&sta_priv->ampdu_lock);
946                 sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_NONE;
947                 spin_unlock_bh(&sta_priv->ampdu_lock);
948
949                 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
950                 break;
951         default:
952                 wcn36xx_err("Unknown AMPDU action\n");
953         }
954
955         return 0;
956 }
957
958 static const struct ieee80211_ops wcn36xx_ops = {
959         .start                  = wcn36xx_start,
960         .stop                   = wcn36xx_stop,
961         .add_interface          = wcn36xx_add_interface,
962         .remove_interface       = wcn36xx_remove_interface,
963 #ifdef CONFIG_PM
964         .suspend                = wcn36xx_suspend,
965         .resume                 = wcn36xx_resume,
966 #endif
967         .config                 = wcn36xx_config,
968         .prepare_multicast      = wcn36xx_prepare_multicast,
969         .configure_filter       = wcn36xx_configure_filter,
970         .tx                     = wcn36xx_tx,
971         .set_key                = wcn36xx_set_key,
972         .sw_scan_start          = wcn36xx_sw_scan_start,
973         .sw_scan_complete       = wcn36xx_sw_scan_complete,
974         .bss_info_changed       = wcn36xx_bss_info_changed,
975         .set_rts_threshold      = wcn36xx_set_rts_threshold,
976         .sta_add                = wcn36xx_sta_add,
977         .sta_remove             = wcn36xx_sta_remove,
978         .ampdu_action           = wcn36xx_ampdu_action,
979 };
980
981 static int wcn36xx_init_ieee80211(struct wcn36xx *wcn)
982 {
983         int ret = 0;
984
985         static const u32 cipher_suites[] = {
986                 WLAN_CIPHER_SUITE_WEP40,
987                 WLAN_CIPHER_SUITE_WEP104,
988                 WLAN_CIPHER_SUITE_TKIP,
989                 WLAN_CIPHER_SUITE_CCMP,
990         };
991
992         ieee80211_hw_set(wcn->hw, TIMING_BEACON_ONLY);
993         ieee80211_hw_set(wcn->hw, AMPDU_AGGREGATION);
994         ieee80211_hw_set(wcn->hw, CONNECTION_MONITOR);
995         ieee80211_hw_set(wcn->hw, SUPPORTS_PS);
996         ieee80211_hw_set(wcn->hw, SIGNAL_DBM);
997         ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL);
998
999         /* 3620 powersaving currently unstable */
1000         if (wcn->chip_version == WCN36XX_CHIP_3620)
1001                 __clear_bit(IEEE80211_HW_SUPPORTS_PS, wcn->hw->flags);
1002
1003         wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
1004                 BIT(NL80211_IFTYPE_AP) |
1005                 BIT(NL80211_IFTYPE_ADHOC) |
1006                 BIT(NL80211_IFTYPE_MESH_POINT);
1007
1008         wcn->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &wcn_band_2ghz;
1009         wcn->hw->wiphy->bands[IEEE80211_BAND_5GHZ] = &wcn_band_5ghz;
1010
1011         wcn->hw->wiphy->cipher_suites = cipher_suites;
1012         wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
1013
1014         wcn->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
1015
1016         /* TODO: Figure out why this is necessary */
1017         wcn->hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
1018
1019 #ifdef CONFIG_PM
1020         wcn->hw->wiphy->wowlan = &wowlan_support;
1021 #endif
1022
1023         wcn->hw->max_listen_interval = 200;
1024
1025         wcn->hw->queues = 4;
1026
1027         SET_IEEE80211_DEV(wcn->hw, wcn->dev);
1028
1029         wcn->hw->sta_data_size = sizeof(struct wcn36xx_sta);
1030         wcn->hw->vif_data_size = sizeof(struct wcn36xx_vif);
1031
1032         return ret;
1033 }
1034
1035 static int wcn36xx_platform_get_resources(struct wcn36xx *wcn,
1036                                           struct platform_device *pdev)
1037 {
1038         struct resource *res;
1039         /* Set TX IRQ */
1040         res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1041                                            "wcnss_wlantx_irq");
1042         if (!res) {
1043                 wcn36xx_err("failed to get tx_irq\n");
1044                 return -ENOENT;
1045         }
1046         wcn->tx_irq = res->start;
1047
1048         /* Set RX IRQ */
1049         res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
1050                                            "wcnss_wlanrx_irq");
1051         if (!res) {
1052                 wcn36xx_err("failed to get rx_irq\n");
1053                 return -ENOENT;
1054         }
1055         wcn->rx_irq = res->start;
1056
1057         /* Map the memory */
1058         res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1059                                                  "wcnss_mmio");
1060         if (!res) {
1061                 wcn36xx_err("failed to get mmio\n");
1062                 return -ENOENT;
1063         }
1064         wcn->mmio = ioremap(res->start, resource_size(res));
1065         if (!wcn->mmio) {
1066                 wcn36xx_err("failed to map io memory\n");
1067                 return -ENOMEM;
1068         }
1069         return 0;
1070 }
1071
1072 static int wcn36xx_probe(struct platform_device *pdev)
1073 {
1074         struct ieee80211_hw *hw;
1075         struct wcn36xx *wcn;
1076         int ret;
1077         u8 addr[ETH_ALEN];
1078
1079         wcn36xx_dbg(WCN36XX_DBG_MAC, "platform probe\n");
1080
1081         hw = ieee80211_alloc_hw(sizeof(struct wcn36xx), &wcn36xx_ops);
1082         if (!hw) {
1083                 wcn36xx_err("failed to alloc hw\n");
1084                 ret = -ENOMEM;
1085                 goto out_err;
1086         }
1087         platform_set_drvdata(pdev, hw);
1088         wcn = hw->priv;
1089         wcn->hw = hw;
1090         wcn->dev = &pdev->dev;
1091         wcn->dev->dma_mask = kzalloc(sizeof(*wcn->dev->dma_mask), GFP_KERNEL);
1092         if (!wcn->dev->dma_mask) {
1093                 ret = -ENOMEM;
1094                 goto dma_mask_err;
1095         }
1096         dma_set_mask_and_coherent(wcn->dev, DMA_BIT_MASK(32));
1097         wcn->wcn36xx_data = pdev->dev.platform_data;
1098         wcn->ctrl_ops = &wcn->wcn36xx_data->ctrl_ops;
1099         wcn->wcn36xx_data->wcn = wcn;
1100         if (!wcn->ctrl_ops->get_chip_type) {
1101                 dev_err(&pdev->dev, "Missing ops->get_chip_type\n");
1102                 ret = -EINVAL;
1103                 goto out_wq;
1104         }
1105         wcn->chip_version = wcn->ctrl_ops->get_chip_type(wcn);
1106
1107         mutex_init(&wcn->hal_mutex);
1108
1109         if (!wcn->ctrl_ops->get_hw_mac(wcn, addr)) {
1110                 wcn36xx_info("mac address: %pM\n", addr);
1111                 SET_IEEE80211_PERM_ADDR(wcn->hw, addr);
1112         }
1113
1114         ret = wcn36xx_platform_get_resources(wcn, pdev);
1115         if (ret)
1116                 goto out_wq;
1117
1118         wcn36xx_init_ieee80211(wcn);
1119         ret = ieee80211_register_hw(wcn->hw);
1120         if (ret)
1121                 goto out_unmap;
1122
1123         return 0;
1124
1125 out_unmap:
1126         iounmap(wcn->mmio);
1127 out_wq:
1128         kfree(wcn->dev->dma_mask);
1129 dma_mask_err:
1130         ieee80211_free_hw(hw);
1131 out_err:
1132         return ret;
1133 }
1134 static int wcn36xx_remove(struct platform_device *pdev)
1135 {
1136         struct ieee80211_hw *hw = platform_get_drvdata(pdev);
1137         struct wcn36xx *wcn = hw->priv;
1138         wcn36xx_dbg(WCN36XX_DBG_MAC, "platform remove\n");
1139
1140         release_firmware(wcn->nv);
1141         mutex_destroy(&wcn->hal_mutex);
1142
1143         ieee80211_unregister_hw(hw);
1144         iounmap(wcn->mmio);
1145         ieee80211_free_hw(hw);
1146
1147         return 0;
1148 }
1149 static const struct platform_device_id wcn36xx_platform_id_table[] = {
1150         {
1151                 .name = "wcn36xx",
1152                 .driver_data = 0
1153         },
1154         {}
1155 };
1156 MODULE_DEVICE_TABLE(platform, wcn36xx_platform_id_table);
1157
1158 static struct platform_driver wcn36xx_driver = {
1159         .probe      = wcn36xx_probe,
1160         .remove     = wcn36xx_remove,
1161         .driver         = {
1162                 .name   = "wcn36xx",
1163         },
1164         .id_table    = wcn36xx_platform_id_table,
1165 };
1166
1167 static int __init wcn36xx_init(void)
1168 {
1169         platform_driver_register(&wcn36xx_driver);
1170         return 0;
1171 }
1172 module_init(wcn36xx_init);
1173
1174 static void __exit wcn36xx_exit(void)
1175 {
1176         platform_driver_unregister(&wcn36xx_driver);
1177 }
1178 module_exit(wcn36xx_exit);
1179
1180 MODULE_LICENSE("Dual BSD/GPL");
1181 MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
1182 MODULE_FIRMWARE(WLAN_NV_FILE);