diff options
author | David S. Miller <davem@davemloft.net> | 2018-03-29 16:24:06 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-03-29 16:24:06 -0400 |
commit | 18845557fd6fc1998f2d0d8c30467f86db587529 (patch) | |
tree | 80e3f239192cb421b54f8e6d85c03270c5ac394d /drivers | |
parent | e15f20ea33b8e5074145abe464b4b48acea505d9 (diff) | |
parent | 14c99949a3398a655c47b262ca8e2e83edfae7fd (diff) | |
download | linux-stable-18845557fd6fc1998f2d0d8c30467f86db587529.tar.gz linux-stable-18845557fd6fc1998f2d0d8c30467f86db587529.tar.bz2 linux-stable-18845557fd6fc1998f2d0d8c30467f86db587529.zip |
Merge tag 'wireless-drivers-next-for-davem-2018-03-29' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next
Kalle Valo says:
====================
wireless-drivers-next patches for 4.17
Smaller new features to various drivers but nothing really out of
ordinary.
Major changes:
ath10k
* enable chip temperature measurement for QCA6174/QCA9377
* add firmware memory dump for QCA9984
* enable buffer STA on TDLS link for QCA6174
* support different beacon internals in multiple interface scenario
for QCA988X/QCA99X0/QCA9984/QCA4019
iwlwifi
* support for new PCI IDs for the 9000 family
* support for a new firmware API version
* support for advanced dwell and Optimized Connectivity Experience
(OCE) in scanning
btrsi
* fix kconfig dependencies
wil6210
* support multiple virtual interfaces
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
173 files changed, 6233 insertions, 2505 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index d8bbd661dbdb..149a38ee1fce 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -393,9 +393,7 @@ config BT_QCOMSMD kernel or say M to compile as a module. config BT_HCIRSI - tristate "Redpine HCI support" - default n - select RSI_COEX + tristate help Redpine BT driver. This driver handles BT traffic from upper layers and pass diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index f3f2784f6ebd..7a364eca46d6 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -33,8 +33,6 @@ */ #define ATH_KEYMAX 128 /* max key cache size we handle */ -static const u8 ath_bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - struct ath_ani { bool caldone; unsigned int longcal_timer; diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f3ec13b80b20..8a3020dbd4cf 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -2040,7 +2041,8 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS; ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; ar->fw_stats_req_mask = WMI_10_4_STAT_PEER | - WMI_10_4_STAT_PEER_EXTD; + WMI_10_4_STAT_PEER_EXTD | + WMI_10_4_STAT_VDEV_EXTD; ar->max_spatial_stream = ar->hw_params.max_spatial_stream; ar->max_num_tdls_vdevs = TARGET_10_4_NUM_TDLS_VDEVS; @@ -2281,6 +2283,9 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, if (ath10k_peer_stats_enabled(ar)) val = WMI_10_4_PEER_STATS; + /* Enable vdev stats by default */ + val |= WMI_10_4_VDEV_STATS; + if (test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map)) val |= WMI_10_4_BSS_CHANNEL_INFO_64; @@ -2439,7 +2444,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ret = ath10k_hif_power_up(ar); if (ret) { - ath10k_err(ar, "could not start pci hif (%d)\n", ret); + ath10k_err(ar, "could not power on hif bus (%d)\n", ret); return ret; } diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index fe6b30356d3b..c17d805d68cc 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -221,6 +222,27 @@ struct ath10k_fw_stats_vdev { u32 beacon_rssi_history[10]; }; +struct ath10k_fw_stats_vdev_extd { + struct list_head list; + + u32 vdev_id; + u32 ppdu_aggr_cnt; + u32 ppdu_noack; + u32 mpdu_queued; + u32 ppdu_nonaggr_cnt; + u32 mpdu_sw_requeued; + u32 mpdu_suc_retry; + u32 mpdu_suc_multitry; + u32 mpdu_fail_retry; + u32 tx_ftm_suc; + u32 tx_ftm_suc_retry; + u32 tx_ftm_fail; + u32 rx_ftmr_cnt; + u32 rx_ftmr_dup_cnt; + u32 rx_iftmr_cnt; + u32 rx_iftmr_dup_cnt; +}; + struct ath10k_fw_stats_pdev { struct list_head list; @@ -324,6 +346,27 @@ struct ath10k_tpc_stats { struct ath10k_tpc_table tpc_table[WMI_TPC_FLAG]; }; +struct ath10k_tpc_table_final { + u32 pream_idx[WMI_TPC_FINAL_RATE_MAX]; + u8 rate_code[WMI_TPC_FINAL_RATE_MAX]; + char tpc_value[WMI_TPC_FINAL_RATE_MAX][WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE]; +}; + +struct ath10k_tpc_stats_final { + u32 reg_domain; + u32 chan_freq; + u32 phy_mode; + u32 twice_antenna_reduction; + u32 twice_max_rd_power; + s32 twice_antenna_gain; + u32 power_limit; + u32 num_tx_chain; + u32 ctl; + u32 rate_max; + u8 flag[WMI_TPC_FLAG]; + struct ath10k_tpc_table_final tpc_table_final[WMI_TPC_FLAG]; +}; + struct ath10k_dfs_stats { u32 phy_errors; u32 pulses_total; @@ -354,6 +397,45 @@ struct ath10k_txq { unsigned long num_push_allowed; }; +enum ath10k_pkt_rx_err { + ATH10K_PKT_RX_ERR_FCS, + ATH10K_PKT_RX_ERR_TKIP, + ATH10K_PKT_RX_ERR_CRYPT, + ATH10K_PKT_RX_ERR_PEER_IDX_INVAL, + ATH10K_PKT_RX_ERR_MAX, +}; + +enum ath10k_ampdu_subfrm_num { + ATH10K_AMPDU_SUBFRM_NUM_10, + ATH10K_AMPDU_SUBFRM_NUM_20, + ATH10K_AMPDU_SUBFRM_NUM_30, + ATH10K_AMPDU_SUBFRM_NUM_40, + ATH10K_AMPDU_SUBFRM_NUM_50, + ATH10K_AMPDU_SUBFRM_NUM_60, + ATH10K_AMPDU_SUBFRM_NUM_MORE, + ATH10K_AMPDU_SUBFRM_NUM_MAX, +}; + +enum ath10k_amsdu_subfrm_num { + ATH10K_AMSDU_SUBFRM_NUM_1, + ATH10K_AMSDU_SUBFRM_NUM_2, + ATH10K_AMSDU_SUBFRM_NUM_3, + ATH10K_AMSDU_SUBFRM_NUM_4, + ATH10K_AMSDU_SUBFRM_NUM_MORE, + ATH10K_AMSDU_SUBFRM_NUM_MAX, +}; + +struct ath10k_sta_tid_stats { + unsigned long int rx_pkt_from_fw; + unsigned long int rx_pkt_unchained; + unsigned long int rx_pkt_drop_chained; + unsigned long int rx_pkt_drop_filter; + unsigned long int rx_pkt_err[ATH10K_PKT_RX_ERR_MAX]; + unsigned long int rx_pkt_queued_for_mac; + unsigned long int rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MAX]; + unsigned long int rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MAX]; +}; + struct ath10k_sta { struct ath10k_vif *arvif; @@ -371,6 +453,9 @@ struct ath10k_sta { #ifdef CONFIG_MAC80211_DEBUGFS /* protected by conf_mutex */ bool aggr_mode; + + /* Protected with ar->data_lock */ + struct ath10k_sta_tid_stats tid_stats[IEEE80211_NUM_TIDS + 1]; #endif }; @@ -487,6 +572,7 @@ struct ath10k_debug { /* used for tpc-dump storage, protected by data-lock */ struct ath10k_tpc_stats *tpc_stats; + struct ath10k_tpc_stats_final *tpc_stats_final; struct completion tpc_complete; @@ -1019,6 +1105,8 @@ struct ath10k { void *ce_priv; + u32 sta_tid_stats_mask; + /* must be last */ u8 drv_priv[0] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index 7173b3743b43..f90cec0ebb1c 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -701,6 +701,89 @@ static const struct ath10k_mem_region qca988x_hw20_mem_regions[] = { }, }; +static const struct ath10k_mem_region qca9984_hw10_mem_regions[] = { + { + .type = ATH10K_MEM_REGION_TYPE_DRAM, + .start = 0x400000, + .len = 0x80000, + .name = "DRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_REG, + .start = 0x98000, + .len = 0x50000, + .name = "IRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOSRAM, + .start = 0xC0000, + .len = 0x40000, + .name = "SRAM", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x30000, + .len = 0x7000, + .name = "APB REG 1", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x3f000, + .len = 0x3000, + .name = "APB REG 2", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x43000, + .len = 0x3000, + .name = "WIFI REG", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x4A000, + .len = 0x5000, + .name = "CE REG", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, + { + .type = ATH10K_MEM_REGION_TYPE_IOREG, + .start = 0x80000, + .len = 0x6000, + .name = "SOC REG", + .section_table = { + .sections = NULL, + .size = 0, + }, + }, +}; + static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { { .hw_id = QCA6174_HW_1_0_VERSION, @@ -758,6 +841,13 @@ static const struct ath10k_hw_mem_layout hw_mem_layouts[] = { .size = ARRAY_SIZE(qca988x_hw20_mem_regions), }, }, + { + .hw_id = QCA9984_HW_1_0_DEV_VERSION, + .region_table = { + .regions = qca9984_hw10_mem_regions, + .size = ARRAY_SIZE(qca9984_hw10_mem_regions), + }, + }, }; static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/coredump.h b/drivers/net/wireless/ath/ath10k/coredump.h index bfee13038e59..3baaf9d2cbcd 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.h +++ b/drivers/net/wireless/ath/ath10k/coredump.h @@ -124,6 +124,8 @@ enum ath10k_mem_region_type { ATH10K_MEM_REGION_TYPE_AXI = 3, ATH10K_MEM_REGION_TYPE_IRAM1 = 4, ATH10K_MEM_REGION_TYPE_IRAM2 = 5, + ATH10K_MEM_REGION_TYPE_IOSRAM = 6, + ATH10K_MEM_REGION_TYPE_IOREG = 7, }; /* Define a section of the region which should be copied. As not all parts diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 554cd7856cb6..bac832ce1873 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -1480,6 +1480,19 @@ void ath10k_debug_tpc_stats_process(struct ath10k *ar, spin_unlock_bh(&ar->data_lock); } +void +ath10k_debug_tpc_stats_final_process(struct ath10k *ar, + struct ath10k_tpc_stats_final *tpc_stats) +{ + spin_lock_bh(&ar->data_lock); + + kfree(ar->debug.tpc_stats_final); + ar->debug.tpc_stats_final = tpc_stats; + complete(&ar->debug.tpc_complete); + + spin_unlock_bh(&ar->data_lock); +} + static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats, unsigned int j, char *buf, size_t *len) { @@ -2143,6 +2156,137 @@ static const struct file_operations fops_fw_checksums = { .llseek = default_llseek, }; +static ssize_t ath10k_sta_tid_stats_mask_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + char buf[32]; + size_t len; + + len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->sta_tid_stats_mask); + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t ath10k_sta_tid_stats_mask_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath10k *ar = file->private_data; + char buf[32]; + ssize_t len; + u32 mask; + + len = min(count, sizeof(buf) - 1); + if (copy_from_user(buf, user_buf, len)) + return -EFAULT; + + buf[len] = '\0'; + if (kstrtoint(buf, 0, &mask)) + return -EINVAL; + + ar->sta_tid_stats_mask = mask; + + return len; +} + +static const struct file_operations fops_sta_tid_stats_mask = { + .read = ath10k_sta_tid_stats_mask_read, + .write = ath10k_sta_tid_stats_mask_write, + .open = simple_open, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +static int ath10k_debug_tpc_stats_final_request(struct ath10k *ar) +{ + int ret; + unsigned long time_left; + + lockdep_assert_held(&ar->conf_mutex); + + reinit_completion(&ar->debug.tpc_complete); + + ret = ath10k_wmi_pdev_get_tpc_table_cmdid(ar, WMI_TPC_CONFIG_PARAM); + if (ret) { + ath10k_warn(ar, "failed to request tpc table cmdid: %d\n", ret); + return ret; + } + + time_left = wait_for_completion_timeout(&ar->debug.tpc_complete, + 1 * HZ); + if (time_left == 0) + return -ETIMEDOUT; + + return 0; +} + +static int ath10k_tpc_stats_final_open(struct inode *inode, struct file *file) +{ + struct ath10k *ar = inode->i_private; + void *buf; + int ret; + + mutex_lock(&ar->conf_mutex); + + if (ar->state != ATH10K_STATE_ON) { + ret = -ENETDOWN; + goto err_unlock; + } + + buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE); + if (!buf) { + ret = -ENOMEM; + goto err_unlock; + } + + ret = ath10k_debug_tpc_stats_final_request(ar); + if (ret) { + ath10k_warn(ar, "failed to request tpc stats final: %d\n", + ret); + goto err_free; + } + + ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf); + file->private_data = buf; + + mutex_unlock(&ar->conf_mutex); + return 0; + +err_free: + vfree(buf); + +err_unlock: + mutex_unlock(&ar->conf_mutex); + return ret; +} + +static int ath10k_tpc_stats_final_release(struct inode *inode, + struct file *file) +{ + vfree(file->private_data); + + return 0; +} + +static ssize_t ath10k_tpc_stats_final_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + const char *buf = file->private_data; + unsigned int len = strlen(buf); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_tpc_stats_final = { + .open = ath10k_tpc_stats_final_open, + .release = ath10k_tpc_stats_final_release, + .read = ath10k_tpc_stats_final_read, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + int ath10k_debug_create(struct ath10k *ar) { ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN); @@ -2258,6 +2402,16 @@ int ath10k_debug_register(struct ath10k *ar) debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar, &fops_fw_checksums); + if (IS_ENABLED(CONFIG_MAC80211_DEBUGFS)) + debugfs_create_file("sta_tid_stats_mask", 0600, + ar->debug.debugfs_phy, + ar, &fops_sta_tid_stats_mask); + + if (test_bit(WMI_SERVICE_TPC_STATS_FINAL, ar->wmi.svc_map)) + debugfs_create_file("tpc_stats_final", 0400, + ar->debug.debugfs_phy, ar, + &fops_tpc_stats_final); + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h index e54308889e59..0afca5c106b6 100644 --- a/drivers/net/wireless/ath/ath10k/debug.h +++ b/drivers/net/wireless/ath/ath10k/debug.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -101,6 +102,9 @@ void ath10k_debug_unregister(struct ath10k *ar); void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb); void ath10k_debug_tpc_stats_process(struct ath10k *ar, struct ath10k_tpc_stats *tpc_stats); +void +ath10k_debug_tpc_stats_final_process(struct ath10k *ar, + struct ath10k_tpc_stats_final *tpc_stats); void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len); #define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++) @@ -164,6 +168,13 @@ static inline void ath10k_debug_tpc_stats_process(struct ath10k *ar, kfree(tpc_stats); } +static inline void +ath10k_debug_tpc_stats_final_process(struct ath10k *ar, + struct ath10k_tpc_stats_final *tpc_stats) +{ + kfree(tpc_stats); +} + static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len) { @@ -191,12 +202,42 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); void ath10k_sta_update_rx_duration(struct ath10k *ar, struct ath10k_fw_stats *stats); +void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr, + unsigned long int num_msdus, + enum ath10k_pkt_rx_err err, + unsigned long int unchain_cnt, + unsigned long int drop_cnt, + unsigned long int drop_cnt_filter, + unsigned long int queued_msdus); +void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, + u16 peer_id, u8 tid, + struct htt_rx_indication_mpdu_range *ranges, + int num_ranges); #else static inline void ath10k_sta_update_rx_duration(struct ath10k *ar, struct ath10k_fw_stats *stats) { } + +static inline +void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr, + unsigned long int num_msdus, + enum ath10k_pkt_rx_err err, + unsigned long int unchain_cnt, + unsigned long int drop_cnt, + unsigned long int drop_cnt_filter, + unsigned long int queued_msdus) +{ +} + +static inline +void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, + u16 peer_id, u8 tid, + struct htt_rx_indication_mpdu_range *ranges, + int num_ranges) +{ +} #endif /* CONFIG_MAC80211_DEBUGFS */ #ifdef CONFIG_ATH10K_DEBUG diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index b260b09dd4d3..8f688f136c22 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -16,8 +17,125 @@ #include "core.h" #include "wmi-ops.h" +#include "txrx.h" #include "debug.h" +static void ath10k_rx_stats_update_amsdu_subfrm(struct ath10k *ar, + struct ath10k_sta_tid_stats *stats, + u32 msdu_count) +{ + if (msdu_count == 1) + stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_1]++; + else if (msdu_count == 2) + stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_2]++; + else if (msdu_count == 3) + stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_3]++; + else if (msdu_count == 4) + stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_4]++; + else if (msdu_count > 4) + stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MORE]++; +} + +static void ath10k_rx_stats_update_ampdu_subfrm(struct ath10k *ar, + struct ath10k_sta_tid_stats *stats, + u32 mpdu_count) +{ + if (mpdu_count <= 10) + stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_10]++; + else if (mpdu_count <= 20) + stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_20]++; + else if (mpdu_count <= 30) + stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_30]++; + else if (mpdu_count <= 40) + stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_40]++; + else if (mpdu_count <= 50) + stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_50]++; + else if (mpdu_count <= 60) + stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_60]++; + else if (mpdu_count > 60) + stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MORE]++; +} + +void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid, + struct htt_rx_indication_mpdu_range *ranges, + int num_ranges) +{ + struct ath10k_sta *arsta; + struct ath10k_peer *peer; + int i; + + if (tid > IEEE80211_NUM_TIDS || !(ar->sta_tid_stats_mask & BIT(tid))) + return; + + rcu_read_lock(); + spin_lock_bh(&ar->data_lock); + + peer = ath10k_peer_find_by_id(ar, peer_id); + if (!peer) + goto out; + + arsta = (struct ath10k_sta *)peer->sta->drv_priv; + + for (i = 0; i < num_ranges; i++) + ath10k_rx_stats_update_ampdu_subfrm(ar, + &arsta->tid_stats[tid], + ranges[i].mpdu_count); + +out: + spin_unlock_bh(&ar->data_lock); + rcu_read_unlock(); +} + +void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr, + unsigned long int num_msdus, + enum ath10k_pkt_rx_err err, + unsigned long int unchain_cnt, + unsigned long int drop_cnt, + unsigned long int drop_cnt_filter, + unsigned long int queued_msdus) +{ + struct ieee80211_sta *sta; + struct ath10k_sta *arsta; + struct ieee80211_hdr *hdr; + struct ath10k_sta_tid_stats *stats; + u8 tid = IEEE80211_NUM_TIDS; + bool non_data_frm = false; + + hdr = (struct ieee80211_hdr *)first_hdr; + if (!ieee80211_is_data(hdr->frame_control)) + non_data_frm = true; + + if (ieee80211_is_data_qos(hdr->frame_control)) + tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; + + if (!(ar->sta_tid_stats_mask & BIT(tid)) || non_data_frm) + return; + + rcu_read_lock(); + + sta = ieee80211_find_sta_by_ifaddr(ar->hw, hdr->addr2, NULL); + if (!sta) + goto exit; + + arsta = (struct ath10k_sta *)sta->drv_priv; + + spin_lock_bh(&ar->data_lock); + stats = &arsta->tid_stats[tid]; + stats->rx_pkt_from_fw += num_msdus; + stats->rx_pkt_unchained += unchain_cnt; + stats->rx_pkt_drop_chained += drop_cnt; + stats->rx_pkt_drop_filter += drop_cnt_filter; + if (err != ATH10K_PKT_RX_ERR_MAX) + stats->rx_pkt_err[err] += queued_msdus; + stats->rx_pkt_queued_for_mac += queued_msdus; + ath10k_rx_stats_update_amsdu_subfrm(ar, &arsta->tid_stats[tid], + num_msdus); + spin_unlock_bh(&ar->data_lock); + +exit: + rcu_read_unlock(); +} + static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar, struct ath10k_fw_stats *stats) { @@ -342,6 +460,172 @@ static const struct file_operations fops_peer_debug_trigger = { .llseek = default_llseek, }; +static char *get_err_str(enum ath10k_pkt_rx_err i) +{ + switch (i) { + case ATH10K_PKT_RX_ERR_FCS: + return "fcs_err"; + case ATH10K_PKT_RX_ERR_TKIP: + return "tkip_err"; + case ATH10K_PKT_RX_ERR_CRYPT: + return "crypt_err"; + case ATH10K_PKT_RX_ERR_PEER_IDX_INVAL: + return "peer_idx_inval"; + case ATH10K_PKT_RX_ERR_MAX: + return "unknown"; + } + + return "unknown"; +} + +static char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i) +{ + switch (i) { + case ATH10K_AMPDU_SUBFRM_NUM_10: + return "upto 10"; + case ATH10K_AMPDU_SUBFRM_NUM_20: + return "11-20"; + case ATH10K_AMPDU_SUBFRM_NUM_30: + return "21-30"; + case ATH10K_AMPDU_SUBFRM_NUM_40: + return "31-40"; + case ATH10K_AMPDU_SUBFRM_NUM_50: + return "41-50"; + case ATH10K_AMPDU_SUBFRM_NUM_60: + return "51-60"; + case ATH10K_AMPDU_SUBFRM_NUM_MORE: + return ">60"; + case ATH10K_AMPDU_SUBFRM_NUM_MAX: + return "0"; + } + + return "0"; +} + +static char *get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i) +{ + switch (i) { + case ATH10K_AMSDU_SUBFRM_NUM_1: + return "1"; + case ATH10K_AMSDU_SUBFRM_NUM_2: + return "2"; + case ATH10K_AMSDU_SUBFRM_NUM_3: + return "3"; + case ATH10K_AMSDU_SUBFRM_NUM_4: + return "4"; + case ATH10K_AMSDU_SUBFRM_NUM_MORE: + return ">4"; + case ATH10K_AMSDU_SUBFRM_NUM_MAX: + return "0"; + } + + return "0"; +} + +#define PRINT_TID_STATS(_field, _tabs) \ + do { \ + int k = 0; \ + for (j = 0; j <= IEEE80211_NUM_TIDS; j++) { \ + if (ar->sta_tid_stats_mask & BIT(j)) { \ + len += scnprintf(buf + len, buf_len - len, \ + "[%02d] %-10lu ", \ + j, stats[j]._field); \ + k++; \ + if (k % 8 == 0) { \ + len += scnprintf(buf + len, \ + buf_len - len, "\n"); \ + len += scnprintf(buf + len, \ + buf_len - len, \ + _tabs); \ + } \ + } \ + } \ + len += scnprintf(buf + len, buf_len - len, "\n"); \ + } while (0) + +static ssize_t ath10k_dbg_sta_read_tid_stats(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_sta *sta = file->private_data; + struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k *ar = arsta->arvif->ar; + struct ath10k_sta_tid_stats *stats = arsta->tid_stats; + size_t len = 0, buf_len = 1048 * IEEE80211_NUM_TIDS; + char *buf; + int i, j; + ssize_t ret; + + buf = kzalloc(buf_len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&ar->conf_mutex); + + spin_lock_bh(&ar->data_lock); + + len += scnprintf(buf + len, buf_len - len, + "\n\t\tDriver Rx pkt stats per tid, ([tid] count)\n"); + len += scnprintf(buf + len, buf_len - len, + "\t\t------------------------------------------\n"); + len += scnprintf(buf + len, buf_len - len, "MSDUs from FW\t\t\t"); + PRINT_TID_STATS(rx_pkt_from_fw, "\t\t\t\t"); + + len += scnprintf(buf + len, buf_len - len, "MSDUs unchained\t\t\t"); + PRINT_TID_STATS(rx_pkt_unchained, "\t\t\t\t"); + + len += scnprintf(buf + len, buf_len - len, + "MSDUs locally dropped:chained\t"); + PRINT_TID_STATS(rx_pkt_drop_chained, "\t\t\t\t"); + + len += scnprintf(buf + len, buf_len - len, + "MSDUs locally dropped:filtered\t"); + PRINT_TID_STATS(rx_pkt_drop_filter, "\t\t\t\t"); + + len += scnprintf(buf + len, buf_len - len, + "MSDUs queued for mac80211\t"); + PRINT_TID_STATS(rx_pkt_queued_for_mac, "\t\t\t\t"); + + for (i = 0; i < ATH10K_PKT_RX_ERR_MAX; i++) { + len += scnprintf(buf + len, buf_len - len, + "MSDUs with error:%s\t", get_err_str(i)); + PRINT_TID_STATS(rx_pkt_err[i], "\t\t\t\t"); + } + + len += scnprintf(buf + len, buf_len - len, "\n"); + for (i = 0; i < ATH10K_AMPDU_SUBFRM_NUM_MAX; i++) { + len += scnprintf(buf + len, buf_len - len, + "A-MPDU num subframes %s\t", + get_num_ampdu_subfrm_str(i)); + PRINT_TID_STATS(rx_pkt_ampdu[i], "\t\t\t\t"); + } + + len += scnprintf(buf + len, buf_len - len, "\n"); + for (i = 0; i < ATH10K_AMSDU_SUBFRM_NUM_MAX; i++) { + len += scnprintf(buf + len, buf_len - len, + "A-MSDU num subframes %s\t\t", + get_num_amsdu_subfrm_str(i)); + PRINT_TID_STATS(rx_pkt_amsdu[i], "\t\t\t\t"); + } + + spin_unlock_bh(&ar->data_lock); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); + + kfree(buf); + + mutex_unlock(&ar->conf_mutex); + + return ret; +} + +static const struct file_operations fops_tid_stats_dump = { + .open = simple_open, + .read = ath10k_dbg_sta_read_tid_stats, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir) { @@ -351,4 +635,6 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, debugfs_create_file("delba", 0200, dir, sta, &fops_delba); debugfs_create_file("peer_debug_trigger", 0600, dir, sta, &fops_peer_debug_trigger); + debugfs_create_file("dump_tid_stats", 0400, dir, sta, + &fops_tid_stats_dump); } diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 6d96f9560950..5e02e26158f6 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -723,6 +724,28 @@ struct amsdu_subframe_hdr { #define GROUP_ID_IS_SU_MIMO(x) ((x) == 0 || (x) == 63) +static inline u8 ath10k_bw_to_mac80211_bw(u8 bw) +{ + u8 ret = 0; + + switch (bw) { + case 0: + ret = RATE_INFO_BW_20; + break; + case 1: + ret = RATE_INFO_BW_40; + break; + case 2: + ret = RATE_INFO_BW_80; + break; + case 3: + ret = RATE_INFO_BW_160; + break; + } + + return ret; +} + static void ath10k_htt_rx_h_rates(struct ath10k *ar, struct ieee80211_rx_status *status, struct htt_rx_desc *rxd) @@ -825,23 +848,7 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar, if (sgi) status->enc_flags |= RX_ENC_FLAG_SHORT_GI; - switch (bw) { - /* 20MHZ */ - case 0: - break; - /* 40MHZ */ - case 1: - status->bw = RATE_INFO_BW_40; - break; - /* 80MHZ */ - case 2: - status->bw = RATE_INFO_BW_80; - break; - case 3: - status->bw = RATE_INFO_BW_160; - break; - } - + status->bw = ath10k_bw_to_mac80211_bw(bw); status->encoding = RX_ENC_VHT; break; default: @@ -1502,7 +1509,9 @@ static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu) static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, struct sk_buff_head *amsdu, struct ieee80211_rx_status *status, - bool fill_crypt_header) + bool fill_crypt_header, + u8 *rx_hdr, + enum ath10k_pkt_rx_err *err) { struct sk_buff *first; struct sk_buff *last; @@ -1538,6 +1547,9 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, hdr = (void *)rxd->rx_hdr_status; memcpy(first_hdr, hdr, RX_HTT_HDR_STATUS_LEN); + if (rx_hdr) + memcpy(rx_hdr, hdr, RX_HTT_HDR_STATUS_LEN); + /* Each A-MSDU subframe will use the original header as the base and be * reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl. */ @@ -1581,6 +1593,17 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, if (has_tkip_err) status->flag |= RX_FLAG_MMIC_ERROR; + if (err) { + if (has_fcs_err) + *err = ATH10K_PKT_RX_ERR_FCS; + else if (has_tkip_err) + *err = ATH10K_PKT_RX_ERR_TKIP; + else if (has_crypto_err) + *err = ATH10K_PKT_RX_ERR_CRYPT; + else if (has_peer_idx_invalid) + *err = ATH10K_PKT_RX_ERR_PEER_IDX_INVAL; + } + /* Firmware reports all necessary management frames via WMI already. * They are not reported to monitor interfaces at all so pass the ones * coming via HTT to monitor interfaces instead. This simplifies @@ -1651,11 +1674,13 @@ static void ath10k_htt_rx_h_enqueue(struct ath10k *ar, } } -static int ath10k_unchain_msdu(struct sk_buff_head *amsdu) +static int ath10k_unchain_msdu(struct sk_buff_head *amsdu, + unsigned long int *unchain_cnt) { struct sk_buff *skb, *first; int space; int total_len = 0; + int amsdu_len = skb_queue_len(amsdu); /* TODO: Might could optimize this by using * skb_try_coalesce or similar method to @@ -1691,11 +1716,16 @@ static int ath10k_unchain_msdu(struct sk_buff_head *amsdu) } __skb_queue_head(amsdu, first); + + *unchain_cnt += amsdu_len - 1; + return 0; } static void ath10k_htt_rx_h_unchain(struct ath10k *ar, - struct sk_buff_head *amsdu) + struct sk_buff_head *amsdu, + unsigned long int *drop_cnt, + unsigned long int *unchain_cnt) { struct sk_buff *first; struct htt_rx_desc *rxd; @@ -1713,11 +1743,12 @@ static void ath10k_htt_rx_h_unchain(struct ath10k *ar, */ if (decap != RX_MSDU_DECAP_RAW || skb_queue_len(amsdu) != 1 + rxd->frag_info.ring2_more_count) { + *drop_cnt += skb_queue_len(amsdu); __skb_queue_purge(amsdu); return; } - ath10k_unchain_msdu(amsdu); + ath10k_unchain_msdu(amsdu, unchain_cnt); } static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, @@ -1743,7 +1774,8 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, static void ath10k_htt_rx_h_filter(struct ath10k *ar, struct sk_buff_head *amsdu, - struct ieee80211_rx_status *rx_status) + struct ieee80211_rx_status *rx_status, + unsigned long int *drop_cnt) { if (skb_queue_empty(amsdu)) return; @@ -1751,6 +1783,9 @@ static void ath10k_htt_rx_h_filter(struct ath10k *ar, if (ath10k_htt_rx_amsdu_allowed(ar, amsdu, rx_status)) return; + if (drop_cnt) + *drop_cnt += skb_queue_len(amsdu); + __skb_queue_purge(amsdu); } @@ -1760,6 +1795,12 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt) struct ieee80211_rx_status *rx_status = &htt->rx_status; struct sk_buff_head amsdu; int ret; + unsigned long int drop_cnt = 0; + unsigned long int unchain_cnt = 0; + unsigned long int drop_cnt_filter = 0; + unsigned long int msdus_to_queue, num_msdus; + enum ath10k_pkt_rx_err err = ATH10K_PKT_RX_ERR_MAX; + u8 first_hdr[RX_HTT_HDR_STATUS_LEN]; __skb_queue_head_init(&amsdu); @@ -1781,16 +1822,23 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt) return ret; } + num_msdus = skb_queue_len(&amsdu); + ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff); /* only for ret = 1 indicates chained msdus */ if (ret > 0) - ath10k_htt_rx_h_unchain(ar, &amsdu); + ath10k_htt_rx_h_unchain(ar, &amsdu, &drop_cnt, &unchain_cnt); - ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); - ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true); + ath10k_htt_rx_h_filter(ar, &amsdu, rx_status, &drop_cnt_filter); + ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err); + msdus_to_queue = skb_queue_len(&amsdu); ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status); + ath10k_sta_update_rx_tid_stats(ar, first_hdr, num_msdus, err, + unchain_cnt, drop_cnt, drop_cnt_filter, + msdus_to_queue); + return 0; } @@ -1801,9 +1849,14 @@ static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt, struct htt_rx_indication_mpdu_range *mpdu_ranges; int num_mpdu_ranges; int i, mpdu_count = 0; + u16 peer_id; + u8 tid; num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1), HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES); + peer_id = __le16_to_cpu(rx->hdr.peer_id); + tid = MS(rx->hdr.info0, HTT_RX_INDICATION_INFO0_EXT_TID); + mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx); ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ", @@ -1815,6 +1868,9 @@ static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt, mpdu_count += mpdu_ranges[i].mpdu_count; atomic_add(mpdu_count, &htt->num_mpdus_ready); + + ath10k_sta_update_rx_tid_stats_ampdu(ar, peer_id, tid, mpdu_ranges, + num_mpdu_ranges); } static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar, @@ -2124,8 +2180,9 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) * should still give an idea about rx rate to the user. */ ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id); - ath10k_htt_rx_h_filter(ar, &amsdu, status); - ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false); + ath10k_htt_rx_h_filter(ar, &amsdu, status, NULL); + ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false, NULL, + NULL); ath10k_htt_rx_h_enqueue(ar, &amsdu, status); break; case -EAGAIN: @@ -2499,7 +2556,7 @@ ath10k_update_per_peer_tx_stats(struct ath10k *ar, arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; arsta->txrate.nss = txrate.nss; - arsta->txrate.bw = txrate.bw + RATE_INFO_BW_20; + arsta->txrate.bw = ath10k_bw_to_mac80211_bw(txrate.bw); } static void ath10k_htt_fetch_peer_stats(struct ath10k *ar, diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index ebb3f1b046f3..bf05a3689558 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -2976,7 +2977,7 @@ static int ath10k_station_assoc(struct ath10k *ar, } /* Plumb cached keys only for static WEP */ - if (arvif->def_wep_key_idx != -1) { + if ((arvif->def_wep_key_idx != -1) && (!sta->tdls)) { ret = ath10k_install_peer_wep_keys(arvif, sta->addr); if (ret) { ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n", @@ -3808,6 +3809,7 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) { struct ath10k *ar = container_of(work, struct ath10k, wmi_mgmt_tx_work); struct sk_buff *skb; + dma_addr_t paddr; int ret; for (;;) { @@ -3815,11 +3817,27 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) if (!skb) break; - ret = ath10k_wmi_mgmt_tx(ar, skb); - if (ret) { - ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n", - ret); - ieee80211_free_txskb(ar->hw, skb); + if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF, + ar->running_fw->fw_file.fw_features)) { + paddr = dma_map_single(ar->dev, skb->data, + skb->len, DMA_TO_DEVICE); + if (!paddr) + continue; + ret = ath10k_wmi_mgmt_tx_send(ar, skb, paddr); + if (ret) { + ath10k_warn(ar, "failed to transmit management frame by ref via WMI: %d\n", + ret); + dma_unmap_single(ar->dev, paddr, skb->len, + DMA_FROM_DEVICE); + ieee80211_free_txskb(ar->hw, skb); + } + } else { + ret = ath10k_wmi_mgmt_tx(ar, skb); + if (ret) { + ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n", + ret); + ieee80211_free_txskb(ar->hw, skb); + } } } } @@ -5914,6 +5932,10 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, ath10k_warn(ar, "Peer %pM disappeared!\n", peer_addr); spin_unlock_bh(&ar->data_lock); + if (sta && sta->tdls) + ath10k_wmi_peer_set_param(ar, arvif->vdev_id, sta->addr, + WMI_PEER_AUTHORIZE, 1); + exit: mutex_unlock(&ar->conf_mutex); return ret; @@ -6028,9 +6050,8 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk) sta->addr, smps, err); } - if (changed & IEEE80211_RC_SUPP_RATES_CHANGED || - changed & IEEE80211_RC_NSS_CHANGED) { - ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n", + if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) { + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n", sta->addr); err = ath10k_station_assoc(ar, arvif->vif, sta, true); @@ -7085,10 +7106,20 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, { struct ath10k *ar = hw->priv; struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; + struct ath10k_vif *arvif = (void *)vif->drv_priv; + struct ath10k_peer *peer; u32 bw, smps; spin_lock_bh(&ar->data_lock); + peer = ath10k_peer_find(ar, arvif->vdev_id, sta->addr); + if (!peer) { + spin_unlock_bh(&ar->data_lock); + ath10k_warn(ar, "mac sta rc update failed to find peer %pM on vdev %i\n", + sta->addr, arvif->vdev_id); + return; + } + ath10k_dbg(ar, ATH10K_DBG_MAC, "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", sta->addr, changed, sta->bandwidth, sta->rx_nss, @@ -7874,6 +7905,7 @@ static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = { .max_interfaces = 8, .num_different_channels = 1, .beacon_int_infra_match = true, + .beacon_int_min_gcd = 1, #ifdef CONFIG_ATH10K_DFS_CERTIFIED .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | @@ -7997,6 +8029,7 @@ static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = { .max_interfaces = 16, .num_different_channels = 1, .beacon_int_infra_match = true, + .beacon_int_min_gcd = 1, #ifdef CONFIG_ATH10K_DFS_CERTIFIED .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | BIT(NL80211_CHAN_WIDTH_20) | @@ -8298,6 +8331,9 @@ int ath10k_mac_register(struct ath10k *ar) ieee80211_hw_set(ar->hw, TDLS_WIDER_BW); } + if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, ar->wmi.svc_map)) + ieee80211_hw_set(ar->hw, SUPPORTS_TDLS_BUFFER_STA); + ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; ar->hw->wiphy->max_remain_on_channel_duration = 5000; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 1b266cd0c2ec..fd1566cd7d2b 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -57,6 +57,10 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); */ #define ATH10K_DIAG_TRANSFER_LIMIT 0x5000 +#define QCA99X0_PCIE_BAR0_START_REG 0x81030 +#define QCA99X0_CPU_MEM_ADDR_REG 0x4d00c +#define QCA99X0_CPU_MEM_DATA_REG 0x4d010 + static const struct pci_device_id ath10k_pci_id_table[] = { /* PCI-E QCA988X V2 (Ubiquiti branded) */ { PCI_VDEVICE(UBIQUITI, QCA988X_2_0_DEVICE_ID_UBNT) }, @@ -1584,6 +1588,69 @@ static int ath10k_pci_set_ram_config(struct ath10k *ar, u32 config) return 0; } +/* if an error happened returns < 0, otherwise the length */ +static int ath10k_pci_dump_memory_sram(struct ath10k *ar, + const struct ath10k_mem_region *region, + u8 *buf) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + u32 base_addr, i; + + base_addr = ioread32(ar_pci->mem + QCA99X0_PCIE_BAR0_START_REG); + base_addr += region->start; + + for (i = 0; i < region->len; i += 4) { + iowrite32(base_addr + i, ar_pci->mem + QCA99X0_CPU_MEM_ADDR_REG); + *(u32 *)(buf + i) = ioread32(ar_pci->mem + QCA99X0_CPU_MEM_DATA_REG); + } + + return region->len; +} + +/* if an error happened returns < 0, otherwise the length */ +static int ath10k_pci_dump_memory_reg(struct ath10k *ar, + const struct ath10k_mem_region *region, + u8 *buf) +{ + struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); + u32 i; + + for (i = 0; i < region->len; i += 4) + *(u32 *)(buf + i) = ioread32(ar_pci->mem + region->start + i); + + return region->len; +} + +/* if an error happened returns < 0, otherwise the length */ +static int ath10k_pci_dump_memory_generic(struct ath10k *ar, + const struct ath10k_mem_region *current_region, + u8 *buf) +{ + int ret; + + if (current_region->section_table.size > 0) + /* Copy each section individually. */ + return ath10k_pci_dump_memory_section(ar, + current_region, + buf, + current_region->len); + + /* No individiual memory sections defined so we can + * copy the entire memory region. + */ + ret = ath10k_pci_diag_read_mem(ar, + current_region->start, + buf, + current_region->len); + if (ret) { + ath10k_warn(ar, "failed to copy ramdump region %s: %d\n", + current_region->name, ret); + return ret; + } + + return current_region->len; +} + static void ath10k_pci_dump_memory(struct ath10k *ar, struct ath10k_fw_crash_data *crash_data) { @@ -1642,27 +1709,20 @@ static void ath10k_pci_dump_memory(struct ath10k *ar, buf += sizeof(*hdr); buf_len -= sizeof(*hdr); - if (current_region->section_table.size > 0) { - /* Copy each section individually. */ - count = ath10k_pci_dump_memory_section(ar, - current_region, - buf, - current_region->len); - } else { - /* No individiual memory sections defined so we can - * copy the entire memory region. - */ - ret = ath10k_pci_diag_read_mem(ar, - current_region->start, - buf, - current_region->len); - if (ret) { - ath10k_warn(ar, "failed to copy ramdump region %s: %d\n", - current_region->name, ret); + switch (current_region->type) { + case ATH10K_MEM_REGION_TYPE_IOSRAM: + count = ath10k_pci_dump_memory_sram(ar, current_region, buf); + break; + case ATH10K_MEM_REGION_TYPE_IOREG: + count = ath10k_pci_dump_memory_reg(ar, current_region, buf); + break; + default: + ret = ath10k_pci_dump_memory_generic(ar, current_region, buf); + if (ret < 0) break; - } - count = current_region->len; + count = ret; + break; } hdr->region_type = cpu_to_le32(current_region->type); @@ -2221,7 +2281,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar) } break; case QCA9377_1_0_DEVICE_ID: - return 4; + return 9; } ath10k_warn(ar, "unknown number of banks, assuming 1\n"); @@ -3718,5 +3778,6 @@ MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE); MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE); /* QCA9377 1.0 firmware files */ +MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API6_FILE); MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API5_FILE); MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" QCA9377_HW_1_0_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h index e40edced1d82..7d2fac342150 100644 --- a/drivers/net/wireless/ath/ath10k/trace.h +++ b/drivers/net/wireless/ath/ath10k/trace.h @@ -152,10 +152,9 @@ TRACE_EVENT(ath10k_log_dbg_dump, ); TRACE_EVENT(ath10k_wmi_cmd, - TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len, - int ret), + TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len), - TP_ARGS(ar, id, buf, buf_len, ret), + TP_ARGS(ar, id, buf, buf_len), TP_STRUCT__entry( __string(device, dev_name(ar->dev)) @@ -163,7 +162,6 @@ TRACE_EVENT(ath10k_wmi_cmd, __field(unsigned int, id) __field(size_t, buf_len) __dynamic_array(u8, buf, buf_len) - __field(int, ret) ), TP_fast_assign( @@ -171,17 +169,15 @@ TRACE_EVENT(ath10k_wmi_cmd, __assign_str(driver, dev_driver_string(ar->dev)); __entry->id = id; __entry->buf_len = buf_len; - __entry->ret = ret; memcpy(__get_dynamic_array(buf), buf, buf_len); ), TP_printk( - "%s %s id %d len %zu ret %d", + "%s %s id %d len %zu", __get_str(driver), __get_str(device), __entry->id, - __entry->buf_len, - __entry->ret + __entry->buf_len ) ); diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 5b3b021526ab..70e23bbf7171 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -102,11 +102,6 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, memset(&info->status, 0, sizeof(info->status)); trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id); - if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) { - ieee80211_free_txskb(htt->ar->hw, msdu); - return 0; - } - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) info->flags |= IEEE80211_TX_STAT_ACK; @@ -117,6 +112,13 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, (info->flags & IEEE80211_TX_CTL_NO_ACK)) info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) { + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED; + else + info->flags &= ~IEEE80211_TX_STAT_ACK; + } + ieee80211_tx_status(htt->ar->hw, msdu); /* we do not own the msdu anymore */ diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h index 14093cfdc505..c35e45340b4f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -125,6 +126,9 @@ struct wmi_ops { enum wmi_force_fw_hang_type type, u32 delay_ms); struct sk_buff *(*gen_mgmt_tx)(struct ath10k *ar, struct sk_buff *skb); + struct sk_buff *(*gen_mgmt_tx_send)(struct ath10k *ar, + struct sk_buff *skb, + dma_addr_t paddr); struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u64 module_enable, u32 log_level); struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter); @@ -197,6 +201,9 @@ struct wmi_ops { (struct ath10k *ar, enum wmi_bss_survey_req_type type); struct sk_buff *(*gen_echo)(struct ath10k *ar, u32 value); + struct sk_buff *(*gen_pdev_get_tpc_table_cmdid)(struct ath10k *ar, + u32 param); + }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); @@ -372,12 +379,33 @@ ath10k_wmi_get_txbf_conf_scheme(struct ath10k *ar) } static inline int +ath10k_wmi_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu, + dma_addr_t paddr) +{ + struct sk_buff *skb; + int ret; + + if (!ar->wmi.ops->gen_mgmt_tx_send) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_mgmt_tx_send(ar, msdu, paddr); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + ret = ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->mgmt_tx_send_cmdid); + if (ret) + return ret; + + return 0; +} + +static inline int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu); struct sk_buff *skb; int ret; - u32 mgmt_tx_cmdid; if (!ar->wmi.ops->gen_mgmt_tx) return -EOPNOTSUPP; @@ -386,13 +414,8 @@ ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) if (IS_ERR(skb)) return PTR_ERR(skb); - if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF, - ar->running_fw->fw_file.fw_features)) - mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_send_cmdid; - else - mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_cmdid; - - ret = ath10k_wmi_cmd_send(ar, skb, mgmt_tx_cmdid); + ret = ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->mgmt_tx_cmdid); if (ret) return ret; @@ -1425,4 +1448,21 @@ ath10k_wmi_echo(struct ath10k *ar, u32 value) return ath10k_wmi_cmd_send(ar, skb, wmi->cmd->echo_cmdid); } +static inline int +ath10k_wmi_pdev_get_tpc_table_cmdid(struct ath10k *ar, u32 param) +{ + struct sk_buff *skb; + + if (!ar->wmi.ops->gen_pdev_get_tpc_table_cmdid) + return -EOPNOTSUPP; + + skb = ar->wmi.ops->gen_pdev_get_tpc_table_cmdid(ar, param); + + if (IS_ERR(skb)) + return PTR_ERR(skb); + + return ath10k_wmi_cmd_send(ar, skb, + ar->wmi.cmd->pdev_get_tpc_table_cmdid); +} + #endif diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index ae77a007ae07..9d1b0a459069 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -412,6 +413,62 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar, return 0; } +static int ath10k_wmi_tlv_event_temperature(struct ath10k *ar, + struct sk_buff *skb) +{ + const struct wmi_tlv_pdev_temperature_event *ev; + + ev = (struct wmi_tlv_pdev_temperature_event *)skb->data; + if (WARN_ON(skb->len < sizeof(*ev))) + return -EPROTO; + + ath10k_thermal_event_temperature(ar, __le32_to_cpu(ev->temperature)); + return 0; +} + +static void ath10k_wmi_event_tdls_peer(struct ath10k *ar, struct sk_buff *skb) +{ + struct ieee80211_sta *station; + const struct wmi_tlv_tdls_peer_event *ev; + const void **tb; + struct ath10k_vif *arvif; + + tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); + if (IS_ERR(tb)) { + ath10k_warn(ar, "tdls peer failed to parse tlv"); + return; + } + ev = tb[WMI_TLV_TAG_STRUCT_TDLS_PEER_EVENT]; + if (!ev) { + kfree(tb); + ath10k_warn(ar, "tdls peer NULL event"); + return; + } + + switch (__le32_to_cpu(ev->peer_reason)) { + case WMI_TDLS_TEARDOWN_REASON_TX: + case WMI_TDLS_TEARDOWN_REASON_RSSI: + case WMI_TDLS_TEARDOWN_REASON_PTR_TIMEOUT: + station = ieee80211_find_sta_by_ifaddr(ar->hw, + ev->peer_macaddr.addr, + NULL); + if (!station) { + ath10k_warn(ar, "did not find station from tdls peer event"); + kfree(tb); + return; + } + arvif = ath10k_get_arvif(ar, __le32_to_cpu(ev->vdev_id)); + ieee80211_tdls_oper_request( + arvif->vif, station->addr, + NL80211_TDLS_TEARDOWN, + WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE, + GFP_ATOMIC + ); + break; + } + kfree(tb); +} + /***********/ /* TLV ops */ /***********/ @@ -552,6 +609,12 @@ static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_TLV_TX_PAUSE_EVENTID: ath10k_wmi_tlv_event_tx_pause(ar, skb); break; + case WMI_TLV_PDEV_TEMPERATURE_EVENTID: + ath10k_wmi_tlv_event_temperature(ar, skb); + break; + case WMI_TLV_TDLS_PEER_EVENTID: + ath10k_wmi_event_tdls_peer(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -2484,19 +2547,19 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask) } static struct sk_buff * -ath10k_wmi_tlv_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) +ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu, + dma_addr_t paddr) { struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu); struct wmi_tlv_mgmt_tx_cmd *cmd; - struct wmi_tlv *tlv; struct ieee80211_hdr *hdr; + struct ath10k_vif *arvif; + u32 buf_len = msdu->len; + struct wmi_tlv *tlv; struct sk_buff *skb; + u32 vdev_id; void *ptr; int len; - u32 buf_len = msdu->len; - struct ath10k_vif *arvif; - dma_addr_t mgmt_frame_dma; - u32 vdev_id; if (!cb->vif) return ERR_PTR(-EINVAL); @@ -2537,12 +2600,7 @@ ath10k_wmi_tlv_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) cmd->chanfreq = 0; cmd->buf_len = __cpu_to_le32(buf_len); cmd->frame_len = __cpu_to_le32(msdu->len); - mgmt_frame_dma = dma_map_single(arvif->ar->dev, msdu->data, - msdu->len, DMA_TO_DEVICE); - if (!mgmt_frame_dma) - return ERR_PTR(-ENOMEM); - - cmd->paddr = __cpu_to_le64(mgmt_frame_dma); + cmd->paddr = __cpu_to_le64(paddr); ptr += sizeof(*tlv); ptr += sizeof(*cmd); @@ -2662,6 +2720,25 @@ ath10k_wmi_tlv_op_gen_pktlog_enable(struct ath10k *ar, u32 filter) } static struct sk_buff * +ath10k_wmi_tlv_op_gen_pdev_get_temperature(struct ath10k *ar) +{ + struct wmi_tlv_pdev_get_temp_cmd *cmd; + struct wmi_tlv *tlv; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + tlv = (void *)skb->data; + tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_GET_TEMPERATURE_CMD); + tlv->len = __cpu_to_le16(sizeof(*cmd)); + cmd = (void *)tlv->value; + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev get temperature tlv\n"); + return skb; +} + +static struct sk_buff * ath10k_wmi_tlv_op_gen_pktlog_disable(struct ath10k *ar) { struct wmi_tlv_pktlog_disable *cmd; @@ -2855,6 +2932,15 @@ ath10k_wmi_tlv_op_gen_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id, */ u32 options = 0; + if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, ar->wmi.svc_map)) + options |= WMI_TLV_TDLS_BUFFER_STA_EN; + + /* WMI_TDLS_ENABLE_ACTIVE_EXTERNAL_CONTROL means firm will handle TDLS + * link inactivity detecting logic. + */ + if (state == WMI_TDLS_ENABLE_ACTIVE) + state = WMI_TDLS_ENABLE_ACTIVE_EXTERNAL_CONTROL; + len = sizeof(*tlv) + sizeof(*cmd); skb = ath10k_wmi_alloc_skb(ar, len); if (!skb) @@ -3443,7 +3529,7 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = { .force_fw_hang_cmdid = WMI_TLV_FORCE_FW_HANG_CMDID, .gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID, - .pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED, + .pdev_get_temperature_cmdid = WMI_TLV_PDEV_GET_TEMPERATURE_CMDID, .vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID, .tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID, .tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_CMDID, @@ -3701,12 +3787,12 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats, .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang, /* .gen_mgmt_tx = not implemented; HTT is used */ - .gen_mgmt_tx = ath10k_wmi_tlv_op_gen_mgmt_tx, + .gen_mgmt_tx_send = ath10k_wmi_tlv_op_gen_mgmt_tx_send, .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg, .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable, /* .gen_pdev_set_quiet_mode not implemented */ - /* .gen_pdev_get_temperature not implemented */ + .gen_pdev_get_temperature = ath10k_wmi_tlv_op_gen_pdev_get_temperature, /* .gen_addba_clear_resp not implemented */ /* .gen_addba_send not implemented */ /* .gen_addba_set_resp not implemented */ diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h index da89128e8dd6..fa3773ec7c68 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.h +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h @@ -1340,6 +1340,17 @@ struct wmi_tlv_init_cmd { __le32 num_host_mem_chunks; } __packed; +struct wmi_tlv_pdev_get_temp_cmd { + __le32 pdev_id; /* not used */ +} __packed; + +struct wmi_tlv_pdev_temperature_event { + __le32 tlv_hdr; + /* temperature value in Celcius degree */ + __le32 temperature; + __le32 pdev_id; +} __packed; + struct wmi_tlv_pdev_set_param_cmd { __le32 pdev_id; /* not used yet */ __le32 param_id; @@ -1746,6 +1757,13 @@ struct wmi_tlv_tx_pause_ev { __le32 tid_map; } __packed; +struct wmi_tlv_tdls_peer_event { + struct wmi_mac_addr peer_macaddr; + __le32 peer_status; + __le32 peer_reason; + __le32 vdev_id; +} __packed; + void ath10k_wmi_tlv_attach(struct ath10k *ar); struct wmi_tlv_mgmt_tx_cmd { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 58dc2189ba49..c5e1ca5945db 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -196,6 +197,7 @@ static struct wmi_cmd_map wmi_cmd_map = { .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.X WMI cmd track */ @@ -362,6 +364,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.2.4 WMI cmd track */ @@ -528,6 +531,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = { .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, .pdev_bss_chan_info_request_cmdid = WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID, + .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.4 WMI cmd track */ @@ -1480,6 +1484,7 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = { @@ -1742,8 +1747,8 @@ int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, cmd_hdr->cmd_id = __cpu_to_le32(cmd); memset(skb_cb, 0, sizeof(*skb_cb)); + trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len); ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb); - trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len, ret); if (ret) goto err_pull; @@ -2703,6 +2708,28 @@ ath10k_wmi_10_4_pull_peer_stats(const struct wmi_10_4_peer_stats *src, dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate); } +static void +ath10k_wmi_10_4_pull_vdev_stats(const struct wmi_vdev_stats_extd *src, + struct ath10k_fw_stats_vdev_extd *dst) +{ + dst->vdev_id = __le32_to_cpu(src->vdev_id); + dst->ppdu_aggr_cnt = __le32_to_cpu(src->ppdu_aggr_cnt); + dst->ppdu_noack = __le32_to_cpu(src->ppdu_noack); + dst->mpdu_queued = __le32_to_cpu(src->mpdu_queued); + dst->ppdu_nonaggr_cnt = __le32_to_cpu(src->ppdu_nonaggr_cnt); + dst->mpdu_sw_requeued = __le32_to_cpu(src->mpdu_sw_requeued); + dst->mpdu_suc_retry = __le32_to_cpu(src->mpdu_suc_retry); + dst->mpdu_suc_multitry = __le32_to_cpu(src->mpdu_suc_multitry); + dst->mpdu_fail_retry = __le32_to_cpu(src->mpdu_fail_retry); + dst->tx_ftm_suc = __le32_to_cpu(src->tx_ftm_suc); + dst->tx_ftm_suc_retry = __le32_to_cpu(src->tx_ftm_suc_retry); + dst->tx_ftm_fail = __le32_to_cpu(src->tx_ftm_fail); + dst->rx_ftmr_cnt = __le32_to_cpu(src->rx_ftmr_cnt); + dst->rx_ftmr_dup_cnt = __le32_to_cpu(src->rx_ftmr_dup_cnt); + dst->rx_iftmr_cnt = __le32_to_cpu(src->rx_iftmr_cnt); + dst->rx_iftmr_dup_cnt = __le32_to_cpu(src->rx_iftmr_dup_cnt); +} + static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb, struct ath10k_fw_stats *stats) @@ -3042,7 +3069,16 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar, */ } - /* fw doesn't implement vdev stats */ + for (i = 0; i < num_vdev_stats; i++) { + const struct wmi_vdev_stats *src; + + /* Ignore vdev stats here as it has only vdev id. Actual vdev + * stats will be retrieved from vdev extended stats. + */ + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + } for (i = 0; i < num_peer_stats; i++) { const struct wmi_10_4_peer_stats *src; @@ -3074,26 +3110,43 @@ static int ath10k_wmi_10_4_op_pull_fw_stats(struct ath10k *ar, */ } - if ((stats_id & WMI_10_4_STAT_PEER_EXTD) == 0) - return 0; + if (stats_id & WMI_10_4_STAT_PEER_EXTD) { + stats->extended = true; - stats->extended = true; + for (i = 0; i < num_peer_stats; i++) { + const struct wmi_10_4_peer_extd_stats *src; + struct ath10k_fw_extd_stats_peer *dst; - for (i = 0; i < num_peer_stats; i++) { - const struct wmi_10_4_peer_extd_stats *src; - struct ath10k_fw_extd_stats_peer *dst; + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; - src = (void *)skb->data; - if (!skb_pull(skb, sizeof(*src))) - return -EPROTO; + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; - dst = kzalloc(sizeof(*dst), GFP_ATOMIC); - if (!dst) - continue; + ether_addr_copy(dst->peer_macaddr, + src->peer_macaddr.addr); + dst->rx_duration = __le32_to_cpu(src->rx_duration); + list_add_tail(&dst->list, &stats->peers_extd); + } + } + + if (stats_id & WMI_10_4_STAT_VDEV_EXTD) { + for (i = 0; i < num_vdev_stats; i++) { + const struct wmi_vdev_stats_extd *src; + struct ath10k_fw_stats_vdev_extd *dst; - ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr); - dst->rx_duration = __le32_to_cpu(src->rx_duration); - list_add_tail(&dst->list, &stats->peers_extd); + src = (void *)skb->data; + if (!skb_pull(skb, sizeof(*src))) + return -EPROTO; + + dst = kzalloc(sizeof(*dst), GFP_ATOMIC); + if (!dst) + continue; + ath10k_wmi_10_4_pull_vdev_stats(src, dst); + list_add_tail(&dst->list, &stats->vdevs); + } } return 0; @@ -4313,19 +4366,11 @@ static void ath10k_tpc_config_disp_tables(struct ath10k *ar, } } -void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) +void ath10k_wmi_tpc_config_get_rate_code(u8 *rate_code, u16 *pream_table, + u32 num_tx_chain) { - u32 i, j, pream_idx, num_tx_chain; - u8 rate_code[WMI_TPC_RATE_MAX], rate_idx; - u16 pream_table[WMI_TPC_PREAM_TABLE_MAX]; - struct wmi_pdev_tpc_config_event *ev; - struct ath10k_tpc_stats *tpc_stats; - - ev = (struct wmi_pdev_tpc_config_event *)skb->data; - - tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC); - if (!tpc_stats) - return; + u32 i, j, pream_idx; + u8 rate_idx; /* Create the rate code table based on the chains supported */ rate_idx = 0; @@ -4349,8 +4394,6 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) pream_table[pream_idx] = rate_idx; pream_idx++; - num_tx_chain = __le32_to_cpu(ev->num_tx_chain); - /* Fill HT20 rate code */ for (i = 0; i < num_tx_chain; i++) { for (j = 0; j < 8; j++) { @@ -4374,7 +4417,7 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) pream_idx++; /* Fill VHT20 rate code */ - for (i = 0; i < __le32_to_cpu(ev->num_tx_chain); i++) { + for (i = 0; i < num_tx_chain; i++) { for (j = 0; j < 10; j++) { rate_code[rate_idx] = ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT); @@ -4418,6 +4461,26 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_OFDM); pream_table[pream_idx] = ATH10K_TPC_PREAM_TABLE_END; +} + +void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) +{ + u32 num_tx_chain; + u8 rate_code[WMI_TPC_RATE_MAX]; + u16 pream_table[WMI_TPC_PREAM_TABLE_MAX]; + struct wmi_pdev_tpc_config_event *ev; + struct ath10k_tpc_stats *tpc_stats; + + ev = (struct wmi_pdev_tpc_config_event *)skb->data; + + tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC); + if (!tpc_stats) + return; + + num_tx_chain = __le32_to_cpu(ev->num_tx_chain); + + ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table, + num_tx_chain); tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq); tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode); @@ -4457,6 +4520,246 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) __le32_to_cpu(ev->rate_max)); } +static u8 +ath10k_wmi_tpc_final_get_rate(struct ath10k *ar, + struct wmi_pdev_tpc_final_table_event *ev, + u32 rate_idx, u32 num_chains, + u32 rate_code, u8 type, u32 pream_idx) +{ + u8 tpc, num_streams, preamble, ch, stm_idx; + s8 pow_agcdd, pow_agstbc, pow_agtxbf; + int pream; + + num_streams = ATH10K_HW_NSS(rate_code); + preamble = ATH10K_HW_PREAMBLE(rate_code); + ch = num_chains - 1; + stm_idx = num_streams - 1; + pream = -1; + + if (__le32_to_cpu(ev->chan_freq) <= 2483) { + switch (pream_idx) { + case WMI_TPC_PREAM_2GHZ_CCK: + pream = 0; + break; + case WMI_TPC_PREAM_2GHZ_OFDM: + pream = 1; + break; + case WMI_TPC_PREAM_2GHZ_HT20: + case WMI_TPC_PREAM_2GHZ_VHT20: + pream = 2; + break; + case WMI_TPC_PREAM_2GHZ_HT40: + case WMI_TPC_PREAM_2GHZ_VHT40: + pream = 3; + break; + case WMI_TPC_PREAM_2GHZ_VHT80: + pream = 4; + break; + default: + pream = -1; + break; + } + } + + if (__le32_to_cpu(ev->chan_freq) >= 5180) { + switch (pream_idx) { + case WMI_TPC_PREAM_5GHZ_OFDM: + pream = 0; + break; + case WMI_TPC_PREAM_5GHZ_HT20: + case WMI_TPC_PREAM_5GHZ_VHT20: + pream = 1; + break; + case WMI_TPC_PREAM_5GHZ_HT40: + case WMI_TPC_PREAM_5GHZ_VHT40: + pream = 2; + break; + case WMI_TPC_PREAM_5GHZ_VHT80: + pream = 3; + break; + case WMI_TPC_PREAM_5GHZ_HTCUP: + pream = 4; + break; + default: + pream = -1; + break; + } + } + + if (pream == 4) + tpc = min_t(u8, ev->rates_array[rate_idx], + ev->max_reg_allow_pow[ch]); + else + tpc = min_t(u8, min_t(u8, ev->rates_array[rate_idx], + ev->max_reg_allow_pow[ch]), + ev->ctl_power_table[0][pream][stm_idx]); + + if (__le32_to_cpu(ev->num_tx_chain) <= 1) + goto out; + + if (preamble == WMI_RATE_PREAMBLE_CCK) + goto out; + + if (num_chains <= num_streams) + goto out; + + switch (type) { + case WMI_TPC_TABLE_TYPE_STBC: + pow_agstbc = ev->max_reg_allow_pow_agstbc[ch - 1][stm_idx]; + if (pream == 4) + tpc = min_t(u8, tpc, pow_agstbc); + else + tpc = min_t(u8, min_t(u8, tpc, pow_agstbc), + ev->ctl_power_table[0][pream][stm_idx]); + break; + case WMI_TPC_TABLE_TYPE_TXBF: + pow_agtxbf = ev->max_reg_allow_pow_agtxbf[ch - 1][stm_idx]; + if (pream == 4) + tpc = min_t(u8, tpc, pow_agtxbf); + else + tpc = min_t(u8, min_t(u8, tpc, pow_agtxbf), + ev->ctl_power_table[1][pream][stm_idx]); + break; + case WMI_TPC_TABLE_TYPE_CDD: + pow_agcdd = ev->max_reg_allow_pow_agcdd[ch - 1][stm_idx]; + if (pream == 4) + tpc = min_t(u8, tpc, pow_agcdd); + else + tpc = min_t(u8, min_t(u8, tpc, pow_agcdd), + ev->ctl_power_table[0][pream][stm_idx]); + break; + default: + ath10k_warn(ar, "unknown wmi tpc final table type: %d\n", type); + tpc = 0; + break; + } + +out: + return tpc; +} + +static void +ath10k_wmi_tpc_stats_final_disp_tables(struct ath10k *ar, + struct wmi_pdev_tpc_final_table_event *ev, + struct ath10k_tpc_stats_final *tpc_stats, + u8 *rate_code, u16 *pream_table, u8 type) +{ + u32 i, j, pream_idx, flags; + u8 tpc[WMI_TPC_TX_N_CHAIN]; + char tpc_value[WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE]; + char buff[WMI_TPC_BUF_SIZE]; + + flags = __le32_to_cpu(ev->flags); + + switch (type) { + case WMI_TPC_TABLE_TYPE_CDD: + if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_CDD)) { + ath10k_dbg(ar, ATH10K_DBG_WMI, "CDD not supported\n"); + tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG; + return; + } + break; + case WMI_TPC_TABLE_TYPE_STBC: + if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_STBC)) { + ath10k_dbg(ar, ATH10K_DBG_WMI, "STBC not supported\n"); + tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG; + return; + } + break; + case WMI_TPC_TABLE_TYPE_TXBF: + if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_TXBF)) { + ath10k_dbg(ar, ATH10K_DBG_WMI, "TXBF not supported\n"); + tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG; + return; + } + break; + default: + ath10k_dbg(ar, ATH10K_DBG_WMI, + "invalid table type in wmi tpc event: %d\n", type); + return; + } + + pream_idx = 0; + for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) { + memset(tpc_value, 0, sizeof(tpc_value)); + memset(buff, 0, sizeof(buff)); + if (i == pream_table[pream_idx]) + pream_idx++; + + for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) { + if (j >= __le32_to_cpu(ev->num_tx_chain)) + break; + + tpc[j] = ath10k_wmi_tpc_final_get_rate(ar, ev, i, j + 1, + rate_code[i], + type, pream_idx); + snprintf(buff, sizeof(buff), "%8d ", tpc[j]); + strncat(tpc_value, buff, strlen(buff)); + } + tpc_stats->tpc_table_final[type].pream_idx[i] = pream_idx; + tpc_stats->tpc_table_final[type].rate_code[i] = rate_code[i]; + memcpy(tpc_stats->tpc_table_final[type].tpc_value[i], + tpc_value, sizeof(tpc_value)); + } +} + +void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb) +{ + u32 num_tx_chain; + u8 rate_code[WMI_TPC_FINAL_RATE_MAX]; + u16 pream_table[WMI_TPC_PREAM_TABLE_MAX]; + struct wmi_pdev_tpc_final_table_event *ev; + struct ath10k_tpc_stats_final *tpc_stats; + + ev = (struct wmi_pdev_tpc_final_table_event *)skb->data; + + tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC); + if (!tpc_stats) + return; + + num_tx_chain = __le32_to_cpu(ev->num_tx_chain); + + ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table, + num_tx_chain); + + tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq); + tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode); + tpc_stats->ctl = __le32_to_cpu(ev->ctl); + tpc_stats->reg_domain = __le32_to_cpu(ev->reg_domain); + tpc_stats->twice_antenna_gain = a_sle32_to_cpu(ev->twice_antenna_gain); + tpc_stats->twice_antenna_reduction = + __le32_to_cpu(ev->twice_antenna_reduction); + tpc_stats->power_limit = __le32_to_cpu(ev->power_limit); + tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power); + tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain); + tpc_stats->rate_max = __le32_to_cpu(ev->rate_max); + + ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats, + rate_code, pream_table, + WMI_TPC_TABLE_TYPE_CDD); + ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats, + rate_code, pream_table, + WMI_TPC_TABLE_TYPE_STBC); + ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats, + rate_code, pream_table, + WMI_TPC_TABLE_TYPE_TXBF); + + ath10k_debug_tpc_stats_final_process(ar, tpc_stats); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi event tpc final table channel %d mode %d ctl %d regd %d gain %d %d limit %d max_power %d tx_chanins %d rates %d\n", + __le32_to_cpu(ev->chan_freq), + __le32_to_cpu(ev->phy_mode), + __le32_to_cpu(ev->ctl), + __le32_to_cpu(ev->reg_domain), + a_sle32_to_cpu(ev->twice_antenna_gain), + __le32_to_cpu(ev->twice_antenna_reduction), + __le32_to_cpu(ev->power_limit), + __le32_to_cpu(ev->twice_max_rd_power) / 2, + __le32_to_cpu(ev->num_tx_chain), + __le32_to_cpu(ev->rate_max)); +} + static void ath10k_wmi_handle_tdls_peer_event(struct ath10k *ar, struct sk_buff *skb) { @@ -5531,6 +5834,7 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_4_WOW_WAKEUP_HOST_EVENTID: case WMI_10_4_PEER_RATECODE_LIST_EVENTID: case WMI_10_4_WDS_PEER_EVENTID: + case WMI_10_4_DEBUG_FATAL_CONDITION_EVENTID: ath10k_dbg(ar, ATH10K_DBG_WMI, "received event id %d not implemented\n", id); break; @@ -5549,6 +5853,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_4_TDLS_PEER_EVENTID: ath10k_wmi_handle_tdls_peer_event(ar, skb); break; + case WMI_10_4_PDEV_TPC_TABLE_EVENTID: + ath10k_wmi_event_tpc_final_table(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -7745,6 +8052,72 @@ ath10k_wmi_op_gen_pdev_enable_adaptive_cca(struct ath10k *ar, u8 enable, return skb; } +static void +ath10k_wmi_fw_vdev_stats_extd_fill(const struct ath10k_fw_stats_vdev_extd *vdev, + char *buf, u32 *length) +{ + u32 len = *length; + u32 buf_len = ATH10K_FW_STATS_BUF_SIZE; + u32 val; + + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "vdev id", vdev->vdev_id); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "ppdu aggr count", vdev->ppdu_aggr_cnt); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "ppdu noack", vdev->ppdu_noack); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "mpdu queued", vdev->mpdu_queued); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "ppdu nonaggr count", vdev->ppdu_nonaggr_cnt); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "mpdu sw requeued", vdev->mpdu_sw_requeued); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "mpdu success retry", vdev->mpdu_suc_retry); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "mpdu success multitry", vdev->mpdu_suc_multitry); + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "mpdu fail retry", vdev->mpdu_fail_retry); + val = vdev->tx_ftm_suc; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "tx ftm success", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + val = vdev->tx_ftm_suc_retry; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "tx ftm success retry", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + val = vdev->tx_ftm_fail; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "tx ftm fail", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + val = vdev->rx_ftmr_cnt; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "rx ftm request count", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + val = vdev->rx_ftmr_dup_cnt; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "rx ftm request dup count", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + val = vdev->rx_iftmr_cnt; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "rx initial ftm req count", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + val = vdev->rx_iftmr_dup_cnt; + if (val & WMI_VDEV_STATS_FTM_COUNT_VALID) + len += scnprintf(buf + len, buf_len - len, "%30s %u\n", + "rx initial ftm req dup cnt", + MS(val, WMI_VDEV_STATS_FTM_COUNT)); + len += scnprintf(buf + len, buf_len - len, "\n"); + + *length = len; +} + void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, struct ath10k_fw_stats *fw_stats, char *buf) @@ -7752,7 +8125,7 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, u32 len = 0; u32 buf_len = ATH10K_FW_STATS_BUF_SIZE; const struct ath10k_fw_stats_pdev *pdev; - const struct ath10k_fw_stats_vdev *vdev; + const struct ath10k_fw_stats_vdev_extd *vdev; const struct ath10k_fw_stats_peer *peer; size_t num_peers; size_t num_vdevs; @@ -7805,9 +8178,8 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, "ath10k VDEV stats", num_vdevs); len += scnprintf(buf + len, buf_len - len, "%30s\n\n", "================="); - list_for_each_entry(vdev, &fw_stats->vdevs, list) { - ath10k_wmi_fw_vdev_stats_fill(vdev, buf, &len); + ath10k_wmi_fw_vdev_stats_extd_fill(vdev, buf, &len); } len += scnprintf(buf + len, buf_len - len, "\n"); @@ -7990,6 +8362,24 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp) } static struct sk_buff * +ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid(struct ath10k *ar, u32 param) +{ + struct wmi_pdev_get_tpc_table_cmd *cmd; + struct sk_buff *skb; + + skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd)); + if (!skb) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_pdev_get_tpc_table_cmd *)skb->data; + cmd->param = __cpu_to_le32(param); + + ath10k_dbg(ar, ATH10K_DBG_WMI, + "wmi pdev get tpc table param:%d\n", param); + return skb; +} + +static struct sk_buff * ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar, const struct wmi_tdls_peer_update_cmd_arg *arg, const struct wmi_tdls_peer_capab_arg *cap, @@ -8430,6 +8820,8 @@ static const struct wmi_ops wmi_10_4_ops = { .ext_resource_config = ath10k_wmi_10_4_ext_resource_config, .gen_update_fw_tdls_state = ath10k_wmi_10_4_gen_update_fw_tdls_state, .gen_tdls_peer_update = ath10k_wmi_10_4_gen_tdls_peer_update, + .gen_pdev_get_tpc_table_cmdid = + ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid, /* shared with 10.2 */ .pull_echo_ev = ath10k_wmi_op_pull_echo_ev, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index c7b30ed9015d..6fbc84c29521 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -1,6 +1,7 @@ /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -197,6 +198,9 @@ enum wmi_service { WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, WMI_SERVICE_MGMT_TX_WMI, WMI_SERVICE_TDLS_WIDER_BANDWIDTH, + WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, + WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, + WMI_SERVICE_TPC_STATS_FINAL, /* keep last */ WMI_SERVICE_MAX, @@ -339,6 +343,9 @@ enum wmi_10_4_service { WMI_10_4_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE, WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY, WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH, + WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, + WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT, + WMI_10_4_SERVICE_TPC_STATS_FINAL, }; static inline char *wmi_service_name(int service_id) @@ -448,6 +455,9 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE); SVCSTR(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY); SVCSTR(WMI_SERVICE_TDLS_WIDER_BANDWIDTH); + SVCSTR(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS); + SVCSTR(WMI_SERVICE_HOST_DFS_CHECK_SUPPORT); + SVCSTR(WMI_SERVICE_TPC_STATS_FINAL); default: return NULL; } @@ -746,6 +756,12 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, len); SVCMAP(WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH, WMI_SERVICE_TDLS_WIDER_BANDWIDTH, len); + SVCMAP(WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, + WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, len); + SVCMAP(WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT, + WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, len); + SVCMAP(WMI_10_4_SERVICE_TPC_STATS_FINAL, + WMI_SERVICE_TPC_STATS_FINAL, len); } #undef SVCMAP @@ -3993,10 +4009,12 @@ struct wmi_pdev_get_tpc_config_cmd { #define WMI_TPC_CONFIG_PARAM 1 #define WMI_TPC_RATE_MAX 160 +#define WMI_TPC_FINAL_RATE_MAX 240 #define WMI_TPC_TX_N_CHAIN 4 #define WMI_TPC_PREAM_TABLE_MAX 10 #define WMI_TPC_FLAG 3 #define WMI_TPC_BUF_SIZE 10 +#define WMI_TPC_BEAMFORMING 2 enum wmi_tpc_table_type { WMI_TPC_TABLE_TYPE_CDD = 0, @@ -4039,6 +4057,51 @@ enum wmi_tp_scale { WMI_TP_SCALE_SIZE = 5, /* max num of enum */ }; +struct wmi_pdev_tpc_final_table_event { + __le32 reg_domain; + __le32 chan_freq; + __le32 phy_mode; + __le32 twice_antenna_reduction; + __le32 twice_max_rd_power; + a_sle32 twice_antenna_gain; + __le32 power_limit; + __le32 rate_max; + __le32 num_tx_chain; + __le32 ctl; + __le32 flags; + s8 max_reg_allow_pow[WMI_TPC_TX_N_CHAIN]; + s8 max_reg_allow_pow_agcdd[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN]; + s8 max_reg_allow_pow_agstbc[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN]; + s8 max_reg_allow_pow_agtxbf[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN]; + u8 rates_array[WMI_TPC_FINAL_RATE_MAX]; + u8 ctl_power_table[WMI_TPC_BEAMFORMING][WMI_TPC_TX_N_CHAIN] + [WMI_TPC_TX_N_CHAIN]; +} __packed; + +struct wmi_pdev_get_tpc_table_cmd { + __le32 param; +} __packed; + +enum wmi_tpc_pream_2ghz { + WMI_TPC_PREAM_2GHZ_CCK = 0, + WMI_TPC_PREAM_2GHZ_OFDM, + WMI_TPC_PREAM_2GHZ_HT20, + WMI_TPC_PREAM_2GHZ_HT40, + WMI_TPC_PREAM_2GHZ_VHT20, + WMI_TPC_PREAM_2GHZ_VHT40, + WMI_TPC_PREAM_2GHZ_VHT80, +}; + +enum wmi_tpc_pream_5ghz { + WMI_TPC_PREAM_5GHZ_OFDM = 1, + WMI_TPC_PREAM_5GHZ_HT20, + WMI_TPC_PREAM_5GHZ_HT40, + WMI_TPC_PREAM_5GHZ_VHT20, + WMI_TPC_PREAM_5GHZ_VHT40, + WMI_TPC_PREAM_5GHZ_VHT80, + WMI_TPC_PREAM_5GHZ_HTCUP, +}; + struct wmi_pdev_chanlist_update_event { /* number of channels */ __le32 num_chan; @@ -4350,6 +4413,7 @@ enum wmi_10_4_stats_id { WMI_10_4_STAT_AP = BIT(1), WMI_10_4_STAT_INST = BIT(2), WMI_10_4_STAT_PEER_EXTD = BIT(3), + WMI_10_4_STAT_VDEV_EXTD = BIT(4), }; struct wlan_inst_rssi_args { @@ -4489,12 +4553,36 @@ struct wmi_10_4_pdev_stats { /* * VDEV statistics - * TODO: add all VDEV stats here */ + +#define WMI_VDEV_STATS_FTM_COUNT_VALID BIT(31) +#define WMI_VDEV_STATS_FTM_COUNT_LSB 0 +#define WMI_VDEV_STATS_FTM_COUNT_MASK 0x7fffffff + struct wmi_vdev_stats { __le32 vdev_id; } __packed; +struct wmi_vdev_stats_extd { + __le32 vdev_id; + __le32 ppdu_aggr_cnt; + __le32 ppdu_noack; + __le32 mpdu_queued; + __le32 ppdu_nonaggr_cnt; + __le32 mpdu_sw_requeued; + __le32 mpdu_suc_retry; + __le32 mpdu_suc_multitry; + __le32 mpdu_fail_retry; + __le32 tx_ftm_suc; + __le32 tx_ftm_suc_retry; + __le32 tx_ftm_fail; + __le32 rx_ftmr_cnt; + __le32 rx_ftmr_dup_cnt; + __le32 rx_iftmr_cnt; + __le32 rx_iftmr_dup_cnt; + __le32 reserved[6]; +} __packed; + /* * peer statistics. * TODO: add more stats @@ -6729,6 +6817,7 @@ enum wmi_tdls_state { WMI_TDLS_DISABLE, WMI_TDLS_ENABLE_PASSIVE, WMI_TDLS_ENABLE_ACTIVE, + WMI_TDLS_ENABLE_ACTIVE_EXTERNAL_CONTROL, }; enum wmi_tdls_peer_state { @@ -6979,5 +7068,8 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar, enum wmi_vdev_subtype subtype); int ath10k_wmi_barrier(struct ath10k *ar); +void ath10k_wmi_tpc_config_get_rate_code(u8 *rate_code, u16 *pream_table, + u32 num_tx_chain); +void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb); #endif /* _WMI_H_ */ diff --git a/drivers/net/wireless/ath/ath5k/attach.c b/drivers/net/wireless/ath/ath5k/attach.c index 233054bd6b52..12d3a6c92ba4 100644 --- a/drivers/net/wireless/ath/ath5k/attach.c +++ b/drivers/net/wireless/ath/ath5k/attach.c @@ -327,7 +327,7 @@ int ath5k_hw_init(struct ath5k_hw *ah) ath5k_hw_set_lladdr(ah, zero_mac); /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ - memcpy(common->curbssid, ath_bcast_mac, ETH_ALEN); + eth_broadcast_addr(common->curbssid); ath5k_hw_set_bssid(ah); ath5k_hw_set_opmode(ah, ah->opmode); diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 527afcf39246..a2351ef45ae0 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -73,16 +73,16 @@ #include "trace.h" bool ath5k_modparam_nohwcrypt; -module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO); +module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); static bool modparam_fastchanswitch; -module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO); +module_param_named(fastchanswitch, modparam_fastchanswitch, bool, 0444); MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios."); static bool ath5k_modparam_no_hw_rfkill_switch; module_param_named(no_hw_rfkill_switch, ath5k_modparam_no_hw_rfkill_switch, - bool, S_IRUGO); + bool, 0444); MODULE_PARM_DESC(no_hw_rfkill_switch, "Ignore the GPIO RFKill switch state"); diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c index bd7f6d7b199e..3513bbec4639 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c @@ -1004,32 +1004,17 @@ ath5k_debug_init_device(struct ath5k_hw *ah) if (!phydir) return; - debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, ah, - &fops_debug); - - debugfs_create_file("registers", S_IRUSR, phydir, ah, &fops_registers); - - debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, ah, - &fops_beacon); - - debugfs_create_file("reset", S_IWUSR, phydir, ah, &fops_reset); - - debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, ah, - &fops_antenna); - - debugfs_create_file("misc", S_IRUSR, phydir, ah, &fops_misc); - - debugfs_create_file("eeprom", S_IRUSR, phydir, ah, &fops_eeprom); - - debugfs_create_file("frameerrors", S_IWUSR | S_IRUSR, phydir, ah, - &fops_frameerrors); - - debugfs_create_file("ani", S_IWUSR | S_IRUSR, phydir, ah, &fops_ani); - - debugfs_create_file("queue", S_IWUSR | S_IRUSR, phydir, ah, - &fops_queue); - - debugfs_create_bool("32khz_clock", S_IWUSR | S_IRUSR, phydir, + debugfs_create_file("debug", 0600, phydir, ah, &fops_debug); + debugfs_create_file("registers", 0400, phydir, ah, &fops_registers); + debugfs_create_file("beacon", 0600, phydir, ah, &fops_beacon); + debugfs_create_file("reset", 0200, phydir, ah, &fops_reset); + debugfs_create_file("antenna", 0600, phydir, ah, &fops_antenna); + debugfs_create_file("misc", 0400, phydir, ah, &fops_misc); + debugfs_create_file("eeprom", 0400, phydir, ah, &fops_eeprom); + debugfs_create_file("frameerrors", 0600, phydir, ah, &fops_frameerrors); + debugfs_create_file("ani", 0600, phydir, ah, &fops_ani); + debugfs_create_file("queue", 0600, phydir, ah, &fops_queue); + debugfs_create_bool("32khz_clock", 0600, phydir, &ah->ah_use_32khz_clock); } diff --git a/drivers/net/wireless/ath/ath5k/qcu.c b/drivers/net/wireless/ath/ath5k/qcu.c index beda11ce34a7..147947f632f7 100644 --- a/drivers/net/wireless/ath/ath5k/qcu.c +++ b/drivers/net/wireless/ath/ath5k/qcu.c @@ -327,8 +327,6 @@ ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); - tq = &ah->ah_txq[queue]; - /* Skip if queue inactive or if we are on AR5210 * that doesn't have QCU/DCU */ if ((ah->ah_version == AR5K_AR5210) || diff --git a/drivers/net/wireless/ath/ath5k/sysfs.c b/drivers/net/wireless/ath/ath5k/sysfs.c index 25978c732fe1..8113baddd8fc 100644 --- a/drivers/net/wireless/ath/ath5k/sysfs.c +++ b/drivers/net/wireless/ath/ath5k/sysfs.c @@ -31,7 +31,7 @@ static ssize_t ath5k_attr_store_##name(struct device *dev, \ set(ah, val); \ return count; \ } \ -static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, \ +static DEVICE_ATTR(name, 0644, \ ath5k_attr_show_##name, ath5k_attr_store_##name) #define SIMPLE_SHOW(name, get) \ @@ -43,7 +43,7 @@ static ssize_t ath5k_attr_show_##name(struct device *dev, \ struct ath5k_hw *ah = hw->priv; \ return snprintf(buf, PAGE_SIZE, "%d\n", get); \ } \ -static DEVICE_ATTR(name, S_IRUGO, ath5k_attr_show_##name, NULL) +static DEVICE_ATTR(name, 0444, ath5k_attr_show_##name, NULL) /*** ANI ***/ @@ -66,7 +66,7 @@ static ssize_t ath5k_attr_show_noise_immunity_level_max(struct device *dev, { return snprintf(buf, PAGE_SIZE, "%d\n", ATH5K_ANI_MAX_NOISE_IMM_LVL); } -static DEVICE_ATTR(noise_immunity_level_max, S_IRUGO, +static DEVICE_ATTR(noise_immunity_level_max, 0444, ath5k_attr_show_noise_immunity_level_max, NULL); static ssize_t ath5k_attr_show_firstep_level_max(struct device *dev, @@ -75,7 +75,7 @@ static ssize_t ath5k_attr_show_firstep_level_max(struct device *dev, { return snprintf(buf, PAGE_SIZE, "%d\n", ATH5K_ANI_MAX_FIRSTEP_LVL); } -static DEVICE_ATTR(firstep_level_max, S_IRUGO, +static DEVICE_ATTR(firstep_level_max, 0444, ath5k_attr_show_firstep_level_max, NULL); static struct attribute *ath5k_sysfs_entries_ani[] = { diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index 1eea6c23976f..0f965e9f38a4 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -1794,69 +1794,68 @@ int ath6kl_debug_init_fs(struct ath6kl *ar) if (!ar->debugfs_phy) return -ENOMEM; - debugfs_create_file("tgt_stats", S_IRUSR, ar->debugfs_phy, ar, + debugfs_create_file("tgt_stats", 0400, ar->debugfs_phy, ar, &fops_tgt_stats); if (ar->hif_type == ATH6KL_HIF_TYPE_SDIO) - debugfs_create_file("credit_dist_stats", S_IRUSR, + debugfs_create_file("credit_dist_stats", 0400, ar->debugfs_phy, ar, &fops_credit_dist_stats); - debugfs_create_file("endpoint_stats", S_IRUSR | S_IWUSR, + debugfs_create_file("endpoint_stats", 0600, ar->debugfs_phy, ar, &fops_endpoint_stats); - debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, - &fops_fwlog); + debugfs_create_file("fwlog", 0400, ar->debugfs_phy, ar, &fops_fwlog); - debugfs_create_file("fwlog_block", S_IRUSR, ar->debugfs_phy, ar, + debugfs_create_file("fwlog_block", 0400, ar->debugfs_phy, ar, &fops_fwlog_block); - debugfs_create_file("fwlog_mask", S_IRUSR | S_IWUSR, ar->debugfs_phy, + debugfs_create_file("fwlog_mask", 0600, ar->debugfs_phy, ar, &fops_fwlog_mask); - debugfs_create_file("reg_addr", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar, + debugfs_create_file("reg_addr", 0600, ar->debugfs_phy, ar, &fops_diag_reg_read); - debugfs_create_file("reg_dump", S_IRUSR, ar->debugfs_phy, ar, + debugfs_create_file("reg_dump", 0400, ar->debugfs_phy, ar, &fops_reg_dump); - debugfs_create_file("lrssi_roam_threshold", S_IRUSR | S_IWUSR, + debugfs_create_file("lrssi_roam_threshold", 0600, ar->debugfs_phy, ar, &fops_lrssi_roam_threshold); - debugfs_create_file("reg_write", S_IRUSR | S_IWUSR, + debugfs_create_file("reg_write", 0600, ar->debugfs_phy, ar, &fops_diag_reg_write); - debugfs_create_file("war_stats", S_IRUSR, ar->debugfs_phy, ar, + debugfs_create_file("war_stats", 0400, ar->debugfs_phy, ar, &fops_war_stats); - debugfs_create_file("roam_table", S_IRUSR, ar->debugfs_phy, ar, + debugfs_create_file("roam_table", 0400, ar->debugfs_phy, ar, &fops_roam_table); - debugfs_create_file("force_roam", S_IWUSR, ar->debugfs_phy, ar, + debugfs_create_file("force_roam", 0200, ar->debugfs_phy, ar, &fops_force_roam); - debugfs_create_file("roam_mode", S_IWUSR, ar->debugfs_phy, ar, + debugfs_create_file("roam_mode", 0200, ar->debugfs_phy, ar, &fops_roam_mode); - debugfs_create_file("keepalive", S_IRUSR | S_IWUSR, ar->debugfs_phy, ar, + debugfs_create_file("keepalive", 0600, ar->debugfs_phy, ar, &fops_keepalive); - debugfs_create_file("disconnect_timeout", S_IRUSR | S_IWUSR, + debugfs_create_file("disconnect_timeout", 0600, ar->debugfs_phy, ar, &fops_disconnect_timeout); - debugfs_create_file("create_qos", S_IWUSR, ar->debugfs_phy, ar, + debugfs_create_file("create_qos", 0200, ar->debugfs_phy, ar, &fops_create_qos); - debugfs_create_file("delete_qos", S_IWUSR, ar->debugfs_phy, ar, + debugfs_create_file("delete_qos", 0200, ar->debugfs_phy, ar, &fops_delete_qos); - debugfs_create_file("bgscan_interval", S_IWUSR, + debugfs_create_file("bgscan_interval", 0200, ar->debugfs_phy, ar, &fops_bgscan_int); - debugfs_create_file("listen_interval", S_IRUSR | S_IWUSR, + debugfs_create_file("listen_interval", 0600, ar->debugfs_phy, ar, &fops_listen_int); - debugfs_create_file("power_params", S_IWUSR, ar->debugfs_phy, ar, + debugfs_create_file("power_params", 0200, ar->debugfs_phy, ar, &fops_power_params); return 0; diff --git a/drivers/net/wireless/ath/ath9k/common-debug.c b/drivers/net/wireless/ath/ath9k/common-debug.c index 84afcf78151f..239429f10378 100644 --- a/drivers/net/wireless/ath/ath9k/common-debug.c +++ b/drivers/net/wireless/ath/ath9k/common-debug.c @@ -47,7 +47,7 @@ static const struct file_operations fops_modal_eeprom = { void ath9k_cmn_debug_modal_eeprom(struct dentry *debugfs_phy, struct ath_hw *ah) { - debugfs_create_file("modal_eeprom", S_IRUSR, debugfs_phy, ah, + debugfs_create_file("modal_eeprom", 0400, debugfs_phy, ah, &fops_modal_eeprom); } EXPORT_SYMBOL(ath9k_cmn_debug_modal_eeprom); @@ -82,7 +82,7 @@ static const struct file_operations fops_base_eeprom = { void ath9k_cmn_debug_base_eeprom(struct dentry *debugfs_phy, struct ath_hw *ah) { - debugfs_create_file("base_eeprom", S_IRUSR, debugfs_phy, ah, + debugfs_create_file("base_eeprom", 0400, debugfs_phy, ah, &fops_base_eeprom); } EXPORT_SYMBOL(ath9k_cmn_debug_base_eeprom); @@ -178,8 +178,7 @@ static const struct file_operations fops_recv = { void ath9k_cmn_debug_recv(struct dentry *debugfs_phy, struct ath_rx_stats *rxstats) { - debugfs_create_file("recv", S_IRUSR, debugfs_phy, rxstats, - &fops_recv); + debugfs_create_file("recv", 0400, debugfs_phy, rxstats, &fops_recv); } EXPORT_SYMBOL(ath9k_cmn_debug_recv); @@ -255,7 +254,7 @@ static const struct file_operations fops_phy_err = { void ath9k_cmn_debug_phy_err(struct dentry *debugfs_phy, struct ath_rx_stats *rxstats) { - debugfs_create_file("phy_err", S_IRUSR, debugfs_phy, rxstats, + debugfs_create_file("phy_err", 0400, debugfs_phy, rxstats, &fops_phy_err); } EXPORT_SYMBOL(ath9k_cmn_debug_phy_err); diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c index 8b4f7fdabf58..82de0fadbc95 100644 --- a/drivers/net/wireless/ath/ath9k/common-init.c +++ b/drivers/net/wireless/ath/ath9k/common-init.c @@ -88,7 +88,7 @@ static const struct ieee80211_channel ath9k_5ghz_chantable[] = { CHAN5G(5825, 37), /* Channel 165 */ }; -/* Atheros hardware rate code addition for short premble */ +/* Atheros hardware rate code addition for short preamble */ #define SHPCHECK(__hw_rate, __flags) \ ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index 5e77fe1f5b0d..440e16e641e4 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -479,14 +479,16 @@ ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv) { int i = 0; int ret = 0; + struct rchan_buf *buf; struct rchan *rc = spec_priv->rfs_chan_spec_scan; - for_each_online_cpu(i) - ret += relay_buf_full(*per_cpu_ptr(rc->buf, i)); - - i = num_online_cpus(); + for_each_possible_cpu(i) { + if ((buf = *per_cpu_ptr(rc->buf, i))) { + ret += relay_buf_full(buf); + } + } - if (ret == i) + if (ret) return 1; else return 0; @@ -1096,23 +1098,23 @@ void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv, return; debugfs_create_file("spectral_scan_ctl", - S_IRUSR | S_IWUSR, + 0600, debugfs_phy, spec_priv, &fops_spec_scan_ctl); debugfs_create_file("spectral_short_repeat", - S_IRUSR | S_IWUSR, + 0600, debugfs_phy, spec_priv, &fops_spectral_short_repeat); debugfs_create_file("spectral_count", - S_IRUSR | S_IWUSR, + 0600, debugfs_phy, spec_priv, &fops_spectral_count); debugfs_create_file("spectral_period", - S_IRUSR | S_IWUSR, + 0600, debugfs_phy, spec_priv, &fops_spectral_period); debugfs_create_file("spectral_fft_period", - S_IRUSR | S_IWUSR, + 0600, debugfs_phy, spec_priv, &fops_spectral_fft_period); } diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 9e8aed5c478c..f685843a2ff3 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -1385,7 +1385,7 @@ int ath9k_init_debug(struct ath_hw *ah) return -ENOMEM; #ifdef CONFIG_ATH_DEBUG - debugfs_create_file("debug", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + debugfs_create_file("debug", 0600, sc->debug.debugfs_phy, sc, &fops_debug); #endif @@ -1409,22 +1409,22 @@ int ath9k_init_debug(struct ath_hw *ah) ath9k_cmn_debug_recv(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); ath9k_cmn_debug_phy_err(sc->debug.debugfs_phy, &sc->debug.stats.rxstats); - debugfs_create_u8("rx_chainmask", S_IRUSR, sc->debug.debugfs_phy, + debugfs_create_u8("rx_chainmask", 0400, sc->debug.debugfs_phy, &ah->rxchainmask); - debugfs_create_u8("tx_chainmask", S_IRUSR, sc->debug.debugfs_phy, + debugfs_create_u8("tx_chainmask", 0400, sc->debug.debugfs_phy, &ah->txchainmask); - debugfs_create_file("ani", S_IRUSR | S_IWUSR, + debugfs_create_file("ani", 0600, sc->debug.debugfs_phy, sc, &fops_ani); - debugfs_create_bool("paprd", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + debugfs_create_bool("paprd", 0600, sc->debug.debugfs_phy, &sc->sc_ah->config.enable_paprd); - debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + debugfs_create_file("regidx", 0600, sc->debug.debugfs_phy, sc, &fops_regidx); - debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + debugfs_create_file("regval", 0600, sc->debug.debugfs_phy, sc, &fops_regval); - debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR, + debugfs_create_bool("ignore_extcca", 0600, sc->debug.debugfs_phy, &ah->config.cwm_ignore_extcca); - debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc, + debugfs_create_file("regdump", 0400, sc->debug.debugfs_phy, sc, &fops_regdump); debugfs_create_devm_seqfile(sc->dev, "dump_nfcal", sc->debug.debugfs_phy, @@ -1433,35 +1433,33 @@ int ath9k_init_debug(struct ath_hw *ah) ath9k_cmn_debug_base_eeprom(sc->debug.debugfs_phy, sc->sc_ah); ath9k_cmn_debug_modal_eeprom(sc->debug.debugfs_phy, sc->sc_ah); - debugfs_create_u32("gpio_mask", S_IRUSR | S_IWUSR, + debugfs_create_u32("gpio_mask", 0600, sc->debug.debugfs_phy, &sc->sc_ah->gpio_mask); - debugfs_create_u32("gpio_val", S_IRUSR | S_IWUSR, + debugfs_create_u32("gpio_val", 0600, sc->debug.debugfs_phy, &sc->sc_ah->gpio_val); - debugfs_create_file("antenna_diversity", S_IRUSR, + debugfs_create_file("antenna_diversity", 0400, sc->debug.debugfs_phy, sc, &fops_antenna_diversity); #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT - debugfs_create_file("bt_ant_diversity", S_IRUSR | S_IWUSR, + debugfs_create_file("bt_ant_diversity", 0600, sc->debug.debugfs_phy, sc, &fops_bt_ant_diversity); - debugfs_create_file("btcoex", S_IRUSR, sc->debug.debugfs_phy, sc, + debugfs_create_file("btcoex", 0400, sc->debug.debugfs_phy, sc, &fops_btcoex); #endif #ifdef CONFIG_ATH9K_WOW - debugfs_create_file("wow", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_wow); + debugfs_create_file("wow", 0600, sc->debug.debugfs_phy, sc, &fops_wow); #endif #ifdef CONFIG_ATH9K_DYNACK - debugfs_create_file("ack_to", S_IRUSR, sc->debug.debugfs_phy, + debugfs_create_file("ack_to", 0400, sc->debug.debugfs_phy, sc, &fops_ackto); #endif - debugfs_create_file("tpc", S_IRUSR | S_IWUSR, - sc->debug.debugfs_phy, sc, &fops_tpc); + debugfs_create_file("tpc", 0600, sc->debug.debugfs_phy, sc, &fops_tpc); - debugfs_create_u16("airtime_flags", S_IRUSR | S_IWUSR, + debugfs_create_u16("airtime_flags", 0600, sc->debug.debugfs_phy, &sc->airtime_flags); - debugfs_create_file("nf_override", S_IRUSR | S_IWUSR, + debugfs_create_file("nf_override", 0600, sc->debug.debugfs_phy, sc, &fops_nf_override); return 0; diff --git a/drivers/net/wireless/ath/ath9k/debug_sta.c b/drivers/net/wireless/ath/ath9k/debug_sta.c index efc692ee67d4..a6f45f1bb5bb 100644 --- a/drivers/net/wireless/ath/ath9k/debug_sta.c +++ b/drivers/net/wireless/ath/ath9k/debug_sta.c @@ -302,7 +302,7 @@ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw, { struct ath_node *an = (struct ath_node *)sta->drv_priv; - debugfs_create_file("node_aggr", S_IRUGO, dir, an, &fops_node_aggr); - debugfs_create_file("node_recv", S_IRUGO, dir, an, &fops_node_recv); - debugfs_create_file("airtime", S_IRUGO, dir, an, &fops_airtime); + debugfs_create_file("node_aggr", 0444, dir, an, &fops_node_aggr); + debugfs_create_file("node_recv", 0444, dir, an, &fops_node_recv); + debugfs_create_file("airtime", 0444, dir, an, &fops_airtime); } diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c index 8824610c21fb..3251c9abe270 100644 --- a/drivers/net/wireless/ath/ath9k/dfs_debug.c +++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c @@ -144,8 +144,8 @@ static const struct file_operations fops_dfs_stats = { void ath9k_dfs_init_debug(struct ath_softc *sc) { - debugfs_create_file("dfs_stats", S_IRUSR, + debugfs_create_file("dfs_stats", 0400, sc->debug.debugfs_phy, sc, &fops_dfs_stats); - debugfs_create_file("dfs_simulate_radar", S_IWUSR, + debugfs_create_file("dfs_simulate_radar", 0200, sc->debug.debugfs_phy, sc, &fops_simulate_radar); } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c index dc79afd7e151..b3ed65e5c4da 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c @@ -496,25 +496,25 @@ int ath9k_htc_init_debug(struct ath_hw *ah) ath9k_cmn_spectral_init_debug(&priv->spec_priv, priv->debug.debugfs_phy); - debugfs_create_file("tgt_int_stats", S_IRUSR, priv->debug.debugfs_phy, + debugfs_create_file("tgt_int_stats", 0400, priv->debug.debugfs_phy, priv, &fops_tgt_int_stats); - debugfs_create_file("tgt_tx_stats", S_IRUSR, priv->debug.debugfs_phy, + debugfs_create_file("tgt_tx_stats", 0400, priv->debug.debugfs_phy, priv, &fops_tgt_tx_stats); - debugfs_create_file("tgt_rx_stats", S_IRUSR, priv->debug.debugfs_phy, + debugfs_create_file("tgt_rx_stats", 0400, priv->debug.debugfs_phy, priv, &fops_tgt_rx_stats); - debugfs_create_file("xmit", S_IRUSR, priv->debug.debugfs_phy, + debugfs_create_file("xmit", 0400, priv->debug.debugfs_phy, priv, &fops_xmit); - debugfs_create_file("skb_rx", S_IRUSR, priv->debug.debugfs_phy, + debugfs_create_file("skb_rx", 0400, priv->debug.debugfs_phy, priv, &fops_skb_rx); ath9k_cmn_debug_recv(priv->debug.debugfs_phy, &priv->debug.rx_stats); ath9k_cmn_debug_phy_err(priv->debug.debugfs_phy, &priv->debug.rx_stats); - debugfs_create_file("slot", S_IRUSR, priv->debug.debugfs_phy, + debugfs_create_file("slot", 0400, priv->debug.debugfs_phy, priv, &fops_slot); - debugfs_create_file("queue", S_IRUSR, priv->debug.debugfs_phy, + debugfs_create_file("queue", 0400, priv->debug.debugfs_phy, priv, &fops_queue); - debugfs_create_file("debug", S_IRUSR | S_IWUSR, priv->debug.debugfs_phy, + debugfs_create_file("debug", 0600, priv->debug.debugfs_phy, priv, &fops_debug); ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index f246e9ed4a81..214c68269a69 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -591,7 +591,7 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv) { struct ath_common *common = ath9k_hw_common(priv->ah); - memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); + eth_broadcast_addr(common->bssidmask); common->last_rssi = ATH_RSSI_DUMMY_MARKER; priv->ah->opmode = NL80211_IFTYPE_STATION; diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index cd0f023ccf77..6b37036b2d36 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -184,7 +184,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah, break; case WLAN_RC_PHY_OFDM: if (ah->curchan && IS_CHAN_QUARTER_RATE(ah->curchan)) { - bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; + bitsPerSymbol = + ((kbps >> 2) * OFDM_SYMBOL_TIME_QUARTER) / 1000; numBits = OFDM_PLCP_BITS + (frameLen << 3); numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); txTime = OFDM_SIFS_TIME_QUARTER @@ -192,7 +193,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah, + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); } else if (ah->curchan && IS_CHAN_HALF_RATE(ah->curchan)) { - bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; + bitsPerSymbol = + ((kbps >> 1) * OFDM_SYMBOL_TIME_HALF) / 1000; numBits = OFDM_PLCP_BITS + (frameLen << 3); numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); txTime = OFDM_SIFS_TIME_HALF + @@ -1036,7 +1038,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) int acktimeout, ctstimeout, ack_offset = 0; int slottime; int sifstime; - int rx_lat = 0, tx_lat = 0, eifs = 0; + int rx_lat = 0, tx_lat = 0, eifs = 0, ack_shift = 0; u32 reg; ath_dbg(ath9k_hw_common(ah), RESET, "ah->misc_mode 0x%x\n", @@ -1068,6 +1070,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) sifstime = 32; ack_offset = 16; + ack_shift = 3; slottime = 13; } else if (IS_CHAN_QUARTER_RATE(chan)) { eifs = 340; @@ -1078,6 +1081,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) sifstime = 64; ack_offset = 32; + ack_shift = 1; slottime = 21; } else { if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) { @@ -1134,6 +1138,10 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) SM(tx_lat, AR_USEC_TX_LAT), AR_USEC_TX_LAT | AR_USEC_RX_LAT | AR_USEC_USEC); + if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan)) + REG_RMW(ah, AR_TXSIFS, + sifstime | SM(ack_shift, AR_TXSIFS_ACK_SHIFT), + (AR_TXSIFS_TIME | AR_TXSIFS_ACK_SHIFT)); } EXPORT_SYMBOL(ath9k_hw_init_global_settings); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index e479fae5aab9..c070a9e51ebf 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -257,6 +257,11 @@ static void ath9k_reg_notifier(struct wiphy *wiphy, ath_reg_notifier_apply(wiphy, request, reg); + /* synchronize DFS detector if regulatory domain changed */ + if (sc->dfs_detector != NULL) + sc->dfs_detector->set_dfs_domain(sc->dfs_detector, + request->dfs_region); + /* Set tx power */ if (!ah->curchan) return; @@ -267,10 +272,6 @@ static void ath9k_reg_notifier(struct wiphy *wiphy, ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, sc->cur_chan->txpower, &sc->cur_chan->cur_txpower); - /* synchronize DFS detector if regulatory domain changed */ - if (sc->dfs_detector != NULL) - sc->dfs_detector->set_dfs_domain(sc->dfs_detector, - request->dfs_region); ath9k_ps_restore(sc); } @@ -427,7 +428,7 @@ static void ath9k_init_misc(struct ath_softc *sc) timer_setup(&common->ani.timer, ath_ani_calibrate, 0); common->last_rssi = ATH_RSSI_DUMMY_MARKER; - memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); + eth_broadcast_addr(common->bssidmask); sc->beacon.slottime = 9; for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) diff --git a/drivers/net/wireless/ath/ath9k/tx99.c b/drivers/net/wireless/ath/ath9k/tx99.c index fe3a8263b224..ce50d8f5835e 100644 --- a/drivers/net/wireless/ath/ath9k/tx99.c +++ b/drivers/net/wireless/ath/ath9k/tx99.c @@ -278,10 +278,10 @@ void ath9k_tx99_init_debug(struct ath_softc *sc) if (!AR_SREV_9280_20_OR_LATER(sc->sc_ah)) return; - debugfs_create_file("tx99", S_IRUSR | S_IWUSR, + debugfs_create_file("tx99", 0600, sc->debug.debugfs_phy, sc, &fops_tx99); - debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR, + debugfs_create_file("tx99_power", 0600, sc->debug.debugfs_phy, sc, &fops_tx99_power); } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 396bf05c6bf6..d8b041f48ca8 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2892,6 +2892,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) struct ath_txq *txq; int tidno; + rcu_read_lock(); + for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { tid = ath_node_to_tid(an, tidno); txq = tid->txq; @@ -2909,6 +2911,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) if (!an->sta) break; /* just one multicast ath_atx_tid */ } + + rcu_read_unlock(); } #ifdef CONFIG_ATH9K_TX99 diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c index ec3a64e5d2bb..a9b6dc17e408 100644 --- a/drivers/net/wireless/ath/carl9170/debug.c +++ b/drivers/net/wireless/ath/carl9170/debug.c @@ -187,21 +187,21 @@ static const struct carl9170_debugfs_fops carl_debugfs_##name ##_ops = {\ #define DEBUGFS_DECLARE_RO_FILE(name, _read_bufsize) \ DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \ - NULL, _read_bufsize, S_IRUSR) + NULL, _read_bufsize, 0400) #define DEBUGFS_DECLARE_WO_FILE(name) \ DEBUGFS_DECLARE_FILE(name, NULL, carl9170_debugfs_##name ##_write,\ - 0, S_IWUSR) + 0, 0200) #define DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize) \ DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \ carl9170_debugfs_##name ##_write, \ - _read_bufsize, S_IRUSR | S_IWUSR) + _read_bufsize, 0600) #define __DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize, _dstate) \ __DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \ carl9170_debugfs_##name ##_write, \ - _read_bufsize, S_IRUSR | S_IWUSR, _dstate) + _read_bufsize, 0600, _dstate) #define DEBUGFS_READONLY_FILE(name, _read_bufsize, fmt, value...) \ static char *carl9170_debugfs_ ##name ## _read(struct ar9170 *ar, \ diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 988c8857d78c..29e93c953d93 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -48,11 +48,11 @@ #include "cmd.h" static bool modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware crypto offload."); int modparam_noht; -module_param_named(noht, modparam_noht, int, S_IRUGO); +module_param_named(noht, modparam_noht, int, 0444); MODULE_PARM_DESC(noht, "Disable MPDU aggregation."); #define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c index 4100ffd42a43..448b83eea810 100644 --- a/drivers/net/wireless/ath/dfs_pattern_detector.c +++ b/drivers/net/wireless/ath/dfs_pattern_detector.c @@ -115,7 +115,7 @@ static const struct radar_detector_specs jp_radar_ref_types[] = { JP_PATTERN(4, 0, 5, 150, 230, 1, 23, 50, false), JP_PATTERN(5, 6, 10, 200, 500, 1, 16, 50, false), JP_PATTERN(6, 11, 20, 200, 500, 1, 12, 50, false), - JP_PATTERN(7, 50, 100, 1000, 2000, 1, 3, 50, false), + JP_PATTERN(7, 50, 100, 1000, 2000, 1, 3, 50, true), JP_PATTERN(5, 0, 1, 333, 333, 1, 9, 50, false), }; diff --git a/drivers/net/wireless/ath/wcn36xx/debug.c b/drivers/net/wireless/ath/wcn36xx/debug.c index 2a6bb62e785c..389b5e7129a6 100644 --- a/drivers/net/wireless/ath/wcn36xx/debug.c +++ b/drivers/net/wireless/ath/wcn36xx/debug.c @@ -161,9 +161,8 @@ void wcn36xx_debugfs_init(struct wcn36xx *wcn) dfs->rootdir = NULL; } - ADD_FILE(bmps_switcher, S_IRUSR | S_IWUSR, - &fops_wcn36xx_bmps, wcn); - ADD_FILE(dump, S_IWUSR, &fops_wcn36xx_dump, wcn); + ADD_FILE(bmps_switcher, 0600, &fops_wcn36xx_bmps, wcn); + ADD_FILE(dump, 0200, &fops_wcn36xx_dump, wcn); } void wcn36xx_debugfs_exit(struct wcn36xx *wcn) diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index a3f1f7d042a4..2c3b899a88fa 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -27,15 +27,6 @@ #include "wcn36xx.h" #include "txrx.h" -void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low) -{ - struct wcn36xx_dxe_ch *ch = is_low ? - &wcn->dxe_tx_l_ch : - &wcn->dxe_tx_h_ch; - - return ch->head_blk_ctl->bd_cpu_addr; -} - static void wcn36xx_ccu_write_register(struct wcn36xx *wcn, int addr, int data) { wcn36xx_dbg(WCN36XX_DBG_DXE, @@ -376,7 +367,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) spin_lock_irqsave(&ch->lock, flags); ctl = ch->tail_blk_ctl; do { - if (ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK) + if (ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD) break; if (ctl->skb) { dma_unmap_single(wcn->dev, ctl->desc->src_addr_l, @@ -397,7 +388,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) } ctl = ctl->next; } while (ctl != ch->head_blk_ctl && - !(ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)); + !(ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD)); ch->tail_blk_ctl = ctl; spin_unlock_irqrestore(&ch->lock, flags); @@ -415,14 +406,31 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev) WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_H, &int_reason); - /* TODO: Check int_reason */ - wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR, WCN36XX_INT_MASK_CHAN_TX_H); - wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR, - WCN36XX_INT_MASK_CHAN_TX_H); + if (int_reason & WCN36XX_CH_STAT_INT_ERR_MASK ) { + wcn36xx_dxe_write_register(wcn, + WCN36XX_DXE_0_INT_ERR_CLR, + WCN36XX_INT_MASK_CHAN_TX_H); + + wcn36xx_err("DXE IRQ reported error: 0x%x in high TX channel\n", + int_src); + } + + if (int_reason & WCN36XX_CH_STAT_INT_DONE_MASK) { + wcn36xx_dxe_write_register(wcn, + WCN36XX_DXE_0_INT_DONE_CLR, + WCN36XX_INT_MASK_CHAN_TX_H); + } + + if (int_reason & WCN36XX_CH_STAT_INT_ED_MASK) { + wcn36xx_dxe_write_register(wcn, + WCN36XX_DXE_0_INT_ED_CLR, + WCN36XX_INT_MASK_CHAN_TX_H); + } + wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready high\n"); reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch); } @@ -431,14 +439,33 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev) wcn36xx_dxe_read_register(wcn, WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_L, &int_reason); - /* TODO: Check int_reason */ wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_CLR, WCN36XX_INT_MASK_CHAN_TX_L); - wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR, - WCN36XX_INT_MASK_CHAN_TX_L); + + if (int_reason & WCN36XX_CH_STAT_INT_ERR_MASK ) { + wcn36xx_dxe_write_register(wcn, + WCN36XX_DXE_0_INT_ERR_CLR, + WCN36XX_INT_MASK_CHAN_TX_L); + + wcn36xx_err("DXE IRQ reported error: 0x%x in low TX channel\n", + int_src); + } + + if (int_reason & WCN36XX_CH_STAT_INT_DONE_MASK) { + wcn36xx_dxe_write_register(wcn, + WCN36XX_DXE_0_INT_DONE_CLR, + WCN36XX_INT_MASK_CHAN_TX_L); + } + + if (int_reason & WCN36XX_CH_STAT_INT_ED_MASK) { + wcn36xx_dxe_write_register(wcn, + WCN36XX_DXE_0_INT_ED_CLR, + WCN36XX_INT_MASK_CHAN_TX_L); + } + wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready low\n"); reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch); } @@ -503,7 +530,7 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, int_mask = WCN36XX_DXE_INT_CH3_MASK; } - while (!(dxe->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) { + while (!(dxe->ctrl & WCN36xx_DXE_CTRL_VLD)) { skb = ctl->skb; dma_addr = dxe->dst_addr_l; ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl); @@ -612,6 +639,7 @@ void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn) int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, struct wcn36xx_vif *vif_priv, + struct wcn36xx_tx_bd *bd, struct sk_buff *skb, bool is_low) { @@ -645,6 +673,9 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, ctl->skb = NULL; desc = ctl->desc; + /* write buffer descriptor */ + memcpy(ctl->bd_cpu_addr, bd, sizeof(*bd)); + /* Set source address of the BD we send */ desc->src_addr_l = ctl->bd_phy_addr; diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.h b/drivers/net/wireless/ath/wcn36xx/dxe.h index c012e807753b..ce580960d109 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.h +++ b/drivers/net/wireless/ath/wcn36xx/dxe.h @@ -33,15 +33,106 @@ H2H_TEST_RX_TX = DMA2 #define WCN36XX_CCU_DXE_INT_SELECT_RIVA 0x310 #define WCN36XX_CCU_DXE_INT_SELECT_PRONTO 0x10dc -/* TODO This must calculated properly but not hardcoded */ -#define WCN36XX_DXE_CTRL_TX_L 0x328a44 -#define WCN36XX_DXE_CTRL_TX_H 0x32ce44 -#define WCN36XX_DXE_CTRL_RX_L 0x12ad2f -#define WCN36XX_DXE_CTRL_RX_H 0x12d12f -#define WCN36XX_DXE_CTRL_TX_H_BD 0x30ce45 -#define WCN36XX_DXE_CTRL_TX_H_SKB 0x32ce4d -#define WCN36XX_DXE_CTRL_TX_L_BD 0x308a45 -#define WCN36XX_DXE_CTRL_TX_L_SKB 0x328a4d +/* Descriptor valid */ +#define WCN36xx_DXE_CTRL_VLD BIT(0) +/* End of packet */ +#define WCN36xx_DXE_CTRL_EOP BIT(3) +/* BD handling bit */ +#define WCN36xx_DXE_CTRL_BDH BIT(4) +/* Source is a queue */ +#define WCN36xx_DXE_CTRL_SIQ BIT(5) +/* Destination is a queue */ +#define WCN36xx_DXE_CTRL_DIQ BIT(6) +/* Pointer address is a queue */ +#define WCN36xx_DXE_CTRL_PIQ BIT(7) +/* Release PDU when done */ +#define WCN36xx_DXE_CTRL_PDU_REL BIT(8) +/* STOP channel processing */ +#define WCN36xx_DXE_CTRL_STOP BIT(16) +/* INT on descriptor done */ +#define WCN36xx_DXE_CTRL_INT BIT(17) +/* Endian byte swap enable */ +#define WCN36xx_DXE_CTRL_SWAP BIT(20) +/* Master endianness */ +#define WCN36xx_DXE_CTRL_ENDIANNESS BIT(21) + +/* Transfer type */ +#define WCN36xx_DXE_CTRL_XTYPE_SHIFT 1 +#define WCN36xx_DXE_CTRL_XTYPE_MASK GENMASK(2, WCN36xx_DXE_CTRL_XTYPE_SHIFT) +#define WCN36xx_DXE_CTRL_XTYPE_SET(x) ((x) << WCN36xx_DXE_CTRL_XTYPE_SHIFT) + +/* BMU Threshold select */ +#define WCN36xx_DXE_CTRL_BTHLD_SEL_SHIFT 9 +#define WCN36xx_DXE_CTRL_BTHLD_SEL_MASK GENMASK(12, WCN36xx_DXE_CTRL_BTHLD_SEL_SHIFT) +#define WCN36xx_DXE_CTRL_BTHLD_SEL_SET(x) ((x) << WCN36xx_DXE_CTRL_BTHLD_SEL_SHIFT) + +/* Priority */ +#define WCN36xx_DXE_CTRL_PRIO_SHIFT 13 +#define WCN36xx_DXE_CTRL_PRIO_MASK GENMASK(15, WCN36xx_DXE_CTRL_PRIO_SHIFT) +#define WCN36xx_DXE_CTRL_PRIO_SET(x) ((x) << WCN36xx_DXE_CTRL_PRIO_SHIFT) + +/* BD Template index */ +#define WCN36xx_DXE_CTRL_BDT_IDX_SHIFT 18 +#define WCN36xx_DXE_CTRL_BDT_IDX_MASK GENMASK(19, WCN36xx_DXE_CTRL_BDT_IDX_SHIFT) +#define WCN36xx_DXE_CTRL_BDT_IDX_SET(x) ((x) << WCN36xx_DXE_CTRL_BDT_IDX_SHIFT) + +/* Transfer types: */ +/* Host to host */ +#define WCN36xx_DXE_XTYPE_H2H (0) +/* Host to BMU */ +#define WCN36xx_DXE_XTYPE_H2B (2) +/* BMU to host */ +#define WCN36xx_DXE_XTYPE_B2H (3) + +#define WCN36XX_DXE_CTRL_TX_L (WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \ + WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(5) | \ + WCN36xx_DXE_CTRL_PRIO_SET(4) | WCN36xx_DXE_CTRL_INT | \ + WCN36xx_DXE_CTRL_SWAP | WCN36xx_DXE_CTRL_ENDIANNESS) + +#define WCN36XX_DXE_CTRL_TX_H (WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \ + WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(7) | \ + WCN36xx_DXE_CTRL_PRIO_SET(6) | WCN36xx_DXE_CTRL_INT | \ + WCN36xx_DXE_CTRL_SWAP | WCN36xx_DXE_CTRL_ENDIANNESS) + +#define WCN36XX_DXE_CTRL_RX_L (WCN36xx_DXE_CTRL_VLD | \ + WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \ + WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_SIQ | \ + WCN36xx_DXE_CTRL_PDU_REL | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(6) | \ + WCN36xx_DXE_CTRL_PRIO_SET(5) | WCN36xx_DXE_CTRL_INT | \ + WCN36xx_DXE_CTRL_SWAP) + +#define WCN36XX_DXE_CTRL_RX_H (WCN36xx_DXE_CTRL_VLD | \ + WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \ + WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_SIQ | \ + WCN36xx_DXE_CTRL_PDU_REL | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(8) | \ + WCN36xx_DXE_CTRL_PRIO_SET(6) | WCN36xx_DXE_CTRL_INT | \ + WCN36xx_DXE_CTRL_SWAP) + +#define WCN36XX_DXE_CTRL_TX_H_BD (WCN36xx_DXE_CTRL_VLD | \ + WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \ + WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(7) | \ + WCN36xx_DXE_CTRL_PRIO_SET(6) | WCN36xx_DXE_CTRL_SWAP | \ + WCN36xx_DXE_CTRL_ENDIANNESS) + +#define WCN36XX_DXE_CTRL_TX_H_SKB (WCN36xx_DXE_CTRL_VLD | \ + WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \ + WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_DIQ | \ + WCN36xx_DXE_CTRL_BTHLD_SEL_SET(7) | WCN36xx_DXE_CTRL_PRIO_SET(6) | \ + WCN36xx_DXE_CTRL_INT | WCN36xx_DXE_CTRL_SWAP | \ + WCN36xx_DXE_CTRL_ENDIANNESS) + +#define WCN36XX_DXE_CTRL_TX_L_BD (WCN36xx_DXE_CTRL_VLD | \ + WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \ + WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(5) | \ + WCN36xx_DXE_CTRL_PRIO_SET(4) | WCN36xx_DXE_CTRL_SWAP | \ + WCN36xx_DXE_CTRL_ENDIANNESS) + +#define WCN36XX_DXE_CTRL_TX_L_SKB (WCN36xx_DXE_CTRL_VLD | \ + WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \ + WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_DIQ | \ + WCN36xx_DXE_CTRL_BTHLD_SEL_SET(5) | WCN36xx_DXE_CTRL_PRIO_SET(4) | \ + WCN36xx_DXE_CTRL_INT | WCN36xx_DXE_CTRL_SWAP | \ + WCN36xx_DXE_CTRL_ENDIANNESS) /* TODO This must calculated properly but not hardcoded */ #define WCN36XX_DXE_WQ_TX_L 0x17 @@ -49,15 +140,106 @@ H2H_TEST_RX_TX = DMA2 #define WCN36XX_DXE_WQ_RX_L 0xB #define WCN36XX_DXE_WQ_RX_H 0x4 -/* DXE descriptor control filed */ -#define WCN36XX_DXE_CTRL_VALID_MASK (0x00000001) +/* Channel enable or restart */ +#define WCN36xx_DXE_CH_CTRL_EN BIT(0) +/* End of packet bit */ +#define WCN36xx_DXE_CH_CTRL_EOP BIT(3) +/* BD Handling bit */ +#define WCN36xx_DXE_CH_CTRL_BDH BIT(4) +/* Source is queue */ +#define WCN36xx_DXE_CH_CTRL_SIQ BIT(5) +/* Destination is queue */ +#define WCN36xx_DXE_CH_CTRL_DIQ BIT(6) +/* Pointer descriptor is queue */ +#define WCN36xx_DXE_CH_CTRL_PIQ BIT(7) +/* Relase PDU when done */ +#define WCN36xx_DXE_CH_CTRL_PDU_REL BIT(8) +/* Stop channel processing */ +#define WCN36xx_DXE_CH_CTRL_STOP BIT(16) +/* Enable external descriptor interrupt */ +#define WCN36xx_DXE_CH_CTRL_INE_ED BIT(17) +/* Enable channel interrupt on errors */ +#define WCN36xx_DXE_CH_CTRL_INE_ERR BIT(18) +/* Enable Channel interrupt when done */ +#define WCN36xx_DXE_CH_CTRL_INE_DONE BIT(19) +/* External descriptor enable */ +#define WCN36xx_DXE_CH_CTRL_EDEN BIT(20) +/* Wait for valid bit */ +#define WCN36xx_DXE_CH_CTRL_EDVEN BIT(21) +/* Endianness is little endian*/ +#define WCN36xx_DXE_CH_CTRL_ENDIANNESS BIT(26) +/* Abort transfer */ +#define WCN36xx_DXE_CH_CTRL_ABORT BIT(27) +/* Long descriptor format */ +#define WCN36xx_DXE_CH_CTRL_DFMT BIT(28) +/* Endian byte swap enable */ +#define WCN36xx_DXE_CH_CTRL_SWAP BIT(31) + +/* Transfer type */ +#define WCN36xx_DXE_CH_CTRL_XTYPE_SHIFT 1 +#define WCN36xx_DXE_CH_CTRL_XTYPE_MASK GENMASK(2, WCN36xx_DXE_CH_CTRL_XTYPE_SHIFT) +#define WCN36xx_DXE_CH_CTRL_XTYPE_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_XTYPE_SHIFT) + +/* Channel BMU Threshold select */ +#define WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SHIFT 9 +#define WCN36xx_DXE_CH_CTRL_BTHLD_SEL_MASK GENMASK(12, WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SHIFT) +#define WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SHIFT) + +/* Channel Priority */ +#define WCN36xx_DXE_CH_CTRL_PRIO_SHIFT 13 +#define WCN36xx_DXE_CH_CTRL_PRIO_MASK GENMASK(15, WCN36xx_DXE_CH_CTRL_PRIO_SHIFT) +#define WCN36xx_DXE_CH_CTRL_PRIO_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_PRIO_SHIFT) + +/* Counter select */ +#define WCN36xx_DXE_CH_CTRL_SEL_SHIFT 22 +#define WCN36xx_DXE_CH_CTRL_SEL_MASK GENMASK(25, WCN36xx_DXE_CH_CTRL_SEL_SHIFT) +#define WCN36xx_DXE_CH_CTRL_SEL_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_SEL_SHIFT) + +/* Channel BD template index */ +#define WCN36xx_DXE_CH_CTRL_BDT_IDX_SHIFT 29 +#define WCN36xx_DXE_CH_CTRL_BDT_IDX_MASK GENMASK(30, WCN36xx_DXE_CH_CTRL_BDT_IDX_SHIFT) +#define WCN36xx_DXE_CH_CTRL_BDT_IDX_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_BDT_IDX_SHIFT) -/* TODO This must calculated properly but not hardcoded */ /* DXE default control register values */ -#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_L 0x847EAD2F -#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_H 0x84FED12F -#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_H 0x853ECF4D -#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_L 0x843e8b4d +#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_L (WCN36xx_DXE_CH_CTRL_EN | \ + WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \ + WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_SIQ | \ + WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(6) | \ + WCN36xx_DXE_CH_CTRL_PRIO_SET(5) | WCN36xx_DXE_CH_CTRL_INE_ED | \ + WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \ + WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \ + WCN36xx_DXE_CH_CTRL_SEL_SET(1) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \ + WCN36xx_DXE_CH_CTRL_SWAP) + +#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_H (WCN36xx_DXE_CH_CTRL_EN | \ + WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \ + WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_SIQ | \ + WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(8) | \ + WCN36xx_DXE_CH_CTRL_PRIO_SET(6) | WCN36xx_DXE_CH_CTRL_INE_ED | \ + WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \ + WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \ + WCN36xx_DXE_CH_CTRL_SEL_SET(3) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \ + WCN36xx_DXE_CH_CTRL_SWAP) + +#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_H (WCN36xx_DXE_CH_CTRL_EN | \ + WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \ + WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_DIQ | \ + WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(7) | \ + WCN36xx_DXE_CH_CTRL_PRIO_SET(6) | WCN36xx_DXE_CH_CTRL_INE_ED | \ + WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \ + WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \ + WCN36xx_DXE_CH_CTRL_SEL_SET(4) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \ + WCN36xx_DXE_CH_CTRL_SWAP) + +#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_L (WCN36xx_DXE_CH_CTRL_EN | \ + WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \ + WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_DIQ | \ + WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(5) | \ + WCN36xx_DXE_CH_CTRL_PRIO_SET(4) | WCN36xx_DXE_CH_CTRL_INE_ED | \ + WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \ + WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \ + WCN36xx_DXE_CH_CTRL_SEL_SET(0) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \ + WCN36xx_DXE_CH_CTRL_SWAP) /* Common DXE registers */ #define WCN36XX_DXE_MEM_CSR (WCN36XX_DXE_MEM_REG + 0x00) @@ -80,6 +262,10 @@ H2H_TEST_RX_TX = DMA2 #define WCN36XX_DXE_0_INT_DONE_CLR (WCN36XX_DXE_MEM_REG + 0x38) #define WCN36XX_DXE_0_INT_ERR_CLR (WCN36XX_DXE_MEM_REG + 0x3C) +#define WCN36XX_CH_STAT_INT_DONE_MASK 0x00008000 +#define WCN36XX_CH_STAT_INT_ERR_MASK 0x00004000 +#define WCN36XX_CH_STAT_INT_ED_MASK 0x00002000 + #define WCN36XX_DXE_0_CH0_STATUS (WCN36XX_DXE_MEM_REG + 0x404) #define WCN36XX_DXE_0_CH1_STATUS (WCN36XX_DXE_MEM_REG + 0x444) #define WCN36XX_DXE_0_CH2_STATUS (WCN36XX_DXE_MEM_REG + 0x484) @@ -266,6 +452,7 @@ struct wcn36xx_dxe_mem_pool { dma_addr_t phy_addr; }; +struct wcn36xx_tx_bd; struct wcn36xx_vif; int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn); void wcn36xx_dxe_free_mem_pools(struct wcn36xx *wcn); @@ -277,8 +464,8 @@ void wcn36xx_dxe_deinit(struct wcn36xx *wcn); int wcn36xx_dxe_init_channels(struct wcn36xx *wcn); int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, struct wcn36xx_vif *vif_priv, + struct wcn36xx_tx_bd *bd, struct sk_buff *skb, bool is_low); void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status); -void *wcn36xx_dxe_get_next_bd(struct wcn36xx *wcn, bool is_low); #endif /* _DXE_H_ */ diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index ab5be6d2c691..69d6be59d97f 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -261,7 +261,7 @@ static void wcn36xx_feat_caps_info(struct wcn36xx *wcn) for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) { if (get_feat_caps(wcn->fw_feat_caps, i)) - wcn36xx_info("FW Cap %s\n", wcn36xx_get_cap_name(i)); + wcn36xx_dbg(WCN36XX_DBG_MAC, "FW Cap %s\n", wcn36xx_get_cap_name(i)); } } @@ -666,16 +666,13 @@ static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw, { struct wcn36xx *wcn = hw->priv; - if (!wcn36xx_smd_stop_hw_scan(wcn)) { - struct cfg80211_scan_info scan_info = { .aborted = true }; - - ieee80211_scan_completed(wcn->hw, &scan_info); - } - mutex_lock(&wcn->scan_lock); wcn->scan_aborted = true; mutex_unlock(&wcn->scan_lock); + /* ieee80211_scan_completed will be called on FW scan indication */ + wcn36xx_smd_stop_hw_scan(wcn); + cancel_work_sync(&wcn->scan_work); } @@ -1155,8 +1152,6 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) wcn->hw->wiphy->cipher_suites = cipher_suites; wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); - wcn->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; - #ifdef CONFIG_PM wcn->hw->wiphy->wowlan = &wowlan_support; #endif @@ -1283,6 +1278,7 @@ static int wcn36xx_probe(struct platform_device *pdev) wcn = hw->priv; wcn->hw = hw; wcn->dev = &pdev->dev; + wcn->first_boot = true; mutex_init(&wcn->conf_mutex); mutex_init(&wcn->hal_mutex); mutex_init(&wcn->scan_lock); diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c index 2a4871ca9c72..8932af5e4d8d 100644 --- a/drivers/net/wireless/ath/wcn36xx/smd.c +++ b/drivers/net/wireless/ath/wcn36xx/smd.c @@ -409,15 +409,17 @@ static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len) wcn->fw_minor = rsp->start_rsp_params.version.minor; wcn->fw_major = rsp->start_rsp_params.version.major; - wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n", - wcn->wlan_version, wcn->crm_version); - - wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n", - wcn->fw_major, wcn->fw_minor, - wcn->fw_version, wcn->fw_revision, - rsp->start_rsp_params.stations, - rsp->start_rsp_params.bssids); + if (wcn->first_boot) { + wcn->first_boot = false; + wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n", + wcn->wlan_version, wcn->crm_version); + wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n", + wcn->fw_major, wcn->fw_minor, + wcn->fw_version, wcn->fw_revision, + rsp->start_rsp_params.stations, + rsp->start_rsp_params.bssids); + } return 0; } @@ -2138,6 +2140,8 @@ static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len) case WCN36XX_HAL_SCAN_IND_COMPLETED: mutex_lock(&wcn->scan_lock); wcn->scan_req = NULL; + if (wcn->scan_aborted) + scan_info.aborted = true; mutex_unlock(&wcn->scan_lock); ieee80211_scan_completed(wcn->hw, &scan_info); break; @@ -2407,54 +2411,63 @@ static void wcn36xx_ind_smd_work(struct work_struct *work) { struct wcn36xx *wcn = container_of(work, struct wcn36xx, hal_ind_work); - struct wcn36xx_hal_msg_header *msg_header; - struct wcn36xx_hal_ind_msg *hal_ind_msg; - unsigned long flags; - spin_lock_irqsave(&wcn->hal_ind_lock, flags); + for (;;) { + struct wcn36xx_hal_msg_header *msg_header; + struct wcn36xx_hal_ind_msg *hal_ind_msg; + unsigned long flags; - hal_ind_msg = list_first_entry(&wcn->hal_ind_queue, - struct wcn36xx_hal_ind_msg, - list); - list_del(wcn->hal_ind_queue.next); - spin_unlock_irqrestore(&wcn->hal_ind_lock, flags); + spin_lock_irqsave(&wcn->hal_ind_lock, flags); - msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg; + if (list_empty(&wcn->hal_ind_queue)) { + spin_unlock_irqrestore(&wcn->hal_ind_lock, flags); + return; + } - switch (msg_header->msg_type) { - case WCN36XX_HAL_COEX_IND: - case WCN36XX_HAL_DEL_BA_IND: - case WCN36XX_HAL_AVOID_FREQ_RANGE_IND: - break; - case WCN36XX_HAL_OTA_TX_COMPL_IND: - wcn36xx_smd_tx_compl_ind(wcn, - hal_ind_msg->msg, - hal_ind_msg->msg_len); - break; - case WCN36XX_HAL_MISSED_BEACON_IND: - wcn36xx_smd_missed_beacon_ind(wcn, - hal_ind_msg->msg, - hal_ind_msg->msg_len); - break; - case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: - wcn36xx_smd_delete_sta_context_ind(wcn, - hal_ind_msg->msg, - hal_ind_msg->msg_len); - break; - case WCN36XX_HAL_PRINT_REG_INFO_IND: - wcn36xx_smd_print_reg_info_ind(wcn, - hal_ind_msg->msg, - hal_ind_msg->msg_len); - break; - case WCN36XX_HAL_SCAN_OFFLOAD_IND: - wcn36xx_smd_hw_scan_ind(wcn, hal_ind_msg->msg, - hal_ind_msg->msg_len); - break; - default: - wcn36xx_err("SMD_EVENT (%d) not supported\n", - msg_header->msg_type); + hal_ind_msg = list_first_entry(&wcn->hal_ind_queue, + struct wcn36xx_hal_ind_msg, + list); + list_del(&hal_ind_msg->list); + spin_unlock_irqrestore(&wcn->hal_ind_lock, flags); + + msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg; + + switch (msg_header->msg_type) { + case WCN36XX_HAL_COEX_IND: + case WCN36XX_HAL_DEL_BA_IND: + case WCN36XX_HAL_AVOID_FREQ_RANGE_IND: + break; + case WCN36XX_HAL_OTA_TX_COMPL_IND: + wcn36xx_smd_tx_compl_ind(wcn, + hal_ind_msg->msg, + hal_ind_msg->msg_len); + break; + case WCN36XX_HAL_MISSED_BEACON_IND: + wcn36xx_smd_missed_beacon_ind(wcn, + hal_ind_msg->msg, + hal_ind_msg->msg_len); + break; + case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: + wcn36xx_smd_delete_sta_context_ind(wcn, + hal_ind_msg->msg, + hal_ind_msg->msg_len); + break; + case WCN36XX_HAL_PRINT_REG_INFO_IND: + wcn36xx_smd_print_reg_info_ind(wcn, + hal_ind_msg->msg, + hal_ind_msg->msg_len); + break; + case WCN36XX_HAL_SCAN_OFFLOAD_IND: + wcn36xx_smd_hw_scan_ind(wcn, hal_ind_msg->msg, + hal_ind_msg->msg_len); + break; + default: + wcn36xx_err("SMD_EVENT (%d) not supported\n", + msg_header->msg_type); + } + + kfree(hal_ind_msg); } - kfree(hal_ind_msg); } int wcn36xx_smd_open(struct wcn36xx *wcn) { diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c index 22304edc5948..b1768ed6b0be 100644 --- a/drivers/net/wireless/ath/wcn36xx/txrx.c +++ b/drivers/net/wireless/ath/wcn36xx/txrx.c @@ -272,21 +272,9 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, bool is_low = ieee80211_is_data(hdr->frame_control); bool bcast = is_broadcast_ether_addr(hdr->addr1) || is_multicast_ether_addr(hdr->addr1); - struct wcn36xx_tx_bd *bd = wcn36xx_dxe_get_next_bd(wcn, is_low); - - if (!bd) { - /* - * TX DXE are used in pairs. One for the BD and one for the - * actual frame. The BD DXE's has a preallocated buffer while - * the skb ones does not. If this isn't true something is really - * wierd. TODO: Recover from this situation - */ - - wcn36xx_err("bd address may not be NULL for BD DXE\n"); - return -EINVAL; - } + struct wcn36xx_tx_bd bd; - memset(bd, 0, sizeof(*bd)); + memset(&bd, 0, sizeof(bd)); wcn36xx_dbg(WCN36XX_DBG_TX, "tx skb %p len %d fc %04x sn %d %s %s\n", @@ -296,10 +284,10 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, wcn36xx_dbg_dump(WCN36XX_DBG_TX_DUMP, "", skb->data, skb->len); - bd->dpu_rf = WCN36XX_BMU_WQ_TX; + bd.dpu_rf = WCN36XX_BMU_WQ_TX; - bd->tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS); - if (bd->tx_comp) { + bd.tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS); + if (bd.tx_comp) { wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n"); spin_lock_irqsave(&wcn->dxe_lock, flags); if (wcn->tx_ack_skb) { @@ -321,13 +309,13 @@ int wcn36xx_start_tx(struct wcn36xx *wcn, /* Data frames served first*/ if (is_low) - wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, skb, bcast); + wcn36xx_set_tx_data(&bd, wcn, &vif_priv, sta_priv, skb, bcast); else /* MGMT and CTRL frames are handeld here*/ - wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, skb, bcast); + wcn36xx_set_tx_mgmt(&bd, wcn, &vif_priv, skb, bcast); - buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32)); - bd->tx_bd_sign = 0xbdbdbdbd; + buff_to_be((u32 *)&bd, sizeof(bd)/sizeof(u32)); + bd.tx_bd_sign = 0xbdbdbdbd; - return wcn36xx_dxe_tx_frame(wcn, vif_priv, skb, is_low); + return wcn36xx_dxe_tx_frame(wcn, vif_priv, &bd, skb, is_low); } diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h index 81017e6703b4..5854adf43f3a 100644 --- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h +++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h @@ -192,6 +192,8 @@ struct wcn36xx { u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1]; u8 wlan_version[WCN36XX_HAL_VERSION_LENGTH + 1]; + bool first_boot; + /* IRQs */ int tx_irq; int rx_irq; diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index b799a5384abb..cdbb393863f3 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,8 +18,10 @@ #include <linux/etherdevice.h> #include <linux/moduleparam.h> #include <net/netlink.h> +#include <net/cfg80211.h> #include "wil6210.h" #include "wmi.h" +#include "fw.h" #define WIL_MAX_ROC_DURATION_MS 5000 @@ -258,9 +261,10 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type) return -EOPNOTSUPP; } -int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, +int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid, struct station_info *sinfo) { + struct wil6210_priv *wil = vif_to_wil(vif); struct wmi_notify_req_cmd cmd = { .cid = cid, .interval_usec = 0, @@ -272,17 +276,17 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, struct wil_net_stats *stats = &wil->sta[cid].stats; int rc; - rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20); if (rc) return rc; - wil_dbg_wmi(wil, "Link status for CID %d: {\n" + wil_dbg_wmi(wil, "Link status for CID %d MID %d: {\n" " MCS %d TSF 0x%016llx\n" " BF status 0x%08x RSSI %d SQI %d%%\n" " Tx Tpt %d goodput %d Rx goodput %d\n" " Sectors(rx:tx) my %d:%d peer %d:%d\n""}\n", - cid, le16_to_cpu(reply.evt.bf_mcs), + cid, vif->mid, le16_to_cpu(reply.evt.bf_mcs), le64_to_cpu(reply.evt.tsf), reply.evt.status, reply.evt.rssi, reply.evt.sqi, @@ -315,7 +319,7 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, sinfo->tx_packets = stats->tx_packets; sinfo->tx_failed = stats->tx_errors; - if (test_bit(wil_status_fwconnected, wil->status)) { + if (test_bit(wil_vif_fwconnected, vif->status)) { sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL); if (test_bit(WMI_FW_CAPABILITY_RSSI_REPORTING, wil->fw_capabilities)) @@ -331,30 +335,34 @@ static int wil_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev, const u8 *mac, struct station_info *sinfo) { + struct wil6210_vif *vif = ndev_to_vif(ndev); struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; - int cid = wil_find_cid(wil, mac); + int cid = wil_find_cid(wil, vif->mid, mac); - wil_dbg_misc(wil, "get_station: %pM CID %d\n", mac, cid); + wil_dbg_misc(wil, "get_station: %pM CID %d MID %d\n", mac, cid, + vif->mid); if (cid < 0) return cid; - rc = wil_cid_fill_sinfo(wil, cid, sinfo); + rc = wil_cid_fill_sinfo(vif, cid, sinfo); return rc; } /* - * Find @idx-th active STA for station dump. + * Find @idx-th active STA for specific MID for station dump. */ -static int wil_find_cid_by_idx(struct wil6210_priv *wil, int idx) +static int wil_find_cid_by_idx(struct wil6210_priv *wil, u8 mid, int idx) { int i; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { if (wil->sta[i].status == wil_sta_unused) continue; + if (wil->sta[i].mid != mid) + continue; if (idx == 0) return i; idx--; @@ -367,17 +375,19 @@ static int wil_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) { + struct wil6210_vif *vif = ndev_to_vif(dev); struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; - int cid = wil_find_cid_by_idx(wil, idx); + int cid = wil_find_cid_by_idx(wil, vif->mid, idx); if (cid < 0) return -ENOENT; ether_addr_copy(mac, wil->sta[cid].addr); - wil_dbg_misc(wil, "dump_station: %pM CID %d\n", mac, cid); + wil_dbg_misc(wil, "dump_station: %pM CID %d MID %d\n", mac, cid, + vif->mid); - rc = wil_cid_fill_sinfo(wil, cid, sinfo); + rc = wil_cid_fill_sinfo(vif, cid, sinfo); return rc; } @@ -388,7 +398,7 @@ static int wil_cfg80211_start_p2p_device(struct wiphy *wiphy, struct wil6210_priv *wil = wiphy_to_wil(wiphy); wil_dbg_misc(wil, "start_p2p_device: entered\n"); - wil->p2p.p2p_dev_started = 1; + wil->p2p_dev_started = 1; return 0; } @@ -396,20 +406,66 @@ static void wil_cfg80211_stop_p2p_device(struct wiphy *wiphy, struct wireless_dev *wdev) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); - struct wil_p2p_info *p2p = &wil->p2p; - if (!p2p->p2p_dev_started) + if (!wil->p2p_dev_started) return; wil_dbg_misc(wil, "stop_p2p_device: entered\n"); mutex_lock(&wil->mutex); - mutex_lock(&wil->p2p_wdev_mutex); + mutex_lock(&wil->vif_mutex); wil_p2p_stop_radio_operations(wil); - p2p->p2p_dev_started = 0; - mutex_unlock(&wil->p2p_wdev_mutex); + wil->p2p_dev_started = 0; + mutex_unlock(&wil->vif_mutex); mutex_unlock(&wil->mutex); } +static int wil_cfg80211_validate_add_iface(struct wil6210_priv *wil, + enum nl80211_iftype new_type) +{ + int i; + struct wireless_dev *wdev; + struct iface_combination_params params = { + .num_different_channels = 1, + }; + + for (i = 0; i < wil->max_vifs; i++) { + if (wil->vifs[i]) { + wdev = vif_to_wdev(wil->vifs[i]); + params.iftype_num[wdev->iftype]++; + } + } + params.iftype_num[new_type]++; + return cfg80211_check_combinations(wil->wiphy, ¶ms); +} + +static int wil_cfg80211_validate_change_iface(struct wil6210_priv *wil, + struct wil6210_vif *vif, + enum nl80211_iftype new_type) +{ + int i, ret = 0; + struct wireless_dev *wdev; + struct iface_combination_params params = { + .num_different_channels = 1, + }; + bool check_combos = false; + + for (i = 0; i < wil->max_vifs; i++) { + struct wil6210_vif *vif_pos = wil->vifs[i]; + + if (vif_pos && vif != vif_pos) { + wdev = vif_to_wdev(vif_pos); + params.iftype_num[wdev->iftype]++; + check_combos = true; + } + } + + if (check_combos) { + params.iftype_num[new_type]++; + ret = cfg80211_check_combinations(wil->wiphy, ¶ms); + } + return ret; +} + static struct wireless_dev * wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name, unsigned char name_assign_type, @@ -417,51 +473,137 @@ wil_cfg80211_add_iface(struct wiphy *wiphy, const char *name, struct vif_params *params) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); - struct net_device *ndev = wil_to_ndev(wil); - struct wireless_dev *p2p_wdev; + struct net_device *ndev_main = wil->main_ndev, *ndev; + struct wil6210_vif *vif; + struct wireless_dev *p2p_wdev, *wdev; + int rc; - wil_dbg_misc(wil, "add_iface\n"); + wil_dbg_misc(wil, "add_iface, type %d\n", type); - if (type != NL80211_IFTYPE_P2P_DEVICE) { - wil_err(wil, "unsupported iftype %d\n", type); - return ERR_PTR(-EINVAL); + /* P2P device is not a real virtual interface, it is a management-only + * interface that shares the main interface. + * Skip concurrency checks here. + */ + if (type == NL80211_IFTYPE_P2P_DEVICE) { + if (wil->p2p_wdev) { + wil_err(wil, "P2P_DEVICE interface already created\n"); + return ERR_PTR(-EINVAL); + } + + p2p_wdev = kzalloc(sizeof(*p2p_wdev), GFP_KERNEL); + if (!p2p_wdev) + return ERR_PTR(-ENOMEM); + + p2p_wdev->iftype = type; + p2p_wdev->wiphy = wiphy; + /* use our primary ethernet address */ + ether_addr_copy(p2p_wdev->address, ndev_main->perm_addr); + + wil->p2p_wdev = p2p_wdev; + + return p2p_wdev; } - if (wil->p2p_wdev) { - wil_err(wil, "P2P_DEVICE interface already created\n"); + if (!wil->wiphy->n_iface_combinations) { + wil_err(wil, "virtual interfaces not supported\n"); return ERR_PTR(-EINVAL); } - p2p_wdev = kzalloc(sizeof(*p2p_wdev), GFP_KERNEL); - if (!p2p_wdev) - return ERR_PTR(-ENOMEM); + rc = wil_cfg80211_validate_add_iface(wil, type); + if (rc) { + wil_err(wil, "iface validation failed, err=%d\n", rc); + return ERR_PTR(rc); + } - p2p_wdev->iftype = type; - p2p_wdev->wiphy = wiphy; - /* use our primary ethernet address */ - ether_addr_copy(p2p_wdev->address, ndev->perm_addr); + vif = wil_vif_alloc(wil, name, name_assign_type, type); + if (IS_ERR(vif)) + return ERR_CAST(vif); + + ndev = vif_to_ndev(vif); + ether_addr_copy(ndev->perm_addr, ndev_main->perm_addr); + if (is_valid_ether_addr(params->macaddr)) { + ether_addr_copy(ndev->dev_addr, params->macaddr); + } else { + ether_addr_copy(ndev->dev_addr, ndev_main->perm_addr); + ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << vif->mid)) | + 0x2; /* locally administered */ + } + wdev = vif_to_wdev(vif); + ether_addr_copy(wdev->address, ndev->dev_addr); - wil->p2p_wdev = p2p_wdev; + rc = wil_vif_add(wil, vif); + if (rc) + goto out; - return p2p_wdev; + wil_info(wil, "added VIF, mid %d iftype %d MAC %pM\n", + vif->mid, type, wdev->address); + return wdev; +out: + wil_vif_free(vif); + return ERR_PTR(rc); +} + +int wil_vif_prepare_stop(struct wil6210_vif *vif) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct wireless_dev *wdev = vif_to_wdev(vif); + struct net_device *ndev; + int rc; + + if (wdev->iftype != NL80211_IFTYPE_AP) + return 0; + + ndev = vif_to_ndev(vif); + if (netif_carrier_ok(ndev)) { + rc = wmi_pcp_stop(vif); + if (rc) { + wil_info(wil, "failed to stop AP, status %d\n", + rc); + /* continue */ + } + wil_bcast_fini(vif); + netif_carrier_off(ndev); + } + + return 0; } static int wil_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = wdev_to_vif(wil, wdev); + int rc; wil_dbg_misc(wil, "del_iface\n"); - if (wdev != wil->p2p_wdev) { - wil_err(wil, "delete of incorrect interface 0x%p\n", wdev); + if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { + if (wdev != wil->p2p_wdev) { + wil_err(wil, "delete of incorrect interface 0x%p\n", + wdev); + return -EINVAL; + } + + wil_cfg80211_stop_p2p_device(wiphy, wdev); + wil_p2p_wdev_free(wil); + return 0; + } + + if (vif->mid == 0) { + wil_err(wil, "cannot remove the main interface\n"); return -EINVAL; } - wil_cfg80211_stop_p2p_device(wiphy, wdev); - wil_p2p_wdev_free(wil); + rc = wil_vif_prepare_stop(vif); + if (rc) + goto out; + + wil_info(wil, "deleted VIF, mid %d iftype %d MAC %pM\n", + vif->mid, wdev->iftype, wdev->address); - return 0; + wil_vif_remove(wil, vif->mid); +out: + return rc; } static int wil_cfg80211_change_iface(struct wiphy *wiphy, @@ -470,12 +612,26 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy, struct vif_params *params) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); - struct wireless_dev *wdev = wil_to_wdev(wil); + struct wil6210_vif *vif = ndev_to_vif(ndev); + struct wireless_dev *wdev = vif_to_wdev(vif); int rc; + bool fw_reset = false; wil_dbg_misc(wil, "change_iface: type=%d\n", type); - if (netif_running(wil_to_ndev(wil)) && !wil_is_recovery_blocked(wil)) { + if (wiphy->n_iface_combinations) { + rc = wil_cfg80211_validate_change_iface(wil, vif, type); + if (rc) { + wil_err(wil, "iface validation failed, err=%d\n", rc); + return rc; + } + } + + /* do not reset FW when there are active VIFs, + * because it can cause significant disruption + */ + if (!wil_has_other_active_ifaces(wil, ndev, true, false) && + netif_running(ndev) && !wil_is_recovery_blocked(wil)) { wil_dbg_misc(wil, "interface is up. resetting...\n"); mutex_lock(&wil->mutex); __wil_down(wil); @@ -484,6 +640,7 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy, if (rc) return rc; + fw_reset = true; } switch (type) { @@ -500,8 +657,18 @@ static int wil_cfg80211_change_iface(struct wiphy *wiphy, return -EOPNOTSUPP; } - wdev->iftype = type; + if (vif->mid != 0 && wil_has_active_ifaces(wil, true, false)) { + if (!fw_reset) + wil_vif_prepare_stop(vif); + rc = wmi_port_delete(wil, vif->mid); + if (rc) + return rc; + rc = wmi_port_allocate(wil, vif->mid, ndev->dev_addr, type); + if (rc) + return rc; + } + wdev->iftype = type; return 0; } @@ -510,6 +677,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, { struct wil6210_priv *wil = wiphy_to_wil(wiphy); struct wireless_dev *wdev = request->wdev; + struct wil6210_vif *vif = wdev_to_vif(wil, wdev); struct { struct wmi_start_scan_cmd cmd; u16 chnl[4]; @@ -537,35 +705,38 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, mutex_lock(&wil->mutex); - mutex_lock(&wil->p2p_wdev_mutex); - if (wil->scan_request || wil->p2p.discovery_started) { + mutex_lock(&wil->vif_mutex); + if (vif->scan_request || vif->p2p.discovery_started) { wil_err(wil, "Already scanning\n"); - mutex_unlock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->vif_mutex); rc = -EAGAIN; goto out; } - mutex_unlock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->vif_mutex); if (wdev->iftype == NL80211_IFTYPE_P2P_DEVICE) { - if (!wil->p2p.p2p_dev_started) { + if (!wil->p2p_dev_started) { wil_err(wil, "P2P search requested on stopped P2P device\n"); rc = -EIO; goto out; } /* social scan on P2P_DEVICE is handled as p2p search */ if (wil_p2p_is_social_scan(request)) { - wil->scan_request = request; - wil->radio_wdev = wdev; - rc = wil_p2p_search(wil, request); + vif->scan_request = request; + if (vif->mid == 0) + wil->radio_wdev = wdev; + rc = wil_p2p_search(vif, request); if (rc) { - wil->radio_wdev = wil_to_wdev(wil); - wil->scan_request = NULL; + if (vif->mid == 0) + wil->radio_wdev = + wil->main_ndev->ieee80211_ptr; + vif->scan_request = NULL; } goto out; } } - (void)wil_p2p_stop_discovery(wil); + (void)wil_p2p_stop_discovery(vif); wil_dbg_misc(wil, "Start scan_request 0x%p\n", request); wil_dbg_misc(wil, "SSID count: %d", request->n_ssids); @@ -578,18 +749,18 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, } if (request->n_ssids) - rc = wmi_set_ssid(wil, request->ssids[0].ssid_len, + rc = wmi_set_ssid(vif, request->ssids[0].ssid_len, request->ssids[0].ssid); else - rc = wmi_set_ssid(wil, 0, NULL); + rc = wmi_set_ssid(vif, 0, NULL); if (rc) { wil_err(wil, "set SSID for scan request failed: %d\n", rc); goto out; } - wil->scan_request = request; - mod_timer(&wil->scan_timer, jiffies + WIL6210_SCAN_TO); + vif->scan_request = request; + mod_timer(&vif->scan_timer, jiffies + WIL6210_SCAN_TO); memset(&cmd, 0, sizeof(cmd)); cmd.cmd.scan_type = WMI_ACTIVE_SCAN; @@ -616,7 +787,8 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, else wil_dbg_misc(wil, "Scan has no IE's\n"); - rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie); + rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ, + request->ie_len, request->ie); if (rc) goto out_restore; @@ -625,15 +797,18 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, wil_dbg_misc(wil, "active scan with discovery_mode=1\n"); } - wil->radio_wdev = wdev; - rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) + - cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); + if (vif->mid == 0) + wil->radio_wdev = wdev; + rc = wmi_send(wil, WMI_START_SCAN_CMDID, vif->mid, + &cmd, sizeof(cmd.cmd) + + cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0])); out_restore: if (rc) { - del_timer_sync(&wil->scan_timer); - wil->radio_wdev = wil_to_wdev(wil); - wil->scan_request = NULL; + del_timer_sync(&vif->scan_timer); + if (vif->mid == 0) + wil->radio_wdev = wil->main_ndev->ieee80211_ptr; + vif->scan_request = NULL; } out: mutex_unlock(&wil->mutex); @@ -644,27 +819,28 @@ static void wil_cfg80211_abort_scan(struct wiphy *wiphy, struct wireless_dev *wdev) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = wdev_to_vif(wil, wdev); wil_dbg_misc(wil, "wdev=0x%p iftype=%d\n", wdev, wdev->iftype); mutex_lock(&wil->mutex); - mutex_lock(&wil->p2p_wdev_mutex); + mutex_lock(&wil->vif_mutex); - if (!wil->scan_request) + if (!vif->scan_request) goto out; - if (wdev != wil->scan_request->wdev) { + if (wdev != vif->scan_request->wdev) { wil_dbg_misc(wil, "abort scan was called on the wrong iface\n"); goto out; } - if (wil->radio_wdev == wil->p2p_wdev) + if (wdev == wil->p2p_wdev && wil->radio_wdev == wil->p2p_wdev) wil_p2p_stop_radio_operations(wil); else - wil_abort_scan(wil, true); + wil_abort_scan(vif, true); out: - mutex_unlock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->vif_mutex); mutex_unlock(&wil->mutex); } @@ -715,6 +891,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, struct cfg80211_connect_params *sme) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = ndev_to_vif(ndev); struct cfg80211_bss *bss; struct wmi_connect_cmd conn; const u8 *ssid_eid; @@ -723,11 +900,11 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, int rc = 0; enum ieee80211_bss_type bss_type = IEEE80211_BSS_TYPE_ESS; - wil_dbg_misc(wil, "connect\n"); + wil_dbg_misc(wil, "connect, mid=%d\n", vif->mid); wil_print_connect_params(wil, sme); - if (test_bit(wil_status_fwconnecting, wil->status) || - test_bit(wil_status_fwconnected, wil->status)) + if (test_bit(wil_vif_fwconnecting, vif->status) || + test_bit(wil_vif_fwconnected, vif->status)) return -EALREADY; if (sme->ie_len > WMI_MAX_IE_LEN) { @@ -758,18 +935,18 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, rc = -ENOENT; goto out; } - wil->privacy = sme->privacy; - wil->pbss = sme->pbss; + vif->privacy = sme->privacy; + vif->pbss = sme->pbss; - if (wil->privacy) { + if (vif->privacy) { /* For secure assoc, remove old keys */ - rc = wmi_del_cipher_key(wil, 0, bss->bssid, + rc = wmi_del_cipher_key(vif, 0, bss->bssid, WMI_KEY_USE_PAIRWISE); if (rc) { wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(PTK) failed\n"); goto out; } - rc = wmi_del_cipher_key(wil, 0, bss->bssid, + rc = wmi_del_cipher_key(vif, 0, bss->bssid, WMI_KEY_USE_RX_GROUP); if (rc) { wil_err(wil, "WMI_DELETE_CIPHER_KEY_CMD(GTK) failed\n"); @@ -781,7 +958,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, * elements. Send it also in case it's empty, to erase previously set * ies in FW. */ - rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); + rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_REQ, sme->ie_len, sme->ie); if (rc) goto out; @@ -799,7 +976,7 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, bss->capability); goto out; } - if (wil->privacy) { + if (vif->privacy) { if (rsn_eid) { /* regular secure connection */ conn.dot11_auth_mode = WMI_AUTH11_SHARED; conn.auth_mode = WMI_AUTH_WPA2_PSK; @@ -831,18 +1008,19 @@ static int wil_cfg80211_connect(struct wiphy *wiphy, ether_addr_copy(conn.bssid, bss->bssid); ether_addr_copy(conn.dst_mac, bss->bssid); - set_bit(wil_status_fwconnecting, wil->status); + set_bit(wil_vif_fwconnecting, vif->status); - rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn)); + rc = wmi_send(wil, WMI_CONNECT_CMDID, vif->mid, &conn, sizeof(conn)); if (rc == 0) { netif_carrier_on(ndev); - wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS); - wil->bss = bss; + if (!wil_has_other_active_ifaces(wil, ndev, false, true)) + wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS); + vif->bss = bss; /* Connect can take lots of time */ - mod_timer(&wil->connect_timer, + mod_timer(&vif->connect_timer, jiffies + msecs_to_jiffies(5000)); } else { - clear_bit(wil_status_fwconnecting, wil->status); + clear_bit(wil_vif_fwconnecting, vif->status); } out: @@ -857,17 +1035,19 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, { int rc; struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = ndev_to_vif(ndev); - wil_dbg_misc(wil, "disconnect: reason=%d\n", reason_code); + wil_dbg_misc(wil, "disconnect: reason=%d, mid=%d\n", + reason_code, vif->mid); - if (!(test_bit(wil_status_fwconnecting, wil->status) || - test_bit(wil_status_fwconnected, wil->status))) { + if (!(test_bit(wil_vif_fwconnecting, vif->status) || + test_bit(wil_vif_fwconnected, vif->status))) { wil_err(wil, "Disconnect was called while disconnected\n"); return 0; } - wil->locally_generated_disc = true; - rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0, + vif->locally_generated_disc = true; + rc = wmi_call(wil, WMI_DISCONNECT_CMDID, vif->mid, NULL, 0, WMI_DISCONNECT_EVENTID, NULL, 0, WIL6210_DISCONNECT_TO_MS); if (rc) @@ -903,6 +1083,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, const u8 *buf = params->buf; size_t len = params->len, total; struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = wdev_to_vif(wil, wdev); int rc; bool tx_status = false; struct ieee80211_mgmt *mgmt_frame = (void *)buf; @@ -919,7 +1100,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, * different from currently "listened" channel and fail if it is. */ - wil_dbg_misc(wil, "mgmt_tx\n"); + wil_dbg_misc(wil, "mgmt_tx mid %d\n", vif->mid); wil_hex_dump_misc("mgmt tx frame ", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true); @@ -940,7 +1121,7 @@ int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, cmd->len = cpu_to_le16(len); memcpy(cmd->payload, buf, len); - rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, cmd, total, + rc = wmi_call(wil, WMI_SW_TX_REQ_CMDID, vif->mid, cmd, total, WMI_SW_TX_COMPLETE_EVENTID, &evt, sizeof(evt), 2000); if (rc == 0) tx_status = !evt.evt.status; @@ -962,10 +1143,10 @@ static int wil_cfg80211_set_channel(struct wiphy *wiphy, return 0; } -static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil, +static enum wmi_key_usage wil_detect_key_usage(struct wireless_dev *wdev, bool pairwise) { - struct wireless_dev *wdev = wil_to_wdev(wil); + struct wil6210_priv *wil = wdev_to_wil(wdev); enum wmi_key_usage rc; if (pairwise) { @@ -993,7 +1174,7 @@ static enum wmi_key_usage wil_detect_key_usage(struct wil6210_priv *wil, } static struct wil_sta_info * -wil_find_sta_by_key_usage(struct wil6210_priv *wil, +wil_find_sta_by_key_usage(struct wil6210_priv *wil, u8 mid, enum wmi_key_usage key_usage, const u8 *mac_addr) { int cid = -EINVAL; @@ -1003,9 +1184,9 @@ wil_find_sta_by_key_usage(struct wil6210_priv *wil, /* supplicant provides Rx group key in STA mode with NULL MAC address */ if (mac_addr) - cid = wil_find_cid(wil, mac_addr); + cid = wil_find_cid(wil, mid, mac_addr); else if (key_usage == WMI_KEY_USE_RX_GROUP) - cid = wil_find_cid_by_idx(wil, 0); + cid = wil_find_cid_by_idx(wil, mid, 0); if (cid < 0) { wil_err(wil, "No CID for %pM %s\n", mac_addr, key_usage_str[key_usage]); @@ -1082,9 +1263,12 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy, struct key_params *params) { int rc; + struct wil6210_vif *vif = ndev_to_vif(ndev); struct wil6210_priv *wil = wiphy_to_wil(wiphy); - enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise); - struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, key_usage, + struct wireless_dev *wdev = vif_to_wdev(vif); + enum wmi_key_usage key_usage = wil_detect_key_usage(wdev, pairwise); + struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, vif->mid, + key_usage, mac_addr); if (!params) { @@ -1114,7 +1298,7 @@ static int wil_cfg80211_add_key(struct wiphy *wiphy, return -EINVAL; } - rc = wmi_add_cipher_key(wil, key_index, mac_addr, params->key_len, + rc = wmi_add_cipher_key(vif, key_index, mac_addr, params->key_len, params->key, key_usage); if (!rc) wil_set_crypto_rx(key_index, key_usage, cs, params); @@ -1127,9 +1311,12 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy, u8 key_index, bool pairwise, const u8 *mac_addr) { + struct wil6210_vif *vif = ndev_to_vif(ndev); struct wil6210_priv *wil = wiphy_to_wil(wiphy); - enum wmi_key_usage key_usage = wil_detect_key_usage(wil, pairwise); - struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, key_usage, + struct wireless_dev *wdev = vif_to_wdev(vif); + enum wmi_key_usage key_usage = wil_detect_key_usage(wdev, pairwise); + struct wil_sta_info *cs = wil_find_sta_by_key_usage(wil, vif->mid, + key_usage, mac_addr); wil_dbg_misc(wil, "del_key: %pM %s[%d]\n", mac_addr, @@ -1142,7 +1329,7 @@ static int wil_cfg80211_del_key(struct wiphy *wiphy, if (!IS_ERR_OR_NULL(cs)) wil_del_rx_key(key_index, key_usage, cs); - return wmi_del_cipher_key(wil, key_index, mac_addr, key_usage); + return wmi_del_cipher_key(vif, key_index, mac_addr, key_usage); } /* Need to be present or wiphy_new() will WARN */ @@ -1179,10 +1366,11 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy, u64 cookie) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = wdev_to_vif(wil, wdev); wil_dbg_misc(wil, "cancel_remain_on_channel\n"); - return wil_p2p_cancel_listen(wil, cookie); + return wil_p2p_cancel_listen(vif, cookie); } /** @@ -1275,11 +1463,10 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b) } /* internal functions for device reset and starting AP */ -static int _wil_cfg80211_set_ies(struct wiphy *wiphy, +static int _wil_cfg80211_set_ies(struct wil6210_vif *vif, struct cfg80211_beacon_data *bcon) { int rc; - struct wil6210_priv *wil = wiphy_to_wil(wiphy); u16 len = 0, proberesp_len = 0; u8 *ies = NULL, *proberesp = NULL; @@ -1300,20 +1487,21 @@ static int _wil_cfg80211_set_ies(struct wiphy *wiphy, if (rc) goto out; - rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, len, ies); + rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP, len, ies); if (rc) goto out; if (bcon->assocresp_ies) - rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, + rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, bcon->assocresp_ies); else - rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, len, ies); + rc = wmi_set_ie(vif, WMI_FRAME_ASSOC_RESP, len, ies); #if 0 /* to use beacon IE's, remove this #if 0 */ if (rc) goto out; - rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, bcon->tail); + rc = wmi_set_ie(vif, WMI_FRAME_BEACON, + bcon->tail_len, bcon->tail); #endif out: kfree(ies); @@ -1328,6 +1516,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, u8 hidden_ssid, u32 pbss) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = ndev_to_vif(ndev); int rc; struct wireless_dev *wdev = ndev->ieee80211_ptr; u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); @@ -1336,7 +1525,7 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, if (pbss) wmi_nettype = WMI_NETTYPE_P2P; - wil_dbg_misc(wil, "start_ap: is_go=%d\n", is_go); + wil_dbg_misc(wil, "start_ap: mid=%d, is_go=%d\n", vif->mid, is_go); if (is_go && !pbss) { wil_err(wil, "P2P GO must be in PBSS\n"); return -ENOTSUPP; @@ -1346,42 +1535,46 @@ static int _wil_cfg80211_start_ap(struct wiphy *wiphy, mutex_lock(&wil->mutex); - __wil_down(wil); - rc = __wil_up(wil); - if (rc) - goto out; + if (!wil_has_other_active_ifaces(wil, ndev, true, false)) { + __wil_down(wil); + rc = __wil_up(wil); + if (rc) + goto out; + } - rc = wmi_set_ssid(wil, ssid_len, ssid); + rc = wmi_set_ssid(vif, ssid_len, ssid); if (rc) goto out; - rc = _wil_cfg80211_set_ies(wiphy, bcon); + rc = _wil_cfg80211_set_ies(vif, bcon); if (rc) goto out; - wil->privacy = privacy; - wil->channel = chan; - wil->hidden_ssid = hidden_ssid; - wil->pbss = pbss; + vif->privacy = privacy; + vif->channel = chan; + vif->hidden_ssid = hidden_ssid; + vif->pbss = pbss; netif_carrier_on(ndev); - wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS); + if (!wil_has_other_active_ifaces(wil, ndev, false, true)) + wil6210_bus_request(wil, WIL_MAX_BUS_REQUEST_KBPS); - rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid, is_go); + rc = wmi_pcp_start(vif, bi, wmi_nettype, chan, hidden_ssid, is_go); if (rc) goto err_pcp_start; - rc = wil_bcast_init(wil); + rc = wil_bcast_init(vif); if (rc) goto err_bcast; goto out; /* success */ err_bcast: - wmi_pcp_stop(wil); + wmi_pcp_stop(vif); err_pcp_start: netif_carrier_off(ndev); - wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); + if (!wil_has_other_active_ifaces(wil, ndev, false, true)) + wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); out: mutex_unlock(&wil->mutex); return rc; @@ -1392,10 +1585,11 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, struct cfg80211_beacon_data *bcon) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = ndev_to_vif(ndev); int rc; u32 privacy = 0; - wil_dbg_misc(wil, "change_beacon\n"); + wil_dbg_misc(wil, "change_beacon, mid=%d\n", vif->mid); wil_print_bcon_data(bcon); if (bcon->tail && @@ -1404,20 +1598,20 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, privacy = 1; /* in case privacy has changed, need to restart the AP */ - if (wil->privacy != privacy) { + if (vif->privacy != privacy) { struct wireless_dev *wdev = ndev->ieee80211_ptr; wil_dbg_misc(wil, "privacy changed %d=>%d. Restarting AP\n", - wil->privacy, privacy); + vif->privacy, privacy); rc = _wil_cfg80211_start_ap(wiphy, ndev, wdev->ssid, wdev->ssid_len, privacy, wdev->beacon_interval, - wil->channel, bcon, - wil->hidden_ssid, - wil->pbss); + vif->channel, bcon, + vif->hidden_ssid, + vif->pbss); } else { - rc = _wil_cfg80211_set_ies(wiphy, bcon); + rc = _wil_cfg80211_set_ies(vif, bcon); } return rc; @@ -1484,20 +1678,27 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = ndev_to_vif(ndev); + bool last; - wil_dbg_misc(wil, "stop_ap\n"); + wil_dbg_misc(wil, "stop_ap, mid=%d\n", vif->mid); netif_carrier_off(ndev); - wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); - wil_set_recovery_state(wil, fw_recovery_idle); - - set_bit(wil_status_resetting, wil->status); + last = !wil_has_other_active_ifaces(wil, ndev, false, true); + if (last) { + wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); + wil_set_recovery_state(wil, fw_recovery_idle); + set_bit(wil_status_resetting, wil->status); + } mutex_lock(&wil->mutex); - wmi_pcp_stop(wil); + wmi_pcp_stop(vif); - __wil_down(wil); + if (last) + __wil_down(wil); + else + wil_bcast_fini(vif); mutex_unlock(&wil->mutex); @@ -1509,9 +1710,11 @@ static int wil_cfg80211_add_station(struct wiphy *wiphy, const u8 *mac, struct station_parameters *params) { + struct wil6210_vif *vif = ndev_to_vif(dev); struct wil6210_priv *wil = wiphy_to_wil(wiphy); - wil_dbg_misc(wil, "add station %pM aid %d\n", mac, params->aid); + wil_dbg_misc(wil, "add station %pM aid %d mid %d\n", + mac, params->aid, vif->mid); if (!disable_ap_sme) { wil_err(wil, "not supported with AP SME enabled\n"); @@ -1523,20 +1726,21 @@ static int wil_cfg80211_add_station(struct wiphy *wiphy, return -EINVAL; } - return wmi_new_sta(wil, mac, params->aid); + return wmi_new_sta(vif, mac, params->aid); } static int wil_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, struct station_del_parameters *params) { + struct wil6210_vif *vif = ndev_to_vif(dev); struct wil6210_priv *wil = wiphy_to_wil(wiphy); - wil_dbg_misc(wil, "del_station: %pM, reason=%d\n", params->mac, - params->reason_code); + wil_dbg_misc(wil, "del_station: %pM, reason=%d mid=%d\n", + params->mac, params->reason_code, vif->mid); mutex_lock(&wil->mutex); - wil6210_disconnect(wil, params->mac, params->reason_code, false); + wil6210_disconnect(vif, params->mac, params->reason_code, false); mutex_unlock(&wil->mutex); return 0; @@ -1547,13 +1751,15 @@ static int wil_cfg80211_change_station(struct wiphy *wiphy, const u8 *mac, struct station_parameters *params) { + struct wil6210_vif *vif = ndev_to_vif(dev); struct wil6210_priv *wil = wiphy_to_wil(wiphy); int authorize; int cid, i; struct vring_tx_data *txdata = NULL; - wil_dbg_misc(wil, "change station %pM mask 0x%x set 0x%x\n", mac, - params->sta_flags_mask, params->sta_flags_set); + wil_dbg_misc(wil, "change station %pM mask 0x%x set 0x%x mid %d\n", + mac, params->sta_flags_mask, params->sta_flags_set, + vif->mid); if (!disable_ap_sme) { wil_dbg_misc(wil, "not supported with AP SME enabled\n"); @@ -1563,7 +1769,7 @@ static int wil_cfg80211_change_station(struct wiphy *wiphy, if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED))) return 0; - cid = wil_find_cid(wil, mac); + cid = wil_find_cid(wil, vif->mid, mac); if (cid < 0) { wil_err(wil, "station not found\n"); return -ENOLINK; @@ -1590,9 +1796,10 @@ static int wil_cfg80211_change_station(struct wiphy *wiphy, /* probe_client handling */ static void wil_probe_client_handle(struct wil6210_priv *wil, + struct wil6210_vif *vif, struct wil_probe_client_req *req) { - struct net_device *ndev = wil_to_ndev(wil); + struct net_device *ndev = vif_to_ndev(vif); struct wil_sta_info *sta = &wil->sta[req->cid]; /* assume STA is alive if it is still connected, * else FW will disconnect it @@ -1603,51 +1810,53 @@ static void wil_probe_client_handle(struct wil6210_priv *wil, 0, false, GFP_KERNEL); } -static struct list_head *next_probe_client(struct wil6210_priv *wil) +static struct list_head *next_probe_client(struct wil6210_vif *vif) { struct list_head *ret = NULL; - mutex_lock(&wil->probe_client_mutex); + mutex_lock(&vif->probe_client_mutex); - if (!list_empty(&wil->probe_client_pending)) { - ret = wil->probe_client_pending.next; + if (!list_empty(&vif->probe_client_pending)) { + ret = vif->probe_client_pending.next; list_del(ret); } - mutex_unlock(&wil->probe_client_mutex); + mutex_unlock(&vif->probe_client_mutex); return ret; } void wil_probe_client_worker(struct work_struct *work) { - struct wil6210_priv *wil = container_of(work, struct wil6210_priv, - probe_client_worker); + struct wil6210_vif *vif = container_of(work, struct wil6210_vif, + probe_client_worker); + struct wil6210_priv *wil = vif_to_wil(vif); struct wil_probe_client_req *req; struct list_head *lh; - while ((lh = next_probe_client(wil)) != NULL) { + while ((lh = next_probe_client(vif)) != NULL) { req = list_entry(lh, struct wil_probe_client_req, list); - wil_probe_client_handle(wil, req); + wil_probe_client_handle(wil, vif, req); kfree(req); } } -void wil_probe_client_flush(struct wil6210_priv *wil) +void wil_probe_client_flush(struct wil6210_vif *vif) { struct wil_probe_client_req *req, *t; + struct wil6210_priv *wil = vif_to_wil(vif); wil_dbg_misc(wil, "probe_client_flush\n"); - mutex_lock(&wil->probe_client_mutex); + mutex_lock(&vif->probe_client_mutex); - list_for_each_entry_safe(req, t, &wil->probe_client_pending, list) { + list_for_each_entry_safe(req, t, &vif->probe_client_pending, list) { list_del(&req->list); kfree(req); } - mutex_unlock(&wil->probe_client_mutex); + mutex_unlock(&vif->probe_client_mutex); } static int wil_cfg80211_probe_client(struct wiphy *wiphy, @@ -1655,10 +1864,12 @@ static int wil_cfg80211_probe_client(struct wiphy *wiphy, const u8 *peer, u64 *cookie) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = ndev_to_vif(dev); struct wil_probe_client_req *req; - int cid = wil_find_cid(wil, peer); + int cid = wil_find_cid(wil, vif->mid, peer); - wil_dbg_misc(wil, "probe_client: %pM => CID %d\n", peer, cid); + wil_dbg_misc(wil, "probe_client: %pM => CID %d MID %d\n", + peer, cid, vif->mid); if (cid < 0) return -ENOLINK; @@ -1670,12 +1881,12 @@ static int wil_cfg80211_probe_client(struct wiphy *wiphy, req->cid = cid; req->cookie = cid; - mutex_lock(&wil->probe_client_mutex); - list_add_tail(&req->list, &wil->probe_client_pending); - mutex_unlock(&wil->probe_client_mutex); + mutex_lock(&vif->probe_client_mutex); + list_add_tail(&req->list, &vif->probe_client_pending); + mutex_unlock(&vif->probe_client_mutex); *cookie = req->cookie; - queue_work(wil->wq_service, &wil->probe_client_worker); + queue_work(wil->wq_service, &vif->probe_client_worker); return 0; } @@ -1684,11 +1895,12 @@ static int wil_cfg80211_change_bss(struct wiphy *wiphy, struct bss_parameters *params) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = ndev_to_vif(dev); if (params->ap_isolate >= 0) { - wil_dbg_misc(wil, "change_bss: ap_isolate %d => %d\n", - wil->ap_isolate, params->ap_isolate); - wil->ap_isolate = params->ap_isolate; + wil_dbg_misc(wil, "change_bss: ap_isolate MID %d, %d => %d\n", + vif->mid, vif->ap_isolate, params->ap_isolate); + vif->ap_isolate = params->ap_isolate; } return 0; @@ -1732,10 +1944,10 @@ static int wil_cfg80211_suspend(struct wiphy *wiphy, wil_dbg_pm(wil, "suspending\n"); mutex_lock(&wil->mutex); - mutex_lock(&wil->p2p_wdev_mutex); + mutex_lock(&wil->vif_mutex); wil_p2p_stop_radio_operations(wil); - wil_abort_scan(wil, true); - mutex_unlock(&wil->p2p_wdev_mutex); + wil_abort_scan_all_vifs(wil, true); + mutex_unlock(&wil->vif_mutex); mutex_unlock(&wil->mutex); out: @@ -1757,8 +1969,12 @@ wil_cfg80211_sched_scan_start(struct wiphy *wiphy, struct cfg80211_sched_scan_request *request) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = ndev_to_vif(dev); int i, rc; + if (vif->mid != 0) + return -EOPNOTSUPP; + wil_dbg_misc(wil, "sched scan start: n_ssids %d, ie_len %zu, flags 0x%x\n", request->n_ssids, request->ie_len, request->flags); @@ -1792,7 +2008,8 @@ wil_cfg80211_sched_scan_start(struct wiphy *wiphy, i, sp->interval, sp->iterations); } - rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie); + rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ, + request->ie_len, request->ie); if (rc) return rc; return wmi_start_sched_scan(wil, request); @@ -1803,8 +2020,12 @@ wil_cfg80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev, u64 reqid) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); + struct wil6210_vif *vif = ndev_to_vif(dev); int rc; + if (vif->mid != 0) + return -EOPNOTSUPP; + rc = wmi_stop_sched_scan(wil); /* device would return error if it thinks PNO is already stopped. * ignore the return code so user space and driver gets back in-sync @@ -1893,57 +2114,132 @@ static void wil_wiphy_init(struct wiphy *wiphy) #endif } -struct wireless_dev *wil_cfg80211_init(struct device *dev) +int wil_cfg80211_iface_combinations_from_fw( + struct wil6210_priv *wil, const struct wil_fw_record_concurrency *conc) { - int rc = 0; - struct wireless_dev *wdev; + struct wiphy *wiphy = wil_to_wiphy(wil); + u32 total_limits = 0; + u16 n_combos; + const struct wil_fw_concurrency_combo *combo; + const struct wil_fw_concurrency_limit *limit; + struct ieee80211_iface_combination *iface_combinations; + struct ieee80211_iface_limit *iface_limit; + int i, j; + + if (wiphy->iface_combinations) { + wil_dbg_misc(wil, "iface_combinations already set, skipping\n"); + return 0; + } - dev_dbg(dev, "%s()\n", __func__); + combo = conc->combos; + n_combos = le16_to_cpu(conc->n_combos); + for (i = 0; i < n_combos; i++) { + total_limits += combo->n_limits; + limit = combo->limits + combo->n_limits; + combo = (struct wil_fw_concurrency_combo *)limit; + } - wdev = kzalloc(sizeof(*wdev), GFP_KERNEL); - if (!wdev) - return ERR_PTR(-ENOMEM); + iface_combinations = + kzalloc(n_combos * sizeof(struct ieee80211_iface_combination) + + total_limits * sizeof(struct ieee80211_iface_limit), + GFP_KERNEL); + if (!iface_combinations) + return -ENOMEM; + iface_limit = (struct ieee80211_iface_limit *)(iface_combinations + + n_combos); + combo = conc->combos; + for (i = 0; i < n_combos; i++) { + iface_combinations[i].max_interfaces = combo->max_interfaces; + iface_combinations[i].num_different_channels = + combo->n_diff_channels; + iface_combinations[i].beacon_int_infra_match = + combo->same_bi; + iface_combinations[i].n_limits = combo->n_limits; + wil_dbg_misc(wil, + "iface_combination %d: max_if %d, num_ch %d, bi_match %d\n", + i, iface_combinations[i].max_interfaces, + iface_combinations[i].num_different_channels, + iface_combinations[i].beacon_int_infra_match); + limit = combo->limits; + for (j = 0; j < combo->n_limits; j++) { + iface_limit[j].max = le16_to_cpu(limit[j].max); + iface_limit[j].types = le16_to_cpu(limit[j].types); + wil_dbg_misc(wil, + "limit %d: max %d types 0x%x\n", j, + iface_limit[j].max, iface_limit[j].types); + } + iface_combinations[i].limits = iface_limit; + iface_limit += combo->n_limits; + limit += combo->n_limits; + combo = (struct wil_fw_concurrency_combo *)limit; + } - wdev->wiphy = wiphy_new(&wil_cfg80211_ops, - sizeof(struct wil6210_priv)); - if (!wdev->wiphy) { - rc = -ENOMEM; - goto out; + wil_dbg_misc(wil, "multiple VIFs supported, n_mids %d\n", conc->n_mids); + wil->max_vifs = conc->n_mids + 1; /* including main interface */ + if (wil->max_vifs > WIL_MAX_VIFS) { + wil_info(wil, "limited number of VIFs supported(%d, FW %d)\n", + WIL_MAX_VIFS, wil->max_vifs); + wil->max_vifs = WIL_MAX_VIFS; } + wiphy->n_iface_combinations = n_combos; + wiphy->iface_combinations = iface_combinations; + return 0; +} - set_wiphy_dev(wdev->wiphy, dev); - wil_wiphy_init(wdev->wiphy); +struct wil6210_priv *wil_cfg80211_init(struct device *dev) +{ + struct wiphy *wiphy; + struct wil6210_priv *wil; + struct ieee80211_channel *ch; - return wdev; + dev_dbg(dev, "%s()\n", __func__); -out: - kfree(wdev); + /* Note: the wireless_dev structure is no longer allocated here. + * Instead, it is allocated as part of the net_device structure + * for main interface and each VIF. + */ + wiphy = wiphy_new(&wil_cfg80211_ops, sizeof(struct wil6210_priv)); + if (!wiphy) + return ERR_PTR(-ENOMEM); - return ERR_PTR(rc); + set_wiphy_dev(wiphy, dev); + wil_wiphy_init(wiphy); + + wil = wiphy_to_wil(wiphy); + wil->wiphy = wiphy; + + /* default monitor channel */ + ch = wiphy->bands[NL80211_BAND_60GHZ]->channels; + cfg80211_chandef_create(&wil->monitor_chandef, ch, NL80211_CHAN_NO_HT); + + return wil; } -void wil_wdev_free(struct wil6210_priv *wil) +void wil_cfg80211_deinit(struct wil6210_priv *wil) { - struct wireless_dev *wdev = wil_to_wdev(wil); + struct wiphy *wiphy = wil_to_wiphy(wil); dev_dbg(wil_to_dev(wil), "%s()\n", __func__); - if (!wdev) + if (!wiphy) return; - wiphy_free(wdev->wiphy); - kfree(wdev); + kfree(wiphy->iface_combinations); + wiphy->iface_combinations = NULL; + + wiphy_free(wiphy); + /* do not access wil6210_priv after returning from here */ } void wil_p2p_wdev_free(struct wil6210_priv *wil) { struct wireless_dev *p2p_wdev; - mutex_lock(&wil->p2p_wdev_mutex); + mutex_lock(&wil->vif_mutex); p2p_wdev = wil->p2p_wdev; wil->p2p_wdev = NULL; - wil->radio_wdev = wil_to_wdev(wil); - mutex_unlock(&wil->p2p_wdev_mutex); + wil->radio_wdev = wil->main_ndev->ieee80211_ptr; + mutex_unlock(&wil->vif_mutex); if (p2p_wdev) { cfg80211_unregister_wdev(p2p_wdev); kfree(p2p_wdev); @@ -1971,6 +2267,7 @@ static int wil_rf_sector_get_cfg(struct wiphy *wiphy, const void *data, int data_len) { struct wil6210_priv *wil = wdev_to_wil(wdev); + struct wil6210_vif *vif = wdev_to_vif(wil, wdev); int rc; struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1]; u16 sector_index; @@ -2027,8 +2324,8 @@ static int wil_rf_sector_get_cfg(struct wiphy *wiphy, cmd.sector_type = sector_type; cmd.rf_modules_vec = rf_modules_vec & 0xFF; memset(&reply, 0, sizeof(reply)); - rc = wmi_call(wil, WMI_GET_RF_SECTOR_PARAMS_CMDID, &cmd, sizeof(cmd), - WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID, + rc = wmi_call(wil, WMI_GET_RF_SECTOR_PARAMS_CMDID, vif->mid, + &cmd, sizeof(cmd), WMI_GET_RF_SECTOR_PARAMS_DONE_EVENTID, &reply, sizeof(reply), 500); if (rc) @@ -2090,6 +2387,7 @@ static int wil_rf_sector_set_cfg(struct wiphy *wiphy, const void *data, int data_len) { struct wil6210_priv *wil = wdev_to_wil(wdev); + struct wil6210_vif *vif = wdev_to_vif(wil, wdev); int rc, tmp; struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1]; struct nlattr *tb2[QCA_ATTR_DMG_RF_SECTOR_CFG_MAX + 1]; @@ -2184,8 +2482,8 @@ static int wil_rf_sector_set_cfg(struct wiphy *wiphy, cmd.rf_modules_vec = rf_modules_vec & 0xFF; memset(&reply, 0, sizeof(reply)); - rc = wmi_call(wil, WMI_SET_RF_SECTOR_PARAMS_CMDID, &cmd, sizeof(cmd), - WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID, + rc = wmi_call(wil, WMI_SET_RF_SECTOR_PARAMS_CMDID, vif->mid, + &cmd, sizeof(cmd), WMI_SET_RF_SECTOR_PARAMS_DONE_EVENTID, &reply, sizeof(reply), 500); if (rc) @@ -2198,6 +2496,7 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy, const void *data, int data_len) { struct wil6210_priv *wil = wdev_to_wil(wdev); + struct wil6210_vif *vif = wdev_to_vif(wil, wdev); int rc; struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1]; u8 sector_type, mac_addr[ETH_ALEN]; @@ -2231,13 +2530,13 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy, if (tb[QCA_ATTR_MAC_ADDR]) { ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR])); - cid = wil_find_cid(wil, mac_addr); + cid = wil_find_cid(wil, vif->mid, mac_addr); if (cid < 0) { wil_err(wil, "invalid MAC address %pM\n", mac_addr); return -ENOENT; } } else { - if (test_bit(wil_status_fwconnected, wil->status)) { + if (test_bit(wil_vif_fwconnected, vif->status)) { wil_err(wil, "must specify MAC address when connected\n"); return -EINVAL; } @@ -2247,7 +2546,7 @@ static int wil_rf_sector_get_selected(struct wiphy *wiphy, cmd.cid = (u8)cid; cmd.sector_type = sector_type; memset(&reply, 0, sizeof(reply)); - rc = wmi_call(wil, WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID, + rc = wmi_call(wil, WMI_GET_SELECTED_RF_SECTOR_INDEX_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_GET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID, &reply, sizeof(reply), @@ -2280,7 +2579,7 @@ nla_put_failure: } static int wil_rf_sector_wmi_set_selected(struct wil6210_priv *wil, - u16 sector_index, + u8 mid, u16 sector_index, u8 sector_type, u8 cid) { struct wmi_set_selected_rf_sector_index_cmd cmd; @@ -2295,7 +2594,7 @@ static int wil_rf_sector_wmi_set_selected(struct wil6210_priv *wil, cmd.sector_type = sector_type; cmd.cid = (u8)cid; memset(&reply, 0, sizeof(reply)); - rc = wmi_call(wil, WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID, + rc = wmi_call(wil, WMI_SET_SELECTED_RF_SECTOR_INDEX_CMDID, mid, &cmd, sizeof(cmd), WMI_SET_SELECTED_RF_SECTOR_INDEX_DONE_EVENTID, &reply, sizeof(reply), @@ -2310,6 +2609,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy, const void *data, int data_len) { struct wil6210_priv *wil = wdev_to_wil(wdev); + struct wil6210_vif *vif = wdev_to_vif(wil, wdev); int rc; struct nlattr *tb[QCA_ATTR_DMG_RF_SECTOR_MAX + 1]; u16 sector_index; @@ -2349,7 +2649,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy, if (tb[QCA_ATTR_MAC_ADDR]) { ether_addr_copy(mac_addr, nla_data(tb[QCA_ATTR_MAC_ADDR])); if (!is_broadcast_ether_addr(mac_addr)) { - cid = wil_find_cid(wil, mac_addr); + cid = wil_find_cid(wil, vif->mid, mac_addr); if (cid < 0) { wil_err(wil, "invalid MAC address %pM\n", mac_addr); @@ -2363,7 +2663,7 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy, cid = -1; } } else { - if (test_bit(wil_status_fwconnected, wil->status)) { + if (test_bit(wil_vif_fwconnected, vif->status)) { wil_err(wil, "must specify MAC address when connected\n"); return -EINVAL; } @@ -2371,17 +2671,20 @@ static int wil_rf_sector_set_selected(struct wiphy *wiphy, } if (cid >= 0) { - rc = wil_rf_sector_wmi_set_selected(wil, sector_index, + rc = wil_rf_sector_wmi_set_selected(wil, vif->mid, sector_index, sector_type, cid); } else { /* unlock all cids */ rc = wil_rf_sector_wmi_set_selected( - wil, WMI_INVALID_RF_SECTOR_INDEX, sector_type, - WIL_CID_ALL); + wil, vif->mid, WMI_INVALID_RF_SECTOR_INDEX, + sector_type, WIL_CID_ALL); if (rc == -EINVAL) { for (i = 0; i < WIL6210_MAX_CID; i++) { + if (wil->sta[i].mid != vif->mid) + continue; rc = wil_rf_sector_wmi_set_selected( - wil, WMI_INVALID_RF_SECTOR_INDEX, + wil, vif->mid, + WMI_INVALID_RF_SECTOR_INDEX, sector_type, i); /* the FW will silently ignore and return * success for unused cid, so abort the loop diff --git a/drivers/net/wireless/ath/wil6210/debug.c b/drivers/net/wireless/ath/wil6210/debug.c index 217a4591bde4..a9befb971cc4 100644 --- a/drivers/net/wireless/ath/wil6210/debug.c +++ b/drivers/net/wireless/ath/wil6210/debug.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013,2016 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,7 +26,7 @@ void __wil_err(struct wil6210_priv *wil, const char *fmt, ...) va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; - netdev_err(wil_to_ndev(wil), "%pV", &vaf); + netdev_err(wil->main_ndev, "%pV", &vaf); trace_wil6210_log_err(&vaf); va_end(args); } @@ -41,7 +42,7 @@ void __wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...) va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; - netdev_err(wil_to_ndev(wil), "%pV", &vaf); + netdev_err(wil->main_ndev, "%pV", &vaf); trace_wil6210_log_err(&vaf); va_end(args); } @@ -57,7 +58,7 @@ void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...) va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; - netdev_dbg(wil_to_ndev(wil), "%pV", &vaf); + netdev_dbg(wil->main_ndev, "%pV", &vaf); trace_wil6210_log_dbg(&vaf); va_end(args); } @@ -70,7 +71,7 @@ void __wil_info(struct wil6210_priv *wil, const char *fmt, ...) va_start(args, fmt); vaf.fmt = fmt; vaf.va = &args; - netdev_info(wil_to_ndev(wil), "%pV", &vaf); + netdev_info(wil->main_ndev, "%pV", &vaf); trace_wil6210_log_info(&vaf); va_end(args); } diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 4a4888246e8c..8c90b3111f0b 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -621,7 +622,7 @@ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; - struct net_device *ndev = wil_to_ndev(wil); + struct net_device *ndev = wil->main_ndev; /** * BUG: @@ -716,27 +717,44 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf, if (rc < 2) return -EINVAL; - if (0 == strcmp(cmd, "add")) { - if (rc < 3) { - wil_err(wil, "BACK: add require at least 2 params\n"); + if ((strcmp(cmd, "add") == 0) || + (strcmp(cmd, "del_tx") == 0)) { + struct vring_tx_data *txdata; + + if (p1 < 0 || p1 >= WIL6210_MAX_TX_RINGS) { + wil_err(wil, "BACK: invalid ring id %d\n", p1); return -EINVAL; } - if (rc < 4) - p3 = 0; - wmi_addba(wil, p1, p2, p3); - } else if (0 == strcmp(cmd, "del_tx")) { - if (rc < 3) - p2 = WLAN_REASON_QSTA_LEAVE_QBSS; - wmi_delba_tx(wil, p1, p2); - } else if (0 == strcmp(cmd, "del_rx")) { + txdata = &wil->vring_tx_data[p1]; + if (strcmp(cmd, "add") == 0) { + if (rc < 3) { + wil_err(wil, "BACK: add require at least 2 params\n"); + return -EINVAL; + } + if (rc < 4) + p3 = 0; + wmi_addba(wil, txdata->mid, p1, p2, p3); + } else { + if (rc < 3) + p2 = WLAN_REASON_QSTA_LEAVE_QBSS; + wmi_delba_tx(wil, txdata->mid, p1, p2); + } + } else if (strcmp(cmd, "del_rx") == 0) { + struct wil_sta_info *sta; + if (rc < 3) { wil_err(wil, "BACK: del_rx require at least 2 params\n"); return -EINVAL; } + if (p1 < 0 || p1 >= WIL6210_MAX_CID) { + wil_err(wil, "BACK: invalid CID %d\n", p1); + return -EINVAL; + } if (rc < 4) p3 = WLAN_REASON_QSTA_LEAVE_QBSS; - wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3); + sta = &wil->sta[p1]; + wmi_delba_rx(wil, sta->mid, mk_cidxtid(p1, p2), p3); } else { wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd); return -EINVAL; @@ -855,7 +873,7 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, { struct wil6210_priv *wil = file->private_data; struct wiphy *wiphy = wil_to_wiphy(wil); - struct wireless_dev *wdev = wil_to_wdev(wil); + struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr; struct cfg80211_mgmt_tx_params params; int rc; void *frame; @@ -890,6 +908,7 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, size_t len, loff_t *ppos) { struct wil6210_priv *wil = file->private_data; + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); struct wmi_cmd_hdr *wmi; void *cmd; int cmdlen = len - sizeof(struct wmi_cmd_hdr); @@ -912,7 +931,7 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, cmd = (cmdlen > 0) ? &wmi[1] : NULL; cmdid = le16_to_cpu(wmi->command_id); - rc1 = wmi_send(wil, cmdid, cmd, cmdlen); + rc1 = wmi_send(wil, cmdid, vif->mid, cmd, cmdlen); kfree(wmi); wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1); @@ -1050,6 +1069,7 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data) int rc; int i; struct wil6210_priv *wil = s->private; + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); struct wmi_notify_req_cmd cmd = { .interval_usec = 0, }; @@ -1062,7 +1082,8 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data) u32 status; cmd.cid = i; - rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid, + &cmd, sizeof(cmd), WMI_NOTIFY_REQ_DONE_EVENTID, &reply, sizeof(reply), 20); /* if reply is all-0, ignore this CID */ @@ -1155,7 +1176,7 @@ static const struct file_operations fops_temp = { static int wil_freq_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; - struct wireless_dev *wdev = wil_to_wdev(wil); + struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr; u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0; seq_printf(s, "Freq = %d\n", freq); @@ -1185,6 +1206,8 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data) for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { struct wil_sta_info *p = &wil->sta[i]; char *status = "unknown"; + struct wil6210_vif *vif; + u8 mid; switch (p->status) { case wil_sta_unused: @@ -1197,16 +1220,24 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data) status = "connected"; break; } - seq_printf(s, "[%d] %pM %s\n", i, p->addr, status); + mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; + seq_printf(s, "[%d][MID %d] %pM %s\n", + i, mid, p->addr, status); - if (p->status == wil_sta_connected) { - rc = wil_cid_fill_sinfo(wil, i, &sinfo); + if (p->status != wil_sta_connected) + continue; + + vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL; + if (vif) { + rc = wil_cid_fill_sinfo(vif, i, &sinfo); if (rc) return rc; seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs); seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs); seq_printf(s, " SQ = %d\n", sinfo.signal); + } else { + seq_puts(s, " INVALID MID\n"); } } @@ -1229,7 +1260,7 @@ static const struct file_operations fops_link = { static int wil_info_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; - struct net_device *ndev = wil_to_ndev(wil); + struct net_device *ndev = wil->main_ndev; int is_ac = power_supply_is_system_supplied(); int rx = atomic_xchg(&wil->isr_count_rx, 0); int tx = atomic_xchg(&wil->isr_count_tx, 0); @@ -1398,6 +1429,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) struct wil_sta_info *p = &wil->sta[i]; char *status = "unknown"; u8 aid = 0; + u8 mid; switch (p->status) { case wil_sta_unused: @@ -1411,7 +1443,9 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) aid = p->aid; break; } - seq_printf(s, "[%d] %pM %s AID %d\n", i, p->addr, status, aid); + mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX; + seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status, + mid, aid); if (p->status == wil_sta_connected) { spin_lock_bh(&p->tid_rx_lock); @@ -1461,6 +1495,42 @@ static const struct file_operations fops_sta = { .llseek = seq_lseek, }; +static int wil_mids_debugfs_show(struct seq_file *s, void *data) +{ + struct wil6210_priv *wil = s->private; + struct wil6210_vif *vif; + struct net_device *ndev; + int i; + + mutex_lock(&wil->vif_mutex); + for (i = 0; i < wil->max_vifs; i++) { + vif = wil->vifs[i]; + + if (vif) { + ndev = vif_to_ndev(vif); + seq_printf(s, "[%d] %pM %s\n", i, ndev->dev_addr, + ndev->name); + } else { + seq_printf(s, "[%d] unused\n", i); + } + } + mutex_unlock(&wil->vif_mutex); + + return 0; +} + +static int wil_mids_seq_open(struct inode *inode, struct file *file) +{ + return single_open(file, wil_mids_debugfs_show, inode->i_private); +} + +static const struct file_operations fops_mids = { + .open = wil_mids_seq_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -1715,6 +1785,7 @@ static const struct { {"mbox", 0444, &fops_mbox}, {"vrings", 0444, &fops_vring}, {"stations", 0444, &fops_sta}, + {"mids", 0444, &fops_mids}, {"desc", 0444, &fops_txdesc}, {"bf", 0444, &fops_bf}, {"mem_val", 0644, &fops_memread}, @@ -1773,11 +1844,9 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil, /* fields in struct wil6210_priv */ static const struct dbg_off dbg_wil_off[] = { - WIL_FIELD(privacy, 0444, doff_u32), WIL_FIELD(status[0], 0644, doff_ulong), WIL_FIELD(hw_version, 0444, doff_x32), WIL_FIELD(recovery_count, 0444, doff_u32), - WIL_FIELD(ap_isolate, 0444, doff_u32), WIL_FIELD(discovery_mode, 0644, doff_u8), WIL_FIELD(chip_revision, 0444, doff_u8), WIL_FIELD(abft_len, 0644, doff_u8), diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index 66200f616a37..e7ff41e623d2 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014,2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -74,12 +75,13 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *cp) { struct wil6210_priv *wil = ndev_to_wil(ndev); + struct wireless_dev *wdev = ndev->ieee80211_ptr; int ret; wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n", cp->rx_coalesce_usecs, cp->tx_coalesce_usecs); - if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { + if (wdev->iftype == NL80211_IFTYPE_MONITOR) { wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n"); return -EINVAL; } diff --git a/drivers/net/wireless/ath/wil6210/fw.h b/drivers/net/wireless/ath/wil6210/fw.h index 2c7b24f61587..3e7a28045cab 100644 --- a/drivers/net/wireless/ath/wil6210/fw.h +++ b/drivers/net/wireless/ath/wil6210/fw.h @@ -14,6 +14,8 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifndef __WIL_FW_H__ +#define __WIL_FW_H__ #define WIL_FW_SIGNATURE (0x36323130) /* '0126' */ #define WIL_FW_FMT_VERSION (1) /* format version driver supports */ @@ -71,7 +73,39 @@ struct wil_fw_record_capabilities { /* type == wil_fw_type_comment */ struct wil_fw_record_comment_hdr hdr; /* capabilities (variable size), see enum wmi_fw_capability */ u8 capabilities[0]; -}; +} __packed; + +/* FW VIF concurrency encoded inside a comment record + * Format is similar to wiphy->iface_combinations + */ +#define WIL_FW_CONCURRENCY_MAGIC (0xfedccdef) +#define WIL_FW_CONCURRENCY_REC_VER 1 +struct wil_fw_concurrency_limit { + __le16 max; /* maximum number of interfaces of these types */ + __le16 types; /* interface types (bit mask of enum nl80211_iftype) */ +} __packed; + +struct wil_fw_concurrency_combo { + u8 n_limits; /* number of wil_fw_concurrency_limit entries */ + u8 max_interfaces; /* max number of concurrent interfaces allowed */ + u8 n_diff_channels; /* total number of different channels allowed */ + u8 same_bi; /* for APs, 1 if all APs must have same BI */ + /* keep last - concurrency limits, variable size by n_limits */ + struct wil_fw_concurrency_limit limits[0]; +} __packed; + +struct wil_fw_record_concurrency { /* type == wil_fw_type_comment */ + /* identifies concurrency record */ + __le32 magic; + /* structure version, currently always 1 */ + u8 version; + /* maximum number of supported MIDs _in addition_ to MID 0 */ + u8 n_mids; + /* number of concurrency combinations that follow */ + __le16 n_combos; + /* keep last - combinations, variable size by n_combos */ + struct wil_fw_concurrency_combo combos[0]; +} __packed; /* brd file info encoded inside a comment record */ #define WIL_BRD_FILE_MAGIC (0xabcddcbb) @@ -175,3 +209,5 @@ struct wil_fw_record_gateway_data4 { /* type == wil_fw_type_gateway_data4 */ __le32 command; struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */ } __packed; + +#endif /* __WIL_FW_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/fw_inc.c b/drivers/net/wireless/ath/wil6210/fw_inc.c index 914c0106e94b..718161b829c2 100644 --- a/drivers/net/wireless/ath/wil6210/fw_inc.c +++ b/drivers/net/wireless/ath/wil6210/fw_inc.c @@ -136,8 +136,8 @@ fw_handle_capabilities(struct wil6210_priv *wil, const void *data, size_t capa_size; if (size < sizeof(*rec)) { - wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, - data, size, true); + wil_err_fw(wil, "capabilities record too short: %zu\n", size); + /* let the FW load anyway */ return 0; } @@ -158,8 +158,7 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data, const struct wil_fw_record_brd_file *rec = data; if (size < sizeof(*rec)) { - wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, - data, size, true); + wil_err_fw(wil, "brd_file record too short: %zu\n", size); return 0; } @@ -173,6 +172,44 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data, } static int +fw_handle_concurrency(struct wil6210_priv *wil, const void *data, + size_t size) +{ + const struct wil_fw_record_concurrency *rec = data; + const struct wil_fw_concurrency_combo *combo; + const struct wil_fw_concurrency_limit *limit; + size_t remain, lsize; + int i, n_combos; + + if (size < sizeof(*rec)) { + wil_err_fw(wil, "concurrency record too short: %zu\n", size); + /* continue, let the FW load anyway */ + return 0; + } + + n_combos = le16_to_cpu(rec->n_combos); + remain = size - offsetof(struct wil_fw_record_concurrency, combos); + combo = rec->combos; + for (i = 0; i < n_combos; i++) { + if (remain < sizeof(*combo)) + goto out_short; + remain -= sizeof(*combo); + limit = combo->limits; + lsize = combo->n_limits * sizeof(*limit); + if (remain < lsize) + goto out_short; + remain -= lsize; + limit += combo->n_limits; + combo = (struct wil_fw_concurrency_combo *)limit; + } + + return wil_cfg80211_iface_combinations_from_fw(wil, rec); +out_short: + wil_err_fw(wil, "concurrency record truncated\n"); + return 0; +} + +static int fw_handle_comment(struct wil6210_priv *wil, const void *data, size_t size) { @@ -194,6 +231,13 @@ fw_handle_comment(struct wil6210_priv *wil, const void *data, wil_dbg_fw(wil, "magic is WIL_BRD_FILE_MAGIC\n"); rc = fw_handle_brd_file(wil, data, size); break; + case WIL_FW_CONCURRENCY_MAGIC: + wil_dbg_fw(wil, "magic is WIL_FW_CONCURRENCY_MAGIC\n"); + rc = fw_handle_concurrency(wil, data, size); + break; + default: + wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, + data, size, true); } return rc; diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 1835187ea075..84e9840c1752 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -127,7 +127,7 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil) void wil6210_unmask_irq_rx(struct wil6210_priv *wil) { - bool unmask_rx_htrsh = test_bit(wil_status_fwconnected, wil->status); + bool unmask_rx_htrsh = atomic_read(&wil->connected_vifs) > 0; wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC), unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH); @@ -188,12 +188,14 @@ void wil_unmask_irq(struct wil6210_priv *wil) void wil_configure_interrupt_moderation(struct wil6210_priv *wil) { + struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr; + wil_dbg_irq(wil, "configure_interrupt_moderation\n"); /* disable interrupt moderation for monitor * to get better timestamp precision */ - if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) + if (wdev->iftype == NL80211_IFTYPE_MONITOR) return; /* Disable and clear tx counter before (re)configuration */ @@ -340,7 +342,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) static void wil_notify_fw_error(struct wil6210_priv *wil) { - struct device *dev = &wil_to_ndev(wil)->dev; + struct device *dev = &wil->main_ndev->dev; char *envp[3] = { [0] = "SOURCE=wil6210", [1] = "EVENT=FW_ERROR", diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 0c61a6c13991..a4b413e8d55a 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -160,24 +160,34 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, } } -static void wil_disconnect_cid(struct wil6210_priv *wil, int cid, +static void wil_disconnect_cid(struct wil6210_vif *vif, int cid, u16 reason_code, bool from_event) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { uint i; - struct net_device *ndev = wil_to_ndev(wil); - struct wireless_dev *wdev = wil->wdev; + struct wil6210_priv *wil = vif_to_wil(vif); + struct net_device *ndev = vif_to_ndev(vif); + struct wireless_dev *wdev = vif_to_wdev(vif); struct wil_sta_info *sta = &wil->sta[cid]; might_sleep(); - wil_dbg_misc(wil, "disconnect_cid: CID %d, status %d\n", - cid, sta->status); + wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n", + cid, sta->mid, sta->status); /* inform upper/lower layers */ if (sta->status != wil_sta_unused) { + if (vif->mid != sta->mid) { + wil_err(wil, "STA MID mismatch with VIF MID(%d)\n", + vif->mid); + /* let FW override sta->mid but be more strict with + * user space requests + */ + if (!from_event) + return; + } if (!from_event) { bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ? disable_ap_sme : false; - wmi_disconnect_sta(wil, sta->addr, reason_code, + wmi_disconnect_sta(vif, sta->addr, reason_code, true, del_sta); } @@ -191,6 +201,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) break; } sta->status = wil_sta_unused; + sta->mid = U8_MAX; } /* reorder buffers */ for (i = 0; i < WIL_STA_TID_NUM; i++) { @@ -216,28 +227,33 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) memset(&sta->stats, 0, sizeof(sta->stats)); } -static bool wil_is_connected(struct wil6210_priv *wil) +static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid) { int i; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { - if (wil->sta[i].status == wil_sta_connected) + if (wil->sta[i].mid == mid && + wil->sta[i].status == wil_sta_connected) return true; } return false; } -static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, +static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, u16 reason_code, bool from_event) { + struct wil6210_priv *wil = vif_to_wil(vif); int cid = -ENOENT; - struct net_device *ndev = wil_to_ndev(wil); - struct wireless_dev *wdev = wil->wdev; + struct net_device *ndev; + struct wireless_dev *wdev; - if (unlikely(!ndev)) + if (unlikely(!vif)) return; + ndev = vif_to_ndev(vif); + wdev = vif_to_wdev(vif); + might_sleep(); wil_info(wil, "bssid=%pM, reason=%d, ev%s\n", bssid, reason_code, from_event ? "+" : "-"); @@ -254,48 +270,51 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, */ if (bssid && !is_broadcast_ether_addr(bssid) && !ether_addr_equal_unaligned(ndev->dev_addr, bssid)) { - cid = wil_find_cid(wil, bssid); + cid = wil_find_cid(wil, vif->mid, bssid); wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n", bssid, cid, reason_code); if (cid >= 0) /* disconnect 1 peer */ - wil_disconnect_cid(wil, cid, reason_code, from_event); + wil_disconnect_cid(vif, cid, reason_code, from_event); } else { /* all */ wil_dbg_misc(wil, "Disconnect all\n"); for (cid = 0; cid < WIL6210_MAX_CID; cid++) - wil_disconnect_cid(wil, cid, reason_code, from_event); + wil_disconnect_cid(vif, cid, reason_code, from_event); } /* link state */ switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: - wil_bcast_fini(wil); - wil_update_net_queues_bh(wil, NULL, true); + wil_bcast_fini(vif); + wil_update_net_queues_bh(wil, vif, NULL, true); netif_carrier_off(ndev); - wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); + if (!wil_has_other_active_ifaces(wil, ndev, false, true)) + wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS); - if (test_bit(wil_status_fwconnected, wil->status)) { - clear_bit(wil_status_fwconnected, wil->status); + if (test_and_clear_bit(wil_vif_fwconnected, vif->status)) { + atomic_dec(&wil->connected_vifs); cfg80211_disconnected(ndev, reason_code, NULL, 0, - wil->locally_generated_disc, + vif->locally_generated_disc, GFP_KERNEL); - wil->locally_generated_disc = false; - } else if (test_bit(wil_status_fwconnecting, wil->status)) { + vif->locally_generated_disc = false; + } else if (test_bit(wil_vif_fwconnecting, vif->status)) { cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL); - wil->bss = NULL; + vif->bss = NULL; } - clear_bit(wil_status_fwconnecting, wil->status); + clear_bit(wil_vif_fwconnecting, vif->status); break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: - if (!wil_is_connected(wil)) { - wil_update_net_queues_bh(wil, NULL, true); - clear_bit(wil_status_fwconnected, wil->status); + if (!wil_vif_is_connected(wil, vif->mid)) { + wil_update_net_queues_bh(wil, vif, NULL, true); + if (test_and_clear_bit(wil_vif_fwconnected, + vif->status)) + atomic_dec(&wil->connected_vifs); } else { - wil_update_net_queues_bh(wil, NULL, false); + wil_update_net_queues_bh(wil, vif, NULL, false); } break; default: @@ -303,26 +322,27 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, } } -static void wil_disconnect_worker(struct work_struct *work) +void wil_disconnect_worker(struct work_struct *work) { - struct wil6210_priv *wil = container_of(work, - struct wil6210_priv, disconnect_worker); - struct net_device *ndev = wil_to_ndev(wil); + struct wil6210_vif *vif = container_of(work, + struct wil6210_vif, disconnect_worker); + struct wil6210_priv *wil = vif_to_wil(vif); + struct net_device *ndev = vif_to_ndev(vif); int rc; struct { struct wmi_cmd_hdr wmi; struct wmi_disconnect_event evt; } __packed reply; - if (test_bit(wil_status_fwconnected, wil->status)) + if (test_bit(wil_vif_fwconnected, vif->status)) /* connect succeeded after all */ return; - if (!test_bit(wil_status_fwconnecting, wil->status)) + if (!test_bit(wil_vif_fwconnecting, vif->status)) /* already disconnected */ return; - rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0, + rc = wmi_call(wil, WMI_DISCONNECT_CMDID, vif->mid, NULL, 0, WMI_DISCONNECT_EVENTID, &reply, sizeof(reply), WIL6210_DISCONNECT_TO_MS); if (rc) { @@ -330,35 +350,11 @@ static void wil_disconnect_worker(struct work_struct *work) return; } - wil_update_net_queues_bh(wil, NULL, true); + wil_update_net_queues_bh(wil, vif, NULL, true); netif_carrier_off(ndev); cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0, WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL); - clear_bit(wil_status_fwconnecting, wil->status); -} - -static void wil_connect_timer_fn(struct timer_list *t) -{ - struct wil6210_priv *wil = from_timer(wil, t, connect_timer); - bool q; - - wil_err(wil, "Connect timeout detected, disconnect station\n"); - - /* reschedule to thread context - disconnect won't - * run from atomic context. - * queue on wmi_wq to prevent race with connect event. - */ - q = queue_work(wil->wmi_wq, &wil->disconnect_worker); - wil_dbg_wmi(wil, "queue_work of disconnect_worker -> %d\n", q); -} - -static void wil_scan_timer_fn(struct timer_list *t) -{ - struct wil6210_priv *wil = from_timer(wil, t, scan_timer); - - clear_bit(wil_status_fwready, wil->status); - wil_err(wil, "Scan timeout detected, start fw error recovery\n"); - wil_fw_error_recovery(wil); + clear_bit(wil_vif_fwconnecting, vif->status); } static int wil_wait_for_recovery(struct wil6210_priv *wil) @@ -394,12 +390,12 @@ static void wil_fw_error_worker(struct work_struct *work) { struct wil6210_priv *wil = container_of(work, struct wil6210_priv, fw_error_worker); - struct wireless_dev *wdev = wil->wdev; - struct net_device *ndev = wil_to_ndev(wil); + struct net_device *ndev = wil->main_ndev; + struct wireless_dev *wdev = ndev->ieee80211_ptr; wil_dbg_misc(wil, "fw error worker\n"); - if (!(ndev->flags & IFF_UP)) { + if (!ndev || !(ndev->flags & IFF_UP)) { wil_info(wil, "No recovery - interface is down\n"); return; } @@ -429,6 +425,10 @@ static void wil_fw_error_worker(struct work_struct *work) return; mutex_lock(&wil->mutex); + /* Needs adaptation for multiple VIFs + * need to go over all VIFs and consider the appropriate + * recovery. + */ switch (wdev->iftype) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: @@ -461,8 +461,9 @@ static int wil_find_free_vring(struct wil6210_priv *wil) return -EINVAL; } -int wil_tx_init(struct wil6210_priv *wil, int cid) +int wil_tx_init(struct wil6210_vif *vif, int cid) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc = -EINVAL, ringid; if (cid < 0) { @@ -475,21 +476,22 @@ int wil_tx_init(struct wil6210_priv *wil, int cid) goto out; } - wil_dbg_wmi(wil, "Configure for connection CID %d vring %d\n", - cid, ringid); + wil_dbg_wmi(wil, "Configure for connection CID %d MID %d vring %d\n", + cid, vif->mid, ringid); - rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0); + rc = wil_vring_init_tx(vif, ringid, 1 << tx_ring_order, cid, 0); if (rc) - wil_err(wil, "wil_vring_init_tx for CID %d vring %d failed\n", - cid, ringid); + wil_err(wil, "init TX for CID %d MID %d vring %d failed\n", + cid, vif->mid, ringid); out: return rc; } -int wil_bcast_init(struct wil6210_priv *wil) +int wil_bcast_init(struct wil6210_vif *vif) { - int ri = wil->bcast_vring, rc; + struct wil6210_priv *wil = vif_to_wil(vif); + int ri = vif->bcast_vring, rc; if ((ri >= 0) && wil->vring_tx[ri].va) return 0; @@ -498,25 +500,38 @@ int wil_bcast_init(struct wil6210_priv *wil) if (ri < 0) return ri; - wil->bcast_vring = ri; - rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order); + vif->bcast_vring = ri; + rc = wil_vring_init_bcast(vif, ri, 1 << bcast_ring_order); if (rc) - wil->bcast_vring = -1; + vif->bcast_vring = -1; return rc; } -void wil_bcast_fini(struct wil6210_priv *wil) +void wil_bcast_fini(struct wil6210_vif *vif) { - int ri = wil->bcast_vring; + struct wil6210_priv *wil = vif_to_wil(vif); + int ri = vif->bcast_vring; if (ri < 0) return; - wil->bcast_vring = -1; + vif->bcast_vring = -1; wil_vring_fini_tx(wil, ri); } +void wil_bcast_fini_all(struct wil6210_priv *wil) +{ + int i; + struct wil6210_vif *vif; + + for (i = 0; i < wil->max_vifs; i++) { + vif = wil->vifs[i]; + if (vif) + wil_bcast_fini(vif); + } +} + int wil_priv_init(struct wil6210_priv *wil) { uint i; @@ -524,38 +539,29 @@ int wil_priv_init(struct wil6210_priv *wil) wil_dbg_misc(wil, "priv_init\n"); memset(wil->sta, 0, sizeof(wil->sta)); - for (i = 0; i < WIL6210_MAX_CID; i++) + for (i = 0; i < WIL6210_MAX_CID; i++) { spin_lock_init(&wil->sta[i].tid_rx_lock); + wil->sta[i].mid = U8_MAX; + } for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) spin_lock_init(&wil->vring_tx_data[i].lock); mutex_init(&wil->mutex); + mutex_init(&wil->vif_mutex); mutex_init(&wil->wmi_mutex); - mutex_init(&wil->probe_client_mutex); - mutex_init(&wil->p2p_wdev_mutex); mutex_init(&wil->halp.lock); init_completion(&wil->wmi_ready); init_completion(&wil->wmi_call); init_completion(&wil->halp.comp); - wil->bcast_vring = -1; - timer_setup(&wil->connect_timer, wil_connect_timer_fn, 0); - timer_setup(&wil->scan_timer, wil_scan_timer_fn, 0); - timer_setup(&wil->p2p.discovery_timer, wil_p2p_discovery_timer_fn, 0); - - INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker); INIT_WORK(&wil->wmi_event_worker, wmi_event_worker); INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker); - INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker); - INIT_WORK(&wil->p2p.delayed_listen_work, wil_p2p_delayed_listen_work); INIT_LIST_HEAD(&wil->pending_wmi_ev); - INIT_LIST_HEAD(&wil->probe_client_pending); spin_lock_init(&wil->wmi_ev_lock); spin_lock_init(&wil->net_queue_lock); - wil->net_queue_stopped = 1; init_waitqueue_head(&wil->wq); wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi"); @@ -582,6 +588,9 @@ int wil_priv_init(struct wil6210_priv *wil) memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats)); wil->vring_idle_trsh = 16; + wil->reply_mid = U8_MAX; + wil->max_vifs = 1; + return 0; out_wmi_wq: @@ -600,7 +609,7 @@ void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps) /** * wil6210_disconnect - disconnect one connection - * @wil: driver context + * @vif: virtual interface context * @bssid: peer to disconnect, NULL to disconnect all * @reason_code: Reason code for the Disassociation frame * @from_event: whether is invoked from FW event handler @@ -608,13 +617,15 @@ void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps) * Disconnect and release associated resources. If invoked not from the * FW event handler, issue WMI command(s) to trigger MAC disconnect. */ -void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, +void wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, u16 reason_code, bool from_event) { + struct wil6210_priv *wil = vif_to_wil(vif); + wil_dbg_misc(wil, "disconnect\n"); - del_timer_sync(&wil->connect_timer); - _wil6210_disconnect(wil, bssid, reason_code, from_event); + del_timer_sync(&vif->connect_timer); + _wil6210_disconnect(vif, bssid, reason_code, from_event); } void wil_priv_deinit(struct wil6210_priv *wil) @@ -622,18 +633,8 @@ void wil_priv_deinit(struct wil6210_priv *wil) wil_dbg_misc(wil, "priv_deinit\n"); wil_set_recovery_state(wil, fw_recovery_idle); - del_timer_sync(&wil->scan_timer); - del_timer_sync(&wil->p2p.discovery_timer); - cancel_work_sync(&wil->disconnect_worker); cancel_work_sync(&wil->fw_error_worker); - cancel_work_sync(&wil->p2p.discovery_expired_work); - cancel_work_sync(&wil->p2p.delayed_listen_work); - mutex_lock(&wil->mutex); - wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); - mutex_unlock(&wil->mutex); wmi_event_flush(wil); - wil_probe_client_flush(wil); - cancel_work_sync(&wil->probe_client_worker); destroy_workqueue(wil->wq_service); destroy_workqueue(wil->wmi_wq); } @@ -715,7 +716,7 @@ static void wil_bl_prepare_halt(struct wil6210_priv *wil) offsetof(struct bl_dedicated_registers_v0, boot_loader_struct_version)); if (!tmp) { - wil_dbg_misc(wil, "old BL, skipping halt preperation\n"); + wil_dbg_misc(wil, "old BL, skipping halt preparation\n"); return; } @@ -943,7 +944,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r) static int wil_get_bl_info(struct wil6210_priv *wil) { - struct net_device *ndev = wil_to_ndev(wil); + struct net_device *ndev = wil->main_ndev; struct wiphy *wiphy = wil_to_wiphy(wil); union { struct bl_dedicated_registers_v0 bl0; @@ -1035,7 +1036,7 @@ static void wil_bl_crash_info(struct wil6210_priv *wil, bool is_err) static int wil_get_otp_info(struct wil6210_priv *wil) { - struct net_device *ndev = wil_to_ndev(wil); + struct net_device *ndev = wil->main_ndev; struct wiphy *wiphy = wil_to_wiphy(wil); u8 mac[8]; @@ -1069,31 +1070,46 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil) return 0; } -void wil_abort_scan(struct wil6210_priv *wil, bool sync) +void wil_abort_scan(struct wil6210_vif *vif, bool sync) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; struct cfg80211_scan_info info = { .aborted = true, }; - lockdep_assert_held(&wil->p2p_wdev_mutex); + lockdep_assert_held(&wil->vif_mutex); - if (!wil->scan_request) + if (!vif->scan_request) return; - wil_dbg_misc(wil, "Abort scan_request 0x%p\n", wil->scan_request); - del_timer_sync(&wil->scan_timer); - mutex_unlock(&wil->p2p_wdev_mutex); - rc = wmi_abort_scan(wil); + wil_dbg_misc(wil, "Abort scan_request 0x%p\n", vif->scan_request); + del_timer_sync(&vif->scan_timer); + mutex_unlock(&wil->vif_mutex); + rc = wmi_abort_scan(vif); if (!rc && sync) - wait_event_interruptible_timeout(wil->wq, !wil->scan_request, + wait_event_interruptible_timeout(wil->wq, !vif->scan_request, msecs_to_jiffies( WAIT_FOR_SCAN_ABORT_MS)); - mutex_lock(&wil->p2p_wdev_mutex); - if (wil->scan_request) { - cfg80211_scan_done(wil->scan_request, &info); - wil->scan_request = NULL; + mutex_lock(&wil->vif_mutex); + if (vif->scan_request) { + cfg80211_scan_done(vif->scan_request, &info); + vif->scan_request = NULL; + } +} + +void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync) +{ + int i; + + lockdep_assert_held(&wil->vif_mutex); + + for (i = 0; i < wil->max_vifs; i++) { + struct wil6210_vif *vif = wil->vifs[i]; + + if (vif) + wil_abort_scan(vif, sync); } } @@ -1138,6 +1154,34 @@ static void wil_pre_fw_config(struct wil6210_priv *wil) } } +static int wil_restore_vifs(struct wil6210_priv *wil) +{ + struct wil6210_vif *vif; + struct net_device *ndev; + struct wireless_dev *wdev; + int i, rc; + + for (i = 0; i < wil->max_vifs; i++) { + vif = wil->vifs[i]; + if (!vif) + continue; + vif->ap_isolate = 0; + if (vif->mid) { + ndev = vif_to_ndev(vif); + wdev = vif_to_wdev(vif); + rc = wmi_port_allocate(wil, vif->mid, ndev->dev_addr, + wdev->iftype); + if (rc) { + wil_err(wil, "fail to restore VIF %d type %d, rc %d\n", + i, wdev->iftype, rc); + return rc; + } + } + } + + return 0; +} + /* * We reset all the structures, and we reset the UMAC. * After calling this routine, you're expected to reload @@ -1145,9 +1189,10 @@ static void wil_pre_fw_config(struct wil6210_priv *wil) */ int wil_reset(struct wil6210_priv *wil, bool load_fw) { - int rc; + int rc, i; unsigned long status_flags = BIT(wil_status_resetting); int no_flash; + struct wil6210_vif *vif; wil_dbg_misc(wil, "reset\n"); @@ -1158,7 +1203,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) static const u8 mac[ETH_ALEN] = { 0x00, 0xde, 0xad, 0x12, 0x34, 0x56, }; - struct net_device *ndev = wil_to_ndev(wil); + struct net_device *ndev = wil->main_ndev; ether_addr_copy(ndev->perm_addr, mac); ether_addr_copy(ndev->dev_addr, ndev->perm_addr); @@ -1196,17 +1241,23 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) goto out; } - cancel_work_sync(&wil->disconnect_worker); - wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); - wil_bcast_fini(wil); + mutex_lock(&wil->vif_mutex); + wil_abort_scan_all_vifs(wil, false); + mutex_unlock(&wil->vif_mutex); + + for (i = 0; i < wil->max_vifs; i++) { + vif = wil->vifs[i]; + if (vif) { + cancel_work_sync(&vif->disconnect_worker); + wil6210_disconnect(vif, NULL, + WLAN_REASON_DEAUTH_LEAVING, false); + } + } + wil_bcast_fini_all(wil); /* Disable device led before reset*/ wmi_led_cfg(wil, false); - mutex_lock(&wil->p2p_wdev_mutex); - wil_abort_scan(wil, false); - mutex_unlock(&wil->p2p_wdev_mutex); - /* prevent NAPI from being scheduled and prevent wmi commands */ mutex_lock(&wil->wmi_mutex); if (test_bit(wil_status_suspending, wil->status)) @@ -1276,7 +1327,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) } /* init after reset */ - wil->ap_isolate = 0; reinit_completion(&wil->wmi_ready); reinit_completion(&wil->wmi_call); reinit_completion(&wil->halp.comp); @@ -1299,6 +1349,12 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; } + rc = wil_restore_vifs(wil); + if (rc) { + wil_err(wil, "failed to restore vifs, rc %d\n", rc); + return rc; + } + wil_collect_fw_info(wil); if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT) @@ -1337,8 +1393,8 @@ void wil_fw_error_recovery(struct wil6210_priv *wil) int __wil_up(struct wil6210_priv *wil) { - struct net_device *ndev = wil_to_ndev(wil); - struct wireless_dev *wdev = wil->wdev; + struct net_device *ndev = wil->main_ndev; + struct wireless_dev *wdev = ndev->ieee80211_ptr; int rc; WARN_ON(!mutex_is_locked(&wil->mutex)); @@ -1420,10 +1476,10 @@ int __wil_down(struct wil6210_priv *wil) } wil_enable_irq(wil); - mutex_lock(&wil->p2p_wdev_mutex); + mutex_lock(&wil->vif_mutex); wil_p2p_stop_radio_operations(wil); - wil_abort_scan(wil, false); - mutex_unlock(&wil->p2p_wdev_mutex); + wil_abort_scan_all_vifs(wil, false); + mutex_unlock(&wil->vif_mutex); return wil_reset(wil, false); } @@ -1442,13 +1498,14 @@ int wil_down(struct wil6210_priv *wil) return rc; } -int wil_find_cid(struct wil6210_priv *wil, const u8 *mac) +int wil_find_cid(struct wil6210_priv *wil, u8 mid, const u8 *mac) { int i; int rc = -ENOENT; for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { - if ((wil->sta[i].status != wil_sta_unused) && + if (wil->sta[i].mid == mid && + wil->sta[i].status != wil_sta_unused && ether_addr_equal(wil->sta[i].addr, mac)) { rc = i; break; diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 7ba4e0af8f57..05e9408e7ea3 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -15,13 +16,41 @@ */ #include <linux/etherdevice.h> +#include <linux/rtnetlink.h> #include "wil6210.h" #include "txrx.h" +bool wil_has_other_active_ifaces(struct wil6210_priv *wil, + struct net_device *ndev, bool up, bool ok) +{ + int i; + struct wil6210_vif *vif; + struct net_device *ndev_i; + + for (i = 0; i < wil->max_vifs; i++) { + vif = wil->vifs[i]; + if (vif) { + ndev_i = vif_to_ndev(vif); + if (ndev_i != ndev) + if ((up && (ndev_i->flags & IFF_UP)) || + (ok && netif_carrier_ok(ndev_i))) + return true; + } + } + + return false; +} + +bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok) +{ + /* use NULL ndev argument to check all interfaces */ + return wil_has_other_active_ifaces(wil, NULL, up, ok); +} + static int wil_open(struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); - int rc; + int rc = 0; wil_dbg_misc(wil, "open\n"); @@ -31,13 +60,16 @@ static int wil_open(struct net_device *ndev) return -EINVAL; } - rc = wil_pm_runtime_get(wil); - if (rc < 0) - return rc; + if (!wil_has_other_active_ifaces(wil, ndev, true, false)) { + wil_dbg_misc(wil, "open, first iface\n"); + rc = wil_pm_runtime_get(wil); + if (rc < 0) + return rc; - rc = wil_up(wil); - if (rc) - wil_pm_runtime_put(wil); + rc = wil_up(wil); + if (rc) + wil_pm_runtime_put(wil); + } return rc; } @@ -45,13 +77,16 @@ static int wil_open(struct net_device *ndev) static int wil_stop(struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); - int rc; + int rc = 0; wil_dbg_misc(wil, "stop\n"); - rc = wil_down(wil); - if (!rc) - wil_pm_runtime_put(wil); + if (!wil_has_other_active_ifaces(wil, ndev, true, false)) { + wil_dbg_misc(wil, "stop, last iface\n"); + rc = wil_down(wil); + if (!rc) + wil_pm_runtime_put(wil); + } return rc; } @@ -96,11 +131,19 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget) for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { struct vring *vring = &wil->vring_tx[i]; struct vring_tx_data *txdata = &wil->vring_tx_data[i]; + struct wil6210_vif *vif; - if (!vring->va || !txdata->enabled) + if (!vring->va || !txdata->enabled || + txdata->mid >= wil->max_vifs) continue; - tx_done += wil_tx_complete(wil, i); + vif = wil->vifs[txdata->mid]; + if (unlikely(!vif)) { + wil_dbg_txrx(wil, "Invalid MID %d\n", txdata->mid); + continue; + } + + tx_done += wil_tx_complete(vif, i); } if (tx_done < budget) { @@ -121,44 +164,137 @@ static void wil_dev_setup(struct net_device *dev) dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT; } -void *wil_if_alloc(struct device *dev) +static void wil_vif_deinit(struct wil6210_vif *vif) { - struct net_device *ndev; - struct wireless_dev *wdev; - struct wil6210_priv *wil; - struct ieee80211_channel *ch; - int rc = 0; + del_timer_sync(&vif->scan_timer); + del_timer_sync(&vif->p2p.discovery_timer); + cancel_work_sync(&vif->disconnect_worker); + cancel_work_sync(&vif->p2p.discovery_expired_work); + cancel_work_sync(&vif->p2p.delayed_listen_work); + wil_probe_client_flush(vif); + cancel_work_sync(&vif->probe_client_worker); +} - wdev = wil_cfg80211_init(dev); - if (IS_ERR(wdev)) { - dev_err(dev, "wil_cfg80211_init failed\n"); - return wdev; - } +void wil_vif_free(struct wil6210_vif *vif) +{ + struct net_device *ndev = vif_to_ndev(vif); - wil = wdev_to_wil(wdev); - wil->wdev = wdev; - wil->radio_wdev = wdev; + wil_vif_deinit(vif); + free_netdev(ndev); +} - wil_dbg_misc(wil, "if_alloc\n"); +static void wil_ndev_destructor(struct net_device *ndev) +{ + struct wil6210_vif *vif = ndev_to_vif(ndev); - rc = wil_priv_init(wil); - if (rc) { - dev_err(dev, "wil_priv_init failed\n"); - goto out_wdev; + wil_vif_deinit(vif); +} + +static void wil_connect_timer_fn(struct timer_list *t) +{ + struct wil6210_vif *vif = from_timer(vif, t, connect_timer); + struct wil6210_priv *wil = vif_to_wil(vif); + bool q; + + wil_err(wil, "Connect timeout detected, disconnect station\n"); + + /* reschedule to thread context - disconnect won't + * run from atomic context. + * queue on wmi_wq to prevent race with connect event. + */ + q = queue_work(wil->wmi_wq, &vif->disconnect_worker); + wil_dbg_wmi(wil, "queue_work of disconnect_worker -> %d\n", q); +} + +static void wil_scan_timer_fn(struct timer_list *t) +{ + struct wil6210_vif *vif = from_timer(vif, t, scan_timer); + struct wil6210_priv *wil = vif_to_wil(vif); + + clear_bit(wil_status_fwready, wil->status); + wil_err(wil, "Scan timeout detected, start fw error recovery\n"); + wil_fw_error_recovery(wil); +} + +static void wil_p2p_discovery_timer_fn(struct timer_list *t) +{ + struct wil6210_vif *vif = from_timer(vif, t, p2p.discovery_timer); + struct wil6210_priv *wil = vif_to_wil(vif); + + wil_dbg_misc(wil, "p2p_discovery_timer_fn\n"); + + schedule_work(&vif->p2p.discovery_expired_work); +} + +static void wil_vif_init(struct wil6210_vif *vif) +{ + vif->bcast_vring = -1; + + mutex_init(&vif->probe_client_mutex); + + timer_setup(&vif->connect_timer, wil_connect_timer_fn, 0); + timer_setup(&vif->scan_timer, wil_scan_timer_fn, 0); + timer_setup(&vif->p2p.discovery_timer, wil_p2p_discovery_timer_fn, 0); + + INIT_WORK(&vif->probe_client_worker, wil_probe_client_worker); + INIT_WORK(&vif->disconnect_worker, wil_disconnect_worker); + INIT_WORK(&vif->p2p.delayed_listen_work, wil_p2p_delayed_listen_work); + + INIT_LIST_HEAD(&vif->probe_client_pending); + + vif->net_queue_stopped = 1; +} + +static u8 wil_vif_find_free_mid(struct wil6210_priv *wil) +{ + u8 i; + + for (i = 0; i < wil->max_vifs; i++) { + if (!wil->vifs[i]) + return i; } - wdev->iftype = NL80211_IFTYPE_STATION; /* TODO */ - /* default monitor channel */ - ch = wdev->wiphy->bands[NL80211_BAND_60GHZ]->channels; - cfg80211_chandef_create(&wil->monitor_chandef, ch, NL80211_CHAN_NO_HT); + return U8_MAX; +} + +struct wil6210_vif * +wil_vif_alloc(struct wil6210_priv *wil, const char *name, + unsigned char name_assign_type, enum nl80211_iftype iftype) +{ + struct net_device *ndev; + struct wireless_dev *wdev; + struct wil6210_vif *vif; + u8 mid; + + mid = wil_vif_find_free_mid(wil); + if (mid == U8_MAX) { + wil_err(wil, "no available virtual interface\n"); + return ERR_PTR(-EINVAL); + } - ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup); + ndev = alloc_netdev(sizeof(*vif), name, name_assign_type, + wil_dev_setup); if (!ndev) { - dev_err(dev, "alloc_netdev_mqs failed\n"); - rc = -ENOMEM; - goto out_priv; + dev_err(wil_to_dev(wil), "alloc_netdev failed\n"); + return ERR_PTR(-ENOMEM); + } + if (mid == 0) { + wil->main_ndev = ndev; + } else { + ndev->priv_destructor = wil_ndev_destructor; + ndev->needs_free_netdev = true; } + vif = ndev_to_vif(ndev); + vif->ndev = ndev; + vif->wil = wil; + vif->mid = mid; + wil_vif_init(vif); + + wdev = &vif->wdev; + wdev->wiphy = wil->wiphy; + wdev->iftype = iftype; + ndev->netdev_ops = &wil_netdev_ops; wil_set_ethtoolops(ndev); ndev->ieee80211_ptr = wdev; @@ -170,21 +306,53 @@ void *wil_if_alloc(struct device *dev) ndev->features |= ndev->hw_features; SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); wdev->netdev = ndev; + return vif; +} + +void *wil_if_alloc(struct device *dev) +{ + struct wil6210_priv *wil; + struct wil6210_vif *vif; + int rc = 0; + + wil = wil_cfg80211_init(dev); + if (IS_ERR(wil)) { + dev_err(dev, "wil_cfg80211_init failed\n"); + return wil; + } + + rc = wil_priv_init(wil); + if (rc) { + dev_err(dev, "wil_priv_init failed\n"); + goto out_cfg; + } + + wil_dbg_misc(wil, "if_alloc\n"); + + vif = wil_vif_alloc(wil, "wlan%d", NET_NAME_UNKNOWN, + NL80211_IFTYPE_STATION); + if (IS_ERR(vif)) { + dev_err(dev, "wil_vif_alloc failed\n"); + rc = -ENOMEM; + goto out_priv; + } + + wil->radio_wdev = vif_to_wdev(vif); return wil; - out_priv: +out_priv: wil_priv_deinit(wil); - out_wdev: - wil_wdev_free(wil); +out_cfg: + wil_cfg80211_deinit(wil); return ERR_PTR(rc); } void wil_if_free(struct wil6210_priv *wil) { - struct net_device *ndev = wil_to_ndev(wil); + struct net_device *ndev = wil->main_ndev; wil_dbg_misc(wil, "if_free\n"); @@ -193,17 +361,50 @@ void wil_if_free(struct wil6210_priv *wil) wil_priv_deinit(wil); - wil_to_ndev(wil) = NULL; + wil->main_ndev = NULL; + wil_ndev_destructor(ndev); free_netdev(ndev); - wil_wdev_free(wil); + wil_cfg80211_deinit(wil); +} + +int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif) +{ + struct net_device *ndev = vif_to_ndev(vif); + struct wireless_dev *wdev = vif_to_wdev(vif); + bool any_active = wil_has_active_ifaces(wil, true, false); + int rc; + + ASSERT_RTNL(); + + if (wil->vifs[vif->mid]) { + dev_err(&ndev->dev, "VIF with mid %d already in use\n", + vif->mid); + return -EEXIST; + } + if (any_active && vif->mid != 0) { + rc = wmi_port_allocate(wil, vif->mid, ndev->dev_addr, + wdev->iftype); + if (rc) + return rc; + } + rc = register_netdevice(ndev); + if (rc < 0) { + dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc); + if (any_active && vif->mid != 0) + wmi_port_delete(wil, vif->mid); + return rc; + } + + wil->vifs[vif->mid] = vif; + return 0; } int wil_if_add(struct wil6210_priv *wil) { - struct wireless_dev *wdev = wil_to_wdev(wil); - struct wiphy *wiphy = wdev->wiphy; - struct net_device *ndev = wil_to_ndev(wil); + struct wiphy *wiphy = wil->wiphy; + struct net_device *ndev = wil->main_ndev; + struct wil6210_vif *vif = ndev_to_vif(ndev); int rc; wil_dbg_misc(wil, "entered"); @@ -216,33 +417,94 @@ int wil_if_add(struct wil6210_priv *wil) return rc; } - netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx, + init_dummy_netdev(&wil->napi_ndev); + netif_napi_add(&wil->napi_ndev, &wil->napi_rx, wil6210_netdev_poll_rx, WIL6210_NAPI_BUDGET); - netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx, + netif_tx_napi_add(&wil->napi_ndev, + &wil->napi_tx, wil6210_netdev_poll_tx, WIL6210_NAPI_BUDGET); - wil_update_net_queues_bh(wil, NULL, true); + wil_update_net_queues_bh(wil, vif, NULL, true); - rc = register_netdev(ndev); - if (rc < 0) { - dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc); + rtnl_lock(); + rc = wil_vif_add(wil, vif); + rtnl_unlock(); + if (rc < 0) goto out_wiphy; - } return 0; out_wiphy: - wiphy_unregister(wdev->wiphy); + wiphy_unregister(wiphy); return rc; } +void wil_vif_remove(struct wil6210_priv *wil, u8 mid) +{ + struct wil6210_vif *vif; + struct net_device *ndev; + bool any_active = wil_has_active_ifaces(wil, true, false); + + ASSERT_RTNL(); + if (mid >= wil->max_vifs) { + wil_err(wil, "invalid MID: %d\n", mid); + return; + } + + vif = wil->vifs[mid]; + if (!vif) { + wil_err(wil, "MID %d not registered\n", mid); + return; + } + + ndev = vif_to_ndev(vif); + /* during unregister_netdevice cfg80211_leave may perform operations + * such as stop AP, disconnect, so we only clear the VIF afterwards + */ + unregister_netdevice(ndev); + + mutex_lock(&wil->mutex); + wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false); + mutex_unlock(&wil->mutex); + + if (any_active && vif->mid != 0) + wmi_port_delete(wil, vif->mid); + + /* make sure no one is accessing the VIF before removing */ + mutex_lock(&wil->vif_mutex); + wil->vifs[mid] = NULL; + /* ensure NAPI code will see the NULL VIF */ + wmb(); + if (test_bit(wil_status_napi_en, wil->status)) { + napi_synchronize(&wil->napi_rx); + napi_synchronize(&wil->napi_tx); + } + mutex_unlock(&wil->vif_mutex); + + flush_work(&wil->wmi_event_worker); + del_timer_sync(&vif->connect_timer); + cancel_work_sync(&vif->disconnect_worker); + wil_probe_client_flush(vif); + cancel_work_sync(&vif->probe_client_worker); + /* for VIFs, ndev will be freed by destructor after RTNL is unlocked. + * the main interface will be freed in wil_if_free, we need to keep it + * a bit longer so logging macros will work. + */ +} + void wil_if_remove(struct wil6210_priv *wil) { - struct net_device *ndev = wil_to_ndev(wil); - struct wireless_dev *wdev = wil_to_wdev(wil); + struct net_device *ndev = wil->main_ndev; + struct wireless_dev *wdev = ndev->ieee80211_ptr; wil_dbg_misc(wil, "if_remove\n"); - unregister_netdev(ndev); + rtnl_lock(); + wil_vif_remove(wil, 0); + rtnl_unlock(); + + netif_napi_del(&wil->napi_tx); + netif_napi_del(&wil->napi_rx); + wiphy_unregister(wdev->wiphy); } diff --git a/drivers/net/wireless/ath/wil6210/p2p.c b/drivers/net/wireless/ath/wil6210/p2p.c index 7dbee2c3e482..db087ea58ddf 100644 --- a/drivers/net/wireless/ath/wil6210/p2p.c +++ b/drivers/net/wireless/ath/wil6210/p2p.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -22,27 +23,28 @@ #define P2P_SEARCH_DURATION_MS 500 #define P2P_DEFAULT_BI 100 -static int wil_p2p_start_listen(struct wil6210_priv *wil) +static int wil_p2p_start_listen(struct wil6210_vif *vif) { - struct wil_p2p_info *p2p = &wil->p2p; + struct wil6210_priv *wil = vif_to_wil(vif); + struct wil_p2p_info *p2p = &vif->p2p; u8 channel = p2p->listen_chan.hw_value; int rc; lockdep_assert_held(&wil->mutex); - rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI); + rc = wmi_p2p_cfg(vif, channel, P2P_DEFAULT_BI); if (rc) { wil_err(wil, "wmi_p2p_cfg failed\n"); goto out; } - rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID); + rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID); if (rc) { wil_err(wil, "wmi_set_ssid failed\n"); goto out_stop; } - rc = wmi_start_listen(wil); + rc = wmi_start_listen(vif); if (rc) { wil_err(wil, "wmi_start_listen failed\n"); goto out_stop; @@ -53,7 +55,7 @@ static int wil_p2p_start_listen(struct wil6210_priv *wil) jiffies + msecs_to_jiffies(p2p->listen_duration)); out_stop: if (rc) - wmi_stop_discovery(wil); + wmi_stop_discovery(vif); out: return rc; @@ -65,20 +67,12 @@ bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request) (request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL); } -void wil_p2p_discovery_timer_fn(struct timer_list *t) -{ - struct wil6210_priv *wil = from_timer(wil, t, p2p.discovery_timer); - - wil_dbg_misc(wil, "p2p_discovery_timer_fn\n"); - - schedule_work(&wil->p2p.discovery_expired_work); -} - -int wil_p2p_search(struct wil6210_priv *wil, +int wil_p2p_search(struct wil6210_vif *vif, struct cfg80211_scan_request *request) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; - struct wil_p2p_info *p2p = &wil->p2p; + struct wil_p2p_info *p2p = &vif->p2p; wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL); @@ -90,20 +84,20 @@ int wil_p2p_search(struct wil6210_priv *wil, goto out; } - rc = wmi_p2p_cfg(wil, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI); + rc = wmi_p2p_cfg(vif, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI); if (rc) { wil_err(wil, "wmi_p2p_cfg failed\n"); goto out; } - rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID); + rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID); if (rc) { wil_err(wil, "wmi_set_ssid failed\n"); goto out_stop; } /* Set application IE to probe request and probe response */ - rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ, + rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ, request->ie_len, request->ie); if (rc) { wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n"); @@ -113,14 +107,14 @@ int wil_p2p_search(struct wil6210_priv *wil, /* supplicant doesn't provide Probe Response IEs. As a workaround - * re-use Probe Request IEs */ - rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, + rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP, request->ie_len, request->ie); if (rc) { wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n"); goto out_stop; } - rc = wmi_start_search(wil); + rc = wmi_start_search(vif); if (rc) { wil_err(wil, "wmi_start_search failed\n"); goto out_stop; @@ -133,7 +127,7 @@ int wil_p2p_search(struct wil6210_priv *wil, out_stop: if (rc) - wmi_stop_discovery(wil); + wmi_stop_discovery(vif); out: return rc; @@ -143,7 +137,8 @@ int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev, unsigned int duration, struct ieee80211_channel *chan, u64 *cookie) { - struct wil_p2p_info *p2p = &wil->p2p; + struct wil6210_vif *vif = wdev_to_vif(wil, wdev); + struct wil_p2p_info *p2p = &vif->p2p; int rc; if (!chan) @@ -163,23 +158,24 @@ int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev, *cookie = ++p2p->cookie; p2p->listen_duration = duration; - mutex_lock(&wil->p2p_wdev_mutex); - if (wil->scan_request) { + mutex_lock(&wil->vif_mutex); + if (vif->scan_request) { wil_dbg_misc(wil, "Delaying p2p listen until scan done\n"); p2p->pending_listen_wdev = wdev; p2p->discovery_started = 1; rc = 0; - mutex_unlock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->vif_mutex); goto out; } - mutex_unlock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->vif_mutex); - rc = wil_p2p_start_listen(wil); + rc = wil_p2p_start_listen(vif); if (rc) goto out; p2p->discovery_started = 1; - wil->radio_wdev = wdev; + if (vif->mid == 0) + wil->radio_wdev = wdev; cfg80211_ready_on_channel(wdev, *cookie, chan, duration, GFP_KERNEL); @@ -189,9 +185,9 @@ out: return rc; } -u8 wil_p2p_stop_discovery(struct wil6210_priv *wil) +u8 wil_p2p_stop_discovery(struct wil6210_vif *vif) { - struct wil_p2p_info *p2p = &wil->p2p; + struct wil_p2p_info *p2p = &vif->p2p; u8 started = p2p->discovery_started; if (p2p->discovery_started) { @@ -200,7 +196,7 @@ u8 wil_p2p_stop_discovery(struct wil6210_priv *wil) p2p->pending_listen_wdev = NULL; } else { del_timer_sync(&p2p->discovery_timer); - wmi_stop_discovery(wil); + wmi_stop_discovery(vif); } p2p->discovery_started = 0; } @@ -208,9 +204,10 @@ u8 wil_p2p_stop_discovery(struct wil6210_priv *wil) return started; } -int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie) +int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie) { - struct wil_p2p_info *p2p = &wil->p2p; + struct wil6210_priv *wil = vif_to_wil(vif); + struct wil_p2p_info *p2p = &vif->p2p; u8 started; mutex_lock(&wil->mutex); @@ -222,7 +219,7 @@ int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie) return -ENOENT; } - started = wil_p2p_stop_discovery(wil); + started = wil_p2p_stop_discovery(vif); mutex_unlock(&wil->mutex); @@ -231,13 +228,14 @@ int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie) return -ENOENT; } - mutex_lock(&wil->p2p_wdev_mutex); - cfg80211_remain_on_channel_expired(wil->radio_wdev, + mutex_lock(&wil->vif_mutex); + cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif), p2p->cookie, &p2p->listen_chan, GFP_KERNEL); - wil->radio_wdev = wil->wdev; - mutex_unlock(&wil->p2p_wdev_mutex); + if (vif->mid == 0) + wil->radio_wdev = wil->main_ndev->ieee80211_ptr; + mutex_unlock(&wil->vif_mutex); return 0; } @@ -245,40 +243,43 @@ void wil_p2p_listen_expired(struct work_struct *work) { struct wil_p2p_info *p2p = container_of(work, struct wil_p2p_info, discovery_expired_work); - struct wil6210_priv *wil = container_of(p2p, - struct wil6210_priv, p2p); + struct wil6210_vif *vif = container_of(p2p, + struct wil6210_vif, p2p); + struct wil6210_priv *wil = vif_to_wil(vif); u8 started; wil_dbg_misc(wil, "p2p_listen_expired\n"); mutex_lock(&wil->mutex); - started = wil_p2p_stop_discovery(wil); + started = wil_p2p_stop_discovery(vif); mutex_unlock(&wil->mutex); - if (started) { - mutex_lock(&wil->p2p_wdev_mutex); - cfg80211_remain_on_channel_expired(wil->radio_wdev, - p2p->cookie, - &p2p->listen_chan, - GFP_KERNEL); - wil->radio_wdev = wil->wdev; - mutex_unlock(&wil->p2p_wdev_mutex); - } + if (!started) + return; + mutex_lock(&wil->vif_mutex); + cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif), + p2p->cookie, + &p2p->listen_chan, + GFP_KERNEL); + if (vif->mid == 0) + wil->radio_wdev = wil->main_ndev->ieee80211_ptr; + mutex_unlock(&wil->vif_mutex); } void wil_p2p_search_expired(struct work_struct *work) { struct wil_p2p_info *p2p = container_of(work, struct wil_p2p_info, discovery_expired_work); - struct wil6210_priv *wil = container_of(p2p, - struct wil6210_priv, p2p); + struct wil6210_vif *vif = container_of(p2p, + struct wil6210_vif, p2p); + struct wil6210_priv *wil = vif_to_wil(vif); u8 started; wil_dbg_misc(wil, "p2p_search_expired\n"); mutex_lock(&wil->mutex); - started = wil_p2p_stop_discovery(wil); + started = wil_p2p_stop_discovery(vif); mutex_unlock(&wil->mutex); if (started) { @@ -286,13 +287,15 @@ void wil_p2p_search_expired(struct work_struct *work) .aborted = false, }; - mutex_lock(&wil->p2p_wdev_mutex); - if (wil->scan_request) { - cfg80211_scan_done(wil->scan_request, &info); - wil->scan_request = NULL; - wil->radio_wdev = wil->wdev; + mutex_lock(&wil->vif_mutex); + if (vif->scan_request) { + cfg80211_scan_done(vif->scan_request, &info); + vif->scan_request = NULL; + if (vif->mid == 0) + wil->radio_wdev = + wil->main_ndev->ieee80211_ptr; } - mutex_unlock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->vif_mutex); } } @@ -300,8 +303,9 @@ void wil_p2p_delayed_listen_work(struct work_struct *work) { struct wil_p2p_info *p2p = container_of(work, struct wil_p2p_info, delayed_listen_work); - struct wil6210_priv *wil = container_of(p2p, - struct wil6210_priv, p2p); + struct wil6210_vif *vif = container_of(p2p, + struct wil6210_vif, p2p); + struct wil6210_priv *wil = vif_to_wil(vif); int rc; mutex_lock(&wil->mutex); @@ -310,31 +314,33 @@ void wil_p2p_delayed_listen_work(struct work_struct *work) if (!p2p->discovery_started || !p2p->pending_listen_wdev) goto out; - mutex_lock(&wil->p2p_wdev_mutex); - if (wil->scan_request) { + mutex_lock(&wil->vif_mutex); + if (vif->scan_request) { /* another scan started, wait again... */ - mutex_unlock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->vif_mutex); goto out; } - mutex_unlock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->vif_mutex); - rc = wil_p2p_start_listen(wil); + rc = wil_p2p_start_listen(vif); - mutex_lock(&wil->p2p_wdev_mutex); + mutex_lock(&wil->vif_mutex); if (rc) { cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev, p2p->cookie, &p2p->listen_chan, GFP_KERNEL); - wil->radio_wdev = wil->wdev; + if (vif->mid == 0) + wil->radio_wdev = wil->main_ndev->ieee80211_ptr; } else { cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie, &p2p->listen_chan, p2p->listen_duration, GFP_KERNEL); - wil->radio_wdev = p2p->pending_listen_wdev; + if (vif->mid == 0) + wil->radio_wdev = p2p->pending_listen_wdev; } p2p->pending_listen_wdev = NULL; - mutex_unlock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->vif_mutex); out: mutex_unlock(&wil->mutex); @@ -342,34 +348,35 @@ out: void wil_p2p_stop_radio_operations(struct wil6210_priv *wil) { - struct wil_p2p_info *p2p = &wil->p2p; + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); + struct wil_p2p_info *p2p = &vif->p2p; struct cfg80211_scan_info info = { .aborted = true, }; lockdep_assert_held(&wil->mutex); - lockdep_assert_held(&wil->p2p_wdev_mutex); + lockdep_assert_held(&wil->vif_mutex); if (wil->radio_wdev != wil->p2p_wdev) goto out; if (!p2p->discovery_started) { /* Regular scan on the p2p device */ - if (wil->scan_request && - wil->scan_request->wdev == wil->p2p_wdev) - wil_abort_scan(wil, true); + if (vif->scan_request && + vif->scan_request->wdev == wil->p2p_wdev) + wil_abort_scan(vif, true); goto out; } /* Search or listen on p2p device */ - mutex_unlock(&wil->p2p_wdev_mutex); - wil_p2p_stop_discovery(wil); - mutex_lock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->vif_mutex); + wil_p2p_stop_discovery(vif); + mutex_lock(&wil->vif_mutex); - if (wil->scan_request) { + if (vif->scan_request) { /* search */ - cfg80211_scan_done(wil->scan_request, &info); - wil->scan_request = NULL; + cfg80211_scan_done(vif->scan_request, &info); + vif->scan_request = NULL; } else { /* listen */ cfg80211_remain_on_channel_expired(wil->radio_wdev, @@ -379,5 +386,5 @@ void wil_p2p_stop_radio_operations(struct wil6210_priv *wil) } out: - wil->radio_wdev = wil->wdev; + wil->radio_wdev = wil->main_ndev->ieee80211_ptr; } diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 809092a49192..19cbc6add637 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -137,6 +137,20 @@ void wil_enable_irq(struct wil6210_priv *wil) enable_irq(wil->pdev->irq); } +static void wil_remove_all_additional_vifs(struct wil6210_priv *wil) +{ + struct wil6210_vif *vif; + int i; + + for (i = 1; i < wil->max_vifs; i++) { + vif = wil->vifs[i]; + if (vif) { + wil_vif_prepare_stop(vif); + wil_vif_remove(wil, vif->mid); + } + } +} + /* Bus ops */ static int wil_if_pcie_enable(struct wil6210_priv *wil) { @@ -148,10 +162,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) */ int msi_only = pdev->msi_enabled; bool _use_msi = use_msi; - bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY, - wil->fw_capabilities); - wil_dbg_misc(wil, "if_pcie_enable, wmi_only %d\n", wmi_only); + wil_dbg_misc(wil, "if_pcie_enable\n"); pci_set_master(pdev); @@ -172,11 +184,9 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) if (rc) goto stop_master; - /* need reset here to obtain MAC or in case of WMI-only FW, full reset - * and fw loading takes place - */ + /* need reset here to obtain MAC */ mutex_lock(&wil->mutex); - rc = wil_reset(wil, wmi_only); + rc = wil_reset(wil, false); mutex_unlock(&wil->mutex); if (rc) goto release_irq; @@ -356,6 +366,18 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto bus_disable; } + /* in case of WMI-only FW, perform full reset and FW loading */ + if (test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) { + wil_dbg_misc(wil, "Loading WMI only FW\n"); + mutex_lock(&wil->mutex); + rc = wil_reset(wil, true); + mutex_unlock(&wil->mutex); + if (rc) { + wil_err(wil, "failed to load WMI only FW\n"); + goto if_remove; + } + } + if (IS_ENABLED(CONFIG_PM)) wil->pm_notify.notifier_call = wil6210_pm_notify; @@ -372,6 +394,8 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; +if_remove: + wil_if_remove(wil); bus_disable: wil_if_pcie_disable(wil); err_iounmap: @@ -402,6 +426,7 @@ static void wil_pcie_remove(struct pci_dev *pdev) wil6210_debugfs_remove(wil); rtnl_lock(); wil_p2p_wdev_free(wil); + wil_remove_all_additional_vifs(wil); rtnl_unlock(); wil_if_remove(wil); wil_if_pcie_disable(wil); @@ -425,12 +450,15 @@ static int wil6210_suspend(struct device *dev, bool is_runtime) int rc = 0; struct pci_dev *pdev = to_pci_dev(dev); struct wil6210_priv *wil = pci_get_drvdata(pdev); - struct net_device *ndev = wil_to_ndev(wil); - bool keep_radio_on = ndev->flags & IFF_UP && - wil->keep_radio_on_during_sleep; + bool keep_radio_on, active_ifaces; wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); + mutex_lock(&wil->vif_mutex); + active_ifaces = wil_has_active_ifaces(wil, true, false); + mutex_unlock(&wil->vif_mutex); + keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep; + rc = wil_can_suspend(wil, is_runtime); if (rc) goto out; @@ -457,12 +485,15 @@ static int wil6210_resume(struct device *dev, bool is_runtime) int rc = 0; struct pci_dev *pdev = to_pci_dev(dev); struct wil6210_priv *wil = pci_get_drvdata(pdev); - struct net_device *ndev = wil_to_ndev(wil); - bool keep_radio_on = ndev->flags & IFF_UP && - wil->keep_radio_on_during_sleep; + bool keep_radio_on, active_ifaces; wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); + mutex_lock(&wil->vif_mutex); + active_ifaces = wil_has_active_ifaces(wil, true, false); + mutex_unlock(&wil->vif_mutex); + keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep; + /* In case radio stays on, platform device will control * PCIe master */ diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 0a96518a566f..ba81fb3ac96f 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014,2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,13 +21,72 @@ #define WIL6210_AUTOSUSPEND_DELAY_MS (1000) +static void wil_pm_wake_connected_net_queues(struct wil6210_priv *wil) +{ + int i; + + mutex_lock(&wil->vif_mutex); + for (i = 0; i < wil->max_vifs; i++) { + struct wil6210_vif *vif = wil->vifs[i]; + + if (vif && test_bit(wil_vif_fwconnected, vif->status)) + wil_update_net_queues_bh(wil, vif, NULL, false); + } + mutex_unlock(&wil->vif_mutex); +} + +static void wil_pm_stop_all_net_queues(struct wil6210_priv *wil) +{ + int i; + + mutex_lock(&wil->vif_mutex); + for (i = 0; i < wil->max_vifs; i++) { + struct wil6210_vif *vif = wil->vifs[i]; + + if (vif) + wil_update_net_queues_bh(wil, vif, NULL, true); + } + mutex_unlock(&wil->vif_mutex); +} + +static bool +wil_can_suspend_vif(struct wil6210_priv *wil, struct wil6210_vif *vif, + bool is_runtime) +{ + struct wireless_dev *wdev = vif_to_wdev(vif); + + switch (wdev->iftype) { + case NL80211_IFTYPE_MONITOR: + wil_dbg_pm(wil, "Sniffer\n"); + return false; + + /* for STA-like interface, don't runtime suspend */ + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + if (test_bit(wil_vif_fwconnecting, vif->status)) { + wil_dbg_pm(wil, "Delay suspend when connecting\n"); + return false; + } + if (is_runtime) { + wil_dbg_pm(wil, "STA-like interface\n"); + return false; + } + break; + /* AP-like interface - can't suspend */ + default: + wil_dbg_pm(wil, "AP-like interface\n"); + return false; + } + + return true; +} + int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) { - int rc = 0; - struct wireless_dev *wdev = wil->wdev; - struct net_device *ndev = wil_to_ndev(wil); + int rc = 0, i; bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities); + bool active_ifaces; wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system"); @@ -40,7 +100,12 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) rc = -EBUSY; goto out; } - if (!(ndev->flags & IFF_UP)) { + + mutex_lock(&wil->vif_mutex); + active_ifaces = wil_has_active_ifaces(wil, true, false); + mutex_unlock(&wil->vif_mutex); + + if (!active_ifaces) { /* can always sleep when down */ wil_dbg_pm(wil, "Interface is down\n"); goto out; @@ -57,32 +122,19 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) } /* interface is running */ - switch (wdev->iftype) { - case NL80211_IFTYPE_MONITOR: - wil_dbg_pm(wil, "Sniffer\n"); - rc = -EBUSY; - goto out; - /* for STA-like interface, don't runtime suspend */ - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_P2P_CLIENT: - if (test_bit(wil_status_fwconnecting, wil->status)) { - wil_dbg_pm(wil, "Delay suspend when connecting\n"); - rc = -EBUSY; - goto out; - } - /* Runtime pm not supported in case the interface is up */ - if (is_runtime) { - wil_dbg_pm(wil, "STA-like interface\n"); + mutex_lock(&wil->vif_mutex); + for (i = 0; i < wil->max_vifs; i++) { + struct wil6210_vif *vif = wil->vifs[i]; + + if (!vif) + continue; + if (!wil_can_suspend_vif(wil, vif, is_runtime)) { rc = -EBUSY; + mutex_unlock(&wil->vif_mutex); goto out; } - break; - /* AP-like interface - can't suspend */ - default: - wil_dbg_pm(wil, "AP-like interface\n"); - rc = -EBUSY; - break; } + mutex_unlock(&wil->vif_mutex); out: wil_dbg_pm(wil, "can_suspend: %s => %s (%d)\n", @@ -127,8 +179,7 @@ static int wil_resume_keep_radio_on(struct wil6210_priv *wil) } /* Wake all queues */ - if (test_bit(wil_status_fwconnected, wil->status)) - wil_update_net_queues_bh(wil, NULL, false); + wil_pm_wake_connected_net_queues(wil); out: if (rc) @@ -152,7 +203,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) wil->suspend_stats.rejected_by_host++; return -EBUSY; } - wil_update_net_queues_bh(wil, NULL, true); + wil_pm_stop_all_net_queues(wil); if (!wil_is_tx_idle(wil)) { wil_dbg_pm(wil, "Pending TX data, reject suspend\n"); @@ -243,22 +294,20 @@ resume_after_fail: /* if resume succeeded, reject the suspend */ if (!rc) { rc = -EBUSY; - if (test_bit(wil_status_fwconnected, wil->status)) - wil_update_net_queues_bh(wil, NULL, false); + wil_pm_wake_connected_net_queues(wil); } return rc; reject_suspend: clear_bit(wil_status_suspending, wil->status); - if (test_bit(wil_status_fwconnected, wil->status)) - wil_update_net_queues_bh(wil, NULL, false); + wil_pm_wake_connected_net_queues(wil); return -EBUSY; } static int wil_suspend_radio_off(struct wil6210_priv *wil) { int rc = 0; - struct net_device *ndev = wil_to_ndev(wil); + bool active_ifaces; wil_dbg_pm(wil, "suspend radio off\n"); @@ -272,7 +321,11 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil) } /* if netif up, hardware is alive, shut it down */ - if (ndev->flags & IFF_UP) { + mutex_lock(&wil->vif_mutex); + active_ifaces = wil_has_active_ifaces(wil, true, false); + mutex_unlock(&wil->vif_mutex); + + if (active_ifaces) { rc = wil_down(wil); if (rc) { wil_err(wil, "wil_down : %d\n", rc); @@ -306,16 +359,19 @@ out: static int wil_resume_radio_off(struct wil6210_priv *wil) { int rc = 0; - struct net_device *ndev = wil_to_ndev(wil); + bool active_ifaces; wil_dbg_pm(wil, "Enabling PCIe IRQ\n"); wil_enable_irq(wil); - /* if netif up, bring hardware up + /* if any netif up, bring hardware up * During open(), IFF_UP set after actual device method * invocation. This prevent recursive call to wil_up() * wil_status_suspended will be cleared in wil_reset */ - if (ndev->flags & IFF_UP) + mutex_lock(&wil->vif_mutex); + active_ifaces = wil_has_active_ifaces(wil, true, false); + mutex_unlock(&wil->vif_mutex); + if (active_ifaces) rc = wil_up(wil); else clear_bit(wil_status_suspended, wil->status); diff --git a/drivers/net/wireless/ath/wil6210/pmc.c b/drivers/net/wireless/ath/wil6210/pmc.c index 4ea27b0bd278..c49f7988369e 100644 --- a/drivers/net/wireless/ath/wil6210/pmc.c +++ b/drivers/net/wireless/ath/wil6210/pmc.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2015,2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -53,6 +54,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil, u32 i; struct pmc_ctx *pmc = &wil->pmc; struct device *dev = wil_to_dev(wil); + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); struct wmi_pmc_cmd pmc_cmd = {0}; int last_cmd_err = -ENOMEM; @@ -186,6 +188,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil, wil_dbg_misc(wil, "pmc_alloc: send WMI_PMC_CMD with ALLOCATE op\n"); pmc->last_cmd_status = wmi_send(wil, WMI_PMC_CMDID, + vif->mid, &pmc_cmd, sizeof(pmc_cmd)); if (pmc->last_cmd_status) { @@ -236,6 +239,7 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd) { struct pmc_ctx *pmc = &wil->pmc; struct device *dev = wil_to_dev(wil); + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); struct wmi_pmc_cmd pmc_cmd = {0}; mutex_lock(&pmc->lock); @@ -254,8 +258,8 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd) wil_dbg_misc(wil, "send WMI_PMC_CMD with RELEASE op\n"); pmc_cmd.op = WMI_PMC_RELEASE; pmc->last_cmd_status = - wmi_send(wil, WMI_PMC_CMDID, &pmc_cmd, - sizeof(pmc_cmd)); + wmi_send(wil, WMI_PMC_CMDID, vif->mid, + &pmc_cmd, sizeof(pmc_cmd)); if (pmc->last_cmd_status) { wil_err(wil, "WMI_PMC_CMD with RELEASE op failed, status %d", diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c index a43cffcf1bbf..14dcb0698dee 100644 --- a/drivers/net/wireless/ath/wil6210/rx_reorder.c +++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -40,11 +41,10 @@ static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq) return seq_sub(seq, r->ssn) % r->buf_size; } -static void wil_release_reorder_frame(struct wil6210_priv *wil, +static void wil_release_reorder_frame(struct net_device *ndev, struct wil_tid_ampdu_rx *r, int index) { - struct net_device *ndev = wil_to_ndev(wil); struct sk_buff *skb = r->reorder_buf[index]; if (!skb) @@ -59,7 +59,7 @@ no_frame: r->head_seq_num = seq_inc(r->head_seq_num); } -static void wil_release_reorder_frames(struct wil6210_priv *wil, +static void wil_release_reorder_frames(struct net_device *ndev, struct wil_tid_ampdu_rx *r, u16 hseq) { @@ -73,18 +73,18 @@ static void wil_release_reorder_frames(struct wil6210_priv *wil, */ while (seq_less(r->head_seq_num, hseq) && r->stored_mpdu_num) { index = reorder_index(r, r->head_seq_num); - wil_release_reorder_frame(wil, r, index); + wil_release_reorder_frame(ndev, r, index); } r->head_seq_num = hseq; } -static void wil_reorder_release(struct wil6210_priv *wil, +static void wil_reorder_release(struct net_device *ndev, struct wil_tid_ampdu_rx *r) { int index = reorder_index(r, r->head_seq_num); while (r->reorder_buf[index]) { - wil_release_reorder_frame(wil, r, index); + wil_release_reorder_frame(ndev, r, index); index = reorder_index(r, r->head_seq_num); } } @@ -93,7 +93,8 @@ static void wil_reorder_release(struct wil6210_priv *wil, void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { - struct net_device *ndev = wil_to_ndev(wil); + struct wil6210_vif *vif; + struct net_device *ndev; struct vring_rx_desc *d = wil_skb_rxdesc(skb); int tid = wil_rxdesc_tid(d); int cid = wil_rxdesc_cid(d); @@ -108,6 +109,14 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n", mid, cid, tid, seq, mcast); + vif = wil->vifs[mid]; + if (unlikely(!vif)) { + wil_dbg_txrx(wil, "invalid VIF, mid %d\n", mid); + dev_kfree_skb(skb); + return; + } + ndev = vif_to_ndev(vif); + if (unlikely(mcast)) { wil_netif_rx_any(skb, ndev); return; @@ -168,7 +177,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) if (!seq_less(seq, r->head_seq_num + r->buf_size)) { hseq = seq_inc(seq_sub(seq, r->buf_size)); /* release stored frames up to new head to stack */ - wil_release_reorder_frames(wil, r, hseq); + wil_release_reorder_frames(ndev, r, hseq); } /* Now the new frame is always in the range of the reordering buffer */ @@ -199,16 +208,18 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) r->reorder_buf[index] = skb; r->reorder_time[index] = jiffies; r->stored_mpdu_num++; - wil_reorder_release(wil, r); + wil_reorder_release(ndev, r); out: spin_unlock(&sta->tid_rx_lock); } /* process BAR frame, called in NAPI context */ -void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq) +void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif, + u8 cid, u8 tid, u16 seq) { struct wil_sta_info *sta = &wil->sta[cid]; + struct net_device *ndev = vif_to_ndev(vif); struct wil_tid_ampdu_rx *r; spin_lock(&sta->tid_rx_lock); @@ -223,9 +234,9 @@ void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq) seq, r->head_seq_num); goto out; } - wil_dbg_txrx(wil, "BAR: CID %d TID %d Seq 0x%03x head 0x%03x\n", - cid, tid, seq, r->head_seq_num); - wil_release_reorder_frames(wil, r, seq); + wil_dbg_txrx(wil, "BAR: CID %d MID %d TID %d Seq 0x%03x head 0x%03x\n", + cid, vif->mid, tid, seq, r->head_seq_num); + wil_release_reorder_frames(ndev, r, seq); out: spin_unlock(&sta->tid_rx_lock); @@ -292,8 +303,8 @@ static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize) } /* Block Ack - Rx side (recipient) */ -int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, - u8 dialog_token, __le16 ba_param_set, +int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid, + u8 cidxtid, u8 dialog_token, __le16 ba_param_set, __le16 ba_timeout, __le16 ba_seq_ctrl) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { @@ -354,7 +365,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) } } - rc = wmi_addba_rx_resp(wil, cid, tid, dialog_token, status, + rc = wmi_addba_rx_resp(wil, mid, cid, tid, dialog_token, status, agg_amsdu, agg_wsize, agg_timeout); if (rc || (status != WLAN_STATUS_SUCCESS)) { wil_err(wil, "do not apply ba, rc(%d), status(%d)\n", rc, @@ -393,7 +404,7 @@ int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize) goto out; } txdata->addba_in_progress = true; - rc = wmi_addba(wil, ringid, agg_wsize, agg_timeout); + rc = wmi_addba(wil, txdata->mid, ringid, agg_wsize, agg_timeout); if (rc) { wil_err(wil, "wmi_addba failed, rc (%d)", rc); txdata->addba_in_progress = false; diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 16b8a4e5201f..b60b9fcaaebd 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2017 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -474,7 +475,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, struct vring *vring) { struct device *dev = wil_to_dev(wil); - struct net_device *ndev = wil_to_ndev(wil); + struct wil6210_vif *vif; + struct net_device *ndev; volatile struct vring_rx_desc *_d; struct vring_rx_desc *d; struct sk_buff *skb; @@ -483,7 +485,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, unsigned int sz = wil->rx_buf_len + ETH_HLEN + snaplen; u16 dmalen; u8 ftype; - int cid; + int cid, mid; int i; struct wil_net_stats *stats; @@ -520,6 +522,16 @@ again: (const void *)d, sizeof(*d), false); cid = wil_rxdesc_cid(d); + mid = wil_rxdesc_mid(d); + vif = wil->vifs[mid]; + + if (unlikely(!vif)) { + wil_dbg_txrx(wil, "skipped RX descriptor with invalid mid %d", + mid); + kfree_skb(skb); + goto again; + } + ndev = vif_to_ndev(vif); stats = &wil->sta[cid].stats; if (unlikely(dmalen > sz)) { @@ -553,7 +565,6 @@ again: ftype = wil_rxdesc_ftype(d) << 2; if (unlikely(ftype != IEEE80211_FTYPE_DATA)) { u8 fc1 = wil_rxdesc_fc1(d); - int mid = wil_rxdesc_mid(d); int tid = wil_rxdesc_tid(d); u16 seq = wil_rxdesc_seq(d); @@ -565,7 +576,7 @@ again: wil_dbg_txrx(wil, "BAR: MID %d CID %d TID %d Seq 0x%03x\n", mid, cid, tid, seq); - wil_rx_bar(wil, cid, tid, seq); + wil_rx_bar(wil, vif, cid, tid, seq); } else { /* print again all info. One can enable only this * without overhead for printing every Rx frame @@ -621,10 +632,15 @@ again: /** * allocate and fill up to @count buffers in rx ring * buffers posted at @swtail + * Note: we have a single RX queue for servicing all VIFs, but we + * allocate skbs with headroom according to main interface only. This + * means it will not work with monitor interface together with other VIFs. + * Currently we only support monitor interface on its own without other VIFs, + * and we will need to fix this code once we add support. */ static int wil_rx_refill(struct wil6210_priv *wil, int count) { - struct net_device *ndev = wil_to_ndev(wil); + struct net_device *ndev = wil->main_ndev; struct vring *v = &wil->vring_rx; u32 next_tail; int rc = 0; @@ -713,8 +729,9 @@ static int wil_rx_crypto_check(struct wil6210_priv *wil, struct sk_buff *skb) void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) { gro_result_t rc = GRO_NORMAL; + struct wil6210_vif *vif = ndev_to_vif(ndev); struct wil6210_priv *wil = ndev_to_wil(ndev); - struct wireless_dev *wdev = wil_to_wdev(wil); + struct wireless_dev *wdev = vif_to_wdev(vif); unsigned int len = skb->len; struct vring_rx_desc *d = wil_skb_rxdesc(skb); int cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */ @@ -751,14 +768,15 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) goto stats; } - if (wdev->iftype == NL80211_IFTYPE_AP && !wil->ap_isolate) { + if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) { if (mcast) { /* send multicast frames both to higher layers in * local net stack and back to the wireless medium */ xmit_skb = skb_copy(skb, GFP_ATOMIC); } else { - int xmit_cid = wil_find_cid(wil, eth->h_dest); + int xmit_cid = wil_find_cid(wil, vif->mid, + eth->h_dest); if (xmit_cid >= 0) { /* The destination station is associated to @@ -786,8 +804,8 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev) } if (skb) { /* deliver to local stack */ - skb->protocol = eth_type_trans(skb, ndev); + skb->dev = ndev; rc = napi_gro_receive(&wil->napi_rx, skb); wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n", len, gro_res_str[rc]); @@ -815,7 +833,8 @@ stats: */ void wil_rx_handle(struct wil6210_priv *wil, int *quota) { - struct net_device *ndev = wil_to_ndev(wil); + struct net_device *ndev = wil->main_ndev; + struct wireless_dev *wdev = ndev->ieee80211_ptr; struct vring *v = &wil->vring_rx; struct sk_buff *skb; @@ -827,7 +846,8 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota) while ((*quota > 0) && (NULL != (skb = wil_vring_reap_rx(wil, v)))) { (*quota)--; - if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { + /* monitor is currently supported on main interface only */ + if (wdev->iftype == NL80211_IFTYPE_MONITOR) { skb->dev = ndev; skb_reset_mac_header(skb); skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -911,12 +931,14 @@ static inline void wil_tx_data_init(struct vring_tx_data *txdata) txdata->agg_timeout = 0; txdata->agg_amsdu = 0; txdata->addba_in_progress = false; + txdata->mid = U8_MAX; spin_unlock_bh(&txdata->lock); } -int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, +int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, int cid, int tid) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; struct wmi_vring_cfg_cmd cmd = { .action = cpu_to_le32(WMI_VRING_CMD_ADD), @@ -966,9 +988,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); - if (!wil->privacy) + if (!vif->privacy) txdata->dot1x_open = true; - rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100); if (rc) goto out_free; @@ -982,6 +1004,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, spin_lock_bh(&txdata->lock); vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); + txdata->mid = vif->mid; txdata->enabled = 1; spin_unlock_bh(&txdata->lock); @@ -1003,8 +1026,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, return rc; } -int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size) +int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; struct wmi_bcast_vring_cfg_cmd cmd = { .action = cpu_to_le32(WMI_VRING_CMD_ADD), @@ -1046,9 +1070,10 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size) cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa); - if (!wil->privacy) + if (!vif->privacy) txdata->dot1x_open = true; - rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, vif->mid, + &cmd, sizeof(cmd), WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100); if (rc) goto out_free; @@ -1062,6 +1087,7 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size) spin_lock_bh(&txdata->lock); vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); + txdata->mid = vif->mid; txdata->enabled = 1; spin_unlock_bh(&txdata->lock); @@ -1091,6 +1117,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) spin_lock_bh(&txdata->lock); txdata->dot1x_open = false; + txdata->mid = U8_MAX; txdata->enabled = 0; /* no Tx can be in progress or start anew */ spin_unlock_bh(&txdata->lock); /* napi_synchronize waits for completion of the current NAPI but will @@ -1108,11 +1135,12 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id) } static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil, + struct wil6210_vif *vif, struct sk_buff *skb) { int i; struct ethhdr *eth = (void *)skb->data; - int cid = wil_find_cid(wil, eth->h_dest); + int cid = wil_find_cid(wil, vif->mid, eth->h_dest); if (cid < 0) return NULL; @@ -1142,10 +1170,11 @@ static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil, return NULL; } -static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, - struct sk_buff *skb); +static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, + struct vring *vring, struct sk_buff *skb); static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil, + struct wil6210_vif *vif, struct sk_buff *skb) { struct vring *v; @@ -1160,7 +1189,7 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil, for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { v = &wil->vring_tx[i]; txdata = &wil->vring_tx_data[i]; - if (!v->va || !txdata->enabled) + if (!v->va || !txdata->enabled || txdata->mid != vif->mid) continue; cid = wil->vring2cid_tid[i][0]; @@ -1193,11 +1222,12 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil, * - for PBSS */ static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil, + struct wil6210_vif *vif, struct sk_buff *skb) { struct vring *v; struct vring_tx_data *txdata; - int i = wil->bcast_vring; + int i = vif->bcast_vring; if (i < 0) return NULL; @@ -1222,6 +1252,7 @@ static void wil_set_da_for_vring(struct wil6210_priv *wil, } static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil, + struct wil6210_vif *vif, struct sk_buff *skb) { struct vring *v, *v2; @@ -1230,13 +1261,13 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil, u8 cid; struct ethhdr *eth = (void *)skb->data; char *src = eth->h_source; - struct vring_tx_data *txdata; + struct vring_tx_data *txdata, *txdata2; /* find 1-st vring eligible for data */ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { v = &wil->vring_tx[i]; txdata = &wil->vring_tx_data[i]; - if (!v->va || !txdata->enabled) + if (!v->va || !txdata->enabled || txdata->mid != vif->mid) continue; cid = wil->vring2cid_tid[i][0]; @@ -1264,7 +1295,8 @@ found: /* find other active vrings and duplicate skb for each */ for (i++; i < WIL6210_MAX_TX_RINGS; i++) { v2 = &wil->vring_tx[i]; - if (!v2->va) + txdata2 = &wil->vring_tx_data[i]; + if (!v2->va || txdata2->mid != vif->mid) continue; cid = wil->vring2cid_tid[i][0]; if (cid >= WIL6210_MAX_CID) /* skip BCAST */ @@ -1280,7 +1312,7 @@ found: if (skb2) { wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i); wil_set_da_for_vring(wil, skb2, i); - wil_tx_vring(wil, v2, skb2); + wil_tx_vring(wil, vif, v2, skb2); } else { wil_err(wil, "skb_copy failed\n"); } @@ -1417,8 +1449,8 @@ static inline void wil_set_tx_desc_last_tso(volatile struct vring_tx_desc *d) DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS; } -static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring, - struct sk_buff *skb) +static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif, + struct vring *vring, struct sk_buff *skb) { struct device *dev = wil_to_dev(wil); @@ -1710,8 +1742,8 @@ err_exit: return rc; } -static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, - struct sk_buff *skb) +static int __wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, + struct vring *vring, struct sk_buff *skb) { struct device *dev = wil_to_dev(wil); struct vring_tx_desc dd, *d = ⅆ @@ -1725,7 +1757,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, uint i = swhead; dma_addr_t pa; int used; - bool mcast = (vring_index == wil->bcast_vring); + bool mcast = (vring_index == vif->bcast_vring); uint len = skb_headlen(skb); wil_dbg_txrx(wil, "tx_vring: %d bytes to vring %d\n", skb->len, @@ -1860,8 +1892,8 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, return -EINVAL; } -static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, - struct sk_buff *skb) +static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif, + struct vring *vring, struct sk_buff *skb) { int vring_index = vring - wil->vring_tx; struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; @@ -1879,7 +1911,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, } rc = (skb_is_gso(skb) ? __wil_tx_vring_tso : __wil_tx_vring) - (wil, vring, skb); + (wil, vif, vring, skb); spin_unlock(&txdata->lock); @@ -1888,6 +1920,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, /** * Check status of tx vrings and stop/wake net queues if needed + * It will start/stop net queues of a specific VIF net_device. * * This function does one of two checks: * In case check_stop is true, will check if net queues need to be stopped. If @@ -1903,28 +1936,32 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, * availability and modified vring has high descriptor availability. */ static inline void __wil_update_net_queues(struct wil6210_priv *wil, + struct wil6210_vif *vif, struct vring *vring, bool check_stop) { int i; + if (unlikely(!vif)) + return; + if (vring) - wil_dbg_txrx(wil, "vring %d, check_stop=%d, stopped=%d", - (int)(vring - wil->vring_tx), check_stop, - wil->net_queue_stopped); + wil_dbg_txrx(wil, "vring %d, mid %d, check_stop=%d, stopped=%d", + (int)(vring - wil->vring_tx), vif->mid, check_stop, + vif->net_queue_stopped); else - wil_dbg_txrx(wil, "check_stop=%d, stopped=%d", - check_stop, wil->net_queue_stopped); + wil_dbg_txrx(wil, "check_stop=%d, mid=%d, stopped=%d", + check_stop, vif->mid, vif->net_queue_stopped); - if (check_stop == wil->net_queue_stopped) + if (check_stop == vif->net_queue_stopped) /* net queues already in desired state */ return; if (check_stop) { if (!vring || unlikely(wil_vring_avail_low(vring))) { /* not enough room in the vring */ - netif_tx_stop_all_queues(wil_to_ndev(wil)); - wil->net_queue_stopped = true; + netif_tx_stop_all_queues(vif_to_ndev(vif)); + vif->net_queue_stopped = true; wil_dbg_txrx(wil, "netif_tx_stop called\n"); } return; @@ -1940,7 +1977,8 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil, struct vring *cur_vring = &wil->vring_tx[i]; struct vring_tx_data *txdata = &wil->vring_tx_data[i]; - if (!cur_vring->va || !txdata->enabled || cur_vring == vring) + if (txdata->mid != vif->mid || !cur_vring->va || + !txdata->enabled || cur_vring == vring) continue; if (wil_vring_avail_low(cur_vring)) { @@ -1953,30 +1991,31 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil, if (!vring || wil_vring_avail_high(vring)) { /* enough room in the vring */ wil_dbg_txrx(wil, "calling netif_tx_wake\n"); - netif_tx_wake_all_queues(wil_to_ndev(wil)); - wil->net_queue_stopped = false; + netif_tx_wake_all_queues(vif_to_ndev(vif)); + vif->net_queue_stopped = false; } } -void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring, - bool check_stop) +void wil_update_net_queues(struct wil6210_priv *wil, struct wil6210_vif *vif, + struct vring *vring, bool check_stop) { spin_lock(&wil->net_queue_lock); - __wil_update_net_queues(wil, vring, check_stop); + __wil_update_net_queues(wil, vif, vring, check_stop); spin_unlock(&wil->net_queue_lock); } -void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring, - bool check_stop) +void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif, + struct vring *vring, bool check_stop) { spin_lock_bh(&wil->net_queue_lock); - __wil_update_net_queues(wil, vring, check_stop); + __wil_update_net_queues(wil, vif, vring, check_stop); spin_unlock_bh(&wil->net_queue_lock); } netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) { - struct wil6210_priv *wil = ndev_to_wil(ndev); + struct wil6210_vif *vif = ndev_to_vif(ndev); + struct wil6210_priv *wil = vif_to_wil(vif); struct ethhdr *eth = (void *)skb->data; bool bcast = is_multicast_ether_addr(eth->h_dest); struct vring *vring; @@ -1991,49 +2030,50 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) } goto drop; } - if (unlikely(!test_bit(wil_status_fwconnected, wil->status))) { - wil_dbg_ratelimited(wil, "FW not connected, packet dropped\n"); + if (unlikely(!test_bit(wil_vif_fwconnected, vif->status))) { + wil_dbg_ratelimited(wil, + "VIF not connected, packet dropped\n"); goto drop; } - if (unlikely(wil->wdev->iftype == NL80211_IFTYPE_MONITOR)) { + if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_MONITOR)) { wil_err(wil, "Xmit in monitor mode not supported\n"); goto drop; } pr_once_fw = false; /* find vring */ - if (wil->wdev->iftype == NL80211_IFTYPE_STATION && !wil->pbss) { + if (vif->wdev.iftype == NL80211_IFTYPE_STATION && !vif->pbss) { /* in STA mode (ESS), all to same VRING (to AP) */ - vring = wil_find_tx_vring_sta(wil, skb); + vring = wil_find_tx_vring_sta(wil, vif, skb); } else if (bcast) { - if (wil->pbss) + if (vif->pbss) /* in pbss, no bcast VRING - duplicate skb in * all stations VRINGs */ - vring = wil_find_tx_bcast_2(wil, skb); - else if (wil->wdev->iftype == NL80211_IFTYPE_AP) + vring = wil_find_tx_bcast_2(wil, vif, skb); + else if (vif->wdev.iftype == NL80211_IFTYPE_AP) /* AP has a dedicated bcast VRING */ - vring = wil_find_tx_bcast_1(wil, skb); + vring = wil_find_tx_bcast_1(wil, vif, skb); else /* unexpected combination, fallback to duplicating * the skb in all stations VRINGs */ - vring = wil_find_tx_bcast_2(wil, skb); + vring = wil_find_tx_bcast_2(wil, vif, skb); } else { /* unicast, find specific VRING by dest. address */ - vring = wil_find_tx_ucast(wil, skb); + vring = wil_find_tx_ucast(wil, vif, skb); } if (unlikely(!vring)) { wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest); goto drop; } /* set up vring entry */ - rc = wil_tx_vring(wil, vring, skb); + rc = wil_tx_vring(wil, vif, vring, skb); switch (rc) { case 0: /* shall we stop net queues? */ - wil_update_net_queues_bh(wil, vring, true); + wil_update_net_queues_bh(wil, vif, vring, true); /* statistics will be updated on the tx_complete */ dev_kfree_skb_any(skb); return NETDEV_TX_OK; @@ -2072,9 +2112,10 @@ static inline void wil_consume_skb(struct sk_buff *skb, bool acked) * * Safe to call from IRQ */ -int wil_tx_complete(struct wil6210_priv *wil, int ringid) +int wil_tx_complete(struct wil6210_vif *vif, int ringid) { - struct net_device *ndev = wil_to_ndev(wil); + struct wil6210_priv *wil = vif_to_wil(vif); + struct net_device *ndev = vif_to_ndev(vif); struct device *dev = wil_to_dev(wil); struct vring *vring = &wil->vring_tx[ringid]; struct vring_tx_data *txdata = &wil->vring_tx_data[ringid]; @@ -2184,7 +2225,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid) /* shall we wake net queues? */ if (done) - wil_update_net_queues(wil, vring, false); + wil_update_net_queues(wil, vif, vring, false); return done; } diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h index fcdffaa8251b..5f07717acc2c 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.h +++ b/drivers/net/wireless/ath/wil6210/txrx.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2012-2016 Qualcomm Atheros, Inc. + * Copyright (c) 2018, The Linux Foundation. All rights reserved. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -63,7 +64,9 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr, * [dword 1] * bit 0.. 3 : pkt_mode:4 * bit 4 : pkt_mode_en:1 - * bit 5..14 : reserved0:10 + * bit 5 : mac_id_en:1 + * bit 6..7 : mac_id:2 + * bit 8..14 : reserved0:7 * bit 15 : ack_policy_en:1 * bit 16..19 : dst_index:4 * bit 20 : dst_index_en:1 @@ -132,6 +135,14 @@ struct vring_tx_mac { #define MAC_CFG_DESC_TX_1_PKT_MODE_EN_LEN 1 #define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10 +#define MAC_CFG_DESC_TX_1_MAC_ID_EN_POS 5 +#define MAC_CFG_DESC_TX_1_MAC_ID_EN_LEN 1 +#define MAC_CFG_DESC_TX_1_MAC_ID_EN_MSK 0x20 + +#define MAC_CFG_DESC_TX_1_MAC_ID_POS 6 +#define MAC_CFG_DESC_TX_1_MAC_ID_LEN 2 +#define MAC_CFG_DESC_TX_1_MAC_ID_MSK 0xc0 + #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_POS 15 #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1 #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000 @@ -304,7 +315,7 @@ enum { * bit 0.. 3 : tid:4 The QoS (b3-0) TID Field * bit 4.. 6 : cid:3 The Source index that was found during parsing the TA. * This field is used to define the source of the packet - * bit 7 : reserved:1 + * bit 7 : MAC_id_valid:1, 1 if MAC virtual number is valid. * bit 8.. 9 : mid:2 The MAC virtual number * bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type * (management, data, control and extension) @@ -395,6 +406,7 @@ struct vring_rx_mac { #define RX_DMA_D0_CMD_DMA_EOP BIT(8) #define RX_DMA_D0_CMD_DMA_RT BIT(9) /* always 1 */ #define RX_DMA_D0_CMD_DMA_IT BIT(10) /* interrupt */ +#define RX_MAC_D0_MAC_ID_VALID BIT(7) /* Error field */ #define RX_DMA_ERROR_FCS BIT(0) @@ -451,7 +463,8 @@ static inline int wil_rxdesc_cid(struct vring_rx_desc *d) static inline int wil_rxdesc_mid(struct vring_rx_desc *d) { - return WIL_GET_BITS(d->mac.d0, 8, 9); + return (d->mac.d0 & RX_MAC_D0_MAC_ID_VALID) ? + WIL_GET_BITS(d->mac.d0, 8, 9) : 0; } static inline int wil_rxdesc_ftype(struct vring_rx_desc *d) @@ -517,7 +530,8 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb) void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev); void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb); -void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq); +void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif, + u8 cid, u8 tid, u16 seq); struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, int size, u16 ssn); void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 0df2aada6659..f9c5155025bc 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -26,6 +26,7 @@ #include <linux/types.h> #include "wmi.h" #include "wil_platform.h" +#include "fw.h" extern bool no_fw_recovery; extern unsigned int mtu_max; @@ -49,6 +50,11 @@ extern bool disable_ap_sme; #define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */ #define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */ +/* maximum number of virtual interfaces the driver supports + * (including the main interface) + */ +#define WIL_MAX_VIFS 4 + /** * extract bits [@b0:@b1] (inclusive) from the value @x * it should be @b0 <= @b1, or result is incorrect @@ -463,13 +469,12 @@ struct vring_tx_data { u16 agg_timeout; u8 agg_amsdu; bool addba_in_progress; /* if set, agg_xxx is for request in progress */ + u8 mid; spinlock_t lock; }; enum { /* for wil6210_priv.status */ wil_status_fwready = 0, /* FW operational */ - wil_status_fwconnecting, - wil_status_fwconnected, wil_status_dontscan, wil_status_mbox_ready, /* MBOX structures ready */ wil_status_irqen, /* interrupts enabled - for debug */ @@ -541,7 +546,6 @@ struct wil_tid_crypto_rx { struct wil_p2p_info { struct ieee80211_channel listen_chan; u8 discovery_started; - u8 p2p_dev_started; u64 cookie; struct wireless_dev *pending_listen_wdev; unsigned int listen_duration; @@ -584,6 +588,7 @@ struct wil_net_stats { */ struct wil_sta_info { u8 addr[ETH_ALEN]; + u8 mid; enum wil_sta_status status; struct wil_net_stats stats; /* Rx BACK */ @@ -669,10 +674,44 @@ extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST]; extern u8 led_id; extern u8 led_polarity; +enum wil6210_vif_status { + wil_vif_fwconnecting, + wil_vif_fwconnected, + wil_vif_status_last /* keep last */ +}; + +struct wil6210_vif { + struct wireless_dev wdev; + struct net_device *ndev; + struct wil6210_priv *wil; + u8 mid; + DECLARE_BITMAP(status, wil_vif_status_last); + u32 privacy; /* secure connection? */ + u16 channel; /* relevant in AP mode */ + u8 hidden_ssid; /* relevant in AP mode */ + u32 ap_isolate; /* no intra-BSS communication */ + bool pbss; + int bcast_vring; + struct cfg80211_bss *bss; /* connected bss, relevant in STA mode */ + int locally_generated_disc; /* relevant in STA mode */ + struct timer_list connect_timer; + struct work_struct disconnect_worker; + /* scan */ + struct cfg80211_scan_request *scan_request; + struct timer_list scan_timer; /* detect scan timeout */ + struct wil_p2p_info p2p; + /* keep alive */ + struct list_head probe_client_pending; + struct mutex probe_client_mutex; /* protect @probe_client_pending */ + struct work_struct probe_client_worker; + int net_queue_stopped; /* netif_tx_stop_all_queues invoked */ +}; + struct wil6210_priv { struct pci_dev *pdev; u32 bar_size; - struct wireless_dev *wdev; + struct wiphy *wiphy; + struct net_device *main_ndev; void __iomem *csr; DECLARE_BITMAP(status, wil_status_last); u8 fw_version[ETHTOOL_FWVERS_LEN]; @@ -686,21 +725,18 @@ struct wil6210_priv { DECLARE_BITMAP(hw_capa, hw_capa_last); DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX); DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX); - u8 n_mids; /* number of additional MIDs as reported by FW */ u32 recovery_count; /* num of FW recovery attempts in a short time */ u32 recovery_state; /* FW recovery state machine */ unsigned long last_fw_recovery; /* jiffies of last fw recovery */ wait_queue_head_t wq; /* for all wait_event() use */ + u8 max_vifs; /* maximum number of interfaces, including main */ + struct wil6210_vif *vifs[WIL_MAX_VIFS]; + struct mutex vif_mutex; /* protects access to VIF entries */ + atomic_t connected_vifs; /* profile */ struct cfg80211_chan_def monitor_chandef; u32 monitor_flags; - u32 privacy; /* secure connection? */ - u8 hidden_ssid; /* relevant in AP mode */ - u16 channel; /* relevant in AP mode */ int sinfo_gen; - u32 ap_isolate; /* no intra-BSS communication */ - struct cfg80211_bss *bss; /* connected bss, relevant in STA mode */ - int locally_generated_disc; /* relevant in STA mode */ /* interrupt moderation */ u32 tx_max_burst_duration; u32 tx_interframe_timeout; @@ -715,15 +751,13 @@ struct wil6210_priv { struct completion wmi_call; u16 wmi_seq; u16 reply_id; /**< wait for this WMI event */ + u8 reply_mid; void *reply_buf; u16 reply_size; struct workqueue_struct *wmi_wq; /* for deferred calls */ struct work_struct wmi_event_worker; struct workqueue_struct *wq_service; - struct work_struct disconnect_worker; struct work_struct fw_error_worker; /* for FW error recovery */ - struct timer_list connect_timer; - struct timer_list scan_timer; /* detect scan timeout */ struct list_head pending_wmi_ev; /* * protect pending_wmi_ev @@ -732,13 +766,10 @@ struct wil6210_priv { */ spinlock_t wmi_ev_lock; spinlock_t net_queue_lock; /* guarding stop/wake netif queue */ - int net_queue_stopped; /* netif_tx_stop_all_queues invoked */ struct napi_struct napi_rx; struct napi_struct napi_tx; - /* keep alive */ - struct list_head probe_client_pending; - struct mutex probe_client_mutex; /* protect @probe_client_pending */ - struct work_struct probe_client_worker; + struct net_device napi_ndev; /* dummy net_device serving all VIFs */ + /* DMA related */ struct vring vring_rx; unsigned int rx_buf_len; @@ -746,11 +777,8 @@ struct wil6210_priv { struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS]; u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ struct wil_sta_info sta[WIL6210_MAX_CID]; - int bcast_vring; u32 vring_idle_trsh; /* HW fetches up to 16 descriptors at once */ u32 dma_addr_size; /* indicates dma addr size */ - /* scan */ - struct cfg80211_scan_request *scan_request; struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */ /* statistics */ @@ -770,13 +798,10 @@ struct wil6210_priv { struct pmc_ctx pmc; - bool pbss; - - struct wil_p2p_info p2p; + u8 p2p_dev_started; /* P2P_DEVICE vif */ struct wireless_dev *p2p_wdev; - struct mutex p2p_wdev_mutex; /* protect @p2p_wdev and @scan_request */ struct wireless_dev *radio_wdev; /* High Access Latency Policy voting */ @@ -798,13 +823,35 @@ struct wil6210_priv { u32 iccm_base; }; -#define wil_to_wiphy(i) (i->wdev->wiphy) +#define wil_to_wiphy(i) (i->wiphy) #define wil_to_dev(i) (wiphy_dev(wil_to_wiphy(i))) #define wiphy_to_wil(w) (struct wil6210_priv *)(wiphy_priv(w)) -#define wil_to_wdev(i) (i->wdev) #define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w)) -#define wil_to_ndev(i) (wil_to_wdev(i)->netdev) #define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr)) +#define ndev_to_vif(n) (struct wil6210_vif *)(netdev_priv(n)) +#define vif_to_wil(v) (v->wil) +#define vif_to_ndev(v) (v->ndev) +#define vif_to_wdev(v) (&v->wdev) + +static inline struct wil6210_vif *wdev_to_vif(struct wil6210_priv *wil, + struct wireless_dev *wdev) +{ + /* main interface is shared with P2P device */ + if (wdev == wil->p2p_wdev) + return ndev_to_vif(wil->main_ndev); + else + return container_of(wdev, struct wil6210_vif, wdev); +} + +static inline struct wireless_dev * +vif_to_radio_wdev(struct wil6210_priv *wil, struct wil6210_vif *vif) +{ + /* main interface is shared with P2P device */ + if (vif->mid) + return vif_to_wdev(vif); + else + return wil->radio_wdev; +} __printf(2, 3) void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...); @@ -817,7 +864,7 @@ void __wil_info(struct wil6210_priv *wil, const char *fmt, ...); __printf(2, 3) void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...); #define wil_dbg(wil, fmt, arg...) do { \ - netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \ + netdev_dbg(wil->main_ndev, fmt, ##arg); \ wil_dbg_trace(wil, fmt, ##arg); \ } while (0) @@ -900,9 +947,18 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src, void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src, size_t count); +struct wil6210_vif * +wil_vif_alloc(struct wil6210_priv *wil, const char *name, + unsigned char name_assign_type, enum nl80211_iftype iftype); +void wil_vif_free(struct wil6210_vif *vif); void *wil_if_alloc(struct device *dev); +bool wil_has_other_active_ifaces(struct wil6210_priv *wil, + struct net_device *ndev, bool up, bool ok); +bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok); void wil_if_free(struct wil6210_priv *wil); +int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif); int wil_if_add(struct wil6210_priv *wil); +void wil_vif_remove(struct wil6210_priv *wil, u8 mid); void wil_if_remove(struct wil6210_priv *wil); int wil_priv_init(struct wil6210_priv *wil); void wil_priv_deinit(struct wil6210_priv *wil); @@ -918,7 +974,7 @@ int wil_down(struct wil6210_priv *wil); int __wil_down(struct wil6210_priv *wil); void wil_refresh_fw_capabilities(struct wil6210_priv *wil); void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); -int wil_find_cid(struct wil6210_priv *wil, const u8 *mac); +int wil_find_cid(struct wil6210_priv *wil, u8 mid, const u8 *mac); void wil_set_ethtoolops(struct net_device *ndev); struct fw_map *wil_find_fw_mapping(const char *section); @@ -927,40 +983,45 @@ void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr); void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr); int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, struct wil6210_mbox_hdr *hdr); -int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len); +int wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len); void wmi_recv_cmd(struct wil6210_priv *wil); -int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, +int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len, u16 reply_id, void *reply, u8 reply_size, int to_msec); void wmi_event_worker(struct work_struct *work); void wmi_event_flush(struct wil6210_priv *wil); -int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid); -int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid); +int wmi_set_ssid(struct wil6210_vif *vif, u8 ssid_len, const void *ssid); +int wmi_get_ssid(struct wil6210_vif *vif, u8 *ssid_len, void *ssid); int wmi_set_channel(struct wil6210_priv *wil, int channel); int wmi_get_channel(struct wil6210_priv *wil, int *channel); -int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index, +int wmi_del_cipher_key(struct wil6210_vif *vif, u8 key_index, const void *mac_addr, int key_usage); -int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, +int wmi_add_cipher_key(struct wil6210_vif *vif, u8 key_index, const void *mac_addr, int key_len, const void *key, int key_usage); int wmi_echo(struct wil6210_priv *wil); -int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie); +int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie); int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring); int wmi_rxon(struct wil6210_priv *wil, bool on); int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r); -int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, +int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, u16 reason, bool full_disconnect, bool del_sta); -int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout); -int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason); -int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason); -int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, +int wmi_addba(struct wil6210_priv *wil, u8 mid, + u8 ringid, u8 size, u16 timeout); +int wmi_delba_tx(struct wil6210_priv *wil, u8 mid, u8 ringid, u16 reason); +int wmi_delba_rx(struct wil6210_priv *wil, u8 mid, u8 cidxtid, u16 reason); +int wmi_addba_rx_resp(struct wil6210_priv *wil, + u8 mid, u8 cid, u8 tid, u8 token, u16 status, bool amsdu, u16 agg_wsize, u16 timeout); int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile); int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short); int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short); -int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid); -int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, - u8 dialog_token, __le16 ba_param_set, +int wmi_new_sta(struct wil6210_vif *vif, const u8 *mac, u8 aid); +int wmi_port_allocate(struct wil6210_priv *wil, u8 mid, + const u8 *mac, enum nl80211_iftype iftype); +int wmi_port_delete(struct wil6210_priv *wil, u8 mid); +int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid, + u8 cidxtid, u8 dialog_token, __le16 ba_param_set, __le16 ba_timeout, __le16 ba_seq_ctrl); int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize); @@ -976,28 +1037,31 @@ void wil6210_mask_halp(struct wil6210_priv *wil); /* P2P */ bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request); -void wil_p2p_discovery_timer_fn(struct timer_list *t); -int wil_p2p_search(struct wil6210_priv *wil, +int wil_p2p_search(struct wil6210_vif *vif, struct cfg80211_scan_request *request); int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev, unsigned int duration, struct ieee80211_channel *chan, u64 *cookie); -u8 wil_p2p_stop_discovery(struct wil6210_priv *wil); -int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie); +u8 wil_p2p_stop_discovery(struct wil6210_vif *vif); +int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie); void wil_p2p_listen_expired(struct work_struct *work); void wil_p2p_search_expired(struct work_struct *work); void wil_p2p_stop_radio_operations(struct wil6210_priv *wil); void wil_p2p_delayed_listen_work(struct work_struct *work); /* WMI for P2P */ -int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi); -int wmi_start_listen(struct wil6210_priv *wil); -int wmi_start_search(struct wil6210_priv *wil); -int wmi_stop_discovery(struct wil6210_priv *wil); +int wmi_p2p_cfg(struct wil6210_vif *vif, int channel, int bi); +int wmi_start_listen(struct wil6210_vif *vif); +int wmi_start_search(struct wil6210_vif *vif); +int wmi_stop_discovery(struct wil6210_vif *vif); int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct cfg80211_mgmt_tx_params *params, u64 *cookie); +int wil_cfg80211_iface_combinations_from_fw( + struct wil6210_priv *wil, + const struct wil_fw_record_concurrency *conc); +int wil_vif_prepare_stop(struct wil6210_vif *vif); #if defined(CONFIG_WIL6210_DEBUGFS) int wil6210_debugfs_init(struct wil6210_priv *wil); @@ -1007,44 +1071,47 @@ static inline int wil6210_debugfs_init(struct wil6210_priv *wil) { return 0; } static inline void wil6210_debugfs_remove(struct wil6210_priv *wil) {} #endif -int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid, +int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid, struct station_info *sinfo); -struct wireless_dev *wil_cfg80211_init(struct device *dev); -void wil_wdev_free(struct wil6210_priv *wil); +struct wil6210_priv *wil_cfg80211_init(struct device *dev); +void wil_cfg80211_deinit(struct wil6210_priv *wil); void wil_p2p_wdev_free(struct wil6210_priv *wil); int wmi_set_mac_address(struct wil6210_priv *wil, void *addr); -int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, - u8 chan, u8 hidden_ssid, u8 is_go); -int wmi_pcp_stop(struct wil6210_priv *wil); +int wmi_pcp_start(struct wil6210_vif *vif, int bi, u8 wmi_nettype, u8 chan, + u8 hidden_ssid, u8 is_go); +int wmi_pcp_stop(struct wil6210_vif *vif); int wmi_led_cfg(struct wil6210_priv *wil, bool enable); -int wmi_abort_scan(struct wil6210_priv *wil); -void wil_abort_scan(struct wil6210_priv *wil, bool sync); +int wmi_abort_scan(struct wil6210_vif *vif); +void wil_abort_scan(struct wil6210_vif *vif, bool sync); +void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync); void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps); -void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid, +void wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid, u16 reason_code, bool from_event); -void wil_probe_client_flush(struct wil6210_priv *wil); +void wil_probe_client_flush(struct wil6210_vif *vif); void wil_probe_client_worker(struct work_struct *work); +void wil_disconnect_worker(struct work_struct *work); int wil_rx_init(struct wil6210_priv *wil, u16 size); void wil_rx_fini(struct wil6210_priv *wil); /* TX API */ -int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size, +int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size, int cid, int tid); void wil_vring_fini_tx(struct wil6210_priv *wil, int id); -int wil_tx_init(struct wil6210_priv *wil, int cid); -int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size); -int wil_bcast_init(struct wil6210_priv *wil); -void wil_bcast_fini(struct wil6210_priv *wil); - -void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring, - bool should_stop); -void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring, - bool check_stop); +int wil_tx_init(struct wil6210_vif *vif, int cid); +int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size); +int wil_bcast_init(struct wil6210_vif *vif); +void wil_bcast_fini(struct wil6210_vif *vif); +void wil_bcast_fini_all(struct wil6210_priv *wil); + +void wil_update_net_queues(struct wil6210_priv *wil, struct wil6210_vif *vif, + struct vring *vring, bool should_stop); +void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif, + struct vring *vring, bool check_stop); netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); -int wil_tx_complete(struct wil6210_priv *wil, int ringid); +int wil_tx_complete(struct wil6210_vif *vif, int ringid); void wil6210_unmask_irq_tx(struct wil6210_priv *wil); /* RX API */ diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index b31e2514f8c2..a3dda9a97c1f 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -341,6 +341,10 @@ static const char *cmdid2name(u16 cmdid) return "WMI_GET_PCP_CHANNEL_CMD"; case WMI_P2P_CFG_CMDID: return "WMI_P2P_CFG_CMD"; + case WMI_PORT_ALLOCATE_CMDID: + return "WMI_PORT_ALLOCATE_CMD"; + case WMI_PORT_DELETE_CMDID: + return "WMI_PORT_DELETE_CMD"; case WMI_START_LISTEN_CMDID: return "WMI_START_LISTEN_CMD"; case WMI_START_SEARCH_CMDID: @@ -479,6 +483,10 @@ static const char *eventid2name(u16 eventid) return "WMI_GET_PCP_CHANNEL_EVENT"; case WMI_P2P_CFG_DONE_EVENTID: return "WMI_P2P_CFG_DONE_EVENT"; + case WMI_PORT_ALLOCATED_EVENTID: + return "WMI_PORT_ALLOCATED_EVENT"; + case WMI_PORT_DELETED_EVENTID: + return "WMI_PORT_DELETED_EVENT"; case WMI_LISTEN_STARTED_EVENTID: return "WMI_LISTEN_STARTED_EVENT"; case WMI_SEARCH_STARTED_EVENTID: @@ -516,7 +524,8 @@ static const char *eventid2name(u16 eventid) } } -static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) +static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid, + void *buf, u16 len) { struct { struct wil6210_mbox_hdr hdr; @@ -528,7 +537,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) .len = cpu_to_le16(sizeof(cmd.wmi) + len), }, .wmi = { - .mid = 0, + .mid = mid, .command_id = cpu_to_le16(cmdid), }, }; @@ -612,8 +621,8 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) } cmd.hdr.seq = cpu_to_le16(++wil->wmi_seq); /* set command */ - wil_dbg_wmi(wil, "sending %s (0x%04x) [%d]\n", - cmdid2name(cmdid), cmdid, len); + wil_dbg_wmi(wil, "sending %s (0x%04x) [%d] mid %d\n", + cmdid2name(cmdid), cmdid, len, mid); wil_hex_dump_wmi("Cmd ", DUMP_PREFIX_OFFSET, 16, 1, &cmd, sizeof(cmd), true); wil_hex_dump_wmi("cmd ", DUMP_PREFIX_OFFSET, 16, 1, buf, @@ -637,31 +646,34 @@ out: return rc; } -int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len) +int wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len) { int rc; mutex_lock(&wil->wmi_mutex); - rc = __wmi_send(wil, cmdid, buf, len); + rc = __wmi_send(wil, cmdid, mid, buf, len); mutex_unlock(&wil->wmi_mutex); return rc; } /*=== Event handlers ===*/ -static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) +static void wmi_evt_ready(struct wil6210_vif *vif, int id, void *d, int len) { - struct wireless_dev *wdev = wil->wdev; + struct wil6210_priv *wil = vif_to_wil(vif); + struct wiphy *wiphy = wil_to_wiphy(wil); struct wmi_ready_event *evt = d; - wil->n_mids = evt->numof_additional_mids; - wil_info(wil, "FW ver. %s(SW %d); MAC %pM; %d MID's\n", wil->fw_version, le32_to_cpu(evt->sw_version), - evt->mac, wil->n_mids); + evt->mac, evt->numof_additional_mids); + if (evt->numof_additional_mids + 1 < wil->max_vifs) { + wil_err(wil, "FW does not support enough MIDs (need %d)", + wil->max_vifs - 1); + return; /* FW load will fail after timeout */ + } /* ignore MAC address, we already have it from the boot loader */ - strlcpy(wdev->wiphy->fw_version, wil->fw_version, - sizeof(wdev->wiphy->fw_version)); + strlcpy(wiphy->fw_version, wil->fw_version, sizeof(wiphy->fw_version)); if (len > offsetof(struct wmi_ready_event, rfc_read_calib_result)) { wil_dbg_wmi(wil, "rfc calibration result %d\n", @@ -674,8 +686,9 @@ static void wmi_evt_ready(struct wil6210_priv *wil, int id, void *d, int len) complete(&wil->wmi_ready); } -static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) +static void wmi_evt_rx_mgmt(struct wil6210_vif *vif, int id, void *d, int len) { + struct wil6210_priv *wil = vif_to_wil(vif); struct wmi_rx_mgmt_packet_event *data = d; struct wiphy *wiphy = wil_to_wiphy(wil); struct ieee80211_mgmt *rx_mgmt_frame = @@ -753,14 +766,14 @@ static void wmi_evt_rx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) wil_err(wil, "cfg80211_inform_bss_frame() failed\n"); } } else { - mutex_lock(&wil->p2p_wdev_mutex); - cfg80211_rx_mgmt(wil->radio_wdev, freq, signal, + mutex_lock(&wil->vif_mutex); + cfg80211_rx_mgmt(vif_to_radio_wdev(wil, vif), freq, signal, (void *)rx_mgmt_frame, d_len, 0); - mutex_unlock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->vif_mutex); } } -static void wmi_evt_tx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) +static void wmi_evt_tx_mgmt(struct wil6210_vif *vif, int id, void *d, int len) { struct wmi_tx_mgmt_packet_event *data = d; struct ieee80211_mgmt *mgmt_frame = @@ -771,11 +784,13 @@ static void wmi_evt_tx_mgmt(struct wil6210_priv *wil, int id, void *d, int len) flen, true); } -static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, +static void wmi_evt_scan_complete(struct wil6210_vif *vif, int id, void *d, int len) { - mutex_lock(&wil->p2p_wdev_mutex); - if (wil->scan_request) { + struct wil6210_priv *wil = vif_to_wil(vif); + + mutex_lock(&wil->vif_mutex); + if (vif->scan_request) { struct wmi_scan_complete_event *data = d; int status = le32_to_cpu(data->status); struct cfg80211_scan_info info = { @@ -785,26 +800,28 @@ static void wmi_evt_scan_complete(struct wil6210_priv *wil, int id, wil_dbg_wmi(wil, "SCAN_COMPLETE(0x%08x)\n", status); wil_dbg_misc(wil, "Complete scan_request 0x%p aborted %d\n", - wil->scan_request, info.aborted); - del_timer_sync(&wil->scan_timer); - cfg80211_scan_done(wil->scan_request, &info); - wil->radio_wdev = wil->wdev; - wil->scan_request = NULL; + vif->scan_request, info.aborted); + del_timer_sync(&vif->scan_timer); + cfg80211_scan_done(vif->scan_request, &info); + if (vif->mid == 0) + wil->radio_wdev = wil->main_ndev->ieee80211_ptr; + vif->scan_request = NULL; wake_up_interruptible(&wil->wq); - if (wil->p2p.pending_listen_wdev) { + if (vif->p2p.pending_listen_wdev) { wil_dbg_misc(wil, "Scheduling delayed listen\n"); - schedule_work(&wil->p2p.delayed_listen_work); + schedule_work(&vif->p2p.delayed_listen_work); } } else { wil_err(wil, "SCAN_COMPLETE while not scanning\n"); } - mutex_unlock(&wil->p2p_wdev_mutex); + mutex_unlock(&wil->vif_mutex); } -static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) +static void wmi_evt_connect(struct wil6210_vif *vif, int id, void *d, int len) { - struct net_device *ndev = wil_to_ndev(wil); - struct wireless_dev *wdev = wil->wdev; + struct wil6210_priv *wil = vif_to_wil(vif); + struct net_device *ndev = vif_to_ndev(vif); + struct wireless_dev *wdev = vif_to_wdev(vif); struct wmi_connect_event *evt = d; int ch; /* channel number */ struct station_info sinfo; @@ -869,12 +886,12 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) if ((wdev->iftype == NL80211_IFTYPE_STATION) || (wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) { - if (!test_bit(wil_status_fwconnecting, wil->status)) { + if (!test_bit(wil_vif_fwconnecting, vif->status)) { wil_err(wil, "Not in connecting state\n"); mutex_unlock(&wil->mutex); return; } - del_timer_sync(&wil->connect_timer); + del_timer_sync(&vif->connect_timer); } else if ((wdev->iftype == NL80211_IFTYPE_AP) || (wdev->iftype == NL80211_IFTYPE_P2P_GO)) { if (wil->sta[evt->cid].status != wil_sta_unused) { @@ -886,13 +903,14 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) } ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid); + wil->sta[evt->cid].mid = vif->mid; wil->sta[evt->cid].status = wil_sta_conn_pending; - rc = wil_tx_init(wil, evt->cid); + rc = wil_tx_init(vif, evt->cid); if (rc) { wil_err(wil, "config tx vring failed for CID %d, rc (%d)\n", evt->cid, rc); - wmi_disconnect_sta(wil, wil->sta[evt->cid].addr, + wmi_disconnect_sta(vif, wil->sta[evt->cid].addr, WLAN_REASON_UNSPECIFIED, false, false); } else { wil_info(wil, "successful connection to CID %d\n", evt->cid); @@ -912,14 +930,14 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) } else { struct wiphy *wiphy = wil_to_wiphy(wil); - cfg80211_ref_bss(wiphy, wil->bss); - cfg80211_connect_bss(ndev, evt->bssid, wil->bss, + cfg80211_ref_bss(wiphy, vif->bss); + cfg80211_connect_bss(ndev, evt->bssid, vif->bss, assoc_req_ie, assoc_req_ielen, assoc_resp_ie, assoc_resp_ielen, WLAN_STATUS_SUCCESS, GFP_KERNEL, NL80211_TIMEOUT_UNSPECIFIED); } - wil->bss = NULL; + vif->bss = NULL; } else if ((wdev->iftype == NL80211_IFTYPE_AP) || (wdev->iftype == NL80211_IFTYPE_P2P_GO)) { if (rc) { @@ -947,19 +965,23 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len) wil->sta[evt->cid].status = wil_sta_connected; wil->sta[evt->cid].aid = evt->aid; - set_bit(wil_status_fwconnected, wil->status); - wil_update_net_queues_bh(wil, NULL, false); + if (!test_and_set_bit(wil_vif_fwconnected, vif->status)) + atomic_inc(&wil->connected_vifs); + wil_update_net_queues_bh(wil, vif, NULL, false); out: - if (rc) + if (rc) { wil->sta[evt->cid].status = wil_sta_unused; - clear_bit(wil_status_fwconnecting, wil->status); + wil->sta[evt->cid].mid = U8_MAX; + } + clear_bit(wil_vif_fwconnecting, vif->status); mutex_unlock(&wil->mutex); } -static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, +static void wmi_evt_disconnect(struct wil6210_vif *vif, int id, void *d, int len) { + struct wil6210_priv *wil = vif_to_wil(vif); struct wmi_disconnect_event *evt = d; u16 reason_code = le16_to_cpu(evt->protocol_reason_status); @@ -976,7 +998,7 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, } mutex_lock(&wil->mutex); - wil6210_disconnect(wil, evt->bssid, reason_code, true); + wil6210_disconnect(vif, evt->bssid, reason_code, true); mutex_unlock(&wil->mutex); } @@ -984,10 +1006,10 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id, * Firmware reports EAPOL frame using WME event. * Reconstruct Ethernet frame and deliver it via normal Rx */ -static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, - void *d, int len) +static void wmi_evt_eapol_rx(struct wil6210_vif *vif, int id, void *d, int len) { - struct net_device *ndev = wil_to_ndev(wil); + struct wil6210_priv *wil = vif_to_wil(vif); + struct net_device *ndev = vif_to_ndev(vif); struct wmi_eapol_rx_event *evt = d; u16 eapol_len = le16_to_cpu(evt->eapol_len); int sz = eapol_len + ETH_HLEN; @@ -996,10 +1018,10 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, int cid; struct wil_net_stats *stats = NULL; - wil_dbg_wmi(wil, "EAPOL len %d from %pM\n", eapol_len, - evt->src_mac); + wil_dbg_wmi(wil, "EAPOL len %d from %pM MID %d\n", eapol_len, + evt->src_mac, vif->mid); - cid = wil_find_cid(wil, evt->src_mac); + cid = wil_find_cid(wil, vif->mid, evt->src_mac); if (cid >= 0) stats = &wil->sta[cid].stats; @@ -1034,13 +1056,14 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id, } } -static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len) +static void wmi_evt_vring_en(struct wil6210_vif *vif, int id, void *d, int len) { + struct wil6210_priv *wil = vif_to_wil(vif); struct wmi_vring_en_event *evt = d; u8 vri = evt->vring_index; - struct wireless_dev *wdev = wil_to_wdev(wil); + struct wireless_dev *wdev = vif_to_wdev(vif); - wil_dbg_wmi(wil, "Enable vring %d\n", vri); + wil_dbg_wmi(wil, "Enable vring %d MID %d\n", vri, vif->mid); if (vri >= ARRAY_SIZE(wil->vring_tx)) { wil_err(wil, "Enable for invalid vring %d\n", vri); @@ -1052,15 +1075,16 @@ static void wmi_evt_vring_en(struct wil6210_priv *wil, int id, void *d, int len) * wil_cfg80211_change_station() */ wil->vring_tx_data[vri].dot1x_open = true; - if (vri == wil->bcast_vring) /* no BA for bcast */ + if (vri == vif->bcast_vring) /* no BA for bcast */ return; if (agg_wsize >= 0) wil_addba_tx_request(wil, vri, agg_wsize); } -static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, - int len) +static void wmi_evt_ba_status(struct wil6210_vif *vif, int id, + void *d, int len) { + struct wil6210_priv *wil = vif_to_wil(vif); struct wmi_ba_status_event *evt = d; struct vring_tx_data *txdata; @@ -1089,19 +1113,21 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d, txdata->addba_in_progress = false; } -static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d, - int len) +static void wmi_evt_addba_rx_req(struct wil6210_vif *vif, int id, + void *d, int len) { + struct wil6210_priv *wil = vif_to_wil(vif); struct wmi_rcp_addba_req_event *evt = d; - wil_addba_rx_request(wil, evt->cidxtid, evt->dialog_token, + wil_addba_rx_request(wil, vif->mid, evt->cidxtid, evt->dialog_token, evt->ba_param_set, evt->ba_timeout, evt->ba_seq_ctrl); } -static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len) +static void wmi_evt_delba(struct wil6210_vif *vif, int id, void *d, int len) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) { + struct wil6210_priv *wil = vif_to_wil(vif); struct wmi_delba_event *evt = d; u8 cid, tid; u16 reason = __le16_to_cpu(evt->reason); @@ -1110,8 +1136,8 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) might_sleep(); parse_cidxtid(evt->cidxtid, &cid, &tid); - wil_dbg_wmi(wil, "DELBA CID %d TID %d from %s reason %d\n", - cid, tid, + wil_dbg_wmi(wil, "DELBA MID %d CID %d TID %d from %s reason %d\n", + vif->mid, cid, tid, evt->from_initiator ? "originator" : "recipient", reason); if (!evt->from_initiator) { @@ -1148,8 +1174,9 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) } static void -wmi_evt_sched_scan_result(struct wil6210_priv *wil, int id, void *d, int len) +wmi_evt_sched_scan_result(struct wil6210_vif *vif, int id, void *d, int len) { + struct wil6210_priv *wil = vif_to_wil(vif); struct wmi_sched_scan_result_event *data = d; struct wiphy *wiphy = wil_to_wiphy(wil); struct ieee80211_mgmt *rx_mgmt_frame = @@ -1220,15 +1247,17 @@ wmi_evt_sched_scan_result(struct wil6210_priv *wil, int id, void *d, int len) * Some events are ignored for purpose; and need not be interpreted as * "unhandled events" */ -static void wmi_evt_ignore(struct wil6210_priv *wil, int id, void *d, int len) +static void wmi_evt_ignore(struct wil6210_vif *vif, int id, void *d, int len) { + struct wil6210_priv *wil = vif_to_wil(vif); + wil_dbg_wmi(wil, "Ignore event 0x%04x len %d\n", id, len); } static const struct { int eventid; - void (*handler)(struct wil6210_priv *wil, int eventid, - void *data, int data_len); + void (*handler)(struct wil6210_vif *vif, + int eventid, void *data, int data_len); } wmi_evt_handlers[] = { {WMI_READY_EVENTID, wmi_evt_ready}, {WMI_FW_READY_EVENTID, wmi_evt_ignore}, @@ -1325,6 +1354,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) (len >= sizeof(struct wmi_cmd_hdr))) { struct wmi_cmd_hdr *wmi = &evt->event.wmi; u16 id = le16_to_cpu(wmi->command_id); + u8 mid = wmi->mid; u32 tstamp = le32_to_cpu(wmi->fw_timestamp); if (test_bit(wil_status_resuming, wil->status)) { if (id == WMI_TRAFFIC_RESUME_EVENTID) @@ -1336,7 +1366,8 @@ void wmi_recv_cmd(struct wil6210_priv *wil) id); } spin_lock_irqsave(&wil->wmi_ev_lock, flags); - if (wil->reply_id && wil->reply_id == id) { + if (wil->reply_id && wil->reply_id == id && + wil->reply_mid == mid) { if (wil->reply_buf) { memcpy(wil->reply_buf, wmi, min(len, wil->reply_size)); @@ -1384,7 +1415,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil) n - num_immed_reply, num_immed_reply); } -int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, +int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len, u16 reply_id, void *reply, u8 reply_size, int to_msec) { int rc; @@ -1394,12 +1425,13 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, spin_lock(&wil->wmi_ev_lock); wil->reply_id = reply_id; + wil->reply_mid = mid; wil->reply_buf = reply; wil->reply_size = reply_size; reinit_completion(&wil->wmi_call); spin_unlock(&wil->wmi_ev_lock); - rc = __wmi_send(wil, cmdid, buf, len); + rc = __wmi_send(wil, cmdid, mid, buf, len); if (rc) goto out; @@ -1419,6 +1451,7 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len, out: spin_lock(&wil->wmi_ev_lock); wil->reply_id = 0; + wil->reply_mid = U8_MAX; wil->reply_buf = NULL; wil->reply_size = 0; spin_unlock(&wil->wmi_ev_lock); @@ -1430,27 +1463,31 @@ out: int wmi_echo(struct wil6210_priv *wil) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); struct wmi_echo_cmd cmd = { .value = cpu_to_le32(0x12345678), }; - return wmi_call(wil, WMI_ECHO_CMDID, &cmd, sizeof(cmd), + return wmi_call(wil, WMI_ECHO_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_ECHO_RSP_EVENTID, NULL, 0, 50); } int wmi_set_mac_address(struct wil6210_priv *wil, void *addr) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); struct wmi_set_mac_address_cmd cmd; ether_addr_copy(cmd.mac, addr); wil_dbg_wmi(wil, "Set MAC %pM\n", addr); - return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, &cmd, sizeof(cmd)); + return wmi_send(wil, WMI_SET_MAC_ADDRESS_CMDID, vif->mid, + &cmd, sizeof(cmd)); } int wmi_led_cfg(struct wil6210_priv *wil, bool enable) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); int rc = 0; struct wmi_led_cfg_cmd cmd = { .led_mode = enable, @@ -1487,7 +1524,7 @@ int wmi_led_cfg(struct wil6210_priv *wil, bool enable) "%s led %d\n", enable ? "enabling" : "disabling", led_id); - rc = wmi_call(wil, WMI_LED_CFG_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_LED_CFG_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_LED_CFG_DONE_EVENTID, &reply, sizeof(reply), 100); if (rc) @@ -1503,9 +1540,10 @@ out: return rc; } -int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, - u8 chan, u8 hidden_ssid, u8 is_go) +int wmi_pcp_start(struct wil6210_vif *vif, + int bi, u8 wmi_nettype, u8 chan, u8 hidden_ssid, u8 is_go) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; struct wmi_pcp_start_cmd cmd = { @@ -1524,7 +1562,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, struct wmi_pcp_started_event evt; } __packed reply; - if (!wil->privacy) + if (!vif->privacy) cmd.disable_sec = 1; if ((cmd.pcp_max_assoc_sta > WIL6210_MAX_CID) || @@ -1546,7 +1584,7 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, * Processing time may be huge, in case of secure AP it takes about * 3500ms for FW to start AP */ - rc = wmi_call(wil, WMI_PCP_START_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_PCP_START_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_PCP_STARTED_EVENTID, &reply, sizeof(reply), 5000); if (rc) return rc; @@ -1561,20 +1599,22 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, return rc; } -int wmi_pcp_stop(struct wil6210_priv *wil) +int wmi_pcp_stop(struct wil6210_vif *vif) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; rc = wmi_led_cfg(wil, false); if (rc) return rc; - return wmi_call(wil, WMI_PCP_STOP_CMDID, NULL, 0, + return wmi_call(wil, WMI_PCP_STOP_CMDID, vif->mid, NULL, 0, WMI_PCP_STOPPED_EVENTID, NULL, 0, 20); } -int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid) +int wmi_set_ssid(struct wil6210_vif *vif, u8 ssid_len, const void *ssid) { + struct wil6210_priv *wil = vif_to_wil(vif); struct wmi_set_ssid_cmd cmd = { .ssid_len = cpu_to_le32(ssid_len), }; @@ -1584,11 +1624,12 @@ int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid) memcpy(cmd.ssid, ssid, ssid_len); - return wmi_send(wil, WMI_SET_SSID_CMDID, &cmd, sizeof(cmd)); + return wmi_send(wil, WMI_SET_SSID_CMDID, vif->mid, &cmd, sizeof(cmd)); } -int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid) +int wmi_get_ssid(struct wil6210_vif *vif, u8 *ssid_len, void *ssid) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; struct { struct wmi_cmd_hdr wmi; @@ -1596,8 +1637,8 @@ int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid) } __packed reply; int len; /* reply.cmd.ssid_len in CPU order */ - rc = wmi_call(wil, WMI_GET_SSID_CMDID, NULL, 0, WMI_GET_SSID_EVENTID, - &reply, sizeof(reply), 20); + rc = wmi_call(wil, WMI_GET_SSID_CMDID, vif->mid, NULL, 0, + WMI_GET_SSID_EVENTID, &reply, sizeof(reply), 20); if (rc) return rc; @@ -1613,22 +1654,25 @@ int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid) int wmi_set_channel(struct wil6210_priv *wil, int channel) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); struct wmi_set_pcp_channel_cmd cmd = { .channel = channel - 1, }; - return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, &cmd, sizeof(cmd)); + return wmi_send(wil, WMI_SET_PCP_CHANNEL_CMDID, vif->mid, + &cmd, sizeof(cmd)); } int wmi_get_channel(struct wil6210_priv *wil, int *channel) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); int rc; struct { struct wmi_cmd_hdr wmi; struct wmi_set_pcp_channel_cmd cmd; } __packed reply; - rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, NULL, 0, + rc = wmi_call(wil, WMI_GET_PCP_CHANNEL_CMDID, vif->mid, NULL, 0, WMI_GET_PCP_CHANNEL_EVENTID, &reply, sizeof(reply), 20); if (rc) return rc; @@ -1641,8 +1685,9 @@ int wmi_get_channel(struct wil6210_priv *wil, int *channel) return 0; } -int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi) +int wmi_p2p_cfg(struct wil6210_vif *vif, int channel, int bi) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; struct wmi_p2p_cfg_cmd cmd = { .discovery_mode = WMI_DISCOVERY_MODE_PEER2PEER, @@ -1656,7 +1701,7 @@ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi) wil_dbg_wmi(wil, "sending WMI_P2P_CFG_CMDID\n"); - rc = wmi_call(wil, WMI_P2P_CFG_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_P2P_CFG_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_P2P_CFG_DONE_EVENTID, &reply, sizeof(reply), 300); if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) { wil_err(wil, "P2P_CFG failed. status %d\n", reply.evt.status); @@ -1666,8 +1711,9 @@ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi) return rc; } -int wmi_start_listen(struct wil6210_priv *wil) +int wmi_start_listen(struct wil6210_vif *vif) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; struct { struct wmi_cmd_hdr wmi; @@ -1676,7 +1722,7 @@ int wmi_start_listen(struct wil6210_priv *wil) wil_dbg_wmi(wil, "sending WMI_START_LISTEN_CMDID\n"); - rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0, + rc = wmi_call(wil, WMI_START_LISTEN_CMDID, vif->mid, NULL, 0, WMI_LISTEN_STARTED_EVENTID, &reply, sizeof(reply), 300); if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) { wil_err(wil, "device failed to start listen. status %d\n", @@ -1687,8 +1733,9 @@ int wmi_start_listen(struct wil6210_priv *wil) return rc; } -int wmi_start_search(struct wil6210_priv *wil) +int wmi_start_search(struct wil6210_vif *vif) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; struct { struct wmi_cmd_hdr wmi; @@ -1697,7 +1744,7 @@ int wmi_start_search(struct wil6210_priv *wil) wil_dbg_wmi(wil, "sending WMI_START_SEARCH_CMDID\n"); - rc = wmi_call(wil, WMI_START_SEARCH_CMDID, NULL, 0, + rc = wmi_call(wil, WMI_START_SEARCH_CMDID, vif->mid, NULL, 0, WMI_SEARCH_STARTED_EVENTID, &reply, sizeof(reply), 300); if (!rc && reply.evt.status != WMI_FW_STATUS_SUCCESS) { wil_err(wil, "device failed to start search. status %d\n", @@ -1708,13 +1755,14 @@ int wmi_start_search(struct wil6210_priv *wil) return rc; } -int wmi_stop_discovery(struct wil6210_priv *wil) +int wmi_stop_discovery(struct wil6210_vif *vif) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; wil_dbg_wmi(wil, "sending WMI_DISCOVERY_STOP_CMDID\n"); - rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0, + rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, vif->mid, NULL, 0, WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 100); if (rc) @@ -1723,9 +1771,10 @@ int wmi_stop_discovery(struct wil6210_priv *wil) return rc; } -int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index, +int wmi_del_cipher_key(struct wil6210_vif *vif, u8 key_index, const void *mac_addr, int key_usage) { + struct wil6210_priv *wil = vif_to_wil(vif); struct wmi_delete_cipher_key_cmd cmd = { .key_index = key_index, }; @@ -1733,13 +1782,15 @@ int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index, if (mac_addr) memcpy(cmd.mac, mac_addr, WMI_MAC_LEN); - return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, &cmd, sizeof(cmd)); + return wmi_send(wil, WMI_DELETE_CIPHER_KEY_CMDID, vif->mid, + &cmd, sizeof(cmd)); } -int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, +int wmi_add_cipher_key(struct wil6210_vif *vif, u8 key_index, const void *mac_addr, int key_len, const void *key, int key_usage) { + struct wil6210_priv *wil = vif_to_wil(vif); struct wmi_add_cipher_key_cmd cmd = { .key_index = key_index, .key_usage = key_usage, @@ -1753,11 +1804,13 @@ int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index, if (mac_addr) memcpy(cmd.mac, mac_addr, WMI_MAC_LEN); - return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, &cmd, sizeof(cmd)); + return wmi_send(wil, WMI_ADD_CIPHER_KEY_CMDID, vif->mid, + &cmd, sizeof(cmd)); } -int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) +int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie) { + struct wil6210_priv *wil = vif_to_wil(vif); static const char *const names[] = { [WMI_FRAME_BEACON] = "BEACON", [WMI_FRAME_PROBE_REQ] = "PROBE_REQ", @@ -1786,7 +1839,7 @@ int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie) /* BUG: FW API define ieLen as u8. Will fix FW */ cmd->ie_len = cpu_to_le16(ie_len); memcpy(cmd->ie_info, ie, ie_len); - rc = wmi_send(wil, WMI_SET_APPIE_CMDID, cmd, len); + rc = wmi_send(wil, WMI_SET_APPIE_CMDID, vif->mid, cmd, len); kfree(cmd); out: if (rc) { @@ -1808,6 +1861,7 @@ out: */ int wmi_rxon(struct wil6210_priv *wil, bool on) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); int rc; struct { struct wmi_cmd_hdr wmi; @@ -1817,13 +1871,13 @@ int wmi_rxon(struct wil6210_priv *wil, bool on) wil_info(wil, "(%s)\n", on ? "on" : "off"); if (on) { - rc = wmi_call(wil, WMI_START_LISTEN_CMDID, NULL, 0, + rc = wmi_call(wil, WMI_START_LISTEN_CMDID, vif->mid, NULL, 0, WMI_LISTEN_STARTED_EVENTID, &reply, sizeof(reply), 100); if ((rc == 0) && (reply.evt.status != WMI_FW_STATUS_SUCCESS)) rc = -EINVAL; } else { - rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, NULL, 0, + rc = wmi_call(wil, WMI_DISCOVERY_STOP_CMDID, vif->mid, NULL, 0, WMI_DISCOVERY_STOPPED_EVENTID, NULL, 0, 20); } @@ -1832,8 +1886,9 @@ int wmi_rxon(struct wil6210_priv *wil, bool on) int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) { - struct wireless_dev *wdev = wil->wdev; - struct net_device *ndev = wil_to_ndev(wil); + struct net_device *ndev = wil->main_ndev; + struct wireless_dev *wdev = ndev->ieee80211_ptr; + struct wil6210_vif *vif = ndev_to_vif(ndev); struct wmi_cfg_rx_chain_cmd cmd = { .action = WMI_RX_CHAIN_ADD, .rx_sw_ring = { @@ -1877,7 +1932,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) L2_802_3_OFFLOAD_CTRL_SNAP_KEEP_MSK; /* typical time for secure PCP is 840ms */ - rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_CFG_RX_CHAIN_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_CFG_RX_CHAIN_DONE_EVENTID, &evt, sizeof(evt), 2000); if (rc) return rc; @@ -1895,6 +1950,7 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring) int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); int rc; struct wmi_temp_sense_cmd cmd = { .measure_baseband_en = cpu_to_le32(!!t_bb), @@ -1906,7 +1962,7 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) struct wmi_temp_sense_done_event evt; } __packed reply; - rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_TEMP_SENSE_CMDID, vif->mid, &cmd, sizeof(cmd), WMI_TEMP_SENSE_DONE_EVENTID, &reply, sizeof(reply), 100); if (rc) return rc; @@ -1919,9 +1975,10 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf) return 0; } -int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, +int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac, u16 reason, bool full_disconnect, bool del_sta) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; u16 reason_code; struct wmi_disconnect_sta_cmd disc_sta_cmd = { @@ -1937,16 +1994,17 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, wil_dbg_wmi(wil, "disconnect_sta: (%pM, reason %d)\n", mac, reason); - wil->locally_generated_disc = true; + vif->locally_generated_disc = true; if (del_sta) { ether_addr_copy(del_sta_cmd.dst_mac, mac); - rc = wmi_call(wil, WMI_DEL_STA_CMDID, &del_sta_cmd, + rc = wmi_call(wil, WMI_DEL_STA_CMDID, vif->mid, &del_sta_cmd, sizeof(del_sta_cmd), WMI_DISCONNECT_EVENTID, &reply, sizeof(reply), 1000); } else { ether_addr_copy(disc_sta_cmd.dst_mac, mac); - rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, &disc_sta_cmd, - sizeof(disc_sta_cmd), WMI_DISCONNECT_EVENTID, + rc = wmi_call(wil, WMI_DISCONNECT_STA_CMDID, vif->mid, + &disc_sta_cmd, sizeof(disc_sta_cmd), + WMI_DISCONNECT_EVENTID, &reply, sizeof(reply), 1000); } /* failure to disconnect in reasonable time treated as FW error */ @@ -1967,12 +2025,13 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, reply.evt.disconnect_reason); wil->sinfo_gen++; - wil6210_disconnect(wil, reply.evt.bssid, reason_code, true); + wil6210_disconnect(vif, reply.evt.bssid, reason_code, true); } return 0; } -int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout) +int wmi_addba(struct wil6210_priv *wil, u8 mid, + u8 ringid, u8 size, u16 timeout) { struct wmi_vring_ba_en_cmd cmd = { .ringid = ringid, @@ -1984,10 +2043,10 @@ int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout) wil_dbg_wmi(wil, "addba: (ring %d size %d timeout %d)\n", ringid, size, timeout); - return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd)); + return wmi_send(wil, WMI_VRING_BA_EN_CMDID, mid, &cmd, sizeof(cmd)); } -int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason) +int wmi_delba_tx(struct wil6210_priv *wil, u8 mid, u8 ringid, u16 reason) { struct wmi_vring_ba_dis_cmd cmd = { .ringid = ringid, @@ -1996,10 +2055,10 @@ int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason) wil_dbg_wmi(wil, "delba_tx: (ring %d reason %d)\n", ringid, reason); - return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd)); + return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, mid, &cmd, sizeof(cmd)); } -int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason) +int wmi_delba_rx(struct wil6210_priv *wil, u8 mid, u8 cidxtid, u16 reason) { struct wmi_rcp_delba_cmd cmd = { .cidxtid = cidxtid, @@ -2009,10 +2068,11 @@ int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason) wil_dbg_wmi(wil, "delba_rx: (CID %d TID %d reason %d)\n", cidxtid & 0xf, (cidxtid >> 4) & 0xf, reason); - return wmi_send(wil, WMI_RCP_DELBA_CMDID, &cmd, sizeof(cmd)); + return wmi_send(wil, WMI_RCP_DELBA_CMDID, mid, &cmd, sizeof(cmd)); } -int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, +int wmi_addba_rx_resp(struct wil6210_priv *wil, + u8 mid, u8 cid, u8 tid, u8 token, u16 status, bool amsdu, u16 agg_wsize, u16 timeout) { int rc; @@ -2035,10 +2095,11 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, } __packed reply; wil_dbg_wmi(wil, - "ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s\n", - cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-"); + "ADDBA response for MID %d CID %d TID %d size %d timeout %d status %d AMSDU%s\n", + mid, cid, tid, agg_wsize, + timeout, status, amsdu ? "+" : "-"); - rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, mid, &cmd, sizeof(cmd), WMI_RCP_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply), 100); if (rc) @@ -2056,6 +2117,7 @@ int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil, enum wmi_ps_profile_type ps_profile) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); int rc; struct wmi_ps_dev_profile_cfg_cmd cmd = { .ps_profile = ps_profile, @@ -2070,7 +2132,8 @@ int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil, reply.evt.status = cpu_to_le32(WMI_PS_CFG_CMD_STATUS_ERROR); - rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_PS_DEV_PROFILE_CFG_CMDID, vif->mid, + &cmd, sizeof(cmd), WMI_PS_DEV_PROFILE_CFG_EVENTID, &reply, sizeof(reply), 100); if (rc) @@ -2089,6 +2152,7 @@ int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil, int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); int rc; struct wmi_set_mgmt_retry_limit_cmd cmd = { .mgmt_retry_limit = retry_short, @@ -2105,7 +2169,8 @@ int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short) reply.evt.status = WMI_FW_STATUS_FAILURE; - rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_SET_MGMT_RETRY_LIMIT_CMDID, vif->mid, + &cmd, sizeof(cmd), WMI_SET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply), 100); if (rc) @@ -2122,6 +2187,7 @@ int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short) int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); int rc; struct { struct wmi_cmd_hdr wmi; @@ -2134,7 +2200,7 @@ int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short) return -ENOTSUPP; reply.evt.mgmt_retry_limit = 0; - rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, NULL, 0, + rc = wmi_call(wil, WMI_GET_MGMT_RETRY_LIMIT_CMDID, vif->mid, NULL, 0, WMI_GET_MGMT_RETRY_LIMIT_EVENTID, &reply, sizeof(reply), 100); if (rc) @@ -2146,21 +2212,23 @@ int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short) return 0; } -int wmi_abort_scan(struct wil6210_priv *wil) +int wmi_abort_scan(struct wil6210_vif *vif) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; wil_dbg_wmi(wil, "sending WMI_ABORT_SCAN_CMDID\n"); - rc = wmi_send(wil, WMI_ABORT_SCAN_CMDID, NULL, 0); + rc = wmi_send(wil, WMI_ABORT_SCAN_CMDID, vif->mid, NULL, 0); if (rc) wil_err(wil, "Failed to abort scan (%d)\n", rc); return rc; } -int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid) +int wmi_new_sta(struct wil6210_vif *vif, const u8 *mac, u8 aid) { + struct wil6210_priv *wil = vif_to_wil(vif); int rc; struct wmi_new_sta_cmd cmd = { .aid = aid, @@ -2170,7 +2238,7 @@ int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid) ether_addr_copy(cmd.dst_mac, mac); - rc = wmi_send(wil, WMI_NEW_STA_CMDID, &cmd, sizeof(cmd)); + rc = wmi_send(wil, WMI_NEW_STA_CMDID, vif->mid, &cmd, sizeof(cmd)); if (rc) wil_err(wil, "Failed to send new sta (%d)\n", rc); @@ -2206,6 +2274,7 @@ static const char *suspend_status2name(u8 status) int wmi_suspend(struct wil6210_priv *wil) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); int rc; struct wmi_traffic_suspend_cmd cmd = { .wakeup_trigger = wil->wakeup_trigger, @@ -2221,7 +2290,8 @@ int wmi_suspend(struct wil6210_priv *wil) reply.evt.status = WMI_TRAFFIC_SUSPEND_REJECTED_LINK_NOT_IDLE; - rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_TRAFFIC_SUSPEND_CMDID, vif->mid, + &cmd, sizeof(cmd), WMI_TRAFFIC_SUSPEND_EVENTID, &reply, sizeof(reply), suspend_to); if (rc) { @@ -2289,6 +2359,7 @@ static void resume_triggers2string(u32 triggers, char *string, int str_size) int wmi_resume(struct wil6210_priv *wil) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); int rc; char string[100]; struct { @@ -2299,7 +2370,7 @@ int wmi_resume(struct wil6210_priv *wil) reply.evt.status = WMI_TRAFFIC_RESUME_FAILED; reply.evt.resume_triggers = WMI_RESUME_TRIGGER_UNKNOWN; - rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, NULL, 0, + rc = wmi_call(wil, WMI_TRAFFIC_RESUME_CMDID, vif->mid, NULL, 0, WMI_TRAFFIC_RESUME_EVENTID, &reply, sizeof(reply), WIL_WAIT_FOR_SUSPEND_RESUME_COMP); if (rc) @@ -2313,14 +2384,100 @@ int wmi_resume(struct wil6210_priv *wil) return reply.evt.status; } -static bool wmi_evt_call_handler(struct wil6210_priv *wil, int id, +int wmi_port_allocate(struct wil6210_priv *wil, u8 mid, + const u8 *mac, enum nl80211_iftype iftype) +{ + int rc; + struct wmi_port_allocate_cmd cmd = { + .mid = mid, + }; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_port_allocated_event evt; + } __packed reply; + + wil_dbg_misc(wil, "port allocate, mid %d iftype %d, mac %pM\n", + mid, iftype, mac); + + ether_addr_copy(cmd.mac, mac); + switch (iftype) { + case NL80211_IFTYPE_STATION: + cmd.port_role = WMI_PORT_STA; + break; + case NL80211_IFTYPE_AP: + cmd.port_role = WMI_PORT_AP; + break; + case NL80211_IFTYPE_P2P_CLIENT: + cmd.port_role = WMI_PORT_P2P_CLIENT; + break; + case NL80211_IFTYPE_P2P_GO: + cmd.port_role = WMI_PORT_P2P_GO; + break; + /* what about monitor??? */ + default: + wil_err(wil, "unsupported iftype: %d\n", iftype); + return -EINVAL; + } + + reply.evt.status = WMI_FW_STATUS_FAILURE; + + rc = wmi_call(wil, WMI_PORT_ALLOCATE_CMDID, mid, + &cmd, sizeof(cmd), + WMI_PORT_ALLOCATED_EVENTID, &reply, + sizeof(reply), 300); + if (rc) { + wil_err(wil, "failed to allocate port, status %d\n", rc); + return rc; + } + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "WMI_PORT_ALLOCATE returned status %d\n", + reply.evt.status); + return -EINVAL; + } + + return 0; +} + +int wmi_port_delete(struct wil6210_priv *wil, u8 mid) +{ + int rc; + struct wmi_port_delete_cmd cmd = { + .mid = mid, + }; + struct { + struct wmi_cmd_hdr wmi; + struct wmi_port_deleted_event evt; + } __packed reply; + + wil_dbg_misc(wil, "port delete, mid %d\n", mid); + + reply.evt.status = WMI_FW_STATUS_FAILURE; + + rc = wmi_call(wil, WMI_PORT_DELETE_CMDID, mid, + &cmd, sizeof(cmd), + WMI_PORT_DELETED_EVENTID, &reply, + sizeof(reply), 2000); + if (rc) { + wil_err(wil, "failed to delete port, status %d\n", rc); + return rc; + } + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "WMI_PORT_DELETE returned status %d\n", + reply.evt.status); + return -EINVAL; + } + + return 0; +} + +static bool wmi_evt_call_handler(struct wil6210_vif *vif, int id, void *d, int len) { uint i; for (i = 0; i < ARRAY_SIZE(wmi_evt_handlers); i++) { if (wmi_evt_handlers[i].eventid == id) { - wmi_evt_handlers[i].handler(wil, id, d, len); + wmi_evt_handlers[i].handler(vif, id, d, len); return true; } } @@ -2332,19 +2489,39 @@ static void wmi_event_handle(struct wil6210_priv *wil, struct wil6210_mbox_hdr *hdr) { u16 len = le16_to_cpu(hdr->len); + struct wil6210_vif *vif; if ((hdr->type == WIL_MBOX_HDR_TYPE_WMI) && (len >= sizeof(struct wmi_cmd_hdr))) { struct wmi_cmd_hdr *wmi = (void *)(&hdr[1]); void *evt_data = (void *)(&wmi[1]); u16 id = le16_to_cpu(wmi->command_id); + u8 mid = wmi->mid; + + wil_dbg_wmi(wil, "Handle %s (0x%04x) (reply_id 0x%04x,%d)\n", + eventid2name(id), id, wil->reply_id, + wil->reply_mid); + + if (mid == MID_BROADCAST) + mid = 0; + if (mid >= wil->max_vifs) { + wil_dbg_wmi(wil, "invalid mid %d, event skipped\n", + mid); + return; + } + vif = wil->vifs[mid]; + if (!vif) { + wil_dbg_wmi(wil, "event for empty VIF(%d), skipped\n", + mid); + return; + } - wil_dbg_wmi(wil, "Handle %s (0x%04x) (reply_id 0x%04x)\n", - eventid2name(id), id, wil->reply_id); /* check if someone waits for this event */ - if (wil->reply_id && wil->reply_id == id) { + if (wil->reply_id && wil->reply_id == id && + wil->reply_mid == mid) { WARN_ON(wil->reply_buf); - wmi_evt_call_handler(wil, id, evt_data, + + wmi_evt_call_handler(vif, id, evt_data, len - sizeof(*wmi)); wil_dbg_wmi(wil, "event_handle: Complete WMI 0x%04x\n", id); @@ -2353,7 +2530,7 @@ static void wmi_event_handle(struct wil6210_priv *wil, } /* unsolicited event */ /* search for handler */ - if (!wmi_evt_call_handler(wil, id, evt_data, + if (!wmi_evt_call_handler(vif, id, evt_data, len - sizeof(*wmi))) { wil_info(wil, "Unhandled event 0x%04x\n", id); } @@ -2523,6 +2700,7 @@ wmi_sched_scan_set_plans(struct wil6210_priv *wil, int wmi_start_sched_scan(struct wil6210_priv *wil, struct cfg80211_sched_scan_request *request) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); int rc; struct wmi_start_sched_scan_cmd cmd = { .min_rssi_threshold = S8_MIN, @@ -2549,7 +2727,8 @@ int wmi_start_sched_scan(struct wil6210_priv *wil, reply.evt.result = WMI_PNO_REJECT; - rc = wmi_call(wil, WMI_START_SCHED_SCAN_CMDID, &cmd, sizeof(cmd), + rc = wmi_call(wil, WMI_START_SCHED_SCAN_CMDID, vif->mid, + &cmd, sizeof(cmd), WMI_START_SCHED_SCAN_EVENTID, &reply, sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); if (rc) @@ -2566,6 +2745,7 @@ int wmi_start_sched_scan(struct wil6210_priv *wil, int wmi_stop_sched_scan(struct wil6210_priv *wil) { + struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev); int rc; struct { struct wmi_cmd_hdr wmi; @@ -2577,7 +2757,7 @@ int wmi_stop_sched_scan(struct wil6210_priv *wil) reply.evt.result = WMI_PNO_REJECT; - rc = wmi_call(wil, WMI_STOP_SCHED_SCAN_CMDID, NULL, 0, + rc = wmi_call(wil, WMI_STOP_SCHED_SCAN_CMDID, vif->mid, NULL, 0, WMI_STOP_SCHED_SCAN_EVENTID, &reply, sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); if (rc) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c index 2d3a5dd07a3f..1068a2a4494c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c @@ -445,6 +445,11 @@ brcmf_proto_bcdc_init_done(struct brcmf_pub *drvr) return 0; } +static void brcmf_proto_bcdc_debugfs_create(struct brcmf_pub *drvr) +{ + brcmf_fws_debugfs_create(drvr); +} + int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) { struct brcmf_bcdc *bcdc; @@ -472,6 +477,7 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) drvr->proto->del_if = brcmf_proto_bcdc_del_if; drvr->proto->reset_if = brcmf_proto_bcdc_reset_if; drvr->proto->init_done = brcmf_proto_bcdc_init_done; + drvr->proto->debugfs_create = brcmf_proto_bcdc_debugfs_create; drvr->proto->pd = bcdc; drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c index 03aae6bc1838..372363a6e752 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c @@ -462,7 +462,7 @@ static void brcmf_btcoex_dhcp_end(struct brcmf_btcoex_info *btci) int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif, enum brcmf_btcoex_mode mode, u16 duration) { - struct brcmf_cfg80211_info *cfg = wiphy_priv(vif->wdev.wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy); struct brcmf_btcoex_info *btci = cfg->btcoex; struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h index 0b90a63bdeb1..27e693e93f21 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h @@ -88,7 +88,7 @@ struct brcmf_bus_ops { void (*wowl_config)(struct device *dev, bool enabled); size_t (*get_ramsize)(struct device *dev); int (*get_memdump)(struct device *dev, void *data, size_t len); - int (*get_fwname)(struct device *dev, uint chip, uint chiprev, + int (*get_fwname)(struct device *dev, const char *ext, unsigned char *fw_name); }; @@ -140,6 +140,7 @@ struct brcmf_bus_stats { * @always_use_fws_queue: bus wants use queue also when fwsignal is inactive. * @wowl_supported: is wowl supported by bus driver. * @chiprev: revision of the dongle chip. + * @msgbuf: msgbuf protocol parameters provided by bus layer. */ struct brcmf_bus { union { @@ -228,10 +229,10 @@ int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len) } static inline -int brcmf_bus_get_fwname(struct brcmf_bus *bus, uint chip, uint chiprev, +int brcmf_bus_get_fwname(struct brcmf_bus *bus, const char *ext, unsigned char *fw_name) { - return bus->ops->get_fwname(bus->dev, chip, chiprev, fw_name); + return bus->ops->get_fwname(bus->dev, ext, fw_name); } /* diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 74a83020c073..89b86251910e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -753,7 +753,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy, struct wireless_dev *wdev) { - struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct net_device *ndev = wdev->netdev; struct brcmf_if *ifp = netdev_priv(ndev); int ret; @@ -786,7 +786,7 @@ err_unarm: static int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) { - struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct net_device *ndev = wdev->netdev; if (ndev && ndev == cfg_to_ndev(cfg)) @@ -831,7 +831,7 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, enum nl80211_iftype type, struct vif_params *params) { - struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_cfg80211_vif *vif = ifp->vif; s32 infra = 0; @@ -2127,17 +2127,15 @@ static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, s32 *dbm) { - struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); - struct net_device *ndev = cfg_to_ndev(cfg); - struct brcmf_if *ifp = netdev_priv(ndev); + struct brcmf_cfg80211_vif *vif = wdev_to_vif(wdev); s32 qdbm = 0; s32 err; brcmf_dbg(TRACE, "Enter\n"); - if (!check_vif_up(ifp->vif)) + if (!check_vif_up(vif)) return -EIO; - err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm); + err = brcmf_fil_iovar_int_get(vif->ifp, "qtxpower", &qdbm); if (err) { brcmf_err("error (%d)\n", err); goto done; @@ -3358,7 +3356,7 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy, struct cfg80211_sched_scan_request *req) { struct brcmf_if *ifp = netdev_priv(ndev); - struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); brcmf_dbg(SCAN, "Enter: n_match_sets=%d n_ssids=%d\n", req->n_match_sets, req->n_ssids); @@ -5190,6 +5188,12 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { .del_pmk = brcmf_cfg80211_del_pmk, }; +struct cfg80211_ops *brcmf_cfg80211_get_ops(void) +{ + return kmemdup(&brcmf_cfg80211_ops, sizeof(brcmf_cfg80211_ops), + GFP_KERNEL); +} + struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, enum nl80211_iftype type) { @@ -5897,7 +5901,7 @@ static void brcmf_update_bw40_channel_flag(struct ieee80211_channel *channel, static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap[]) { - struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); struct ieee80211_supported_band *band; struct ieee80211_channel *channel; struct wiphy *wiphy; @@ -6012,7 +6016,7 @@ fail_pbuf: static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg) { - struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); struct ieee80211_supported_band *band; struct brcmf_fil_bwcap_le band_bwcap; struct brcmf_chanspec_list *list; @@ -6197,10 +6201,10 @@ static void brcmf_update_vht_cap(struct ieee80211_supported_band *band, } } -static int brcmf_setup_wiphybands(struct wiphy *wiphy) +static int brcmf_setup_wiphybands(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); - struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); + struct wiphy *wiphy; u32 nmode = 0; u32 vhtmode = 0; u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT }; @@ -6794,8 +6798,8 @@ static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2], static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, struct regulatory_request *req) { - struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); - struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); struct brcmf_fil_country_le ccreq; s32 err; int i; @@ -6805,7 +6809,7 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, return; /* ignore non-ISO3166 country codes */ - for (i = 0; i < sizeof(req->alpha2); i++) + for (i = 0; i < 2; i++) if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') { brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n", req->alpha2[0], req->alpha2[1]); @@ -6830,7 +6834,7 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, brcmf_err("Firmware rejected country setting\n"); return; } - brcmf_setup_wiphybands(wiphy); + brcmf_setup_wiphybands(cfg); } static void brcmf_free_wiphy(struct wiphy *wiphy) @@ -6857,17 +6861,15 @@ static void brcmf_free_wiphy(struct wiphy *wiphy) if (wiphy->wowlan != &brcmf_wowlan_support) kfree(wiphy->wowlan); #endif - wiphy_free(wiphy); } struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, - struct device *busdev, + struct cfg80211_ops *ops, bool p2pdev_forced) { + struct wiphy *wiphy = drvr->wiphy; struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev; struct brcmf_cfg80211_info *cfg; - struct wiphy *wiphy; - struct cfg80211_ops *ops; struct brcmf_cfg80211_vif *vif; struct brcmf_if *ifp; s32 err = 0; @@ -6879,26 +6881,13 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, return NULL; } - ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL); - if (!ops) - return NULL; - - ifp = netdev_priv(ndev); -#ifdef CONFIG_PM - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) - ops->set_rekey_data = brcmf_cfg80211_set_rekey_data; -#endif - wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info)); - if (!wiphy) { + cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); + if (!cfg) { brcmf_err("Could not allocate wiphy device\n"); - goto ops_out; + return NULL; } - memcpy(wiphy->perm_addr, drvr->mac, ETH_ALEN); - set_wiphy_dev(wiphy, busdev); - cfg = wiphy_priv(wiphy); cfg->wiphy = wiphy; - cfg->ops = ops; cfg->pub = drvr; init_vif_event(&cfg->vif_event); INIT_LIST_HEAD(&cfg->vif_list); @@ -6907,6 +6896,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, if (IS_ERR(vif)) goto wiphy_out; + ifp = netdev_priv(ndev); vif->ifp = ifp; vif->wdev.netdev = ndev; ndev->ieee80211_ptr = &vif->wdev; @@ -6933,6 +6923,11 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, if (err < 0) goto priv_out; + /* regulatory notifer below needs access to cfg so + * assign it now. + */ + drvr->config = cfg; + brcmf_dbg(INFO, "Registering custom regulatory\n"); wiphy->reg_notifier = brcmf_cfg80211_reg_notifier; wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; @@ -6946,13 +6941,17 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, cap = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap; *cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; } +#ifdef CONFIG_PM + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) + ops->set_rekey_data = brcmf_cfg80211_set_rekey_data; +#endif err = wiphy_register(wiphy); if (err < 0) { brcmf_err("Could not register wiphy device (%d)\n", err); goto priv_out; } - err = brcmf_setup_wiphybands(wiphy); + err = brcmf_setup_wiphybands(cfg); if (err) { brcmf_err("Setting wiphy bands failed (%d)\n", err); goto wiphy_unreg_out; @@ -6969,12 +6968,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, else *cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; } - /* p2p might require that "if-events" get processed by fweh. So - * activate the already registered event handlers now and activate - * the rest when initialization has completed. drvr->config needs to - * be assigned before activating events. - */ - drvr->config = cfg; + err = brcmf_fweh_activate_events(ifp); if (err) { brcmf_err("FWEH activation failed (%d)\n", err); @@ -7042,8 +7036,7 @@ priv_out: ifp->vif = NULL; wiphy_out: brcmf_free_wiphy(wiphy); -ops_out: - kfree(ops); + kfree(cfg); return NULL; } @@ -7058,4 +7051,5 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) kfree(cfg->ops); wl_deinit_priv(cfg); brcmf_free_wiphy(cfg->wiphy); + kfree(cfg); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index b5b5f0f10b63..a4aec0004e4f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -355,20 +355,24 @@ static inline struct wiphy *cfg_to_wiphy(struct brcmf_cfg80211_info *cfg) static inline struct brcmf_cfg80211_info *wiphy_to_cfg(struct wiphy *w) { - return (struct brcmf_cfg80211_info *)(wiphy_priv(w)); + struct brcmf_pub *drvr = wiphy_priv(w); + return drvr->config; } static inline struct brcmf_cfg80211_info *wdev_to_cfg(struct wireless_dev *wd) { - return (struct brcmf_cfg80211_info *)(wdev_priv(wd)); + return wiphy_to_cfg(wd->wiphy); +} + +static inline struct brcmf_cfg80211_vif *wdev_to_vif(struct wireless_dev *wdev) +{ + return container_of(wdev, struct brcmf_cfg80211_vif, wdev); } static inline struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_vif *vif; - vif = list_first_entry(&cfg->vif_list, struct brcmf_cfg80211_vif, list); - return vif->wdev.netdev; + return brcmf_get_ifp(cfg->pub, 0)->ndev; } static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *ndev) @@ -395,11 +399,12 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg) } struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, - struct device *busdev, + struct cfg80211_ops *ops, bool p2pdev_forced); void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); s32 brcmf_cfg80211_up(struct net_device *ndev); s32 brcmf_cfg80211_down(struct net_device *ndev); +struct cfg80211_ops *brcmf_cfg80211_get_ops(void); enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp); struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index f7b30ce2300d..3b829fed8631 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -464,12 +464,12 @@ static void brcmf_chip_ai_resetcore(struct brcmf_core_priv *core, u32 prereset, ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); } -static char *brcmf_chip_name(uint chipid, char *buf, uint len) +char *brcmf_chip_name(u32 id, u32 rev, char *buf, uint len) { const char *fmt; - fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; - snprintf(buf, len, fmt, chipid); + fmt = ((id > 0xa000) || (id < 0x4000)) ? "BCM%d/%u" : "BCM%x/%u"; + snprintf(buf, len, fmt, id, rev); return buf; } @@ -924,10 +924,10 @@ static int brcmf_chip_recognition(struct brcmf_chip_priv *ci) ci->pub.chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT; - brcmf_chip_name(ci->pub.chip, ci->pub.name, sizeof(ci->pub.name)); - brcmf_dbg(INFO, "found %s chip: BCM%s, rev=%d\n", - socitype == SOCI_SB ? "SB" : "AXI", ci->pub.name, - ci->pub.chiprev); + brcmf_chip_name(ci->pub.chip, ci->pub.chiprev, + ci->pub.name, sizeof(ci->pub.name)); + brcmf_dbg(INFO, "found %s chip: %s\n", + socitype == SOCI_SB ? "SB" : "AXI", ci->pub.name); if (socitype == SOCI_SB) { if (ci->pub.chip != BRCM_CC_4329_CHIP_ID) { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h index dd0ec3eba6a9..0ae3b33bab62 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h @@ -45,7 +45,7 @@ struct brcmf_chip { u32 rambase; u32 ramsize; u32 srsize; - char name[8]; + char name[12]; }; /** @@ -93,5 +93,6 @@ void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset, void brcmf_chip_set_passive(struct brcmf_chip *ci); bool brcmf_chip_set_active(struct brcmf_chip *ci, u32 rstvec); bool brcmf_chip_sr_capable(struct brcmf_chip *pub); +char *brcmf_chip_name(u32 chipid, u32 chiprev, char *buf, uint len); #endif /* BRCMF_AXIDMP_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index 70ef9835b647..105b8774fca9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -30,6 +30,7 @@ #include "common.h" #include "of.h" #include "firmware.h" +#include "chip.h" MODULE_AUTHOR("Broadcom Corporation"); MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); @@ -51,7 +52,7 @@ MODULE_PARM_DESC(txglomsz, "Maximum tx packet chain size [SDIO]"); /* Debug level configuration. See debug.h for bits, sysfs modifiable */ int brcmf_msg_level; -module_param_named(debug, brcmf_msg_level, int, S_IRUSR | S_IWUSR); +module_param_named(debug, brcmf_msg_level, int, 0600); MODULE_PARM_DESC(debug, "Level of debug output"); static int brcmf_p2p_enable; @@ -64,7 +65,7 @@ MODULE_PARM_DESC(feature_disable, "Disable features"); static char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN]; module_param_string(alternative_fw_path, brcmf_firmware_path, - BRCMF_FW_ALTPATH_LEN, S_IRUSR); + BRCMF_FW_ALTPATH_LEN, 0400); MODULE_PARM_DESC(alternative_fw_path, "Alternative firmware path"); static int brcmf_fcmode; @@ -72,9 +73,13 @@ module_param_named(fcmode, brcmf_fcmode, int, 0); MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control"); static int brcmf_roamoff; -module_param_named(roamoff, brcmf_roamoff, int, S_IRUSR); +module_param_named(roamoff, brcmf_roamoff, int, 0400); MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine"); +static int brcmf_iapp_enable; +module_param_named(iapp, brcmf_iapp_enable, int, 0); +MODULE_PARM_DESC(iapp, "Enable partial support for the obsoleted Inter-Access Point Protocol"); + #ifdef DEBUG /* always succeed brcmf_bus_started() */ static int brcmf_ignore_probe_fail; @@ -124,43 +129,9 @@ static int brcmf_c_download(struct brcmf_if *ifp, u16 flag, return err; } -static int brcmf_c_get_clm_name(struct brcmf_if *ifp, u8 *clm_name) -{ - struct brcmf_bus *bus = ifp->drvr->bus_if; - struct brcmf_rev_info *ri = &ifp->drvr->revinfo; - u8 fw_name[BRCMF_FW_NAME_LEN]; - u8 *ptr; - size_t len; - s32 err; - - memset(fw_name, 0, BRCMF_FW_NAME_LEN); - err = brcmf_bus_get_fwname(bus, ri->chipnum, ri->chiprev, fw_name); - if (err) { - brcmf_err("get firmware name failed (%d)\n", err); - goto done; - } - - /* generate CLM blob file name */ - ptr = strrchr(fw_name, '.'); - if (!ptr) { - err = -ENOENT; - goto done; - } - - len = ptr - fw_name + 1; - if (len + strlen(".clm_blob") > BRCMF_FW_NAME_LEN) { - err = -E2BIG; - } else { - strlcpy(clm_name, fw_name, len); - strlcat(clm_name, ".clm_blob", BRCMF_FW_NAME_LEN); - } -done: - return err; -} - static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) { - struct device *dev = ifp->drvr->bus_if->dev; + struct brcmf_bus *bus = ifp->drvr->bus_if; struct brcmf_dload_data_le *chunk_buf; const struct firmware *clm = NULL; u8 clm_name[BRCMF_FW_NAME_LEN]; @@ -173,16 +144,16 @@ static int brcmf_c_process_clm_blob(struct brcmf_if *ifp) brcmf_dbg(TRACE, "Enter\n"); - memset(clm_name, 0, BRCMF_FW_NAME_LEN); - err = brcmf_c_get_clm_name(ifp, clm_name); + memset(clm_name, 0, sizeof(clm_name)); + err = brcmf_bus_get_fwname(bus, ".clm_blob", clm_name); if (err) { brcmf_err("get CLM blob file name failed (%d)\n", err); return err; } - err = request_firmware(&clm, clm_name, dev); + err = request_firmware(&clm, clm_name, bus->dev); if (err) { - brcmf_info("no clm_blob available(err=%d), device may have limited channels available\n", + brcmf_info("no clm_blob available (err=%d), device may have limited channels available\n", err); return 0; } @@ -234,6 +205,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) { s8 eventmask[BRCMF_EVENTING_MASK_LEN]; u8 buf[BRCMF_DCMD_SMLEN]; + struct brcmf_bus *bus; struct brcmf_rev_info_le revinfo; struct brcmf_rev_info *ri; char *clmver; @@ -247,18 +219,21 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) brcmf_err("Retreiving cur_etheraddr failed, %d\n", err); goto done; } + memcpy(ifp->drvr->wiphy->perm_addr, ifp->drvr->mac, ETH_ALEN); memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac)); + bus = ifp->drvr->bus_if; + ri = &ifp->drvr->revinfo; + err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO, &revinfo, sizeof(revinfo)); - ri = &ifp->drvr->revinfo; if (err < 0) { brcmf_err("retrieving revision info failed, %d\n", err); + strlcpy(ri->chipname, "UNKNOWN", sizeof(ri->chipname)); } else { ri->vendorid = le32_to_cpu(revinfo.vendorid); ri->deviceid = le32_to_cpu(revinfo.deviceid); ri->radiorev = le32_to_cpu(revinfo.radiorev); - ri->chiprev = le32_to_cpu(revinfo.chiprev); ri->corerev = le32_to_cpu(revinfo.corerev); ri->boardid = le32_to_cpu(revinfo.boardid); ri->boardvendor = le32_to_cpu(revinfo.boardvendor); @@ -266,15 +241,24 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) ri->driverrev = le32_to_cpu(revinfo.driverrev); ri->ucoderev = le32_to_cpu(revinfo.ucoderev); ri->bus = le32_to_cpu(revinfo.bus); - ri->chipnum = le32_to_cpu(revinfo.chipnum); ri->phytype = le32_to_cpu(revinfo.phytype); ri->phyrev = le32_to_cpu(revinfo.phyrev); ri->anarev = le32_to_cpu(revinfo.anarev); ri->chippkg = le32_to_cpu(revinfo.chippkg); ri->nvramrev = le32_to_cpu(revinfo.nvramrev); + + /* use revinfo if not known yet */ + if (!bus->chip) { + bus->chip = le32_to_cpu(revinfo.chipnum); + bus->chiprev = le32_to_cpu(revinfo.chiprev); + } } ri->result = err; + if (bus->chip) + brcmf_chip_name(bus->chip, bus->chiprev, + ri->chipname, sizeof(ri->chipname)); + /* Do any CLM downloading */ err = brcmf_c_process_clm_blob(ifp); if (err < 0) { @@ -295,7 +279,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp) strsep(&ptr, "\n"); /* Print fw version info */ - brcmf_info("Firmware version = %s\n", buf); + brcmf_info("Firmware: %s %s\n", ri->chipname, buf); /* locate firmware version number for ethtool */ ptr = strrchr(buf, ' ') + 1; @@ -438,6 +422,7 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev, settings->feature_disable = brcmf_feature_disable; settings->fcmode = brcmf_fcmode; settings->roamoff = !!brcmf_roamoff; + settings->iapp = !!brcmf_iapp_enable; #ifdef DEBUG settings->ignore_probe_fail = !!brcmf_ignore_probe_fail; #endif @@ -511,9 +496,6 @@ static int __init brcmfmac_module_init(void) { int err; - /* Initialize debug system first */ - brcmf_debugfs_init(); - /* Get the platform data (if available) for our devices */ err = platform_driver_probe(&brcmf_pd, brcmf_common_pd_probe); if (err == -ENODEV) @@ -525,7 +507,6 @@ static int __init brcmfmac_module_init(void) /* Continue the initialization by registering the different busses */ err = brcmf_core_init(); if (err) { - brcmf_debugfs_exit(); if (brcmfmac_pdata) platform_driver_unregister(&brcmf_pd); } @@ -538,7 +519,6 @@ static void __exit brcmfmac_module_exit(void) brcmf_core_exit(); if (brcmfmac_pdata) platform_driver_unregister(&brcmf_pd); - brcmf_debugfs_exit(); } module_init(brcmfmac_module_init); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h index a62f8e70b320..ef914619e8e1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h @@ -58,6 +58,7 @@ struct brcmf_mp_device { unsigned int feature_disable; int fcmode; bool roamoff; + bool iapp; bool ignore_probe_fail; struct brcmfmac_pd_cc *country_codes; union { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 19048526b4af..8d4511eaa9b9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -230,6 +230,37 @@ static void brcmf_netdev_set_multicast_list(struct net_device *ndev) schedule_work(&ifp->multicast_work); } +/** + * brcmf_skb_is_iapp - checks if skb is an IAPP packet + * + * @skb: skb to check + */ +static bool brcmf_skb_is_iapp(struct sk_buff *skb) +{ + static const u8 iapp_l2_update_packet[6] __aligned(2) = { + 0x00, 0x01, 0xaf, 0x81, 0x01, 0x00, + }; + unsigned char *eth_data; +#if !defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + const u16 *a, *b; +#endif + + if (skb->len - skb->mac_len != 6 || + !is_multicast_ether_addr(eth_hdr(skb)->h_dest)) + return false; + + eth_data = skb_mac_header(skb) + ETH_HLEN; +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + return !(((*(const u32 *)eth_data) ^ (*(const u32 *)iapp_l2_update_packet)) | + ((*(const u16 *)(eth_data + 4)) ^ (*(const u16 *)(iapp_l2_update_packet + 4)))); +#else + a = (const u16 *)eth_data; + b = (const u16 *)iapp_l2_update_packet; + + return !((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])); +#endif +} + static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev) { @@ -250,6 +281,23 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb, goto done; } + /* Some recent Broadcom's firmwares disassociate STA when they receive + * an 802.11f ADD frame. This behavior can lead to a local DoS security + * issue. Attacker may trigger disassociation of any STA by sending a + * proper Ethernet frame to the wireless interface. + * + * Moreover this feature may break AP interfaces in some specific + * setups. This applies e.g. to the bridge with hairpin mode enabled and + * IFLA_BRPORT_MCAST_TO_UCAST set. IAPP packet generated by a firmware + * will get passed back to the wireless interface and cause immediate + * disassociation of a just-connected STA. + */ + if (!drvr->settings->iapp && brcmf_skb_is_iapp(skb)) { + dev_kfree_skb(skb); + ret = -EINVAL; + goto done; + } + /* Make sure there's enough writeable headroom */ if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) { head_delta = max_t(int, drvr->hdrlen - skb_headroom(skb), 0); @@ -325,6 +373,15 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp, void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb) { + /* Most of Broadcom's firmwares send 802.11f ADD frame every time a new + * STA connects to the AP interface. This is an obsoleted standard most + * users don't use, so don't pass these frames up unless requested. + */ + if (!ifp->drvr->settings->iapp && brcmf_skb_is_iapp(skb)) { + brcmu_pkt_buf_free_skb(skb); + return; + } + if (skb->pkt_type == PACKET_MULTICAST) ifp->ndev->stats.multicast++; @@ -924,8 +981,7 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data) seq_printf(s, "vendorid: 0x%04x\n", ri->vendorid); seq_printf(s, "deviceid: 0x%04x\n", ri->deviceid); seq_printf(s, "radiorev: %s\n", brcmu_dotrev_str(ri->radiorev, drev)); - seq_printf(s, "chipnum: %u (%x)\n", ri->chipnum, ri->chipnum); - seq_printf(s, "chiprev: %u\n", ri->chiprev); + seq_printf(s, "chip: %s\n", ri->chipname); seq_printf(s, "chippkg: %u\n", ri->chippkg); seq_printf(s, "corerev: %u\n", ri->corerev); seq_printf(s, "boardid: 0x%04x\n", ri->boardid); @@ -944,7 +1000,7 @@ static int brcmf_revinfo_read(struct seq_file *s, void *data) return 0; } -static int brcmf_bus_started(struct brcmf_pub *drvr) +static int brcmf_bus_started(struct brcmf_pub *drvr, struct cfg80211_ops *ops) { int ret = -1; struct brcmf_bus *bus_if = drvr->bus_if; @@ -973,15 +1029,6 @@ static int brcmf_bus_started(struct brcmf_pub *drvr) if (ret < 0) goto fail; - brcmf_debugfs_add_entry(drvr, "revinfo", brcmf_revinfo_read); - - /* assure we have chipid before feature attach */ - if (!bus_if->chip) { - bus_if->chip = drvr->revinfo.chipnum; - bus_if->chiprev = drvr->revinfo.chiprev; - brcmf_dbg(INFO, "firmware revinfo: chip %x (%d) rev %d\n", - bus_if->chip, bus_if->chip, bus_if->chiprev); - } brcmf_feat_attach(drvr); ret = brcmf_proto_init_done(drvr); @@ -990,7 +1037,7 @@ static int brcmf_bus_started(struct brcmf_pub *drvr) brcmf_proto_add_if(drvr, ifp); - drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev, + drvr->config = brcmf_cfg80211_attach(drvr, ops, drvr->settings->p2p_enable); if (drvr->config == NULL) { ret = -ENOMEM; @@ -1024,6 +1071,11 @@ static int brcmf_bus_started(struct brcmf_pub *drvr) #endif #endif /* CONFIG_INET */ + /* populate debugfs */ + brcmf_debugfs_add_entry(drvr, "revinfo", brcmf_revinfo_read); + brcmf_feat_debugfs_create(drvr); + brcmf_proto_debugfs_create(drvr); + return 0; fail: @@ -1045,17 +1097,26 @@ fail: int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings) { + struct wiphy *wiphy; + struct cfg80211_ops *ops; struct brcmf_pub *drvr = NULL; int ret = 0; int i; brcmf_dbg(TRACE, "Enter\n"); - /* Allocate primary brcmf_info */ - drvr = kzalloc(sizeof(*drvr), GFP_ATOMIC); - if (!drvr) + ops = brcmf_cfg80211_get_ops(); + if (!ops) + return -ENOMEM; + + wiphy = wiphy_new(ops, sizeof(*drvr)); + if (!wiphy) return -ENOMEM; + set_wiphy_dev(wiphy, dev); + drvr = wiphy_priv(wiphy); + drvr->wiphy = wiphy; + for (i = 0; i < ARRAY_SIZE(drvr->if2bss); i++) drvr->if2bss[i] = BRCMF_BSSIDX_INVALID; @@ -1067,9 +1128,6 @@ int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings) drvr->bus_if->drvr = drvr; drvr->settings = settings; - /* attach debug facilities */ - brcmf_debug_attach(drvr); - /* Attach and link in the protocol */ ret = brcmf_proto_attach(drvr); if (ret != 0) { @@ -1084,15 +1142,18 @@ int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings) /* attach firmware event handler */ brcmf_fweh_attach(drvr); - ret = brcmf_bus_started(drvr); + ret = brcmf_bus_started(drvr, ops); if (ret != 0) { brcmf_err("dongle is not responding: err=%d\n", ret); goto fail; } + + drvr->config->ops = ops; return 0; fail: brcmf_detach(dev); + kfree(ops); return ret; } @@ -1150,14 +1211,14 @@ void brcmf_detach(struct device *dev) brcmf_remove_interface(drvr->iflist[i], false); brcmf_cfg80211_detach(drvr->config); + drvr->config = NULL; brcmf_bus_stop(drvr->bus_if); brcmf_proto_detach(drvr); - brcmf_debug_detach(drvr); bus_if->drvr = NULL; - kfree(drvr); + wiphy_free(drvr->wiphy); } s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index 232dcbb83311..401f50458686 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -87,7 +87,6 @@ struct brcmf_rev_info { u32 vendorid; u32 deviceid; u32 radiorev; - u32 chiprev; u32 corerev; u32 boardid; u32 boardvendor; @@ -95,7 +94,7 @@ struct brcmf_rev_info { u32 driverrev; u32 ucoderev; u32 bus; - u32 chipnum; + char chipname[12]; u32 phytype; u32 phyrev; u32 anarev; @@ -108,6 +107,7 @@ struct brcmf_pub { /* Linkage ponters */ struct brcmf_bus *bus_if; struct brcmf_proto *proto; + struct wiphy *wiphy; struct brcmf_cfg80211_info *config; /* Internal brcmf items */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c index 2d3e5e263a32..504832084eca 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.c @@ -25,8 +25,6 @@ #include "fweh.h" #include "debug.h" -static struct dentry *root_folder; - int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data, size_t len) { @@ -54,44 +52,9 @@ int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data, return 0; } -void brcmf_debugfs_init(void) -{ - root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL); - if (IS_ERR(root_folder)) - root_folder = NULL; -} - -void brcmf_debugfs_exit(void) -{ - if (!root_folder) - return; - - debugfs_remove_recursive(root_folder); - root_folder = NULL; -} - -int brcmf_debug_attach(struct brcmf_pub *drvr) -{ - struct device *dev = drvr->bus_if->dev; - - if (!root_folder) - return -ENODEV; - - drvr->dbgfs_dir = debugfs_create_dir(dev_name(dev), root_folder); - return PTR_ERR_OR_ZERO(drvr->dbgfs_dir); -} - -void brcmf_debug_detach(struct brcmf_pub *drvr) -{ - brcmf_fweh_unregister(drvr, BRCMF_E_PSM_WATCHDOG); - - if (!IS_ERR_OR_NULL(drvr->dbgfs_dir)) - debugfs_remove_recursive(drvr->dbgfs_dir); -} - struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr) { - return drvr->dbgfs_dir; + return drvr->wiphy->debugfsdir; } int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn, @@ -99,7 +62,8 @@ int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn, { struct dentry *e; + WARN(!drvr->wiphy->debugfsdir, "wiphy not (yet) registered\n"); e = debugfs_create_devm_seqfile(drvr->bus_if->dev, fn, - drvr->dbgfs_dir, read_fn); + drvr->wiphy->debugfsdir, read_fn); return PTR_ERR_OR_ZERO(e); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h index 35919d9e8e13..cfed0626bf5a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/debug.h @@ -113,29 +113,12 @@ extern int brcmf_msg_level; struct brcmf_bus; struct brcmf_pub; #ifdef DEBUG -void brcmf_debugfs_init(void); -void brcmf_debugfs_exit(void); -int brcmf_debug_attach(struct brcmf_pub *drvr); -void brcmf_debug_detach(struct brcmf_pub *drvr); struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr); int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn, int (*read_fn)(struct seq_file *seq, void *data)); int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data, size_t len); #else -static inline void brcmf_debugfs_init(void) -{ -} -static inline void brcmf_debugfs_exit(void) -{ -} -static inline int brcmf_debug_attach(struct brcmf_pub *drvr) -{ - return 0; -} -static inline void brcmf_debug_detach(struct brcmf_pub *drvr) -{ -} static inline int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn, int (*read_fn)(struct seq_file *seq, void *data)) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c index bede7b7fd996..876731c57bf5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c @@ -228,7 +228,10 @@ void brcmf_feat_attach(struct brcmf_pub *drvr) /* no quirks */ break; } +} +void brcmf_feat_debugfs_create(struct brcmf_pub *drvr) +{ brcmf_debugfs_add_entry(drvr, "features", brcmf_feat_debugfs_read); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h index 1ab4f1617112..d1193825e559 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h @@ -90,6 +90,13 @@ enum brcmf_feat_quirk { void brcmf_feat_attach(struct brcmf_pub *drvr); /** + * brcmf_feat_debugfs_create() - create debugfs entries. + * + * @drvr: driver instance. + */ +void brcmf_feat_debugfs_create(struct brcmf_pub *drvr); + +/** * brcmf_feat_is_enabled() - query feature. * * @ifp: interface instance. diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c index 091b52979e03..9277f4c2bfeb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -25,6 +25,7 @@ #include "firmware.h" #include "core.h" #include "common.h" +#include "chip.h" #define BRCMF_FW_MAX_NVRAM_SIZE 64000 #define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */ @@ -437,18 +438,31 @@ void brcmf_fw_nvram_free(void *nvram) struct brcmf_fw { struct device *dev; - u16 flags; - const struct firmware *code; - const char *nvram_name; - u16 domain_nr; - u16 bus_nr; - void (*done)(struct device *dev, int err, const struct firmware *fw, - void *nvram_image, u32 nvram_len); + struct brcmf_fw_request *req; + u32 curpos; + void (*done)(struct device *dev, int err, struct brcmf_fw_request *req); }; +static void brcmf_fw_request_done(const struct firmware *fw, void *ctx); + +static void brcmf_fw_free_request(struct brcmf_fw_request *req) +{ + struct brcmf_fw_item *item; + int i; + + for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) { + if (item->type == BRCMF_FW_TYPE_BINARY) + release_firmware(item->binary); + else if (item->type == BRCMF_FW_TYPE_NVRAM) + brcmf_fw_nvram_free(item->nv_data.data); + } + kfree(req); +} + static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) { struct brcmf_fw *fwctx = ctx; + struct brcmf_fw_item *cur; u32 nvram_length = 0; void *nvram = NULL; u8 *data = NULL; @@ -456,83 +470,150 @@ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) bool raw_nvram; brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev)); + + cur = &fwctx->req->items[fwctx->curpos]; + if (fw && fw->data) { data = (u8 *)fw->data; data_len = fw->size; raw_nvram = false; } else { data = bcm47xx_nvram_get_contents(&data_len); - if (!data && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) + if (!data && !(cur->flags & BRCMF_FW_REQF_OPTIONAL)) goto fail; raw_nvram = true; } if (data) nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length, - fwctx->domain_nr, fwctx->bus_nr); + fwctx->req->domain_nr, + fwctx->req->bus_nr); if (raw_nvram) bcm47xx_nvram_release_contents(data); release_firmware(fw); - if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) + if (!nvram && !(cur->flags & BRCMF_FW_REQF_OPTIONAL)) goto fail; - fwctx->done(fwctx->dev, 0, fwctx->code, nvram, nvram_length); - kfree(fwctx); + brcmf_dbg(TRACE, "nvram %p len %d\n", nvram, nvram_length); + cur->nv_data.data = nvram; + cur->nv_data.len = nvram_length; return; fail: brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); - release_firmware(fwctx->code); - fwctx->done(fwctx->dev, -ENOENT, NULL, NULL, 0); + fwctx->done(fwctx->dev, -ENOENT, NULL); + brcmf_fw_free_request(fwctx->req); kfree(fwctx); } -static void brcmf_fw_request_code_done(const struct firmware *fw, void *ctx) +static int brcmf_fw_request_next_item(struct brcmf_fw *fwctx, bool async) +{ + struct brcmf_fw_item *cur; + const struct firmware *fw = NULL; + int ret; + + cur = &fwctx->req->items[fwctx->curpos]; + + brcmf_dbg(TRACE, "%srequest for %s\n", async ? "async " : "", + cur->path); + + if (async) + ret = request_firmware_nowait(THIS_MODULE, true, cur->path, + fwctx->dev, GFP_KERNEL, fwctx, + brcmf_fw_request_done); + else + ret = request_firmware(&fw, cur->path, fwctx->dev); + + if (ret < 0) { + brcmf_fw_request_done(NULL, fwctx); + } else if (!async && fw) { + brcmf_dbg(TRACE, "firmware %s %sfound\n", cur->path, + fw ? "" : "not "); + if (cur->type == BRCMF_FW_TYPE_BINARY) + cur->binary = fw; + else if (cur->type == BRCMF_FW_TYPE_NVRAM) + brcmf_fw_request_nvram_done(fw, fwctx); + else + release_firmware(fw); + + return -EAGAIN; + } + return 0; +} + +static void brcmf_fw_request_done(const struct firmware *fw, void *ctx) { struct brcmf_fw *fwctx = ctx; + struct brcmf_fw_item *cur; int ret = 0; - brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev)); - if (!fw) { + cur = &fwctx->req->items[fwctx->curpos]; + + brcmf_dbg(TRACE, "enter: firmware %s %sfound\n", cur->path, + fw ? "" : "not "); + + if (fw) { + if (cur->type == BRCMF_FW_TYPE_BINARY) + cur->binary = fw; + else if (cur->type == BRCMF_FW_TYPE_NVRAM) + brcmf_fw_request_nvram_done(fw, fwctx); + else + release_firmware(fw); + } else if (cur->type == BRCMF_FW_TYPE_NVRAM) { + brcmf_fw_request_nvram_done(NULL, fwctx); + } else if (!(cur->flags & BRCMF_FW_REQF_OPTIONAL)) { ret = -ENOENT; goto fail; } - /* only requested code so done here */ - if (!(fwctx->flags & BRCMF_FW_REQUEST_NVRAM)) - goto done; - fwctx->code = fw; - ret = request_firmware_nowait(THIS_MODULE, true, fwctx->nvram_name, - fwctx->dev, GFP_KERNEL, fwctx, - brcmf_fw_request_nvram_done); + do { + if (++fwctx->curpos == fwctx->req->n_items) { + ret = 0; + goto done; + } + + ret = brcmf_fw_request_next_item(fwctx, false); + } while (ret == -EAGAIN); - /* pass NULL to nvram callback for bcm47xx fallback */ - if (ret) - brcmf_fw_request_nvram_done(NULL, fwctx); return; fail: - brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); + brcmf_dbg(TRACE, "failed err=%d: dev=%s, fw=%s\n", ret, + dev_name(fwctx->dev), cur->path); + brcmf_fw_free_request(fwctx->req); + fwctx->req = NULL; done: - fwctx->done(fwctx->dev, ret, fw, NULL, 0); + fwctx->done(fwctx->dev, ret, fwctx->req); kfree(fwctx); } -int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags, - const char *code, const char *nvram, - void (*fw_cb)(struct device *dev, int err, - const struct firmware *fw, - void *nvram_image, u32 nvram_len), - u16 domain_nr, u16 bus_nr) +static bool brcmf_fw_request_is_valid(struct brcmf_fw_request *req) +{ + struct brcmf_fw_item *item; + int i; + + if (!req->n_items) + return false; + + for (i = 0, item = &req->items[0]; i < req->n_items; i++, item++) { + if (!item->path) + return false; + } + return true; +} + +int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req, + void (*fw_cb)(struct device *dev, int err, + struct brcmf_fw_request *req)) { struct brcmf_fw *fwctx; brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev)); - if (!fw_cb || !code) + if (!fw_cb) return -EINVAL; - if ((flags & BRCMF_FW_REQUEST_NVRAM) && !nvram) + if (!brcmf_fw_request_is_valid(req)) return -EINVAL; fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL); @@ -540,35 +621,25 @@ int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags, return -ENOMEM; fwctx->dev = dev; - fwctx->flags = flags; + fwctx->req = req; fwctx->done = fw_cb; - if (flags & BRCMF_FW_REQUEST_NVRAM) - fwctx->nvram_name = nvram; - fwctx->domain_nr = domain_nr; - fwctx->bus_nr = bus_nr; - - return request_firmware_nowait(THIS_MODULE, true, code, dev, - GFP_KERNEL, fwctx, - brcmf_fw_request_code_done); -} -int brcmf_fw_get_firmwares(struct device *dev, u16 flags, - const char *code, const char *nvram, - void (*fw_cb)(struct device *dev, int err, - const struct firmware *fw, - void *nvram_image, u32 nvram_len)) -{ - return brcmf_fw_get_firmwares_pcie(dev, flags, code, nvram, fw_cb, 0, - 0); + brcmf_fw_request_next_item(fwctx, true); + return 0; } -int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev, - struct brcmf_firmware_mapping mapping_table[], - u32 table_size, char fw_name[BRCMF_FW_NAME_LEN], - char nvram_name[BRCMF_FW_NAME_LEN]) +struct brcmf_fw_request * +brcmf_fw_alloc_request(u32 chip, u32 chiprev, + struct brcmf_firmware_mapping mapping_table[], + u32 table_size, struct brcmf_fw_name *fwnames, + u32 n_fwnames) { - u32 i; + struct brcmf_fw_request *fwreq; + char chipname[12]; + const char *mp_path; + u32 i, j; char end; + size_t reqsz; for (i = 0; i < table_size; i++) { if (mapping_table[i].chipid == chip && @@ -578,32 +649,41 @@ int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev, if (i == table_size) { brcmf_err("Unknown chipid %d [%d]\n", chip, chiprev); - return -ENODEV; + return NULL; } - /* check if firmware path is provided by module parameter */ - if (brcmf_mp_global.firmware_path[0] != '\0') { - strlcpy(fw_name, brcmf_mp_global.firmware_path, - BRCMF_FW_NAME_LEN); - if ((nvram_name) && (mapping_table[i].nvram)) - strlcpy(nvram_name, brcmf_mp_global.firmware_path, + reqsz = sizeof(*fwreq) + n_fwnames * sizeof(struct brcmf_fw_item); + fwreq = kzalloc(reqsz, GFP_KERNEL); + if (!fwreq) + return NULL; + + brcmf_chip_name(chip, chiprev, chipname, sizeof(chipname)); + + brcmf_info("using %s for chip %s\n", + mapping_table[i].fw_base, chipname); + + mp_path = brcmf_mp_global.firmware_path; + end = mp_path[strlen(mp_path) - 1]; + fwreq->n_items = n_fwnames; + + for (j = 0; j < n_fwnames; j++) { + fwreq->items[j].path = fwnames[j].path; + /* check if firmware path is provided by module parameter */ + if (brcmf_mp_global.firmware_path[0] != '\0') { + strlcpy(fwnames[j].path, mp_path, BRCMF_FW_NAME_LEN); - end = brcmf_mp_global.firmware_path[ - strlen(brcmf_mp_global.firmware_path) - 1]; - if (end != '/') { - strlcat(fw_name, "/", BRCMF_FW_NAME_LEN); - if ((nvram_name) && (mapping_table[i].nvram)) - strlcat(nvram_name, "/", BRCMF_FW_NAME_LEN); + if (end != '/') { + strlcat(fwnames[j].path, "/", + BRCMF_FW_NAME_LEN); + } } + strlcat(fwnames[j].path, mapping_table[i].fw_base, + BRCMF_FW_NAME_LEN); + strlcat(fwnames[j].path, fwnames[j].extension, + BRCMF_FW_NAME_LEN); + fwreq->items[j].path = fwnames[j].path; } - strlcat(fw_name, mapping_table[i].fw, BRCMF_FW_NAME_LEN); - if ((nvram_name) && (mapping_table[i].nvram)) - strlcat(nvram_name, mapping_table[i].nvram, BRCMF_FW_NAME_LEN); - brcmf_info("using %s for chip %#08x(%d) rev %#08x\n", - fw_name, chip, chip, chiprev); - - return 0; + return fwreq; } - diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h index 8fa4b7e1ab3d..79a21095c349 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.h @@ -16,10 +16,7 @@ #ifndef BRCMFMAC_FIRMWARE_H #define BRCMFMAC_FIRMWARE_H -#define BRCMF_FW_REQUEST 0x000F -#define BRCMF_FW_REQUEST_NVRAM 0x0001 -#define BRCMF_FW_REQ_FLAGS 0x00F0 -#define BRCMF_FW_REQ_NV_OPTIONAL 0x0010 +#define BRCMF_FW_REQF_OPTIONAL 0x0001 #define BRCMF_FW_NAME_LEN 320 @@ -38,49 +35,62 @@ struct brcmf_firmware_mapping { u32 chipid; u32 revmask; - const char *fw; - const char *nvram; + const char *fw_base; }; -#define BRCMF_FW_NVRAM_DEF(fw_nvram_name, fw, nvram) \ -static const char BRCM_ ## fw_nvram_name ## _FIRMWARE_NAME[] = \ - BRCMF_FW_DEFAULT_PATH fw; \ -static const char BRCM_ ## fw_nvram_name ## _NVRAM_NAME[] = \ - BRCMF_FW_DEFAULT_PATH nvram; \ -MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw); - -#define BRCMF_FW_DEF(fw_name, fw) \ -static const char BRCM_ ## fw_name ## _FIRMWARE_NAME[] = \ - BRCMF_FW_DEFAULT_PATH fw; \ -MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw) \ - -#define BRCMF_FW_NVRAM_ENTRY(chipid, mask, name) \ - { chipid, mask, \ - BRCM_ ## name ## _FIRMWARE_NAME, BRCM_ ## name ## _NVRAM_NAME } +#define BRCMF_FW_DEF(fw_name, fw_base) \ +static const char BRCM_ ## fw_name ## _FIRMWARE_BASENAME[] = \ + BRCMF_FW_DEFAULT_PATH fw_base; \ +MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".bin") #define BRCMF_FW_ENTRY(chipid, mask, name) \ - { chipid, mask, BRCM_ ## name ## _FIRMWARE_NAME, NULL } + { chipid, mask, BRCM_ ## name ## _FIRMWARE_BASENAME } -int brcmf_fw_map_chip_to_name(u32 chip, u32 chiprev, - struct brcmf_firmware_mapping mapping_table[], - u32 table_size, char fw_name[BRCMF_FW_NAME_LEN], - char nvram_name[BRCMF_FW_NAME_LEN]); void brcmf_fw_nvram_free(void *nvram); + +enum brcmf_fw_type { + BRCMF_FW_TYPE_BINARY, + BRCMF_FW_TYPE_NVRAM +}; + +struct brcmf_fw_item { + const char *path; + enum brcmf_fw_type type; + u16 flags; + union { + const struct firmware *binary; + struct { + void *data; + u32 len; + } nv_data; + }; +}; + +struct brcmf_fw_request { + u16 domain_nr; + u16 bus_nr; + u32 n_items; + struct brcmf_fw_item items[0]; +}; + +struct brcmf_fw_name { + const char *extension; + char *path; +}; + +struct brcmf_fw_request * +brcmf_fw_alloc_request(u32 chip, u32 chiprev, + struct brcmf_firmware_mapping mapping_table[], + u32 table_size, struct brcmf_fw_name *fwnames, + u32 n_fwnames); + /* * Request firmware(s) asynchronously. When the asynchronous request * fails it will not use the callback, but call device_release_driver() * instead which will call the driver .remove() callback. */ -int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags, - const char *code, const char *nvram, - void (*fw_cb)(struct device *dev, int err, - const struct firmware *fw, - void *nvram_image, u32 nvram_len), - u16 domain_nr, u16 bus_nr); -int brcmf_fw_get_firmwares(struct device *dev, u16 flags, - const char *code, const char *nvram, +int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req, void (*fw_cb)(struct device *dev, int err, - const struct firmware *fw, - void *nvram_image, u32 nvram_len)); + struct brcmf_fw_request *req)); #endif /* BRCMFMAC_FIRMWARE_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c index fc5751116d99..802d7cb73b80 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.c @@ -124,8 +124,7 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set) data, len, &fwerr); if (err) { - brcmf_dbg(FIL, "Failed: %s (%d)\n", - brcmf_fil_get_errstr((u32)(-err)), err); + brcmf_dbg(FIL, "Failed: error=%d\n", err); } else if (fwerr < 0) { brcmf_dbg(FIL, "Firmware error: %s (%d)\n", brcmf_fil_get_errstr((u32)(-fwerr)), fwerr); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c index f59642b2c935..f3cbf78c8899 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c @@ -2399,10 +2399,6 @@ struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr) brcmu_pktq_init(&fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT, BRCMF_FWS_PSQ_LEN); - /* create debugfs file for statistics */ - brcmf_debugfs_add_entry(drvr, "fws_stats", - brcmf_debugfs_fws_stats_read); - brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n", fws->fw_signals ? "enabled" : "disabled", tlv); return fws; @@ -2429,6 +2425,13 @@ void brcmf_fws_detach(struct brcmf_fws_info *fws) kfree(fws); } +void brcmf_fws_debugfs_create(struct brcmf_pub *drvr) +{ + /* create debugfs file for statistics */ + brcmf_debugfs_add_entry(drvr, "fws_stats", + brcmf_debugfs_fws_stats_read); +} + bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws) { return !fws->avoid_queueing; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h index ba07bd972002..4e6835766d5d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h @@ -20,6 +20,7 @@ struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr); void brcmf_fws_detach(struct brcmf_fws_info *fws); +void brcmf_fws_debugfs_create(struct brcmf_pub *drvr); bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws); bool brcmf_fws_fc_active(struct brcmf_fws_info *fws); void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c index e212a791a072..49d37ad96958 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c @@ -1418,6 +1418,11 @@ static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data) } #endif +static void brcmf_msgbuf_debugfs_create(struct brcmf_pub *drvr) +{ + brcmf_debugfs_add_entry(drvr, "msgbuf_stats", brcmf_msgbuf_stats_read); +} + int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) { struct brcmf_bus_msgbuf *if_msgbuf; @@ -1472,6 +1477,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) drvr->proto->delete_peer = brcmf_msgbuf_delete_peer; drvr->proto->add_tdls_peer = brcmf_msgbuf_add_tdls_peer; drvr->proto->rxreorder = brcmf_msgbuf_rxreorder; + drvr->proto->debugfs_create = brcmf_msgbuf_debugfs_create; drvr->proto->pd = msgbuf; init_waitqueue_head(&msgbuf->ioctl_resp_wait); @@ -1525,8 +1531,6 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) spin_lock_init(&msgbuf->flowring_work_lock); INIT_LIST_HEAD(&msgbuf->work_queue); - brcmf_debugfs_add_entry(drvr, "msgbuf_stats", brcmf_msgbuf_stats_read); - return 0; fail: diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index 82064e909784..bcef208a81a5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -2227,7 +2227,7 @@ fail: */ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) { - struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_p2p_info *p2p = &cfg->p2p; struct brcmf_cfg80211_vif *vif; enum nl80211_iftype iftype; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index a7d827ce1684..091c191ce259 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -46,36 +46,36 @@ enum brcmf_pcie_state { BRCMFMAC_PCIE_STATE_UP }; -BRCMF_FW_NVRAM_DEF(43602, "brcmfmac43602-pcie.bin", "brcmfmac43602-pcie.txt"); -BRCMF_FW_NVRAM_DEF(4350, "brcmfmac4350-pcie.bin", "brcmfmac4350-pcie.txt"); -BRCMF_FW_NVRAM_DEF(4350C, "brcmfmac4350c2-pcie.bin", "brcmfmac4350c2-pcie.txt"); -BRCMF_FW_NVRAM_DEF(4356, "brcmfmac4356-pcie.bin", "brcmfmac4356-pcie.txt"); -BRCMF_FW_NVRAM_DEF(43570, "brcmfmac43570-pcie.bin", "brcmfmac43570-pcie.txt"); -BRCMF_FW_NVRAM_DEF(4358, "brcmfmac4358-pcie.bin", "brcmfmac4358-pcie.txt"); -BRCMF_FW_NVRAM_DEF(4359, "brcmfmac4359-pcie.bin", "brcmfmac4359-pcie.txt"); -BRCMF_FW_NVRAM_DEF(4365B, "brcmfmac4365b-pcie.bin", "brcmfmac4365b-pcie.txt"); -BRCMF_FW_NVRAM_DEF(4365C, "brcmfmac4365c-pcie.bin", "brcmfmac4365c-pcie.txt"); -BRCMF_FW_NVRAM_DEF(4366B, "brcmfmac4366b-pcie.bin", "brcmfmac4366b-pcie.txt"); -BRCMF_FW_NVRAM_DEF(4366C, "brcmfmac4366c-pcie.bin", "brcmfmac4366c-pcie.txt"); -BRCMF_FW_NVRAM_DEF(4371, "brcmfmac4371-pcie.bin", "brcmfmac4371-pcie.txt"); +BRCMF_FW_DEF(43602, "brcmfmac43602-pcie"); +BRCMF_FW_DEF(4350, "brcmfmac4350-pcie"); +BRCMF_FW_DEF(4350C, "brcmfmac4350c2-pcie"); +BRCMF_FW_DEF(4356, "brcmfmac4356-pcie"); +BRCMF_FW_DEF(43570, "brcmfmac43570-pcie"); +BRCMF_FW_DEF(4358, "brcmfmac4358-pcie"); +BRCMF_FW_DEF(4359, "brcmfmac4359-pcie"); +BRCMF_FW_DEF(4365B, "brcmfmac4365b-pcie"); +BRCMF_FW_DEF(4365C, "brcmfmac4365c-pcie"); +BRCMF_FW_DEF(4366B, "brcmfmac4366b-pcie"); +BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie"); +BRCMF_FW_DEF(4371, "brcmfmac4371-pcie"); static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43465_CHIP_ID, 0xFFFFFFF0, 4366C), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4350_CHIP_ID, 0x000000FF, 4350C), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4350_CHIP_ID, 0xFFFFFF00, 4350), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43525_CHIP_ID, 0xFFFFFFF0, 4365C), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43567_CHIP_ID, 0xFFFFFFFF, 43570), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43570), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43570_CHIP_ID, 0xFFFFFFFF, 43570), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0x0000000F, 4365B), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFF0, 4365C), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), + BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602), + BRCMF_FW_ENTRY(BRCM_CC_43465_CHIP_ID, 0xFFFFFFF0, 4366C), + BRCMF_FW_ENTRY(BRCM_CC_4350_CHIP_ID, 0x000000FF, 4350C), + BRCMF_FW_ENTRY(BRCM_CC_4350_CHIP_ID, 0xFFFFFF00, 4350), + BRCMF_FW_ENTRY(BRCM_CC_43525_CHIP_ID, 0xFFFFFFF0, 4365C), + BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), + BRCMF_FW_ENTRY(BRCM_CC_43567_CHIP_ID, 0xFFFFFFFF, 43570), + BRCMF_FW_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43570), + BRCMF_FW_ENTRY(BRCM_CC_43570_CHIP_ID, 0xFFFFFFFF, 43570), + BRCMF_FW_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358), + BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), + BRCMF_FW_ENTRY(BRCM_CC_4365_CHIP_ID, 0x0000000F, 4365B), + BRCMF_FW_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFF0, 4365C), + BRCMF_FW_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B), + BRCMF_FW_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C), + BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), }; #define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */ @@ -1350,23 +1350,24 @@ static int brcmf_pcie_get_memdump(struct device *dev, void *data, size_t len) return 0; } -static int brcmf_pcie_get_fwname(struct device *dev, u32 chip, u32 chiprev, - u8 *fw_name) +static +int brcmf_pcie_get_fwname(struct device *dev, const char *ext, u8 *fw_name) { struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie; - struct brcmf_pciedev_info *devinfo = buspub->devinfo; - int ret = 0; - - if (devinfo->fw_name[0] != '\0') - strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN); - else - ret = brcmf_fw_map_chip_to_name(chip, chiprev, - brcmf_pcie_fwnames, - ARRAY_SIZE(brcmf_pcie_fwnames), - fw_name, NULL); - - return ret; + struct brcmf_fw_request *fwreq; + struct brcmf_fw_name fwnames[] = { + { ext, fw_name }, + }; + + fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev, + brcmf_pcie_fwnames, + ARRAY_SIZE(brcmf_pcie_fwnames), + fwnames, ARRAY_SIZE(fwnames)); + if (!fwreq) + return -ENOMEM; + + kfree(fwreq); + return 0; } static const struct brcmf_bus_ops brcmf_pcie_bus_ops = { @@ -1651,15 +1652,19 @@ static const struct brcmf_buscore_ops brcmf_pcie_buscore_ops = { .write32 = brcmf_pcie_buscore_write32, }; +#define BRCMF_PCIE_FW_CODE 0 +#define BRCMF_PCIE_FW_NVRAM 1 + static void brcmf_pcie_setup(struct device *dev, int ret, - const struct firmware *fw, - void *nvram, u32 nvram_len) + struct brcmf_fw_request *fwreq) { + const struct firmware *fw; + void *nvram; struct brcmf_bus *bus; struct brcmf_pciedev *pcie_bus_dev; struct brcmf_pciedev_info *devinfo; struct brcmf_commonring **flowrings; - u32 i; + u32 i, nvram_len; /* check firmware loading result */ if (ret) @@ -1670,6 +1675,11 @@ static void brcmf_pcie_setup(struct device *dev, int ret, devinfo = pcie_bus_dev->devinfo; brcmf_pcie_attach(devinfo); + fw = fwreq->items[BRCMF_PCIE_FW_CODE].binary; + nvram = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.data; + nvram_len = fwreq->items[BRCMF_PCIE_FW_NVRAM].nv_data.len; + kfree(fwreq); + /* Some of the firmwares have the size of the memory of the device * defined inside the firmware. This is because part of the memory in * the device is shared and the devision is determined by FW. Parse @@ -1726,20 +1736,41 @@ fail: device_release_driver(dev); } +static struct brcmf_fw_request * +brcmf_pcie_prepare_fw_request(struct brcmf_pciedev_info *devinfo) +{ + struct brcmf_fw_request *fwreq; + struct brcmf_fw_name fwnames[] = { + { ".bin", devinfo->fw_name }, + { ".txt", devinfo->nvram_name }, + }; + + fwreq = brcmf_fw_alloc_request(devinfo->ci->chip, devinfo->ci->chiprev, + brcmf_pcie_fwnames, + ARRAY_SIZE(brcmf_pcie_fwnames), + fwnames, ARRAY_SIZE(fwnames)); + if (!fwreq) + return NULL; + + fwreq->items[BRCMF_PCIE_FW_CODE].type = BRCMF_FW_TYPE_BINARY; + fwreq->items[BRCMF_PCIE_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM; + fwreq->items[BRCMF_PCIE_FW_NVRAM].flags = BRCMF_FW_REQF_OPTIONAL; + fwreq->domain_nr = pci_domain_nr(devinfo->pdev->bus); + fwreq->bus_nr = devinfo->pdev->bus->number; + + return fwreq; +} + static int brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int ret; + struct brcmf_fw_request *fwreq; struct brcmf_pciedev_info *devinfo; struct brcmf_pciedev *pcie_bus_dev; struct brcmf_bus *bus; - u16 domain_nr; - u16 bus_nr; - domain_nr = pci_domain_nr(pdev->bus) + 1; - bus_nr = pdev->bus->number; - brcmf_dbg(PCIE, "Enter %x:%x (%d/%d)\n", pdev->vendor, pdev->device, - domain_nr, bus_nr); + brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device); ret = -ENOMEM; devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); @@ -1793,19 +1824,19 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) bus->wowl_supported = pci_pme_capable(pdev, PCI_D3hot); dev_set_drvdata(&pdev->dev, bus); - ret = brcmf_fw_map_chip_to_name(devinfo->ci->chip, devinfo->ci->chiprev, - brcmf_pcie_fwnames, - ARRAY_SIZE(brcmf_pcie_fwnames), - devinfo->fw_name, devinfo->nvram_name); - if (ret) + fwreq = brcmf_pcie_prepare_fw_request(devinfo); + if (!fwreq) { + ret = -ENOMEM; goto fail_bus; + } + + ret = brcmf_fw_get_firmwares(bus->dev, fwreq, brcmf_pcie_setup); + if (ret < 0) { + kfree(fwreq); + goto fail_bus; + } + return 0; - ret = brcmf_fw_get_firmwares_pcie(bus->dev, BRCMF_FW_REQUEST_NVRAM | - BRCMF_FW_REQ_NV_OPTIONAL, - devinfo->fw_name, devinfo->nvram_name, - brcmf_pcie_setup, domain_nr, bus_nr); - if (ret == 0) - return 0; fail_bus: kfree(bus->msgbuf); kfree(bus); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c index d26ff219ef66..c5ff551ec659 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.c @@ -54,7 +54,8 @@ int brcmf_proto_attach(struct brcmf_pub *drvr) if (!proto->tx_queue_data || (proto->hdrpull == NULL) || (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL) || (proto->configure_addr_mode == NULL) || - (proto->delete_peer == NULL) || (proto->add_tdls_peer == NULL)) { + (proto->delete_peer == NULL) || (proto->add_tdls_peer == NULL) || + (proto->debugfs_create == NULL)) { brcmf_err("Not all proto handlers have been installed\n"); goto fail; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h index 8a8e08f09ea0..d3c3b9a815ad 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h @@ -48,6 +48,7 @@ struct brcmf_proto { void (*del_if)(struct brcmf_if *ifp); void (*reset_if)(struct brcmf_if *ifp); int (*init_done)(struct brcmf_pub *drvr); + void (*debugfs_create)(struct brcmf_pub *drvr); void *pd; }; @@ -156,4 +157,10 @@ brcmf_proto_init_done(struct brcmf_pub *drvr) return drvr->proto->init_done(drvr); } +static inline void +brcmf_proto_debugfs_create(struct brcmf_pub *drvr) +{ + drvr->proto->debugfs_create(drvr); +} + #endif /* BRCMFMAC_PROTO_H */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index 4a6459a429ec..1037df7297bb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -600,47 +600,44 @@ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = { {4, 0x1} }; -BRCMF_FW_NVRAM_DEF(43143, "brcmfmac43143-sdio.bin", "brcmfmac43143-sdio.txt"); -BRCMF_FW_NVRAM_DEF(43241B0, "brcmfmac43241b0-sdio.bin", - "brcmfmac43241b0-sdio.txt"); -BRCMF_FW_NVRAM_DEF(43241B4, "brcmfmac43241b4-sdio.bin", - "brcmfmac43241b4-sdio.txt"); -BRCMF_FW_NVRAM_DEF(43241B5, "brcmfmac43241b5-sdio.bin", - "brcmfmac43241b5-sdio.txt"); -BRCMF_FW_NVRAM_DEF(4329, "brcmfmac4329-sdio.bin", "brcmfmac4329-sdio.txt"); -BRCMF_FW_NVRAM_DEF(4330, "brcmfmac4330-sdio.bin", "brcmfmac4330-sdio.txt"); -BRCMF_FW_NVRAM_DEF(4334, "brcmfmac4334-sdio.bin", "brcmfmac4334-sdio.txt"); -BRCMF_FW_NVRAM_DEF(43340, "brcmfmac43340-sdio.bin", "brcmfmac43340-sdio.txt"); -BRCMF_FW_NVRAM_DEF(4335, "brcmfmac4335-sdio.bin", "brcmfmac4335-sdio.txt"); -BRCMF_FW_NVRAM_DEF(43362, "brcmfmac43362-sdio.bin", "brcmfmac43362-sdio.txt"); -BRCMF_FW_NVRAM_DEF(4339, "brcmfmac4339-sdio.bin", "brcmfmac4339-sdio.txt"); -BRCMF_FW_NVRAM_DEF(43430A0, "brcmfmac43430a0-sdio.bin", "brcmfmac43430a0-sdio.txt"); +BRCMF_FW_DEF(43143, "brcmfmac43143-sdio"); +BRCMF_FW_DEF(43241B0, "brcmfmac43241b0-sdio"); +BRCMF_FW_DEF(43241B4, "brcmfmac43241b4-sdio"); +BRCMF_FW_DEF(43241B5, "brcmfmac43241b5-sdio"); +BRCMF_FW_DEF(4329, "brcmfmac4329-sdio"); +BRCMF_FW_DEF(4330, "brcmfmac4330-sdio"); +BRCMF_FW_DEF(4334, "brcmfmac4334-sdio"); +BRCMF_FW_DEF(43340, "brcmfmac43340-sdio"); +BRCMF_FW_DEF(4335, "brcmfmac4335-sdio"); +BRCMF_FW_DEF(43362, "brcmfmac43362-sdio"); +BRCMF_FW_DEF(4339, "brcmfmac4339-sdio"); +BRCMF_FW_DEF(43430A0, "brcmfmac43430a0-sdio"); /* Note the names are not postfixed with a1 for backward compatibility */ -BRCMF_FW_NVRAM_DEF(43430A1, "brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt"); -BRCMF_FW_NVRAM_DEF(43455, "brcmfmac43455-sdio.bin", "brcmfmac43455-sdio.txt"); -BRCMF_FW_NVRAM_DEF(4354, "brcmfmac4354-sdio.bin", "brcmfmac4354-sdio.txt"); -BRCMF_FW_NVRAM_DEF(4356, "brcmfmac4356-sdio.bin", "brcmfmac4356-sdio.txt"); -BRCMF_FW_NVRAM_DEF(4373, "brcmfmac4373-sdio.bin", "brcmfmac4373-sdio.txt"); +BRCMF_FW_DEF(43430A1, "brcmfmac43430-sdio"); +BRCMF_FW_DEF(43455, "brcmfmac43455-sdio"); +BRCMF_FW_DEF(4354, "brcmfmac4354-sdio"); +BRCMF_FW_DEF(4356, "brcmfmac4356-sdio"); +BRCMF_FW_DEF(4373, "brcmfmac4373-sdio"); static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43241_CHIP_ID, 0xFFFFFFC0, 43241B5), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, 4329), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, 4330), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, 4334), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, 43340), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43340), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), - BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), - BRCMF_FW_NVRAM_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373) + BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), + BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0), + BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4), + BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0xFFFFFFC0, 43241B5), + BRCMF_FW_ENTRY(BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, 4329), + BRCMF_FW_ENTRY(BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, 4330), + BRCMF_FW_ENTRY(BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, 4334), + BRCMF_FW_ENTRY(BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, 43340), + BRCMF_FW_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43340), + BRCMF_FW_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335), + BRCMF_FW_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362), + BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), + BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0), + BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1), + BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455), + BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), + BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), + BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373) }; static void pkt_align(struct sk_buff *p, int len, int align) @@ -4003,22 +4000,24 @@ brcmf_sdio_watchdog(struct timer_list *t) } } -static int brcmf_sdio_get_fwname(struct device *dev, u32 chip, u32 chiprev, - u8 *fw_name) +static +int brcmf_sdio_get_fwname(struct device *dev, const char *ext, u8 *fw_name) { struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; - int ret = 0; - - if (sdiodev->fw_name[0] != '\0') - strlcpy(fw_name, sdiodev->fw_name, BRCMF_FW_NAME_LEN); - else - ret = brcmf_fw_map_chip_to_name(chip, chiprev, - brcmf_sdio_fwnames, - ARRAY_SIZE(brcmf_sdio_fwnames), - fw_name, NULL); + struct brcmf_fw_request *fwreq; + struct brcmf_fw_name fwnames[] = { + { ext, fw_name }, + }; + + fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev, + brcmf_sdio_fwnames, + ARRAY_SIZE(brcmf_sdio_fwnames), + fwnames, ARRAY_SIZE(fwnames)); + if (!fwreq) + return -ENOMEM; - return ret; + kfree(fwreq); + return 0; } static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { @@ -4034,14 +4033,19 @@ static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { .get_fwname = brcmf_sdio_get_fwname, }; +#define BRCMF_SDIO_FW_CODE 0 +#define BRCMF_SDIO_FW_NVRAM 1 + static void brcmf_sdio_firmware_callback(struct device *dev, int err, - const struct firmware *code, - void *nvram, u32 nvram_len) + struct brcmf_fw_request *fwreq) { struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiod = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiod->bus; struct brcmf_core *core = bus->sdio_core; + const struct firmware *code; + void *nvram; + u32 nvram_len; u8 saveclk; brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err); @@ -4049,6 +4053,11 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, if (err) goto fail; + code = fwreq->items[BRCMF_SDIO_FW_CODE].binary; + nvram = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.data; + nvram_len = fwreq->items[BRCMF_SDIO_FW_NVRAM].nv_data.len; + kfree(fwreq); + /* try to download image and nvram to the dongle */ bus->alp_only = true; err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len); @@ -4148,11 +4157,34 @@ fail: device_release_driver(dev); } +static struct brcmf_fw_request * +brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus) +{ + struct brcmf_fw_request *fwreq; + struct brcmf_fw_name fwnames[] = { + { ".bin", bus->sdiodev->fw_name }, + { ".txt", bus->sdiodev->nvram_name }, + }; + + fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev, + brcmf_sdio_fwnames, + ARRAY_SIZE(brcmf_sdio_fwnames), + fwnames, ARRAY_SIZE(fwnames)); + if (!fwreq) + return NULL; + + fwreq->items[BRCMF_SDIO_FW_CODE].type = BRCMF_FW_TYPE_BINARY; + fwreq->items[BRCMF_SDIO_FW_NVRAM].type = BRCMF_FW_TYPE_NVRAM; + + return fwreq; +} + struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) { int ret; struct brcmf_sdio *bus; struct workqueue_struct *wq; + struct brcmf_fw_request *fwreq; brcmf_dbg(TRACE, "Enter\n"); @@ -4235,18 +4267,17 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) brcmf_dbg(INFO, "completed!!\n"); - ret = brcmf_fw_map_chip_to_name(bus->ci->chip, bus->ci->chiprev, - brcmf_sdio_fwnames, - ARRAY_SIZE(brcmf_sdio_fwnames), - sdiodev->fw_name, sdiodev->nvram_name); - if (ret) + fwreq = brcmf_sdio_prepare_fw_request(bus); + if (!fwreq) { + ret = -ENOMEM; goto fail; + } - ret = brcmf_fw_get_firmwares(sdiodev->dev, BRCMF_FW_REQUEST_NVRAM, - sdiodev->fw_name, sdiodev->nvram_name, + ret = brcmf_fw_get_firmwares(sdiodev->dev, fwreq, brcmf_sdio_firmware_callback); if (ret != 0) { brcmf_err("async firmware request failed: %d\n", ret); + kfree(fwreq); goto fail; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index 41642dda40fd..a0873adcc01c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -46,11 +46,11 @@ #define BRCMF_USB_CBCTL_READ 1 #define BRCMF_USB_MAX_PKT_SIZE 1600 -BRCMF_FW_DEF(43143, "brcmfmac43143.bin"); -BRCMF_FW_DEF(43236B, "brcmfmac43236b.bin"); -BRCMF_FW_DEF(43242A, "brcmfmac43242a.bin"); -BRCMF_FW_DEF(43569, "brcmfmac43569.bin"); -BRCMF_FW_DEF(4373, "brcmfmac4373.bin"); +BRCMF_FW_DEF(43143, "brcmfmac43143"); +BRCMF_FW_DEF(43236B, "brcmfmac43236b"); +BRCMF_FW_DEF(43242A, "brcmfmac43242a"); +BRCMF_FW_DEF(43569, "brcmfmac43569"); +BRCMF_FW_DEF(4373, "brcmfmac4373"); static struct brcmf_firmware_mapping brcmf_usb_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), @@ -1128,21 +1128,24 @@ static void brcmf_usb_wowl_config(struct device *dev, bool enabled) device_set_wakeup_enable(devinfo->dev, false); } -static int brcmf_usb_get_fwname(struct device *dev, u32 chip, u32 chiprev, - u8 *fw_name) +static +int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name) { - struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); - int ret = 0; - - if (devinfo->fw_name[0] != '\0') - strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN); - else - ret = brcmf_fw_map_chip_to_name(chip, chiprev, - brcmf_usb_fwnames, - ARRAY_SIZE(brcmf_usb_fwnames), - fw_name, NULL); + struct brcmf_bus *bus = dev_get_drvdata(dev); + struct brcmf_fw_request *fwreq; + struct brcmf_fw_name fwnames[] = { + { ext, fw_name }, + }; + + fwreq = brcmf_fw_alloc_request(bus->chip, bus->chiprev, + brcmf_usb_fwnames, + ARRAY_SIZE(brcmf_usb_fwnames), + fwnames, ARRAY_SIZE(fwnames)); + if (!fwreq) + return -ENOMEM; - return ret; + kfree(fwreq); + return 0; } static const struct brcmf_bus_ops brcmf_usb_bus_ops = { @@ -1155,18 +1158,23 @@ static const struct brcmf_bus_ops brcmf_usb_bus_ops = { .get_fwname = brcmf_usb_get_fwname, }; +#define BRCMF_USB_FW_CODE 0 + static void brcmf_usb_probe_phase2(struct device *dev, int ret, - const struct firmware *fw, - void *nvram, u32 nvlen) + struct brcmf_fw_request *fwreq) { struct brcmf_bus *bus = dev_get_drvdata(dev); struct brcmf_usbdev_info *devinfo = bus->bus_priv.usb->devinfo; + const struct firmware *fw; if (ret) goto error; brcmf_dbg(USB, "Start fw downloading\n"); + fw = fwreq->items[BRCMF_USB_FW_CODE].binary; + kfree(fwreq); + ret = check_file(fw->data); if (ret < 0) { brcmf_err("invalid firmware\n"); @@ -1195,11 +1203,33 @@ error: device_release_driver(dev); } +static struct brcmf_fw_request * +brcmf_usb_prepare_fw_request(struct brcmf_usbdev_info *devinfo) +{ + struct brcmf_fw_request *fwreq; + struct brcmf_fw_name fwnames[] = { + { ".bin", devinfo->fw_name }, + }; + + fwreq = brcmf_fw_alloc_request(devinfo->bus_pub.devid, + devinfo->bus_pub.chiprev, + brcmf_usb_fwnames, + ARRAY_SIZE(brcmf_usb_fwnames), + fwnames, ARRAY_SIZE(fwnames)); + if (!fwreq) + return NULL; + + fwreq->items[BRCMF_USB_FW_CODE].type = BRCMF_FW_TYPE_BINARY; + + return fwreq; +} + static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) { struct brcmf_bus *bus = NULL; struct brcmf_usbdev *bus_pub = NULL; struct device *dev = devinfo->dev; + struct brcmf_fw_request *fwreq; int ret; brcmf_dbg(USB, "Enter\n"); @@ -1243,18 +1273,17 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo) bus->chip = bus_pub->devid; bus->chiprev = bus_pub->chiprev; - ret = brcmf_fw_map_chip_to_name(bus_pub->devid, bus_pub->chiprev, - brcmf_usb_fwnames, - ARRAY_SIZE(brcmf_usb_fwnames), - devinfo->fw_name, NULL); - if (ret) + fwreq = brcmf_usb_prepare_fw_request(devinfo); + if (!fwreq) { + ret = -ENOMEM; goto fail; + } /* request firmware here */ - ret = brcmf_fw_get_firmwares(dev, 0, devinfo->fw_name, NULL, - brcmf_usb_probe_phase2); + ret = brcmf_fw_get_firmwares(dev, fwreq, brcmf_usb_probe_phase2); if (ret) { brcmf_err("firmware request failed: %d\n", ret); + kfree(fwreq); goto fail; } @@ -1447,11 +1476,20 @@ static int brcmf_usb_reset_resume(struct usb_interface *intf) { struct usb_device *usb = interface_to_usbdev(intf); struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); + struct brcmf_fw_request *fwreq; + int ret; brcmf_dbg(USB, "Enter\n"); - return brcmf_fw_get_firmwares(&usb->dev, 0, devinfo->fw_name, NULL, - brcmf_usb_probe_phase2); + fwreq = brcmf_usb_prepare_fw_request(devinfo); + if (!fwreq) + return -ENOMEM; + + ret = brcmf_fw_get_firmwares(&usb->dev, fwreq, brcmf_usb_probe_phase2); + if (ret < 0) + kfree(fwreq); + + return ret; } #define BRCMF_USB_DEVICE(dev_id) \ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c index 7a1fbb2e3a71..2fe1f6863278 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/debug.c @@ -214,7 +214,7 @@ brcms_debugfs_add_entry(struct brcms_pub *drvr, const char *fn, entry->read = read_fn; entry->drvr = drvr; - dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry, + dentry = debugfs_create_file(fn, 0444, dentry, entry, &brcms_debugfs_def_ops); return PTR_ERR_OR_ZERO(dentry); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index ddfdfe177e24..ecc89e718b9c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -108,7 +108,7 @@ MODULE_DEVICE_TABLE(bcma, brcms_coreid_table); * flags are specified by the BRCM_DL_* macros in * drivers/net/wireless/brcm80211/include/defs.h. */ -module_param_named(debug, brcm_msg_level, uint, S_IRUGO | S_IWUSR); +module_param_named(debug, brcm_msg_level, uint, 0644); #endif static struct ieee80211_channel brcms_2ghz_chantable[] = { @@ -1563,7 +1563,7 @@ void brcms_free_timer(struct brcms_timer *t) } /* - * precondition: perimeter lock has been acquired + * precondition: no locking required */ int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx) { @@ -1578,7 +1578,7 @@ int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx) if (le32_to_cpu(hdr->idx) == idx) { pdata = wl->fw.fw_bin[i]->data + le32_to_cpu(hdr->offset); - *pbuf = kmemdup(pdata, len, GFP_ATOMIC); + *pbuf = kmemdup(pdata, len, GFP_KERNEL); if (*pbuf == NULL) goto fail; diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c index 54201c02fdb8..ce0fbf83285f 100644 --- a/drivers/net/wireless/cisco/airo.c +++ b/drivers/net/wireless/cisco/airo.c @@ -4519,21 +4519,21 @@ static int setup_proc_entry( struct net_device *dev, proc_set_user(apriv->proc_entry, proc_kuid, proc_kgid); /* Setup the StatsDelta */ - entry = proc_create_data("StatsDelta", S_IRUGO & proc_perm, + entry = proc_create_data("StatsDelta", 0444 & proc_perm, apriv->proc_entry, &proc_statsdelta_ops, dev); if (!entry) goto fail; proc_set_user(entry, proc_kuid, proc_kgid); /* Setup the Stats */ - entry = proc_create_data("Stats", S_IRUGO & proc_perm, + entry = proc_create_data("Stats", 0444 & proc_perm, apriv->proc_entry, &proc_stats_ops, dev); if (!entry) goto fail; proc_set_user(entry, proc_kuid, proc_kgid); /* Setup the Status */ - entry = proc_create_data("Status", S_IRUGO & proc_perm, + entry = proc_create_data("Status", 0444 & proc_perm, apriv->proc_entry, &proc_status_ops, dev); if (!entry) goto fail; diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index 19c442cb93e4..236b52423506 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -3538,7 +3538,7 @@ static ssize_t show_pci(struct device *d, struct device_attribute *attr, return out - buf; } -static DEVICE_ATTR(pci, S_IRUGO, show_pci, NULL); +static DEVICE_ATTR(pci, 0444, show_pci, NULL); static ssize_t show_cfg(struct device *d, struct device_attribute *attr, char *buf) @@ -3547,7 +3547,7 @@ static ssize_t show_cfg(struct device *d, struct device_attribute *attr, return sprintf(buf, "0x%08x\n", (int)p->config); } -static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); +static DEVICE_ATTR(cfg, 0444, show_cfg, NULL); static ssize_t show_status(struct device *d, struct device_attribute *attr, char *buf) @@ -3556,7 +3556,7 @@ static ssize_t show_status(struct device *d, struct device_attribute *attr, return sprintf(buf, "0x%08x\n", (int)p->status); } -static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); +static DEVICE_ATTR(status, 0444, show_status, NULL); static ssize_t show_capability(struct device *d, struct device_attribute *attr, char *buf) @@ -3565,7 +3565,7 @@ static ssize_t show_capability(struct device *d, struct device_attribute *attr, return sprintf(buf, "0x%08x\n", (int)p->capability); } -static DEVICE_ATTR(capability, S_IRUGO, show_capability, NULL); +static DEVICE_ATTR(capability, 0444, show_capability, NULL); #define IPW2100_REG(x) { IPW_ ##x, #x } static const struct { @@ -3822,7 +3822,7 @@ static ssize_t show_registers(struct device *d, struct device_attribute *attr, return out - buf; } -static DEVICE_ATTR(registers, S_IRUGO, show_registers, NULL); +static DEVICE_ATTR(registers, 0444, show_registers, NULL); static ssize_t show_hardware(struct device *d, struct device_attribute *attr, char *buf) @@ -3863,7 +3863,7 @@ static ssize_t show_hardware(struct device *d, struct device_attribute *attr, return out - buf; } -static DEVICE_ATTR(hardware, S_IRUGO, show_hardware, NULL); +static DEVICE_ATTR(hardware, 0444, show_hardware, NULL); static ssize_t show_memory(struct device *d, struct device_attribute *attr, char *buf) @@ -3957,7 +3957,7 @@ static ssize_t store_memory(struct device *d, struct device_attribute *attr, return count; } -static DEVICE_ATTR(memory, S_IWUSR | S_IRUGO, show_memory, store_memory); +static DEVICE_ATTR(memory, 0644, show_memory, store_memory); static ssize_t show_ordinals(struct device *d, struct device_attribute *attr, char *buf) @@ -3993,7 +3993,7 @@ static ssize_t show_ordinals(struct device *d, struct device_attribute *attr, return len; } -static DEVICE_ATTR(ordinals, S_IRUGO, show_ordinals, NULL); +static DEVICE_ATTR(ordinals, 0444, show_ordinals, NULL); static ssize_t show_stats(struct device *d, struct device_attribute *attr, char *buf) @@ -4014,7 +4014,7 @@ static ssize_t show_stats(struct device *d, struct device_attribute *attr, return out - buf; } -static DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL); +static DEVICE_ATTR(stats, 0444, show_stats, NULL); static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode) { @@ -4112,7 +4112,7 @@ static ssize_t show_internals(struct device *d, struct device_attribute *attr, return len; } -static DEVICE_ATTR(internals, S_IRUGO, show_internals, NULL); +static DEVICE_ATTR(internals, 0444, show_internals, NULL); static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, char *buf) @@ -4157,7 +4157,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, return out - buf; } -static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL); +static DEVICE_ATTR(bssinfo, 0444, show_bssinfo, NULL); #ifdef CONFIG_IPW2100_DEBUG static ssize_t debug_level_show(struct device_driver *d, char *buf) @@ -4216,8 +4216,7 @@ static ssize_t store_fatal_error(struct device *d, return count; } -static DEVICE_ATTR(fatal_error, S_IWUSR | S_IRUGO, show_fatal_error, - store_fatal_error); +static DEVICE_ATTR(fatal_error, 0644, show_fatal_error, store_fatal_error); static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, char *buf) @@ -4250,7 +4249,7 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, return strnlen(buf, count); } -static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age); +static DEVICE_ATTR(scan_age, 0644, show_scan_age, store_scan_age); static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr, char *buf) @@ -4304,7 +4303,7 @@ static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, return count; } -static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); +static DEVICE_ATTR(rf_kill, 0644, show_rf_kill, store_rf_kill); static struct attribute *ipw2100_sysfs_entries[] = { &dev_attr_hardware.attr, diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index 8da87496cb58..87a5e414c2f7 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -1303,7 +1303,7 @@ static ssize_t show_event_log(struct device *d, return len; } -static DEVICE_ATTR(event_log, S_IRUGO, show_event_log, NULL); +static DEVICE_ATTR(event_log, 0444, show_event_log, NULL); static ssize_t show_error(struct device *d, struct device_attribute *attr, char *buf) @@ -1351,7 +1351,7 @@ static ssize_t clear_error(struct device *d, return count; } -static DEVICE_ATTR(error, S_IRUGO | S_IWUSR, show_error, clear_error); +static DEVICE_ATTR(error, 0644, show_error, clear_error); static ssize_t show_cmd_log(struct device *d, struct device_attribute *attr, char *buf) @@ -1378,7 +1378,7 @@ static ssize_t show_cmd_log(struct device *d, return len; } -static DEVICE_ATTR(cmd_log, S_IRUGO, show_cmd_log, NULL); +static DEVICE_ATTR(cmd_log, 0444, show_cmd_log, NULL); #ifdef CONFIG_IPW2200_PROMISCUOUS static void ipw_prom_free(struct ipw_priv *priv); @@ -1443,8 +1443,7 @@ static ssize_t show_rtap_iface(struct device *d, } } -static DEVICE_ATTR(rtap_iface, S_IWUSR | S_IRUSR, show_rtap_iface, - store_rtap_iface); +static DEVICE_ATTR(rtap_iface, 0600, show_rtap_iface, store_rtap_iface); static ssize_t store_rtap_filter(struct device *d, struct device_attribute *attr, @@ -1475,8 +1474,7 @@ static ssize_t show_rtap_filter(struct device *d, priv->prom_priv ? priv->prom_priv->filter : 0); } -static DEVICE_ATTR(rtap_filter, S_IWUSR | S_IRUSR, show_rtap_filter, - store_rtap_filter); +static DEVICE_ATTR(rtap_filter, 0600, show_rtap_filter, store_rtap_filter); #endif static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, @@ -1520,7 +1518,7 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, return len; } -static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age); +static DEVICE_ATTR(scan_age, 0644, show_scan_age, store_scan_age); static ssize_t show_led(struct device *d, struct device_attribute *attr, char *buf) @@ -1553,7 +1551,7 @@ static ssize_t store_led(struct device *d, struct device_attribute *attr, return count; } -static DEVICE_ATTR(led, S_IWUSR | S_IRUGO, show_led, store_led); +static DEVICE_ATTR(led, 0644, show_led, store_led); static ssize_t show_status(struct device *d, struct device_attribute *attr, char *buf) @@ -1562,7 +1560,7 @@ static ssize_t show_status(struct device *d, return sprintf(buf, "0x%08x\n", (int)p->status); } -static DEVICE_ATTR(status, S_IRUGO, show_status, NULL); +static DEVICE_ATTR(status, 0444, show_status, NULL); static ssize_t show_cfg(struct device *d, struct device_attribute *attr, char *buf) @@ -1571,7 +1569,7 @@ static ssize_t show_cfg(struct device *d, struct device_attribute *attr, return sprintf(buf, "0x%08x\n", (int)p->config); } -static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); +static DEVICE_ATTR(cfg, 0444, show_cfg, NULL); static ssize_t show_nic_type(struct device *d, struct device_attribute *attr, char *buf) @@ -1580,7 +1578,7 @@ static ssize_t show_nic_type(struct device *d, return sprintf(buf, "TYPE: %d\n", priv->nic_type); } -static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL); +static DEVICE_ATTR(nic_type, 0444, show_nic_type, NULL); static ssize_t show_ucode_version(struct device *d, struct device_attribute *attr, char *buf) @@ -1594,7 +1592,7 @@ static ssize_t show_ucode_version(struct device *d, return sprintf(buf, "0x%08x\n", tmp); } -static DEVICE_ATTR(ucode_version, S_IWUSR | S_IRUGO, show_ucode_version, NULL); +static DEVICE_ATTR(ucode_version, 0644, show_ucode_version, NULL); static ssize_t show_rtc(struct device *d, struct device_attribute *attr, char *buf) @@ -1608,7 +1606,7 @@ static ssize_t show_rtc(struct device *d, struct device_attribute *attr, return sprintf(buf, "0x%08x\n", tmp); } -static DEVICE_ATTR(rtc, S_IWUSR | S_IRUGO, show_rtc, NULL); +static DEVICE_ATTR(rtc, 0644, show_rtc, NULL); /* * Add a device attribute to view/control the delay between eeprom @@ -1630,8 +1628,7 @@ static ssize_t store_eeprom_delay(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(eeprom_delay, S_IWUSR | S_IRUGO, - show_eeprom_delay, store_eeprom_delay); +static DEVICE_ATTR(eeprom_delay, 0644, show_eeprom_delay, store_eeprom_delay); static ssize_t show_command_event_reg(struct device *d, struct device_attribute *attr, char *buf) @@ -1654,7 +1651,7 @@ static ssize_t store_command_event_reg(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(command_event_reg, S_IWUSR | S_IRUGO, +static DEVICE_ATTR(command_event_reg, 0644, show_command_event_reg, store_command_event_reg); static ssize_t show_mem_gpio_reg(struct device *d, @@ -1678,8 +1675,7 @@ static ssize_t store_mem_gpio_reg(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(mem_gpio_reg, S_IWUSR | S_IRUGO, - show_mem_gpio_reg, store_mem_gpio_reg); +static DEVICE_ATTR(mem_gpio_reg, 0644, show_mem_gpio_reg, store_mem_gpio_reg); static ssize_t show_indirect_dword(struct device *d, struct device_attribute *attr, char *buf) @@ -1705,7 +1701,7 @@ static ssize_t store_indirect_dword(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(indirect_dword, S_IWUSR | S_IRUGO, +static DEVICE_ATTR(indirect_dword, 0644, show_indirect_dword, store_indirect_dword); static ssize_t show_indirect_byte(struct device *d, @@ -1732,7 +1728,7 @@ static ssize_t store_indirect_byte(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(indirect_byte, S_IWUSR | S_IRUGO, +static DEVICE_ATTR(indirect_byte, 0644, show_indirect_byte, store_indirect_byte); static ssize_t show_direct_dword(struct device *d, @@ -1759,8 +1755,7 @@ static ssize_t store_direct_dword(struct device *d, return strnlen(buf, count); } -static DEVICE_ATTR(direct_dword, S_IWUSR | S_IRUGO, - show_direct_dword, store_direct_dword); +static DEVICE_ATTR(direct_dword, 0644, show_direct_dword, store_direct_dword); static int rf_kill_active(struct ipw_priv *priv) { @@ -1831,7 +1826,7 @@ static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr, return count; } -static DEVICE_ATTR(rf_kill, S_IWUSR | S_IRUGO, show_rf_kill, store_rf_kill); +static DEVICE_ATTR(rf_kill, 0644, show_rf_kill, store_rf_kill); static ssize_t show_speed_scan(struct device *d, struct device_attribute *attr, char *buf) @@ -1884,8 +1879,7 @@ static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr, return count; } -static DEVICE_ATTR(speed_scan, S_IWUSR | S_IRUGO, show_speed_scan, - store_speed_scan); +static DEVICE_ATTR(speed_scan, 0644, show_speed_scan, store_speed_scan); static ssize_t show_net_stats(struct device *d, struct device_attribute *attr, char *buf) @@ -1906,8 +1900,7 @@ static ssize_t store_net_stats(struct device *d, struct device_attribute *attr, return count; } -static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, - show_net_stats, store_net_stats); +static DEVICE_ATTR(net_stats, 0644, show_net_stats, store_net_stats); static ssize_t show_channels(struct device *d, struct device_attribute *attr, @@ -1953,7 +1946,7 @@ static ssize_t show_channels(struct device *d, return len; } -static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); +static DEVICE_ATTR(channels, 0400, show_channels, NULL); static void notify_wx_assoc_event(struct ipw_priv *priv) { diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c index c58c5b2dcce5..f00d45f54c76 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_module.c @@ -276,7 +276,7 @@ static int __init libipw_init(void) " proc directory\n"); return -EIO; } - e = proc_create("debug_level", S_IRUGO | S_IWUSR, libipw_proc, + e = proc_create("debug_level", 0644, libipw_proc, &debug_level_proc_fops); if (!e) { remove_proc_entry(DRV_PROCNAME, init_net.proc_net); diff --git a/drivers/net/wireless/intel/iwlegacy/3945-mac.c b/drivers/net/wireless/intel/iwlegacy/3945-mac.c index 4b53ebf00c7f..62a9794f952b 100644 --- a/drivers/net/wireless/intel/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/3945-mac.c @@ -3122,7 +3122,7 @@ il3945_store_debug_level(struct device *d, struct device_attribute *attr, return strnlen(buf, count); } -static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, il3945_show_debug_level, +static DEVICE_ATTR(debug_level, 0644, il3945_show_debug_level, il3945_store_debug_level); #endif /* CONFIG_IWLEGACY_DEBUG */ @@ -3139,7 +3139,7 @@ il3945_show_temperature(struct device *d, struct device_attribute *attr, return sprintf(buf, "%d\n", il3945_hw_get_temperature(il)); } -static DEVICE_ATTR(temperature, S_IRUGO, il3945_show_temperature, NULL); +static DEVICE_ATTR(temperature, 0444, il3945_show_temperature, NULL); static ssize_t il3945_show_tx_power(struct device *d, struct device_attribute *attr, char *buf) @@ -3165,8 +3165,7 @@ il3945_store_tx_power(struct device *d, struct device_attribute *attr, return count; } -static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, il3945_show_tx_power, - il3945_store_tx_power); +static DEVICE_ATTR(tx_power, 0644, il3945_show_tx_power, il3945_store_tx_power); static ssize_t il3945_show_flags(struct device *d, struct device_attribute *attr, char *buf) @@ -3199,8 +3198,7 @@ il3945_store_flags(struct device *d, struct device_attribute *attr, return count; } -static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, il3945_show_flags, - il3945_store_flags); +static DEVICE_ATTR(flags, 0644, il3945_show_flags, il3945_store_flags); static ssize_t il3945_show_filter_flags(struct device *d, struct device_attribute *attr, @@ -3235,7 +3233,7 @@ il3945_store_filter_flags(struct device *d, struct device_attribute *attr, return count; } -static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, il3945_show_filter_flags, +static DEVICE_ATTR(filter_flags, 0644, il3945_show_filter_flags, il3945_store_filter_flags); static ssize_t @@ -3306,7 +3304,7 @@ il3945_store_measurement(struct device *d, struct device_attribute *attr, return count; } -static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, il3945_show_measurement, +static DEVICE_ATTR(measurement, 0600, il3945_show_measurement, il3945_store_measurement); static ssize_t @@ -3330,7 +3328,7 @@ il3945_show_retry_rate(struct device *d, struct device_attribute *attr, return sprintf(buf, "%d", il->retry_rate); } -static DEVICE_ATTR(retry_rate, S_IWUSR | S_IRUSR, il3945_show_retry_rate, +static DEVICE_ATTR(retry_rate, 0600, il3945_show_retry_rate, il3945_store_retry_rate); static ssize_t @@ -3340,7 +3338,7 @@ il3945_show_channels(struct device *d, struct device_attribute *attr, char *buf) return 0; } -static DEVICE_ATTR(channels, S_IRUSR, il3945_show_channels, NULL); +static DEVICE_ATTR(channels, 0400, il3945_show_channels, NULL); static ssize_t il3945_show_antenna(struct device *d, struct device_attribute *attr, char *buf) @@ -3377,8 +3375,7 @@ il3945_store_antenna(struct device *d, struct device_attribute *attr, return count; } -static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, il3945_show_antenna, - il3945_store_antenna); +static DEVICE_ATTR(antenna, 0644, il3945_show_antenna, il3945_store_antenna); static ssize_t il3945_show_status(struct device *d, struct device_attribute *attr, char *buf) @@ -3389,7 +3386,7 @@ il3945_show_status(struct device *d, struct device_attribute *attr, char *buf) return sprintf(buf, "0x%08x\n", (int)il->status); } -static DEVICE_ATTR(status, S_IRUGO, il3945_show_status, NULL); +static DEVICE_ATTR(status, 0444, il3945_show_status, NULL); static ssize_t il3945_dump_error_log(struct device *d, struct device_attribute *attr, @@ -3404,7 +3401,7 @@ il3945_dump_error_log(struct device *d, struct device_attribute *attr, return strnlen(buf, count); } -static DEVICE_ATTR(dump_errors, S_IWUSR, NULL, il3945_dump_error_log); +static DEVICE_ATTR(dump_errors, 0200, NULL, il3945_dump_error_log); /***************************************************************************** * @@ -3943,18 +3940,18 @@ il3945_exit(void) MODULE_FIRMWARE(IL3945_MODULE_FIRMWARE(IL3945_UCODE_API_MAX)); -module_param_named(antenna, il3945_mod_params.antenna, int, S_IRUGO); +module_param_named(antenna, il3945_mod_params.antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); -module_param_named(swcrypto, il3945_mod_params.sw_crypto, int, S_IRUGO); +module_param_named(swcrypto, il3945_mod_params.sw_crypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using software crypto (default 1 [software])"); module_param_named(disable_hw_scan, il3945_mod_params.disable_hw_scan, int, - S_IRUGO); + 0444); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 1)"); #ifdef CONFIG_IWLEGACY_DEBUG -module_param_named(debug, il_debug_level, uint, S_IRUGO | S_IWUSR); +module_param_named(debug, il_debug_level, uint, 0644); MODULE_PARM_DESC(debug, "debug output mask"); #endif -module_param_named(fw_restart, il3945_mod_params.restart_fw, int, S_IRUGO); +module_param_named(fw_restart, il3945_mod_params.restart_fw, int, 0444); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); module_exit(il3945_exit); diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index de63f2518f23..562e94870a9c 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -4591,7 +4591,7 @@ il4965_store_debug_level(struct device *d, struct device_attribute *attr, return strnlen(buf, count); } -static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, il4965_show_debug_level, +static DEVICE_ATTR(debug_level, 0644, il4965_show_debug_level, il4965_store_debug_level); #endif /* CONFIG_IWLEGACY_DEBUG */ @@ -4608,7 +4608,7 @@ il4965_show_temperature(struct device *d, struct device_attribute *attr, return sprintf(buf, "%d\n", il->temperature); } -static DEVICE_ATTR(temperature, S_IRUGO, il4965_show_temperature, NULL); +static DEVICE_ATTR(temperature, 0444, il4965_show_temperature, NULL); static ssize_t il4965_show_tx_power(struct device *d, struct device_attribute *attr, char *buf) @@ -4642,7 +4642,7 @@ il4965_store_tx_power(struct device *d, struct device_attribute *attr, return ret; } -static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, il4965_show_tx_power, +static DEVICE_ATTR(tx_power, 0644, il4965_show_tx_power, il4965_store_tx_power); static struct attribute *il_sysfs_entries[] = { @@ -6859,18 +6859,17 @@ module_exit(il4965_exit); module_init(il4965_init); #ifdef CONFIG_IWLEGACY_DEBUG -module_param_named(debug, il_debug_level, uint, S_IRUGO | S_IWUSR); +module_param_named(debug, il_debug_level, uint, 0644); MODULE_PARM_DESC(debug, "debug output mask"); #endif -module_param_named(swcrypto, il4965_mod_params.sw_crypto, int, S_IRUGO); +module_param_named(swcrypto, il4965_mod_params.sw_crypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); -module_param_named(queues_num, il4965_mod_params.num_of_queues, int, S_IRUGO); +module_param_named(queues_num, il4965_mod_params.num_of_queues, int, 0444); MODULE_PARM_DESC(queues_num, "number of hw queues."); -module_param_named(11n_disable, il4965_mod_params.disable_11n, int, S_IRUGO); +module_param_named(11n_disable, il4965_mod_params.disable_11n, int, 0444); MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); -module_param_named(amsdu_size_8K, il4965_mod_params.amsdu_size_8K, int, - S_IRUGO); +module_param_named(amsdu_size_8K, il4965_mod_params.amsdu_size_8K, int, 0444); MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0 [disabled])"); -module_param_named(fw_restart, il4965_mod_params.restart_fw, int, S_IRUGO); +module_param_named(fw_restart, il4965_mod_params.restart_fw, int, 0444); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error"); diff --git a/drivers/net/wireless/intel/iwlegacy/4965-rs.c b/drivers/net/wireless/intel/iwlegacy/4965-rs.c index 365a4187fc37..54ff83829afb 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-rs.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-rs.c @@ -2768,16 +2768,16 @@ il4965_rs_add_debugfs(void *il, void *il_sta, struct dentry *dir) { struct il_lq_sta *lq_sta = il_sta; lq_sta->rs_sta_dbgfs_scale_table_file = - debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, + debugfs_create_file("rate_scale_table", 0600, dir, lq_sta, &rs_sta_dbgfs_scale_table_ops); lq_sta->rs_sta_dbgfs_stats_table_file = - debugfs_create_file("rate_stats_table", S_IRUSR, dir, lq_sta, + debugfs_create_file("rate_stats_table", 0400, dir, lq_sta, &rs_sta_dbgfs_stats_table_ops); lq_sta->rs_sta_dbgfs_rate_scale_data_file = - debugfs_create_file("rate_scale_data", S_IRUSR, dir, lq_sta, + debugfs_create_file("rate_scale_data", 0400, dir, lq_sta, &rs_sta_dbgfs_rate_scale_data_ops); lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = - debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, + debugfs_create_u8("tx_agg_tid_enable", 0600, dir, &lq_sta->tx_agg_tid_en); } diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 558bb16bfd46..063e19ced7c8 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -435,7 +435,7 @@ EXPORT_SYMBOL(il_send_cmd_pdu_async); /* default: IL_LED_BLINK(0) using blinking idx table */ static int led_mode; -module_param(led_mode, int, S_IRUGO); +module_param(led_mode, int, 0444); MODULE_PARM_DESC(led_mode, "0=system default, " "1=On(RF On)/Off(RF Off), 2=blinking"); @@ -3372,7 +3372,7 @@ MODULE_LICENSE("GPL"); * default: bt_coex_active = true (BT_COEX_ENABLE) */ static bool bt_coex_active = true; -module_param(bt_coex_active, bool, S_IRUGO); +module_param(bt_coex_active, bool, 0444); MODULE_PARM_DESC(bt_coex_active, "enable wifi/bluetooth co-exist"); u32 il_debug_level; diff --git a/drivers/net/wireless/intel/iwlegacy/debug.c b/drivers/net/wireless/intel/iwlegacy/debug.c index 6fc6b7ff9849..d76073def677 100644 --- a/drivers/net/wireless/intel/iwlegacy/debug.c +++ b/drivers/net/wireless/intel/iwlegacy/debug.c @@ -135,16 +135,14 @@ EXPORT_SYMBOL(il_update_stats); #define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ struct dentry *__tmp; \ - __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \ - parent, ptr); \ + __tmp = debugfs_create_bool(#name, 0600, parent, ptr); \ if (IS_ERR(__tmp) || !__tmp) \ goto err; \ } while (0) #define DEBUGFS_ADD_X32(name, parent, ptr) do { \ struct dentry *__tmp; \ - __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR, \ - parent, ptr); \ + __tmp = debugfs_create_x32(#name, 0600, parent, ptr); \ if (IS_ERR(__tmp) || !__tmp) \ goto err; \ } while (0) @@ -1365,35 +1363,35 @@ il_dbgfs_register(struct il_priv *il, const char *name) if (!dir_debug) goto err; - DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(interrupt, dir_data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(rx_stats, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(tx_stats, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(rx_queue, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(tx_queue, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(clear_ucode_stats, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(clear_traffic_stats, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(fh_reg, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(force_reset, dir_debug, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(nvm, dir_data, 0400); + DEBUGFS_ADD_FILE(sram, dir_data, 0600); + DEBUGFS_ADD_FILE(stations, dir_data, 0400); + DEBUGFS_ADD_FILE(channels, dir_data, 0400); + DEBUGFS_ADD_FILE(status, dir_data, 0400); + DEBUGFS_ADD_FILE(interrupt, dir_data, 0600); + DEBUGFS_ADD_FILE(qos, dir_data, 0400); + DEBUGFS_ADD_FILE(disable_ht40, dir_data, 0600); + DEBUGFS_ADD_FILE(rx_stats, dir_debug, 0400); + DEBUGFS_ADD_FILE(tx_stats, dir_debug, 0400); + DEBUGFS_ADD_FILE(rx_queue, dir_debug, 0400); + DEBUGFS_ADD_FILE(tx_queue, dir_debug, 0400); + DEBUGFS_ADD_FILE(power_save_status, dir_debug, 0400); + DEBUGFS_ADD_FILE(clear_ucode_stats, dir_debug, 0200); + DEBUGFS_ADD_FILE(clear_traffic_stats, dir_debug, 0200); + DEBUGFS_ADD_FILE(fh_reg, dir_debug, 0400); + DEBUGFS_ADD_FILE(missed_beacon, dir_debug, 0200); + DEBUGFS_ADD_FILE(force_reset, dir_debug, 0600); + DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, 0400); + DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, 0400); + DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, 0400); if (il->cfg->sensitivity_calib_by_driver) - DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(sensitivity, dir_debug, 0400); if (il->cfg->chain_noise_calib_by_driver) - DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR); + DEBUGFS_ADD_FILE(chain_noise, dir_debug, 0400); + DEBUGFS_ADD_FILE(rxon_flags, dir_debug, 0200); + DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, 0200); + DEBUGFS_ADD_FILE(wd_timeout, dir_debug, 0200); if (il->cfg->sensitivity_calib_by_driver) DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf, &il->disable_sens_cal); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 48f6f80eb24b..dffd9df782b0 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2015-2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -19,6 +20,7 @@ * BSD LICENSE * * Copyright(c) 2015-2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,7 +57,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 36 +#define IWL_22000_UCODE_API_MAX 38 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 24 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c index 90a1d14cf7d2..e1c869a1f8cc 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c @@ -6,6 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2015-2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -19,6 +20,7 @@ * BSD LICENSE * * Copyright(c) 2015-2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -53,9 +55,10 @@ #include <linux/stringify.h> #include "iwl-config.h" #include "iwl-agn-hw.h" +#include "fw/file.h" /* Highest firmware API version supported */ -#define IWL9000_UCODE_API_MAX 36 +#define IWL9000_UCODE_API_MAX 38 /* Lowest firmware API version supported */ #define IWL9000_UCODE_API_MIN 30 @@ -265,6 +268,67 @@ const struct iwl_cfg iwl9560_2ac_cfg_soc = { .integrated = true, .soc_latency = 5000, }; + +const struct iwl_cfg iwl9460_2ac_cfg_shared_clk = { + .name = "Intel(R) Dual Band Wireless AC 9460", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, + .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK +}; + +const struct iwl_cfg iwl9461_2ac_cfg_shared_clk = { + .name = "Intel(R) Dual Band Wireless AC 9461", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, + .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK +}; + +const struct iwl_cfg iwl9462_2ac_cfg_shared_clk = { + .name = "Intel(R) Dual Band Wireless AC 9462", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, + .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK +}; + +const struct iwl_cfg iwl9560_2ac_cfg_shared_clk = { + .name = "Intel(R) Dual Band Wireless AC 9560", + .fw_name_pre = IWL9000A_FW_PRE, + .fw_name_pre_b_or_c_step = IWL9000B_FW_PRE, + .fw_name_pre_rf_next_step = IWL9000RFB_FW_PRE, + IWL_DEVICE_9000, + .ht_params = &iwl9000_ht_params, + .nvm_ver = IWL9000_NVM_VERSION, + .nvm_calib_ver = IWL9000_TX_POWER_VERSION, + .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, + .integrated = true, + .soc_latency = 5000, + .extra_phy_cfg_flags = FW_PHY_CFG_SHARED_CLK +}; + MODULE_FIRMWARE(IWL9000A_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9000B_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL9000RFB_MODULE_FIRMWARE(IWL9000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c index 482ac8fdc67b..096a07c5a33f 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c @@ -48,16 +48,14 @@ #define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ struct dentry *__tmp; \ - __tmp = debugfs_create_bool(#name, S_IWUSR | S_IRUSR, \ - parent, ptr); \ + __tmp = debugfs_create_bool(#name, 0600, parent, ptr); \ if (IS_ERR(__tmp) || !__tmp) \ goto err; \ } while (0) #define DEBUGFS_ADD_X32(name, parent, ptr) do { \ struct dentry *__tmp; \ - __tmp = debugfs_create_x32(#name, S_IWUSR | S_IRUSR, \ - parent, ptr); \ + __tmp = debugfs_create_x32(#name, 0600, parent, ptr); \ if (IS_ERR(__tmp) || !__tmp) \ goto err; \ } while (0) @@ -2370,48 +2368,48 @@ int iwl_dbgfs_register(struct iwl_priv *priv, struct dentry *dbgfs_dir) if (!dir_debug) goto err; - DEBUGFS_ADD_FILE(nvm, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(sram, dir_data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(wowlan_sram, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(stations, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(channels, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(status, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(rx_handlers, dir_data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(qos, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(sleep_level_override, dir_data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR); - DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(temperature, dir_data, S_IRUSR); - - DEBUGFS_ADD_FILE(power_save_status, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(missed_beacon, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(plcp_delta, dir_debug, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(rf_reset, dir_debug, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, S_IRUSR); - DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR); - DEBUGFS_ADD_FILE(fw_restart, dir_debug, S_IWUSR); + DEBUGFS_ADD_FILE(nvm, dir_data, 0400); + DEBUGFS_ADD_FILE(sram, dir_data, 0600); + DEBUGFS_ADD_FILE(wowlan_sram, dir_data, 0400); + DEBUGFS_ADD_FILE(stations, dir_data, 0400); + DEBUGFS_ADD_FILE(channels, dir_data, 0400); + DEBUGFS_ADD_FILE(status, dir_data, 0400); + DEBUGFS_ADD_FILE(rx_handlers, dir_data, 0600); + DEBUGFS_ADD_FILE(qos, dir_data, 0400); + DEBUGFS_ADD_FILE(sleep_level_override, dir_data, 0600); + DEBUGFS_ADD_FILE(current_sleep_command, dir_data, 0400); + DEBUGFS_ADD_FILE(thermal_throttling, dir_data, 0400); + DEBUGFS_ADD_FILE(disable_ht40, dir_data, 0600); + DEBUGFS_ADD_FILE(temperature, dir_data, 0400); + + DEBUGFS_ADD_FILE(power_save_status, dir_debug, 0400); + DEBUGFS_ADD_FILE(clear_ucode_statistics, dir_debug, 0200); + DEBUGFS_ADD_FILE(missed_beacon, dir_debug, 0200); + DEBUGFS_ADD_FILE(plcp_delta, dir_debug, 0600); + DEBUGFS_ADD_FILE(rf_reset, dir_debug, 0600); + DEBUGFS_ADD_FILE(ucode_rx_stats, dir_debug, 0400); + DEBUGFS_ADD_FILE(ucode_tx_stats, dir_debug, 0400); + DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, 0400); + DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, 0200); + DEBUGFS_ADD_FILE(protection_mode, dir_debug, 0600); + DEBUGFS_ADD_FILE(sensitivity, dir_debug, 0400); + DEBUGFS_ADD_FILE(chain_noise, dir_debug, 0400); + DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, 0600); + DEBUGFS_ADD_FILE(ucode_bt_stats, dir_debug, 0400); + DEBUGFS_ADD_FILE(reply_tx_error, dir_debug, 0400); + DEBUGFS_ADD_FILE(rxon_flags, dir_debug, 0200); + DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, 0200); + DEBUGFS_ADD_FILE(echo_test, dir_debug, 0200); + DEBUGFS_ADD_FILE(fw_restart, dir_debug, 0200); #ifdef CONFIG_IWLWIFI_DEBUG - DEBUGFS_ADD_FILE(log_event, dir_debug, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(log_event, dir_debug, 0600); #endif if (iwl_advanced_bt_coexist(priv)) - DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR); + DEBUGFS_ADD_FILE(bt_traffic, dir_debug, 0400); /* Calibrations disabled/enabled status*/ - DEBUGFS_ADD_FILE(calib_disabled, dir_rf, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(calib_disabled, dir_rf, 0600); /* * Create a symlink with mac80211. This is not very robust, as it does diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c index ddcd8c2d66cd..98050d7be411 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c @@ -3276,17 +3276,17 @@ static void rs_add_debugfs(void *priv, void *priv_sta, { struct iwl_lq_sta *lq_sta = priv_sta; lq_sta->rs_sta_dbgfs_scale_table_file = - debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, - lq_sta, &rs_sta_dbgfs_scale_table_ops); + debugfs_create_file("rate_scale_table", 0600, dir, + lq_sta, &rs_sta_dbgfs_scale_table_ops); lq_sta->rs_sta_dbgfs_stats_table_file = - debugfs_create_file("rate_stats_table", S_IRUSR, dir, - lq_sta, &rs_sta_dbgfs_stats_table_ops); + debugfs_create_file("rate_stats_table", 0400, dir, + lq_sta, &rs_sta_dbgfs_stats_table_ops); lq_sta->rs_sta_dbgfs_rate_scale_data_file = - debugfs_create_file("rate_scale_data", S_IRUSR, dir, - lq_sta, &rs_sta_dbgfs_rate_scale_data_ops); + debugfs_create_file("rate_scale_data", 0400, dir, + lq_sta, &rs_sta_dbgfs_rate_scale_data_ops); lq_sta->rs_sta_dbgfs_tx_agg_tid_en_file = - debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, - &lq_sta->tx_agg_tid_en); + debugfs_create_u8("tx_agg_tid_enable", 0600, dir, + &lq_sta->tx_agg_tid_en); } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 3fd07bc80f54..37c57bcbfb4a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright (C) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -311,6 +313,17 @@ struct iwl_mcc_update_resp_v1 { } __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_1 */ /** + * enum iwl_geo_information - geographic information. + * @GEO_NO_INFO: no special info for this geo profile. + * @GEO_WMM_ETSI_5GHZ_INFO: this geo profile limits the WMM params + * for the 5 GHz band. + */ +enum iwl_geo_information { + GEO_NO_INFO = 0, + GEO_WMM_ETSI_5GHZ_INFO = BIT(0), +}; + +/** * struct iwl_mcc_update_resp - response to MCC_UPDATE_CMD. * Contains the new channel control profile map, if changed, and the new MCC * (mobile country code). @@ -320,7 +333,8 @@ struct iwl_mcc_update_resp_v1 { * @cap: capabilities for all channels which matches the MCC * @source_id: the MCC source, see iwl_mcc_source * @time: time elapsed from the MCC test start (in 30 seconds TU) - * @reserved: reserved. + * @geo_info: geographic specific profile information + * see &enum iwl_geo_information. * @n_channels: number of channels in @channels_data (may be 14, 39, 50 or 51 * channels, depending on platform) * @channels: channel control data map, DWORD for each channel. Only the first @@ -332,10 +346,10 @@ struct iwl_mcc_update_resp { u8 cap; u8 source_id; __le16 time; - __le16 reserved; + __le16 geo_info; __le32 n_channels; __le32 channels[0]; -} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_2 */ +} __packed; /* LAR_UPDATE_MCC_CMD_RESP_S_VER_3 */ /** * struct iwl_mcc_chub_notif - chub notifies of mcc change diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index 3bfc657f6b42..7af3a0f51b77 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -30,6 +30,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -579,8 +580,23 @@ enum iwl_umac_scan_general_flags { IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED = BIT(8), IWL_UMAC_SCAN_GEN_FLAGS_MATCH = BIT(9), IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL = BIT(10), + /* Extended dwell is obselete when adaptive dwell is used, making this + * bit reusable. Hence, probe request defer is used only when adaptive + * dwell is supported. */ + IWL_UMAC_SCAN_GEN_FLAGS_PROB_REQ_DEFER_SUPP = BIT(10), IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED = BIT(11), IWL_UMAC_SCAN_GEN_FLAGS_ADAPTIVE_DWELL = BIT(13), + IWL_UMAC_SCAN_GEN_FLAGS_MAX_CHNL_TIME = BIT(14), + IWL_UMAC_SCAN_GEN_FLAGS_PROB_REQ_HIGH_TX_RATE = BIT(15), +}; + +/** + * enum iwl_umac_scan_general_flags2 - UMAC scan general flags #2 + * @IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL: Whether to send a complete + * notification per channel or not. + */ +enum iwl_umac_scan_general_flags2 { + IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL = BIT(0), }; /** @@ -629,6 +645,18 @@ struct iwl_scan_req_umac_tail { } __packed; /** + * struct iwl_scan_umac_chan_param + * @flags: channel flags &enum iwl_scan_channel_flags + * @count: num of channels in scan request + * @reserved: for future use and alignment + */ +struct iwl_scan_umac_chan_param { + u8 flags; + u8 count; + __le16 reserved; +} __packed; /*SCAN_CHANNEL_PARAMS_API_S_VER_1 */ + +/** * struct iwl_scan_req_umac * @flags: &enum iwl_umac_scan_flags * @uid: scan id, &enum iwl_umac_scan_uid_offsets @@ -636,23 +664,24 @@ struct iwl_scan_req_umac_tail { * @general_flags: &enum iwl_umac_scan_general_flags * @scan_start_mac_id: report the scan start TSF time according to this mac TSF * @extended_dwell: dwell time for channels 1, 6 and 11 - * @active_dwell: dwell time for active scan - * @passive_dwell: dwell time for passive scan + * @active_dwell: dwell time for active scan per LMAC + * @passive_dwell: dwell time for passive scan per LMAC * @fragmented_dwell: dwell time for fragmented passive scan * @adwell_default_n_aps: for adaptive dwell the default number of APs * per channel * @adwell_default_n_aps_social: for adaptive dwell the default * number of APs per social (1,6,11) channel + * @general_flags2: &enum iwl_umac_scan_general_flags2 * @adwell_max_budget: for adaptive dwell the maximal budget of TU to be added * to total scan time * @max_out_time: max out of serving channel time, per LMAC - for CDB there * are 2 LMACs * @suspend_time: max suspend time, per LMAC - for CDB there are 2 LMACs * @scan_priority: scan internal prioritization &enum iwl_scan_priority - * @channel_flags: &enum iwl_scan_channel_flags - * @n_channels: num of channels in scan request + * @num_of_fragments: Number of fragments needed for full coverage per band. + * Relevant only for fragmented scan. + * @channel: &struct iwl_scan_umac_chan_param * @reserved: for future use and alignment - * @reserved2: for future use and alignment * @reserved3: for future use and alignment * @data: &struct iwl_scan_channel_cfg_umac and * &struct iwl_scan_req_umac_tail @@ -673,10 +702,7 @@ struct iwl_scan_req_umac { __le32 max_out_time; __le32 suspend_time; __le32 scan_priority; - /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ - u8 channel_flags; - u8 n_channels; - __le16 reserved2; + struct iwl_scan_umac_chan_param channel; u8 data[]; } v1; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */ struct { @@ -687,10 +713,7 @@ struct iwl_scan_req_umac { __le32 max_out_time[SCAN_TWO_LMACS]; __le32 suspend_time[SCAN_TWO_LMACS]; __le32 scan_priority; - /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ - u8 channel_flags; - u8 n_channels; - __le16 reserved2; + struct iwl_scan_umac_chan_param channel; u8 data[]; } v6; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_6 */ struct { @@ -704,16 +727,30 @@ struct iwl_scan_req_umac { __le32 max_out_time[SCAN_TWO_LMACS]; __le32 suspend_time[SCAN_TWO_LMACS]; __le32 scan_priority; - /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ - u8 channel_flags; - u8 n_channels; - __le16 reserved2; + struct iwl_scan_umac_chan_param channel; u8 data[]; } v7; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_7 */ + struct { + u8 active_dwell[SCAN_TWO_LMACS]; + u8 reserved2; + u8 adwell_default_n_aps; + u8 adwell_default_n_aps_social; + u8 general_flags2; + __le16 adwell_max_budget; + __le32 max_out_time[SCAN_TWO_LMACS]; + __le32 suspend_time[SCAN_TWO_LMACS]; + __le32 scan_priority; + u8 passive_dwell[SCAN_TWO_LMACS]; + u8 num_of_fragments[SCAN_TWO_LMACS]; + struct iwl_scan_umac_chan_param channel; + u8 data[]; + } v8; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_8 */ }; } __packed; -#define IWL_SCAN_REQ_UMAC_SIZE_V7 sizeof(struct iwl_scan_req_umac) +#define IWL_SCAN_REQ_UMAC_SIZE_V8 sizeof(struct iwl_scan_req_umac) +#define IWL_SCAN_REQ_UMAC_SIZE_V7 (sizeof(struct iwl_scan_req_umac) - \ + 4 * sizeof(u8)) #define IWL_SCAN_REQ_UMAC_SIZE_V6 (sizeof(struct iwl_scan_req_umac) - \ 2 * sizeof(u8) - sizeof(__le16)) #define IWL_SCAN_REQ_UMAC_SIZE_V1 (sizeof(struct iwl_scan_req_umac) - \ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 7bd704a3e640..fa283285fcbe 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -68,6 +68,7 @@ #include "iwl-drv.h" #include "runtime.h" #include "dbg.h" +#include "debugfs.h" #include "iwl-io.h" #include "iwl-prph.h" #include "iwl-csr.h" @@ -1007,6 +1008,12 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, { struct iwl_fw_dump_desc *desc; + if (trigger && trigger->flags & IWL_FW_DBG_FORCE_RESTART) { + IWL_WARN(fwrt, "Force restart: trigger %d fired.\n", trig); + iwl_force_nmi(fwrt->trans); + return 0; + } + desc = kzalloc(sizeof(*desc) + len, GFP_ATOMIC); if (!desc) return -ENOMEM; @@ -1080,6 +1087,9 @@ int iwl_fw_start_dbg_conf(struct iwl_fw_runtime *fwrt, u8 conf_id) IWL_WARN(fwrt, "FW already configured (%d) - re-configuring\n", fwrt->dump.conf); + /* start default config marker cmd for syncing logs */ + iwl_fw_trigger_timestamp(fwrt, 1); + /* Send all HCMDs for configuring the FW debug */ ptr = (void *)&fwrt->fw->dbg_conf_tlv[conf_id]->hcmd; for (i = 0; i < fwrt->fw->dbg_conf_tlv[conf_id]->num_of_hcmds; i++) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index e2ded29a145d..8f005cd69559 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -157,6 +157,20 @@ static void iwl_fw_timestamp_marker_wk(struct work_struct *work) ret, jiffies_to_msecs(delay) / 1000); } +void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay) +{ + IWL_INFO(fwrt, + "starting timestamp_marker trigger with delay: %us\n", + delay); + + iwl_fw_cancel_timestamp(fwrt); + + fwrt->timestamp.delay = msecs_to_jiffies(delay * 1000); + + schedule_delayed_work(&fwrt->timestamp.wk, + round_jiffies_relative(fwrt->timestamp.delay)); +} + static ssize_t iwl_dbgfs_timestamp_marker_write(struct iwl_fw_runtime *fwrt, char *buf, size_t count, loff_t *ppos) @@ -168,16 +182,8 @@ static ssize_t iwl_dbgfs_timestamp_marker_write(struct iwl_fw_runtime *fwrt, if (ret < 0) return ret; - IWL_INFO(fwrt, - "starting timestamp_marker trigger with delay: %us\n", - delay); + iwl_fw_trigger_timestamp(fwrt, delay); - iwl_fw_cancel_timestamp(fwrt); - - fwrt->timestamp.delay = msecs_to_jiffies(delay * 1000); - - schedule_delayed_work(&fwrt->timestamp.wk, - round_jiffies_relative(fwrt->timestamp.delay)); return count; } @@ -187,7 +193,7 @@ int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, struct dentry *dbgfs_dir) { INIT_DELAYED_WORK(&fwrt->timestamp.wk, iwl_fw_timestamp_marker_wk); - FWRT_DEBUGFS_ADD_FILE(timestamp_marker, dbgfs_dir, S_IWUSR); + FWRT_DEBUGFS_ADD_FILE(timestamp_marker, dbgfs_dir, 0200); return 0; err: IWL_ERR(fwrt, "Can't create the fwrt debugfs directory\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h index 3da468d2cc92..d93f6a4bb22d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.h @@ -89,6 +89,8 @@ static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) round_jiffies_relative(fwrt->timestamp.delay)); } +void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay); + #else static inline int iwl_fwrt_dbgfs_register(struct iwl_fw_runtime *fwrt, struct dentry *dbgfs_dir) @@ -102,4 +104,7 @@ static inline void iwl_fw_suspend_timestamp(struct iwl_fw_runtime *fwrt) {} static inline void iwl_fw_resume_timestamp(struct iwl_fw_runtime *fwrt) {} +static inline void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, + u32 delay) {} + #endif /* CONFIG_IWLWIFI_DEBUGFS */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 1a05d506ac9a..9b2805e1e3b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -250,6 +250,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * indicating low latency direction. * @IWL_UCODE_TLV_API_DEPRECATE_TTAK: RX status flag TTAK ok (bit 7) is * deprecated. + * @IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2: This ucode supports version 8 + * of scan request: SCAN_REQUEST_CMD_UMAC_API_S_VER_8 * * @NUM_IWL_UCODE_TLV_API: number of bits used */ @@ -265,10 +267,12 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_NAN2_VER2 = (__force iwl_ucode_tlv_api_t)31, /* API Set 1 */ IWL_UCODE_TLV_API_ADAPTIVE_DWELL = (__force iwl_ucode_tlv_api_t)32, + IWL_UCODE_TLV_API_OCE = (__force iwl_ucode_tlv_api_t)33, IWL_UCODE_TLV_API_NEW_BEACON_TEMPLATE = (__force iwl_ucode_tlv_api_t)34, IWL_UCODE_TLV_API_NEW_RX_STATS = (__force iwl_ucode_tlv_api_t)35, IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY = (__force iwl_ucode_tlv_api_t)38, IWL_UCODE_TLV_API_DEPRECATE_TTAK = (__force iwl_ucode_tlv_api_t)41, + IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2 = (__force iwl_ucode_tlv_api_t)42, NUM_IWL_UCODE_TLV_API #ifdef __CHECKER__ @@ -441,6 +445,7 @@ enum iwl_fw_phy_cfg { FW_PHY_CFG_TX_CHAIN = 0xf << FW_PHY_CFG_TX_CHAIN_POS, FW_PHY_CFG_RX_CHAIN_POS = 20, FW_PHY_CFG_RX_CHAIN = 0xf << FW_PHY_CFG_RX_CHAIN_POS, + FW_PHY_CFG_SHARED_CLK = BIT(31), }; #define IWL_UCODE_MAX_CS 1 @@ -616,6 +621,14 @@ enum iwl_fw_dbg_trigger_mode { }; /** + * enum iwl_fw_dbg_trigger_flags - the flags supported by wrt triggers + * @IWL_FW_DBG_FORCE_RESTART: force a firmware restart + */ +enum iwl_fw_dbg_trigger_flags { + IWL_FW_DBG_FORCE_RESTART = BIT(0), +}; + +/** * enum iwl_fw_dbg_trigger_vif_type - define the VIF type for a trigger * @IWL_FW_DBG_CONF_VIF_ANY: any vif type * @IWL_FW_DBG_CONF_VIF_IBSS: IBSS mode @@ -651,6 +664,7 @@ enum iwl_fw_dbg_trigger_vif_type { * @occurrences: number of occurrences. 0 means the trigger will never fire. * @trig_dis_ms: the time, in milliseconds, after an occurrence of this * trigger in which another occurrence should be ignored. + * @flags: &enum iwl_fw_dbg_trigger_flags */ struct iwl_fw_dbg_trigger_tlv { __le32 id; @@ -661,7 +675,8 @@ struct iwl_fw_dbg_trigger_tlv { u8 start_conf_id; __le16 occurrences; __le16 trig_dis_ms; - __le16 reserved[3]; + u8 flags; + u8 reserved[5]; u8 data[0]; } __packed; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 258d439bb0a9..f0f5636dd3ea 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -398,6 +398,7 @@ struct iwl_cfg { u8 ucode_api_max; u8 ucode_api_min; u32 min_umac_error_event_table; + u32 extra_phy_cfg_flags; }; /* @@ -477,6 +478,10 @@ extern const struct iwl_cfg iwl9460_2ac_cfg_soc; extern const struct iwl_cfg iwl9461_2ac_cfg_soc; extern const struct iwl_cfg iwl9462_2ac_cfg_soc; extern const struct iwl_cfg iwl9560_2ac_cfg_soc; +extern const struct iwl_cfg iwl9460_2ac_cfg_shared_clk; +extern const struct iwl_cfg iwl9461_2ac_cfg_shared_clk; +extern const struct iwl_cfg iwl9462_2ac_cfg_shared_clk; +extern const struct iwl_cfg iwl9560_2ac_cfg_shared_clk; extern const struct iwl_cfg iwl22000_2ac_cfg_hr; extern const struct iwl_cfg iwl22000_2ac_cfg_hr_cdb; extern const struct iwl_cfg iwl22000_2ac_cfg_jf; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 9c4a7f648a44..aa2d5c14e202 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1768,41 +1768,36 @@ static void __exit iwl_drv_exit(void) module_exit(iwl_drv_exit); #ifdef CONFIG_IWLWIFI_DEBUG -module_param_named(debug, iwlwifi_mod_params.debug_level, uint, - S_IRUGO | S_IWUSR); +module_param_named(debug, iwlwifi_mod_params.debug_level, uint, 0644); MODULE_PARM_DESC(debug, "debug output mask"); #endif -module_param_named(swcrypto, iwlwifi_mod_params.swcrypto, int, S_IRUGO); +module_param_named(swcrypto, iwlwifi_mod_params.swcrypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); -module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, S_IRUGO); +module_param_named(11n_disable, iwlwifi_mod_params.disable_11n, uint, 0444); MODULE_PARM_DESC(11n_disable, "disable 11n functionality, bitmap: 1: full, 2: disable agg TX, 4: disable agg RX, 8 enable agg TX"); -module_param_named(amsdu_size, iwlwifi_mod_params.amsdu_size, - int, S_IRUGO); +module_param_named(amsdu_size, iwlwifi_mod_params.amsdu_size, int, 0444); MODULE_PARM_DESC(amsdu_size, "amsdu size 0: 12K for multi Rx queue devices, 4K for other devices 1:4K 2:8K 3:12K (default 0)"); -module_param_named(fw_restart, iwlwifi_mod_params.fw_restart, bool, S_IRUGO); +module_param_named(fw_restart, iwlwifi_mod_params.fw_restart, bool, 0444); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error (default true)"); module_param_named(antenna_coupling, iwlwifi_mod_params.antenna_coupling, - int, S_IRUGO); + int, 0444); MODULE_PARM_DESC(antenna_coupling, "specify antenna coupling in dB (default: 0 dB)"); -module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO); +module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, 0444); MODULE_PARM_DESC(nvm_file, "NVM file name"); -module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable, - bool, S_IRUGO); +module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable, bool, 0444); MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)"); -module_param_named(lar_disable, iwlwifi_mod_params.lar_disable, - bool, S_IRUGO); +module_param_named(lar_disable, iwlwifi_mod_params.lar_disable, bool, 0444); MODULE_PARM_DESC(lar_disable, "disable LAR functionality (default: N)"); -module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, - uint, S_IRUGO | S_IWUSR); +module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, uint, 0644); MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality bitmap 1: BSS 2: P2P Client (default: 3)"); @@ -1823,31 +1818,27 @@ MODULE_PARM_DESC(uapsd_disable, * default: bt_coex_active = true (BT_COEX_ENABLE) */ module_param_named(bt_coex_active, iwlwifi_mod_params.bt_coex_active, - bool, S_IRUGO); + bool, 0444); MODULE_PARM_DESC(bt_coex_active, "enable wifi/bt co-exist (default: enable)"); -module_param_named(led_mode, iwlwifi_mod_params.led_mode, int, S_IRUGO); +module_param_named(led_mode, iwlwifi_mod_params.led_mode, int, 0444); MODULE_PARM_DESC(led_mode, "0=system default, " "1=On(RF On)/Off(RF Off), 2=blinking, 3=Off (default: 0)"); -module_param_named(power_save, iwlwifi_mod_params.power_save, - bool, S_IRUGO); +module_param_named(power_save, iwlwifi_mod_params.power_save, bool, 0444); MODULE_PARM_DESC(power_save, "enable WiFi power management (default: disable)"); -module_param_named(power_level, iwlwifi_mod_params.power_level, - int, S_IRUGO); +module_param_named(power_level, iwlwifi_mod_params.power_level, int, 0444); MODULE_PARM_DESC(power_level, "default power save level (range from 1 - 5, default: 1)"); -module_param_named(fw_monitor, iwlwifi_mod_params.fw_monitor, bool, S_IRUGO); +module_param_named(fw_monitor, iwlwifi_mod_params.fw_monitor, bool, 0444); MODULE_PARM_DESC(fw_monitor, "firmware monitor - to debug FW (default: false - needs lots of memory)"); -module_param_named(d0i3_timeout, iwlwifi_mod_params.d0i3_timeout, - uint, S_IRUGO); +module_param_named(d0i3_timeout, iwlwifi_mod_params.d0i3_timeout, uint, 0444); MODULE_PARM_DESC(d0i3_timeout, "Timeout to D0i3 entry when idle (ms)"); -module_param_named(disable_11ac, iwlwifi_mod_params.disable_11ac, bool, - S_IRUGO); +module_param_named(disable_11ac, iwlwifi_mod_params.disable_11ac, bool, 0444); MODULE_PARM_DESC(disable_11ac, "Disable VHT capabilities (default: false)"); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index 976640fed334..96b52a275ee3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -110,6 +110,8 @@ #define IWL_MVM_SW_TX_CSUM_OFFLOAD 0 #define IWL_MVM_HW_CSUM_DISABLE 0 #define IWL_MVM_PARSE_NVM 0 +#define IWL_MVM_ADWELL_ENABLE 1 +#define IWL_MVM_ADWELL_MAX_BUDGET 0 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 4228fac77f41..f7fcf700196b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -1276,7 +1276,6 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->mvm; - bool prev; u8 value; int ret; @@ -1287,9 +1286,7 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf, return -EINVAL; mutex_lock(&mvm->mutex); - prev = iwl_mvm_vif_low_latency(mvmvif); - mvmvif->low_latency_dbgfs = value; - iwl_mvm_update_low_latency(mvm, vif, prev); + iwl_mvm_update_low_latency(mvm, vif, value, LOW_LATENCY_DEBUGFS); mutex_unlock(&mvm->mutex); return count; @@ -1306,9 +1303,9 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file, len = scnprintf(buf, sizeof(buf) - 1, "traffic=%d\ndbgfs=%d\nvcmd=%d\n", - mvmvif->low_latency_traffic, - mvmvif->low_latency_dbgfs, - mvmvif->low_latency_vcmd); + !!(mvmvif->low_latency & LOW_LATENCY_TRAFFIC), + !!(mvmvif->low_latency & LOW_LATENCY_DEBUGFS), + !!(mvmvif->low_latency & LOW_LATENCY_VCMD)); return simple_read_from_buffer(user_buf, count, ppos, buf, len); } @@ -1506,44 +1503,36 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM && ((vif->type == NL80211_IFTYPE_STATION && !vif->p2p) || (vif->type == NL80211_IFTYPE_STATION && vif->p2p))) - MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, S_IWUSR | - S_IRUSR); - - MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, - S_IRUSR | S_IWUSR); - MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, - S_IRUSR | S_IWUSR); - MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, - S_IRUSR | S_IWUSR); - MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, - S_IRUSR | S_IWUSR); - MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff, - mvmvif->dbgfs_dir, S_IRUSR); + MVM_DEBUGFS_ADD_FILE_VIF(pm_params, mvmvif->dbgfs_dir, 0600); + + MVM_DEBUGFS_ADD_FILE_VIF(tx_pwr_lmt, mvmvif->dbgfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff, mvmvif->dbgfs_dir, 0400); if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && mvmvif == mvm->bf_allowed_vif) - MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, - S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 0600); if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TOF_SUPPORT) && !vif->p2p && (vif->type != NL80211_IFTYPE_P2P_DEVICE)) { if (IWL_MVM_TOF_IS_RESPONDER && vif->type == NL80211_IFTYPE_AP) MVM_DEBUGFS_ADD_FILE_VIF(tof_responder_params, - mvmvif->dbgfs_dir, - S_IRUSR | S_IWUSR); + mvmvif->dbgfs_dir, 0600); MVM_DEBUGFS_ADD_FILE_VIF(tof_range_request, mvmvif->dbgfs_dir, - S_IRUSR | S_IWUSR); + 0600); MVM_DEBUGFS_ADD_FILE_VIF(tof_range_req_ext, mvmvif->dbgfs_dir, - S_IRUSR | S_IWUSR); + 0600); MVM_DEBUGFS_ADD_FILE_VIF(tof_enable, mvmvif->dbgfs_dir, - S_IRUSR | S_IWUSR); + 0600); MVM_DEBUGFS_ADD_FILE_VIF(tof_range_abort, mvmvif->dbgfs_dir, - S_IRUSR | S_IWUSR); + 0600); MVM_DEBUGFS_ADD_FILE_VIF(tof_range_response, mvmvif->dbgfs_dir, - S_IRUSR); + 0400); } /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 9c436d8d001d..0e6401cd7ccc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1914,7 +1914,7 @@ void iwl_mvm_sta_add_debugfs(struct ieee80211_hw *hw, struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); if (iwl_mvm_has_tlc_offload(mvm)) - MVM_DEBUGFS_ADD_STA_FILE(rs_data, dir, S_IRUSR); + MVM_DEBUGFS_ADD_STA_FILE(rs_data, dir, 0400); return; err: @@ -1930,48 +1930,45 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) mvm->debugfs_dir = dbgfs_dir; - MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, S_IWUSR | S_IRUSR); - MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir, - S_IWUSR | S_IRUSR); - MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(ctdp_budget, dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(stop_ctdp, dbgfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(force_ctkill, dbgfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, - S_IRUSR | S_IWUSR); - MVM_DEBUGFS_ADD_FILE(fw_ver, mvm->debugfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, S_IRUSR); - MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(bt_force_ant, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, - S_IWUSR | S_IRUSR); - MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR); - MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR); - MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR); - MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR); - MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, S_IWUSR); + MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(sta_drain, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(nic_temp, dbgfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(ctdp_budget, dbgfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(stop_ctdp, dbgfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(force_ctkill, dbgfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(stations, dbgfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(bt_notif, dbgfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(bt_cmd, dbgfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(fw_ver, mvm->debugfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(bt_force_ant, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, 0200); #ifdef CONFIG_ACPI - MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, S_IRUSR); + MVM_DEBUGFS_ADD_FILE(sar_geo_profile, dbgfs_dir, 0400); #endif if (!debugfs_create_bool("enable_scan_iteration_notif", - S_IRUSR | S_IWUSR, + 0600, mvm->debugfs_dir, &mvm->scan_iter_notif_enabled)) goto err; - if (!debugfs_create_bool("drop_bcn_ap_mode", S_IRUSR | S_IWUSR, + if (!debugfs_create_bool("drop_bcn_ap_mode", 0600, mvm->debugfs_dir, &mvm->drop_bcn_ap_mode)) goto err; @@ -1982,50 +1979,49 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir) if (!bcast_dir) goto err; - if (!debugfs_create_bool("override", S_IRUSR | S_IWUSR, - bcast_dir, - &mvm->dbgfs_bcast_filtering.override)) + if (!debugfs_create_bool("override", 0600, + bcast_dir, + &mvm->dbgfs_bcast_filtering.override)) goto err; MVM_DEBUGFS_ADD_FILE_ALIAS("filters", bcast_filters, - bcast_dir, S_IWUSR | S_IRUSR); + bcast_dir, 0600); MVM_DEBUGFS_ADD_FILE_ALIAS("macs", bcast_filters_macs, - bcast_dir, S_IWUSR | S_IRUSR); + bcast_dir, 0600); } #endif #ifdef CONFIG_PM_SLEEP - MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, S_IRUSR | S_IWUSR); - MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, S_IRUSR); - if (!debugfs_create_bool("d3_wake_sysassert", S_IRUSR | S_IWUSR, + MVM_DEBUGFS_ADD_FILE(d3_sram, mvm->debugfs_dir, 0600); + MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, 0400); + if (!debugfs_create_bool("d3_wake_sysassert", 0600, mvm->debugfs_dir, &mvm->d3_wake_sysassert)) goto err; - if (!debugfs_create_u32("last_netdetect_scans", S_IRUSR, + if (!debugfs_create_u32("last_netdetect_scans", 0400, mvm->debugfs_dir, &mvm->last_netdetect_scans)) goto err; #endif - if (!debugfs_create_u8("ps_disabled", S_IRUSR, + if (!debugfs_create_u8("ps_disabled", 0400, mvm->debugfs_dir, &mvm->ps_disabled)) goto err; - if (!debugfs_create_blob("nvm_hw", S_IRUSR, - mvm->debugfs_dir, &mvm->nvm_hw_blob)) + if (!debugfs_create_blob("nvm_hw", 0400, + mvm->debugfs_dir, &mvm->nvm_hw_blob)) goto err; - if (!debugfs_create_blob("nvm_sw", S_IRUSR, - mvm->debugfs_dir, &mvm->nvm_sw_blob)) + if (!debugfs_create_blob("nvm_sw", 0400, + mvm->debugfs_dir, &mvm->nvm_sw_blob)) goto err; - if (!debugfs_create_blob("nvm_calib", S_IRUSR, - mvm->debugfs_dir, &mvm->nvm_calib_blob)) + if (!debugfs_create_blob("nvm_calib", 0400, + mvm->debugfs_dir, &mvm->nvm_calib_blob)) goto err; - if (!debugfs_create_blob("nvm_prod", S_IRUSR, - mvm->debugfs_dir, &mvm->nvm_prod_blob)) + if (!debugfs_create_blob("nvm_prod", 0400, + mvm->debugfs_dir, &mvm->nvm_prod_blob)) goto err; - if (!debugfs_create_blob("nvm_phy_sku", S_IRUSR, + if (!debugfs_create_blob("nvm_phy_sku", 0400, mvm->debugfs_dir, &mvm->nvm_phy_sku_blob)) goto err; - debugfs_create_file("mem", S_IRUSR | S_IWUSR, dbgfs_dir, mvm, - &iwl_dbgfs_mem_ops); + debugfs_create_file("mem", 0600, dbgfs_dir, mvm, &iwl_dbgfs_mem_ops); /* * Create a symlink with mac80211. It will be removed when mac80211 diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 0920be637b57..3c59109bea20 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -433,6 +433,10 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) /* Set parameters */ phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm)); + + /* set flags extra PHY configuration flags from the device's cfg */ + phy_cfg_cmd.phy_cfg |= cpu_to_le32(mvm->cfg->extra_phy_cfg_flags); + phy_cfg_cmd.calib_control.event_trigger = mvm->fw->default_calib[ucode_type].event_trigger; phy_cfg_cmd.calib_control.flow_trigger = diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index ebf511150f4d..51b30424575b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -421,6 +421,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU); ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); + ieee80211_hw_set(hw, DEAUTH_NEED_MGD_TX_PREP); if (iwl_mvm_has_tlc_offload(mvm)) { ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); @@ -661,6 +662,17 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) NL80211_EXT_FEATURE_SET_SCAN_DWELL); } + if (iwl_mvm_is_oce_supported(mvm)) { + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_ACCEPT_BCAST_PROBE_RESP); + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME); + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION); + wiphy_ext_feature_set(hw->wiphy, + NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE); + } + mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; #ifdef CONFIG_PM_SLEEP @@ -2132,10 +2144,10 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, * Send the bcast station. At this stage the TBTT and DTIM time * events are added and applied to the scheduler */ - iwl_mvm_send_add_bcast_sta(mvm, vif); + ret = iwl_mvm_send_add_bcast_sta(mvm, vif); if (ret) goto out_unbind; - iwl_mvm_add_mcast_sta(mvm, vif); + ret = iwl_mvm_add_mcast_sta(mvm, vif); if (ret) { iwl_mvm_send_rm_bcast_sta(mvm, vif); goto out_unbind; @@ -2804,9 +2816,6 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS; u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS; - if (WARN_ON_ONCE(vif->bss_conf.assoc)) - return; - /* * iwl_mvm_protect_session() reads directly from the device * (the system time), so make sure it is available. @@ -3494,6 +3503,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, ret = 0; goto out; case NL80211_IFTYPE_STATION: + mvmvif->csa_bcn_pending = false; break; case NL80211_IFTYPE_MONITOR: /* always disable PS when a monitor interface is active */ @@ -3537,7 +3547,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, } if (switching_chanctx && vif->type == NL80211_IFTYPE_STATION) { - u32 duration = 2 * vif->bss_conf.beacon_int; + u32 duration = 3 * vif->bss_conf.beacon_int; /* iwl_mvm_protect_session() reads directly from the * device (the system time), so make sure it is @@ -3550,6 +3560,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, /* Protect the session to make sure we hear the first * beacon on the new channel. */ + mvmvif->csa_bcn_pending = true; iwl_mvm_protect_session(mvm, vif, duration, duration, vif->bss_conf.beacon_int / 2, true); @@ -3988,6 +3999,7 @@ static int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw, if (vif->type == NL80211_IFTYPE_STATION) { struct iwl_mvm_sta *mvmsta; + mvmvif->csa_bcn_pending = false; mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 89ff02d7c876..d2cf751db68d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -300,6 +300,18 @@ enum iwl_bt_force_ant_mode { }; /** +* struct iwl_mvm_low_latency_cause - low latency set causes +* @LOW_LATENCY_TRAFFIC: indicates low latency traffic was detected +* @LOW_LATENCY_DEBUGFS: low latency mode set from debugfs +* @LOW_LATENCY_VCMD: low latency mode set from vendor command +*/ +enum iwl_mvm_low_latency_cause { + LOW_LATENCY_TRAFFIC = BIT(0), + LOW_LATENCY_DEBUGFS = BIT(1), + LOW_LATENCY_VCMD = BIT(2), +}; + +/** * struct iwl_mvm_vif_bf_data - beacon filtering related data * @bf_enabled: indicates if beacon filtering is enabled * @ba_enabled: indicated if beacon abort is enabled @@ -335,9 +347,8 @@ struct iwl_mvm_vif_bf_data { * @pm_enabled - Indicate if MAC power management is allowed * @monitor_active: indicates that monitor context is configured, and that the * interface should get quota etc. - * @low_latency_traffic: indicates low latency traffic was detected - * @low_latency_dbgfs: low latency mode set from debugfs - * @low_latency_vcmd: low latency mode set from vendor command + * @low_latency: indicates low latency is set, see + * enum &iwl_mvm_low_latency_cause for causes. * @ps_disabled: indicates that this interface requires PS to be disabled * @queue_params: QoS params for this MAC * @bcast_sta: station used for broadcast packets. Used by the following @@ -367,7 +378,7 @@ struct iwl_mvm_vif { bool ap_ibss_active; bool pm_enabled; bool monitor_active; - bool low_latency_traffic, low_latency_dbgfs, low_latency_vcmd; + u8 low_latency; bool ps_disabled; struct iwl_mvm_vif_bf_data bf_data; @@ -438,6 +449,9 @@ struct iwl_mvm_vif { bool csa_failed; u16 csa_target_freq; + /* Indicates that we are waiting for a beacon on a new channel */ + bool csa_bcn_pending; + /* TCP Checksum Offload */ netdev_features_t features; }; @@ -1152,6 +1166,18 @@ static inline bool iwl_mvm_is_adaptive_dwell_supported(struct iwl_mvm *mvm) IWL_UCODE_TLV_API_ADAPTIVE_DWELL); } +static inline bool iwl_mvm_is_adaptive_dwell_v2_supported(struct iwl_mvm *mvm) +{ + return fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_ADAPTIVE_DWELL_V2); +} + +static inline bool iwl_mvm_is_oce_supported(struct iwl_mvm *mvm) +{ + /* OCE should never be enabled for LMAC scan FWs */ + return fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_OCE); +} + static inline bool iwl_mvm_enter_d0i3_on_suspend(struct iwl_mvm *mvm) { /* For now we only use this mode to differentiate between @@ -1741,7 +1767,8 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm); /* Low latency */ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - bool value); + bool low_latency, + enum iwl_mvm_low_latency_cause cause); /* get SystemLowLatencyMode - only needed for beacon threshold? */ bool iwl_mvm_low_latency(struct iwl_mvm *mvm); /* get VMACLowLatencyMode */ @@ -1757,9 +1784,17 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif) * binding, so this has no real impact. For now, just return * the current desired low-latency state. */ - return mvmvif->low_latency_dbgfs || - mvmvif->low_latency_traffic || - mvmvif->low_latency_vcmd; + return mvmvif->low_latency; +} + +static inline +void iwl_mvm_vif_set_low_latency(struct iwl_mvm_vif *mvmvif, bool set, + enum iwl_mvm_low_latency_cause cause) +{ + if (set) + mvmvif->low_latency |= cause; + else + mvmvif->low_latency &= ~cause; } /* hw scheduler queue config */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index ab7fb5aad984..224bfa1bcf53 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -104,14 +104,14 @@ struct iwl_mvm_mod_params iwlmvm_mod_params = { /* rest of fields are 0 by default */ }; -module_param_named(init_dbg, iwlmvm_mod_params.init_dbg, bool, S_IRUGO); +module_param_named(init_dbg, iwlmvm_mod_params.init_dbg, bool, 0444); MODULE_PARM_DESC(init_dbg, "set to true to debug an ASSERT in INIT fw (default: false"); -module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, S_IRUGO); +module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, 0444); MODULE_PARM_DESC(power_scheme, "power management scheme: 1-active, 2-balanced, 3-low power, default: 2"); module_param_named(tfd_q_hang_detect, iwlmvm_mod_params.tfd_q_hang_detect, - bool, S_IRUGO); + bool, 0444); MODULE_PARM_DESC(tfd_q_hang_detect, "TFD queues hang detection (default: true"); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 305cd56bf746..7f5434b34d0d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -18,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -34,6 +30,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -286,6 +283,20 @@ void iwl_mvm_phy_ctxt_unref(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt) return; ctxt->ref--; + + /* + * Move unused phy's to a default channel. When the phy is moved the, + * fw will cleanup immediate quiet bit if it was previously set, + * otherwise we might not be able to reuse this phy. + */ + if (ctxt->ref == 0) { + struct ieee80211_channel *chan; + struct cfg80211_chan_def chandef; + + chan = &mvm->hw->wiphy->bands[NL80211_BAND_2GHZ]->channels[0]; + cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); + iwl_mvm_phy_ctxt_changed(mvm, ctxt, &chandef, 1, 1); + } } static void iwl_mvm_binding_iterator(void *_data, u8 *mac, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index 55d1274c6092..fb5745660509 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -234,13 +234,15 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) struct iwl_mvm_sta *mvmsta; struct iwl_lq_sta_rs_fw *lq_sta; + rcu_read_lock(); + notif = (void *)pkt->data; mvmsta = iwl_mvm_sta_from_staid_rcu(mvm, notif->sta_id); if (!mvmsta) { IWL_ERR(mvm, "Invalid sta id (%d) in FW TLC notification\n", notif->sta_id); - return; + goto out; } lq_sta = &mvmsta->lq_sta.rs_fw; @@ -251,6 +253,8 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm, struct iwl_rx_packet *pkt) IWL_DEBUG_RATE(mvm, "new rate_n_flags: 0x%X\n", lq_sta->last_rate_n_flags); } +out: + rcu_read_unlock(); } void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c index 47f4c7a1d80d..5d776ec1840f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c @@ -4010,18 +4010,18 @@ static void rs_drv_add_sta_debugfs(void *mvm, void *priv_sta, if (!mvmsta->vif) return; - debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir, + debugfs_create_file("rate_scale_table", 0600, dir, lq_sta, &rs_sta_dbgfs_scale_table_ops); - debugfs_create_file("rate_stats_table", S_IRUSR, dir, + debugfs_create_file("rate_stats_table", 0400, dir, lq_sta, &rs_sta_dbgfs_stats_table_ops); - debugfs_create_file("drv_tx_stats", S_IRUSR | S_IWUSR, dir, + debugfs_create_file("drv_tx_stats", 0600, dir, lq_sta, &rs_sta_dbgfs_drv_tx_stats_ops); - debugfs_create_u8("tx_agg_tid_enable", S_IRUSR | S_IWUSR, dir, + debugfs_create_u8("tx_agg_tid_enable", 0600, dir, &lq_sta->tx_agg_tid_en); - debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir, + debugfs_create_u8("reduced_tpc", 0600, dir, &lq_sta->pers.dbg_fixed_txp_reduction); - MVM_DEBUGFS_ADD_FILE_RS(ss_force, dir, S_IRUSR | S_IWUSR); + MVM_DEBUGFS_ADD_FILE_RS(ss_force, dir, 0600); return; err: IWL_ERR((struct iwl_mvm *)mvm, "Can't create debugfs entity\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 580de5851fc7..4a4ccfd11e5b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -831,6 +831,16 @@ out: rcu_read_unlock(); } +static void iwl_mvm_flip_address(u8 *addr) +{ + int i; + u8 mac_addr[ETH_ALEN]; + + for (i = 0; i < ETH_ALEN; i++) + mac_addr[i] = addr[ETH_ALEN - i - 1]; + ether_addr_copy(addr, mac_addr); +} + void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue) { @@ -985,21 +995,16 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, */ if ((desc->mac_flags2 & IWL_RX_MPDU_MFLG2_AMSDU) && !WARN_ON(!ieee80211_is_data_qos(hdr->frame_control))) { - int i; u8 *qc = ieee80211_get_qos_ctl(hdr); - u8 mac_addr[ETH_ALEN]; *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; - for (i = 0; i < ETH_ALEN; i++) - mac_addr[i] = hdr->addr3[ETH_ALEN - i - 1]; - ether_addr_copy(hdr->addr3, mac_addr); + if (mvm->trans->cfg->device_family == + IWL_DEVICE_FAMILY_9000) { + iwl_mvm_flip_address(hdr->addr3); - if (ieee80211_has_a4(hdr->frame_control)) { - for (i = 0; i < ETH_ALEN; i++) - mac_addr[i] = - hdr->addr4[ETH_ALEN - i - 1]; - ether_addr_copy(hdr->addr4, mac_addr); + if (ieee80211_has_a4(hdr->frame_control)) + iwl_mvm_flip_address(hdr->addr4); } } if (baid != IWL_RX_REORDER_DATA_INVALID_BAID) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 356b16f40e78..b31f0ffbbbf0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -35,6 +35,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -85,6 +86,17 @@ enum iwl_mvm_traffic_load { #define IWL_SCAN_DWELL_PASSIVE 110 #define IWL_SCAN_DWELL_FRAGMENTED 44 #define IWL_SCAN_DWELL_EXTENDED 90 +#define IWL_SCAN_NUM_OF_FRAGS 3 + + +/* adaptive dwell max budget time [TU] for full scan */ +#define IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN 300 +/* adaptive dwell max budget time [TU] for directed scan */ +#define IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN 100 +/* adaptive dwell default APs number */ +#define IWL_SCAN_ADWELL_DEFAULT_N_APS 2 +/* adaptive dwell default APs number in social channels (1, 6, 11) */ +#define IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL 10 struct iwl_mvm_scan_timing_params { u32 suspend_time; @@ -134,6 +146,9 @@ static inline void *iwl_mvm_get_scan_req_umac_data(struct iwl_mvm *mvm) { struct iwl_scan_req_umac *cmd = mvm->scan_cmd; + if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) + return (void *)&cmd->v8.data; + if (iwl_mvm_is_adaptive_dwell_supported(mvm)) return (void *)&cmd->v7.data; @@ -143,6 +158,23 @@ static inline void *iwl_mvm_get_scan_req_umac_data(struct iwl_mvm *mvm) return (void *)&cmd->v1.data; } +static inline struct iwl_scan_umac_chan_param * +iwl_mvm_get_scan_req_umac_channel(struct iwl_mvm *mvm) +{ + struct iwl_scan_req_umac *cmd = mvm->scan_cmd; + + if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) + return &cmd->v8.channel; + + if (iwl_mvm_is_adaptive_dwell_supported(mvm)) + return &cmd->v7.channel; + + if (iwl_mvm_has_new_tx_api(mvm)) + return &cmd->v6.channel; + + return &cmd->v1.channel; +} + static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm) { if (mvm->scan_rx_ant != ANT_NONE) @@ -1113,66 +1145,92 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm, struct iwl_scan_req_umac *cmd, struct iwl_mvm_scan_params *params) { - struct iwl_mvm_scan_timing_params *timing = &scan_timing[params->type]; + struct iwl_mvm_scan_timing_params *timing, *hb_timing; + u8 active_dwell, passive_dwell; - if (iwl_mvm_is_regular_scan(params)) - cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); - else - cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_2); + timing = &scan_timing[params->type]; + active_dwell = params->measurement_dwell ? + params->measurement_dwell : IWL_SCAN_DWELL_ACTIVE; + passive_dwell = params->measurement_dwell ? + params->measurement_dwell : IWL_SCAN_DWELL_PASSIVE; if (iwl_mvm_is_adaptive_dwell_supported(mvm)) { - if (params->measurement_dwell) { - cmd->v7.active_dwell = params->measurement_dwell; - cmd->v7.passive_dwell = params->measurement_dwell; - } else { - cmd->v7.active_dwell = IWL_SCAN_DWELL_ACTIVE; - cmd->v7.passive_dwell = IWL_SCAN_DWELL_PASSIVE; - } - cmd->v7.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED; + cmd->v7.adwell_default_n_aps_social = + IWL_SCAN_ADWELL_DEFAULT_N_APS_SOCIAL; + cmd->v7.adwell_default_n_aps = + IWL_SCAN_ADWELL_DEFAULT_N_APS; + + /* if custom max budget was configured with debugfs */ + if (IWL_MVM_ADWELL_MAX_BUDGET) + cmd->v7.adwell_max_budget = + cpu_to_le16(IWL_MVM_ADWELL_MAX_BUDGET); + else if (params->ssids && params->ssids[0].ssid_len) + cmd->v7.adwell_max_budget = + cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_DIRECTED_SCAN); + else + cmd->v7.adwell_max_budget = + cpu_to_le16(IWL_SCAN_ADWELL_MAX_BUDGET_FULL_SCAN); cmd->v7.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); cmd->v7.max_out_time[SCAN_LB_LMAC_IDX] = cpu_to_le32(timing->max_out_time); cmd->v7.suspend_time[SCAN_LB_LMAC_IDX] = cpu_to_le32(timing->suspend_time); + if (iwl_mvm_is_cdb_supported(mvm)) { + hb_timing = &scan_timing[params->type]; + cmd->v7.max_out_time[SCAN_HB_LMAC_IDX] = - cpu_to_le32(timing->max_out_time); + cpu_to_le32(hb_timing->max_out_time); cmd->v7.suspend_time[SCAN_HB_LMAC_IDX] = - cpu_to_le32(timing->suspend_time); + cpu_to_le32(hb_timing->suspend_time); } - return; - } - - if (params->measurement_dwell) { - cmd->v1.active_dwell = params->measurement_dwell; - cmd->v1.passive_dwell = params->measurement_dwell; - cmd->v1.extended_dwell = params->measurement_dwell; + if (!iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) { + cmd->v7.active_dwell = active_dwell; + cmd->v7.passive_dwell = passive_dwell; + cmd->v7.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED; + } else { + cmd->v8.active_dwell[SCAN_LB_LMAC_IDX] = active_dwell; + cmd->v8.passive_dwell[SCAN_LB_LMAC_IDX] = passive_dwell; + if (iwl_mvm_is_cdb_supported(mvm)) { + cmd->v8.active_dwell[SCAN_HB_LMAC_IDX] = + active_dwell; + cmd->v8.passive_dwell[SCAN_HB_LMAC_IDX] = + passive_dwell; + } + } } else { - cmd->v1.active_dwell = IWL_SCAN_DWELL_ACTIVE; - cmd->v1.passive_dwell = IWL_SCAN_DWELL_PASSIVE; - cmd->v1.extended_dwell = IWL_SCAN_DWELL_EXTENDED; - } - cmd->v1.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED; + cmd->v1.extended_dwell = params->measurement_dwell ? + params->measurement_dwell : IWL_SCAN_DWELL_EXTENDED; + cmd->v1.active_dwell = active_dwell; + cmd->v1.passive_dwell = passive_dwell; + cmd->v1.fragmented_dwell = IWL_SCAN_DWELL_FRAGMENTED; - if (iwl_mvm_has_new_tx_api(mvm)) { - cmd->v6.scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); - cmd->v6.max_out_time[SCAN_LB_LMAC_IDX] = - cpu_to_le32(timing->max_out_time); - cmd->v6.suspend_time[SCAN_LB_LMAC_IDX] = - cpu_to_le32(timing->suspend_time); if (iwl_mvm_is_cdb_supported(mvm)) { + hb_timing = &scan_timing[params->type]; + cmd->v6.max_out_time[SCAN_HB_LMAC_IDX] = - cpu_to_le32(timing->max_out_time); + cpu_to_le32(hb_timing->max_out_time); cmd->v6.suspend_time[SCAN_HB_LMAC_IDX] = + cpu_to_le32(hb_timing->suspend_time); + } + + if (iwl_mvm_has_new_tx_api(mvm)) { + cmd->v6.scan_priority = + cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); + cmd->v6.max_out_time[SCAN_LB_LMAC_IDX] = + cpu_to_le32(timing->max_out_time); + cmd->v6.suspend_time[SCAN_LB_LMAC_IDX] = + cpu_to_le32(timing->suspend_time); + } else { + cmd->v1.scan_priority = + cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); + cmd->v1.max_out_time = + cpu_to_le32(timing->max_out_time); + cmd->v1.suspend_time = cpu_to_le32(timing->suspend_time); } - } else { - cmd->v1.max_out_time = cpu_to_le32(timing->max_out_time); - cmd->v1.suspend_time = cpu_to_le32(timing->suspend_time); - cmd->v1.scan_priority = - cpu_to_le32(IWL_SCAN_PRIORITY_EXT_6); } } @@ -1234,11 +1292,39 @@ static u16 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm, if (mvm->sched_scan_pass_all == SCHED_SCAN_PASS_ALL_ENABLED) flags |= IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE; + if (iwl_mvm_is_adaptive_dwell_supported(mvm) && IWL_MVM_ADWELL_ENABLE && + vif->type != NL80211_IFTYPE_P2P_DEVICE) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_ADAPTIVE_DWELL; + + /* + * Extended dwell is relevant only for low band to start with, as it is + * being used for social channles only (1, 6, 11), so we can check + * only scan type on low band also for CDB. + */ if (iwl_mvm_is_regular_scan(params) && vif->type != NL80211_IFTYPE_P2P_DEVICE && - params->type != IWL_SCAN_TYPE_FRAGMENTED) + params->type != IWL_SCAN_TYPE_FRAGMENTED && + !iwl_mvm_is_adaptive_dwell_supported(mvm) && + !iwl_mvm_is_oce_supported(mvm)) flags |= IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL; + if (iwl_mvm_is_oce_supported(mvm)) { + if ((params->flags & + NL80211_SCAN_FLAG_OCE_PROBE_REQ_HIGH_TX_RATE)) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_PROB_REQ_HIGH_TX_RATE; + /* Since IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL and + * NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION shares + * the same bit, we need to make sure that we use this bit here + * only when IWL_UMAC_SCAN_GEN_FLAGS_EXTENDED_DWELL cannot be + * used. */ + if ((params->flags & + NL80211_SCAN_FLAG_OCE_PROBE_REQ_DEFERRAL_SUPPRESSION) && + !WARN_ON_ONCE(!iwl_mvm_is_adaptive_dwell_supported(mvm))) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_PROB_REQ_DEFER_SUPP; + if ((params->flags & NL80211_SCAN_FLAG_FILS_MAX_CHANNEL_TIME)) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_MAX_CHNL_TIME; + } + return flags; } @@ -1247,6 +1333,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int type) { struct iwl_scan_req_umac *cmd = mvm->scan_cmd; + struct iwl_scan_umac_chan_param *chan_param; void *cmd_data = iwl_mvm_get_scan_req_umac_data(mvm); struct iwl_scan_req_umac_tail *sec_part = cmd_data + sizeof(struct iwl_scan_channel_cfg_umac) * @@ -1254,8 +1341,11 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int uid, i; u32 ssid_bitmap = 0; u8 channel_flags = 0; + u16 gen_flags; struct iwl_mvm_vif *scan_vif = iwl_mvm_vif_from_mac80211(vif); + chan_param = iwl_mvm_get_scan_req_umac_channel(mvm); + lockdep_assert_held(&mvm->mutex); if (WARN_ON(params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS)) @@ -1272,8 +1362,17 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvm->scan_uid_status[uid] = type; cmd->uid = cpu_to_le32(uid); - cmd->general_flags = cpu_to_le16(iwl_mvm_scan_umac_flags(mvm, params, - vif)); + gen_flags = iwl_mvm_scan_umac_flags(mvm, params, vif); + cmd->general_flags = cpu_to_le16(gen_flags); + if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) { + if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED) + cmd->v8.num_of_fragments[SCAN_LB_LMAC_IDX] = + IWL_SCAN_NUM_OF_FRAGS; + if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_LMAC2_FRAGMENTED) + cmd->v8.num_of_fragments[SCAN_HB_LMAC_IDX] = + IWL_SCAN_NUM_OF_FRAGS; + } + cmd->scan_start_mac_id = scan_vif->id; if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT) @@ -1284,16 +1383,8 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; - if (iwl_mvm_is_adaptive_dwell_supported(mvm)) { - cmd->v7.channel_flags = channel_flags; - cmd->v7.n_channels = params->n_channels; - } else if (iwl_mvm_has_new_tx_api(mvm)) { - cmd->v6.channel_flags = channel_flags; - cmd->v6.n_channels = params->n_channels; - } else { - cmd->v1.channel_flags = channel_flags; - cmd->v1.n_channels = params->n_channels; - } + chan_param->flags = channel_flags; + chan_param->count = params->n_channels; iwl_scan_build_ssids(params, sec_part->direct_scan, &ssid_bitmap); @@ -1732,7 +1823,9 @@ int iwl_mvm_scan_size(struct iwl_mvm *mvm) { int base_size = IWL_SCAN_REQ_UMAC_SIZE_V1; - if (iwl_mvm_is_adaptive_dwell_supported(mvm)) + if (iwl_mvm_is_adaptive_dwell_v2_supported(mvm)) + base_size = IWL_SCAN_REQ_UMAC_SIZE_V8; + else if (iwl_mvm_is_adaptive_dwell_supported(mvm)) base_size = IWL_SCAN_REQ_UMAC_SIZE_V7; else if (iwl_mvm_has_new_tx_api(mvm)) base_size = IWL_SCAN_REQ_UMAC_SIZE_V6; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 630e23cb0ffb..80067eb9ea05 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1695,7 +1695,8 @@ int iwl_mvm_allocate_int_sta(struct iwl_mvm *mvm, u32 qmask, enum nl80211_iftype iftype, enum iwl_sta_type type) { - if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { + if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) || + sta->sta_id == IWL_MVM_INVALID_STA) { sta->sta_id = iwl_mvm_find_free_sta_id(mvm, iftype); if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA)) return -ENOSPC; @@ -2478,28 +2479,12 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, /* * Note the possible cases: - * 1. In DQA mode with an enabled TXQ - TXQ needs to become agg'ed - * 2. Non-DQA mode: the TXQ hasn't yet been enabled, so find a free - * one and mark it as reserved - * 3. In DQA mode, but no traffic yet on this TID: same treatment as in - * non-DQA mode, since the TXQ hasn't yet been allocated - * Don't support case 3 for new TX path as it is not expected to happen - * and aggregation will be offloaded soon anyway + * 1. An enabled TXQ - TXQ needs to become agg'ed + * 2. The TXQ hasn't yet been enabled, so find a free one and mark + * it as reserved */ txq_id = mvmsta->tid_data[tid].txq_id; - if (iwl_mvm_has_new_tx_api(mvm)) { - if (txq_id == IWL_MVM_INVALID_QUEUE) { - ret = -ENXIO; - goto release_locks; - } - } else if (unlikely(mvm->queue_info[txq_id].status == - IWL_MVM_QUEUE_SHARED)) { - ret = -ENXIO; - IWL_DEBUG_TX_QUEUES(mvm, - "Can't start tid %d agg on shared queue!\n", - tid); - goto release_locks; - } else if (mvm->queue_info[txq_id].status != IWL_MVM_QUEUE_READY) { + if (txq_id == IWL_MVM_INVALID_QUEUE) { txq_id = iwl_mvm_find_free_queue(mvm, mvmsta->sta_id, IWL_MVM_DQA_MIN_DATA_QUEUE, IWL_MVM_DQA_MAX_DATA_QUEUE); @@ -2508,16 +2493,16 @@ int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, IWL_ERR(mvm, "Failed to allocate agg queue\n"); goto release_locks; } - /* - * TXQ shouldn't be in inactive mode for non-DQA, so getting - * an inactive queue from iwl_mvm_find_free_queue() is - * certainly a bug - */ - WARN_ON(mvm->queue_info[txq_id].status == - IWL_MVM_QUEUE_INACTIVE); /* TXQ hasn't yet been enabled, so mark it only as reserved */ mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_RESERVED; + } else if (unlikely(mvm->queue_info[txq_id].status == + IWL_MVM_QUEUE_SHARED)) { + ret = -ENXIO; + IWL_DEBUG_TX_QUEUES(mvm, + "Can't start tid %d agg on shared queue!\n", + tid); + goto release_locks; } spin_unlock(&mvm->queue_info_lock); @@ -2696,8 +2681,10 @@ out: static void iwl_mvm_unreserve_agg_queue(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, - u16 txq_id) + struct iwl_mvm_tid_data *tid_data) { + u16 txq_id = tid_data->txq_id; + if (iwl_mvm_has_new_tx_api(mvm)) return; @@ -2709,8 +2696,10 @@ static void iwl_mvm_unreserve_agg_queue(struct iwl_mvm *mvm, * allocated through iwl_mvm_enable_txq, so we can just mark it back as * free. */ - if (mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_RESERVED) + if (mvm->queue_info[txq_id].status == IWL_MVM_QUEUE_RESERVED) { mvm->queue_info[txq_id].status = IWL_MVM_QUEUE_FREE; + tid_data->txq_id = IWL_MVM_INVALID_QUEUE; + } spin_unlock_bh(&mvm->queue_info_lock); } @@ -2741,7 +2730,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvmsta->agg_tids &= ~BIT(tid); - iwl_mvm_unreserve_agg_queue(mvm, mvmsta, txq_id); + iwl_mvm_unreserve_agg_queue(mvm, mvmsta, tid_data); switch (tid_data->state) { case IWL_AGG_ON: @@ -2808,7 +2797,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif, mvmsta->agg_tids &= ~BIT(tid); spin_unlock_bh(&mvmsta->lock); - iwl_mvm_unreserve_agg_queue(mvm, mvmsta, txq_id); + iwl_mvm_unreserve_agg_queue(mvm, mvmsta, tid_data); if (old_state >= IWL_AGG_ON) { iwl_mvm_drain_sta(mvm, mvmsta, true); @@ -3233,17 +3222,9 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, } sta_id = mvm_sta->sta_id; - if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC || - keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || - keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) { - ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, - false); - goto end; - } - /* * It is possible that the 'sta' parameter is NULL, and thus - * there is a need to retrieve the sta from the local station + * there is a need to retrieve the sta from the local station * table. */ if (!sta) { @@ -3258,6 +3239,17 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm, if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif)) return -EINVAL; + } else { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + sta_id = mvmvif->mcast_sta.sta_id; + } + + if (keyconf->cipher == WLAN_CIPHER_SUITE_AES_CMAC || + keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || + keyconf->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256) { + ret = iwl_mvm_send_sta_igtk(mvm, keyconf, sta_id, false); + goto end; } /* If the key_offset is not pre-assigned, we need to find a diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index acb217e666db..cd91bc44259c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -8,6 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -18,11 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110, - * USA - * * The full GNU General Public License is included in this distribution * in the file called COPYING. * @@ -35,6 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -198,9 +195,13 @@ static bool iwl_mvm_te_check_disconnect(struct iwl_mvm *mvm, struct ieee80211_vif *vif, const char *errmsg) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + if (vif->type != NL80211_IFTYPE_STATION) return false; - if (vif->bss_conf.assoc && vif->bss_conf.dtim_period) + + if (!mvmvif->csa_bcn_pending && vif->bss_conf.assoc && + vif->bss_conf.dtim_period) return false; if (errmsg) IWL_ERR(mvm, "%s\n", errmsg); @@ -344,7 +345,7 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, * and know the dtim period. */ iwl_mvm_te_check_disconnect(mvm, te_data->vif, - "No association and the time event is over already..."); + "No beacon heard and the time event is over already..."); break; default: break; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index af6dfceab6b8..795065974d78 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -687,6 +687,74 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb) } #ifdef CONFIG_INET + +static int +iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes, + netdev_features_t netdev_flags, + struct sk_buff_head *mpdus_skb) +{ + struct sk_buff *tmp, *next; + struct ieee80211_hdr *hdr = (void *)skb->data; + char cb[sizeof(skb->cb)]; + u16 i = 0; + unsigned int tcp_payload_len; + unsigned int mss = skb_shinfo(skb)->gso_size; + bool ipv4 = (skb->protocol == htons(ETH_P_IP)); + u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0; + + skb_shinfo(skb)->gso_size = num_subframes * mss; + memcpy(cb, skb->cb, sizeof(cb)); + + next = skb_gso_segment(skb, netdev_flags); + skb_shinfo(skb)->gso_size = mss; + if (WARN_ON_ONCE(IS_ERR(next))) + return -EINVAL; + else if (next) + consume_skb(skb); + + while (next) { + tmp = next; + next = tmp->next; + + memcpy(tmp->cb, cb, sizeof(tmp->cb)); + /* + * Compute the length of all the data added for the A-MSDU. + * This will be used to compute the length to write in the TX + * command. We have: SNAP + IP + TCP for n -1 subframes and + * ETH header for n subframes. + */ + tcp_payload_len = skb_tail_pointer(tmp) - + skb_transport_header(tmp) - + tcp_hdrlen(tmp) + tmp->data_len; + + if (ipv4) + ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes); + + if (tcp_payload_len > mss) { + skb_shinfo(tmp)->gso_size = mss; + } else { + if (ieee80211_is_data_qos(hdr->frame_control)) { + u8 *qc; + + if (ipv4) + ip_send_check(ip_hdr(tmp)); + + qc = ieee80211_get_qos_ctl((void *)tmp->data); + *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; + } + skb_shinfo(tmp)->gso_size = 0; + } + + tmp->prev = NULL; + tmp->next = NULL; + + __skb_queue_tail(mpdus_skb, tmp); + i++; + } + + return 0; +} + static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_tx_info *info, struct ieee80211_sta *sta, @@ -695,14 +763,10 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct ieee80211_hdr *hdr = (void *)skb->data; unsigned int mss = skb_shinfo(skb)->gso_size; - struct sk_buff *tmp, *next; - char cb[sizeof(skb->cb)]; unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len; - bool ipv4 = (skb->protocol == htons(ETH_P_IP)); - u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0; - u16 snap_ip_tcp, pad, i = 0; + u16 snap_ip_tcp, pad; unsigned int dbg_max_amsdu_len; - netdev_features_t netdev_features = NETIF_F_CSUM_MASK | NETIF_F_SG; + netdev_features_t netdev_flags = NETIF_F_CSUM_MASK | NETIF_F_SG; u8 *qc, tid, txf; snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) + @@ -712,16 +776,8 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, if (!sta->max_amsdu_len || !ieee80211_is_data_qos(hdr->frame_control) || - (!mvmsta->tlc_amsdu && !dbg_max_amsdu_len)) { - num_subframes = 1; - pad = 0; - goto segment; - } - - qc = ieee80211_get_qos_ctl(hdr); - tid = *qc & IEEE80211_QOS_CTL_TID_MASK; - if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) - return -EINVAL; + (!mvmsta->tlc_amsdu && !dbg_max_amsdu_len)) + return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); /* * Do not build AMSDU for IPv6 with extension headers. @@ -730,22 +786,22 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, if (skb->protocol == htons(ETH_P_IPV6) && ((struct ipv6hdr *)skb_network_header(skb))->nexthdr != IPPROTO_TCP) { - num_subframes = 1; - pad = 0; - netdev_features &= ~NETIF_F_CSUM_MASK; - goto segment; + netdev_flags &= ~NETIF_F_CSUM_MASK; + return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); } + qc = ieee80211_get_qos_ctl(hdr); + tid = *qc & IEEE80211_QOS_CTL_TID_MASK; + if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT)) + return -EINVAL; + /* * No need to lock amsdu_in_ampdu_allowed since it can't be modified * during an BA session. */ if (info->flags & IEEE80211_TX_CTL_AMPDU && - !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed) { - num_subframes = 1; - pad = 0; - goto segment; - } + !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed) + return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb); max_amsdu_len = sta->max_amsdu_len; @@ -811,56 +867,8 @@ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, * Trick the segmentation function to make it * create SKBs that can fit into one A-MSDU. */ -segment: - skb_shinfo(skb)->gso_size = num_subframes * mss; - memcpy(cb, skb->cb, sizeof(cb)); - - next = skb_gso_segment(skb, netdev_features); - skb_shinfo(skb)->gso_size = mss; - if (WARN_ON_ONCE(IS_ERR(next))) - return -EINVAL; - else if (next) - consume_skb(skb); - - while (next) { - tmp = next; - next = tmp->next; - - memcpy(tmp->cb, cb, sizeof(tmp->cb)); - /* - * Compute the length of all the data added for the A-MSDU. - * This will be used to compute the length to write in the TX - * command. We have: SNAP + IP + TCP for n -1 subframes and - * ETH header for n subframes. - */ - tcp_payload_len = skb_tail_pointer(tmp) - - skb_transport_header(tmp) - - tcp_hdrlen(tmp) + tmp->data_len; - - if (ipv4) - ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes); - - if (tcp_payload_len > mss) { - skb_shinfo(tmp)->gso_size = mss; - } else { - if (ieee80211_is_data_qos(hdr->frame_control)) { - qc = ieee80211_get_qos_ctl((void *)tmp->data); - - if (ipv4) - ip_send_check(ip_hdr(tmp)); - *qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT; - } - skb_shinfo(tmp)->gso_size = 0; - } - - tmp->prev = NULL; - tmp->next = NULL; - - __skb_queue_tail(mpdus_skb, tmp); - i++; - } - - return 0; + return iwl_mvm_tx_tso_segment(skb, num_subframes, netdev_flags, + mpdus_skb); } #else /* CONFIG_INET */ static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb, @@ -1894,14 +1902,12 @@ int iwl_mvm_flush_sta(struct iwl_mvm *mvm, void *sta, bool internal, u32 flags) struct iwl_mvm_int_sta *int_sta = sta; struct iwl_mvm_sta *mvm_sta = sta; - if (iwl_mvm_has_new_tx_api(mvm)) { - if (internal) - return iwl_mvm_flush_sta_tids(mvm, int_sta->sta_id, - BIT(IWL_MGMT_TID), flags); + BUILD_BUG_ON(offsetof(struct iwl_mvm_int_sta, sta_id) != + offsetof(struct iwl_mvm_sta, sta_id)); + if (iwl_mvm_has_new_tx_api(mvm)) return iwl_mvm_flush_sta_tids(mvm, mvm_sta->sta_id, - 0xFF, flags); - } + 0xff | BIT(IWL_MGMT_TID), flags); if (internal) return iwl_mvm_flush_tx_path(mvm, int_sta->tfd_queue_msk, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index d65e1db7c097..bebcfb44c8c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -800,12 +800,19 @@ int iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, int mac80211_queue, .scd_queue = queue, .action = SCD_CFG_DISABLE_QUEUE, }; - bool remove_mac_queue = true; + bool remove_mac_queue = mac80211_queue != IEEE80211_INVAL_HW_QUEUE; int ret; + if (WARN_ON(remove_mac_queue && mac80211_queue >= IEEE80211_MAX_QUEUES)) + return -EINVAL; + if (iwl_mvm_has_new_tx_api(mvm)) { spin_lock_bh(&mvm->queue_info_lock); - mvm->hw_queue_to_mac80211[queue] &= ~BIT(mac80211_queue); + + if (remove_mac_queue) + mvm->hw_queue_to_mac80211[queue] &= + ~BIT(mac80211_queue); + spin_unlock_bh(&mvm->queue_info_lock); iwl_trans_txq_free(mvm->trans, queue); @@ -1027,14 +1034,18 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm) } int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - bool prev) + bool low_latency, + enum iwl_mvm_low_latency_cause cause) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int res; - bool low_latency; + bool prev; lockdep_assert_held(&mvm->mutex); + prev = iwl_mvm_vif_low_latency(mvmvif); + iwl_mvm_vif_set_low_latency(mvmvif, low_latency, cause); + low_latency = iwl_mvm_vif_low_latency(mvmvif); if (low_latency == prev) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 56fc28750a41..959de2f8bb28 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -8,6 +8,7 @@ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016-2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -36,6 +37,7 @@ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * All rights reserved. * Copyright(c) 2017 Intel Deutschland GmbH + * Copyright(c) 2018 Intel Corporation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -517,9 +519,9 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x24FD, 0x9074, iwl8265_2ac_cfg)}, /* 9000 Series */ - {IWL_PCI_DEVICE(0x2526, 0x0000, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0014, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x0018, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0030, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0034, iwl9560_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x0038, iwl9560_2ac_cfg)}, @@ -544,11 +546,15 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2526, 0x1410, iwl9270_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x1420, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x1610, iwl9270_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x4010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x2526, 0x4030, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x4034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x40A4, iwl9460_2ac_cfg)}, - {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2526, 0x4234, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2526, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2526, 0xA014, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0010, iwl9160_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0014, iwl9160_2ac_cfg)}, {IWL_PCI_DEVICE(0x271B, 0x0210, iwl9160_2ac_cfg)}, @@ -569,38 +575,146 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2720, 0x0264, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x02A0, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x4030, iwl9560_2ac_cfg)}, + {IWL_PCI_DEVICE(0x2720, 0x4034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x2720, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x2720, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0038, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x003C, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x0060, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x0064, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x00A0, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x023C, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x0260, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x0264, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x02A0, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x30DC, 0x02A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0060, iwl9460_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0064, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x00A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x00A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0230, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0234, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0238, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x023C, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0260, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x0264, iwl9461_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x02A0, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x02A4, iwl9462_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x4034, iwl9560_2ac_cfg_soc)}, - {IWL_PCI_DEVICE(0x31DC, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x30DC, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x30DC, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x2034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x4030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x30DC, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x31DC, 0x0030, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0034, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0038, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x003C, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0060, iwl9460_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0064, iwl9461_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x00A0, iwl9462_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x00A4, iwl9462_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0230, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0234, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0238, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x023C, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0260, iwl9461_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x0264, iwl9461_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x02A0, iwl9462_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x02A4, iwl9462_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x31DC, 0x1030, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x31DC, 0x2030, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x2034, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x4030, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x4034, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x40A4, iwl9462_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x4234, iwl9560_2ac_cfg_shared_clk)}, + {IWL_PCI_DEVICE(0x31DC, 0x42A4, iwl9462_2ac_cfg_shared_clk)}, {IWL_PCI_DEVICE(0x34F0, 0x0030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0038, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0060, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x02A0, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x34F0, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x34F0, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x34F0, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x2034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x4030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x34F0, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0038, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0060, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x02A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3DF0, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x3DF0, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x2034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x4030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x3DF0, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0038, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0060, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x02A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x43F0, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x43F0, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x2034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x4030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x43F0, 0x42A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0000, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0010, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0030, iwl9560_2ac_cfg_soc)}, @@ -626,11 +740,44 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x9DF0, 0x0610, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0710, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x0A10, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0x9DF0, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x1210, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0x9DF0, 0x2010, iwl9460_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl9460_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x4030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x4034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0x9DF0, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0x9DF0, 0x42A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0038, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x003C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0060, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0064, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x00A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x00A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0230, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0238, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x023C, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0260, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x0264, iwl9461_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x02A0, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1010, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA0F0, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x2034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x4030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x4034, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA0F0, 0x42A4, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x0030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x0034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x0038, iwl9560_2ac_cfg_soc)}, @@ -647,10 +794,16 @@ static const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0xA370, 0x0264, iwl9461_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x02A0, iwl9462_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x02A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x1010, iwl9260_2ac_cfg)}, {IWL_PCI_DEVICE(0xA370, 0x1030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x1210, iwl9260_2ac_cfg)}, + {IWL_PCI_DEVICE(0xA370, 0x2030, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x2034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x4030, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x4034, iwl9560_2ac_cfg_soc)}, {IWL_PCI_DEVICE(0xA370, 0x40A4, iwl9462_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x4234, iwl9560_2ac_cfg_soc)}, + {IWL_PCI_DEVICE(0xA370, 0x42A4, iwl9462_2ac_cfg_soc)}, /* 22000 Series */ {IWL_PCI_DEVICE(0x2720, 0x0A10, iwl22000_2ac_cfg_hr_cdb)}, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index b406b536c850..f8a0234d332c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2616,12 +2616,12 @@ int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) { struct dentry *dir = trans->dbgfs_dir; - DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR); - DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR); - DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR); - DEBUGFS_ADD_FILE(csr, dir, S_IWUSR); - DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR); - DEBUGFS_ADD_FILE(rfkill, dir, S_IWUSR | S_IRUSR); + DEBUGFS_ADD_FILE(rx_queue, dir, 0400); + DEBUGFS_ADD_FILE(tx_queue, dir, 0400); + DEBUGFS_ADD_FILE(interrupt, dir, 0600); + DEBUGFS_ADD_FILE(csr, dir, 0200); + DEBUGFS_ADD_FILE(fh_reg, dir, 0400); + DEBUGFS_ADD_FILE(rfkill, dir, 0600); return 0; err: diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index ab6d39e12069..1c6d428515a4 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -27,7 +27,7 @@ #include "lmac.h" static bool modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); MODULE_AUTHOR("Michael Wu <flamingice@sourmilk.net>"); MODULE_DESCRIPTION("Softmac Prism54 common code"); diff --git a/drivers/net/wireless/marvell/mwifiex/11n.c b/drivers/net/wireless/marvell/mwifiex/11n.c index feebfdcf025a..5d75c971004b 100644 --- a/drivers/net/wireless/marvell/mwifiex/11n.c +++ b/drivers/net/wireless/marvell/mwifiex/11n.c @@ -356,17 +356,19 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv, case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) { ht_cap->ht_cap.cap_info &= - ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cpu_to_le16 + (~IEEE80211_HT_CAP_SUP_WIDTH_20_40); ht_cap->ht_cap.cap_info &= - ~IEEE80211_HT_CAP_SGI_40; + cpu_to_le16(~IEEE80211_HT_CAP_SGI_40); } break; case IEEE80211_HT_PARAM_CHA_SEC_BELOW: if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) { ht_cap->ht_cap.cap_info &= - ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; + cpu_to_le16 + (~IEEE80211_HT_CAP_SUP_WIDTH_20_40); ht_cap->ht_cap.cap_info &= - ~IEEE80211_HT_CAP_SGI_40; + cpu_to_le16(~IEEE80211_HT_CAP_SGI_40); } break; } diff --git a/drivers/net/wireless/mediatek/mt76/debugfs.c b/drivers/net/wireless/mediatek/mt76/debugfs.c index c121b502a462..a38d05dea599 100644 --- a/drivers/net/wireless/mediatek/mt76/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/debugfs.c @@ -64,13 +64,13 @@ struct dentry *mt76_register_debugfs(struct mt76_dev *dev) if (!dir) return NULL; - debugfs_create_u8("led_pin", S_IRUSR | S_IWUSR, dir, &dev->led_pin); - debugfs_create_u32("regidx", S_IRUSR | S_IWUSR, dir, &dev->debugfs_reg); - debugfs_create_file_unsafe("regval", S_IRUSR | S_IWUSR, dir, dev, + debugfs_create_u8("led_pin", 0600, dir, &dev->led_pin); + debugfs_create_u32("regidx", 0600, dir, &dev->debugfs_reg); + debugfs_create_file_unsafe("regval", 0600, dir, dev, &fops_regval); - debugfs_create_blob("eeprom", S_IRUSR, dir, &dev->eeprom); + debugfs_create_blob("eeprom", 0400, dir, &dev->eeprom); if (dev->otp.data) - debugfs_create_blob("otp", S_IRUSR, dir, &dev->otp); + debugfs_create_blob("otp", 0400, dir, &dev->otp); debugfs_create_devm_seqfile(dev->dev, "queues", dir, mt76_queues_read); return dir; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c index 612feb593d7d..955ea3e692dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_debugfs.c @@ -123,11 +123,11 @@ void mt76x2_init_debugfs(struct mt76x2_dev *dev) if (!dir) return; - debugfs_create_u8("temperature", S_IRUSR, dir, &dev->cal.temp); - debugfs_create_bool("tpc", S_IRUSR | S_IWUSR, dir, &dev->enable_tpc); + debugfs_create_u8("temperature", 0400, dir, &dev->cal.temp); + debugfs_create_bool("tpc", 0600, dir, &dev->enable_tpc); - debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat); - debugfs_create_file("dfs_stats", S_IRUSR, dir, dev, &fops_dfs_stat); + debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat); + debugfs_create_file("dfs_stats", 0400, dir, dev, &fops_dfs_stat); debugfs_create_devm_seqfile(dev->mt76.dev, "txpower", dir, read_txpower); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c index 25f4cebef26d..73c127f92613 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_main.c @@ -336,6 +336,17 @@ mt76x2_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, int idx = key->keyidx; int ret; + /* fall back to sw encryption for unsupported ciphers */ + switch (key->cipher) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + case WLAN_CIPHER_SUITE_TKIP: + case WLAN_CIPHER_SUITE_CCMP: + break; + default: + return -EOPNOTSUPP; + } + /* * The hardware does not support per-STA RX GTK, fall back * to software mode for these. diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c index 15820b11f9db..dfd36d736b06 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_mcu.c @@ -187,7 +187,7 @@ mt76pci_load_firmware(struct mt76x2_dev *dev) { const struct firmware *fw; const struct mt76x2_fw_header *hdr; - int i, len, ret; + int len, ret; __le32 *cur; u32 offset, val; @@ -240,16 +240,7 @@ mt76pci_load_firmware(struct mt76x2_dev *dev) /* trigger firmware */ mt76_wr(dev, MT_MCU_INT_LEVEL, 2); - for (i = 200; i > 0; i--) { - val = mt76_rr(dev, MT_MCU_COM_REG0); - - if (val & 1) - break; - - msleep(10); - } - - if (!i) { + if (!mt76_poll_msec(dev, MT_MCU_COM_REG0, 1, 1, 200)) { dev_err(dev->mt76.dev, "Firmware failed to start\n"); release_firmware(fw); return -ETIMEDOUT; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c index 534e4bf9a34c..e46eafc4c436 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2_tx.c @@ -36,9 +36,12 @@ void mt76x2_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, msta = (struct mt76x2_sta *) control->sta->drv_priv; wcid = &msta->wcid; + /* sw encrypted frames */ + if (!info->control.hw_key && wcid->hw_key_idx != -1) + control->sta = NULL; } - if (vif || (!info->control.hw_key && wcid->hw_key_idx != -1)) { + if (vif && !control->sta) { struct mt76x2_vif *mvif; mvif = (struct mt76x2_vif *) vif->drv_priv; diff --git a/drivers/net/wireless/mediatek/mt7601u/debugfs.c b/drivers/net/wireless/mediatek/mt7601u/debugfs.c index fc008475a03b..991a6a729b1e 100644 --- a/drivers/net/wireless/mediatek/mt7601u/debugfs.c +++ b/drivers/net/wireless/mediatek/mt7601u/debugfs.c @@ -160,13 +160,11 @@ void mt7601u_init_debugfs(struct mt7601u_dev *dev) if (!dir) return; - debugfs_create_u8("temperature", S_IRUSR, dir, &dev->raw_temp); - debugfs_create_u32("temp_mode", S_IRUSR, dir, &dev->temp_mode); - - debugfs_create_u32("regidx", S_IRUSR | S_IWUSR, dir, &dev->debugfs_reg); - debugfs_create_file("regval", S_IRUSR | S_IWUSR, dir, dev, - &fops_regval); - debugfs_create_file("ampdu_stat", S_IRUSR, dir, dev, &fops_ampdu_stat); - debugfs_create_file("eeprom_param", S_IRUSR, dir, dev, - &fops_eeprom_param); + debugfs_create_u8("temperature", 0400, dir, &dev->raw_temp); + debugfs_create_u32("temp_mode", 0400, dir, &dev->temp_mode); + + debugfs_create_u32("regidx", 0600, dir, &dev->debugfs_reg); + debugfs_create_file("regval", 0600, dir, dev, &fops_regval); + debugfs_create_file("ampdu_stat", 0400, dir, dev, &fops_ampdu_stat); + debugfs_create_file("eeprom_param", 0400, dir, dev, &fops_eeprom_param); } diff --git a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c index f4b48b77c491..3df8c4b895e7 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2500usb.c @@ -37,7 +37,7 @@ * Allow hardware encryption to be disabled. */ static bool modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); /* diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c index 5cf655ff1430..1172eefd1c1a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c @@ -49,7 +49,7 @@ * Allow hardware encryption to be disabled. */ static bool modparam_nohwcrypt = false; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); static bool rt2800pci_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c index a985a5a7945e..6848ebc83534 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c @@ -41,7 +41,7 @@ /* Allow hardware encryption to be disabled. */ static bool modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); static bool rt2800soc_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c index 24fc6d2045ef..d901a41d36e4 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c @@ -43,7 +43,7 @@ * Allow hardware encryption to be disabled. */ static bool modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); static bool rt2800usb_hwcrypt_disabled(struct rt2x00_dev *rt2x00dev) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c index ac2572943ed0..0eee479583b8 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00debug.c @@ -606,7 +606,7 @@ static struct dentry *rt2x00debug_create_file_driver(const char *name, data += sprintf(data, "version:\t%s\n", DRV_VERSION); blob->size = strlen(blob->data); - return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob); + return debugfs_create_blob(name, 0400, intf->driver_folder, blob); } static struct dentry *rt2x00debug_create_file_chipset(const char *name, @@ -647,7 +647,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name, blob->size = strlen(blob->data); - return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob); + return debugfs_create_blob(name, 0400, intf->driver_folder, blob); } void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) @@ -682,13 +682,13 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) if (IS_ERR(intf->chipset_entry) || !intf->chipset_entry) goto exit; - intf->dev_flags = debugfs_create_file("dev_flags", S_IRUSR, + intf->dev_flags = debugfs_create_file("dev_flags", 0400, intf->driver_folder, intf, &rt2x00debug_fop_dev_flags); if (IS_ERR(intf->dev_flags) || !intf->dev_flags) goto exit; - intf->cap_flags = debugfs_create_file("cap_flags", S_IRUSR, + intf->cap_flags = debugfs_create_file("cap_flags", 0400, intf->driver_folder, intf, &rt2x00debug_fop_cap_flags); if (IS_ERR(intf->cap_flags) || !intf->cap_flags) @@ -699,27 +699,28 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) if (IS_ERR(intf->register_folder) || !intf->register_folder) goto exit; -#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \ -({ \ - if (debug->__name.read) { \ - (__intf)->__name##_off_entry = \ - debugfs_create_u32(__stringify(__name) "_offset", \ - S_IRUSR | S_IWUSR, \ - (__intf)->register_folder, \ - &(__intf)->offset_##__name); \ - if (IS_ERR((__intf)->__name##_off_entry) \ - || !(__intf)->__name##_off_entry) \ - goto exit; \ - \ - (__intf)->__name##_val_entry = \ - debugfs_create_file(__stringify(__name) "_value", \ - S_IRUSR | S_IWUSR, \ - (__intf)->register_folder, \ - (__intf), &rt2x00debug_fop_##__name); \ - if (IS_ERR((__intf)->__name##_val_entry) \ - || !(__intf)->__name##_val_entry) \ - goto exit; \ - } \ +#define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \ +({ \ + if (debug->__name.read) { \ + (__intf)->__name##_off_entry = \ + debugfs_create_u32(__stringify(__name) "_offset", \ + 0600, \ + (__intf)->register_folder, \ + &(__intf)->offset_##__name); \ + if (IS_ERR((__intf)->__name##_off_entry) || \ + !(__intf)->__name##_off_entry) \ + goto exit; \ + \ + (__intf)->__name##_val_entry = \ + debugfs_create_file(__stringify(__name) "_value", \ + 0600, \ + (__intf)->register_folder, \ + (__intf), \ + &rt2x00debug_fop_##__name); \ + if (IS_ERR((__intf)->__name##_val_entry) || \ + !(__intf)->__name##_val_entry) \ + goto exit; \ + } \ }) RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(intf, csr); @@ -736,8 +737,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) goto exit; intf->queue_frame_dump_entry = - debugfs_create_file("dump", S_IRUSR, intf->queue_folder, - intf, &rt2x00debug_fop_queue_dump); + debugfs_create_file("dump", 0400, intf->queue_folder, + intf, &rt2x00debug_fop_queue_dump); if (IS_ERR(intf->queue_frame_dump_entry) || !intf->queue_frame_dump_entry) goto exit; @@ -746,14 +747,15 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) init_waitqueue_head(&intf->frame_dump_waitqueue); intf->queue_stats_entry = - debugfs_create_file("queue", S_IRUSR, intf->queue_folder, - intf, &rt2x00debug_fop_queue_stats); + debugfs_create_file("queue", 0400, intf->queue_folder, + intf, &rt2x00debug_fop_queue_stats); #ifdef CONFIG_RT2X00_LIB_CRYPTO if (rt2x00_has_cap_hw_crypto(rt2x00dev)) intf->crypto_stats_entry = - debugfs_create_file("crypto", S_IRUGO, intf->queue_folder, - intf, &rt2x00debug_fop_crypto_stats); + debugfs_create_file("crypto", 0444, intf->queue_folder, + intf, + &rt2x00debug_fop_crypto_stats); #endif return; diff --git a/drivers/net/wireless/ralink/rt2x00/rt61pci.c b/drivers/net/wireless/ralink/rt2x00/rt61pci.c index 234310200759..cb0e1196f2c2 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt61pci.c +++ b/drivers/net/wireless/ralink/rt2x00/rt61pci.c @@ -40,7 +40,7 @@ * Allow hardware encryption to be disabled. */ static bool modparam_nohwcrypt = false; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); /* diff --git a/drivers/net/wireless/ralink/rt2x00/rt73usb.c b/drivers/net/wireless/ralink/rt2x00/rt73usb.c index 9a212823f42c..319ec4f2d9d2 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt73usb.c +++ b/drivers/net/wireless/ralink/rt2x00/rt73usb.c @@ -38,7 +38,7 @@ * Allow hardware encryption to be disabled. */ static bool modparam_nohwcrypt; -module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); /* diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 0133fcd4601b..7f9b16b97ea3 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -2815,9 +2815,11 @@ static int __init init_ray_cs(void) proc_mkdir("driver/ray_cs", NULL); proc_create("driver/ray_cs/ray_cs", 0, NULL, &ray_cs_proc_fops); - proc_create("driver/ray_cs/essid", S_IWUSR, NULL, &ray_cs_essid_proc_fops); - proc_create_data("driver/ray_cs/net_type", S_IWUSR, NULL, &int_proc_fops, &net_type); - proc_create_data("driver/ray_cs/translate", S_IWUSR, NULL, &int_proc_fops, &translate); + proc_create("driver/ray_cs/essid", 0200, NULL, &ray_cs_essid_proc_fops); + proc_create_data("driver/ray_cs/net_type", 0200, NULL, &int_proc_fops, + &net_type); + proc_create_data("driver/ray_cs/translate", 0200, NULL, &int_proc_fops, + &translate); #endif if (translate != 0) translate = 1; diff --git a/drivers/net/wireless/realtek/rtlwifi/base.c b/drivers/net/wireless/realtek/rtlwifi/base.c index 6db3389e2ced..762a29cdf7ad 100644 --- a/drivers/net/wireless/realtek/rtlwifi/base.c +++ b/drivers/net/wireless/realtek/rtlwifi/base.c @@ -1549,7 +1549,6 @@ u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx, /* EAPOL is seens as in-4way */ rtlpriv->btcoexist.btc_info.in_4way = true; rtlpriv->btcoexist.btc_info.in_4way_ts = jiffies; - rtlpriv->btcoexist.btc_info.in_4way_ts = jiffies; RT_TRACE(rtlpriv, (COMP_SEND | COMP_RECV), DBG_DMESG, "802.1X %s EAPOL pkt!!\n", (is_tx) ? "Tx" : "Rx"); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c index 05beb16f0a0a..59553db020ef 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b1ant.c @@ -1436,6 +1436,7 @@ static void halbtc8723b1ant_ps_tdma(struct btc_coexist *btcoexist, coex_dm->pre_ps_tdma = coex_dm->cur_ps_tdma; } +static void btc8723b1ant_tdma_dur_adj_for_acl(struct btc_coexist *btcoexist, u8 wifi_status) { diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c index 4907c2ffadfe..73ec31972944 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8723b2ant.c @@ -833,9 +833,9 @@ static void btc8723b2ant_set_sw_fulltime_dac_swing(struct btc_coexist *btcoex, btc8723b2ant_set_dac_swing_reg(btcoex, 0x18); } -void btc8723b2ant_dac_swing(struct btc_coexist *btcoexist, - bool force_exec, bool dac_swing_on, - u32 dac_swing_lvl) +static void btc8723b2ant_dac_swing(struct btc_coexist *btcoexist, + bool force_exec, bool dac_swing_on, + u32 dac_swing_lvl) { struct rtl_priv *rtlpriv = btcoexist->adapter; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c index 0b26419881c0..202597cf8915 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a1ant.c @@ -426,39 +426,6 @@ static void btc8821a1ant_query_bt_info(struct btc_coexist *btcoexist) btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); } -bool btc8821a1ant_is_wifi_status_changed(struct btc_coexist *btcoexist) -{ - static bool pre_wifi_busy = true; - static bool pre_under_4way = true; - static bool pre_bt_hs_on = true; - bool wifi_busy = false, under_4way = false, bt_hs_on = false; - bool wifi_connected = false; - - btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_CONNECTED, - &wifi_connected); - btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_BUSY, &wifi_busy); - btcoexist->btc_get(btcoexist, BTC_GET_BL_HS_OPERATION, &bt_hs_on); - btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_4_WAY_PROGRESS, - &under_4way); - - if (wifi_connected) { - if (wifi_busy != pre_wifi_busy) { - pre_wifi_busy = wifi_busy; - return true; - } - if (under_4way != pre_under_4way) { - pre_under_4way = under_4way; - return true; - } - if (bt_hs_on != pre_bt_hs_on) { - pre_bt_hs_on = bt_hs_on; - return true; - } - } - - return false; -} - static void btc8821a1ant_update_bt_link_info(struct btc_coexist *btcoexist) { struct btc_bt_link_info *bt_link_info = &btcoexist->bt_link_info; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c index d5f282cb9d24..2202d5e18977 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtc8821a2ant.c @@ -359,7 +359,7 @@ static void btc8821a2ant_query_bt_info(struct btc_coexist *btcoexist) btcoexist->btc_fill_h2c(btcoexist, 0x61, 1, h2c_parameter); } -bool btc8821a2ant_is_wifi_status_changed(struct btc_coexist *btcoexist) +static bool btc8821a2ant_is_wifi_status_changed(struct btc_coexist *btcoexist) { static bool pre_wifi_busy = true; static bool pre_under_4way = true; @@ -1517,7 +1517,7 @@ static void btc8821a2ant_action_bt_inquiry(struct btc_coexist *btcoexist) btc8821a2ant_sw_mechanism2(btcoexist, false, false, false, 0x18); } -void btc8821a2ant_action_wifi_link_process(struct btc_coexist *btcoexist) +static void btc8821a2ant_action_wifi_link_process(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; u8 u8tmpa, u8tmpb; diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c index 823694cb4fdb..8b6b07a936f5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.c @@ -363,6 +363,22 @@ static void halbtc_normal_lps(struct btc_coexist *btcoexist) } } +static void halbtc_pre_normal_lps(struct btc_coexist *btcoexist) +{ + struct rtl_priv *rtlpriv = btcoexist->adapter; + + if (btcoexist->bt_info.bt_ctrl_lps) { + btcoexist->bt_info.bt_lps_on = false; + rtl_lps_leave(rtlpriv->mac80211.hw); + } +} + +static void halbtc_post_normal_lps(struct btc_coexist *btcoexist) +{ + if (btcoexist->bt_info.bt_ctrl_lps) + btcoexist->bt_info.bt_ctrl_lps = false; +} + static void halbtc_leave_low_power(struct btc_coexist *btcoexist) { } @@ -577,6 +593,9 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) tmp = true; *bool_tmp = tmp; break; + case BTC_GET_BL_WIFI_DUAL_BAND_CONNECTED: + *u8_tmp = BTC_MULTIPORT_SCC; + break; case BTC_GET_BL_WIFI_BUSY: if (halbtc_is_wifi_busy(rtlpriv)) *bool_tmp = true; @@ -637,6 +656,9 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) case BTC_GET_BL_IS_ASUS_8723B: *bool_tmp = false; break; + case BTC_GET_BL_RF4CE_CONNECTED: + *bool_tmp = false; + break; case BTC_GET_S4_WIFI_RSSI: *s32_tmp = halbtc_get_wifi_rssi(rtlpriv); break; @@ -677,6 +699,21 @@ static bool halbtc_get(void *void_btcoexist, u8 get_type, void *out_buf) case BTC_GET_U4_BT_FORBIDDEN_SLOT_VAL: *u32_tmp = halbtc_get_bt_forbidden_slot_val(btcoexist); break; + case BTC_GET_U4_WIFI_IQK_TOTAL: + *u32_tmp = + btcoexist->btc_phydm_query_phy_counter(btcoexist, + DM_INFO_IQK_ALL); + break; + case BTC_GET_U4_WIFI_IQK_OK: + *u32_tmp = + btcoexist->btc_phydm_query_phy_counter(btcoexist, + DM_INFO_IQK_OK); + break; + case BTC_GET_U4_WIFI_IQK_FAIL: + *u32_tmp = + btcoexist->btc_phydm_query_phy_counter(btcoexist, + DM_INFO_IQK_NG); + break; case BTC_GET_U1_WIFI_DOT11_CHNL: *u8_tmp = rtlphy->current_channel; break; @@ -788,6 +825,12 @@ static bool halbtc_set(void *void_btcoexist, u8 set_type, void *in_buf) case BTC_SET_ACT_NORMAL_LPS: halbtc_normal_lps(btcoexist); break; + case BTC_SET_ACT_PRE_NORMAL_LPS: + halbtc_pre_normal_lps(btcoexist); + break; + case BTC_SET_ACT_POST_NORMAL_LPS: + halbtc_post_normal_lps(btcoexist); + break; case BTC_SET_ACT_DISABLE_LOW_POWER: halbtc_disable_low_power(btcoexist, *bool_tmp); break; @@ -1101,6 +1144,11 @@ static void halbtc_display_dbg_msg(void *bt_context, u8 disp_type, } } +static u32 halbtc_get_bt_reg(void *btc_context, u8 reg_type, u32 offset) +{ + return 0; +} + static bool halbtc_under_ips(struct btc_coexist *btcoexist) { struct rtl_priv *rtlpriv = btcoexist->adapter; @@ -1119,6 +1167,25 @@ static bool halbtc_under_ips(struct btc_coexist *btcoexist) return false; } +static +u32 halbtc_get_phydm_version(void *btc_context) +{ + return 0; +} + +static +void halbtc_phydm_modify_ra_pcr_threshold(void *btc_context, + u8 ra_offset_direction, + u8 ra_threshold_offset) +{ +} + +static +u32 halbtc_phydm_query_phy_counter(void *btc_context, enum dm_info_query dm_id) +{ + return 0; +} + static u8 halbtc_get_ant_det_val_from_bt(void *btc_context) { struct btc_coexist *btcoexist = (struct btc_coexist *)btc_context; @@ -1232,6 +1299,7 @@ bool exhalbtc_initlize_variables(struct rtl_priv *rtlpriv) btcoexist->btc_get = halbtc_get; btcoexist->btc_set = halbtc_set; btcoexist->btc_set_bt_reg = halbtc_set_bt_reg; + btcoexist->btc_get_bt_reg = halbtc_get_bt_reg; btcoexist->bt_info.bt_ctrl_buf_size = false; btcoexist->bt_info.agg_buf_size = 5; @@ -1242,6 +1310,10 @@ bool exhalbtc_initlize_variables(struct rtl_priv *rtlpriv) halbtc_get_bt_coex_supported_feature; btcoexist->btc_get_bt_coex_supported_version = halbtc_get_bt_coex_supported_version; + btcoexist->btc_get_bt_phydm_version = halbtc_get_phydm_version; + btcoexist->btc_phydm_modify_ra_pcr_threshold = + halbtc_phydm_modify_ra_pcr_threshold; + btcoexist->btc_phydm_query_phy_counter = halbtc_phydm_query_phy_counter; btcoexist->btc_get_ant_det_val_from_bt = halbtc_get_ant_det_val_from_bt; btcoexist->btc_get_ble_scan_type_from_bt = halbtc_get_ble_scan_type_from_bt; @@ -1547,7 +1619,8 @@ void exhalbtc_scan_notify_wifi_only(struct wifi_only_cfg *wifionly_cfg, void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action) { - u8 asso_type; + u8 asso_type, asso_type_v2; + bool wifi_under_5g; if (!halbtc_is_bt_coexist_available(btcoexist)) return; @@ -1555,10 +1628,17 @@ void exhalbtc_connect_notify(struct btc_coexist *btcoexist, u8 action) if (btcoexist->manual_control) return; - if (action) + btcoexist->btc_get(btcoexist, BTC_GET_BL_WIFI_UNDER_5G, &wifi_under_5g); + + if (action) { asso_type = BTC_ASSOCIATE_START; - else + asso_type_v2 = wifi_under_5g ? BTC_ASSOCIATE_5G_START : + BTC_ASSOCIATE_START; + } else { asso_type = BTC_ASSOCIATE_FINISH; + asso_type_v2 = wifi_under_5g ? BTC_ASSOCIATE_5G_FINISH : + BTC_ASSOCIATE_FINISH; + } halbtc_leave_low_power(btcoexist); diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h index f5d8159a88eb..9eae87d19120 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/halbtcoutsrc.h @@ -62,6 +62,8 @@ #define BTC_ANT_PATH_WIFI 0 #define BTC_ANT_PATH_BT 1 #define BTC_ANT_PATH_PTA 2 +#define BTC_ANT_PATH_WIFI5G 3 +#define BTC_ANT_PATH_AUTO 4 /* dual Antenna definition */ #define BTC_ANT_WIFI_AT_MAIN 0 #define BTC_ANT_WIFI_AT_AUX 1 @@ -154,6 +156,7 @@ struct btc_board_info { u8 rfe_type; u8 ant_div_cfg; + u8 customer_id; }; enum btc_dbg_opcode { @@ -204,6 +207,7 @@ enum btc_wifi_traffic_dir { enum btc_wifi_pnp { BTC_WIFI_PNP_WAKE_UP = 0x0, BTC_WIFI_PNP_SLEEP = 0x1, + BTC_WIFI_PNP_SLEEP_KEEP_ANT = 0x2, BTC_WIFI_PNP_MAX }; @@ -250,6 +254,7 @@ enum btc_get_type { BTC_GET_BL_HS_OPERATION, BTC_GET_BL_HS_CONNECTING, BTC_GET_BL_WIFI_CONNECTED, + BTC_GET_BL_WIFI_DUAL_BAND_CONNECTED, BTC_GET_BL_WIFI_BUSY, BTC_GET_BL_WIFI_SCAN, BTC_GET_BL_WIFI_LINK, @@ -333,6 +338,7 @@ enum btc_set_type { BTC_SET_ACT_GET_BT_RSSI, BTC_SET_ACT_AGGREGATE_CTRL, BTC_SET_ACT_ANTPOSREGRISTRY_CTRL, + BTC_SET_MIMO_PS_MODE, /********* for 1Ant **********/ /* type bool */ @@ -347,8 +353,11 @@ enum btc_set_type { BTC_SET_ACT_LEAVE_LPS, BTC_SET_ACT_ENTER_LPS, BTC_SET_ACT_NORMAL_LPS, + BTC_SET_ACT_PRE_NORMAL_LPS, + BTC_SET_ACT_POST_NORMAL_LPS, BTC_SET_ACT_INC_FORCE_EXEC_PWR_CMD_CNT, BTC_SET_ACT_DISABLE_LOW_POWER, + BTC_SET_BL_BT_LNA_CONSTRAIN_LEVEL, BTC_SET_ACT_UPDATE_RAMASK, BTC_SET_ACT_SEND_MIMO_PS, /* BT Coex related */ @@ -383,6 +392,7 @@ enum btc_notify_type_lps { enum btc_notify_type_scan { BTC_SCAN_FINISH = 0x0, BTC_SCAN_START = 0x1, + BTC_SCAN_START_2G = 0x2, BTC_SCAN_MAX }; @@ -397,6 +407,8 @@ enum btc_notify_type_switchband { enum btc_notify_type_associate { BTC_ASSOCIATE_FINISH = 0x0, BTC_ASSOCIATE_START = 0x1, + BTC_ASSOCIATE_5G_FINISH = 0x2, + BTC_ASSOCIATE_5G_START = 0x3, BTC_ASSOCIATE_MAX }; @@ -435,6 +447,107 @@ enum btc_notify_type_stack_operation { BTC_STACK_OP_MAX }; +enum { + BTC_CCK_1, + BTC_CCK_2, + BTC_CCK_5_5, + BTC_CCK_11, + BTC_OFDM_6, + BTC_OFDM_9, + BTC_OFDM_12, + BTC_OFDM_18, + BTC_OFDM_24, + BTC_OFDM_36, + BTC_OFDM_48, + BTC_OFDM_54, + BTC_MCS_0, + BTC_MCS_1, + BTC_MCS_2, + BTC_MCS_3, + BTC_MCS_4, + BTC_MCS_5, + BTC_MCS_6, + BTC_MCS_7, + BTC_MCS_8, + BTC_MCS_9, + BTC_MCS_10, + BTC_MCS_11, + BTC_MCS_12, + BTC_MCS_13, + BTC_MCS_14, + BTC_MCS_15, + BTC_MCS_16, + BTC_MCS_17, + BTC_MCS_18, + BTC_MCS_19, + BTC_MCS_20, + BTC_MCS_21, + BTC_MCS_22, + BTC_MCS_23, + BTC_MCS_24, + BTC_MCS_25, + BTC_MCS_26, + BTC_MCS_27, + BTC_MCS_28, + BTC_MCS_29, + BTC_MCS_30, + BTC_MCS_31, + BTC_VHT_1SS_MCS_0, + BTC_VHT_1SS_MCS_1, + BTC_VHT_1SS_MCS_2, + BTC_VHT_1SS_MCS_3, + BTC_VHT_1SS_MCS_4, + BTC_VHT_1SS_MCS_5, + BTC_VHT_1SS_MCS_6, + BTC_VHT_1SS_MCS_7, + BTC_VHT_1SS_MCS_8, + BTC_VHT_1SS_MCS_9, + BTC_VHT_2SS_MCS_0, + BTC_VHT_2SS_MCS_1, + BTC_VHT_2SS_MCS_2, + BTC_VHT_2SS_MCS_3, + BTC_VHT_2SS_MCS_4, + BTC_VHT_2SS_MCS_5, + BTC_VHT_2SS_MCS_6, + BTC_VHT_2SS_MCS_7, + BTC_VHT_2SS_MCS_8, + BTC_VHT_2SS_MCS_9, + BTC_VHT_3SS_MCS_0, + BTC_VHT_3SS_MCS_1, + BTC_VHT_3SS_MCS_2, + BTC_VHT_3SS_MCS_3, + BTC_VHT_3SS_MCS_4, + BTC_VHT_3SS_MCS_5, + BTC_VHT_3SS_MCS_6, + BTC_VHT_3SS_MCS_7, + BTC_VHT_3SS_MCS_8, + BTC_VHT_3SS_MCS_9, + BTC_VHT_4SS_MCS_0, + BTC_VHT_4SS_MCS_1, + BTC_VHT_4SS_MCS_2, + BTC_VHT_4SS_MCS_3, + BTC_VHT_4SS_MCS_4, + BTC_VHT_4SS_MCS_5, + BTC_VHT_4SS_MCS_6, + BTC_VHT_4SS_MCS_7, + BTC_VHT_4SS_MCS_8, + BTC_VHT_4SS_MCS_9, + BTC_MCS_32, + BTC_UNKNOWN, + BTC_PKT_MGNT, + BTC_PKT_CTRL, + BTC_PKT_UNKNOWN, + BTC_PKT_NOT_FOR_ME, + BTC_RATE_MAX +}; + +enum { + BTC_MULTIPORT_SCC, + BTC_MULTIPORT_MCC_2CHANNEL, + BTC_MULTIPORT_MCC_2BAND, + BTC_MULTIPORT_MAX +}; + struct btc_bt_info { bool bt_disabled; u8 rssi_adjust_for_agc_table_on; @@ -454,6 +567,7 @@ struct btc_bt_info { u16 bt_hci_ver; u16 bt_real_fw_ver; u8 bt_fw_ver; + u32 bt_get_fw_ver; bool bt_disable_low_pwr; @@ -525,6 +639,7 @@ struct btc_bt_link_info { bool pan_exist; bool pan_only; bool slave_role; + bool acl_busy; }; enum btc_antenna_pos { @@ -625,8 +740,15 @@ struct btc_coexist { void (*btc_set_bt_reg)(void *btc_context, u8 reg_type, u32 offset, u32 value); + u32 (*btc_get_bt_reg)(void *btc_context, u8 reg_type, u32 offset); u32 (*btc_get_bt_coex_supported_feature)(void *btcoexist); u32 (*btc_get_bt_coex_supported_version)(void *btcoexist); + u32 (*btc_get_bt_phydm_version)(void *btcoexist); + void (*btc_phydm_modify_ra_pcr_threshold)(void *btcoexist, + u8 ra_offset_direction, + u8 ra_threshold_offset); + u32 (*btc_phydm_query_phy_counter)(void *btcoexist, + enum dm_info_query dm_id); u8 (*btc_get_ant_det_val_from_bt)(void *btcoexist); u8 (*btc_get_ble_scan_type_from_bt)(void *btcoexist); u32 (*btc_get_ble_scan_para_from_bt)(void *btcoexist, u8 scan_type); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/pwrseq.h b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/pwrseq.h index f2d9c6116e5c..8379a3e5198c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/pwrseq.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/pwrseq.h @@ -142,7 +142,7 @@ /*wait power state to suspend*/}, \ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(4), 0 \ - /*0x04[12:11] = 2b'01enable WL suspend*/}, + /*0x04[12:11] = 2b'00 disable WL suspend*/}, #define RTL8188EE_TRANS_CARDEMU_TO_CARDDIS \ {0x0026, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ @@ -179,7 +179,7 @@ /*wait power state to suspend*/}, \ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0 \ - /*0x04[12:11] = 2b'01enable WL suspend*/}, + /*0x04[12:11] = 2b'00 disable WL suspend*/}, #define RTL8188EE_TRANS_CARDEMU_TO_PDN \ {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/pwrseq.h b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/pwrseq.h index 781eeaa6af49..c570801508cc 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/pwrseq.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/pwrseq.h @@ -134,7 +134,7 @@ /*wait power state to suspend*/ \ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ PWR_BASEADDR_SDIO , PWR_CMD_POLLING, BIT(1), BIT(1)}, \ - /*0x04[12:11] = 2b'01enable WL suspend*/ \ + /*0x04[12:11] = 2b'00 disable WL suspend*/ \ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(3) | BIT(4), 0}, @@ -181,7 +181,7 @@ /*Lock small LDO Register*/ \ {0x00CC, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(2), 0}, \ - /*0x04[12:11] = 2b'01enable WL suspend*/ \ + /*0x04[12:11] = 2b'00 disable WL suspend*/ \ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ PWR_BASEADDR_MAC , PWR_CMD_WRITE, BIT(3) | BIT(4), 0}, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/pwrseq.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/pwrseq.h index 4ac7db526f15..e6c3aac3e9fd 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/pwrseq.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/pwrseq.h @@ -135,7 +135,7 @@ /*wait power state to suspend*/ \ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\ PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},\ - /*0x04[12:11] = 2b'01enable WL suspend*/ \ + /*0x04[12:11] = 2b'00 disable WL suspend*/ \ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, @@ -172,7 +172,7 @@ {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \ PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO,\ PWR_CMD_POLLING, BIT(1), BIT(1)},\ - /*0x04[12:11] = 2b'00enable WL suspend*/ \ + /*0x04[12:11] = 2b'00 disable WL suspend*/ \ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, \ PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC,\ PWR_CMD_WRITE, BIT(3)|BIT(4), 0},\ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/pwrseq.h b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/pwrseq.h index 0fee5e0e55c2..3367cfbc9502 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/pwrseq.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/pwrseq.h @@ -204,7 +204,7 @@ /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, \ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, \ - /*0x04[12:11] = 2b'01enable WL suspend*/ \ + /*0x04[12:11] = 2b'00 disable WL suspend*/ \ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, @@ -251,7 +251,7 @@ /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/ \ {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, \ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, \ - /*0x04[12:11] = 2b'01enable WL suspend*/ \ + /*0x04[12:11] = 2b'00 disable WL suspend*/ \ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, \ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, \ /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c index b11365a5ee1f..9111ba7ff0a1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c @@ -1475,7 +1475,7 @@ void rtl8812ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw, } } else if (method == MIX_MODE) { RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, - "pDM_Odm->DefaultOfdmIndex=%d, pDM_Odm->Aboslute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n", + "pDM_Odm->DefaultOfdmIndex=%d, pDM_Odm->Absolute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n", rtldm->default_ofdm_index, rtldm->absolute_ofdm_swing_idx[rf_path], rf_path); @@ -1750,7 +1750,7 @@ void rtl8812ae_dm_txpower_tracking_callback_thermalmeter( /*Record delta swing for mix mode power tracking*/ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, - "******Temp is higher and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", + "******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", rtldm->absolute_ofdm_swing_idx[RF90_PATH_A]); RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, @@ -1766,7 +1766,7 @@ void rtl8812ae_dm_txpower_tracking_callback_thermalmeter( /*Record delta swing for mix mode power tracking*/ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, - "******Temp is higher and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n", + "******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n", rtldm->absolute_ofdm_swing_idx[RF90_PATH_B]); } else { RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, @@ -1782,7 +1782,7 @@ void rtl8812ae_dm_txpower_tracking_callback_thermalmeter( -1 * delta_swing_table_idx_tdown_a[delta]; /* Record delta swing for mix mode power tracking*/ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, - "******Temp is lower and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", + "******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", rtldm->absolute_ofdm_swing_idx[RF90_PATH_A]); RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, @@ -1799,7 +1799,7 @@ void rtl8812ae_dm_txpower_tracking_callback_thermalmeter( /*Record delta swing for mix mode power tracking*/ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, - "******Temp is lower and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n", + "******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_B] = %d\n", rtldm->absolute_ofdm_swing_idx[RF90_PATH_B]); } @@ -2115,7 +2115,7 @@ void rtl8821ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw, } } else if (method == MIX_MODE) { RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, - "pDM_Odm->DefaultOfdmIndex=%d,pDM_Odm->Aboslute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n", + "pDM_Odm->DefaultOfdmIndex=%d,pDM_Odm->Absolute_OFDMSwingIdx[RFPath]=%d, RF_Path = %d\n", rtldm->default_ofdm_index, rtldm->absolute_ofdm_swing_idx[rf_path], rf_path); @@ -2329,7 +2329,7 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter( /*Record delta swing for mix mode power tracking*/ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, - "******Temp is higher and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", + "******Temp is higher and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", rtldm->absolute_ofdm_swing_idx[RF90_PATH_A]); } else { RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, @@ -2345,7 +2345,7 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter( -1 * delta_swing_table_idx_tdown_a[delta]; /* Record delta swing for mix mode power tracking*/ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD, - "******Temp is lower and pDM_Odm->Aboslute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", + "******Temp is lower and pDM_Odm->Absolute_OFDMSwingIdx[ODM_RF_PATH_A] = %d\n", rtldm->absolute_ofdm_swing_idx[RF90_PATH_A]); } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/pwrseq.h b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/pwrseq.h index 36b3e91d996e..6dd575435c63 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/pwrseq.h +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/pwrseq.h @@ -531,7 +531,7 @@ extern struct wlan_pwr_cfg rtl8812_leave_lps_flow /*0x23[4] = 1b'0 12H LDO enter normal mode*/}, \ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0 \ - /*0x04[12:11] = 2b'01enable WL suspend*/}, + /*0x04[12:11] = 2b'00 disable WL suspend*/}, #define RTL8821A_TRANS_CARDEMU_TO_CARDDIS \ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\ @@ -572,7 +572,7 @@ extern struct wlan_pwr_cfg rtl8812_leave_lps_flow /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/}, \ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0 \ - /*0x04[12:11] = 2b'01enable WL suspend*/},\ + /*0x04[12:11] = 2b'00 disable WL suspend*/},\ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,\ PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0 \ /*0x23[4] = 1b'0 12H LDO enter normal mode*/}, \ diff --git a/drivers/net/wireless/realtek/rtlwifi/wifi.h b/drivers/net/wireless/realtek/rtlwifi/wifi.h index 4f48b934ec01..d27e33960e77 100644 --- a/drivers/net/wireless/realtek/rtlwifi/wifi.h +++ b/drivers/net/wireless/realtek/rtlwifi/wifi.h @@ -556,6 +556,7 @@ enum rt_oem_id { RT_CID_NETGEAR = 36, RT_CID_PLANEX = 37, RT_CID_CC_C = 38, + RT_CID_LENOVO_CHINA = 40, }; enum hw_descs { @@ -977,6 +978,38 @@ enum rtl_spec_ver { RTL_SPEC_EXT_C2H = BIT(2), /* extend FW C2H (e.g. TX REPORT) */ }; +enum dm_info_query { + DM_INFO_FA_OFDM, + DM_INFO_FA_CCK, + DM_INFO_FA_TOTAL, + DM_INFO_CCA_OFDM, + DM_INFO_CCA_CCK, + DM_INFO_CCA_ALL, + DM_INFO_CRC32_OK_VHT, + DM_INFO_CRC32_OK_HT, + DM_INFO_CRC32_OK_LEGACY, + DM_INFO_CRC32_OK_CCK, + DM_INFO_CRC32_ERROR_VHT, + DM_INFO_CRC32_ERROR_HT, + DM_INFO_CRC32_ERROR_LEGACY, + DM_INFO_CRC32_ERROR_CCK, + DM_INFO_EDCCA_FLAG, + DM_INFO_OFDM_ENABLE, + DM_INFO_CCK_ENABLE, + DM_INFO_CRC32_OK_HT_AGG, + DM_INFO_CRC32_ERROR_HT_AGG, + DM_INFO_DBG_PORT_0, + DM_INFO_CURR_IGI, + DM_INFO_RSSI_MIN, + DM_INFO_RSSI_MAX, + DM_INFO_CLM_RATIO, + DM_INFO_NHM_RATIO, + DM_INFO_IQK_ALL, + DM_INFO_IQK_OK, + DM_INFO_IQK_NG, + DM_INFO_SIZE, +}; + struct octet_string { u8 *octet; u16 length; diff --git a/drivers/net/wireless/rsi/Kconfig b/drivers/net/wireless/rsi/Kconfig index f004be33fcfa..976c21866230 100644 --- a/drivers/net/wireless/rsi/Kconfig +++ b/drivers/net/wireless/rsi/Kconfig @@ -13,6 +13,7 @@ if WLAN_VENDOR_RSI config RSI_91X tristate "Redpine Signals Inc 91x WLAN driver support" + select BT_HCIRSI if RSI_COEX depends on MAC80211 ---help--- This option enabes support for RSI 1x1 devices. @@ -44,7 +45,8 @@ config RSI_USB config RSI_COEX bool "Redpine Signals WLAN BT Coexistence support" - depends on BT_HCIRSI && RSI_91X + depends on BT && RSI_91X + depends on !(BT=m && RSI_91X=y) default y ---help--- This option enables the WLAN BT coex support in rsi drivers. diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio.c b/drivers/net/wireless/rsi/rsi_91x_sdio.c index 98c7d1dae18e..d76e69c0beaa 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio.c @@ -576,7 +576,7 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter, { u32 num_blocks, offset, i; u16 msb_address, lsb_address; - u8 temp_buf[block_size]; + u8 *temp_buf; int status; num_blocks = instructions_sz / block_size; @@ -585,11 +585,15 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter, rsi_dbg(INFO_ZONE, "ins_size: %d, num_blocks: %d\n", instructions_sz, num_blocks); + temp_buf = kmalloc(block_size, GFP_KERNEL); + if (!temp_buf) + return -ENOMEM; + /* Loading DM ms word in the sdio slave */ status = rsi_sdio_master_access_msword(adapter, msb_address); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__); - return status; + goto out_free; } for (offset = 0, i = 0; i < num_blocks; i++, offset += block_size) { @@ -601,7 +605,7 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter, temp_buf, block_size); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: failed to write\n", __func__); - return status; + goto out_free; } rsi_dbg(INFO_ZONE, "%s: loading block: %d\n", __func__, i); base_address += block_size; @@ -616,7 +620,7 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter, rsi_dbg(ERR_ZONE, "%s: Unable to set ms word reg\n", __func__); - return status; + goto out_free; } } } @@ -632,12 +636,16 @@ static int rsi_sdio_load_data_master_write(struct rsi_hw *adapter, temp_buf, instructions_sz % block_size); if (status < 0) - return status; + goto out_free; rsi_dbg(INFO_ZONE, "Written Last Block in Address 0x%x Successfully\n", offset | RSI_SD_REQUEST_MASTER); } - return 0; + + status = 0; +out_free: + kfree(temp_buf); + return status; } #define FLASH_SIZE_ADDR 0x04000016 @@ -645,11 +653,14 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, u32 *read_buf, u16 size) { u32 addr_on_bus, *data; - u32 align[2] = {}; u16 ms_addr; int status; - data = PTR_ALIGN(&align[0], 8); + data = kzalloc(RSI_MASTER_REG_BUF_SIZE, GFP_KERNEL); + if (!data) + return -ENOMEM; + + data = PTR_ALIGN(data, 8); ms_addr = (addr >> 16); status = rsi_sdio_master_access_msword(adapter, ms_addr); @@ -657,7 +668,7 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, rsi_dbg(ERR_ZONE, "%s: Unable to set ms word to common reg\n", __func__); - return status; + goto err; } addr &= 0xFFFF; @@ -675,7 +686,7 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, (u8 *)data, 4); if (status < 0) { rsi_dbg(ERR_ZONE, "%s: AHB register read failed\n", __func__); - return status; + goto err; } if (size == 2) { if ((addr & 0x3) == 0) @@ -697,17 +708,23 @@ static int rsi_sdio_master_reg_read(struct rsi_hw *adapter, u32 addr, *read_buf = *data; } - return 0; +err: + kfree(data); + return status; } static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, unsigned long addr, unsigned long data, u16 size) { - unsigned long data1[2], *data_aligned; + unsigned long *data_aligned; int status; - data_aligned = PTR_ALIGN(&data1[0], 8); + data_aligned = kzalloc(RSI_MASTER_REG_BUF_SIZE, GFP_KERNEL); + if (!data_aligned) + return -ENOMEM; + + data_aligned = PTR_ALIGN(data_aligned, 8); if (size == 2) { *data_aligned = ((data << 16) | (data & 0xFFFF)); @@ -726,6 +743,7 @@ static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, rsi_dbg(ERR_ZONE, "%s: Unable to set ms word to common reg\n", __func__); + kfree(data_aligned); return -EIO; } addr = addr & 0xFFFF; @@ -735,12 +753,12 @@ static int rsi_sdio_master_reg_write(struct rsi_hw *adapter, (adapter, (addr | RSI_SD_REQUEST_MASTER), (u8 *)data_aligned, size); - if (status < 0) { + if (status < 0) rsi_dbg(ERR_ZONE, "%s: Unable to do AHB reg write\n", __func__); - return status; - } - return 0; + + kfree(data_aligned); + return status; } /** @@ -959,7 +977,7 @@ static int rsi_probe(struct sdio_func *pfunction, rsi_sdio_rx_thread, "SDIO-RX-Thread"); if (status) { rsi_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__); - goto fail_free_adapter; + goto fail_kill_thread; } skb_queue_head_init(&sdev->rx_q.head); sdev->rx_q.num_rx_pkts = 0; @@ -969,7 +987,7 @@ static int rsi_probe(struct sdio_func *pfunction, rsi_dbg(ERR_ZONE, "%s: Failed to request IRQ\n", __func__); sdio_release_host(pfunction); status = -EIO; - goto fail_kill_thread; + goto fail_claim_irq; } sdio_release_host(pfunction); rsi_dbg(INIT_ZONE, "%s: Registered Interrupt handler\n", __func__); @@ -977,7 +995,7 @@ static int rsi_probe(struct sdio_func *pfunction, if (rsi_hal_device_init(adapter)) { rsi_dbg(ERR_ZONE, "%s: Failed in device init\n", __func__); status = -EINVAL; - goto fail_kill_thread; + goto fail_dev_init; } rsi_dbg(INFO_ZONE, "===> RSI Device Init Done <===\n"); @@ -994,10 +1012,13 @@ static int rsi_probe(struct sdio_func *pfunction, fail_dev_init: sdio_claim_host(pfunction); sdio_release_irq(pfunction); - sdio_disable_func(pfunction); sdio_release_host(pfunction); -fail_kill_thread: +fail_claim_irq: rsi_kill_thread(&sdev->rx_thread); +fail_kill_thread: + sdio_claim_host(pfunction); + sdio_disable_func(pfunction); + sdio_release_host(pfunction); fail_free_adapter: rsi_91x_deinit(adapter); rsi_dbg(ERR_ZONE, "%s: Failed in probe...Exiting\n", __func__); diff --git a/drivers/net/wireless/rsi/rsi_91x_usb.c b/drivers/net/wireless/rsi/rsi_91x_usb.c index be8236f404b5..7b8bae313aa9 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb.c @@ -140,7 +140,6 @@ static int rsi_find_bulk_in_and_out_endpoints(struct usb_interface *interface, buffer_size = endpoint->wMaxPacketSize; dev->bulkout_endpoint_addr[bout_found] = endpoint->bEndpointAddress; - buffer_size = endpoint->wMaxPacketSize; dev->bulkout_size[bout_found] = buffer_size; bout_found++; } diff --git a/drivers/net/wireless/rsi/rsi_sdio.h b/drivers/net/wireless/rsi/rsi_sdio.h index ba649be284af..ead8e7c4df3a 100644 --- a/drivers/net/wireless/rsi/rsi_sdio.h +++ b/drivers/net/wireless/rsi/rsi_sdio.h @@ -46,6 +46,8 @@ enum sdio_interrupt_type { #define PKT_BUFF_AVAILABLE 1 #define FW_ASSERT_IND 2 +#define RSI_MASTER_REG_BUF_SIZE 12 + #define RSI_DEVICE_BUFFER_STATUS_REGISTER 0xf3 #define RSI_FN1_INT_REGISTER 0xf9 #define RSI_INT_ENABLE_REGISTER 0x04 diff --git a/drivers/net/wireless/st/cw1200/debug.c b/drivers/net/wireless/st/cw1200/debug.c index 34f97c31eecf..295cb1a29f25 100644 --- a/drivers/net/wireless/st/cw1200/debug.c +++ b/drivers/net/wireless/st/cw1200/debug.c @@ -398,15 +398,15 @@ int cw1200_debug_init(struct cw1200_common *priv) if (!d->debugfs_phy) goto err; - if (!debugfs_create_file("status", S_IRUSR, d->debugfs_phy, + if (!debugfs_create_file("status", 0400, d->debugfs_phy, priv, &fops_status)) goto err; - if (!debugfs_create_file("counters", S_IRUSR, d->debugfs_phy, + if (!debugfs_create_file("counters", 0400, d->debugfs_phy, priv, &fops_counters)) goto err; - if (!debugfs_create_file("wsm_dumps", S_IWUSR, d->debugfs_phy, + if (!debugfs_create_file("wsm_dumps", 0200, d->debugfs_phy, priv, &fops_wsm_dumps)) goto err; diff --git a/drivers/net/wireless/st/cw1200/main.c b/drivers/net/wireless/st/cw1200/main.c index a186d1df1f29..90dc979f260b 100644 --- a/drivers/net/wireless/st/cw1200/main.c +++ b/drivers/net/wireless/st/cw1200/main.c @@ -46,7 +46,7 @@ MODULE_ALIAS("cw1200_core"); /* Accept MAC address of the form macaddr=0x00,0x80,0xE1,0x30,0x40,0x50 */ static u8 cw1200_mac_template[ETH_ALEN] = {0x02, 0x80, 0xe1, 0x00, 0x00, 0x00}; -module_param_array_named(macaddr, cw1200_mac_template, byte, NULL, S_IRUGO); +module_param_array_named(macaddr, cw1200_mac_template, byte, NULL, 0444); MODULE_PARM_DESC(macaddr, "Override platform_data MAC address"); static char *cw1200_sdd_path; diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 0cf3b4013dd6..ca0f936fc119 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -2092,54 +2092,51 @@ static struct platform_driver wl18xx_driver = { }; module_platform_driver(wl18xx_driver); -module_param_named(ht_mode, ht_mode_param, charp, S_IRUSR); +module_param_named(ht_mode, ht_mode_param, charp, 0400); MODULE_PARM_DESC(ht_mode, "Force HT mode: wide or siso20"); -module_param_named(board_type, board_type_param, charp, S_IRUSR); +module_param_named(board_type, board_type_param, charp, 0400); MODULE_PARM_DESC(board_type, "Board type: fpga, hdk (default), evb, com8 or " "dvp"); -module_param_named(checksum, checksum_param, bool, S_IRUSR); +module_param_named(checksum, checksum_param, bool, 0400); MODULE_PARM_DESC(checksum, "Enable TCP checksum: boolean (defaults to false)"); -module_param_named(dc2dc, dc2dc_param, int, S_IRUSR); +module_param_named(dc2dc, dc2dc_param, int, 0400); MODULE_PARM_DESC(dc2dc, "External DC2DC: u8 (defaults to 0)"); -module_param_named(n_antennas_2, n_antennas_2_param, int, S_IRUSR); +module_param_named(n_antennas_2, n_antennas_2_param, int, 0400); MODULE_PARM_DESC(n_antennas_2, "Number of installed 2.4GHz antennas: 1 (default) or 2"); -module_param_named(n_antennas_5, n_antennas_5_param, int, S_IRUSR); +module_param_named(n_antennas_5, n_antennas_5_param, int, 0400); MODULE_PARM_DESC(n_antennas_5, "Number of installed 5GHz antennas: 1 (default) or 2"); -module_param_named(low_band_component, low_band_component_param, int, - S_IRUSR); +module_param_named(low_band_component, low_band_component_param, int, 0400); MODULE_PARM_DESC(low_band_component, "Low band component: u8 " "(default is 0x01)"); module_param_named(low_band_component_type, low_band_component_type_param, - int, S_IRUSR); + int, 0400); MODULE_PARM_DESC(low_band_component_type, "Low band component type: u8 " "(default is 0x05 or 0x06 depending on the board_type)"); -module_param_named(high_band_component, high_band_component_param, int, - S_IRUSR); +module_param_named(high_band_component, high_band_component_param, int, 0400); MODULE_PARM_DESC(high_band_component, "High band component: u8, " "(default is 0x01)"); module_param_named(high_band_component_type, high_band_component_type_param, - int, S_IRUSR); + int, 0400); MODULE_PARM_DESC(high_band_component_type, "High band component type: u8 " "(default is 0x09)"); module_param_named(pwr_limit_reference_11_abg, - pwr_limit_reference_11_abg_param, int, S_IRUSR); + pwr_limit_reference_11_abg_param, int, 0400); MODULE_PARM_DESC(pwr_limit_reference_11_abg, "Power limit reference: u8 " "(default is 0xc8)"); -module_param_named(num_rx_desc, - num_rx_desc_param, int, S_IRUSR); +module_param_named(num_rx_desc, num_rx_desc_param, int, 0400); MODULE_PARM_DESC(num_rx_desc_param, "Number of Rx descriptors: u8 (default is 32)"); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 09714034dbf1..3a51ab116e79 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -6630,20 +6630,20 @@ EXPORT_SYMBOL_GPL(wlcore_remove); u32 wl12xx_debug_level = DEBUG_NONE; EXPORT_SYMBOL_GPL(wl12xx_debug_level); -module_param_named(debug_level, wl12xx_debug_level, uint, S_IRUSR | S_IWUSR); +module_param_named(debug_level, wl12xx_debug_level, uint, 0600); MODULE_PARM_DESC(debug_level, "wl12xx debugging level"); module_param_named(fwlog, fwlog_param, charp, 0); MODULE_PARM_DESC(fwlog, "FW logger options: continuous, dbgpins or disable"); -module_param(fwlog_mem_blocks, int, S_IRUSR | S_IWUSR); +module_param(fwlog_mem_blocks, int, 0600); MODULE_PARM_DESC(fwlog_mem_blocks, "fwlog mem_blocks"); -module_param(bug_on_recovery, int, S_IRUSR | S_IWUSR); +module_param(bug_on_recovery, int, 0600); MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery"); -module_param(no_recovery, int, S_IRUSR | S_IWUSR); +module_param(no_recovery, int, 0600); MODULE_PARM_DESC(no_recovery, "Prevent HW recovery. FW will remain stuck."); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index f8a1fea64e25..1f727babbea0 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -469,7 +469,7 @@ static void __exit wl1271_exit(void) module_init(wl1271_init); module_exit(wl1271_exit); -module_param(dump, bool, S_IRUSR | S_IWUSR); +module_param(dump, bool, 0600); MODULE_PARM_DESC(dump, "Enable sdio read/write dumps."); MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/ti/wlcore/sysfs.c b/drivers/net/wireless/ti/wlcore/sysfs.c index b72e2101488b..d31eb775e023 100644 --- a/drivers/net/wireless/ti/wlcore/sysfs.c +++ b/drivers/net/wireless/ti/wlcore/sysfs.c @@ -80,7 +80,7 @@ static ssize_t wl1271_sysfs_store_bt_coex_state(struct device *dev, return count; } -static DEVICE_ATTR(bt_coex_state, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(bt_coex_state, 0644, wl1271_sysfs_show_bt_coex_state, wl1271_sysfs_store_bt_coex_state); @@ -103,8 +103,7 @@ static ssize_t wl1271_sysfs_show_hw_pg_ver(struct device *dev, return len; } -static DEVICE_ATTR(hw_pg_ver, S_IRUGO, - wl1271_sysfs_show_hw_pg_ver, NULL); +static DEVICE_ATTR(hw_pg_ver, 0444, wl1271_sysfs_show_hw_pg_ver, NULL); static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, struct bin_attribute *bin_attr, @@ -139,7 +138,7 @@ static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, } static const struct bin_attribute fwlog_attr = { - .attr = {.name = "fwlog", .mode = S_IRUSR}, + .attr = { .name = "fwlog", .mode = 0400 }, .read = wl1271_sysfs_read_fwlog, }; |