2 * Copyright (c) 2013 Eugene Krasnikov <k.eugene.e@gmail.com>
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.
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.
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19 #include <linux/module.h>
20 #include <linux/firmware.h>
21 #include <linux/platform_device.h>
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");
28 #define CHAN2G(_freq, _idx) { \
29 .band = IEEE80211_BAND_2GHZ, \
30 .center_freq = (_freq), \
35 #define CHAN5G(_freq, _idx) { \
36 .band = IEEE80211_BAND_5GHZ, \
37 .center_freq = (_freq), \
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 */
62 static struct ieee80211_channel wcn_5ghz_channels
[] = {
88 #define RATE(_bitrate, _hw_rate, _flags) { \
89 .bitrate = (_bitrate), \
91 .hw_value = (_hw_rate), \
92 .hw_value_short = (_hw_rate) \
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)
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)
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
),
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
,
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
,
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
),
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
,
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
,
167 static const struct wiphy_wowlan_support wowlan_support
= {
168 .flags
= WIPHY_WOWLAN_ANY
173 static inline u8
get_sta_index(struct ieee80211_vif
*vif
,
174 struct wcn36xx_sta
*sta_priv
)
176 return NL80211_IFTYPE_STATION
== vif
->type
?
177 sta_priv
->bss_sta_index
:
181 static const char * const wcn36xx_caps_names
[] = {
185 "SLM_SESSIONIZATION", /* 3 */
186 "DOT11AC_OPMODE", /* 4 */
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 */
201 "BCN_FILTER", /* 19 */
207 static const char *wcn36xx_get_cap_name(enum place_holder_in_cap_bitmap x
)
209 if (x
>= ARRAY_SIZE(wcn36xx_caps_names
))
211 return wcn36xx_caps_names
[x
];
214 static void wcn36xx_feat_caps_info(struct wcn36xx
*wcn
)
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
));
224 static void wcn36xx_detect_chip_version(struct wcn36xx
*wcn
)
226 if (get_feat_caps(wcn
->fw_feat_caps
, DOT11AC
)) {
227 wcn36xx_info("Chip is 3680\n");
228 wcn
->chip_version
= WCN36XX_CHIP_3680
;
230 wcn36xx_info("Chip is 3660\n");
231 wcn
->chip_version
= WCN36XX_CHIP_3660
;
235 static int wcn36xx_start(struct ieee80211_hw
*hw
)
237 struct wcn36xx
*wcn
= hw
->priv
;
240 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac start\n");
242 /* SMD initialization */
243 ret
= wcn36xx_smd_open(wcn
);
245 wcn36xx_err("Failed to open smd channel: %d\n", ret
);
249 /* Allocate memory pools for Mgmt BD headers and Data BD headers */
250 ret
= wcn36xx_dxe_allocate_mem_pools(wcn
);
252 wcn36xx_err("Failed to alloc DXE mempool: %d\n", ret
);
256 ret
= wcn36xx_dxe_alloc_ctl_blks(wcn
);
258 wcn36xx_err("Failed to alloc DXE ctl blocks: %d\n", ret
);
259 goto out_free_dxe_pool
;
262 wcn
->hal_buf
= kmalloc(WCN36XX_HAL_BUF_SIZE
, GFP_KERNEL
);
264 wcn36xx_err("Failed to allocate smd buf\n");
266 goto out_free_dxe_ctl
;
269 ret
= wcn36xx_smd_load_nv(wcn
);
271 wcn36xx_err("Failed to push NV to chip\n");
272 goto out_free_smd_buf
;
275 ret
= wcn36xx_smd_start(wcn
);
277 wcn36xx_err("Failed to start chip\n");
278 goto out_free_smd_buf
;
281 if (!wcn36xx_is_fw_version(wcn
, 1, 2, 2, 24)) {
282 ret
= wcn36xx_smd_feature_caps_exchange(wcn
);
284 wcn36xx_warn("Exchange feature caps failed\n");
286 wcn36xx_feat_caps_info(wcn
);
289 wcn36xx_detect_chip_version(wcn
);
291 /* DMA channel initialization */
292 ret
= wcn36xx_dxe_init(wcn
);
294 wcn36xx_err("DXE init failed\n");
298 wcn36xx_debugfs_init(wcn
);
300 INIT_LIST_HEAD(&wcn
->vif_list
);
301 spin_lock_init(&wcn
->dxe_lock
);
306 wcn36xx_smd_stop(wcn
);
310 wcn36xx_dxe_free_mem_pools(wcn
);
312 wcn36xx_dxe_free_ctl_blks(wcn
);
314 wcn36xx_smd_close(wcn
);
319 static void wcn36xx_stop(struct ieee80211_hw
*hw
)
321 struct wcn36xx
*wcn
= hw
->priv
;
323 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac stop\n");
325 wcn36xx_debugfs_exit(wcn
);
326 wcn36xx_smd_stop(wcn
);
327 wcn36xx_dxe_deinit(wcn
);
328 wcn36xx_smd_close(wcn
);
330 wcn36xx_dxe_free_mem_pools(wcn
);
331 wcn36xx_dxe_free_ctl_blks(wcn
);
336 static int wcn36xx_config(struct ieee80211_hw
*hw
, u32 changed
)
338 struct wcn36xx
*wcn
= hw
->priv
;
339 struct ieee80211_vif
*vif
= NULL
;
340 struct wcn36xx_vif
*tmp
;
342 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac config changed 0x%08x\n", changed
);
344 if (changed
& IEEE80211_CONF_CHANGE_CHANNEL
) {
345 int ch
= WCN36XX_HW_CHANNEL(wcn
);
346 wcn36xx_dbg(WCN36XX_DBG_MAC
, "wcn36xx_config channel switch=%d\n",
348 list_for_each_entry(tmp
, &wcn
->vif_list
, list
) {
349 vif
= container_of((void *)tmp
,
350 struct ieee80211_vif
,
352 wcn36xx_smd_switch_channel(wcn
, vif
, ch
);
359 #define WCN36XX_SUPPORTED_FILTERS (0)
361 static void wcn36xx_configure_filter(struct ieee80211_hw
*hw
,
362 unsigned int changed
,
363 unsigned int *total
, u64 multicast
)
365 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac configure filter\n");
367 *total
&= WCN36XX_SUPPORTED_FILTERS
;
370 static void wcn36xx_tx(struct ieee80211_hw
*hw
,
371 struct ieee80211_tx_control
*control
,
374 struct wcn36xx
*wcn
= hw
->priv
;
375 struct wcn36xx_sta
*sta_priv
= NULL
;
378 sta_priv
= (struct wcn36xx_sta
*)control
->sta
->drv_priv
;
380 if (wcn36xx_start_tx(wcn
, sta_priv
, skb
))
381 ieee80211_free_txskb(wcn
->hw
, skb
);
384 static int wcn36xx_set_key(struct ieee80211_hw
*hw
, enum set_key_cmd cmd
,
385 struct ieee80211_vif
*vif
,
386 struct ieee80211_sta
*sta
,
387 struct ieee80211_key_conf
*key_conf
)
389 struct wcn36xx
*wcn
= hw
->priv
;
390 struct wcn36xx_vif
*vif_priv
= (struct wcn36xx_vif
*)vif
->drv_priv
;
391 struct wcn36xx_sta
*sta_priv
= vif_priv
->sta
;
393 u8 key
[WLAN_MAX_KEY_LEN
];
395 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac80211 set key\n");
396 wcn36xx_dbg(WCN36XX_DBG_MAC
, "Key: cmd=0x%x algo:0x%x, id:%d, len:%d flags 0x%x\n",
397 cmd
, key_conf
->cipher
, key_conf
->keyidx
,
398 key_conf
->keylen
, key_conf
->flags
);
399 wcn36xx_dbg_dump(WCN36XX_DBG_MAC
, "KEY: ",
403 switch (key_conf
->cipher
) {
404 case WLAN_CIPHER_SUITE_WEP40
:
405 vif_priv
->encrypt_type
= WCN36XX_HAL_ED_WEP40
;
407 case WLAN_CIPHER_SUITE_WEP104
:
408 vif_priv
->encrypt_type
= WCN36XX_HAL_ED_WEP40
;
410 case WLAN_CIPHER_SUITE_CCMP
:
411 vif_priv
->encrypt_type
= WCN36XX_HAL_ED_CCMP
;
413 case WLAN_CIPHER_SUITE_TKIP
:
414 vif_priv
->encrypt_type
= WCN36XX_HAL_ED_TKIP
;
417 wcn36xx_err("Unsupported key type 0x%x\n",
425 if (WCN36XX_HAL_ED_TKIP
== vif_priv
->encrypt_type
) {
427 * Supplicant is sending key in the wrong order:
428 * Temporal Key (16 b) - TX MIC (8 b) - RX MIC (8 b)
429 * but HW expects it to be in the order as described in
430 * IEEE 802.11 spec (see chapter 11.7) like this:
431 * Temporal Key (16 b) - RX MIC (8 b) - TX MIC (8 b)
433 memcpy(key
, key_conf
->key
, 16);
434 memcpy(key
+ 16, key_conf
->key
+ 24, 8);
435 memcpy(key
+ 24, key_conf
->key
+ 16, 8);
437 memcpy(key
, key_conf
->key
, key_conf
->keylen
);
440 if (IEEE80211_KEY_FLAG_PAIRWISE
& key_conf
->flags
) {
441 sta_priv
->is_data_encrypted
= true;
442 /* Reconfigure bss with encrypt_type */
443 if (NL80211_IFTYPE_STATION
== vif
->type
)
444 wcn36xx_smd_config_bss(wcn
,
450 wcn36xx_smd_set_stakey(wcn
,
451 vif_priv
->encrypt_type
,
455 get_sta_index(vif
, sta_priv
));
457 wcn36xx_smd_set_bsskey(wcn
,
458 vif_priv
->encrypt_type
,
462 if ((WLAN_CIPHER_SUITE_WEP40
== key_conf
->cipher
) ||
463 (WLAN_CIPHER_SUITE_WEP104
== key_conf
->cipher
)) {
464 sta_priv
->is_data_encrypted
= true;
465 wcn36xx_smd_set_stakey(wcn
,
466 vif_priv
->encrypt_type
,
470 get_sta_index(vif
, sta_priv
));
475 if (!(IEEE80211_KEY_FLAG_PAIRWISE
& key_conf
->flags
)) {
476 wcn36xx_smd_remove_bsskey(wcn
,
477 vif_priv
->encrypt_type
,
480 sta_priv
->is_data_encrypted
= false;
481 /* do not remove key if disassociated */
483 wcn36xx_smd_remove_stakey(wcn
,
484 vif_priv
->encrypt_type
,
486 get_sta_index(vif
, sta_priv
));
490 wcn36xx_err("Unsupported key cmd 0x%x\n", cmd
);
499 static void wcn36xx_sw_scan_start(struct ieee80211_hw
*hw
,
500 struct ieee80211_vif
*vif
,
503 struct wcn36xx
*wcn
= hw
->priv
;
505 wcn36xx_smd_init_scan(wcn
, HAL_SYS_MODE_SCAN
);
506 wcn36xx_smd_start_scan(wcn
);
509 static void wcn36xx_sw_scan_complete(struct ieee80211_hw
*hw
,
510 struct ieee80211_vif
*vif
)
512 struct wcn36xx
*wcn
= hw
->priv
;
514 wcn36xx_smd_end_scan(wcn
);
515 wcn36xx_smd_finish_scan(wcn
, HAL_SYS_MODE_SCAN
);
518 static void wcn36xx_update_allowed_rates(struct ieee80211_sta
*sta
,
519 enum ieee80211_band band
)
523 struct wcn36xx_sta
*sta_priv
= (struct wcn36xx_sta
*)sta
->drv_priv
;
524 u32 rates
= sta
->supp_rates
[band
];
526 memset(&sta_priv
->supported_rates
, 0,
527 sizeof(sta_priv
->supported_rates
));
528 sta_priv
->supported_rates
.op_rate_mode
= STA_11n
;
530 size
= ARRAY_SIZE(sta_priv
->supported_rates
.dsss_rates
);
531 rates_table
= sta_priv
->supported_rates
.dsss_rates
;
532 if (band
== IEEE80211_BAND_2GHZ
) {
533 for (i
= 0; i
< size
; i
++) {
535 rates_table
[i
] = wcn_2ghz_rates
[i
].hw_value
;
541 size
= ARRAY_SIZE(sta_priv
->supported_rates
.ofdm_rates
);
542 rates_table
= sta_priv
->supported_rates
.ofdm_rates
;
543 for (i
= 0; i
< size
; i
++) {
545 rates_table
[i
] = wcn_5ghz_rates
[i
].hw_value
;
550 if (sta
->ht_cap
.ht_supported
) {
551 BUILD_BUG_ON(sizeof(sta
->ht_cap
.mcs
.rx_mask
) >
552 sizeof(sta_priv
->supported_rates
.supported_mcs_set
));
553 memcpy(sta_priv
->supported_rates
.supported_mcs_set
,
554 sta
->ht_cap
.mcs
.rx_mask
,
555 sizeof(sta
->ht_cap
.mcs
.rx_mask
));
558 void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates
*rates
)
560 u16 ofdm_rates
[WCN36XX_HAL_NUM_OFDM_RATES
] = {
563 HW_RATE_INDEX_12MBPS
,
564 HW_RATE_INDEX_18MBPS
,
565 HW_RATE_INDEX_24MBPS
,
566 HW_RATE_INDEX_36MBPS
,
567 HW_RATE_INDEX_48MBPS
,
570 u16 dsss_rates
[WCN36XX_HAL_NUM_DSSS_RATES
] = {
573 HW_RATE_INDEX_5_5MBPS
,
577 rates
->op_rate_mode
= STA_11n
;
578 memcpy(rates
->dsss_rates
, dsss_rates
,
579 sizeof(*dsss_rates
) * WCN36XX_HAL_NUM_DSSS_RATES
);
580 memcpy(rates
->ofdm_rates
, ofdm_rates
,
581 sizeof(*ofdm_rates
) * WCN36XX_HAL_NUM_OFDM_RATES
);
582 rates
->supported_mcs_set
[0] = 0xFF;
584 static void wcn36xx_bss_info_changed(struct ieee80211_hw
*hw
,
585 struct ieee80211_vif
*vif
,
586 struct ieee80211_bss_conf
*bss_conf
,
589 struct wcn36xx
*wcn
= hw
->priv
;
590 struct sk_buff
*skb
= NULL
;
591 u16 tim_off
, tim_len
;
592 enum wcn36xx_hal_link_state link_state
;
593 struct wcn36xx_vif
*vif_priv
= (struct wcn36xx_vif
*)vif
->drv_priv
;
595 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac bss info changed vif %p changed 0x%08x\n",
598 if (changed
& BSS_CHANGED_BEACON_INFO
) {
599 wcn36xx_dbg(WCN36XX_DBG_MAC
,
600 "mac bss changed dtim period %d\n",
601 bss_conf
->dtim_period
);
603 vif_priv
->dtim_period
= bss_conf
->dtim_period
;
606 if (changed
& BSS_CHANGED_PS
) {
607 wcn36xx_dbg(WCN36XX_DBG_MAC
,
608 "mac bss PS set %d\n",
611 wcn36xx_pmc_enter_bmps_state(wcn
, vif
);
613 wcn36xx_pmc_exit_bmps_state(wcn
, vif
);
617 if (changed
& BSS_CHANGED_BSSID
) {
618 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac bss changed_bssid %pM\n",
621 if (!is_zero_ether_addr(bss_conf
->bssid
)) {
622 vif_priv
->is_joining
= true;
623 vif_priv
->bss_index
= 0xff;
624 wcn36xx_smd_join(wcn
, bss_conf
->bssid
,
625 vif
->addr
, WCN36XX_HW_CHANNEL(wcn
));
626 wcn36xx_smd_config_bss(wcn
, vif
, NULL
,
627 bss_conf
->bssid
, false);
629 vif_priv
->is_joining
= false;
630 wcn36xx_smd_delete_bss(wcn
, vif
);
634 if (changed
& BSS_CHANGED_SSID
) {
635 wcn36xx_dbg(WCN36XX_DBG_MAC
,
636 "mac bss changed ssid\n");
637 wcn36xx_dbg_dump(WCN36XX_DBG_MAC
, "ssid ",
638 bss_conf
->ssid
, bss_conf
->ssid_len
);
640 vif_priv
->ssid
.length
= bss_conf
->ssid_len
;
641 memcpy(&vif_priv
->ssid
.ssid
,
646 if (changed
& BSS_CHANGED_ASSOC
) {
647 vif_priv
->is_joining
= false;
648 if (bss_conf
->assoc
) {
649 struct ieee80211_sta
*sta
;
650 struct wcn36xx_sta
*sta_priv
;
652 wcn36xx_dbg(WCN36XX_DBG_MAC
,
653 "mac assoc bss %pM vif %pM AID=%d\n",
659 sta
= ieee80211_find_sta(vif
, bss_conf
->bssid
);
661 wcn36xx_err("sta %pM is not found\n",
666 sta_priv
= (struct wcn36xx_sta
*)sta
->drv_priv
;
668 wcn36xx_update_allowed_rates(sta
, WCN36XX_BAND(wcn
));
670 wcn36xx_smd_set_link_st(wcn
, bss_conf
->bssid
,
672 WCN36XX_HAL_LINK_POSTASSOC_STATE
);
673 wcn36xx_smd_config_bss(wcn
, vif
, sta
,
676 sta_priv
->aid
= bss_conf
->aid
;
678 * config_sta must be called from because this is the
679 * place where AID is available.
681 wcn36xx_smd_config_sta(wcn
, vif
, sta
);
684 wcn36xx_dbg(WCN36XX_DBG_MAC
,
685 "disassociated bss %pM vif %pM AID=%d\n",
689 wcn36xx_smd_set_link_st(wcn
,
692 WCN36XX_HAL_LINK_IDLE_STATE
);
696 if (changed
& BSS_CHANGED_AP_PROBE_RESP
) {
697 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac bss changed ap probe resp\n");
698 skb
= ieee80211_proberesp_get(hw
, vif
);
700 wcn36xx_err("failed to alloc probereq skb\n");
704 wcn36xx_smd_update_proberesp_tmpl(wcn
, vif
, skb
);
708 if (changed
& BSS_CHANGED_BEACON_ENABLED
||
709 changed
& BSS_CHANGED_BEACON
) {
710 wcn36xx_dbg(WCN36XX_DBG_MAC
,
711 "mac bss changed beacon enabled %d\n",
712 bss_conf
->enable_beacon
);
714 if (bss_conf
->enable_beacon
) {
715 vif_priv
->dtim_period
= bss_conf
->dtim_period
;
716 vif_priv
->bss_index
= 0xff;
717 wcn36xx_smd_config_bss(wcn
, vif
, NULL
,
719 skb
= ieee80211_beacon_get_tim(hw
, vif
, &tim_off
,
722 wcn36xx_err("failed to alloc beacon skb\n");
725 wcn36xx_smd_send_beacon(wcn
, vif
, skb
, tim_off
, 0);
728 if (vif
->type
== NL80211_IFTYPE_ADHOC
||
729 vif
->type
== NL80211_IFTYPE_MESH_POINT
)
730 link_state
= WCN36XX_HAL_LINK_IBSS_STATE
;
732 link_state
= WCN36XX_HAL_LINK_AP_STATE
;
734 wcn36xx_smd_set_link_st(wcn
, vif
->addr
, vif
->addr
,
737 wcn36xx_smd_set_link_st(wcn
, vif
->addr
, vif
->addr
,
738 WCN36XX_HAL_LINK_IDLE_STATE
);
739 wcn36xx_smd_delete_bss(wcn
, vif
);
746 /* this is required when using IEEE80211_HW_HAS_RATE_CONTROL */
747 static int wcn36xx_set_rts_threshold(struct ieee80211_hw
*hw
, u32 value
)
749 struct wcn36xx
*wcn
= hw
->priv
;
750 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac set RTS threshold %d\n", value
);
752 wcn36xx_smd_update_cfg(wcn
, WCN36XX_HAL_CFG_RTS_THRESHOLD
, value
);
756 static void wcn36xx_remove_interface(struct ieee80211_hw
*hw
,
757 struct ieee80211_vif
*vif
)
759 struct wcn36xx
*wcn
= hw
->priv
;
760 struct wcn36xx_vif
*vif_priv
= (struct wcn36xx_vif
*)vif
->drv_priv
;
761 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac remove interface vif %p\n", vif
);
763 list_del(&vif_priv
->list
);
764 wcn36xx_smd_delete_sta_self(wcn
, vif
->addr
);
767 static int wcn36xx_add_interface(struct ieee80211_hw
*hw
,
768 struct ieee80211_vif
*vif
)
770 struct wcn36xx
*wcn
= hw
->priv
;
771 struct wcn36xx_vif
*vif_priv
= (struct wcn36xx_vif
*)vif
->drv_priv
;
773 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac add interface vif %p type %d\n",
776 if (!(NL80211_IFTYPE_STATION
== vif
->type
||
777 NL80211_IFTYPE_AP
== vif
->type
||
778 NL80211_IFTYPE_ADHOC
== vif
->type
||
779 NL80211_IFTYPE_MESH_POINT
== vif
->type
)) {
780 wcn36xx_warn("Unsupported interface type requested: %d\n",
785 list_add(&vif_priv
->list
, &wcn
->vif_list
);
786 wcn36xx_smd_add_sta_self(wcn
, vif
);
791 static int wcn36xx_sta_add(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
792 struct ieee80211_sta
*sta
)
794 struct wcn36xx
*wcn
= hw
->priv
;
795 struct wcn36xx_vif
*vif_priv
= (struct wcn36xx_vif
*)vif
->drv_priv
;
796 struct wcn36xx_sta
*sta_priv
= (struct wcn36xx_sta
*)sta
->drv_priv
;
797 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac sta add vif %p sta %pM\n",
800 spin_lock_init(&sta_priv
->ampdu_lock
);
801 vif_priv
->sta
= sta_priv
;
802 sta_priv
->vif
= vif_priv
;
804 * For STA mode HW will be configured on BSS_CHANGED_ASSOC because
805 * at this stage AID is not available yet.
807 if (NL80211_IFTYPE_STATION
!= vif
->type
) {
808 wcn36xx_update_allowed_rates(sta
, WCN36XX_BAND(wcn
));
809 sta_priv
->aid
= sta
->aid
;
810 wcn36xx_smd_config_sta(wcn
, vif
, sta
);
815 static int wcn36xx_sta_remove(struct ieee80211_hw
*hw
,
816 struct ieee80211_vif
*vif
,
817 struct ieee80211_sta
*sta
)
819 struct wcn36xx
*wcn
= hw
->priv
;
820 struct wcn36xx_vif
*vif_priv
= (struct wcn36xx_vif
*)vif
->drv_priv
;
821 struct wcn36xx_sta
*sta_priv
= (struct wcn36xx_sta
*)sta
->drv_priv
;
823 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac sta remove vif %p sta %pM index %d\n",
824 vif
, sta
->addr
, sta_priv
->sta_index
);
826 wcn36xx_smd_delete_sta(wcn
, sta_priv
->sta_index
);
827 vif_priv
->sta
= NULL
;
828 sta_priv
->vif
= NULL
;
834 static int wcn36xx_suspend(struct ieee80211_hw
*hw
, struct cfg80211_wowlan
*wow
)
836 struct wcn36xx
*wcn
= hw
->priv
;
838 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac suspend\n");
840 flush_workqueue(wcn
->hal_ind_wq
);
841 wcn36xx_smd_set_power_params(wcn
, true);
845 static int wcn36xx_resume(struct ieee80211_hw
*hw
)
847 struct wcn36xx
*wcn
= hw
->priv
;
849 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac resume\n");
851 flush_workqueue(wcn
->hal_ind_wq
);
852 wcn36xx_smd_set_power_params(wcn
, false);
858 static int wcn36xx_ampdu_action(struct ieee80211_hw
*hw
,
859 struct ieee80211_vif
*vif
,
860 struct ieee80211_ampdu_params
*params
)
862 struct wcn36xx
*wcn
= hw
->priv
;
863 struct wcn36xx_sta
*sta_priv
= NULL
;
864 struct ieee80211_sta
*sta
= params
->sta
;
865 enum ieee80211_ampdu_mlme_action action
= params
->action
;
866 u16 tid
= params
->tid
;
867 u16
*ssn
= ¶ms
->ssn
;
869 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac ampdu action action %d tid %d\n",
872 sta_priv
= (struct wcn36xx_sta
*)sta
->drv_priv
;
875 case IEEE80211_AMPDU_RX_START
:
877 wcn36xx_smd_add_ba_session(wcn
, sta
, tid
, ssn
, 0,
878 get_sta_index(vif
, sta_priv
));
879 wcn36xx_smd_add_ba(wcn
);
880 wcn36xx_smd_trigger_ba(wcn
, get_sta_index(vif
, sta_priv
));
882 case IEEE80211_AMPDU_RX_STOP
:
883 wcn36xx_smd_del_ba(wcn
, tid
, get_sta_index(vif
, sta_priv
));
885 case IEEE80211_AMPDU_TX_START
:
886 spin_lock_bh(&sta_priv
->ampdu_lock
);
887 sta_priv
->ampdu_state
[tid
] = WCN36XX_AMPDU_START
;
888 spin_unlock_bh(&sta_priv
->ampdu_lock
);
890 ieee80211_start_tx_ba_cb_irqsafe(vif
, sta
->addr
, tid
);
892 case IEEE80211_AMPDU_TX_OPERATIONAL
:
893 spin_lock_bh(&sta_priv
->ampdu_lock
);
894 sta_priv
->ampdu_state
[tid
] = WCN36XX_AMPDU_OPERATIONAL
;
895 spin_unlock_bh(&sta_priv
->ampdu_lock
);
897 wcn36xx_smd_add_ba_session(wcn
, sta
, tid
, ssn
, 1,
898 get_sta_index(vif
, sta_priv
));
900 case IEEE80211_AMPDU_TX_STOP_FLUSH
:
901 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT
:
902 case IEEE80211_AMPDU_TX_STOP_CONT
:
903 spin_lock_bh(&sta_priv
->ampdu_lock
);
904 sta_priv
->ampdu_state
[tid
] = WCN36XX_AMPDU_NONE
;
905 spin_unlock_bh(&sta_priv
->ampdu_lock
);
907 ieee80211_stop_tx_ba_cb_irqsafe(vif
, sta
->addr
, tid
);
910 wcn36xx_err("Unknown AMPDU action\n");
916 static const struct ieee80211_ops wcn36xx_ops
= {
917 .start
= wcn36xx_start
,
918 .stop
= wcn36xx_stop
,
919 .add_interface
= wcn36xx_add_interface
,
920 .remove_interface
= wcn36xx_remove_interface
,
922 .suspend
= wcn36xx_suspend
,
923 .resume
= wcn36xx_resume
,
925 .config
= wcn36xx_config
,
926 .configure_filter
= wcn36xx_configure_filter
,
928 .set_key
= wcn36xx_set_key
,
929 .sw_scan_start
= wcn36xx_sw_scan_start
,
930 .sw_scan_complete
= wcn36xx_sw_scan_complete
,
931 .bss_info_changed
= wcn36xx_bss_info_changed
,
932 .set_rts_threshold
= wcn36xx_set_rts_threshold
,
933 .sta_add
= wcn36xx_sta_add
,
934 .sta_remove
= wcn36xx_sta_remove
,
935 .ampdu_action
= wcn36xx_ampdu_action
,
938 static int wcn36xx_init_ieee80211(struct wcn36xx
*wcn
)
942 static const u32 cipher_suites
[] = {
943 WLAN_CIPHER_SUITE_WEP40
,
944 WLAN_CIPHER_SUITE_WEP104
,
945 WLAN_CIPHER_SUITE_TKIP
,
946 WLAN_CIPHER_SUITE_CCMP
,
949 ieee80211_hw_set(wcn
->hw
, TIMING_BEACON_ONLY
);
950 ieee80211_hw_set(wcn
->hw
, AMPDU_AGGREGATION
);
951 ieee80211_hw_set(wcn
->hw
, CONNECTION_MONITOR
);
952 ieee80211_hw_set(wcn
->hw
, SUPPORTS_PS
);
953 ieee80211_hw_set(wcn
->hw
, SIGNAL_DBM
);
954 ieee80211_hw_set(wcn
->hw
, HAS_RATE_CONTROL
);
956 wcn
->hw
->wiphy
->interface_modes
= BIT(NL80211_IFTYPE_STATION
) |
957 BIT(NL80211_IFTYPE_AP
) |
958 BIT(NL80211_IFTYPE_ADHOC
) |
959 BIT(NL80211_IFTYPE_MESH_POINT
);
961 wcn
->hw
->wiphy
->bands
[IEEE80211_BAND_2GHZ
] = &wcn_band_2ghz
;
962 wcn
->hw
->wiphy
->bands
[IEEE80211_BAND_5GHZ
] = &wcn_band_5ghz
;
964 wcn
->hw
->wiphy
->cipher_suites
= cipher_suites
;
965 wcn
->hw
->wiphy
->n_cipher_suites
= ARRAY_SIZE(cipher_suites
);
967 wcn
->hw
->wiphy
->flags
|= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD
;
970 wcn
->hw
->wiphy
->wowlan
= &wowlan_support
;
973 wcn
->hw
->max_listen_interval
= 200;
977 SET_IEEE80211_DEV(wcn
->hw
, wcn
->dev
);
979 wcn
->hw
->sta_data_size
= sizeof(struct wcn36xx_sta
);
980 wcn
->hw
->vif_data_size
= sizeof(struct wcn36xx_vif
);
985 static int wcn36xx_platform_get_resources(struct wcn36xx
*wcn
,
986 struct platform_device
*pdev
)
988 struct resource
*res
;
990 res
= platform_get_resource_byname(pdev
, IORESOURCE_IRQ
,
993 wcn36xx_err("failed to get tx_irq\n");
996 wcn
->tx_irq
= res
->start
;
999 res
= platform_get_resource_byname(pdev
, IORESOURCE_IRQ
,
1000 "wcnss_wlanrx_irq");
1002 wcn36xx_err("failed to get rx_irq\n");
1005 wcn
->rx_irq
= res
->start
;
1007 /* Map the memory */
1008 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
,
1011 wcn36xx_err("failed to get mmio\n");
1014 wcn
->mmio
= ioremap(res
->start
, resource_size(res
));
1016 wcn36xx_err("failed to map io memory\n");
1022 static int wcn36xx_probe(struct platform_device
*pdev
)
1024 struct ieee80211_hw
*hw
;
1025 struct wcn36xx
*wcn
;
1029 wcn36xx_dbg(WCN36XX_DBG_MAC
, "platform probe\n");
1031 hw
= ieee80211_alloc_hw(sizeof(struct wcn36xx
), &wcn36xx_ops
);
1033 wcn36xx_err("failed to alloc hw\n");
1037 platform_set_drvdata(pdev
, hw
);
1040 wcn
->dev
= &pdev
->dev
;
1041 wcn
->ctrl_ops
= pdev
->dev
.platform_data
;
1043 mutex_init(&wcn
->hal_mutex
);
1045 if (!wcn
->ctrl_ops
->get_hw_mac(addr
)) {
1046 wcn36xx_info("mac address: %pM\n", addr
);
1047 SET_IEEE80211_PERM_ADDR(wcn
->hw
, addr
);
1050 ret
= wcn36xx_platform_get_resources(wcn
, pdev
);
1054 wcn36xx_init_ieee80211(wcn
);
1055 ret
= ieee80211_register_hw(wcn
->hw
);
1064 ieee80211_free_hw(hw
);
1068 static int wcn36xx_remove(struct platform_device
*pdev
)
1070 struct ieee80211_hw
*hw
= platform_get_drvdata(pdev
);
1071 struct wcn36xx
*wcn
= hw
->priv
;
1072 wcn36xx_dbg(WCN36XX_DBG_MAC
, "platform remove\n");
1074 release_firmware(wcn
->nv
);
1075 mutex_destroy(&wcn
->hal_mutex
);
1077 ieee80211_unregister_hw(hw
);
1079 ieee80211_free_hw(hw
);
1083 static const struct platform_device_id wcn36xx_platform_id_table
[] = {
1090 MODULE_DEVICE_TABLE(platform
, wcn36xx_platform_id_table
);
1092 static struct platform_driver wcn36xx_driver
= {
1093 .probe
= wcn36xx_probe
,
1094 .remove
= wcn36xx_remove
,
1098 .id_table
= wcn36xx_platform_id_table
,
1101 static int __init
wcn36xx_init(void)
1103 platform_driver_register(&wcn36xx_driver
);
1106 module_init(wcn36xx_init
);
1108 static void __exit
wcn36xx_exit(void)
1110 platform_driver_unregister(&wcn36xx_driver
);
1112 module_exit(wcn36xx_exit
);
1114 MODULE_LICENSE("Dual BSD/GPL");
1115 MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
1116 MODULE_FIRMWARE(WLAN_NV_FILE
);