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/platform_device.h>
23 unsigned int wcn36xx_dbg_mask
;
24 module_param_named(debug_mask
, wcn36xx_dbg_mask
, uint
, 0644);
25 MODULE_PARM_DESC(debug_mask
, "Debugging mask");
27 #define CHAN2G(_freq, _idx) { \
28 .band = IEEE80211_BAND_2GHZ, \
29 .center_freq = (_freq), \
34 #define CHAN5G(_freq, _idx) { \
35 .band = IEEE80211_BAND_5GHZ, \
36 .center_freq = (_freq), \
41 /* The wcn firmware expects channel values to matching
42 * their mnemonic values. So use these for .hw_value. */
43 static struct ieee80211_channel wcn_2ghz_channels
[] = {
44 CHAN2G(2412, 1), /* Channel 1 */
45 CHAN2G(2417, 2), /* Channel 2 */
46 CHAN2G(2422, 3), /* Channel 3 */
47 CHAN2G(2427, 4), /* Channel 4 */
48 CHAN2G(2432, 5), /* Channel 5 */
49 CHAN2G(2437, 6), /* Channel 6 */
50 CHAN2G(2442, 7), /* Channel 7 */
51 CHAN2G(2447, 8), /* Channel 8 */
52 CHAN2G(2452, 9), /* Channel 9 */
53 CHAN2G(2457, 10), /* Channel 10 */
54 CHAN2G(2462, 11), /* Channel 11 */
55 CHAN2G(2467, 12), /* Channel 12 */
56 CHAN2G(2472, 13), /* Channel 13 */
57 CHAN2G(2484, 14) /* Channel 14 */
61 static struct ieee80211_channel wcn_5ghz_channels
[] = {
87 #define RATE(_bitrate, _hw_rate, _flags) { \
88 .bitrate = (_bitrate), \
90 .hw_value = (_hw_rate), \
91 .hw_value_short = (_hw_rate) \
94 static struct ieee80211_rate wcn_2ghz_rates
[] = {
95 RATE(10, HW_RATE_INDEX_1MBPS
, 0),
96 RATE(20, HW_RATE_INDEX_2MBPS
, IEEE80211_RATE_SHORT_PREAMBLE
),
97 RATE(55, HW_RATE_INDEX_5_5MBPS
, IEEE80211_RATE_SHORT_PREAMBLE
),
98 RATE(110, HW_RATE_INDEX_11MBPS
, IEEE80211_RATE_SHORT_PREAMBLE
),
99 RATE(60, HW_RATE_INDEX_6MBPS
, 0),
100 RATE(90, HW_RATE_INDEX_9MBPS
, 0),
101 RATE(120, HW_RATE_INDEX_12MBPS
, 0),
102 RATE(180, HW_RATE_INDEX_18MBPS
, 0),
103 RATE(240, HW_RATE_INDEX_24MBPS
, 0),
104 RATE(360, HW_RATE_INDEX_36MBPS
, 0),
105 RATE(480, HW_RATE_INDEX_48MBPS
, 0),
106 RATE(540, HW_RATE_INDEX_54MBPS
, 0)
109 static struct ieee80211_rate wcn_5ghz_rates
[] = {
110 RATE(60, HW_RATE_INDEX_6MBPS
, 0),
111 RATE(90, HW_RATE_INDEX_9MBPS
, 0),
112 RATE(120, HW_RATE_INDEX_12MBPS
, 0),
113 RATE(180, HW_RATE_INDEX_18MBPS
, 0),
114 RATE(240, HW_RATE_INDEX_24MBPS
, 0),
115 RATE(360, HW_RATE_INDEX_36MBPS
, 0),
116 RATE(480, HW_RATE_INDEX_48MBPS
, 0),
117 RATE(540, HW_RATE_INDEX_54MBPS
, 0)
120 static struct ieee80211_supported_band wcn_band_2ghz
= {
121 .channels
= wcn_2ghz_channels
,
122 .n_channels
= ARRAY_SIZE(wcn_2ghz_channels
),
123 .bitrates
= wcn_2ghz_rates
,
124 .n_bitrates
= ARRAY_SIZE(wcn_2ghz_rates
),
126 .cap
= IEEE80211_HT_CAP_GRN_FLD
|
127 IEEE80211_HT_CAP_SGI_20
|
128 IEEE80211_HT_CAP_DSSSCCK40
|
129 IEEE80211_HT_CAP_LSIG_TXOP_PROT
,
130 .ht_supported
= true,
131 .ampdu_factor
= IEEE80211_HT_MAX_AMPDU_64K
,
132 .ampdu_density
= IEEE80211_HT_MPDU_DENSITY_16
,
134 .rx_mask
= { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
135 .rx_highest
= cpu_to_le16(72),
136 .tx_params
= IEEE80211_HT_MCS_TX_DEFINED
,
141 static struct ieee80211_supported_band wcn_band_5ghz
= {
142 .channels
= wcn_5ghz_channels
,
143 .n_channels
= ARRAY_SIZE(wcn_5ghz_channels
),
144 .bitrates
= wcn_5ghz_rates
,
145 .n_bitrates
= ARRAY_SIZE(wcn_5ghz_rates
),
147 .cap
= IEEE80211_HT_CAP_GRN_FLD
|
148 IEEE80211_HT_CAP_SGI_20
|
149 IEEE80211_HT_CAP_DSSSCCK40
|
150 IEEE80211_HT_CAP_LSIG_TXOP_PROT
|
151 IEEE80211_HT_CAP_SGI_40
|
152 IEEE80211_HT_CAP_SUP_WIDTH_20_40
,
153 .ht_supported
= true,
154 .ampdu_factor
= IEEE80211_HT_MAX_AMPDU_64K
,
155 .ampdu_density
= IEEE80211_HT_MPDU_DENSITY_16
,
157 .rx_mask
= { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, },
158 .rx_highest
= cpu_to_le16(72),
159 .tx_params
= IEEE80211_HT_MCS_TX_DEFINED
,
166 static const struct wiphy_wowlan_support wowlan_support
= {
167 .flags
= WIPHY_WOWLAN_ANY
172 static inline u8
get_sta_index(struct ieee80211_vif
*vif
,
173 struct wcn36xx_sta
*sta_priv
)
175 return NL80211_IFTYPE_STATION
== vif
->type
?
176 sta_priv
->bss_sta_index
:
180 static int wcn36xx_start(struct ieee80211_hw
*hw
)
182 struct wcn36xx
*wcn
= hw
->priv
;
185 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac start\n");
187 /* SMD initialization */
188 ret
= wcn36xx_smd_open(wcn
);
190 wcn36xx_err("Failed to open smd channel: %d\n", ret
);
194 /* Allocate memory pools for Mgmt BD headers and Data BD headers */
195 ret
= wcn36xx_dxe_allocate_mem_pools(wcn
);
197 wcn36xx_err("Failed to alloc DXE mempool: %d\n", ret
);
201 ret
= wcn36xx_dxe_alloc_ctl_blks(wcn
);
203 wcn36xx_err("Failed to alloc DXE ctl blocks: %d\n", ret
);
204 goto out_free_dxe_pool
;
207 wcn
->hal_buf
= kmalloc(WCN36XX_HAL_BUF_SIZE
, GFP_KERNEL
);
209 wcn36xx_err("Failed to allocate smd buf\n");
211 goto out_free_dxe_ctl
;
214 ret
= wcn36xx_smd_load_nv(wcn
);
216 wcn36xx_err("Failed to push NV to chip\n");
217 goto out_free_smd_buf
;
220 ret
= wcn36xx_smd_start(wcn
);
222 wcn36xx_err("Failed to start chip\n");
223 goto out_free_smd_buf
;
226 /* DMA channel initialization */
227 ret
= wcn36xx_dxe_init(wcn
);
229 wcn36xx_err("DXE init failed\n");
233 wcn36xx_debugfs_init(wcn
);
235 if (!wcn36xx_is_fw_version(wcn
, 1, 2, 2, 24)) {
236 ret
= wcn36xx_smd_feature_caps_exchange(wcn
);
238 wcn36xx_warn("Exchange feature caps failed\n");
240 INIT_LIST_HEAD(&wcn
->vif_list
);
244 wcn36xx_smd_stop(wcn
);
248 wcn36xx_dxe_free_mem_pools(wcn
);
250 wcn36xx_dxe_free_ctl_blks(wcn
);
252 wcn36xx_smd_close(wcn
);
257 static void wcn36xx_stop(struct ieee80211_hw
*hw
)
259 struct wcn36xx
*wcn
= hw
->priv
;
261 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac stop\n");
263 wcn36xx_debugfs_exit(wcn
);
264 wcn36xx_smd_stop(wcn
);
265 wcn36xx_dxe_deinit(wcn
);
266 wcn36xx_smd_close(wcn
);
268 wcn36xx_dxe_free_mem_pools(wcn
);
269 wcn36xx_dxe_free_ctl_blks(wcn
);
274 static int wcn36xx_config(struct ieee80211_hw
*hw
, u32 changed
)
276 struct wcn36xx
*wcn
= hw
->priv
;
277 struct ieee80211_vif
*vif
= NULL
;
278 struct wcn36xx_vif
*tmp
;
280 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac config changed 0x%08x\n", changed
);
282 if (changed
& IEEE80211_CONF_CHANGE_CHANNEL
) {
283 int ch
= WCN36XX_HW_CHANNEL(wcn
);
284 wcn36xx_dbg(WCN36XX_DBG_MAC
, "wcn36xx_config channel switch=%d\n",
286 list_for_each_entry(tmp
, &wcn
->vif_list
, list
) {
287 vif
= container_of((void *)tmp
,
288 struct ieee80211_vif
,
290 wcn36xx_smd_switch_channel(wcn
, vif
, ch
);
297 #define WCN36XX_SUPPORTED_FILTERS (0)
299 static void wcn36xx_configure_filter(struct ieee80211_hw
*hw
,
300 unsigned int changed
,
301 unsigned int *total
, u64 multicast
)
303 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac configure filter\n");
305 *total
&= WCN36XX_SUPPORTED_FILTERS
;
308 static void wcn36xx_tx(struct ieee80211_hw
*hw
,
309 struct ieee80211_tx_control
*control
,
312 struct wcn36xx
*wcn
= hw
->priv
;
313 struct wcn36xx_sta
*sta_priv
= NULL
;
316 sta_priv
= (struct wcn36xx_sta
*)control
->sta
->drv_priv
;
318 if (wcn36xx_start_tx(wcn
, sta_priv
, skb
))
319 ieee80211_free_txskb(wcn
->hw
, skb
);
322 static int wcn36xx_set_key(struct ieee80211_hw
*hw
, enum set_key_cmd cmd
,
323 struct ieee80211_vif
*vif
,
324 struct ieee80211_sta
*sta
,
325 struct ieee80211_key_conf
*key_conf
)
327 struct wcn36xx
*wcn
= hw
->priv
;
328 struct wcn36xx_vif
*vif_priv
= (struct wcn36xx_vif
*)vif
->drv_priv
;
329 struct wcn36xx_sta
*sta_priv
= vif_priv
->sta
;
331 u8 key
[WLAN_MAX_KEY_LEN
];
333 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac80211 set key\n");
334 wcn36xx_dbg(WCN36XX_DBG_MAC
, "Key: cmd=0x%x algo:0x%x, id:%d, len:%d flags 0x%x\n",
335 cmd
, key_conf
->cipher
, key_conf
->keyidx
,
336 key_conf
->keylen
, key_conf
->flags
);
337 wcn36xx_dbg_dump(WCN36XX_DBG_MAC
, "KEY: ",
341 switch (key_conf
->cipher
) {
342 case WLAN_CIPHER_SUITE_WEP40
:
343 vif_priv
->encrypt_type
= WCN36XX_HAL_ED_WEP40
;
345 case WLAN_CIPHER_SUITE_WEP104
:
346 vif_priv
->encrypt_type
= WCN36XX_HAL_ED_WEP40
;
348 case WLAN_CIPHER_SUITE_CCMP
:
349 vif_priv
->encrypt_type
= WCN36XX_HAL_ED_CCMP
;
351 case WLAN_CIPHER_SUITE_TKIP
:
352 vif_priv
->encrypt_type
= WCN36XX_HAL_ED_TKIP
;
355 wcn36xx_err("Unsupported key type 0x%x\n",
363 if (WCN36XX_HAL_ED_TKIP
== vif_priv
->encrypt_type
) {
365 * Supplicant is sending key in the wrong order:
366 * Temporal Key (16 b) - TX MIC (8 b) - RX MIC (8 b)
367 * but HW expects it to be in the order as described in
368 * IEEE 802.11 spec (see chapter 11.7) like this:
369 * Temporal Key (16 b) - RX MIC (8 b) - TX MIC (8 b)
371 memcpy(key
, key_conf
->key
, 16);
372 memcpy(key
+ 16, key_conf
->key
+ 24, 8);
373 memcpy(key
+ 24, key_conf
->key
+ 16, 8);
375 memcpy(key
, key_conf
->key
, key_conf
->keylen
);
378 if (IEEE80211_KEY_FLAG_PAIRWISE
& key_conf
->flags
) {
379 sta_priv
->is_data_encrypted
= true;
380 /* Reconfigure bss with encrypt_type */
381 if (NL80211_IFTYPE_STATION
== vif
->type
)
382 wcn36xx_smd_config_bss(wcn
,
388 wcn36xx_smd_set_stakey(wcn
,
389 vif_priv
->encrypt_type
,
393 get_sta_index(vif
, sta_priv
));
395 wcn36xx_smd_set_bsskey(wcn
,
396 vif_priv
->encrypt_type
,
400 if ((WLAN_CIPHER_SUITE_WEP40
== key_conf
->cipher
) ||
401 (WLAN_CIPHER_SUITE_WEP104
== key_conf
->cipher
)) {
402 sta_priv
->is_data_encrypted
= true;
403 wcn36xx_smd_set_stakey(wcn
,
404 vif_priv
->encrypt_type
,
408 get_sta_index(vif
, sta_priv
));
413 if (!(IEEE80211_KEY_FLAG_PAIRWISE
& key_conf
->flags
)) {
414 wcn36xx_smd_remove_bsskey(wcn
,
415 vif_priv
->encrypt_type
,
418 sta_priv
->is_data_encrypted
= false;
419 /* do not remove key if disassociated */
421 wcn36xx_smd_remove_stakey(wcn
,
422 vif_priv
->encrypt_type
,
424 get_sta_index(vif
, sta_priv
));
428 wcn36xx_err("Unsupported key cmd 0x%x\n", cmd
);
438 static void wcn36xx_sw_scan_start(struct ieee80211_hw
*hw
)
440 struct wcn36xx
*wcn
= hw
->priv
;
442 wcn36xx_smd_init_scan(wcn
, HAL_SYS_MODE_SCAN
);
443 wcn36xx_smd_start_scan(wcn
);
446 static void wcn36xx_sw_scan_complete(struct ieee80211_hw
*hw
)
448 struct wcn36xx
*wcn
= hw
->priv
;
450 wcn36xx_smd_end_scan(wcn
);
451 wcn36xx_smd_finish_scan(wcn
, HAL_SYS_MODE_SCAN
);
454 static void wcn36xx_update_allowed_rates(struct ieee80211_sta
*sta
,
455 enum ieee80211_band band
)
459 struct wcn36xx_sta
*sta_priv
= (struct wcn36xx_sta
*)sta
->drv_priv
;
460 u32 rates
= sta
->supp_rates
[band
];
462 memset(&sta_priv
->supported_rates
, 0,
463 sizeof(sta_priv
->supported_rates
));
464 sta_priv
->supported_rates
.op_rate_mode
= STA_11n
;
466 size
= ARRAY_SIZE(sta_priv
->supported_rates
.dsss_rates
);
467 rates_table
= sta_priv
->supported_rates
.dsss_rates
;
468 if (band
== IEEE80211_BAND_2GHZ
) {
469 for (i
= 0; i
< size
; i
++) {
471 rates_table
[i
] = wcn_2ghz_rates
[i
].hw_value
;
477 size
= ARRAY_SIZE(sta_priv
->supported_rates
.ofdm_rates
);
478 rates_table
= sta_priv
->supported_rates
.ofdm_rates
;
479 for (i
= 0; i
< size
; i
++) {
481 rates_table
[i
] = wcn_5ghz_rates
[i
].hw_value
;
486 if (sta
->ht_cap
.ht_supported
) {
487 BUILD_BUG_ON(sizeof(sta
->ht_cap
.mcs
.rx_mask
) >
488 sizeof(sta_priv
->supported_rates
.supported_mcs_set
));
489 memcpy(sta_priv
->supported_rates
.supported_mcs_set
,
490 sta
->ht_cap
.mcs
.rx_mask
,
491 sizeof(sta
->ht_cap
.mcs
.rx_mask
));
494 void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates
*rates
)
496 u16 ofdm_rates
[WCN36XX_HAL_NUM_OFDM_RATES
] = {
499 HW_RATE_INDEX_12MBPS
,
500 HW_RATE_INDEX_18MBPS
,
501 HW_RATE_INDEX_24MBPS
,
502 HW_RATE_INDEX_36MBPS
,
503 HW_RATE_INDEX_48MBPS
,
506 u16 dsss_rates
[WCN36XX_HAL_NUM_DSSS_RATES
] = {
509 HW_RATE_INDEX_5_5MBPS
,
513 rates
->op_rate_mode
= STA_11n
;
514 memcpy(rates
->dsss_rates
, dsss_rates
,
515 sizeof(*dsss_rates
) * WCN36XX_HAL_NUM_DSSS_RATES
);
516 memcpy(rates
->ofdm_rates
, ofdm_rates
,
517 sizeof(*ofdm_rates
) * WCN36XX_HAL_NUM_OFDM_RATES
);
518 rates
->supported_mcs_set
[0] = 0xFF;
520 static void wcn36xx_bss_info_changed(struct ieee80211_hw
*hw
,
521 struct ieee80211_vif
*vif
,
522 struct ieee80211_bss_conf
*bss_conf
,
525 struct wcn36xx
*wcn
= hw
->priv
;
526 struct sk_buff
*skb
= NULL
;
527 u16 tim_off
, tim_len
;
528 enum wcn36xx_hal_link_state link_state
;
529 struct wcn36xx_vif
*vif_priv
= (struct wcn36xx_vif
*)vif
->drv_priv
;
531 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac bss info changed vif %p changed 0x%08x\n",
534 if (changed
& BSS_CHANGED_BEACON_INFO
) {
535 wcn36xx_dbg(WCN36XX_DBG_MAC
,
536 "mac bss changed dtim period %d\n",
537 bss_conf
->dtim_period
);
539 vif_priv
->dtim_period
= bss_conf
->dtim_period
;
542 if (changed
& BSS_CHANGED_PS
) {
543 wcn36xx_dbg(WCN36XX_DBG_MAC
,
544 "mac bss PS set %d\n",
547 wcn36xx_pmc_enter_bmps_state(wcn
, vif
);
549 wcn36xx_pmc_exit_bmps_state(wcn
, vif
);
553 if (changed
& BSS_CHANGED_BSSID
) {
554 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac bss changed_bssid %pM\n",
557 if (!is_zero_ether_addr(bss_conf
->bssid
)) {
558 vif_priv
->is_joining
= true;
559 vif_priv
->bss_index
= 0xff;
560 wcn36xx_smd_join(wcn
, bss_conf
->bssid
,
561 vif
->addr
, WCN36XX_HW_CHANNEL(wcn
));
562 wcn36xx_smd_config_bss(wcn
, vif
, NULL
,
563 bss_conf
->bssid
, false);
565 vif_priv
->is_joining
= false;
566 wcn36xx_smd_delete_bss(wcn
, vif
);
570 if (changed
& BSS_CHANGED_SSID
) {
571 wcn36xx_dbg(WCN36XX_DBG_MAC
,
572 "mac bss changed ssid\n");
573 wcn36xx_dbg_dump(WCN36XX_DBG_MAC
, "ssid ",
574 bss_conf
->ssid
, bss_conf
->ssid_len
);
576 vif_priv
->ssid
.length
= bss_conf
->ssid_len
;
577 memcpy(&vif_priv
->ssid
.ssid
,
582 if (changed
& BSS_CHANGED_ASSOC
) {
583 vif_priv
->is_joining
= false;
584 if (bss_conf
->assoc
) {
585 struct ieee80211_sta
*sta
;
586 struct wcn36xx_sta
*sta_priv
;
588 wcn36xx_dbg(WCN36XX_DBG_MAC
,
589 "mac assoc bss %pM vif %pM AID=%d\n",
595 sta
= ieee80211_find_sta(vif
, bss_conf
->bssid
);
597 wcn36xx_err("sta %pM is not found\n",
602 sta_priv
= (struct wcn36xx_sta
*)sta
->drv_priv
;
604 wcn36xx_update_allowed_rates(sta
, WCN36XX_BAND(wcn
));
606 wcn36xx_smd_set_link_st(wcn
, bss_conf
->bssid
,
608 WCN36XX_HAL_LINK_POSTASSOC_STATE
);
609 wcn36xx_smd_config_bss(wcn
, vif
, sta
,
612 sta_priv
->aid
= bss_conf
->aid
;
614 * config_sta must be called from because this is the
615 * place where AID is available.
617 wcn36xx_smd_config_sta(wcn
, vif
, sta
);
620 wcn36xx_dbg(WCN36XX_DBG_MAC
,
621 "disassociated bss %pM vif %pM AID=%d\n",
625 wcn36xx_smd_set_link_st(wcn
,
628 WCN36XX_HAL_LINK_IDLE_STATE
);
632 if (changed
& BSS_CHANGED_AP_PROBE_RESP
) {
633 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac bss changed ap probe resp\n");
634 skb
= ieee80211_proberesp_get(hw
, vif
);
636 wcn36xx_err("failed to alloc probereq skb\n");
640 wcn36xx_smd_update_proberesp_tmpl(wcn
, vif
, skb
);
644 if (changed
& BSS_CHANGED_BEACON_ENABLED
||
645 changed
& BSS_CHANGED_BEACON
) {
646 wcn36xx_dbg(WCN36XX_DBG_MAC
,
647 "mac bss changed beacon enabled %d\n",
648 bss_conf
->enable_beacon
);
650 if (bss_conf
->enable_beacon
) {
651 vif_priv
->bss_index
= 0xff;
652 wcn36xx_smd_config_bss(wcn
, vif
, NULL
,
654 skb
= ieee80211_beacon_get_tim(hw
, vif
, &tim_off
,
657 wcn36xx_err("failed to alloc beacon skb\n");
660 wcn36xx_smd_send_beacon(wcn
, vif
, skb
, tim_off
, 0);
663 if (vif
->type
== NL80211_IFTYPE_ADHOC
||
664 vif
->type
== NL80211_IFTYPE_MESH_POINT
)
665 link_state
= WCN36XX_HAL_LINK_IBSS_STATE
;
667 link_state
= WCN36XX_HAL_LINK_AP_STATE
;
669 wcn36xx_smd_set_link_st(wcn
, vif
->addr
, vif
->addr
,
672 wcn36xx_smd_set_link_st(wcn
, vif
->addr
, vif
->addr
,
673 WCN36XX_HAL_LINK_IDLE_STATE
);
674 wcn36xx_smd_delete_bss(wcn
, vif
);
681 /* this is required when using IEEE80211_HW_HAS_RATE_CONTROL */
682 static int wcn36xx_set_rts_threshold(struct ieee80211_hw
*hw
, u32 value
)
684 struct wcn36xx
*wcn
= hw
->priv
;
685 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac set RTS threshold %d\n", value
);
687 wcn36xx_smd_update_cfg(wcn
, WCN36XX_HAL_CFG_RTS_THRESHOLD
, value
);
691 static void wcn36xx_remove_interface(struct ieee80211_hw
*hw
,
692 struct ieee80211_vif
*vif
)
694 struct wcn36xx
*wcn
= hw
->priv
;
695 struct wcn36xx_vif
*vif_priv
= (struct wcn36xx_vif
*)vif
->drv_priv
;
696 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac remove interface vif %p\n", vif
);
698 list_del(&vif_priv
->list
);
699 wcn36xx_smd_delete_sta_self(wcn
, vif
->addr
);
702 static int wcn36xx_add_interface(struct ieee80211_hw
*hw
,
703 struct ieee80211_vif
*vif
)
705 struct wcn36xx
*wcn
= hw
->priv
;
706 struct wcn36xx_vif
*vif_priv
= (struct wcn36xx_vif
*)vif
->drv_priv
;
708 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac add interface vif %p type %d\n",
711 if (!(NL80211_IFTYPE_STATION
== vif
->type
||
712 NL80211_IFTYPE_AP
== vif
->type
||
713 NL80211_IFTYPE_ADHOC
== vif
->type
||
714 NL80211_IFTYPE_MESH_POINT
== vif
->type
)) {
715 wcn36xx_warn("Unsupported interface type requested: %d\n",
720 list_add(&vif_priv
->list
, &wcn
->vif_list
);
721 wcn36xx_smd_add_sta_self(wcn
, vif
);
726 static int wcn36xx_sta_add(struct ieee80211_hw
*hw
, struct ieee80211_vif
*vif
,
727 struct ieee80211_sta
*sta
)
729 struct wcn36xx
*wcn
= hw
->priv
;
730 struct wcn36xx_vif
*vif_priv
= (struct wcn36xx_vif
*)vif
->drv_priv
;
731 struct wcn36xx_sta
*sta_priv
= (struct wcn36xx_sta
*)sta
->drv_priv
;
732 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac sta add vif %p sta %pM\n",
735 vif_priv
->sta
= sta_priv
;
736 sta_priv
->vif
= vif_priv
;
738 * For STA mode HW will be configured on BSS_CHANGED_ASSOC because
739 * at this stage AID is not available yet.
741 if (NL80211_IFTYPE_STATION
!= vif
->type
) {
742 wcn36xx_update_allowed_rates(sta
, WCN36XX_BAND(wcn
));
743 sta_priv
->aid
= sta
->aid
;
744 wcn36xx_smd_config_sta(wcn
, vif
, sta
);
749 static int wcn36xx_sta_remove(struct ieee80211_hw
*hw
,
750 struct ieee80211_vif
*vif
,
751 struct ieee80211_sta
*sta
)
753 struct wcn36xx
*wcn
= hw
->priv
;
754 struct wcn36xx_vif
*vif_priv
= (struct wcn36xx_vif
*)vif
->drv_priv
;
755 struct wcn36xx_sta
*sta_priv
= (struct wcn36xx_sta
*)sta
->drv_priv
;
757 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac sta remove vif %p sta %pM index %d\n",
758 vif
, sta
->addr
, sta_priv
->sta_index
);
760 wcn36xx_smd_delete_sta(wcn
, sta_priv
->sta_index
);
761 vif_priv
->sta
= NULL
;
762 sta_priv
->vif
= NULL
;
768 static int wcn36xx_suspend(struct ieee80211_hw
*hw
, struct cfg80211_wowlan
*wow
)
770 struct wcn36xx
*wcn
= hw
->priv
;
772 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac suspend\n");
774 flush_workqueue(wcn
->hal_ind_wq
);
775 wcn36xx_smd_set_power_params(wcn
, true);
779 static int wcn36xx_resume(struct ieee80211_hw
*hw
)
781 struct wcn36xx
*wcn
= hw
->priv
;
783 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac resume\n");
785 flush_workqueue(wcn
->hal_ind_wq
);
786 wcn36xx_smd_set_power_params(wcn
, false);
792 static int wcn36xx_ampdu_action(struct ieee80211_hw
*hw
,
793 struct ieee80211_vif
*vif
,
794 enum ieee80211_ampdu_mlme_action action
,
795 struct ieee80211_sta
*sta
, u16 tid
, u16
*ssn
,
798 struct wcn36xx
*wcn
= hw
->priv
;
799 struct wcn36xx_sta
*sta_priv
= NULL
;
801 wcn36xx_dbg(WCN36XX_DBG_MAC
, "mac ampdu action action %d tid %d\n",
804 sta_priv
= (struct wcn36xx_sta
*)sta
->drv_priv
;
807 case IEEE80211_AMPDU_RX_START
:
809 wcn36xx_smd_add_ba_session(wcn
, sta
, tid
, ssn
, 0,
810 get_sta_index(vif
, sta_priv
));
811 wcn36xx_smd_add_ba(wcn
);
812 wcn36xx_smd_trigger_ba(wcn
, get_sta_index(vif
, sta_priv
));
813 ieee80211_start_tx_ba_session(sta
, tid
, 0);
815 case IEEE80211_AMPDU_RX_STOP
:
816 wcn36xx_smd_del_ba(wcn
, tid
, get_sta_index(vif
, sta_priv
));
818 case IEEE80211_AMPDU_TX_START
:
819 ieee80211_start_tx_ba_cb_irqsafe(vif
, sta
->addr
, tid
);
821 case IEEE80211_AMPDU_TX_OPERATIONAL
:
822 wcn36xx_smd_add_ba_session(wcn
, sta
, tid
, ssn
, 1,
823 get_sta_index(vif
, sta_priv
));
825 case IEEE80211_AMPDU_TX_STOP_FLUSH
:
826 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT
:
827 case IEEE80211_AMPDU_TX_STOP_CONT
:
828 ieee80211_stop_tx_ba_cb_irqsafe(vif
, sta
->addr
, tid
);
831 wcn36xx_err("Unknown AMPDU action\n");
837 static const struct ieee80211_ops wcn36xx_ops
= {
838 .start
= wcn36xx_start
,
839 .stop
= wcn36xx_stop
,
840 .add_interface
= wcn36xx_add_interface
,
841 .remove_interface
= wcn36xx_remove_interface
,
843 .suspend
= wcn36xx_suspend
,
844 .resume
= wcn36xx_resume
,
846 .config
= wcn36xx_config
,
847 .configure_filter
= wcn36xx_configure_filter
,
849 .set_key
= wcn36xx_set_key
,
850 .sw_scan_start
= wcn36xx_sw_scan_start
,
851 .sw_scan_complete
= wcn36xx_sw_scan_complete
,
852 .bss_info_changed
= wcn36xx_bss_info_changed
,
853 .set_rts_threshold
= wcn36xx_set_rts_threshold
,
854 .sta_add
= wcn36xx_sta_add
,
855 .sta_remove
= wcn36xx_sta_remove
,
856 .ampdu_action
= wcn36xx_ampdu_action
,
859 static int wcn36xx_init_ieee80211(struct wcn36xx
*wcn
)
863 static const u32 cipher_suites
[] = {
864 WLAN_CIPHER_SUITE_WEP40
,
865 WLAN_CIPHER_SUITE_WEP104
,
866 WLAN_CIPHER_SUITE_TKIP
,
867 WLAN_CIPHER_SUITE_CCMP
,
870 wcn
->hw
->flags
= IEEE80211_HW_SIGNAL_DBM
|
871 IEEE80211_HW_HAS_RATE_CONTROL
|
872 IEEE80211_HW_SUPPORTS_PS
|
873 IEEE80211_HW_CONNECTION_MONITOR
|
874 IEEE80211_HW_AMPDU_AGGREGATION
|
875 IEEE80211_HW_TIMING_BEACON_ONLY
;
877 wcn
->hw
->wiphy
->interface_modes
= BIT(NL80211_IFTYPE_STATION
) |
878 BIT(NL80211_IFTYPE_AP
) |
879 BIT(NL80211_IFTYPE_ADHOC
) |
880 BIT(NL80211_IFTYPE_MESH_POINT
);
882 wcn
->hw
->wiphy
->bands
[IEEE80211_BAND_2GHZ
] = &wcn_band_2ghz
;
883 wcn
->hw
->wiphy
->bands
[IEEE80211_BAND_5GHZ
] = &wcn_band_5ghz
;
885 wcn
->hw
->wiphy
->cipher_suites
= cipher_suites
;
886 wcn
->hw
->wiphy
->n_cipher_suites
= ARRAY_SIZE(cipher_suites
);
888 wcn
->hw
->wiphy
->flags
|= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD
;
891 wcn
->hw
->wiphy
->wowlan
= &wowlan_support
;
894 wcn
->hw
->max_listen_interval
= 200;
898 SET_IEEE80211_DEV(wcn
->hw
, wcn
->dev
);
900 wcn
->hw
->sta_data_size
= sizeof(struct wcn36xx_sta
);
901 wcn
->hw
->vif_data_size
= sizeof(struct wcn36xx_vif
);
906 static int wcn36xx_platform_get_resources(struct wcn36xx
*wcn
,
907 struct platform_device
*pdev
)
909 struct resource
*res
;
911 res
= platform_get_resource_byname(pdev
, IORESOURCE_IRQ
,
914 wcn36xx_err("failed to get tx_irq\n");
917 wcn
->tx_irq
= res
->start
;
920 res
= platform_get_resource_byname(pdev
, IORESOURCE_IRQ
,
923 wcn36xx_err("failed to get rx_irq\n");
926 wcn
->rx_irq
= res
->start
;
929 res
= platform_get_resource_byname(pdev
, IORESOURCE_MEM
,
932 wcn36xx_err("failed to get mmio\n");
935 wcn
->mmio
= ioremap(res
->start
, resource_size(res
));
937 wcn36xx_err("failed to map io memory\n");
943 static int wcn36xx_probe(struct platform_device
*pdev
)
945 struct ieee80211_hw
*hw
;
950 wcn36xx_dbg(WCN36XX_DBG_MAC
, "platform probe\n");
952 hw
= ieee80211_alloc_hw(sizeof(struct wcn36xx
), &wcn36xx_ops
);
954 wcn36xx_err("failed to alloc hw\n");
958 platform_set_drvdata(pdev
, hw
);
961 wcn
->dev
= &pdev
->dev
;
962 wcn
->ctrl_ops
= pdev
->dev
.platform_data
;
964 mutex_init(&wcn
->hal_mutex
);
966 if (!wcn
->ctrl_ops
->get_hw_mac(addr
)) {
967 wcn36xx_info("mac address: %pM\n", addr
);
968 SET_IEEE80211_PERM_ADDR(wcn
->hw
, addr
);
971 ret
= wcn36xx_platform_get_resources(wcn
, pdev
);
975 wcn36xx_init_ieee80211(wcn
);
976 ret
= ieee80211_register_hw(wcn
->hw
);
985 ieee80211_free_hw(hw
);
989 static int wcn36xx_remove(struct platform_device
*pdev
)
991 struct ieee80211_hw
*hw
= platform_get_drvdata(pdev
);
992 struct wcn36xx
*wcn
= hw
->priv
;
993 wcn36xx_dbg(WCN36XX_DBG_MAC
, "platform remove\n");
995 mutex_destroy(&wcn
->hal_mutex
);
997 ieee80211_unregister_hw(hw
);
999 ieee80211_free_hw(hw
);
1003 static const struct platform_device_id wcn36xx_platform_id_table
[] = {
1010 MODULE_DEVICE_TABLE(platform
, wcn36xx_platform_id_table
);
1012 static struct platform_driver wcn36xx_driver
= {
1013 .probe
= wcn36xx_probe
,
1014 .remove
= wcn36xx_remove
,
1017 .owner
= THIS_MODULE
,
1019 .id_table
= wcn36xx_platform_id_table
,
1022 static int __init
wcn36xx_init(void)
1024 platform_driver_register(&wcn36xx_driver
);
1027 module_init(wcn36xx_init
);
1029 static void __exit
wcn36xx_exit(void)
1031 platform_driver_unregister(&wcn36xx_driver
);
1033 module_exit(wcn36xx_exit
);
1035 MODULE_LICENSE("Dual BSD/GPL");
1036 MODULE_AUTHOR("Eugene Krasnikov k.eugene.e@gmail.com");
1037 MODULE_FIRMWARE(WLAN_NV_FILE
);