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
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJavOUVAAoJEG4XJFUm622bf2cH/i/we50/PR64rxq5RV8HWQPt
 9P/bn4I1pEDRDJZw00f/bqe20w5ps1UuHs1hgOiJzOsZNfxVv+B17MMY/dN/+5Ob
 hBYeZQFZ0MJ1cEF6J6gzebH1BKVEApVPI49MmAUzdtATO/6YgCnxovb61bl51RYg
 vtMNcrXBQDplPTh5W7YHXrUz4sV1d3daCk/6Coea+SoF6eL1tn+qndo6GhNIMboE
 HA0vV27Wf2RCzlxcQ4WGD4cre6n9sRaX4lcFzMEtbM7ziM0E0SES7eEThB5ST+A6
 3K0+zSuyEfOu40QRJF1g9Wl8FXvp+9SRVC7s1rXjDYUv9sGl+a5fhb7VPgrYn/g=
 =AgFb
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
David S. Miller 2018-03-29 16:24:06 -04:00
commit 18845557fd
173 changed files with 6230 additions and 2502 deletions

View File

@ -393,9 +393,7 @@ config BT_QCOMSMD
kernel or say M to compile as a module. kernel or say M to compile as a module.
config BT_HCIRSI config BT_HCIRSI
tristate "Redpine HCI support" tristate
default n
select RSI_COEX
help help
Redpine BT driver. Redpine BT driver.
This driver handles BT traffic from upper layers and pass This driver handles BT traffic from upper layers and pass

View File

@ -33,8 +33,6 @@
*/ */
#define ATH_KEYMAX 128 /* max key cache size we handle */ #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 { struct ath_ani {
bool caldone; bool caldone;
unsigned int longcal_timer; unsigned int longcal_timer;

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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->max_num_vdevs = TARGET_10_4_NUM_VDEVS;
ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; ar->num_tids = TARGET_10_4_TGT_NUM_TIDS;
ar->fw_stats_req_mask = WMI_10_4_STAT_PEER | 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_spatial_stream = ar->hw_params.max_spatial_stream;
ar->max_num_tdls_vdevs = TARGET_10_4_NUM_TDLS_VDEVS; 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)) if (ath10k_peer_stats_enabled(ar))
val = WMI_10_4_PEER_STATS; 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)) if (test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map))
val |= WMI_10_4_BSS_CHANNEL_INFO_64; 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); ret = ath10k_hif_power_up(ar);
if (ret) { 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; return ret;
} }

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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]; 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 ath10k_fw_stats_pdev {
struct list_head list; 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 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 { struct ath10k_dfs_stats {
u32 phy_errors; u32 phy_errors;
u32 pulses_total; u32 pulses_total;
@ -354,6 +397,45 @@ struct ath10k_txq {
unsigned long num_push_allowed; 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_sta {
struct ath10k_vif *arvif; struct ath10k_vif *arvif;
@ -371,6 +453,9 @@ struct ath10k_sta {
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
/* protected by conf_mutex */ /* protected by conf_mutex */
bool aggr_mode; bool aggr_mode;
/* Protected with ar->data_lock */
struct ath10k_sta_tid_stats tid_stats[IEEE80211_NUM_TIDS + 1];
#endif #endif
}; };
@ -487,6 +572,7 @@ struct ath10k_debug {
/* used for tpc-dump storage, protected by data-lock */ /* used for tpc-dump storage, protected by data-lock */
struct ath10k_tpc_stats *tpc_stats; struct ath10k_tpc_stats *tpc_stats;
struct ath10k_tpc_stats_final *tpc_stats_final;
struct completion tpc_complete; struct completion tpc_complete;
@ -1019,6 +1105,8 @@ struct ath10k {
void *ce_priv; void *ce_priv;
u32 sta_tid_stats_mask;
/* must be last */ /* must be last */
u8 drv_priv[0] __aligned(sizeof(void *)); u8 drv_priv[0] __aligned(sizeof(void *));
}; };

View File

@ -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[] = { static const struct ath10k_hw_mem_layout hw_mem_layouts[] = {
{ {
.hw_id = QCA6174_HW_1_0_VERSION, .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), .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) static u32 ath10k_coredump_get_ramdump_size(struct ath10k *ar)

View File

@ -124,6 +124,8 @@ enum ath10k_mem_region_type {
ATH10K_MEM_REGION_TYPE_AXI = 3, ATH10K_MEM_REGION_TYPE_AXI = 3,
ATH10K_MEM_REGION_TYPE_IRAM1 = 4, ATH10K_MEM_REGION_TYPE_IRAM1 = 4,
ATH10K_MEM_REGION_TYPE_IRAM2 = 5, 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 /* Define a section of the region which should be copied. As not all parts

View File

@ -1480,6 +1480,19 @@ void ath10k_debug_tpc_stats_process(struct ath10k *ar,
spin_unlock_bh(&ar->data_lock); 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, static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats,
unsigned int j, char *buf, size_t *len) unsigned int j, char *buf, size_t *len)
{ {
@ -2143,6 +2156,137 @@ static const struct file_operations fops_fw_checksums = {
.llseek = default_llseek, .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) int ath10k_debug_create(struct ath10k *ar)
{ {
ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN); 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, debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar,
&fops_fw_checksums); &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; return 0;
} }

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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_fw_stats_process(struct ath10k *ar, struct sk_buff *skb);
void ath10k_debug_tpc_stats_process(struct ath10k *ar, void ath10k_debug_tpc_stats_process(struct ath10k *ar,
struct ath10k_tpc_stats *tpc_stats); 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); void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++) #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); 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, static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer,
int len) 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); struct ieee80211_sta *sta, struct dentry *dir);
void ath10k_sta_update_rx_duration(struct ath10k *ar, void ath10k_sta_update_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats); 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 #else
static inline static inline
void ath10k_sta_update_rx_duration(struct ath10k *ar, void ath10k_sta_update_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats) 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 */ #endif /* CONFIG_MAC80211_DEBUGFS */
#ifdef CONFIG_ATH10K_DEBUG #ifdef CONFIG_ATH10K_DEBUG

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -16,8 +17,125 @@
#include "core.h" #include "core.h"
#include "wmi-ops.h" #include "wmi-ops.h"
#include "txrx.h"
#include "debug.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, static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats) struct ath10k_fw_stats *stats)
{ {
@ -342,6 +460,172 @@ static const struct file_operations fops_peer_debug_trigger = {
.llseek = default_llseek, .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, void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir) 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("delba", 0200, dir, sta, &fops_delba);
debugfs_create_file("peer_debug_trigger", 0600, dir, sta, debugfs_create_file("peer_debug_trigger", 0600, dir, sta,
&fops_peer_debug_trigger); &fops_peer_debug_trigger);
debugfs_create_file("dump_tid_stats", 0400, dir, sta,
&fops_tid_stats_dump);
} }

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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) #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, static void ath10k_htt_rx_h_rates(struct ath10k *ar,
struct ieee80211_rx_status *status, struct ieee80211_rx_status *status,
struct htt_rx_desc *rxd) struct htt_rx_desc *rxd)
@ -825,23 +848,7 @@ static void ath10k_htt_rx_h_rates(struct ath10k *ar,
if (sgi) if (sgi)
status->enc_flags |= RX_ENC_FLAG_SHORT_GI; status->enc_flags |= RX_ENC_FLAG_SHORT_GI;
switch (bw) { status->bw = ath10k_bw_to_mac80211_bw(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->encoding = RX_ENC_VHT; status->encoding = RX_ENC_VHT;
break; break;
default: 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, static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
struct sk_buff_head *amsdu, struct sk_buff_head *amsdu,
struct ieee80211_rx_status *status, 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 *first;
struct sk_buff *last; struct sk_buff *last;
@ -1538,6 +1547,9 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
hdr = (void *)rxd->rx_hdr_status; hdr = (void *)rxd->rx_hdr_status;
memcpy(first_hdr, hdr, RX_HTT_HDR_STATUS_LEN); 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 /* 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. * 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) if (has_tkip_err)
status->flag |= RX_FLAG_MMIC_ERROR; 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. /* Firmware reports all necessary management frames via WMI already.
* They are not reported to monitor interfaces at all so pass the ones * They are not reported to monitor interfaces at all so pass the ones
* coming via HTT to monitor interfaces instead. This simplifies * 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; struct sk_buff *skb, *first;
int space; int space;
int total_len = 0; int total_len = 0;
int amsdu_len = skb_queue_len(amsdu);
/* TODO: Might could optimize this by using /* TODO: Might could optimize this by using
* skb_try_coalesce or similar method to * 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); __skb_queue_head(amsdu, first);
*unchain_cnt += amsdu_len - 1;
return 0; return 0;
} }
static void ath10k_htt_rx_h_unchain(struct ath10k *ar, 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 sk_buff *first;
struct htt_rx_desc *rxd; 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 || if (decap != RX_MSDU_DECAP_RAW ||
skb_queue_len(amsdu) != 1 + rxd->frag_info.ring2_more_count) { skb_queue_len(amsdu) != 1 + rxd->frag_info.ring2_more_count) {
*drop_cnt += skb_queue_len(amsdu);
__skb_queue_purge(amsdu); __skb_queue_purge(amsdu);
return; return;
} }
ath10k_unchain_msdu(amsdu); ath10k_unchain_msdu(amsdu, unchain_cnt);
} }
static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, 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, static void ath10k_htt_rx_h_filter(struct ath10k *ar,
struct sk_buff_head *amsdu, 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)) if (skb_queue_empty(amsdu))
return; 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)) if (ath10k_htt_rx_amsdu_allowed(ar, amsdu, rx_status))
return; return;
if (drop_cnt)
*drop_cnt += skb_queue_len(amsdu);
__skb_queue_purge(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 ieee80211_rx_status *rx_status = &htt->rx_status;
struct sk_buff_head amsdu; struct sk_buff_head amsdu;
int ret; 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); __skb_queue_head_init(&amsdu);
@ -1781,16 +1822,23 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
return ret; return ret;
} }
num_msdus = skb_queue_len(&amsdu);
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff); ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
/* only for ret = 1 indicates chained msdus */ /* only for ret = 1 indicates chained msdus */
if (ret > 0) 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_filter(ar, &amsdu, rx_status, &drop_cnt_filter);
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true); 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_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; 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; struct htt_rx_indication_mpdu_range *mpdu_ranges;
int num_mpdu_ranges; int num_mpdu_ranges;
int i, mpdu_count = 0; int i, mpdu_count = 0;
u16 peer_id;
u8 tid;
num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1), num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1),
HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES); 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); mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx);
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ", 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; mpdu_count += mpdu_ranges[i].mpdu_count;
atomic_add(mpdu_count, &htt->num_mpdus_ready); 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, 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. * 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_ppdu(ar, &amsdu, status, vdev_id);
ath10k_htt_rx_h_filter(ar, &amsdu, status); ath10k_htt_rx_h_filter(ar, &amsdu, status, NULL);
ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false); ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false, NULL,
NULL);
ath10k_htt_rx_h_enqueue(ar, &amsdu, status); ath10k_htt_rx_h_enqueue(ar, &amsdu, status);
break; break;
case -EAGAIN: 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.flags |= RATE_INFO_FLAGS_SHORT_GI;
arsta->txrate.nss = txrate.nss; 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, static void ath10k_htt_fetch_peer_stats(struct ath10k *ar,

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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 */ /* 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); ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n", 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 ath10k *ar = container_of(work, struct ath10k, wmi_mgmt_tx_work);
struct sk_buff *skb; struct sk_buff *skb;
dma_addr_t paddr;
int ret; int ret;
for (;;) { for (;;) {
@ -3815,11 +3817,27 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
if (!skb) if (!skb)
break; break;
ret = ath10k_wmi_mgmt_tx(ar, skb); if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
if (ret) { ar->running_fw->fw_file.fw_features)) {
ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n", paddr = dma_map_single(ar->dev, skb->data,
ret); skb->len, DMA_TO_DEVICE);
ieee80211_free_txskb(ar->hw, skb); 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); ath10k_warn(ar, "Peer %pM disappeared!\n", peer_addr);
spin_unlock_bh(&ar->data_lock); 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: exit:
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
return ret; return ret;
@ -6028,9 +6050,8 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
sta->addr, smps, err); sta->addr, smps, err);
} }
if (changed & IEEE80211_RC_SUPP_RATES_CHANGED || if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
changed & IEEE80211_RC_NSS_CHANGED) { ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n",
sta->addr); sta->addr);
err = ath10k_station_assoc(ar, arvif->vif, sta, true); 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 *ar = hw->priv;
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_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; u32 bw, smps;
spin_lock_bh(&ar->data_lock); 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, ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
sta->addr, changed, sta->bandwidth, sta->rx_nss, 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, .max_interfaces = 8,
.num_different_channels = 1, .num_different_channels = 1,
.beacon_int_infra_match = true, .beacon_int_infra_match = true,
.beacon_int_min_gcd = 1,
#ifdef CONFIG_ATH10K_DFS_CERTIFIED #ifdef CONFIG_ATH10K_DFS_CERTIFIED
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) | BIT(NL80211_CHAN_WIDTH_20) |
@ -7997,6 +8029,7 @@ static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = {
.max_interfaces = 16, .max_interfaces = 16,
.num_different_channels = 1, .num_different_channels = 1,
.beacon_int_infra_match = true, .beacon_int_infra_match = true,
.beacon_int_min_gcd = 1,
#ifdef CONFIG_ATH10K_DFS_CERTIFIED #ifdef CONFIG_ATH10K_DFS_CERTIFIED
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) | BIT(NL80211_CHAN_WIDTH_20) |
@ -8298,6 +8331,9 @@ int ath10k_mac_register(struct ath10k *ar)
ieee80211_hw_set(ar->hw, TDLS_WIDER_BW); 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_REMAIN_ON_CHANNEL;
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
ar->hw->wiphy->max_remain_on_channel_duration = 5000; ar->hw->wiphy->max_remain_on_channel_duration = 5000;

View File

@ -57,6 +57,10 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)");
*/ */
#define ATH10K_DIAG_TRANSFER_LIMIT 0x5000 #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[] = { static const struct pci_device_id ath10k_pci_id_table[] = {
/* PCI-E QCA988X V2 (Ubiquiti branded) */ /* PCI-E QCA988X V2 (Ubiquiti branded) */
{ PCI_VDEVICE(UBIQUITI, QCA988X_2_0_DEVICE_ID_UBNT) }, { 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; 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, static void ath10k_pci_dump_memory(struct ath10k *ar,
struct ath10k_fw_crash_data *crash_data) struct ath10k_fw_crash_data *crash_data)
{ {
@ -1642,27 +1709,20 @@ static void ath10k_pci_dump_memory(struct ath10k *ar,
buf += sizeof(*hdr); buf += sizeof(*hdr);
buf_len -= sizeof(*hdr); buf_len -= sizeof(*hdr);
if (current_region->section_table.size > 0) { switch (current_region->type) {
/* Copy each section individually. */ case ATH10K_MEM_REGION_TYPE_IOSRAM:
count = ath10k_pci_dump_memory_section(ar, count = ath10k_pci_dump_memory_sram(ar, current_region, buf);
current_region, break;
buf, case ATH10K_MEM_REGION_TYPE_IOREG:
current_region->len); count = ath10k_pci_dump_memory_reg(ar, current_region, buf);
} else { break;
/* No individiual memory sections defined so we can default:
* copy the entire memory region. ret = ath10k_pci_dump_memory_generic(ar, current_region, buf);
*/ if (ret < 0)
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);
break; break;
}
count = current_region->len; count = ret;
break;
} }
hdr->region_type = cpu_to_le32(current_region->type); hdr->region_type = cpu_to_le32(current_region->type);
@ -2221,7 +2281,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
} }
break; break;
case QCA9377_1_0_DEVICE_ID: case QCA9377_1_0_DEVICE_ID:
return 4; return 9;
} }
ath10k_warn(ar, "unknown number of banks, assuming 1\n"); 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); MODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE);
/* QCA9377 1.0 firmware files */ /* 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 "/" ATH10K_FW_API5_FILE);
MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" QCA9377_HW_1_0_BOARD_DATA_FILE); MODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" QCA9377_HW_1_0_BOARD_DATA_FILE);

View File

@ -152,10 +152,9 @@ TRACE_EVENT(ath10k_log_dbg_dump,
); );
TRACE_EVENT(ath10k_wmi_cmd, TRACE_EVENT(ath10k_wmi_cmd,
TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len, TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len),
int ret),
TP_ARGS(ar, id, buf, buf_len, ret), TP_ARGS(ar, id, buf, buf_len),
TP_STRUCT__entry( TP_STRUCT__entry(
__string(device, dev_name(ar->dev)) __string(device, dev_name(ar->dev))
@ -163,7 +162,6 @@ TRACE_EVENT(ath10k_wmi_cmd,
__field(unsigned int, id) __field(unsigned int, id)
__field(size_t, buf_len) __field(size_t, buf_len)
__dynamic_array(u8, buf, buf_len) __dynamic_array(u8, buf, buf_len)
__field(int, ret)
), ),
TP_fast_assign( TP_fast_assign(
@ -171,17 +169,15 @@ TRACE_EVENT(ath10k_wmi_cmd,
__assign_str(driver, dev_driver_string(ar->dev)); __assign_str(driver, dev_driver_string(ar->dev));
__entry->id = id; __entry->id = id;
__entry->buf_len = buf_len; __entry->buf_len = buf_len;
__entry->ret = ret;
memcpy(__get_dynamic_array(buf), buf, buf_len); memcpy(__get_dynamic_array(buf), buf, buf_len);
), ),
TP_printk( TP_printk(
"%s %s id %d len %zu ret %d", "%s %s id %d len %zu",
__get_str(driver), __get_str(driver),
__get_str(device), __get_str(device),
__entry->id, __entry->id,
__entry->buf_len, __entry->buf_len
__entry->ret
) )
); );

View File

@ -102,11 +102,6 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
memset(&info->status, 0, sizeof(info->status)); memset(&info->status, 0, sizeof(info->status));
trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id); 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)) if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
info->flags |= IEEE80211_TX_STAT_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_CTL_NO_ACK))
info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 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); ieee80211_tx_status(htt->ar->hw, msdu);
/* we do not own the msdu anymore */ /* we do not own the msdu anymore */

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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, enum wmi_force_fw_hang_type type,
u32 delay_ms); u32 delay_ms);
struct sk_buff *(*gen_mgmt_tx)(struct ath10k *ar, struct sk_buff *skb); 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, struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u64 module_enable,
u32 log_level); u32 log_level);
struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter); struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter);
@ -197,6 +201,9 @@ struct wmi_ops {
(struct ath10k *ar, (struct ath10k *ar,
enum wmi_bss_survey_req_type type); enum wmi_bss_survey_req_type type);
struct sk_buff *(*gen_echo)(struct ath10k *ar, u32 value); 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); int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
@ -371,13 +378,34 @@ ath10k_wmi_get_txbf_conf_scheme(struct ath10k *ar)
return ar->wmi.ops->get_txbf_conf_scheme(ar); return ar->wmi.ops->get_txbf_conf_scheme(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 static inline int
ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
{ {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
struct sk_buff *skb; struct sk_buff *skb;
int ret; int ret;
u32 mgmt_tx_cmdid;
if (!ar->wmi.ops->gen_mgmt_tx) if (!ar->wmi.ops->gen_mgmt_tx)
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -386,13 +414,8 @@ ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
if (IS_ERR(skb)) if (IS_ERR(skb))
return PTR_ERR(skb); return PTR_ERR(skb);
if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF, ret = ath10k_wmi_cmd_send(ar, skb,
ar->running_fw->fw_file.fw_features)) ar->wmi.cmd->mgmt_tx_cmdid);
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);
if (ret) if (ret)
return 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); 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 #endif

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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; 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 */ /* 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: case WMI_TLV_TX_PAUSE_EVENTID:
ath10k_wmi_tlv_event_tx_pause(ar, skb); ath10k_wmi_tlv_event_tx_pause(ar, skb);
break; 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: default:
ath10k_warn(ar, "Unknown eventid: %d\n", id); ath10k_warn(ar, "Unknown eventid: %d\n", id);
break; break;
@ -2484,19 +2547,19 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
} }
static struct sk_buff * 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 ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
struct wmi_tlv_mgmt_tx_cmd *cmd; struct wmi_tlv_mgmt_tx_cmd *cmd;
struct wmi_tlv *tlv;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct ath10k_vif *arvif;
u32 buf_len = msdu->len;
struct wmi_tlv *tlv;
struct sk_buff *skb; struct sk_buff *skb;
u32 vdev_id;
void *ptr; void *ptr;
int len; int len;
u32 buf_len = msdu->len;
struct ath10k_vif *arvif;
dma_addr_t mgmt_frame_dma;
u32 vdev_id;
if (!cb->vif) if (!cb->vif)
return ERR_PTR(-EINVAL); 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->chanfreq = 0;
cmd->buf_len = __cpu_to_le32(buf_len); cmd->buf_len = __cpu_to_le32(buf_len);
cmd->frame_len = __cpu_to_le32(msdu->len); cmd->frame_len = __cpu_to_le32(msdu->len);
mgmt_frame_dma = dma_map_single(arvif->ar->dev, msdu->data, cmd->paddr = __cpu_to_le64(paddr);
msdu->len, DMA_TO_DEVICE);
if (!mgmt_frame_dma)
return ERR_PTR(-ENOMEM);
cmd->paddr = __cpu_to_le64(mgmt_frame_dma);
ptr += sizeof(*tlv); ptr += sizeof(*tlv);
ptr += sizeof(*cmd); ptr += sizeof(*cmd);
@ -2661,6 +2719,25 @@ ath10k_wmi_tlv_op_gen_pktlog_enable(struct ath10k *ar, u32 filter)
return skb; return skb;
} }
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 * static struct sk_buff *
ath10k_wmi_tlv_op_gen_pktlog_disable(struct ath10k *ar) ath10k_wmi_tlv_op_gen_pktlog_disable(struct ath10k *ar)
{ {
@ -2855,6 +2932,15 @@ ath10k_wmi_tlv_op_gen_update_fw_tdls_state(struct ath10k *ar, u32 vdev_id,
*/ */
u32 options = 0; 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); len = sizeof(*tlv) + sizeof(*cmd);
skb = ath10k_wmi_alloc_skb(ar, len); skb = ath10k_wmi_alloc_skb(ar, len);
if (!skb) 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, .force_fw_hang_cmdid = WMI_TLV_FORCE_FW_HANG_CMDID,
.gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID, .gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID,
.gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_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, .vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID,
.tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID, .tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID,
.tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_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_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang, .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
/* .gen_mgmt_tx = not implemented; HTT is used */ /* .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_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
.gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
.gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable, .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
/* .gen_pdev_set_quiet_mode not implemented */ /* .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_clear_resp not implemented */
/* .gen_addba_send not implemented */ /* .gen_addba_send not implemented */
/* .gen_addba_set_resp not implemented */ /* .gen_addba_set_resp not implemented */

View File

@ -1340,6 +1340,17 @@ struct wmi_tlv_init_cmd {
__le32 num_host_mem_chunks; __le32 num_host_mem_chunks;
} __packed; } __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 { struct wmi_tlv_pdev_set_param_cmd {
__le32 pdev_id; /* not used yet */ __le32 pdev_id; /* not used yet */
__le32 param_id; __le32 param_id;
@ -1746,6 +1757,13 @@ struct wmi_tlv_tx_pause_ev {
__le32 tid_map; __le32 tid_map;
} __packed; } __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); void ath10k_wmi_tlv_attach(struct ath10k *ar);
struct wmi_tlv_mgmt_tx_cmd { struct wmi_tlv_mgmt_tx_cmd {

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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, .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_bss_chan_info_request_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 */ /* 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, .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_bss_chan_info_request_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 */ /* 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, .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_bss_chan_info_request_cmdid = .pdev_bss_chan_info_request_cmdid =
WMI_10_2_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 */ /* 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_cck_config_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_reserve_ast_entry_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 = { 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); cmd_hdr->cmd_id = __cpu_to_le32(cmd);
memset(skb_cb, 0, sizeof(*skb_cb)); 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); ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb);
trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len, ret);
if (ret) if (ret)
goto err_pull; 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); 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, static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar,
struct sk_buff *skb, struct sk_buff *skb,
struct ath10k_fw_stats *stats) 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++) { for (i = 0; i < num_peer_stats; i++) {
const struct wmi_10_4_peer_stats *src; 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) if (stats_id & WMI_10_4_STAT_PEER_EXTD) {
return 0; 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++) { src = (void *)skb->data;
const struct wmi_10_4_peer_extd_stats *src; if (!skb_pull(skb, sizeof(*src)))
struct ath10k_fw_extd_stats_peer *dst; return -EPROTO;
src = (void *)skb->data; dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
if (!skb_pull(skb, sizeof(*src))) if (!dst)
return -EPROTO; continue;
dst = kzalloc(sizeof(*dst), GFP_ATOMIC); ether_addr_copy(dst->peer_macaddr,
if (!dst) src->peer_macaddr.addr);
continue; dst->rx_duration = __le32_to_cpu(src->rx_duration);
list_add_tail(&dst->list, &stats->peers_extd);
}
}
ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr); if (stats_id & WMI_10_4_STAT_VDEV_EXTD) {
dst->rx_duration = __le32_to_cpu(src->rx_duration); for (i = 0; i < num_vdev_stats; i++) {
list_add_tail(&dst->list, &stats->peers_extd); const struct wmi_vdev_stats_extd *src;
struct ath10k_fw_stats_vdev_extd *dst;
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; 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; u32 i, j, pream_idx;
u8 rate_code[WMI_TPC_RATE_MAX], rate_idx; u8 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;
/* Create the rate code table based on the chains supported */ /* Create the rate code table based on the chains supported */
rate_idx = 0; 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_table[pream_idx] = rate_idx;
pream_idx++; pream_idx++;
num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
/* Fill HT20 rate code */ /* Fill HT20 rate code */
for (i = 0; i < num_tx_chain; i++) { for (i = 0; i < num_tx_chain; i++) {
for (j = 0; j < 8; j++) { 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++; pream_idx++;
/* Fill VHT20 rate code */ /* 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++) { for (j = 0; j < 10; j++) {
rate_code[rate_idx] = rate_code[rate_idx] =
ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT); 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); ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_OFDM);
pream_table[pream_idx] = ATH10K_TPC_PREAM_TABLE_END; 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->chan_freq = __le32_to_cpu(ev->chan_freq);
tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode); 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)); __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 static void
ath10k_wmi_handle_tdls_peer_event(struct ath10k *ar, struct sk_buff *skb) 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_WOW_WAKEUP_HOST_EVENTID:
case WMI_10_4_PEER_RATECODE_LIST_EVENTID: case WMI_10_4_PEER_RATECODE_LIST_EVENTID:
case WMI_10_4_WDS_PEER_EVENTID: case WMI_10_4_WDS_PEER_EVENTID:
case WMI_10_4_DEBUG_FATAL_CONDITION_EVENTID:
ath10k_dbg(ar, ATH10K_DBG_WMI, ath10k_dbg(ar, ATH10K_DBG_WMI,
"received event id %d not implemented\n", id); "received event id %d not implemented\n", id);
break; 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: case WMI_10_4_TDLS_PEER_EVENTID:
ath10k_wmi_handle_tdls_peer_event(ar, skb); ath10k_wmi_handle_tdls_peer_event(ar, skb);
break; break;
case WMI_10_4_PDEV_TPC_TABLE_EVENTID:
ath10k_wmi_event_tpc_final_table(ar, skb);
break;
default: default:
ath10k_warn(ar, "Unknown eventid: %d\n", id); ath10k_warn(ar, "Unknown eventid: %d\n", id);
break; break;
@ -7745,6 +8052,72 @@ ath10k_wmi_op_gen_pdev_enable_adaptive_cca(struct ath10k *ar, u8 enable,
return skb; 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, void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
struct ath10k_fw_stats *fw_stats, struct ath10k_fw_stats *fw_stats,
char *buf) char *buf)
@ -7752,7 +8125,7 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
u32 len = 0; u32 len = 0;
u32 buf_len = ATH10K_FW_STATS_BUF_SIZE; u32 buf_len = ATH10K_FW_STATS_BUF_SIZE;
const struct ath10k_fw_stats_pdev *pdev; 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; const struct ath10k_fw_stats_peer *peer;
size_t num_peers; size_t num_peers;
size_t num_vdevs; 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); "ath10k VDEV stats", num_vdevs);
len += scnprintf(buf + len, buf_len - len, "%30s\n\n", len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
"================="); "=================");
list_for_each_entry(vdev, &fw_stats->vdevs, list) { 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"); len += scnprintf(buf + len, buf_len - len, "\n");
@ -7989,6 +8361,24 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp)
return peer_qos; return peer_qos;
} }
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 * static struct sk_buff *
ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar, 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_update_cmd_arg *arg,
@ -8430,6 +8820,8 @@ static const struct wmi_ops wmi_10_4_ops = {
.ext_resource_config = ath10k_wmi_10_4_ext_resource_config, .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_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_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 */ /* shared with 10.2 */
.pull_echo_ev = ath10k_wmi_op_pull_echo_ev, .pull_echo_ev = ath10k_wmi_op_pull_echo_ev,

View File

@ -1,6 +1,7 @@
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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_TDLS_EXPLICIT_MODE_ONLY,
WMI_SERVICE_MGMT_TX_WMI, WMI_SERVICE_MGMT_TX_WMI,
WMI_SERVICE_TDLS_WIDER_BANDWIDTH, 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 */ /* keep last */
WMI_SERVICE_MAX, 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_CONN_TRACKER_IN_HOST_MODE,
WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY, WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH, 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) 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_CONN_TRACKER_IN_HOST_MODE);
SVCSTR(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY); SVCSTR(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY);
SVCSTR(WMI_SERVICE_TDLS_WIDER_BANDWIDTH); 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: default:
return NULL; 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); WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, len);
SVCMAP(WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH, SVCMAP(WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH,
WMI_SERVICE_TDLS_WIDER_BANDWIDTH, len); 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 #undef SVCMAP
@ -3993,10 +4009,12 @@ struct wmi_pdev_get_tpc_config_cmd {
#define WMI_TPC_CONFIG_PARAM 1 #define WMI_TPC_CONFIG_PARAM 1
#define WMI_TPC_RATE_MAX 160 #define WMI_TPC_RATE_MAX 160
#define WMI_TPC_FINAL_RATE_MAX 240
#define WMI_TPC_TX_N_CHAIN 4 #define WMI_TPC_TX_N_CHAIN 4
#define WMI_TPC_PREAM_TABLE_MAX 10 #define WMI_TPC_PREAM_TABLE_MAX 10
#define WMI_TPC_FLAG 3 #define WMI_TPC_FLAG 3
#define WMI_TPC_BUF_SIZE 10 #define WMI_TPC_BUF_SIZE 10
#define WMI_TPC_BEAMFORMING 2
enum wmi_tpc_table_type { enum wmi_tpc_table_type {
WMI_TPC_TABLE_TYPE_CDD = 0, WMI_TPC_TABLE_TYPE_CDD = 0,
@ -4039,6 +4057,51 @@ enum wmi_tp_scale {
WMI_TP_SCALE_SIZE = 5, /* max num of enum */ 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 { struct wmi_pdev_chanlist_update_event {
/* number of channels */ /* number of channels */
__le32 num_chan; __le32 num_chan;
@ -4350,6 +4413,7 @@ enum wmi_10_4_stats_id {
WMI_10_4_STAT_AP = BIT(1), WMI_10_4_STAT_AP = BIT(1),
WMI_10_4_STAT_INST = BIT(2), WMI_10_4_STAT_INST = BIT(2),
WMI_10_4_STAT_PEER_EXTD = BIT(3), WMI_10_4_STAT_PEER_EXTD = BIT(3),
WMI_10_4_STAT_VDEV_EXTD = BIT(4),
}; };
struct wlan_inst_rssi_args { struct wlan_inst_rssi_args {
@ -4489,12 +4553,36 @@ struct wmi_10_4_pdev_stats {
/* /*
* VDEV statistics * 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 { struct wmi_vdev_stats {
__le32 vdev_id; __le32 vdev_id;
} __packed; } __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. * peer statistics.
* TODO: add more stats * TODO: add more stats
@ -6729,6 +6817,7 @@ enum wmi_tdls_state {
WMI_TDLS_DISABLE, WMI_TDLS_DISABLE,
WMI_TDLS_ENABLE_PASSIVE, WMI_TDLS_ENABLE_PASSIVE,
WMI_TDLS_ENABLE_ACTIVE, WMI_TDLS_ENABLE_ACTIVE,
WMI_TDLS_ENABLE_ACTIVE_EXTERNAL_CONTROL,
}; };
enum wmi_tdls_peer_state { 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, int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar,
enum wmi_vdev_subtype subtype); enum wmi_vdev_subtype subtype);
int ath10k_wmi_barrier(struct ath10k *ar); 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_ */ #endif /* _WMI_H_ */

View File

@ -327,7 +327,7 @@ int ath5k_hw_init(struct ath5k_hw *ah)
ath5k_hw_set_lladdr(ah, zero_mac); ath5k_hw_set_lladdr(ah, zero_mac);
/* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ /* 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_bssid(ah);
ath5k_hw_set_opmode(ah, ah->opmode); ath5k_hw_set_opmode(ah, ah->opmode);

View File

@ -73,16 +73,16 @@
#include "trace.h" #include "trace.h"
bool ath5k_modparam_nohwcrypt; 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."); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
static bool modparam_fastchanswitch; 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."); MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios.");
static bool ath5k_modparam_no_hw_rfkill_switch; static bool ath5k_modparam_no_hw_rfkill_switch;
module_param_named(no_hw_rfkill_switch, 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"); MODULE_PARM_DESC(no_hw_rfkill_switch, "Ignore the GPIO RFKill switch state");

View File

@ -1004,32 +1004,17 @@ ath5k_debug_init_device(struct ath5k_hw *ah)
if (!phydir) if (!phydir)
return; return;
debugfs_create_file("debug", S_IWUSR | S_IRUSR, phydir, ah, debugfs_create_file("debug", 0600, phydir, ah, &fops_debug);
&fops_debug); debugfs_create_file("registers", 0400, phydir, ah, &fops_registers);
debugfs_create_file("beacon", 0600, phydir, ah, &fops_beacon);
debugfs_create_file("registers", S_IRUSR, phydir, ah, &fops_registers); debugfs_create_file("reset", 0200, phydir, ah, &fops_reset);
debugfs_create_file("antenna", 0600, phydir, ah, &fops_antenna);
debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, ah, debugfs_create_file("misc", 0400, phydir, ah, &fops_misc);
&fops_beacon); debugfs_create_file("eeprom", 0400, phydir, ah, &fops_eeprom);
debugfs_create_file("frameerrors", 0600, phydir, ah, &fops_frameerrors);
debugfs_create_file("reset", S_IWUSR, phydir, ah, &fops_reset); debugfs_create_file("ani", 0600, phydir, ah, &fops_ani);
debugfs_create_file("queue", 0600, phydir, ah, &fops_queue);
debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, ah, debugfs_create_bool("32khz_clock", 0600, phydir,
&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,
&ah->ah_use_32khz_clock); &ah->ah_use_32khz_clock);
} }

View File

@ -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); 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 /* Skip if queue inactive or if we are on AR5210
* that doesn't have QCU/DCU */ * that doesn't have QCU/DCU */
if ((ah->ah_version == AR5K_AR5210) || if ((ah->ah_version == AR5K_AR5210) ||

View File

@ -31,7 +31,7 @@ static ssize_t ath5k_attr_store_##name(struct device *dev, \
set(ah, val); \ set(ah, val); \
return count; \ return count; \
} \ } \
static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, \ static DEVICE_ATTR(name, 0644, \
ath5k_attr_show_##name, ath5k_attr_store_##name) ath5k_attr_show_##name, ath5k_attr_store_##name)
#define SIMPLE_SHOW(name, get) \ #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; \ struct ath5k_hw *ah = hw->priv; \
return snprintf(buf, PAGE_SIZE, "%d\n", get); \ 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 ***/ /*** 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); 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); ath5k_attr_show_noise_immunity_level_max, NULL);
static ssize_t ath5k_attr_show_firstep_level_max(struct device *dev, 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); 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); ath5k_attr_show_firstep_level_max, NULL);
static struct attribute *ath5k_sysfs_entries_ani[] = { static struct attribute *ath5k_sysfs_entries_ani[] = {

View File

@ -1794,69 +1794,68 @@ int ath6kl_debug_init_fs(struct ath6kl *ar)
if (!ar->debugfs_phy) if (!ar->debugfs_phy)
return -ENOMEM; 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); &fops_tgt_stats);
if (ar->hif_type == ATH6KL_HIF_TYPE_SDIO) 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, ar->debugfs_phy, ar,
&fops_credit_dist_stats); &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); ar->debugfs_phy, ar, &fops_endpoint_stats);
debugfs_create_file("fwlog", S_IRUSR, ar->debugfs_phy, ar, debugfs_create_file("fwlog", 0400, ar->debugfs_phy, ar, &fops_fwlog);
&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); &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); 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); &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); &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); 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); 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); &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); &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); &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); &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); &fops_keepalive);
debugfs_create_file("disconnect_timeout", S_IRUSR | S_IWUSR, debugfs_create_file("disconnect_timeout", 0600,
ar->debugfs_phy, ar, &fops_disconnect_timeout); 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); &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); &fops_delete_qos);
debugfs_create_file("bgscan_interval", S_IWUSR, debugfs_create_file("bgscan_interval", 0200,
ar->debugfs_phy, ar, &fops_bgscan_int); 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); 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); &fops_power_params);
return 0; return 0;

View File

@ -47,7 +47,7 @@ static const struct file_operations fops_modal_eeprom = {
void ath9k_cmn_debug_modal_eeprom(struct dentry *debugfs_phy, void ath9k_cmn_debug_modal_eeprom(struct dentry *debugfs_phy,
struct ath_hw *ah) 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); &fops_modal_eeprom);
} }
EXPORT_SYMBOL(ath9k_cmn_debug_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, void ath9k_cmn_debug_base_eeprom(struct dentry *debugfs_phy,
struct ath_hw *ah) 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); &fops_base_eeprom);
} }
EXPORT_SYMBOL(ath9k_cmn_debug_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, void ath9k_cmn_debug_recv(struct dentry *debugfs_phy,
struct ath_rx_stats *rxstats) struct ath_rx_stats *rxstats)
{ {
debugfs_create_file("recv", S_IRUSR, debugfs_phy, rxstats, debugfs_create_file("recv", 0400, debugfs_phy, rxstats, &fops_recv);
&fops_recv);
} }
EXPORT_SYMBOL(ath9k_cmn_debug_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, void ath9k_cmn_debug_phy_err(struct dentry *debugfs_phy,
struct ath_rx_stats *rxstats) 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); &fops_phy_err);
} }
EXPORT_SYMBOL(ath9k_cmn_debug_phy_err); EXPORT_SYMBOL(ath9k_cmn_debug_phy_err);

View File

@ -88,7 +88,7 @@ static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
CHAN5G(5825, 37), /* Channel 165 */ 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) \ #define SHPCHECK(__hw_rate, __flags) \
((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)

View File

@ -479,14 +479,16 @@ ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv)
{ {
int i = 0; int i = 0;
int ret = 0; int ret = 0;
struct rchan_buf *buf;
struct rchan *rc = spec_priv->rfs_chan_spec_scan; struct rchan *rc = spec_priv->rfs_chan_spec_scan;
for_each_online_cpu(i) for_each_possible_cpu(i) {
ret += relay_buf_full(*per_cpu_ptr(rc->buf, i)); if ((buf = *per_cpu_ptr(rc->buf, i))) {
ret += relay_buf_full(buf);
}
}
i = num_online_cpus(); if (ret)
if (ret == i)
return 1; return 1;
else else
return 0; return 0;
@ -1096,23 +1098,23 @@ void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv *spec_priv,
return; return;
debugfs_create_file("spectral_scan_ctl", debugfs_create_file("spectral_scan_ctl",
S_IRUSR | S_IWUSR, 0600,
debugfs_phy, spec_priv, debugfs_phy, spec_priv,
&fops_spec_scan_ctl); &fops_spec_scan_ctl);
debugfs_create_file("spectral_short_repeat", debugfs_create_file("spectral_short_repeat",
S_IRUSR | S_IWUSR, 0600,
debugfs_phy, spec_priv, debugfs_phy, spec_priv,
&fops_spectral_short_repeat); &fops_spectral_short_repeat);
debugfs_create_file("spectral_count", debugfs_create_file("spectral_count",
S_IRUSR | S_IWUSR, 0600,
debugfs_phy, spec_priv, debugfs_phy, spec_priv,
&fops_spectral_count); &fops_spectral_count);
debugfs_create_file("spectral_period", debugfs_create_file("spectral_period",
S_IRUSR | S_IWUSR, 0600,
debugfs_phy, spec_priv, debugfs_phy, spec_priv,
&fops_spectral_period); &fops_spectral_period);
debugfs_create_file("spectral_fft_period", debugfs_create_file("spectral_fft_period",
S_IRUSR | S_IWUSR, 0600,
debugfs_phy, spec_priv, debugfs_phy, spec_priv,
&fops_spectral_fft_period); &fops_spectral_fft_period);
} }

View File

@ -1385,7 +1385,7 @@ int ath9k_init_debug(struct ath_hw *ah)
return -ENOMEM; return -ENOMEM;
#ifdef CONFIG_ATH_DEBUG #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); sc, &fops_debug);
#endif #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_recv(sc->debug.debugfs_phy, &sc->debug.stats.rxstats);
ath9k_cmn_debug_phy_err(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); &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); &ah->txchainmask);
debugfs_create_file("ani", S_IRUSR | S_IWUSR, debugfs_create_file("ani", 0600,
sc->debug.debugfs_phy, sc, &fops_ani); 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); &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); 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); sc, &fops_regval);
debugfs_create_bool("ignore_extcca", S_IRUSR | S_IWUSR, debugfs_create_bool("ignore_extcca", 0600,
sc->debug.debugfs_phy, sc->debug.debugfs_phy,
&ah->config.cwm_ignore_extcca); &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); &fops_regdump);
debugfs_create_devm_seqfile(sc->dev, "dump_nfcal", debugfs_create_devm_seqfile(sc->dev, "dump_nfcal",
sc->debug.debugfs_phy, 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_base_eeprom(sc->debug.debugfs_phy, sc->sc_ah);
ath9k_cmn_debug_modal_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); 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); 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); sc->debug.debugfs_phy, sc, &fops_antenna_diversity);
#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT #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); 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); &fops_btcoex);
#endif #endif
#ifdef CONFIG_ATH9K_WOW #ifdef CONFIG_ATH9K_WOW
debugfs_create_file("wow", S_IRUSR | S_IWUSR, debugfs_create_file("wow", 0600, sc->debug.debugfs_phy, sc, &fops_wow);
sc->debug.debugfs_phy, sc, &fops_wow);
#endif #endif
#ifdef CONFIG_ATH9K_DYNACK #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); sc, &fops_ackto);
#endif #endif
debugfs_create_file("tpc", S_IRUSR | S_IWUSR, debugfs_create_file("tpc", 0600, sc->debug.debugfs_phy, sc, &fops_tpc);
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); 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); sc->debug.debugfs_phy, sc, &fops_nf_override);
return 0; return 0;

View File

@ -302,7 +302,7 @@ void ath9k_sta_add_debugfs(struct ieee80211_hw *hw,
{ {
struct ath_node *an = (struct ath_node *)sta->drv_priv; 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_aggr", 0444, dir, an, &fops_node_aggr);
debugfs_create_file("node_recv", S_IRUGO, dir, an, &fops_node_recv); debugfs_create_file("node_recv", 0444, dir, an, &fops_node_recv);
debugfs_create_file("airtime", S_IRUGO, dir, an, &fops_airtime); debugfs_create_file("airtime", 0444, dir, an, &fops_airtime);
} }

View File

@ -144,8 +144,8 @@ static const struct file_operations fops_dfs_stats = {
void ath9k_dfs_init_debug(struct ath_softc *sc) 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); 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); sc->debug.debugfs_phy, sc, &fops_simulate_radar);
} }

View File

@ -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); 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); 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); 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); 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); 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); priv, &fops_skb_rx);
ath9k_cmn_debug_recv(priv->debug.debugfs_phy, &priv->debug.rx_stats); 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); 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); 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); 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); priv, &fops_debug);
ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah); ath9k_cmn_debug_base_eeprom(priv->debug.debugfs_phy, priv->ah);

View File

@ -591,7 +591,7 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv)
{ {
struct ath_common *common = ath9k_hw_common(priv->ah); 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; common->last_rssi = ATH_RSSI_DUMMY_MARKER;
priv->ah->opmode = NL80211_IFTYPE_STATION; priv->ah->opmode = NL80211_IFTYPE_STATION;

View File

@ -184,7 +184,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
break; break;
case WLAN_RC_PHY_OFDM: case WLAN_RC_PHY_OFDM:
if (ah->curchan && IS_CHAN_QUARTER_RATE(ah->curchan)) { 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); numBits = OFDM_PLCP_BITS + (frameLen << 3);
numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
txTime = OFDM_SIFS_TIME_QUARTER txTime = OFDM_SIFS_TIME_QUARTER
@ -192,7 +193,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
+ (numSymbols * OFDM_SYMBOL_TIME_QUARTER); + (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
} else if (ah->curchan && } else if (ah->curchan &&
IS_CHAN_HALF_RATE(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); numBits = OFDM_PLCP_BITS + (frameLen << 3);
numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
txTime = OFDM_SIFS_TIME_HALF + 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 acktimeout, ctstimeout, ack_offset = 0;
int slottime; int slottime;
int sifstime; 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; u32 reg;
ath_dbg(ath9k_hw_common(ah), RESET, "ah->misc_mode 0x%x\n", 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; sifstime = 32;
ack_offset = 16; ack_offset = 16;
ack_shift = 3;
slottime = 13; slottime = 13;
} else if (IS_CHAN_QUARTER_RATE(chan)) { } else if (IS_CHAN_QUARTER_RATE(chan)) {
eifs = 340; eifs = 340;
@ -1078,6 +1081,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
sifstime = 64; sifstime = 64;
ack_offset = 32; ack_offset = 32;
ack_shift = 1;
slottime = 21; slottime = 21;
} else { } else {
if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) { 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), SM(tx_lat, AR_USEC_TX_LAT),
AR_USEC_TX_LAT | AR_USEC_RX_LAT | AR_USEC_USEC); 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); EXPORT_SYMBOL(ath9k_hw_init_global_settings);

View File

@ -257,6 +257,11 @@ static void ath9k_reg_notifier(struct wiphy *wiphy,
ath_reg_notifier_apply(wiphy, request, reg); 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 */ /* Set tx power */
if (!ah->curchan) if (!ah->curchan)
return; return;
@ -267,10 +272,6 @@ static void ath9k_reg_notifier(struct wiphy *wiphy,
ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower,
sc->cur_chan->txpower, sc->cur_chan->txpower,
&sc->cur_chan->cur_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); 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); timer_setup(&common->ani.timer, ath_ani_calibrate, 0);
common->last_rssi = ATH_RSSI_DUMMY_MARKER; common->last_rssi = ATH_RSSI_DUMMY_MARKER;
memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN); eth_broadcast_addr(common->bssidmask);
sc->beacon.slottime = 9; sc->beacon.slottime = 9;
for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)

View File

@ -278,10 +278,10 @@ void ath9k_tx99_init_debug(struct ath_softc *sc)
if (!AR_SREV_9280_20_OR_LATER(sc->sc_ah)) if (!AR_SREV_9280_20_OR_LATER(sc->sc_ah))
return; return;
debugfs_create_file("tx99", S_IRUSR | S_IWUSR, debugfs_create_file("tx99", 0600,
sc->debug.debugfs_phy, sc, sc->debug.debugfs_phy, sc,
&fops_tx99); &fops_tx99);
debugfs_create_file("tx99_power", S_IRUSR | S_IWUSR, debugfs_create_file("tx99_power", 0600,
sc->debug.debugfs_phy, sc, sc->debug.debugfs_phy, sc,
&fops_tx99_power); &fops_tx99_power);
} }

View File

@ -2892,6 +2892,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
struct ath_txq *txq; struct ath_txq *txq;
int tidno; int tidno;
rcu_read_lock();
for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
tid = ath_node_to_tid(an, tidno); tid = ath_node_to_tid(an, tidno);
txq = tid->txq; txq = tid->txq;
@ -2909,6 +2911,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
if (!an->sta) if (!an->sta)
break; /* just one multicast ath_atx_tid */ break; /* just one multicast ath_atx_tid */
} }
rcu_read_unlock();
} }
#ifdef CONFIG_ATH9K_TX99 #ifdef CONFIG_ATH9K_TX99

View File

@ -187,21 +187,21 @@ static const struct carl9170_debugfs_fops carl_debugfs_##name ##_ops = {\
#define DEBUGFS_DECLARE_RO_FILE(name, _read_bufsize) \ #define DEBUGFS_DECLARE_RO_FILE(name, _read_bufsize) \
DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \ DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \
NULL, _read_bufsize, S_IRUSR) NULL, _read_bufsize, 0400)
#define DEBUGFS_DECLARE_WO_FILE(name) \ #define DEBUGFS_DECLARE_WO_FILE(name) \
DEBUGFS_DECLARE_FILE(name, NULL, carl9170_debugfs_##name ##_write,\ DEBUGFS_DECLARE_FILE(name, NULL, carl9170_debugfs_##name ##_write,\
0, S_IWUSR) 0, 0200)
#define DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize) \ #define DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize) \
DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \ DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \
carl9170_debugfs_##name ##_write, \ carl9170_debugfs_##name ##_write, \
_read_bufsize, S_IRUSR | S_IWUSR) _read_bufsize, 0600)
#define __DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize, _dstate) \ #define __DEBUGFS_DECLARE_RW_FILE(name, _read_bufsize, _dstate) \
__DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \ __DEBUGFS_DECLARE_FILE(name, carl9170_debugfs_##name ##_read, \
carl9170_debugfs_##name ##_write, \ carl9170_debugfs_##name ##_write, \
_read_bufsize, S_IRUSR | S_IWUSR, _dstate) _read_bufsize, 0600, _dstate)
#define DEBUGFS_READONLY_FILE(name, _read_bufsize, fmt, value...) \ #define DEBUGFS_READONLY_FILE(name, _read_bufsize, fmt, value...) \
static char *carl9170_debugfs_ ##name ## _read(struct ar9170 *ar, \ static char *carl9170_debugfs_ ##name ## _read(struct ar9170 *ar, \

View File

@ -48,11 +48,11 @@
#include "cmd.h" #include "cmd.h"
static bool modparam_nohwcrypt; 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."); MODULE_PARM_DESC(nohwcrypt, "Disable hardware crypto offload.");
int modparam_noht; 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."); MODULE_PARM_DESC(noht, "Disable MPDU aggregation.");
#define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \ #define RATE(_bitrate, _hw_rate, _txpidx, _flags) { \

View File

@ -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(4, 0, 5, 150, 230, 1, 23, 50, false),
JP_PATTERN(5, 6, 10, 200, 500, 1, 16, 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(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), JP_PATTERN(5, 0, 1, 333, 333, 1, 9, 50, false),
}; };

View File

@ -161,9 +161,8 @@ void wcn36xx_debugfs_init(struct wcn36xx *wcn)
dfs->rootdir = NULL; dfs->rootdir = NULL;
} }
ADD_FILE(bmps_switcher, S_IRUSR | S_IWUSR, ADD_FILE(bmps_switcher, 0600, &fops_wcn36xx_bmps, wcn);
&fops_wcn36xx_bmps, wcn); ADD_FILE(dump, 0200, &fops_wcn36xx_dump, wcn);
ADD_FILE(dump, S_IWUSR, &fops_wcn36xx_dump, wcn);
} }
void wcn36xx_debugfs_exit(struct wcn36xx *wcn) void wcn36xx_debugfs_exit(struct wcn36xx *wcn)

View File

@ -27,15 +27,6 @@
#include "wcn36xx.h" #include "wcn36xx.h"
#include "txrx.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) static void wcn36xx_ccu_write_register(struct wcn36xx *wcn, int addr, int data)
{ {
wcn36xx_dbg(WCN36XX_DBG_DXE, 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); spin_lock_irqsave(&ch->lock, flags);
ctl = ch->tail_blk_ctl; ctl = ch->tail_blk_ctl;
do { do {
if (ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK) if (ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD)
break; break;
if (ctl->skb) { if (ctl->skb) {
dma_unmap_single(wcn->dev, ctl->desc->src_addr_l, 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; ctl = ctl->next;
} while (ctl != ch->head_blk_ctl && } 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; ch->tail_blk_ctl = ctl;
spin_unlock_irqrestore(&ch->lock, flags); 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, WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_H,
&int_reason); &int_reason);
/* TODO: Check int_reason */
wcn36xx_dxe_write_register(wcn, wcn36xx_dxe_write_register(wcn,
WCN36XX_DXE_0_INT_CLR, WCN36XX_DXE_0_INT_CLR,
WCN36XX_INT_MASK_CHAN_TX_H); WCN36XX_INT_MASK_CHAN_TX_H);
wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR, if (int_reason & WCN36XX_CH_STAT_INT_ERR_MASK ) {
WCN36XX_INT_MASK_CHAN_TX_H); 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"); wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready high\n");
reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch); 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_read_register(wcn,
WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_L, WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_L,
&int_reason); &int_reason);
/* TODO: Check int_reason */
wcn36xx_dxe_write_register(wcn, wcn36xx_dxe_write_register(wcn,
WCN36XX_DXE_0_INT_CLR, WCN36XX_DXE_0_INT_CLR,
WCN36XX_INT_MASK_CHAN_TX_L); 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"); wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready low\n");
reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch); 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; 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; skb = ctl->skb;
dma_addr = dxe->dst_addr_l; dma_addr = dxe->dst_addr_l;
ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl); 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, int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
struct wcn36xx_vif *vif_priv, struct wcn36xx_vif *vif_priv,
struct wcn36xx_tx_bd *bd,
struct sk_buff *skb, struct sk_buff *skb,
bool is_low) bool is_low)
{ {
@ -645,6 +673,9 @@ int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
ctl->skb = NULL; ctl->skb = NULL;
desc = ctl->desc; desc = ctl->desc;
/* write buffer descriptor */
memcpy(ctl->bd_cpu_addr, bd, sizeof(*bd));
/* Set source address of the BD we send */ /* Set source address of the BD we send */
desc->src_addr_l = ctl->bd_phy_addr; desc->src_addr_l = ctl->bd_phy_addr;

View File

@ -33,15 +33,106 @@ H2H_TEST_RX_TX = DMA2
#define WCN36XX_CCU_DXE_INT_SELECT_RIVA 0x310 #define WCN36XX_CCU_DXE_INT_SELECT_RIVA 0x310
#define WCN36XX_CCU_DXE_INT_SELECT_PRONTO 0x10dc #define WCN36XX_CCU_DXE_INT_SELECT_PRONTO 0x10dc
/* TODO This must calculated properly but not hardcoded */ /* Descriptor valid */
#define WCN36XX_DXE_CTRL_TX_L 0x328a44 #define WCN36xx_DXE_CTRL_VLD BIT(0)
#define WCN36XX_DXE_CTRL_TX_H 0x32ce44 /* End of packet */
#define WCN36XX_DXE_CTRL_RX_L 0x12ad2f #define WCN36xx_DXE_CTRL_EOP BIT(3)
#define WCN36XX_DXE_CTRL_RX_H 0x12d12f /* BD handling bit */
#define WCN36XX_DXE_CTRL_TX_H_BD 0x30ce45 #define WCN36xx_DXE_CTRL_BDH BIT(4)
#define WCN36XX_DXE_CTRL_TX_H_SKB 0x32ce4d /* Source is a queue */
#define WCN36XX_DXE_CTRL_TX_L_BD 0x308a45 #define WCN36xx_DXE_CTRL_SIQ BIT(5)
#define WCN36XX_DXE_CTRL_TX_L_SKB 0x328a4d /* 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 */ /* TODO This must calculated properly but not hardcoded */
#define WCN36XX_DXE_WQ_TX_L 0x17 #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_L 0xB
#define WCN36XX_DXE_WQ_RX_H 0x4 #define WCN36XX_DXE_WQ_RX_H 0x4
/* DXE descriptor control filed */ /* Channel enable or restart */
#define WCN36XX_DXE_CTRL_VALID_MASK (0x00000001) #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 */ /* DXE default control register values */
#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_L 0x847EAD2F #define WCN36XX_DXE_CH_DEFAULT_CTL_RX_L (WCN36xx_DXE_CH_CTRL_EN | \
#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_H 0x84FED12F WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \
#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_H 0x853ECF4D WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_SIQ | \
#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_L 0x843e8b4d 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 */ /* Common DXE registers */
#define WCN36XX_DXE_MEM_CSR (WCN36XX_DXE_MEM_REG + 0x00) #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_DONE_CLR (WCN36XX_DXE_MEM_REG + 0x38)
#define WCN36XX_DXE_0_INT_ERR_CLR (WCN36XX_DXE_MEM_REG + 0x3C) #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_CH0_STATUS (WCN36XX_DXE_MEM_REG + 0x404)
#define WCN36XX_DXE_0_CH1_STATUS (WCN36XX_DXE_MEM_REG + 0x444) #define WCN36XX_DXE_0_CH1_STATUS (WCN36XX_DXE_MEM_REG + 0x444)
#define WCN36XX_DXE_0_CH2_STATUS (WCN36XX_DXE_MEM_REG + 0x484) #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; dma_addr_t phy_addr;
}; };
struct wcn36xx_tx_bd;
struct wcn36xx_vif; struct wcn36xx_vif;
int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn); int wcn36xx_dxe_allocate_mem_pools(struct wcn36xx *wcn);
void wcn36xx_dxe_free_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_init_channels(struct wcn36xx *wcn);
int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn, int wcn36xx_dxe_tx_frame(struct wcn36xx *wcn,
struct wcn36xx_vif *vif_priv, struct wcn36xx_vif *vif_priv,
struct wcn36xx_tx_bd *bd,
struct sk_buff *skb, struct sk_buff *skb,
bool is_low); bool is_low);
void wcn36xx_dxe_tx_ack_ind(struct wcn36xx *wcn, u32 status); 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_ */ #endif /* _DXE_H_ */

View File

@ -261,7 +261,7 @@ static void wcn36xx_feat_caps_info(struct wcn36xx *wcn)
for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) { for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) {
if (get_feat_caps(wcn->fw_feat_caps, 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; 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); mutex_lock(&wcn->scan_lock);
wcn->scan_aborted = true; wcn->scan_aborted = true;
mutex_unlock(&wcn->scan_lock); 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); 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->cipher_suites = cipher_suites;
wcn->hw->wiphy->n_cipher_suites = ARRAY_SIZE(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 #ifdef CONFIG_PM
wcn->hw->wiphy->wowlan = &wowlan_support; wcn->hw->wiphy->wowlan = &wowlan_support;
#endif #endif
@ -1283,6 +1278,7 @@ static int wcn36xx_probe(struct platform_device *pdev)
wcn = hw->priv; wcn = hw->priv;
wcn->hw = hw; wcn->hw = hw;
wcn->dev = &pdev->dev; wcn->dev = &pdev->dev;
wcn->first_boot = true;
mutex_init(&wcn->conf_mutex); mutex_init(&wcn->conf_mutex);
mutex_init(&wcn->hal_mutex); mutex_init(&wcn->hal_mutex);
mutex_init(&wcn->scan_lock); mutex_init(&wcn->scan_lock);

View File

@ -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_minor = rsp->start_rsp_params.version.minor;
wcn->fw_major = rsp->start_rsp_params.version.major; wcn->fw_major = rsp->start_rsp_params.version.major;
wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n", if (wcn->first_boot) {
wcn->wlan_version, wcn->crm_version); wcn->first_boot = false;
wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n",
wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n", wcn->wlan_version, wcn->crm_version);
wcn->fw_major, wcn->fw_minor,
wcn->fw_version, wcn->fw_revision,
rsp->start_rsp_params.stations,
rsp->start_rsp_params.bssids);
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; 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: case WCN36XX_HAL_SCAN_IND_COMPLETED:
mutex_lock(&wcn->scan_lock); mutex_lock(&wcn->scan_lock);
wcn->scan_req = NULL; wcn->scan_req = NULL;
if (wcn->scan_aborted)
scan_info.aborted = true;
mutex_unlock(&wcn->scan_lock); mutex_unlock(&wcn->scan_lock);
ieee80211_scan_completed(wcn->hw, &scan_info); ieee80211_scan_completed(wcn->hw, &scan_info);
break; break;
@ -2407,54 +2411,63 @@ static void wcn36xx_ind_smd_work(struct work_struct *work)
{ {
struct wcn36xx *wcn = struct wcn36xx *wcn =
container_of(work, struct wcn36xx, hal_ind_work); 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, spin_lock_irqsave(&wcn->hal_ind_lock, flags);
struct wcn36xx_hal_ind_msg,
list);
list_del(wcn->hal_ind_queue.next);
spin_unlock_irqrestore(&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) { hal_ind_msg = list_first_entry(&wcn->hal_ind_queue,
case WCN36XX_HAL_COEX_IND: struct wcn36xx_hal_ind_msg,
case WCN36XX_HAL_DEL_BA_IND: list);
case WCN36XX_HAL_AVOID_FREQ_RANGE_IND: list_del(&hal_ind_msg->list);
break; spin_unlock_irqrestore(&wcn->hal_ind_lock, flags);
case WCN36XX_HAL_OTA_TX_COMPL_IND:
wcn36xx_smd_tx_compl_ind(wcn, msg_header = (struct wcn36xx_hal_msg_header *)hal_ind_msg->msg;
hal_ind_msg->msg,
hal_ind_msg->msg_len); switch (msg_header->msg_type) {
break; case WCN36XX_HAL_COEX_IND:
case WCN36XX_HAL_MISSED_BEACON_IND: case WCN36XX_HAL_DEL_BA_IND:
wcn36xx_smd_missed_beacon_ind(wcn, case WCN36XX_HAL_AVOID_FREQ_RANGE_IND:
hal_ind_msg->msg, break;
hal_ind_msg->msg_len); case WCN36XX_HAL_OTA_TX_COMPL_IND:
break; wcn36xx_smd_tx_compl_ind(wcn,
case WCN36XX_HAL_DELETE_STA_CONTEXT_IND: hal_ind_msg->msg,
wcn36xx_smd_delete_sta_context_ind(wcn, hal_ind_msg->msg_len);
hal_ind_msg->msg, break;
hal_ind_msg->msg_len); case WCN36XX_HAL_MISSED_BEACON_IND:
break; wcn36xx_smd_missed_beacon_ind(wcn,
case WCN36XX_HAL_PRINT_REG_INFO_IND: hal_ind_msg->msg,
wcn36xx_smd_print_reg_info_ind(wcn, hal_ind_msg->msg_len);
hal_ind_msg->msg, break;
hal_ind_msg->msg_len); case WCN36XX_HAL_DELETE_STA_CONTEXT_IND:
break; wcn36xx_smd_delete_sta_context_ind(wcn,
case WCN36XX_HAL_SCAN_OFFLOAD_IND: hal_ind_msg->msg,
wcn36xx_smd_hw_scan_ind(wcn, hal_ind_msg->msg, hal_ind_msg->msg_len);
hal_ind_msg->msg_len); break;
break; case WCN36XX_HAL_PRINT_REG_INFO_IND:
default: wcn36xx_smd_print_reg_info_ind(wcn,
wcn36xx_err("SMD_EVENT (%d) not supported\n", hal_ind_msg->msg,
msg_header->msg_type); 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) int wcn36xx_smd_open(struct wcn36xx *wcn)
{ {

View File

@ -272,21 +272,9 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
bool is_low = ieee80211_is_data(hdr->frame_control); bool is_low = ieee80211_is_data(hdr->frame_control);
bool bcast = is_broadcast_ether_addr(hdr->addr1) || bool bcast = is_broadcast_ether_addr(hdr->addr1) ||
is_multicast_ether_addr(hdr->addr1); is_multicast_ether_addr(hdr->addr1);
struct wcn36xx_tx_bd *bd = wcn36xx_dxe_get_next_bd(wcn, is_low); struct wcn36xx_tx_bd bd;
if (!bd) { memset(&bd, 0, sizeof(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;
}
memset(bd, 0, sizeof(*bd));
wcn36xx_dbg(WCN36XX_DBG_TX, wcn36xx_dbg(WCN36XX_DBG_TX,
"tx skb %p len %d fc %04x sn %d %s %s\n", "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); 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); bd.tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS);
if (bd->tx_comp) { if (bd.tx_comp) {
wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n"); wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n");
spin_lock_irqsave(&wcn->dxe_lock, flags); spin_lock_irqsave(&wcn->dxe_lock, flags);
if (wcn->tx_ack_skb) { if (wcn->tx_ack_skb) {
@ -321,13 +309,13 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
/* Data frames served first*/ /* Data frames served first*/
if (is_low) 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 else
/* MGMT and CTRL frames are handeld here*/ /* 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)); buff_to_be((u32 *)&bd, sizeof(bd)/sizeof(u32));
bd->tx_bd_sign = 0xbdbdbdbd; 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);
} }

View File

@ -192,6 +192,8 @@ struct wcn36xx {
u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1]; u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1];
u8 wlan_version[WCN36XX_HAL_VERSION_LENGTH + 1]; u8 wlan_version[WCN36XX_HAL_VERSION_LENGTH + 1];
bool first_boot;
/* IRQs */ /* IRQs */
int tx_irq; int tx_irq;
int rx_irq; int rx_irq;

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2013,2016 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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); va_start(args, fmt);
vaf.fmt = fmt; vaf.fmt = fmt;
vaf.va = &args; vaf.va = &args;
netdev_err(wil_to_ndev(wil), "%pV", &vaf); netdev_err(wil->main_ndev, "%pV", &vaf);
trace_wil6210_log_err(&vaf); trace_wil6210_log_err(&vaf);
va_end(args); va_end(args);
} }
@ -41,7 +42,7 @@ void __wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...)
va_start(args, fmt); va_start(args, fmt);
vaf.fmt = fmt; vaf.fmt = fmt;
vaf.va = &args; vaf.va = &args;
netdev_err(wil_to_ndev(wil), "%pV", &vaf); netdev_err(wil->main_ndev, "%pV", &vaf);
trace_wil6210_log_err(&vaf); trace_wil6210_log_err(&vaf);
va_end(args); va_end(args);
} }
@ -57,7 +58,7 @@ void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...)
va_start(args, fmt); va_start(args, fmt);
vaf.fmt = fmt; vaf.fmt = fmt;
vaf.va = &args; vaf.va = &args;
netdev_dbg(wil_to_ndev(wil), "%pV", &vaf); netdev_dbg(wil->main_ndev, "%pV", &vaf);
trace_wil6210_log_dbg(&vaf); trace_wil6210_log_dbg(&vaf);
va_end(args); va_end(args);
} }
@ -70,7 +71,7 @@ void __wil_info(struct wil6210_priv *wil, const char *fmt, ...)
va_start(args, fmt); va_start(args, fmt);
vaf.fmt = fmt; vaf.fmt = fmt;
vaf.va = &args; vaf.va = &args;
netdev_info(wil_to_ndev(wil), "%pV", &vaf); netdev_info(wil->main_ndev, "%pV", &vaf);
trace_wil6210_log_info(&vaf); trace_wil6210_log_info(&vaf);
va_end(args); va_end(args);
} }

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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) size_t len, loff_t *ppos)
{ {
struct wil6210_priv *wil = file->private_data; struct wil6210_priv *wil = file->private_data;
struct net_device *ndev = wil_to_ndev(wil); struct net_device *ndev = wil->main_ndev;
/** /**
* BUG: * BUG:
@ -716,27 +717,44 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf,
if (rc < 2) if (rc < 2)
return -EINVAL; return -EINVAL;
if (0 == strcmp(cmd, "add")) { if ((strcmp(cmd, "add") == 0) ||
if (rc < 3) { (strcmp(cmd, "del_tx") == 0)) {
wil_err(wil, "BACK: add require at least 2 params\n"); 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; return -EINVAL;
} }
if (rc < 4) txdata = &wil->vring_tx_data[p1];
p3 = 0; if (strcmp(cmd, "add") == 0) {
wmi_addba(wil, p1, p2, p3); if (rc < 3) {
} else if (0 == strcmp(cmd, "del_tx")) { wil_err(wil, "BACK: add require at least 2 params\n");
if (rc < 3) return -EINVAL;
p2 = WLAN_REASON_QSTA_LEAVE_QBSS; }
wmi_delba_tx(wil, p1, p2); if (rc < 4)
} else if (0 == strcmp(cmd, "del_rx")) { 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) { if (rc < 3) {
wil_err(wil, wil_err(wil,
"BACK: del_rx require at least 2 params\n"); "BACK: del_rx require at least 2 params\n");
return -EINVAL; return -EINVAL;
} }
if (p1 < 0 || p1 >= WIL6210_MAX_CID) {
wil_err(wil, "BACK: invalid CID %d\n", p1);
return -EINVAL;
}
if (rc < 4) if (rc < 4)
p3 = WLAN_REASON_QSTA_LEAVE_QBSS; 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 { } else {
wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd); wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
return -EINVAL; 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 wil6210_priv *wil = file->private_data;
struct wiphy *wiphy = wil_to_wiphy(wil); 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; struct cfg80211_mgmt_tx_params params;
int rc; int rc;
void *frame; 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) size_t len, loff_t *ppos)
{ {
struct wil6210_priv *wil = file->private_data; struct wil6210_priv *wil = file->private_data;
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_cmd_hdr *wmi; struct wmi_cmd_hdr *wmi;
void *cmd; void *cmd;
int cmdlen = len - sizeof(struct wmi_cmd_hdr); 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; cmd = (cmdlen > 0) ? &wmi[1] : NULL;
cmdid = le16_to_cpu(wmi->command_id); 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); kfree(wmi);
wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1); 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 rc;
int i; int i;
struct wil6210_priv *wil = s->private; struct wil6210_priv *wil = s->private;
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_notify_req_cmd cmd = { struct wmi_notify_req_cmd cmd = {
.interval_usec = 0, .interval_usec = 0,
}; };
@ -1062,7 +1082,8 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data)
u32 status; u32 status;
cmd.cid = i; 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, WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
sizeof(reply), 20); sizeof(reply), 20);
/* if reply is all-0, ignore this CID */ /* 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) static int wil_freq_debugfs_show(struct seq_file *s, void *data)
{ {
struct wil6210_priv *wil = s->private; 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; u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
seq_printf(s, "Freq = %d\n", freq); 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++) { for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i]; struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown"; char *status = "unknown";
struct wil6210_vif *vif;
u8 mid;
switch (p->status) { switch (p->status) {
case wil_sta_unused: case wil_sta_unused:
@ -1197,16 +1220,24 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
status = "connected"; status = "connected";
break; 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) { if (p->status != wil_sta_connected)
rc = wil_cid_fill_sinfo(wil, i, &sinfo); continue;
vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL;
if (vif) {
rc = wil_cid_fill_sinfo(vif, i, &sinfo);
if (rc) if (rc)
return rc; return rc;
seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs); seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs);
seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs); seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs);
seq_printf(s, " SQ = %d\n", sinfo.signal); 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) static int wil_info_debugfs_show(struct seq_file *s, void *data)
{ {
struct wil6210_priv *wil = s->private; 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 is_ac = power_supply_is_system_supplied();
int rx = atomic_xchg(&wil->isr_count_rx, 0); int rx = atomic_xchg(&wil->isr_count_rx, 0);
int tx = atomic_xchg(&wil->isr_count_tx, 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]; struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown"; char *status = "unknown";
u8 aid = 0; u8 aid = 0;
u8 mid;
switch (p->status) { switch (p->status) {
case wil_sta_unused: case wil_sta_unused:
@ -1411,7 +1443,9 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
aid = p->aid; aid = p->aid;
break; 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) { if (p->status == wil_sta_connected) {
spin_lock_bh(&p->tid_rx_lock); spin_lock_bh(&p->tid_rx_lock);
@ -1461,6 +1495,42 @@ static const struct file_operations fops_sta = {
.llseek = seq_lseek, .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, static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
@ -1715,6 +1785,7 @@ static const struct {
{"mbox", 0444, &fops_mbox}, {"mbox", 0444, &fops_mbox},
{"vrings", 0444, &fops_vring}, {"vrings", 0444, &fops_vring},
{"stations", 0444, &fops_sta}, {"stations", 0444, &fops_sta},
{"mids", 0444, &fops_mids},
{"desc", 0444, &fops_txdesc}, {"desc", 0444, &fops_txdesc},
{"bf", 0444, &fops_bf}, {"bf", 0444, &fops_bf},
{"mem_val", 0644, &fops_memread}, {"mem_val", 0644, &fops_memread},
@ -1773,11 +1844,9 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
/* fields in struct wil6210_priv */ /* fields in struct wil6210_priv */
static const struct dbg_off dbg_wil_off[] = { static const struct dbg_off dbg_wil_off[] = {
WIL_FIELD(privacy, 0444, doff_u32),
WIL_FIELD(status[0], 0644, doff_ulong), WIL_FIELD(status[0], 0644, doff_ulong),
WIL_FIELD(hw_version, 0444, doff_x32), WIL_FIELD(hw_version, 0444, doff_x32),
WIL_FIELD(recovery_count, 0444, doff_u32), WIL_FIELD(recovery_count, 0444, doff_u32),
WIL_FIELD(ap_isolate, 0444, doff_u32),
WIL_FIELD(discovery_mode, 0644, doff_u8), WIL_FIELD(discovery_mode, 0644, doff_u8),
WIL_FIELD(chip_revision, 0444, doff_u8), WIL_FIELD(chip_revision, 0444, doff_u8),
WIL_FIELD(abft_len, 0644, doff_u8), WIL_FIELD(abft_len, 0644, doff_u8),

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2014,2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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 ethtool_coalesce *cp)
{ {
struct wil6210_priv *wil = ndev_to_wil(ndev); struct wil6210_priv *wil = ndev_to_wil(ndev);
struct wireless_dev *wdev = ndev->ieee80211_ptr;
int ret; int ret;
wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n", wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n",
cp->rx_coalesce_usecs, cp->tx_coalesce_usecs); 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"); wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n");
return -EINVAL; return -EINVAL;
} }

View File

@ -14,6 +14,8 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * 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_SIGNATURE (0x36323130) /* '0126' */
#define WIL_FW_FMT_VERSION (1) /* format version driver supports */ #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; struct wil_fw_record_comment_hdr hdr;
/* capabilities (variable size), see enum wmi_fw_capability */ /* capabilities (variable size), see enum wmi_fw_capability */
u8 capabilities[0]; 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 */ /* brd file info encoded inside a comment record */
#define WIL_BRD_FILE_MAGIC (0xabcddcbb) #define WIL_BRD_FILE_MAGIC (0xabcddcbb)
@ -175,3 +209,5 @@ struct wil_fw_record_gateway_data4 { /* type == wil_fw_type_gateway_data4 */
__le32 command; __le32 command;
struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */ struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */
} __packed; } __packed;
#endif /* __WIL_FW_H__ */

View File

@ -136,8 +136,8 @@ fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
size_t capa_size; size_t capa_size;
if (size < sizeof(*rec)) { if (size < sizeof(*rec)) {
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, wil_err_fw(wil, "capabilities record too short: %zu\n", size);
data, size, true); /* let the FW load anyway */
return 0; 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; const struct wil_fw_record_brd_file *rec = data;
if (size < sizeof(*rec)) { if (size < sizeof(*rec)) {
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, wil_err_fw(wil, "brd_file record too short: %zu\n", size);
data, size, true);
return 0; return 0;
} }
@ -172,6 +171,44 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data,
return 0; return 0;
} }
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 static int
fw_handle_comment(struct wil6210_priv *wil, const void *data, fw_handle_comment(struct wil6210_priv *wil, const void *data,
size_t size) 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"); wil_dbg_fw(wil, "magic is WIL_BRD_FILE_MAGIC\n");
rc = fw_handle_brd_file(wil, data, size); rc = fw_handle_brd_file(wil, data, size);
break; 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; return rc;

View File

@ -127,7 +127,7 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
void wil6210_unmask_irq_rx(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), 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); 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) 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"); wil_dbg_irq(wil, "configure_interrupt_moderation\n");
/* disable interrupt moderation for monitor /* disable interrupt moderation for monitor
* to get better timestamp precision * to get better timestamp precision
*/ */
if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) if (wdev->iftype == NL80211_IFTYPE_MONITOR)
return; return;
/* Disable and clear tx counter before (re)configuration */ /* 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) 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] = { char *envp[3] = {
[0] = "SOURCE=wil6210", [0] = "SOURCE=wil6210",
[1] = "EVENT=FW_ERROR", [1] = "EVENT=FW_ERROR",

View File

@ -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) u16 reason_code, bool from_event)
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{ {
uint i; uint i;
struct net_device *ndev = wil_to_ndev(wil); struct wil6210_priv *wil = vif_to_wil(vif);
struct wireless_dev *wdev = wil->wdev; struct net_device *ndev = vif_to_ndev(vif);
struct wireless_dev *wdev = vif_to_wdev(vif);
struct wil_sta_info *sta = &wil->sta[cid]; struct wil_sta_info *sta = &wil->sta[cid];
might_sleep(); might_sleep();
wil_dbg_misc(wil, "disconnect_cid: CID %d, status %d\n", wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n",
cid, sta->status); cid, sta->mid, sta->status);
/* inform upper/lower layers */ /* inform upper/lower layers */
if (sta->status != wil_sta_unused) { 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) { if (!from_event) {
bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ? bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ?
disable_ap_sme : false; disable_ap_sme : false;
wmi_disconnect_sta(wil, sta->addr, reason_code, wmi_disconnect_sta(vif, sta->addr, reason_code,
true, del_sta); true, del_sta);
} }
@ -191,6 +201,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
break; break;
} }
sta->status = wil_sta_unused; sta->status = wil_sta_unused;
sta->mid = U8_MAX;
} }
/* reorder buffers */ /* reorder buffers */
for (i = 0; i < WIL_STA_TID_NUM; i++) { 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)); 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; int i;
for (i = 0; i < ARRAY_SIZE(wil->sta); 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 true;
} }
return false; 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) u16 reason_code, bool from_event)
{ {
struct wil6210_priv *wil = vif_to_wil(vif);
int cid = -ENOENT; int cid = -ENOENT;
struct net_device *ndev = wil_to_ndev(wil); struct net_device *ndev;
struct wireless_dev *wdev = wil->wdev; struct wireless_dev *wdev;
if (unlikely(!ndev)) if (unlikely(!vif))
return; return;
ndev = vif_to_ndev(vif);
wdev = vif_to_wdev(vif);
might_sleep(); might_sleep();
wil_info(wil, "bssid=%pM, reason=%d, ev%s\n", bssid, wil_info(wil, "bssid=%pM, reason=%d, ev%s\n", bssid,
reason_code, from_event ? "+" : "-"); 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) && if (bssid && !is_broadcast_ether_addr(bssid) &&
!ether_addr_equal_unaligned(ndev->dev_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", wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n",
bssid, cid, reason_code); bssid, cid, reason_code);
if (cid >= 0) /* disconnect 1 peer */ 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 */ } else { /* all */
wil_dbg_misc(wil, "Disconnect all\n"); wil_dbg_misc(wil, "Disconnect all\n");
for (cid = 0; cid < WIL6210_MAX_CID; cid++) 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 */ /* link state */
switch (wdev->iftype) { switch (wdev->iftype) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_CLIENT:
wil_bcast_fini(wil); wil_bcast_fini(vif);
wil_update_net_queues_bh(wil, NULL, true); wil_update_net_queues_bh(wil, vif, NULL, true);
netif_carrier_off(ndev); 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)) { if (test_and_clear_bit(wil_vif_fwconnected, vif->status)) {
clear_bit(wil_status_fwconnected, wil->status); atomic_dec(&wil->connected_vifs);
cfg80211_disconnected(ndev, reason_code, cfg80211_disconnected(ndev, reason_code,
NULL, 0, NULL, 0,
wil->locally_generated_disc, vif->locally_generated_disc,
GFP_KERNEL); GFP_KERNEL);
wil->locally_generated_disc = false; vif->locally_generated_disc = false;
} else if (test_bit(wil_status_fwconnecting, wil->status)) { } else if (test_bit(wil_vif_fwconnecting, vif->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0, cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL); GFP_KERNEL);
wil->bss = NULL; vif->bss = NULL;
} }
clear_bit(wil_status_fwconnecting, wil->status); clear_bit(wil_vif_fwconnecting, vif->status);
break; break;
case NL80211_IFTYPE_AP: case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO: case NL80211_IFTYPE_P2P_GO:
if (!wil_is_connected(wil)) { if (!wil_vif_is_connected(wil, vif->mid)) {
wil_update_net_queues_bh(wil, NULL, true); wil_update_net_queues_bh(wil, vif, NULL, true);
clear_bit(wil_status_fwconnected, wil->status); if (test_and_clear_bit(wil_vif_fwconnected,
vif->status))
atomic_dec(&wil->connected_vifs);
} else { } else {
wil_update_net_queues_bh(wil, NULL, false); wil_update_net_queues_bh(wil, vif, NULL, false);
} }
break; break;
default: 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_vif *vif = container_of(work,
struct wil6210_priv, disconnect_worker); struct wil6210_vif, disconnect_worker);
struct net_device *ndev = wil_to_ndev(wil); struct wil6210_priv *wil = vif_to_wil(vif);
struct net_device *ndev = vif_to_ndev(vif);
int rc; int rc;
struct { struct {
struct wmi_cmd_hdr wmi; struct wmi_cmd_hdr wmi;
struct wmi_disconnect_event evt; struct wmi_disconnect_event evt;
} __packed reply; } __packed reply;
if (test_bit(wil_status_fwconnected, wil->status)) if (test_bit(wil_vif_fwconnected, vif->status))
/* connect succeeded after all */ /* connect succeeded after all */
return; return;
if (!test_bit(wil_status_fwconnecting, wil->status)) if (!test_bit(wil_vif_fwconnecting, vif->status))
/* already disconnected */ /* already disconnected */
return; 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), WMI_DISCONNECT_EVENTID, &reply, sizeof(reply),
WIL6210_DISCONNECT_TO_MS); WIL6210_DISCONNECT_TO_MS);
if (rc) { if (rc) {
@ -330,35 +350,11 @@ static void wil_disconnect_worker(struct work_struct *work)
return; return;
} }
wil_update_net_queues_bh(wil, NULL, true); wil_update_net_queues_bh(wil, vif, NULL, true);
netif_carrier_off(ndev); netif_carrier_off(ndev);
cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0, cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL); WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
clear_bit(wil_status_fwconnecting, wil->status); clear_bit(wil_vif_fwconnecting, vif->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);
} }
static int wil_wait_for_recovery(struct wil6210_priv *wil) 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, struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
fw_error_worker); fw_error_worker);
struct wireless_dev *wdev = wil->wdev; struct net_device *ndev = wil->main_ndev;
struct net_device *ndev = wil_to_ndev(wil); struct wireless_dev *wdev = ndev->ieee80211_ptr;
wil_dbg_misc(wil, "fw error worker\n"); 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"); wil_info(wil, "No recovery - interface is down\n");
return; return;
} }
@ -429,6 +425,10 @@ static void wil_fw_error_worker(struct work_struct *work)
return; return;
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
/* Needs adaptation for multiple VIFs
* need to go over all VIFs and consider the appropriate
* recovery.
*/
switch (wdev->iftype) { switch (wdev->iftype) {
case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT: case NL80211_IFTYPE_P2P_CLIENT:
@ -461,8 +461,9 @@ static int wil_find_free_vring(struct wil6210_priv *wil)
return -EINVAL; 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; int rc = -EINVAL, ringid;
if (cid < 0) { if (cid < 0) {
@ -475,21 +476,22 @@ int wil_tx_init(struct wil6210_priv *wil, int cid)
goto out; goto out;
} }
wil_dbg_wmi(wil, "Configure for connection CID %d vring %d\n", wil_dbg_wmi(wil, "Configure for connection CID %d MID %d vring %d\n",
cid, ringid); 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) if (rc)
wil_err(wil, "wil_vring_init_tx for CID %d vring %d failed\n", wil_err(wil, "init TX for CID %d MID %d vring %d failed\n",
cid, ringid); cid, vif->mid, ringid);
out: out:
return rc; 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) if ((ri >= 0) && wil->vring_tx[ri].va)
return 0; return 0;
@ -498,25 +500,38 @@ int wil_bcast_init(struct wil6210_priv *wil)
if (ri < 0) if (ri < 0)
return ri; return ri;
wil->bcast_vring = ri; vif->bcast_vring = ri;
rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order); rc = wil_vring_init_bcast(vif, ri, 1 << bcast_ring_order);
if (rc) if (rc)
wil->bcast_vring = -1; vif->bcast_vring = -1;
return rc; 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) if (ri < 0)
return; return;
wil->bcast_vring = -1; vif->bcast_vring = -1;
wil_vring_fini_tx(wil, ri); 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) int wil_priv_init(struct wil6210_priv *wil)
{ {
uint i; uint i;
@ -524,38 +539,29 @@ int wil_priv_init(struct wil6210_priv *wil)
wil_dbg_misc(wil, "priv_init\n"); wil_dbg_misc(wil, "priv_init\n");
memset(wil->sta, 0, sizeof(wil->sta)); 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); spin_lock_init(&wil->sta[i].tid_rx_lock);
wil->sta[i].mid = U8_MAX;
}
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) for (i = 0; i < WIL6210_MAX_TX_RINGS; i++)
spin_lock_init(&wil->vring_tx_data[i].lock); spin_lock_init(&wil->vring_tx_data[i].lock);
mutex_init(&wil->mutex); mutex_init(&wil->mutex);
mutex_init(&wil->vif_mutex);
mutex_init(&wil->wmi_mutex); mutex_init(&wil->wmi_mutex);
mutex_init(&wil->probe_client_mutex);
mutex_init(&wil->p2p_wdev_mutex);
mutex_init(&wil->halp.lock); mutex_init(&wil->halp.lock);
init_completion(&wil->wmi_ready); init_completion(&wil->wmi_ready);
init_completion(&wil->wmi_call); init_completion(&wil->wmi_call);
init_completion(&wil->halp.comp); 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->wmi_event_worker, wmi_event_worker);
INIT_WORK(&wil->fw_error_worker, wil_fw_error_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->pending_wmi_ev);
INIT_LIST_HEAD(&wil->probe_client_pending);
spin_lock_init(&wil->wmi_ev_lock); spin_lock_init(&wil->wmi_ev_lock);
spin_lock_init(&wil->net_queue_lock); spin_lock_init(&wil->net_queue_lock);
wil->net_queue_stopped = 1;
init_waitqueue_head(&wil->wq); init_waitqueue_head(&wil->wq);
wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi"); 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)); memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
wil->vring_idle_trsh = 16; wil->vring_idle_trsh = 16;
wil->reply_mid = U8_MAX;
wil->max_vifs = 1;
return 0; return 0;
out_wmi_wq: out_wmi_wq:
@ -600,7 +609,7 @@ void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps)
/** /**
* wil6210_disconnect - disconnect one connection * wil6210_disconnect - disconnect one connection
* @wil: driver context * @vif: virtual interface context
* @bssid: peer to disconnect, NULL to disconnect all * @bssid: peer to disconnect, NULL to disconnect all
* @reason_code: Reason code for the Disassociation frame * @reason_code: Reason code for the Disassociation frame
* @from_event: whether is invoked from FW event handler * @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 * Disconnect and release associated resources. If invoked not from the
* FW event handler, issue WMI command(s) to trigger MAC disconnect. * 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) u16 reason_code, bool from_event)
{ {
struct wil6210_priv *wil = vif_to_wil(vif);
wil_dbg_misc(wil, "disconnect\n"); wil_dbg_misc(wil, "disconnect\n");
del_timer_sync(&wil->connect_timer); del_timer_sync(&vif->connect_timer);
_wil6210_disconnect(wil, bssid, reason_code, from_event); _wil6210_disconnect(vif, bssid, reason_code, from_event);
} }
void wil_priv_deinit(struct wil6210_priv *wil) 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_dbg_misc(wil, "priv_deinit\n");
wil_set_recovery_state(wil, fw_recovery_idle); 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->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); wmi_event_flush(wil);
wil_probe_client_flush(wil);
cancel_work_sync(&wil->probe_client_worker);
destroy_workqueue(wil->wq_service); destroy_workqueue(wil->wq_service);
destroy_workqueue(wil->wmi_wq); 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, offsetof(struct bl_dedicated_registers_v0,
boot_loader_struct_version)); boot_loader_struct_version));
if (!tmp) { if (!tmp) {
wil_dbg_misc(wil, "old BL, skipping halt preperation\n"); wil_dbg_misc(wil, "old BL, skipping halt preparation\n");
return; 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) 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); struct wiphy *wiphy = wil_to_wiphy(wil);
union { union {
struct bl_dedicated_registers_v0 bl0; 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) 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); struct wiphy *wiphy = wil_to_wiphy(wil);
u8 mac[8]; u8 mac[8];
@ -1069,31 +1070,46 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
return 0; 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; int rc;
struct cfg80211_scan_info info = { struct cfg80211_scan_info info = {
.aborted = true, .aborted = true,
}; };
lockdep_assert_held(&wil->p2p_wdev_mutex); lockdep_assert_held(&wil->vif_mutex);
if (!wil->scan_request) if (!vif->scan_request)
return; return;
wil_dbg_misc(wil, "Abort scan_request 0x%p\n", wil->scan_request); wil_dbg_misc(wil, "Abort scan_request 0x%p\n", vif->scan_request);
del_timer_sync(&wil->scan_timer); del_timer_sync(&vif->scan_timer);
mutex_unlock(&wil->p2p_wdev_mutex); mutex_unlock(&wil->vif_mutex);
rc = wmi_abort_scan(wil); rc = wmi_abort_scan(vif);
if (!rc && sync) if (!rc && sync)
wait_event_interruptible_timeout(wil->wq, !wil->scan_request, wait_event_interruptible_timeout(wil->wq, !vif->scan_request,
msecs_to_jiffies( msecs_to_jiffies(
WAIT_FOR_SCAN_ABORT_MS)); WAIT_FOR_SCAN_ABORT_MS));
mutex_lock(&wil->p2p_wdev_mutex); mutex_lock(&wil->vif_mutex);
if (wil->scan_request) { if (vif->scan_request) {
cfg80211_scan_done(wil->scan_request, &info); cfg80211_scan_done(vif->scan_request, &info);
wil->scan_request = NULL; 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. * We reset all the structures, and we reset the UMAC.
* After calling this routine, you're expected to reload * 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 wil_reset(struct wil6210_priv *wil, bool load_fw)
{ {
int rc; int rc, i;
unsigned long status_flags = BIT(wil_status_resetting); unsigned long status_flags = BIT(wil_status_resetting);
int no_flash; int no_flash;
struct wil6210_vif *vif;
wil_dbg_misc(wil, "reset\n"); 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] = { static const u8 mac[ETH_ALEN] = {
0x00, 0xde, 0xad, 0x12, 0x34, 0x56, 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->perm_addr, mac);
ether_addr_copy(ndev->dev_addr, ndev->perm_addr); 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; goto out;
} }
cancel_work_sync(&wil->disconnect_worker); mutex_lock(&wil->vif_mutex);
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); wil_abort_scan_all_vifs(wil, false);
wil_bcast_fini(wil); 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*/ /* Disable device led before reset*/
wmi_led_cfg(wil, false); 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 */ /* prevent NAPI from being scheduled and prevent wmi commands */
mutex_lock(&wil->wmi_mutex); mutex_lock(&wil->wmi_mutex);
if (test_bit(wil_status_suspending, wil->status)) 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 */ /* init after reset */
wil->ap_isolate = 0;
reinit_completion(&wil->wmi_ready); reinit_completion(&wil->wmi_ready);
reinit_completion(&wil->wmi_call); reinit_completion(&wil->wmi_call);
reinit_completion(&wil->halp.comp); reinit_completion(&wil->halp.comp);
@ -1299,6 +1349,12 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
return rc; 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); wil_collect_fw_info(wil);
if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT) 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) int __wil_up(struct wil6210_priv *wil)
{ {
struct net_device *ndev = wil_to_ndev(wil); struct net_device *ndev = wil->main_ndev;
struct wireless_dev *wdev = wil->wdev; struct wireless_dev *wdev = ndev->ieee80211_ptr;
int rc; int rc;
WARN_ON(!mutex_is_locked(&wil->mutex)); WARN_ON(!mutex_is_locked(&wil->mutex));
@ -1420,10 +1476,10 @@ int __wil_down(struct wil6210_priv *wil)
} }
wil_enable_irq(wil); wil_enable_irq(wil);
mutex_lock(&wil->p2p_wdev_mutex); mutex_lock(&wil->vif_mutex);
wil_p2p_stop_radio_operations(wil); wil_p2p_stop_radio_operations(wil);
wil_abort_scan(wil, false); wil_abort_scan_all_vifs(wil, false);
mutex_unlock(&wil->p2p_wdev_mutex); mutex_unlock(&wil->vif_mutex);
return wil_reset(wil, false); return wil_reset(wil, false);
} }
@ -1442,13 +1498,14 @@ int wil_down(struct wil6210_priv *wil)
return rc; 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 i;
int rc = -ENOENT; int rc = -ENOENT;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { 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)) { ether_addr_equal(wil->sta[i].addr, mac)) {
rc = i; rc = i;
break; break;

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -15,13 +16,41 @@
*/ */
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
#include "wil6210.h" #include "wil6210.h"
#include "txrx.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) static int wil_open(struct net_device *ndev)
{ {
struct wil6210_priv *wil = ndev_to_wil(ndev); struct wil6210_priv *wil = ndev_to_wil(ndev);
int rc; int rc = 0;
wil_dbg_misc(wil, "open\n"); wil_dbg_misc(wil, "open\n");
@ -31,13 +60,16 @@ static int wil_open(struct net_device *ndev)
return -EINVAL; return -EINVAL;
} }
rc = wil_pm_runtime_get(wil); if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
if (rc < 0) wil_dbg_misc(wil, "open, first iface\n");
return rc; rc = wil_pm_runtime_get(wil);
if (rc < 0)
return rc;
rc = wil_up(wil); rc = wil_up(wil);
if (rc) if (rc)
wil_pm_runtime_put(wil); wil_pm_runtime_put(wil);
}
return rc; return rc;
} }
@ -45,13 +77,16 @@ static int wil_open(struct net_device *ndev)
static int wil_stop(struct net_device *ndev) static int wil_stop(struct net_device *ndev)
{ {
struct wil6210_priv *wil = ndev_to_wil(ndev); struct wil6210_priv *wil = ndev_to_wil(ndev);
int rc; int rc = 0;
wil_dbg_misc(wil, "stop\n"); wil_dbg_misc(wil, "stop\n");
rc = wil_down(wil); if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
if (!rc) wil_dbg_misc(wil, "stop, last iface\n");
wil_pm_runtime_put(wil); rc = wil_down(wil);
if (!rc)
wil_pm_runtime_put(wil);
}
return rc; 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++) { for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
struct vring *vring = &wil->vring_tx[i]; struct vring *vring = &wil->vring_tx[i];
struct vring_tx_data *txdata = &wil->vring_tx_data[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; 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) { if (tx_done < budget) {
@ -121,43 +164,136 @@ static void wil_dev_setup(struct net_device *dev)
dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT; 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)
{
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);
}
void wil_vif_free(struct wil6210_vif *vif)
{
struct net_device *ndev = vif_to_ndev(vif);
wil_vif_deinit(vif);
free_netdev(ndev);
}
static void wil_ndev_destructor(struct net_device *ndev)
{
struct wil6210_vif *vif = ndev_to_vif(ndev);
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;
}
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 net_device *ndev;
struct wireless_dev *wdev; struct wireless_dev *wdev;
struct wil6210_priv *wil; struct wil6210_vif *vif;
struct ieee80211_channel *ch; u8 mid;
int rc = 0;
wdev = wil_cfg80211_init(dev); mid = wil_vif_find_free_mid(wil);
if (IS_ERR(wdev)) { if (mid == U8_MAX) {
dev_err(dev, "wil_cfg80211_init failed\n"); wil_err(wil, "no available virtual interface\n");
return wdev; return ERR_PTR(-EINVAL);
} }
wil = wdev_to_wil(wdev); ndev = alloc_netdev(sizeof(*vif), name, name_assign_type,
wil->wdev = wdev; wil_dev_setup);
wil->radio_wdev = wdev;
wil_dbg_misc(wil, "if_alloc\n");
rc = wil_priv_init(wil);
if (rc) {
dev_err(dev, "wil_priv_init failed\n");
goto out_wdev;
}
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);
ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup);
if (!ndev) { if (!ndev) {
dev_err(dev, "alloc_netdev_mqs failed\n"); dev_err(wil_to_dev(wil), "alloc_netdev failed\n");
rc = -ENOMEM; return ERR_PTR(-ENOMEM);
goto out_priv;
} }
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; ndev->netdev_ops = &wil_netdev_ops;
wil_set_ethtoolops(ndev); wil_set_ethtoolops(ndev);
@ -170,21 +306,53 @@ void *wil_if_alloc(struct device *dev)
ndev->features |= ndev->hw_features; ndev->features |= ndev->hw_features;
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev; 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; return wil;
out_priv: out_priv:
wil_priv_deinit(wil); wil_priv_deinit(wil);
out_wdev: out_cfg:
wil_wdev_free(wil); wil_cfg80211_deinit(wil);
return ERR_PTR(rc); return ERR_PTR(rc);
} }
void wil_if_free(struct wil6210_priv *wil) 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"); wil_dbg_misc(wil, "if_free\n");
@ -193,17 +361,50 @@ void wil_if_free(struct wil6210_priv *wil)
wil_priv_deinit(wil); wil_priv_deinit(wil);
wil_to_ndev(wil) = NULL; wil->main_ndev = NULL;
wil_ndev_destructor(ndev);
free_netdev(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) int wil_if_add(struct wil6210_priv *wil)
{ {
struct wireless_dev *wdev = wil_to_wdev(wil); struct wiphy *wiphy = wil->wiphy;
struct wiphy *wiphy = wdev->wiphy; struct net_device *ndev = wil->main_ndev;
struct net_device *ndev = wil_to_ndev(wil); struct wil6210_vif *vif = ndev_to_vif(ndev);
int rc; int rc;
wil_dbg_misc(wil, "entered"); wil_dbg_misc(wil, "entered");
@ -216,33 +417,94 @@ int wil_if_add(struct wil6210_priv *wil)
return rc; 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); 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); WIL6210_NAPI_BUDGET);
wil_update_net_queues_bh(wil, NULL, true); wil_update_net_queues_bh(wil, vif, NULL, true);
rc = register_netdev(ndev); rtnl_lock();
if (rc < 0) { rc = wil_vif_add(wil, vif);
dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc); rtnl_unlock();
if (rc < 0)
goto out_wiphy; goto out_wiphy;
}
return 0; return 0;
out_wiphy: out_wiphy:
wiphy_unregister(wdev->wiphy); wiphy_unregister(wiphy);
return rc; 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) void wil_if_remove(struct wil6210_priv *wil)
{ {
struct net_device *ndev = wil_to_ndev(wil); struct net_device *ndev = wil->main_ndev;
struct wireless_dev *wdev = wil_to_wdev(wil); struct wireless_dev *wdev = ndev->ieee80211_ptr;
wil_dbg_misc(wil, "if_remove\n"); 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); wiphy_unregister(wdev->wiphy);
} }

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -22,27 +23,28 @@
#define P2P_SEARCH_DURATION_MS 500 #define P2P_SEARCH_DURATION_MS 500
#define P2P_DEFAULT_BI 100 #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; u8 channel = p2p->listen_chan.hw_value;
int rc; int rc;
lockdep_assert_held(&wil->mutex); 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) { if (rc) {
wil_err(wil, "wmi_p2p_cfg failed\n"); wil_err(wil, "wmi_p2p_cfg failed\n");
goto out; 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) { if (rc) {
wil_err(wil, "wmi_set_ssid failed\n"); wil_err(wil, "wmi_set_ssid failed\n");
goto out_stop; goto out_stop;
} }
rc = wmi_start_listen(wil); rc = wmi_start_listen(vif);
if (rc) { if (rc) {
wil_err(wil, "wmi_start_listen failed\n"); wil_err(wil, "wmi_start_listen failed\n");
goto out_stop; goto out_stop;
@ -53,7 +55,7 @@ static int wil_p2p_start_listen(struct wil6210_priv *wil)
jiffies + msecs_to_jiffies(p2p->listen_duration)); jiffies + msecs_to_jiffies(p2p->listen_duration));
out_stop: out_stop:
if (rc) if (rc)
wmi_stop_discovery(wil); wmi_stop_discovery(vif);
out: out:
return rc; 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); (request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
} }
void wil_p2p_discovery_timer_fn(struct timer_list *t) int wil_p2p_search(struct wil6210_vif *vif,
{
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,
struct cfg80211_scan_request *request) struct cfg80211_scan_request *request)
{ {
struct wil6210_priv *wil = vif_to_wil(vif);
int rc; 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); 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; 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) { if (rc) {
wil_err(wil, "wmi_p2p_cfg failed\n"); wil_err(wil, "wmi_p2p_cfg failed\n");
goto out; 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) { if (rc) {
wil_err(wil, "wmi_set_ssid failed\n"); wil_err(wil, "wmi_set_ssid failed\n");
goto out_stop; goto out_stop;
} }
/* Set application IE to probe request and probe response */ /* 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); request->ie_len, request->ie);
if (rc) { if (rc) {
wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n"); 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 - /* supplicant doesn't provide Probe Response IEs. As a workaround -
* re-use Probe Request IEs * 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); request->ie_len, request->ie);
if (rc) { if (rc) {
wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n"); wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
goto out_stop; goto out_stop;
} }
rc = wmi_start_search(wil); rc = wmi_start_search(vif);
if (rc) { if (rc) {
wil_err(wil, "wmi_start_search failed\n"); wil_err(wil, "wmi_start_search failed\n");
goto out_stop; goto out_stop;
@ -133,7 +127,7 @@ int wil_p2p_search(struct wil6210_priv *wil,
out_stop: out_stop:
if (rc) if (rc)
wmi_stop_discovery(wil); wmi_stop_discovery(vif);
out: out:
return rc; 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, unsigned int duration, struct ieee80211_channel *chan,
u64 *cookie) 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; int rc;
if (!chan) if (!chan)
@ -163,23 +158,24 @@ int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
*cookie = ++p2p->cookie; *cookie = ++p2p->cookie;
p2p->listen_duration = duration; p2p->listen_duration = duration;
mutex_lock(&wil->p2p_wdev_mutex); mutex_lock(&wil->vif_mutex);
if (wil->scan_request) { if (vif->scan_request) {
wil_dbg_misc(wil, "Delaying p2p listen until scan done\n"); wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
p2p->pending_listen_wdev = wdev; p2p->pending_listen_wdev = wdev;
p2p->discovery_started = 1; p2p->discovery_started = 1;
rc = 0; rc = 0;
mutex_unlock(&wil->p2p_wdev_mutex); mutex_unlock(&wil->vif_mutex);
goto out; 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) if (rc)
goto out; goto out;
p2p->discovery_started = 1; p2p->discovery_started = 1;
wil->radio_wdev = wdev; if (vif->mid == 0)
wil->radio_wdev = wdev;
cfg80211_ready_on_channel(wdev, *cookie, chan, duration, cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
GFP_KERNEL); GFP_KERNEL);
@ -189,9 +185,9 @@ int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
return rc; 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; u8 started = p2p->discovery_started;
if (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; p2p->pending_listen_wdev = NULL;
} else { } else {
del_timer_sync(&p2p->discovery_timer); del_timer_sync(&p2p->discovery_timer);
wmi_stop_discovery(wil); wmi_stop_discovery(vif);
} }
p2p->discovery_started = 0; p2p->discovery_started = 0;
} }
@ -208,9 +204,10 @@ u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
return started; 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; u8 started;
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
@ -222,7 +219,7 @@ int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
return -ENOENT; return -ENOENT;
} }
started = wil_p2p_stop_discovery(wil); started = wil_p2p_stop_discovery(vif);
mutex_unlock(&wil->mutex); mutex_unlock(&wil->mutex);
@ -231,13 +228,14 @@ int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
return -ENOENT; return -ENOENT;
} }
mutex_lock(&wil->p2p_wdev_mutex); mutex_lock(&wil->vif_mutex);
cfg80211_remain_on_channel_expired(wil->radio_wdev, cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
p2p->cookie, p2p->cookie,
&p2p->listen_chan, &p2p->listen_chan,
GFP_KERNEL); GFP_KERNEL);
wil->radio_wdev = wil->wdev; if (vif->mid == 0)
mutex_unlock(&wil->p2p_wdev_mutex); wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
mutex_unlock(&wil->vif_mutex);
return 0; 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 *p2p = container_of(work,
struct wil_p2p_info, discovery_expired_work); struct wil_p2p_info, discovery_expired_work);
struct wil6210_priv *wil = container_of(p2p, struct wil6210_vif *vif = container_of(p2p,
struct wil6210_priv, p2p); struct wil6210_vif, p2p);
struct wil6210_priv *wil = vif_to_wil(vif);
u8 started; u8 started;
wil_dbg_misc(wil, "p2p_listen_expired\n"); wil_dbg_misc(wil, "p2p_listen_expired\n");
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
started = wil_p2p_stop_discovery(wil); started = wil_p2p_stop_discovery(vif);
mutex_unlock(&wil->mutex); mutex_unlock(&wil->mutex);
if (started) { if (!started)
mutex_lock(&wil->p2p_wdev_mutex); return;
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);
}
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) void wil_p2p_search_expired(struct work_struct *work)
{ {
struct wil_p2p_info *p2p = container_of(work, struct wil_p2p_info *p2p = container_of(work,
struct wil_p2p_info, discovery_expired_work); struct wil_p2p_info, discovery_expired_work);
struct wil6210_priv *wil = container_of(p2p, struct wil6210_vif *vif = container_of(p2p,
struct wil6210_priv, p2p); struct wil6210_vif, p2p);
struct wil6210_priv *wil = vif_to_wil(vif);
u8 started; u8 started;
wil_dbg_misc(wil, "p2p_search_expired\n"); wil_dbg_misc(wil, "p2p_search_expired\n");
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
started = wil_p2p_stop_discovery(wil); started = wil_p2p_stop_discovery(vif);
mutex_unlock(&wil->mutex); mutex_unlock(&wil->mutex);
if (started) { if (started) {
@ -286,13 +287,15 @@ void wil_p2p_search_expired(struct work_struct *work)
.aborted = false, .aborted = false,
}; };
mutex_lock(&wil->p2p_wdev_mutex); mutex_lock(&wil->vif_mutex);
if (wil->scan_request) { if (vif->scan_request) {
cfg80211_scan_done(wil->scan_request, &info); cfg80211_scan_done(vif->scan_request, &info);
wil->scan_request = NULL; vif->scan_request = NULL;
wil->radio_wdev = wil->wdev; 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 *p2p = container_of(work,
struct wil_p2p_info, delayed_listen_work); struct wil_p2p_info, delayed_listen_work);
struct wil6210_priv *wil = container_of(p2p, struct wil6210_vif *vif = container_of(p2p,
struct wil6210_priv, p2p); struct wil6210_vif, p2p);
struct wil6210_priv *wil = vif_to_wil(vif);
int rc; int rc;
mutex_lock(&wil->mutex); 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) if (!p2p->discovery_started || !p2p->pending_listen_wdev)
goto out; goto out;
mutex_lock(&wil->p2p_wdev_mutex); mutex_lock(&wil->vif_mutex);
if (wil->scan_request) { if (vif->scan_request) {
/* another scan started, wait again... */ /* another scan started, wait again... */
mutex_unlock(&wil->p2p_wdev_mutex); mutex_unlock(&wil->vif_mutex);
goto out; 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) { if (rc) {
cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev, cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
p2p->cookie, p2p->cookie,
&p2p->listen_chan, &p2p->listen_chan,
GFP_KERNEL); GFP_KERNEL);
wil->radio_wdev = wil->wdev; if (vif->mid == 0)
wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
} else { } else {
cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie, cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
&p2p->listen_chan, &p2p->listen_chan,
p2p->listen_duration, GFP_KERNEL); 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; p2p->pending_listen_wdev = NULL;
mutex_unlock(&wil->p2p_wdev_mutex); mutex_unlock(&wil->vif_mutex);
out: out:
mutex_unlock(&wil->mutex); mutex_unlock(&wil->mutex);
@ -342,34 +348,35 @@ void wil_p2p_delayed_listen_work(struct work_struct *work)
void wil_p2p_stop_radio_operations(struct wil6210_priv *wil) 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 = { struct cfg80211_scan_info info = {
.aborted = true, .aborted = true,
}; };
lockdep_assert_held(&wil->mutex); 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) if (wil->radio_wdev != wil->p2p_wdev)
goto out; goto out;
if (!p2p->discovery_started) { if (!p2p->discovery_started) {
/* Regular scan on the p2p device */ /* Regular scan on the p2p device */
if (wil->scan_request && if (vif->scan_request &&
wil->scan_request->wdev == wil->p2p_wdev) vif->scan_request->wdev == wil->p2p_wdev)
wil_abort_scan(wil, true); wil_abort_scan(vif, true);
goto out; goto out;
} }
/* Search or listen on p2p device */ /* Search or listen on p2p device */
mutex_unlock(&wil->p2p_wdev_mutex); mutex_unlock(&wil->vif_mutex);
wil_p2p_stop_discovery(wil); wil_p2p_stop_discovery(vif);
mutex_lock(&wil->p2p_wdev_mutex); mutex_lock(&wil->vif_mutex);
if (wil->scan_request) { if (vif->scan_request) {
/* search */ /* search */
cfg80211_scan_done(wil->scan_request, &info); cfg80211_scan_done(vif->scan_request, &info);
wil->scan_request = NULL; vif->scan_request = NULL;
} else { } else {
/* listen */ /* listen */
cfg80211_remain_on_channel_expired(wil->radio_wdev, cfg80211_remain_on_channel_expired(wil->radio_wdev,
@ -379,5 +386,5 @@ void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
} }
out: out:
wil->radio_wdev = wil->wdev; wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
} }

View File

@ -137,6 +137,20 @@ void wil_enable_irq(struct wil6210_priv *wil)
enable_irq(wil->pdev->irq); 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 */ /* Bus ops */
static int wil_if_pcie_enable(struct wil6210_priv *wil) 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; int msi_only = pdev->msi_enabled;
bool _use_msi = use_msi; 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); pci_set_master(pdev);
@ -172,11 +184,9 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
if (rc) if (rc)
goto stop_master; goto stop_master;
/* need reset here to obtain MAC or in case of WMI-only FW, full reset /* need reset here to obtain MAC */
* and fw loading takes place
*/
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
rc = wil_reset(wil, wmi_only); rc = wil_reset(wil, false);
mutex_unlock(&wil->mutex); mutex_unlock(&wil->mutex);
if (rc) if (rc)
goto release_irq; 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; 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)) if (IS_ENABLED(CONFIG_PM))
wil->pm_notify.notifier_call = wil6210_pm_notify; 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; return 0;
if_remove:
wil_if_remove(wil);
bus_disable: bus_disable:
wil_if_pcie_disable(wil); wil_if_pcie_disable(wil);
err_iounmap: err_iounmap:
@ -402,6 +426,7 @@ static void wil_pcie_remove(struct pci_dev *pdev)
wil6210_debugfs_remove(wil); wil6210_debugfs_remove(wil);
rtnl_lock(); rtnl_lock();
wil_p2p_wdev_free(wil); wil_p2p_wdev_free(wil);
wil_remove_all_additional_vifs(wil);
rtnl_unlock(); rtnl_unlock();
wil_if_remove(wil); wil_if_remove(wil);
wil_if_pcie_disable(wil); wil_if_pcie_disable(wil);
@ -425,12 +450,15 @@ static int wil6210_suspend(struct device *dev, bool is_runtime)
int rc = 0; int rc = 0;
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct wil6210_priv *wil = pci_get_drvdata(pdev); struct wil6210_priv *wil = pci_get_drvdata(pdev);
struct net_device *ndev = wil_to_ndev(wil); bool keep_radio_on, active_ifaces;
bool keep_radio_on = ndev->flags & IFF_UP &&
wil->keep_radio_on_during_sleep;
wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); 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); rc = wil_can_suspend(wil, is_runtime);
if (rc) if (rc)
goto out; goto out;
@ -457,12 +485,15 @@ static int wil6210_resume(struct device *dev, bool is_runtime)
int rc = 0; int rc = 0;
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct wil6210_priv *wil = pci_get_drvdata(pdev); struct wil6210_priv *wil = pci_get_drvdata(pdev);
struct net_device *ndev = wil_to_ndev(wil); bool keep_radio_on, active_ifaces;
bool keep_radio_on = ndev->flags & IFF_UP &&
wil->keep_radio_on_during_sleep;
wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); 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 /* In case radio stays on, platform device will control
* PCIe master * PCIe master
*/ */

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2014,2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
@ -20,13 +21,72 @@
#define WIL6210_AUTOSUSPEND_DELAY_MS (1000) #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 wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
{ {
int rc = 0; int rc = 0, i;
struct wireless_dev *wdev = wil->wdev;
struct net_device *ndev = wil_to_ndev(wil);
bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY, bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
wil->fw_capabilities); wil->fw_capabilities);
bool active_ifaces;
wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system"); 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; rc = -EBUSY;
goto out; 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 */ /* can always sleep when down */
wil_dbg_pm(wil, "Interface is down\n"); wil_dbg_pm(wil, "Interface is down\n");
goto out; goto out;
@ -57,32 +122,19 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
} }
/* interface is running */ /* interface is running */
switch (wdev->iftype) { mutex_lock(&wil->vif_mutex);
case NL80211_IFTYPE_MONITOR: for (i = 0; i < wil->max_vifs; i++) {
wil_dbg_pm(wil, "Sniffer\n"); struct wil6210_vif *vif = wil->vifs[i];
rc = -EBUSY;
goto out; if (!vif)
/* for STA-like interface, don't runtime suspend */ continue;
case NL80211_IFTYPE_STATION: if (!wil_can_suspend_vif(wil, vif, is_runtime)) {
case NL80211_IFTYPE_P2P_CLIENT:
if (test_bit(wil_status_fwconnecting, wil->status)) {
wil_dbg_pm(wil, "Delay suspend when connecting\n");
rc = -EBUSY; rc = -EBUSY;
mutex_unlock(&wil->vif_mutex);
goto out; goto out;
} }
/* Runtime pm not supported in case the interface is up */
if (is_runtime) {
wil_dbg_pm(wil, "STA-like interface\n");
rc = -EBUSY;
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: out:
wil_dbg_pm(wil, "can_suspend: %s => %s (%d)\n", 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 */ /* Wake all queues */
if (test_bit(wil_status_fwconnected, wil->status)) wil_pm_wake_connected_net_queues(wil);
wil_update_net_queues_bh(wil, NULL, false);
out: out:
if (rc) if (rc)
@ -152,7 +203,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
wil->suspend_stats.rejected_by_host++; wil->suspend_stats.rejected_by_host++;
return -EBUSY; return -EBUSY;
} }
wil_update_net_queues_bh(wil, NULL, true); wil_pm_stop_all_net_queues(wil);
if (!wil_is_tx_idle(wil)) { if (!wil_is_tx_idle(wil)) {
wil_dbg_pm(wil, "Pending TX data, reject suspend\n"); wil_dbg_pm(wil, "Pending TX data, reject suspend\n");
@ -243,22 +294,20 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
/* if resume succeeded, reject the suspend */ /* if resume succeeded, reject the suspend */
if (!rc) { if (!rc) {
rc = -EBUSY; rc = -EBUSY;
if (test_bit(wil_status_fwconnected, wil->status)) wil_pm_wake_connected_net_queues(wil);
wil_update_net_queues_bh(wil, NULL, false);
} }
return rc; return rc;
reject_suspend: reject_suspend:
clear_bit(wil_status_suspending, wil->status); clear_bit(wil_status_suspending, wil->status);
if (test_bit(wil_status_fwconnected, wil->status)) wil_pm_wake_connected_net_queues(wil);
wil_update_net_queues_bh(wil, NULL, false);
return -EBUSY; return -EBUSY;
} }
static int wil_suspend_radio_off(struct wil6210_priv *wil) static int wil_suspend_radio_off(struct wil6210_priv *wil)
{ {
int rc = 0; int rc = 0;
struct net_device *ndev = wil_to_ndev(wil); bool active_ifaces;
wil_dbg_pm(wil, "suspend radio off\n"); 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 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); rc = wil_down(wil);
if (rc) { if (rc) {
wil_err(wil, "wil_down : %d\n", rc); wil_err(wil, "wil_down : %d\n", rc);
@ -306,16 +359,19 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)
static int wil_resume_radio_off(struct wil6210_priv *wil) static int wil_resume_radio_off(struct wil6210_priv *wil)
{ {
int rc = 0; int rc = 0;
struct net_device *ndev = wil_to_ndev(wil); bool active_ifaces;
wil_dbg_pm(wil, "Enabling PCIe IRQ\n"); wil_dbg_pm(wil, "Enabling PCIe IRQ\n");
wil_enable_irq(wil); 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 * During open(), IFF_UP set after actual device method
* invocation. This prevent recursive call to wil_up() * invocation. This prevent recursive call to wil_up()
* wil_status_suspended will be cleared in wil_reset * 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); rc = wil_up(wil);
else else
clear_bit(wil_status_suspended, wil->status); clear_bit(wil_status_suspended, wil->status);

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2012-2015,2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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; u32 i;
struct pmc_ctx *pmc = &wil->pmc; struct pmc_ctx *pmc = &wil->pmc;
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_pmc_cmd pmc_cmd = {0}; struct wmi_pmc_cmd pmc_cmd = {0};
int last_cmd_err = -ENOMEM; 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"); wil_dbg_misc(wil, "pmc_alloc: send WMI_PMC_CMD with ALLOCATE op\n");
pmc->last_cmd_status = wmi_send(wil, pmc->last_cmd_status = wmi_send(wil,
WMI_PMC_CMDID, WMI_PMC_CMDID,
vif->mid,
&pmc_cmd, &pmc_cmd,
sizeof(pmc_cmd)); sizeof(pmc_cmd));
if (pmc->last_cmd_status) { 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 pmc_ctx *pmc = &wil->pmc;
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_pmc_cmd pmc_cmd = {0}; struct wmi_pmc_cmd pmc_cmd = {0};
mutex_lock(&pmc->lock); 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"); wil_dbg_misc(wil, "send WMI_PMC_CMD with RELEASE op\n");
pmc_cmd.op = WMI_PMC_RELEASE; pmc_cmd.op = WMI_PMC_RELEASE;
pmc->last_cmd_status = pmc->last_cmd_status =
wmi_send(wil, WMI_PMC_CMDID, &pmc_cmd, wmi_send(wil, WMI_PMC_CMDID, vif->mid,
sizeof(pmc_cmd)); &pmc_cmd, sizeof(pmc_cmd));
if (pmc->last_cmd_status) { if (pmc->last_cmd_status) {
wil_err(wil, wil_err(wil,
"WMI_PMC_CMD with RELEASE op failed, status %d", "WMI_PMC_CMD with RELEASE op failed, status %d",

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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; 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, struct wil_tid_ampdu_rx *r,
int index) int index)
{ {
struct net_device *ndev = wil_to_ndev(wil);
struct sk_buff *skb = r->reorder_buf[index]; struct sk_buff *skb = r->reorder_buf[index];
if (!skb) if (!skb)
@ -59,7 +59,7 @@ static void wil_release_reorder_frame(struct wil6210_priv *wil,
r->head_seq_num = seq_inc(r->head_seq_num); 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, struct wil_tid_ampdu_rx *r,
u16 hseq) 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) { while (seq_less(r->head_seq_num, hseq) && r->stored_mpdu_num) {
index = reorder_index(r, r->head_seq_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; 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) struct wil_tid_ampdu_rx *r)
{ {
int index = reorder_index(r, r->head_seq_num); int index = reorder_index(r, r->head_seq_num);
while (r->reorder_buf[index]) { 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); 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) void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) __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); struct vring_rx_desc *d = wil_skb_rxdesc(skb);
int tid = wil_rxdesc_tid(d); int tid = wil_rxdesc_tid(d);
int cid = wil_rxdesc_cid(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", wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n",
mid, cid, tid, seq, mcast); 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)) { if (unlikely(mcast)) {
wil_netif_rx_any(skb, ndev); wil_netif_rx_any(skb, ndev);
return; 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)) { if (!seq_less(seq, r->head_seq_num + r->buf_size)) {
hseq = seq_inc(seq_sub(seq, r->buf_size)); hseq = seq_inc(seq_sub(seq, r->buf_size));
/* release stored frames up to new head to stack */ /* 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 */ /* 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_buf[index] = skb;
r->reorder_time[index] = jiffies; r->reorder_time[index] = jiffies;
r->stored_mpdu_num++; r->stored_mpdu_num++;
wil_reorder_release(wil, r); wil_reorder_release(ndev, r);
out: out:
spin_unlock(&sta->tid_rx_lock); spin_unlock(&sta->tid_rx_lock);
} }
/* process BAR frame, called in NAPI context */ /* 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 wil_sta_info *sta = &wil->sta[cid];
struct net_device *ndev = vif_to_ndev(vif);
struct wil_tid_ampdu_rx *r; struct wil_tid_ampdu_rx *r;
spin_lock(&sta->tid_rx_lock); 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); seq, r->head_seq_num);
goto out; goto out;
} }
wil_dbg_txrx(wil, "BAR: CID %d TID %d Seq 0x%03x head 0x%03x\n", wil_dbg_txrx(wil, "BAR: CID %d MID %d TID %d Seq 0x%03x head 0x%03x\n",
cid, tid, seq, r->head_seq_num); cid, vif->mid, tid, seq, r->head_seq_num);
wil_release_reorder_frames(wil, r, seq); wil_release_reorder_frames(ndev, r, seq);
out: out:
spin_unlock(&sta->tid_rx_lock); 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) */ /* Block Ack - Rx side (recipient) */
int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid,
u8 dialog_token, __le16 ba_param_set, u8 cidxtid, u8 dialog_token, __le16 ba_param_set,
__le16 ba_timeout, __le16 ba_seq_ctrl) __le16 ba_timeout, __le16 ba_seq_ctrl)
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock) __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); agg_amsdu, agg_wsize, agg_timeout);
if (rc || (status != WLAN_STATUS_SUCCESS)) { if (rc || (status != WLAN_STATUS_SUCCESS)) {
wil_err(wil, "do not apply ba, rc(%d), status(%d)\n", rc, 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; goto out;
} }
txdata->addba_in_progress = true; 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) { if (rc) {
wil_err(wil, "wmi_addba failed, rc (%d)", rc); wil_err(wil, "wmi_addba failed, rc (%d)", rc);
txdata->addba_in_progress = false; txdata->addba_in_progress = false;

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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 vring *vring)
{ {
struct device *dev = wil_to_dev(wil); 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; volatile struct vring_rx_desc *_d;
struct vring_rx_desc *d; struct vring_rx_desc *d;
struct sk_buff *skb; 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; unsigned int sz = wil->rx_buf_len + ETH_HLEN + snaplen;
u16 dmalen; u16 dmalen;
u8 ftype; u8 ftype;
int cid; int cid, mid;
int i; int i;
struct wil_net_stats *stats; struct wil_net_stats *stats;
@ -520,6 +522,16 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
(const void *)d, sizeof(*d), false); (const void *)d, sizeof(*d), false);
cid = wil_rxdesc_cid(d); 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; stats = &wil->sta[cid].stats;
if (unlikely(dmalen > sz)) { if (unlikely(dmalen > sz)) {
@ -553,7 +565,6 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
ftype = wil_rxdesc_ftype(d) << 2; ftype = wil_rxdesc_ftype(d) << 2;
if (unlikely(ftype != IEEE80211_FTYPE_DATA)) { if (unlikely(ftype != IEEE80211_FTYPE_DATA)) {
u8 fc1 = wil_rxdesc_fc1(d); u8 fc1 = wil_rxdesc_fc1(d);
int mid = wil_rxdesc_mid(d);
int tid = wil_rxdesc_tid(d); int tid = wil_rxdesc_tid(d);
u16 seq = wil_rxdesc_seq(d); u16 seq = wil_rxdesc_seq(d);
@ -565,7 +576,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
wil_dbg_txrx(wil, wil_dbg_txrx(wil,
"BAR: MID %d CID %d TID %d Seq 0x%03x\n", "BAR: MID %d CID %d TID %d Seq 0x%03x\n",
mid, cid, tid, seq); mid, cid, tid, seq);
wil_rx_bar(wil, cid, tid, seq); wil_rx_bar(wil, vif, cid, tid, seq);
} else { } else {
/* print again all info. One can enable only this /* print again all info. One can enable only this
* without overhead for printing every Rx frame * without overhead for printing every Rx frame
@ -621,10 +632,15 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
/** /**
* allocate and fill up to @count buffers in rx ring * allocate and fill up to @count buffers in rx ring
* buffers posted at @swtail * 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) 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; struct vring *v = &wil->vring_rx;
u32 next_tail; u32 next_tail;
int rc = 0; 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) void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
{ {
gro_result_t rc = GRO_NORMAL; gro_result_t rc = GRO_NORMAL;
struct wil6210_vif *vif = ndev_to_vif(ndev);
struct wil6210_priv *wil = ndev_to_wil(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; unsigned int len = skb->len;
struct vring_rx_desc *d = wil_skb_rxdesc(skb); struct vring_rx_desc *d = wil_skb_rxdesc(skb);
int cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */ 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; goto stats;
} }
if (wdev->iftype == NL80211_IFTYPE_AP && !wil->ap_isolate) { if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) {
if (mcast) { if (mcast) {
/* send multicast frames both to higher layers in /* send multicast frames both to higher layers in
* local net stack and back to the wireless medium * local net stack and back to the wireless medium
*/ */
xmit_skb = skb_copy(skb, GFP_ATOMIC); xmit_skb = skb_copy(skb, GFP_ATOMIC);
} else { } 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) { if (xmit_cid >= 0) {
/* The destination station is associated to /* 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 */ if (skb) { /* deliver to local stack */
skb->protocol = eth_type_trans(skb, ndev); skb->protocol = eth_type_trans(skb, ndev);
skb->dev = ndev;
rc = napi_gro_receive(&wil->napi_rx, skb); rc = napi_gro_receive(&wil->napi_rx, skb);
wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n", wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n",
len, gro_res_str[rc]); len, gro_res_str[rc]);
@ -815,7 +833,8 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
*/ */
void wil_rx_handle(struct wil6210_priv *wil, int *quota) 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 vring *v = &wil->vring_rx;
struct sk_buff *skb; 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)))) { while ((*quota > 0) && (NULL != (skb = wil_vring_reap_rx(wil, v)))) {
(*quota)--; (*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->dev = ndev;
skb_reset_mac_header(skb); skb_reset_mac_header(skb);
skb->ip_summed = CHECKSUM_UNNECESSARY; 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_timeout = 0;
txdata->agg_amsdu = 0; txdata->agg_amsdu = 0;
txdata->addba_in_progress = false; txdata->addba_in_progress = false;
txdata->mid = U8_MAX;
spin_unlock_bh(&txdata->lock); 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) int cid, int tid)
{ {
struct wil6210_priv *wil = vif_to_wil(vif);
int rc; int rc;
struct wmi_vring_cfg_cmd cmd = { struct wmi_vring_cfg_cmd cmd = {
.action = cpu_to_le32(WMI_VRING_CMD_ADD), .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); cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
if (!wil->privacy) if (!vif->privacy)
txdata->dot1x_open = true; 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); WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
if (rc) if (rc)
goto out_free; 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); spin_lock_bh(&txdata->lock);
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
txdata->mid = vif->mid;
txdata->enabled = 1; txdata->enabled = 1;
spin_unlock_bh(&txdata->lock); spin_unlock_bh(&txdata->lock);
@ -1003,8 +1026,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
return rc; 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; int rc;
struct wmi_bcast_vring_cfg_cmd cmd = { struct wmi_bcast_vring_cfg_cmd cmd = {
.action = cpu_to_le32(WMI_VRING_CMD_ADD), .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); cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
if (!wil->privacy) if (!vif->privacy)
txdata->dot1x_open = true; 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); WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
if (rc) if (rc)
goto out_free; 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); spin_lock_bh(&txdata->lock);
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr); vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
txdata->mid = vif->mid;
txdata->enabled = 1; txdata->enabled = 1;
spin_unlock_bh(&txdata->lock); 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); spin_lock_bh(&txdata->lock);
txdata->dot1x_open = false; txdata->dot1x_open = false;
txdata->mid = U8_MAX;
txdata->enabled = 0; /* no Tx can be in progress or start anew */ txdata->enabled = 0; /* no Tx can be in progress or start anew */
spin_unlock_bh(&txdata->lock); spin_unlock_bh(&txdata->lock);
/* napi_synchronize waits for completion of the current NAPI but will /* 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, static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
struct wil6210_vif *vif,
struct sk_buff *skb) struct sk_buff *skb)
{ {
int i; int i;
struct ethhdr *eth = (void *)skb->data; 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) if (cid < 0)
return NULL; return NULL;
@ -1142,10 +1170,11 @@ static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
return NULL; return NULL;
} }
static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif,
struct sk_buff *skb); struct vring *vring, struct sk_buff *skb);
static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil, static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
struct wil6210_vif *vif,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct vring *v; 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++) { for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
v = &wil->vring_tx[i]; v = &wil->vring_tx[i];
txdata = &wil->vring_tx_data[i]; txdata = &wil->vring_tx_data[i];
if (!v->va || !txdata->enabled) if (!v->va || !txdata->enabled || txdata->mid != vif->mid)
continue; continue;
cid = wil->vring2cid_tid[i][0]; cid = wil->vring2cid_tid[i][0];
@ -1193,11 +1222,12 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
* - for PBSS * - for PBSS
*/ */
static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil, static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
struct wil6210_vif *vif,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct vring *v; struct vring *v;
struct vring_tx_data *txdata; struct vring_tx_data *txdata;
int i = wil->bcast_vring; int i = vif->bcast_vring;
if (i < 0) if (i < 0)
return NULL; 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, static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
struct wil6210_vif *vif,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct vring *v, *v2; struct vring *v, *v2;
@ -1230,13 +1261,13 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
u8 cid; u8 cid;
struct ethhdr *eth = (void *)skb->data; struct ethhdr *eth = (void *)skb->data;
char *src = eth->h_source; char *src = eth->h_source;
struct vring_tx_data *txdata; struct vring_tx_data *txdata, *txdata2;
/* find 1-st vring eligible for data */ /* find 1-st vring eligible for data */
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) { for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
v = &wil->vring_tx[i]; v = &wil->vring_tx[i];
txdata = &wil->vring_tx_data[i]; txdata = &wil->vring_tx_data[i];
if (!v->va || !txdata->enabled) if (!v->va || !txdata->enabled || txdata->mid != vif->mid)
continue; continue;
cid = wil->vring2cid_tid[i][0]; cid = wil->vring2cid_tid[i][0];
@ -1264,7 +1295,8 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
/* find other active vrings and duplicate skb for each */ /* find other active vrings and duplicate skb for each */
for (i++; i < WIL6210_MAX_TX_RINGS; i++) { for (i++; i < WIL6210_MAX_TX_RINGS; i++) {
v2 = &wil->vring_tx[i]; v2 = &wil->vring_tx[i];
if (!v2->va) txdata2 = &wil->vring_tx_data[i];
if (!v2->va || txdata2->mid != vif->mid)
continue; continue;
cid = wil->vring2cid_tid[i][0]; cid = wil->vring2cid_tid[i][0];
if (cid >= WIL6210_MAX_CID) /* skip BCAST */ if (cid >= WIL6210_MAX_CID) /* skip BCAST */
@ -1280,7 +1312,7 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
if (skb2) { if (skb2) {
wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i); wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i);
wil_set_da_for_vring(wil, skb2, i); wil_set_da_for_vring(wil, skb2, i);
wil_tx_vring(wil, v2, skb2); wil_tx_vring(wil, vif, v2, skb2);
} else { } else {
wil_err(wil, "skb_copy failed\n"); 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; DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS;
} }
static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring, static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif,
struct sk_buff *skb) struct vring *vring, struct sk_buff *skb)
{ {
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
@ -1710,8 +1742,8 @@ static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
return rc; return rc;
} }
static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, static int __wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif,
struct sk_buff *skb) struct vring *vring, struct sk_buff *skb)
{ {
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
struct vring_tx_desc dd, *d = &dd; struct vring_tx_desc dd, *d = &dd;
@ -1725,7 +1757,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
uint i = swhead; uint i = swhead;
dma_addr_t pa; dma_addr_t pa;
int used; int used;
bool mcast = (vring_index == wil->bcast_vring); bool mcast = (vring_index == vif->bcast_vring);
uint len = skb_headlen(skb); uint len = skb_headlen(skb);
wil_dbg_txrx(wil, "tx_vring: %d bytes to vring %d\n", skb->len, 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; return -EINVAL;
} }
static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring, static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif,
struct sk_buff *skb) struct vring *vring, struct sk_buff *skb)
{ {
int vring_index = vring - wil->vring_tx; int vring_index = vring - wil->vring_tx;
struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index]; 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) rc = (skb_is_gso(skb) ? __wil_tx_vring_tso : __wil_tx_vring)
(wil, vring, skb); (wil, vif, vring, skb);
spin_unlock(&txdata->lock); 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 * 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: * This function does one of two checks:
* In case check_stop is true, will check if net queues need to be stopped. If * 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. * availability and modified vring has high descriptor availability.
*/ */
static inline void __wil_update_net_queues(struct wil6210_priv *wil, static inline void __wil_update_net_queues(struct wil6210_priv *wil,
struct wil6210_vif *vif,
struct vring *vring, struct vring *vring,
bool check_stop) bool check_stop)
{ {
int i; int i;
if (vring) if (unlikely(!vif))
wil_dbg_txrx(wil, "vring %d, check_stop=%d, stopped=%d", return;
(int)(vring - wil->vring_tx), check_stop,
wil->net_queue_stopped);
else
wil_dbg_txrx(wil, "check_stop=%d, stopped=%d",
check_stop, wil->net_queue_stopped);
if (check_stop == wil->net_queue_stopped) if (vring)
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, mid=%d, stopped=%d",
check_stop, vif->mid, vif->net_queue_stopped);
if (check_stop == vif->net_queue_stopped)
/* net queues already in desired state */ /* net queues already in desired state */
return; return;
if (check_stop) { if (check_stop) {
if (!vring || unlikely(wil_vring_avail_low(vring))) { if (!vring || unlikely(wil_vring_avail_low(vring))) {
/* not enough room in the vring */ /* not enough room in the vring */
netif_tx_stop_all_queues(wil_to_ndev(wil)); netif_tx_stop_all_queues(vif_to_ndev(vif));
wil->net_queue_stopped = true; vif->net_queue_stopped = true;
wil_dbg_txrx(wil, "netif_tx_stop called\n"); wil_dbg_txrx(wil, "netif_tx_stop called\n");
} }
return; 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 *cur_vring = &wil->vring_tx[i];
struct vring_tx_data *txdata = &wil->vring_tx_data[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; continue;
if (wil_vring_avail_low(cur_vring)) { 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)) { if (!vring || wil_vring_avail_high(vring)) {
/* enough room in the vring */ /* enough room in the vring */
wil_dbg_txrx(wil, "calling netif_tx_wake\n"); wil_dbg_txrx(wil, "calling netif_tx_wake\n");
netif_tx_wake_all_queues(wil_to_ndev(wil)); netif_tx_wake_all_queues(vif_to_ndev(vif));
wil->net_queue_stopped = false; vif->net_queue_stopped = false;
} }
} }
void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring, void wil_update_net_queues(struct wil6210_priv *wil, struct wil6210_vif *vif,
bool check_stop) struct vring *vring, bool check_stop)
{ {
spin_lock(&wil->net_queue_lock); 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); spin_unlock(&wil->net_queue_lock);
} }
void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring, void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif,
bool check_stop) struct vring *vring, bool check_stop)
{ {
spin_lock_bh(&wil->net_queue_lock); 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); spin_unlock_bh(&wil->net_queue_lock);
} }
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) 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; struct ethhdr *eth = (void *)skb->data;
bool bcast = is_multicast_ether_addr(eth->h_dest); bool bcast = is_multicast_ether_addr(eth->h_dest);
struct vring *vring; struct vring *vring;
@ -1991,49 +2030,50 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
} }
goto drop; goto drop;
} }
if (unlikely(!test_bit(wil_status_fwconnected, wil->status))) { if (unlikely(!test_bit(wil_vif_fwconnected, vif->status))) {
wil_dbg_ratelimited(wil, "FW not connected, packet dropped\n"); wil_dbg_ratelimited(wil,
"VIF not connected, packet dropped\n");
goto drop; 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"); wil_err(wil, "Xmit in monitor mode not supported\n");
goto drop; goto drop;
} }
pr_once_fw = false; pr_once_fw = false;
/* find vring */ /* 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) */ /* 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) { } else if (bcast) {
if (wil->pbss) if (vif->pbss)
/* in pbss, no bcast VRING - duplicate skb in /* in pbss, no bcast VRING - duplicate skb in
* all stations VRINGs * all stations VRINGs
*/ */
vring = wil_find_tx_bcast_2(wil, skb); vring = wil_find_tx_bcast_2(wil, vif, skb);
else if (wil->wdev->iftype == NL80211_IFTYPE_AP) else if (vif->wdev.iftype == NL80211_IFTYPE_AP)
/* AP has a dedicated bcast VRING */ /* AP has a dedicated bcast VRING */
vring = wil_find_tx_bcast_1(wil, skb); vring = wil_find_tx_bcast_1(wil, vif, skb);
else else
/* unexpected combination, fallback to duplicating /* unexpected combination, fallback to duplicating
* the skb in all stations VRINGs * the skb in all stations VRINGs
*/ */
vring = wil_find_tx_bcast_2(wil, skb); vring = wil_find_tx_bcast_2(wil, vif, skb);
} else { } else {
/* unicast, find specific VRING by dest. address */ /* 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)) { if (unlikely(!vring)) {
wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest); wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest);
goto drop; goto drop;
} }
/* set up vring entry */ /* set up vring entry */
rc = wil_tx_vring(wil, vring, skb); rc = wil_tx_vring(wil, vif, vring, skb);
switch (rc) { switch (rc) {
case 0: case 0:
/* shall we stop net queues? */ /* 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 */ /* statistics will be updated on the tx_complete */
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
return NETDEV_TX_OK; 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 * 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 device *dev = wil_to_dev(wil);
struct vring *vring = &wil->vring_tx[ringid]; struct vring *vring = &wil->vring_tx[ringid];
struct vring_tx_data *txdata = &wil->vring_tx_data[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? */ /* shall we wake net queues? */
if (done) if (done)
wil_update_net_queues(wil, vring, false); wil_update_net_queues(wil, vif, vring, false);
return done; return done;
} }

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * 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 * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * 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] * [dword 1]
* bit 0.. 3 : pkt_mode:4 * bit 0.. 3 : pkt_mode:4
* bit 4 : pkt_mode_en:1 * 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 15 : ack_policy_en:1
* bit 16..19 : dst_index:4 * bit 16..19 : dst_index:4
* bit 20 : dst_index_en:1 * 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_LEN 1
#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10 #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_POS 15
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1 #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000 #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 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. * 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 * 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 8.. 9 : mid:2 The MAC virtual number
* bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type * bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type
* (management, data, control and extension) * (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_EOP BIT(8)
#define RX_DMA_D0_CMD_DMA_RT BIT(9) /* always 1 */ #define RX_DMA_D0_CMD_DMA_RT BIT(9) /* always 1 */
#define RX_DMA_D0_CMD_DMA_IT BIT(10) /* interrupt */ #define RX_DMA_D0_CMD_DMA_IT BIT(10) /* interrupt */
#define RX_MAC_D0_MAC_ID_VALID BIT(7)
/* Error field */ /* Error field */
#define RX_DMA_ERROR_FCS BIT(0) #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) 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) 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_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_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, struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
int size, u16 ssn); int size, u16 ssn);
void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,

View File

@ -26,6 +26,7 @@
#include <linux/types.h> #include <linux/types.h>
#include "wmi.h" #include "wmi.h"
#include "wil_platform.h" #include "wil_platform.h"
#include "fw.h"
extern bool no_fw_recovery; extern bool no_fw_recovery;
extern unsigned int mtu_max; extern unsigned int mtu_max;
@ -49,6 +50,11 @@ extern bool disable_ap_sme;
#define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */ #define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */
#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.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 * extract bits [@b0:@b1] (inclusive) from the value @x
* it should be @b0 <= @b1, or result is incorrect * it should be @b0 <= @b1, or result is incorrect
@ -463,13 +469,12 @@ struct vring_tx_data {
u16 agg_timeout; u16 agg_timeout;
u8 agg_amsdu; u8 agg_amsdu;
bool addba_in_progress; /* if set, agg_xxx is for request in progress */ bool addba_in_progress; /* if set, agg_xxx is for request in progress */
u8 mid;
spinlock_t lock; spinlock_t lock;
}; };
enum { /* for wil6210_priv.status */ enum { /* for wil6210_priv.status */
wil_status_fwready = 0, /* FW operational */ wil_status_fwready = 0, /* FW operational */
wil_status_fwconnecting,
wil_status_fwconnected,
wil_status_dontscan, wil_status_dontscan,
wil_status_mbox_ready, /* MBOX structures ready */ wil_status_mbox_ready, /* MBOX structures ready */
wil_status_irqen, /* interrupts enabled - for debug */ wil_status_irqen, /* interrupts enabled - for debug */
@ -541,7 +546,6 @@ struct wil_tid_crypto_rx {
struct wil_p2p_info { struct wil_p2p_info {
struct ieee80211_channel listen_chan; struct ieee80211_channel listen_chan;
u8 discovery_started; u8 discovery_started;
u8 p2p_dev_started;
u64 cookie; u64 cookie;
struct wireless_dev *pending_listen_wdev; struct wireless_dev *pending_listen_wdev;
unsigned int listen_duration; unsigned int listen_duration;
@ -584,6 +588,7 @@ struct wil_net_stats {
*/ */
struct wil_sta_info { struct wil_sta_info {
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
u8 mid;
enum wil_sta_status status; enum wil_sta_status status;
struct wil_net_stats stats; struct wil_net_stats stats;
/* Rx BACK */ /* 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_id;
extern u8 led_polarity; 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 wil6210_priv {
struct pci_dev *pdev; struct pci_dev *pdev;
u32 bar_size; u32 bar_size;
struct wireless_dev *wdev; struct wiphy *wiphy;
struct net_device *main_ndev;
void __iomem *csr; void __iomem *csr;
DECLARE_BITMAP(status, wil_status_last); DECLARE_BITMAP(status, wil_status_last);
u8 fw_version[ETHTOOL_FWVERS_LEN]; u8 fw_version[ETHTOOL_FWVERS_LEN];
@ -686,21 +725,18 @@ struct wil6210_priv {
DECLARE_BITMAP(hw_capa, hw_capa_last); DECLARE_BITMAP(hw_capa, hw_capa_last);
DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX); DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX);
DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_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_count; /* num of FW recovery attempts in a short time */
u32 recovery_state; /* FW recovery state machine */ u32 recovery_state; /* FW recovery state machine */
unsigned long last_fw_recovery; /* jiffies of last fw recovery */ unsigned long last_fw_recovery; /* jiffies of last fw recovery */
wait_queue_head_t wq; /* for all wait_event() use */ 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 */ /* profile */
struct cfg80211_chan_def monitor_chandef; struct cfg80211_chan_def monitor_chandef;
u32 monitor_flags; u32 monitor_flags;
u32 privacy; /* secure connection? */
u8 hidden_ssid; /* relevant in AP mode */
u16 channel; /* relevant in AP mode */
int sinfo_gen; 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 */ /* interrupt moderation */
u32 tx_max_burst_duration; u32 tx_max_burst_duration;
u32 tx_interframe_timeout; u32 tx_interframe_timeout;
@ -715,15 +751,13 @@ struct wil6210_priv {
struct completion wmi_call; struct completion wmi_call;
u16 wmi_seq; u16 wmi_seq;
u16 reply_id; /**< wait for this WMI event */ u16 reply_id; /**< wait for this WMI event */
u8 reply_mid;
void *reply_buf; void *reply_buf;
u16 reply_size; u16 reply_size;
struct workqueue_struct *wmi_wq; /* for deferred calls */ struct workqueue_struct *wmi_wq; /* for deferred calls */
struct work_struct wmi_event_worker; struct work_struct wmi_event_worker;
struct workqueue_struct *wq_service; struct workqueue_struct *wq_service;
struct work_struct disconnect_worker;
struct work_struct fw_error_worker; /* for FW error recovery */ 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; struct list_head pending_wmi_ev;
/* /*
* protect pending_wmi_ev * protect pending_wmi_ev
@ -732,13 +766,10 @@ struct wil6210_priv {
*/ */
spinlock_t wmi_ev_lock; spinlock_t wmi_ev_lock;
spinlock_t net_queue_lock; /* guarding stop/wake netif queue */ 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_rx;
struct napi_struct napi_tx; struct napi_struct napi_tx;
/* keep alive */ struct net_device napi_ndev; /* dummy net_device serving all VIFs */
struct list_head probe_client_pending;
struct mutex probe_client_mutex; /* protect @probe_client_pending */
struct work_struct probe_client_worker;
/* DMA related */ /* DMA related */
struct vring vring_rx; struct vring vring_rx;
unsigned int rx_buf_len; unsigned int rx_buf_len;
@ -746,11 +777,8 @@ struct wil6210_priv {
struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS]; struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS];
u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */ u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
struct wil_sta_info sta[WIL6210_MAX_CID]; struct wil_sta_info sta[WIL6210_MAX_CID];
int bcast_vring;
u32 vring_idle_trsh; /* HW fetches up to 16 descriptors at once */ u32 vring_idle_trsh; /* HW fetches up to 16 descriptors at once */
u32 dma_addr_size; /* indicates dma addr size */ 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} */ struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
/* statistics */ /* statistics */
@ -770,13 +798,10 @@ struct wil6210_priv {
struct pmc_ctx pmc; struct pmc_ctx pmc;
bool pbss; u8 p2p_dev_started;
struct wil_p2p_info p2p;
/* P2P_DEVICE vif */ /* P2P_DEVICE vif */
struct wireless_dev *p2p_wdev; struct wireless_dev *p2p_wdev;
struct mutex p2p_wdev_mutex; /* protect @p2p_wdev and @scan_request */
struct wireless_dev *radio_wdev; struct wireless_dev *radio_wdev;
/* High Access Latency Policy voting */ /* High Access Latency Policy voting */
@ -798,13 +823,35 @@ struct wil6210_priv {
u32 iccm_base; 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 wil_to_dev(i) (wiphy_dev(wil_to_wiphy(i)))
#define wiphy_to_wil(w) (struct wil6210_priv *)(wiphy_priv(w)) #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 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_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) __printf(2, 3)
void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...); 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) __printf(2, 3)
void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...); void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...);
#define wil_dbg(wil, fmt, arg...) do { \ #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); \ wil_dbg_trace(wil, fmt, ##arg); \
} while (0) } 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, void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
size_t count); 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); 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); 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); 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); void wil_if_remove(struct wil6210_priv *wil);
int wil_priv_init(struct wil6210_priv *wil); int wil_priv_init(struct wil6210_priv *wil);
void wil_priv_deinit(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); int __wil_down(struct wil6210_priv *wil);
void wil_refresh_fw_capabilities(struct wil6210_priv *wil); void wil_refresh_fw_capabilities(struct wil6210_priv *wil);
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r); 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); void wil_set_ethtoolops(struct net_device *ndev);
struct fw_map *wil_find_fw_mapping(const char *section); 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); void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr, int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
struct wil6210_mbox_hdr *hdr); 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); 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); u16 reply_id, void *reply, u8 reply_size, int to_msec);
void wmi_event_worker(struct work_struct *work); void wmi_event_worker(struct work_struct *work);
void wmi_event_flush(struct wil6210_priv *wil); void wmi_event_flush(struct wil6210_priv *wil);
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);
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);
int wmi_set_channel(struct wil6210_priv *wil, int channel); int wmi_set_channel(struct wil6210_priv *wil, int channel);
int wmi_get_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); 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, const void *mac_addr, int key_len, const void *key,
int key_usage); int key_usage);
int wmi_echo(struct wil6210_priv *wil); 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_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
int wmi_rxon(struct wil6210_priv *wil, bool on); 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_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); u16 reason, bool full_disconnect, bool del_sta);
int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout); int wmi_addba(struct wil6210_priv *wil, u8 mid,
int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason); u8 ringid, u8 size, u16 timeout);
int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason); int wmi_delba_tx(struct wil6210_priv *wil, u8 mid, u8 ringid, u16 reason);
int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token, 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); u16 status, bool amsdu, u16 agg_wsize, u16 timeout);
int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil, int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
enum wmi_ps_profile_type ps_profile); enum wmi_ps_profile_type ps_profile);
int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short); 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_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short);
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);
int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid, int wmi_port_allocate(struct wil6210_priv *wil, u8 mid,
u8 dialog_token, __le16 ba_param_set, 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); __le16 ba_timeout, __le16 ba_seq_ctrl);
int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize); 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 */ /* P2P */
bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request); 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_vif *vif,
int wil_p2p_search(struct wil6210_priv *wil,
struct cfg80211_scan_request *request); struct cfg80211_scan_request *request);
int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev, int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
unsigned int duration, struct ieee80211_channel *chan, unsigned int duration, struct ieee80211_channel *chan,
u64 *cookie); u64 *cookie);
u8 wil_p2p_stop_discovery(struct wil6210_priv *wil); u8 wil_p2p_stop_discovery(struct wil6210_vif *vif);
int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie); int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie);
void wil_p2p_listen_expired(struct work_struct *work); void wil_p2p_listen_expired(struct work_struct *work);
void wil_p2p_search_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_stop_radio_operations(struct wil6210_priv *wil);
void wil_p2p_delayed_listen_work(struct work_struct *work); void wil_p2p_delayed_listen_work(struct work_struct *work);
/* WMI for P2P */ /* WMI for P2P */
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi); int wmi_p2p_cfg(struct wil6210_vif *vif, int channel, int bi);
int wmi_start_listen(struct wil6210_priv *wil); int wmi_start_listen(struct wil6210_vif *vif);
int wmi_start_search(struct wil6210_priv *wil); int wmi_start_search(struct wil6210_vif *vif);
int wmi_stop_discovery(struct wil6210_priv *wil); int wmi_stop_discovery(struct wil6210_vif *vif);
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
struct cfg80211_mgmt_tx_params *params, struct cfg80211_mgmt_tx_params *params,
u64 *cookie); 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) #if defined(CONFIG_WIL6210_DEBUGFS)
int wil6210_debugfs_init(struct wil6210_priv *wil); 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) {} static inline void wil6210_debugfs_remove(struct wil6210_priv *wil) {}
#endif #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 station_info *sinfo);
struct wireless_dev *wil_cfg80211_init(struct device *dev); struct wil6210_priv *wil_cfg80211_init(struct device *dev);
void wil_wdev_free(struct wil6210_priv *wil); void wil_cfg80211_deinit(struct wil6210_priv *wil);
void wil_p2p_wdev_free(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_set_mac_address(struct wil6210_priv *wil, void *addr);
int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, int wmi_pcp_start(struct wil6210_vif *vif, int bi, u8 wmi_nettype, u8 chan,
u8 chan, u8 hidden_ssid, u8 is_go); u8 hidden_ssid, u8 is_go);
int wmi_pcp_stop(struct wil6210_priv *wil); int wmi_pcp_stop(struct wil6210_vif *vif);
int wmi_led_cfg(struct wil6210_priv *wil, bool enable); int wmi_led_cfg(struct wil6210_priv *wil, bool enable);
int wmi_abort_scan(struct wil6210_priv *wil); int wmi_abort_scan(struct wil6210_vif *vif);
void wil_abort_scan(struct wil6210_priv *wil, bool sync); 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_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); 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_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); int wil_rx_init(struct wil6210_priv *wil, u16 size);
void wil_rx_fini(struct wil6210_priv *wil); void wil_rx_fini(struct wil6210_priv *wil);
/* TX API */ /* 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); int cid, int tid);
void wil_vring_fini_tx(struct wil6210_priv *wil, int id); void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
int wil_tx_init(struct wil6210_priv *wil, int cid); int wil_tx_init(struct wil6210_vif *vif, int cid);
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);
int wil_bcast_init(struct wil6210_priv *wil); int wil_bcast_init(struct wil6210_vif *vif);
void wil_bcast_fini(struct wil6210_priv *wil); 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 vring *vring, void wil_update_net_queues(struct wil6210_priv *wil, struct wil6210_vif *vif,
bool should_stop); struct vring *vring, bool should_stop);
void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring, void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif,
bool check_stop); struct vring *vring, bool check_stop);
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev); 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); void wil6210_unmask_irq_tx(struct wil6210_priv *wil);
/* RX API */ /* RX API */

File diff suppressed because it is too large Load Diff

View File

@ -445,6 +445,11 @@ brcmf_proto_bcdc_init_done(struct brcmf_pub *drvr)
return 0; 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) int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
{ {
struct brcmf_bcdc *bcdc; 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->del_if = brcmf_proto_bcdc_del_if;
drvr->proto->reset_if = brcmf_proto_bcdc_reset_if; drvr->proto->reset_if = brcmf_proto_bcdc_reset_if;
drvr->proto->init_done = brcmf_proto_bcdc_init_done; drvr->proto->init_done = brcmf_proto_bcdc_init_done;
drvr->proto->debugfs_create = brcmf_proto_bcdc_debugfs_create;
drvr->proto->pd = bcdc; drvr->proto->pd = bcdc;
drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES; drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;

View File

@ -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, int brcmf_btcoex_set_mode(struct brcmf_cfg80211_vif *vif,
enum brcmf_btcoex_mode mode, u16 duration) 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_btcoex_info *btci = cfg->btcoex;
struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);

View File

@ -88,7 +88,7 @@ struct brcmf_bus_ops {
void (*wowl_config)(struct device *dev, bool enabled); void (*wowl_config)(struct device *dev, bool enabled);
size_t (*get_ramsize)(struct device *dev); size_t (*get_ramsize)(struct device *dev);
int (*get_memdump)(struct device *dev, void *data, size_t len); 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); 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. * @always_use_fws_queue: bus wants use queue also when fwsignal is inactive.
* @wowl_supported: is wowl supported by bus driver. * @wowl_supported: is wowl supported by bus driver.
* @chiprev: revision of the dongle chip. * @chiprev: revision of the dongle chip.
* @msgbuf: msgbuf protocol parameters provided by bus layer.
*/ */
struct brcmf_bus { struct brcmf_bus {
union { union {
@ -228,10 +229,10 @@ int brcmf_bus_get_memdump(struct brcmf_bus *bus, void *data, size_t len)
} }
static inline 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) 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);
} }
/* /*

View File

@ -753,7 +753,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy, static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy,
struct wireless_dev *wdev) 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 net_device *ndev = wdev->netdev;
struct brcmf_if *ifp = netdev_priv(ndev); struct brcmf_if *ifp = netdev_priv(ndev);
int ret; int ret;
@ -786,7 +786,7 @@ static int brcmf_cfg80211_del_ap_iface(struct wiphy *wiphy,
static static
int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) 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; struct net_device *ndev = wdev->netdev;
if (ndev && ndev == cfg_to_ndev(cfg)) 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, enum nl80211_iftype type,
struct vif_params *params) 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_if *ifp = netdev_priv(ndev);
struct brcmf_cfg80211_vif *vif = ifp->vif; struct brcmf_cfg80211_vif *vif = ifp->vif;
s32 infra = 0; s32 infra = 0;
@ -2127,17 +2127,15 @@ static s32
brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
s32 *dbm) s32 *dbm)
{ {
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_cfg80211_vif *vif = wdev_to_vif(wdev);
struct net_device *ndev = cfg_to_ndev(cfg);
struct brcmf_if *ifp = netdev_priv(ndev);
s32 qdbm = 0; s32 qdbm = 0;
s32 err; s32 err;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
if (!check_vif_up(ifp->vif)) if (!check_vif_up(vif))
return -EIO; return -EIO;
err = brcmf_fil_iovar_int_get(ifp, "qtxpower", &qdbm); err = brcmf_fil_iovar_int_get(vif->ifp, "qtxpower", &qdbm);
if (err) { if (err) {
brcmf_err("error (%d)\n", err); brcmf_err("error (%d)\n", err);
goto done; goto done;
@ -3358,7 +3356,7 @@ brcmf_cfg80211_sched_scan_start(struct wiphy *wiphy,
struct cfg80211_sched_scan_request *req) struct cfg80211_sched_scan_request *req)
{ {
struct brcmf_if *ifp = netdev_priv(ndev); 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", brcmf_dbg(SCAN, "Enter: n_match_sets=%d n_ssids=%d\n",
req->n_match_sets, req->n_ssids); req->n_match_sets, req->n_ssids);
@ -5190,6 +5188,12 @@ static struct cfg80211_ops brcmf_cfg80211_ops = {
.del_pmk = brcmf_cfg80211_del_pmk, .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, struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
enum nl80211_iftype type) 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, static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
u32 bw_cap[]) 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_supported_band *band;
struct ieee80211_channel *channel; struct ieee80211_channel *channel;
struct wiphy *wiphy; struct wiphy *wiphy;
@ -6012,7 +6016,7 @@ static int brcmf_construct_chaninfo(struct brcmf_cfg80211_info *cfg,
static int brcmf_enable_bw40_2g(struct brcmf_cfg80211_info *cfg) 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 ieee80211_supported_band *band;
struct brcmf_fil_bwcap_le band_bwcap; struct brcmf_fil_bwcap_le band_bwcap;
struct brcmf_chanspec_list *list; 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 = brcmf_get_ifp(cfg->pub, 0);
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); struct wiphy *wiphy;
u32 nmode = 0; u32 nmode = 0;
u32 vhtmode = 0; u32 vhtmode = 0;
u32 bw_cap[2] = { WLC_BW_20MHZ_BIT, WLC_BW_20MHZ_BIT }; 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, static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *req) struct regulatory_request *req)
{ {
struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy); struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
struct brcmf_fil_country_le ccreq; struct brcmf_fil_country_le ccreq;
s32 err; s32 err;
int i; int i;
@ -6805,7 +6809,7 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
return; return;
/* ignore non-ISO3166 country codes */ /* 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') { if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n", brcmf_err("not an ISO3166 code (0x%02x 0x%02x)\n",
req->alpha2[0], req->alpha2[1]); 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"); brcmf_err("Firmware rejected country setting\n");
return; return;
} }
brcmf_setup_wiphybands(wiphy); brcmf_setup_wiphybands(cfg);
} }
static void brcmf_free_wiphy(struct wiphy *wiphy) 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) if (wiphy->wowlan != &brcmf_wowlan_support)
kfree(wiphy->wowlan); kfree(wiphy->wowlan);
#endif #endif
wiphy_free(wiphy);
} }
struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
struct device *busdev, struct cfg80211_ops *ops,
bool p2pdev_forced) bool p2pdev_forced)
{ {
struct wiphy *wiphy = drvr->wiphy;
struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev; struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
struct brcmf_cfg80211_info *cfg; struct brcmf_cfg80211_info *cfg;
struct wiphy *wiphy;
struct cfg80211_ops *ops;
struct brcmf_cfg80211_vif *vif; struct brcmf_cfg80211_vif *vif;
struct brcmf_if *ifp; struct brcmf_if *ifp;
s32 err = 0; s32 err = 0;
@ -6879,26 +6881,13 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
return NULL; return NULL;
} }
ops = kmemdup(&brcmf_cfg80211_ops, sizeof(*ops), GFP_KERNEL); cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
if (!ops) if (!cfg) {
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) {
brcmf_err("Could not allocate wiphy device\n"); 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->wiphy = wiphy;
cfg->ops = ops;
cfg->pub = drvr; cfg->pub = drvr;
init_vif_event(&cfg->vif_event); init_vif_event(&cfg->vif_event);
INIT_LIST_HEAD(&cfg->vif_list); 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)) if (IS_ERR(vif))
goto wiphy_out; goto wiphy_out;
ifp = netdev_priv(ndev);
vif->ifp = ifp; vif->ifp = ifp;
vif->wdev.netdev = ndev; vif->wdev.netdev = ndev;
ndev->ieee80211_ptr = &vif->wdev; ndev->ieee80211_ptr = &vif->wdev;
@ -6933,6 +6923,11 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
if (err < 0) if (err < 0)
goto priv_out; goto priv_out;
/* regulatory notifer below needs access to cfg so
* assign it now.
*/
drvr->config = cfg;
brcmf_dbg(INFO, "Registering custom regulatory\n"); brcmf_dbg(INFO, "Registering custom regulatory\n");
wiphy->reg_notifier = brcmf_cfg80211_reg_notifier; wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG; 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 = &wiphy->bands[NL80211_BAND_2GHZ]->ht_cap.cap;
*cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; *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); err = wiphy_register(wiphy);
if (err < 0) { if (err < 0) {
brcmf_err("Could not register wiphy device (%d)\n", err); brcmf_err("Could not register wiphy device (%d)\n", err);
goto priv_out; goto priv_out;
} }
err = brcmf_setup_wiphybands(wiphy); err = brcmf_setup_wiphybands(cfg);
if (err) { if (err) {
brcmf_err("Setting wiphy bands failed (%d)\n", err); brcmf_err("Setting wiphy bands failed (%d)\n", err);
goto wiphy_unreg_out; goto wiphy_unreg_out;
@ -6969,12 +6968,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
else else
*cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; *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); err = brcmf_fweh_activate_events(ifp);
if (err) { if (err) {
brcmf_err("FWEH activation failed (%d)\n", err); brcmf_err("FWEH activation failed (%d)\n", err);
@ -7042,8 +7036,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
ifp->vif = NULL; ifp->vif = NULL;
wiphy_out: wiphy_out:
brcmf_free_wiphy(wiphy); brcmf_free_wiphy(wiphy);
ops_out: kfree(cfg);
kfree(ops);
return NULL; return NULL;
} }
@ -7058,4 +7051,5 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
kfree(cfg->ops); kfree(cfg->ops);
wl_deinit_priv(cfg); wl_deinit_priv(cfg);
brcmf_free_wiphy(cfg->wiphy); brcmf_free_wiphy(cfg->wiphy);
kfree(cfg);
} }

View File

@ -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) 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) 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 static inline
struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg) struct net_device *cfg_to_ndev(struct brcmf_cfg80211_info *cfg)
{ {
struct brcmf_cfg80211_vif *vif; return brcmf_get_ifp(cfg->pub, 0)->ndev;
vif = list_first_entry(&cfg->vif_list, struct brcmf_cfg80211_vif, list);
return vif->wdev.netdev;
} }
static inline struct brcmf_cfg80211_info *ndev_to_cfg(struct net_device *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 brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
struct device *busdev, struct cfg80211_ops *ops,
bool p2pdev_forced); bool p2pdev_forced);
void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg); void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
s32 brcmf_cfg80211_up(struct net_device *ndev); s32 brcmf_cfg80211_up(struct net_device *ndev);
s32 brcmf_cfg80211_down(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); enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp);
struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,

View File

@ -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); 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; const char *fmt;
fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x"; fmt = ((id > 0xa000) || (id < 0x4000)) ? "BCM%d/%u" : "BCM%x/%u";
snprintf(buf, len, fmt, chipid); snprintf(buf, len, fmt, id, rev);
return buf; 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; ci->pub.chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT; socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
brcmf_chip_name(ci->pub.chip, ci->pub.name, sizeof(ci->pub.name)); brcmf_chip_name(ci->pub.chip, ci->pub.chiprev,
brcmf_dbg(INFO, "found %s chip: BCM%s, rev=%d\n", ci->pub.name, sizeof(ci->pub.name));
socitype == SOCI_SB ? "SB" : "AXI", ci->pub.name, brcmf_dbg(INFO, "found %s chip: %s\n",
ci->pub.chiprev); socitype == SOCI_SB ? "SB" : "AXI", ci->pub.name);
if (socitype == SOCI_SB) { if (socitype == SOCI_SB) {
if (ci->pub.chip != BRCM_CC_4329_CHIP_ID) { if (ci->pub.chip != BRCM_CC_4329_CHIP_ID) {

View File

@ -45,7 +45,7 @@ struct brcmf_chip {
u32 rambase; u32 rambase;
u32 ramsize; u32 ramsize;
u32 srsize; 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); void brcmf_chip_set_passive(struct brcmf_chip *ci);
bool brcmf_chip_set_active(struct brcmf_chip *ci, u32 rstvec); bool brcmf_chip_set_active(struct brcmf_chip *ci, u32 rstvec);
bool brcmf_chip_sr_capable(struct brcmf_chip *pub); 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 */ #endif /* BRCMF_AXIDMP_H */

View File

@ -30,6 +30,7 @@
#include "common.h" #include "common.h"
#include "of.h" #include "of.h"
#include "firmware.h" #include "firmware.h"
#include "chip.h"
MODULE_AUTHOR("Broadcom Corporation"); MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver."); 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 */ /* Debug level configuration. See debug.h for bits, sysfs modifiable */
int brcmf_msg_level; 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"); MODULE_PARM_DESC(debug, "Level of debug output");
static int brcmf_p2p_enable; 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]; static char brcmf_firmware_path[BRCMF_FW_ALTPATH_LEN];
module_param_string(alternative_fw_path, brcmf_firmware_path, 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"); MODULE_PARM_DESC(alternative_fw_path, "Alternative firmware path");
static int brcmf_fcmode; 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"); MODULE_PARM_DESC(fcmode, "Mode of firmware signalled flow control");
static int brcmf_roamoff; 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"); 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 #ifdef DEBUG
/* always succeed brcmf_bus_started() */ /* always succeed brcmf_bus_started() */
static int brcmf_ignore_probe_fail; static int brcmf_ignore_probe_fail;
@ -124,43 +129,9 @@ static int brcmf_c_download(struct brcmf_if *ifp, u16 flag,
return err; 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) 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; struct brcmf_dload_data_le *chunk_buf;
const struct firmware *clm = NULL; const struct firmware *clm = NULL;
u8 clm_name[BRCMF_FW_NAME_LEN]; 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"); brcmf_dbg(TRACE, "Enter\n");
memset(clm_name, 0, BRCMF_FW_NAME_LEN); memset(clm_name, 0, sizeof(clm_name));
err = brcmf_c_get_clm_name(ifp, clm_name); err = brcmf_bus_get_fwname(bus, ".clm_blob", clm_name);
if (err) { if (err) {
brcmf_err("get CLM blob file name failed (%d)\n", err); brcmf_err("get CLM blob file name failed (%d)\n", err);
return err; return err;
} }
err = request_firmware(&clm, clm_name, dev); err = request_firmware(&clm, clm_name, bus->dev);
if (err) { 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); err);
return 0; return 0;
} }
@ -234,6 +205,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
{ {
s8 eventmask[BRCMF_EVENTING_MASK_LEN]; s8 eventmask[BRCMF_EVENTING_MASK_LEN];
u8 buf[BRCMF_DCMD_SMLEN]; u8 buf[BRCMF_DCMD_SMLEN];
struct brcmf_bus *bus;
struct brcmf_rev_info_le revinfo; struct brcmf_rev_info_le revinfo;
struct brcmf_rev_info *ri; struct brcmf_rev_info *ri;
char *clmver; char *clmver;
@ -247,18 +219,21 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
brcmf_err("Retreiving cur_etheraddr failed, %d\n", err); brcmf_err("Retreiving cur_etheraddr failed, %d\n", err);
goto done; goto done;
} }
memcpy(ifp->drvr->wiphy->perm_addr, ifp->drvr->mac, ETH_ALEN);
memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac)); 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, err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO,
&revinfo, sizeof(revinfo)); &revinfo, sizeof(revinfo));
ri = &ifp->drvr->revinfo;
if (err < 0) { if (err < 0) {
brcmf_err("retrieving revision info failed, %d\n", err); brcmf_err("retrieving revision info failed, %d\n", err);
strlcpy(ri->chipname, "UNKNOWN", sizeof(ri->chipname));
} else { } else {
ri->vendorid = le32_to_cpu(revinfo.vendorid); ri->vendorid = le32_to_cpu(revinfo.vendorid);
ri->deviceid = le32_to_cpu(revinfo.deviceid); ri->deviceid = le32_to_cpu(revinfo.deviceid);
ri->radiorev = le32_to_cpu(revinfo.radiorev); ri->radiorev = le32_to_cpu(revinfo.radiorev);
ri->chiprev = le32_to_cpu(revinfo.chiprev);
ri->corerev = le32_to_cpu(revinfo.corerev); ri->corerev = le32_to_cpu(revinfo.corerev);
ri->boardid = le32_to_cpu(revinfo.boardid); ri->boardid = le32_to_cpu(revinfo.boardid);
ri->boardvendor = le32_to_cpu(revinfo.boardvendor); 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->driverrev = le32_to_cpu(revinfo.driverrev);
ri->ucoderev = le32_to_cpu(revinfo.ucoderev); ri->ucoderev = le32_to_cpu(revinfo.ucoderev);
ri->bus = le32_to_cpu(revinfo.bus); ri->bus = le32_to_cpu(revinfo.bus);
ri->chipnum = le32_to_cpu(revinfo.chipnum);
ri->phytype = le32_to_cpu(revinfo.phytype); ri->phytype = le32_to_cpu(revinfo.phytype);
ri->phyrev = le32_to_cpu(revinfo.phyrev); ri->phyrev = le32_to_cpu(revinfo.phyrev);
ri->anarev = le32_to_cpu(revinfo.anarev); ri->anarev = le32_to_cpu(revinfo.anarev);
ri->chippkg = le32_to_cpu(revinfo.chippkg); ri->chippkg = le32_to_cpu(revinfo.chippkg);
ri->nvramrev = le32_to_cpu(revinfo.nvramrev); 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; ri->result = err;
if (bus->chip)
brcmf_chip_name(bus->chip, bus->chiprev,
ri->chipname, sizeof(ri->chipname));
/* Do any CLM downloading */ /* Do any CLM downloading */
err = brcmf_c_process_clm_blob(ifp); err = brcmf_c_process_clm_blob(ifp);
if (err < 0) { if (err < 0) {
@ -295,7 +279,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
strsep(&ptr, "\n"); strsep(&ptr, "\n");
/* Print fw version info */ /* 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 */ /* locate firmware version number for ethtool */
ptr = strrchr(buf, ' ') + 1; 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->feature_disable = brcmf_feature_disable;
settings->fcmode = brcmf_fcmode; settings->fcmode = brcmf_fcmode;
settings->roamoff = !!brcmf_roamoff; settings->roamoff = !!brcmf_roamoff;
settings->iapp = !!brcmf_iapp_enable;
#ifdef DEBUG #ifdef DEBUG
settings->ignore_probe_fail = !!brcmf_ignore_probe_fail; settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
#endif #endif
@ -511,9 +496,6 @@ static int __init brcmfmac_module_init(void)
{ {
int err; int err;
/* Initialize debug system first */
brcmf_debugfs_init();
/* Get the platform data (if available) for our devices */ /* Get the platform data (if available) for our devices */
err = platform_driver_probe(&brcmf_pd, brcmf_common_pd_probe); err = platform_driver_probe(&brcmf_pd, brcmf_common_pd_probe);
if (err == -ENODEV) if (err == -ENODEV)
@ -525,7 +507,6 @@ static int __init brcmfmac_module_init(void)
/* Continue the initialization by registering the different busses */ /* Continue the initialization by registering the different busses */
err = brcmf_core_init(); err = brcmf_core_init();
if (err) { if (err) {
brcmf_debugfs_exit();
if (brcmfmac_pdata) if (brcmfmac_pdata)
platform_driver_unregister(&brcmf_pd); platform_driver_unregister(&brcmf_pd);
} }
@ -538,7 +519,6 @@ static void __exit brcmfmac_module_exit(void)
brcmf_core_exit(); brcmf_core_exit();
if (brcmfmac_pdata) if (brcmfmac_pdata)
platform_driver_unregister(&brcmf_pd); platform_driver_unregister(&brcmf_pd);
brcmf_debugfs_exit();
} }
module_init(brcmfmac_module_init); module_init(brcmfmac_module_init);

View File

@ -58,6 +58,7 @@ struct brcmf_mp_device {
unsigned int feature_disable; unsigned int feature_disable;
int fcmode; int fcmode;
bool roamoff; bool roamoff;
bool iapp;
bool ignore_probe_fail; bool ignore_probe_fail;
struct brcmfmac_pd_cc *country_codes; struct brcmfmac_pd_cc *country_codes;
union { union {

View File

@ -230,6 +230,37 @@ static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
schedule_work(&ifp->multicast_work); 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, static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
struct net_device *ndev) struct net_device *ndev)
{ {
@ -250,6 +281,23 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
goto done; 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 */ /* Make sure there's enough writeable headroom */
if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) { if (skb_headroom(skb) < drvr->hdrlen || skb_header_cloned(skb)) {
head_delta = max_t(int, drvr->hdrlen - skb_headroom(skb), 0); 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) 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) if (skb->pkt_type == PACKET_MULTICAST)
ifp->ndev->stats.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, "vendorid: 0x%04x\n", ri->vendorid);
seq_printf(s, "deviceid: 0x%04x\n", ri->deviceid); seq_printf(s, "deviceid: 0x%04x\n", ri->deviceid);
seq_printf(s, "radiorev: %s\n", brcmu_dotrev_str(ri->radiorev, drev)); 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, "chip: %s\n", ri->chipname);
seq_printf(s, "chiprev: %u\n", ri->chiprev);
seq_printf(s, "chippkg: %u\n", ri->chippkg); seq_printf(s, "chippkg: %u\n", ri->chippkg);
seq_printf(s, "corerev: %u\n", ri->corerev); seq_printf(s, "corerev: %u\n", ri->corerev);
seq_printf(s, "boardid: 0x%04x\n", ri->boardid); 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; 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; int ret = -1;
struct brcmf_bus *bus_if = drvr->bus_if; struct brcmf_bus *bus_if = drvr->bus_if;
@ -973,15 +1029,6 @@ static int brcmf_bus_started(struct brcmf_pub *drvr)
if (ret < 0) if (ret < 0)
goto fail; 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); brcmf_feat_attach(drvr);
ret = brcmf_proto_init_done(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); 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); drvr->settings->p2p_enable);
if (drvr->config == NULL) { if (drvr->config == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
@ -1024,6 +1071,11 @@ static int brcmf_bus_started(struct brcmf_pub *drvr)
#endif #endif
#endif /* CONFIG_INET */ #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; return 0;
fail: fail:
@ -1045,17 +1097,26 @@ static int brcmf_bus_started(struct brcmf_pub *drvr)
int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings) int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings)
{ {
struct wiphy *wiphy;
struct cfg80211_ops *ops;
struct brcmf_pub *drvr = NULL; struct brcmf_pub *drvr = NULL;
int ret = 0; int ret = 0;
int i; int i;
brcmf_dbg(TRACE, "Enter\n"); brcmf_dbg(TRACE, "Enter\n");
/* Allocate primary brcmf_info */ ops = brcmf_cfg80211_get_ops();
drvr = kzalloc(sizeof(*drvr), GFP_ATOMIC); if (!ops)
if (!drvr)
return -ENOMEM; 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++) for (i = 0; i < ARRAY_SIZE(drvr->if2bss); i++)
drvr->if2bss[i] = BRCMF_BSSIDX_INVALID; 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->bus_if->drvr = drvr;
drvr->settings = settings; drvr->settings = settings;
/* attach debug facilities */
brcmf_debug_attach(drvr);
/* Attach and link in the protocol */ /* Attach and link in the protocol */
ret = brcmf_proto_attach(drvr); ret = brcmf_proto_attach(drvr);
if (ret != 0) { if (ret != 0) {
@ -1084,15 +1142,18 @@ int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings)
/* attach firmware event handler */ /* attach firmware event handler */
brcmf_fweh_attach(drvr); brcmf_fweh_attach(drvr);
ret = brcmf_bus_started(drvr); ret = brcmf_bus_started(drvr, ops);
if (ret != 0) { if (ret != 0) {
brcmf_err("dongle is not responding: err=%d\n", ret); brcmf_err("dongle is not responding: err=%d\n", ret);
goto fail; goto fail;
} }
drvr->config->ops = ops;
return 0; return 0;
fail: fail:
brcmf_detach(dev); brcmf_detach(dev);
kfree(ops);
return ret; return ret;
} }
@ -1150,14 +1211,14 @@ void brcmf_detach(struct device *dev)
brcmf_remove_interface(drvr->iflist[i], false); brcmf_remove_interface(drvr->iflist[i], false);
brcmf_cfg80211_detach(drvr->config); brcmf_cfg80211_detach(drvr->config);
drvr->config = NULL;
brcmf_bus_stop(drvr->bus_if); brcmf_bus_stop(drvr->bus_if);
brcmf_proto_detach(drvr); brcmf_proto_detach(drvr);
brcmf_debug_detach(drvr);
bus_if->drvr = NULL; bus_if->drvr = NULL;
kfree(drvr); wiphy_free(drvr->wiphy);
} }
s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len) s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len)

View File

@ -87,7 +87,6 @@ struct brcmf_rev_info {
u32 vendorid; u32 vendorid;
u32 deviceid; u32 deviceid;
u32 radiorev; u32 radiorev;
u32 chiprev;
u32 corerev; u32 corerev;
u32 boardid; u32 boardid;
u32 boardvendor; u32 boardvendor;
@ -95,7 +94,7 @@ struct brcmf_rev_info {
u32 driverrev; u32 driverrev;
u32 ucoderev; u32 ucoderev;
u32 bus; u32 bus;
u32 chipnum; char chipname[12];
u32 phytype; u32 phytype;
u32 phyrev; u32 phyrev;
u32 anarev; u32 anarev;
@ -108,6 +107,7 @@ struct brcmf_pub {
/* Linkage ponters */ /* Linkage ponters */
struct brcmf_bus *bus_if; struct brcmf_bus *bus_if;
struct brcmf_proto *proto; struct brcmf_proto *proto;
struct wiphy *wiphy;
struct brcmf_cfg80211_info *config; struct brcmf_cfg80211_info *config;
/* Internal brcmf items */ /* Internal brcmf items */

View File

@ -25,8 +25,6 @@
#include "fweh.h" #include "fweh.h"
#include "debug.h" #include "debug.h"
static struct dentry *root_folder;
int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data, int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
size_t len) size_t len)
{ {
@ -54,44 +52,9 @@ int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
return 0; 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) 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, 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; struct dentry *e;
WARN(!drvr->wiphy->debugfsdir, "wiphy not (yet) registered\n");
e = debugfs_create_devm_seqfile(drvr->bus_if->dev, fn, 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); return PTR_ERR_OR_ZERO(e);
} }

View File

@ -113,29 +113,12 @@ extern int brcmf_msg_level;
struct brcmf_bus; struct brcmf_bus;
struct brcmf_pub; struct brcmf_pub;
#ifdef DEBUG #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); struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr);
int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn, int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
int (*read_fn)(struct seq_file *seq, void *data)); int (*read_fn)(struct seq_file *seq, void *data));
int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data, int brcmf_debug_create_memdump(struct brcmf_bus *bus, const void *data,
size_t len); size_t len);
#else #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 static inline
int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn, int brcmf_debugfs_add_entry(struct brcmf_pub *drvr, const char *fn,
int (*read_fn)(struct seq_file *seq, void *data)) int (*read_fn)(struct seq_file *seq, void *data))

View File

@ -228,7 +228,10 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
/* no quirks */ /* no quirks */
break; break;
} }
}
void brcmf_feat_debugfs_create(struct brcmf_pub *drvr)
{
brcmf_debugfs_add_entry(drvr, "features", brcmf_feat_debugfs_read); brcmf_debugfs_add_entry(drvr, "features", brcmf_feat_debugfs_read);
} }

View File

@ -89,6 +89,13 @@ enum brcmf_feat_quirk {
*/ */
void brcmf_feat_attach(struct brcmf_pub *drvr); 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. * brcmf_feat_is_enabled() - query feature.
* *

View File

@ -25,6 +25,7 @@
#include "firmware.h" #include "firmware.h"
#include "core.h" #include "core.h"
#include "common.h" #include "common.h"
#include "chip.h"
#define BRCMF_FW_MAX_NVRAM_SIZE 64000 #define BRCMF_FW_MAX_NVRAM_SIZE 64000
#define BRCMF_FW_NVRAM_DEVPATH_LEN 19 /* devpath0=pcie/1/4/ */ #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 brcmf_fw {
struct device *dev; struct device *dev;
u16 flags; struct brcmf_fw_request *req;
const struct firmware *code; u32 curpos;
const char *nvram_name; void (*done)(struct device *dev, int err, struct brcmf_fw_request *req);
u16 domain_nr;
u16 bus_nr;
void (*done)(struct device *dev, int err, const struct firmware *fw,
void *nvram_image, u32 nvram_len);
}; };
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) static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
{ {
struct brcmf_fw *fwctx = ctx; struct brcmf_fw *fwctx = ctx;
struct brcmf_fw_item *cur;
u32 nvram_length = 0; u32 nvram_length = 0;
void *nvram = NULL; void *nvram = NULL;
u8 *data = NULL; u8 *data = NULL;
@ -456,83 +470,150 @@ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx)
bool raw_nvram; bool raw_nvram;
brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev)); brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev));
cur = &fwctx->req->items[fwctx->curpos];
if (fw && fw->data) { if (fw && fw->data) {
data = (u8 *)fw->data; data = (u8 *)fw->data;
data_len = fw->size; data_len = fw->size;
raw_nvram = false; raw_nvram = false;
} else { } else {
data = bcm47xx_nvram_get_contents(&data_len); 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; goto fail;
raw_nvram = true; raw_nvram = true;
} }
if (data) if (data)
nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length, 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) if (raw_nvram)
bcm47xx_nvram_release_contents(data); bcm47xx_nvram_release_contents(data);
release_firmware(fw); release_firmware(fw);
if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) if (!nvram && !(cur->flags & BRCMF_FW_REQF_OPTIONAL))
goto fail; goto fail;
fwctx->done(fwctx->dev, 0, fwctx->code, nvram, nvram_length); brcmf_dbg(TRACE, "nvram %p len %d\n", nvram, nvram_length);
kfree(fwctx); cur->nv_data.data = nvram;
cur->nv_data.len = nvram_length;
return; return;
fail: fail:
brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev));
release_firmware(fwctx->code); fwctx->done(fwctx->dev, -ENOENT, NULL);
fwctx->done(fwctx->dev, -ENOENT, NULL, NULL, 0); brcmf_fw_free_request(fwctx->req);
kfree(fwctx); 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 *fwctx = ctx;
struct brcmf_fw_item *cur;
int ret = 0; int ret = 0;
brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev)); cur = &fwctx->req->items[fwctx->curpos];
if (!fw) {
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; ret = -ENOENT;
goto fail; goto fail;
} }
/* only requested code so done here */
if (!(fwctx->flags & BRCMF_FW_REQUEST_NVRAM))
goto done;
fwctx->code = fw; do {
ret = request_firmware_nowait(THIS_MODULE, true, fwctx->nvram_name, if (++fwctx->curpos == fwctx->req->n_items) {
fwctx->dev, GFP_KERNEL, fwctx, ret = 0;
brcmf_fw_request_nvram_done); 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; return;
fail: 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: done:
fwctx->done(fwctx->dev, ret, fw, NULL, 0); fwctx->done(fwctx->dev, ret, fwctx->req);
kfree(fwctx); kfree(fwctx);
} }
int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags, static bool brcmf_fw_request_is_valid(struct brcmf_fw_request *req)
const char *code, const char *nvram, {
void (*fw_cb)(struct device *dev, int err, struct brcmf_fw_item *item;
const struct firmware *fw, int i;
void *nvram_image, u32 nvram_len),
u16 domain_nr, u16 bus_nr) 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; struct brcmf_fw *fwctx;
brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev)); brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(dev));
if (!fw_cb || !code) if (!fw_cb)
return -EINVAL; return -EINVAL;
if ((flags & BRCMF_FW_REQUEST_NVRAM) && !nvram) if (!brcmf_fw_request_is_valid(req))
return -EINVAL; return -EINVAL;
fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL); fwctx = kzalloc(sizeof(*fwctx), GFP_KERNEL);
@ -540,35 +621,25 @@ int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags,
return -ENOMEM; return -ENOMEM;
fwctx->dev = dev; fwctx->dev = dev;
fwctx->flags = flags; fwctx->req = req;
fwctx->done = fw_cb; 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, brcmf_fw_request_next_item(fwctx, true);
GFP_KERNEL, fwctx, return 0;
brcmf_fw_request_code_done);
} }
int brcmf_fw_get_firmwares(struct device *dev, u16 flags, struct brcmf_fw_request *
const char *code, const char *nvram, brcmf_fw_alloc_request(u32 chip, u32 chiprev,
void (*fw_cb)(struct device *dev, int err, struct brcmf_firmware_mapping mapping_table[],
const struct firmware *fw, u32 table_size, struct brcmf_fw_name *fwnames,
void *nvram_image, u32 nvram_len)) u32 n_fwnames)
{ {
return brcmf_fw_get_firmwares_pcie(dev, flags, code, nvram, fw_cb, 0, struct brcmf_fw_request *fwreq;
0); char chipname[12];
} const char *mp_path;
u32 i, j;
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])
{
u32 i;
char end; char end;
size_t reqsz;
for (i = 0; i < table_size; i++) { for (i = 0; i < table_size; i++) {
if (mapping_table[i].chipid == chip && 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) { if (i == table_size) {
brcmf_err("Unknown chipid %d [%d]\n", chip, chiprev); brcmf_err("Unknown chipid %d [%d]\n", chip, chiprev);
return -ENODEV; return NULL;
} }
/* check if firmware path is provided by module parameter */ reqsz = sizeof(*fwreq) + n_fwnames * sizeof(struct brcmf_fw_item);
if (brcmf_mp_global.firmware_path[0] != '\0') { fwreq = kzalloc(reqsz, GFP_KERNEL);
strlcpy(fw_name, brcmf_mp_global.firmware_path, if (!fwreq)
BRCMF_FW_NAME_LEN); return NULL;
if ((nvram_name) && (mapping_table[i].nvram))
strlcpy(nvram_name, brcmf_mp_global.firmware_path, 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); BRCMF_FW_NAME_LEN);
end = brcmf_mp_global.firmware_path[ if (end != '/') {
strlen(brcmf_mp_global.firmware_path) - 1]; strlcat(fwnames[j].path, "/",
if (end != '/') { BRCMF_FW_NAME_LEN);
strlcat(fw_name, "/", BRCMF_FW_NAME_LEN); }
if ((nvram_name) && (mapping_table[i].nvram))
strlcat(nvram_name, "/", 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", return fwreq;
fw_name, chip, chip, chiprev);
return 0;
} }

View File

@ -16,10 +16,7 @@
#ifndef BRCMFMAC_FIRMWARE_H #ifndef BRCMFMAC_FIRMWARE_H
#define BRCMFMAC_FIRMWARE_H #define BRCMFMAC_FIRMWARE_H
#define BRCMF_FW_REQUEST 0x000F #define BRCMF_FW_REQF_OPTIONAL 0x0001
#define BRCMF_FW_REQUEST_NVRAM 0x0001
#define BRCMF_FW_REQ_FLAGS 0x00F0
#define BRCMF_FW_REQ_NV_OPTIONAL 0x0010
#define BRCMF_FW_NAME_LEN 320 #define BRCMF_FW_NAME_LEN 320
@ -38,49 +35,62 @@
struct brcmf_firmware_mapping { struct brcmf_firmware_mapping {
u32 chipid; u32 chipid;
u32 revmask; u32 revmask;
const char *fw; const char *fw_base;
const char *nvram;
}; };
#define BRCMF_FW_NVRAM_DEF(fw_nvram_name, fw, nvram) \ #define BRCMF_FW_DEF(fw_name, fw_base) \
static const char BRCM_ ## fw_nvram_name ## _FIRMWARE_NAME[] = \ static const char BRCM_ ## fw_name ## _FIRMWARE_BASENAME[] = \
BRCMF_FW_DEFAULT_PATH fw; \ BRCMF_FW_DEFAULT_PATH fw_base; \
static const char BRCM_ ## fw_nvram_name ## _NVRAM_NAME[] = \ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH fw_base ".bin")
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_ENTRY(chipid, mask, name) \ #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); 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 * Request firmware(s) asynchronously. When the asynchronous request
* fails it will not use the callback, but call device_release_driver() * fails it will not use the callback, but call device_release_driver()
* instead which will call the driver .remove() callback. * instead which will call the driver .remove() callback.
*/ */
int brcmf_fw_get_firmwares_pcie(struct device *dev, u16 flags, int brcmf_fw_get_firmwares(struct device *dev, struct brcmf_fw_request *req,
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,
void (*fw_cb)(struct device *dev, int err, void (*fw_cb)(struct device *dev, int err,
const struct firmware *fw, struct brcmf_fw_request *req));
void *nvram_image, u32 nvram_len));
#endif /* BRCMFMAC_FIRMWARE_H */ #endif /* BRCMFMAC_FIRMWARE_H */

View File

@ -124,8 +124,7 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
data, len, &fwerr); data, len, &fwerr);
if (err) { if (err) {
brcmf_dbg(FIL, "Failed: %s (%d)\n", brcmf_dbg(FIL, "Failed: error=%d\n", err);
brcmf_fil_get_errstr((u32)(-err)), err);
} else if (fwerr < 0) { } else if (fwerr < 0) {
brcmf_dbg(FIL, "Firmware error: %s (%d)\n", brcmf_dbg(FIL, "Firmware error: %s (%d)\n",
brcmf_fil_get_errstr((u32)(-fwerr)), fwerr); brcmf_fil_get_errstr((u32)(-fwerr)), fwerr);

View File

@ -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, brcmu_pktq_init(&fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
BRCMF_FWS_PSQ_LEN); 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", brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n",
fws->fw_signals ? "enabled" : "disabled", tlv); fws->fw_signals ? "enabled" : "disabled", tlv);
return fws; return fws;
@ -2429,6 +2425,13 @@ void brcmf_fws_detach(struct brcmf_fws_info *fws)
kfree(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) bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws)
{ {
return !fws->avoid_queueing; return !fws->avoid_queueing;

View File

@ -20,6 +20,7 @@
struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr); struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr);
void brcmf_fws_detach(struct brcmf_fws_info *fws); 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_queue_skbs(struct brcmf_fws_info *fws);
bool brcmf_fws_fc_active(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); void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb);

View File

@ -1418,6 +1418,11 @@ static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data)
} }
#endif #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) int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
{ {
struct brcmf_bus_msgbuf *if_msgbuf; 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->delete_peer = brcmf_msgbuf_delete_peer;
drvr->proto->add_tdls_peer = brcmf_msgbuf_add_tdls_peer; drvr->proto->add_tdls_peer = brcmf_msgbuf_add_tdls_peer;
drvr->proto->rxreorder = brcmf_msgbuf_rxreorder; drvr->proto->rxreorder = brcmf_msgbuf_rxreorder;
drvr->proto->debugfs_create = brcmf_msgbuf_debugfs_create;
drvr->proto->pd = msgbuf; drvr->proto->pd = msgbuf;
init_waitqueue_head(&msgbuf->ioctl_resp_wait); 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); spin_lock_init(&msgbuf->flowring_work_lock);
INIT_LIST_HEAD(&msgbuf->work_queue); INIT_LIST_HEAD(&msgbuf->work_queue);
brcmf_debugfs_add_entry(drvr, "msgbuf_stats", brcmf_msgbuf_stats_read);
return 0; return 0;
fail: fail:

View File

@ -2227,7 +2227,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
*/ */
int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) 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_p2p_info *p2p = &cfg->p2p;
struct brcmf_cfg80211_vif *vif; struct brcmf_cfg80211_vif *vif;
enum nl80211_iftype iftype; enum nl80211_iftype iftype;

View File

@ -46,36 +46,36 @@ enum brcmf_pcie_state {
BRCMFMAC_PCIE_STATE_UP BRCMFMAC_PCIE_STATE_UP
}; };
BRCMF_FW_NVRAM_DEF(43602, "brcmfmac43602-pcie.bin", "brcmfmac43602-pcie.txt"); BRCMF_FW_DEF(43602, "brcmfmac43602-pcie");
BRCMF_FW_NVRAM_DEF(4350, "brcmfmac4350-pcie.bin", "brcmfmac4350-pcie.txt"); BRCMF_FW_DEF(4350, "brcmfmac4350-pcie");
BRCMF_FW_NVRAM_DEF(4350C, "brcmfmac4350c2-pcie.bin", "brcmfmac4350c2-pcie.txt"); BRCMF_FW_DEF(4350C, "brcmfmac4350c2-pcie");
BRCMF_FW_NVRAM_DEF(4356, "brcmfmac4356-pcie.bin", "brcmfmac4356-pcie.txt"); BRCMF_FW_DEF(4356, "brcmfmac4356-pcie");
BRCMF_FW_NVRAM_DEF(43570, "brcmfmac43570-pcie.bin", "brcmfmac43570-pcie.txt"); BRCMF_FW_DEF(43570, "brcmfmac43570-pcie");
BRCMF_FW_NVRAM_DEF(4358, "brcmfmac4358-pcie.bin", "brcmfmac4358-pcie.txt"); BRCMF_FW_DEF(4358, "brcmfmac4358-pcie");
BRCMF_FW_NVRAM_DEF(4359, "brcmfmac4359-pcie.bin", "brcmfmac4359-pcie.txt"); BRCMF_FW_DEF(4359, "brcmfmac4359-pcie");
BRCMF_FW_NVRAM_DEF(4365B, "brcmfmac4365b-pcie.bin", "brcmfmac4365b-pcie.txt"); BRCMF_FW_DEF(4365B, "brcmfmac4365b-pcie");
BRCMF_FW_NVRAM_DEF(4365C, "brcmfmac4365c-pcie.bin", "brcmfmac4365c-pcie.txt"); BRCMF_FW_DEF(4365C, "brcmfmac4365c-pcie");
BRCMF_FW_NVRAM_DEF(4366B, "brcmfmac4366b-pcie.bin", "brcmfmac4366b-pcie.txt"); BRCMF_FW_DEF(4366B, "brcmfmac4366b-pcie");
BRCMF_FW_NVRAM_DEF(4366C, "brcmfmac4366c-pcie.bin", "brcmfmac4366c-pcie.txt"); BRCMF_FW_DEF(4366C, "brcmfmac4366c-pcie");
BRCMF_FW_NVRAM_DEF(4371, "brcmfmac4371-pcie.bin", "brcmfmac4371-pcie.txt"); BRCMF_FW_DEF(4371, "brcmfmac4371-pcie");
static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602), BRCMF_FW_ENTRY(BRCM_CC_43602_CHIP_ID, 0xFFFFFFFF, 43602),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43465_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_ENTRY(BRCM_CC_43465_CHIP_ID, 0xFFFFFFF0, 4366C),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4350_CHIP_ID, 0x000000FF, 4350C), BRCMF_FW_ENTRY(BRCM_CC_4350_CHIP_ID, 0x000000FF, 4350C),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4350_CHIP_ID, 0xFFFFFF00, 4350), BRCMF_FW_ENTRY(BRCM_CC_4350_CHIP_ID, 0xFFFFFF00, 4350),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43525_CHIP_ID, 0xFFFFFFF0, 4365C), BRCMF_FW_ENTRY(BRCM_CC_43525_CHIP_ID, 0xFFFFFFF0, 4365C),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43567_CHIP_ID, 0xFFFFFFFF, 43570), BRCMF_FW_ENTRY(BRCM_CC_43567_CHIP_ID, 0xFFFFFFFF, 43570),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43570), BRCMF_FW_ENTRY(BRCM_CC_43569_CHIP_ID, 0xFFFFFFFF, 43570),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43570_CHIP_ID, 0xFFFFFFFF, 43570), BRCMF_FW_ENTRY(BRCM_CC_43570_CHIP_ID, 0xFFFFFFFF, 43570),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358), BRCMF_FW_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0x0000000F, 4365B), BRCMF_FW_ENTRY(BRCM_CC_4365_CHIP_ID, 0x0000000F, 4365B),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFF0, 4365C), BRCMF_FW_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFF0, 4365C),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B), BRCMF_FW_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C), BRCMF_FW_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),
}; };
#define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */ #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; return 0;
} }
static int brcmf_pcie_get_fwname(struct device *dev, u32 chip, u32 chiprev, static
u8 *fw_name) 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_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pciedev *buspub = bus_if->bus_priv.pcie; struct brcmf_fw_request *fwreq;
struct brcmf_pciedev_info *devinfo = buspub->devinfo; struct brcmf_fw_name fwnames[] = {
int ret = 0; { ext, fw_name },
};
if (devinfo->fw_name[0] != '\0') fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN); brcmf_pcie_fwnames,
else ARRAY_SIZE(brcmf_pcie_fwnames),
ret = brcmf_fw_map_chip_to_name(chip, chiprev, fwnames, ARRAY_SIZE(fwnames));
brcmf_pcie_fwnames, if (!fwreq)
ARRAY_SIZE(brcmf_pcie_fwnames), return -ENOMEM;
fw_name, NULL);
return ret; kfree(fwreq);
return 0;
} }
static const struct brcmf_bus_ops brcmf_pcie_bus_ops = { 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, .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, static void brcmf_pcie_setup(struct device *dev, int ret,
const struct firmware *fw, struct brcmf_fw_request *fwreq)
void *nvram, u32 nvram_len)
{ {
const struct firmware *fw;
void *nvram;
struct brcmf_bus *bus; struct brcmf_bus *bus;
struct brcmf_pciedev *pcie_bus_dev; struct brcmf_pciedev *pcie_bus_dev;
struct brcmf_pciedev_info *devinfo; struct brcmf_pciedev_info *devinfo;
struct brcmf_commonring **flowrings; struct brcmf_commonring **flowrings;
u32 i; u32 i, nvram_len;
/* check firmware loading result */ /* check firmware loading result */
if (ret) if (ret)
@ -1670,6 +1675,11 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
devinfo = pcie_bus_dev->devinfo; devinfo = pcie_bus_dev->devinfo;
brcmf_pcie_attach(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 /* 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 * defined inside the firmware. This is because part of the memory in
* the device is shared and the devision is determined by FW. Parse * the device is shared and the devision is determined by FW. Parse
@ -1726,20 +1736,41 @@ static void brcmf_pcie_setup(struct device *dev, int ret,
device_release_driver(dev); 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 static int
brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{ {
int ret; int ret;
struct brcmf_fw_request *fwreq;
struct brcmf_pciedev_info *devinfo; struct brcmf_pciedev_info *devinfo;
struct brcmf_pciedev *pcie_bus_dev; struct brcmf_pciedev *pcie_bus_dev;
struct brcmf_bus *bus; struct brcmf_bus *bus;
u16 domain_nr;
u16 bus_nr;
domain_nr = pci_domain_nr(pdev->bus) + 1; brcmf_dbg(PCIE, "Enter %x:%x\n", pdev->vendor, pdev->device);
bus_nr = pdev->bus->number;
brcmf_dbg(PCIE, "Enter %x:%x (%d/%d)\n", pdev->vendor, pdev->device,
domain_nr, bus_nr);
ret = -ENOMEM; ret = -ENOMEM;
devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); 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); bus->wowl_supported = pci_pme_capable(pdev, PCI_D3hot);
dev_set_drvdata(&pdev->dev, bus); dev_set_drvdata(&pdev->dev, bus);
ret = brcmf_fw_map_chip_to_name(devinfo->ci->chip, devinfo->ci->chiprev, fwreq = brcmf_pcie_prepare_fw_request(devinfo);
brcmf_pcie_fwnames, if (!fwreq) {
ARRAY_SIZE(brcmf_pcie_fwnames), ret = -ENOMEM;
devinfo->fw_name, devinfo->nvram_name);
if (ret)
goto fail_bus; 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: fail_bus:
kfree(bus->msgbuf); kfree(bus->msgbuf);
kfree(bus); kfree(bus);

View File

@ -54,7 +54,8 @@ int brcmf_proto_attach(struct brcmf_pub *drvr)
if (!proto->tx_queue_data || (proto->hdrpull == NULL) || if (!proto->tx_queue_data || (proto->hdrpull == NULL) ||
(proto->query_dcmd == NULL) || (proto->set_dcmd == NULL) || (proto->query_dcmd == NULL) || (proto->set_dcmd == NULL) ||
(proto->configure_addr_mode == 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"); brcmf_err("Not all proto handlers have been installed\n");
goto fail; goto fail;
} }

View File

@ -48,6 +48,7 @@ struct brcmf_proto {
void (*del_if)(struct brcmf_if *ifp); void (*del_if)(struct brcmf_if *ifp);
void (*reset_if)(struct brcmf_if *ifp); void (*reset_if)(struct brcmf_if *ifp);
int (*init_done)(struct brcmf_pub *drvr); int (*init_done)(struct brcmf_pub *drvr);
void (*debugfs_create)(struct brcmf_pub *drvr);
void *pd; void *pd;
}; };
@ -156,4 +157,10 @@ brcmf_proto_init_done(struct brcmf_pub *drvr)
return drvr->proto->init_done(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 */ #endif /* BRCMFMAC_PROTO_H */

View File

@ -600,47 +600,44 @@ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
{4, 0x1} {4, 0x1}
}; };
BRCMF_FW_NVRAM_DEF(43143, "brcmfmac43143-sdio.bin", "brcmfmac43143-sdio.txt"); BRCMF_FW_DEF(43143, "brcmfmac43143-sdio");
BRCMF_FW_NVRAM_DEF(43241B0, "brcmfmac43241b0-sdio.bin", BRCMF_FW_DEF(43241B0, "brcmfmac43241b0-sdio");
"brcmfmac43241b0-sdio.txt"); BRCMF_FW_DEF(43241B4, "brcmfmac43241b4-sdio");
BRCMF_FW_NVRAM_DEF(43241B4, "brcmfmac43241b4-sdio.bin", BRCMF_FW_DEF(43241B5, "brcmfmac43241b5-sdio");
"brcmfmac43241b4-sdio.txt"); BRCMF_FW_DEF(4329, "brcmfmac4329-sdio");
BRCMF_FW_NVRAM_DEF(43241B5, "brcmfmac43241b5-sdio.bin", BRCMF_FW_DEF(4330, "brcmfmac4330-sdio");
"brcmfmac43241b5-sdio.txt"); BRCMF_FW_DEF(4334, "brcmfmac4334-sdio");
BRCMF_FW_NVRAM_DEF(4329, "brcmfmac4329-sdio.bin", "brcmfmac4329-sdio.txt"); BRCMF_FW_DEF(43340, "brcmfmac43340-sdio");
BRCMF_FW_NVRAM_DEF(4330, "brcmfmac4330-sdio.bin", "brcmfmac4330-sdio.txt"); BRCMF_FW_DEF(4335, "brcmfmac4335-sdio");
BRCMF_FW_NVRAM_DEF(4334, "brcmfmac4334-sdio.bin", "brcmfmac4334-sdio.txt"); BRCMF_FW_DEF(43362, "brcmfmac43362-sdio");
BRCMF_FW_NVRAM_DEF(43340, "brcmfmac43340-sdio.bin", "brcmfmac43340-sdio.txt"); BRCMF_FW_DEF(4339, "brcmfmac4339-sdio");
BRCMF_FW_NVRAM_DEF(4335, "brcmfmac4335-sdio.bin", "brcmfmac4335-sdio.txt"); BRCMF_FW_DEF(43430A0, "brcmfmac43430a0-sdio");
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");
/* Note the names are not postfixed with a1 for backward compatibility */ /* Note the names are not postfixed with a1 for backward compatibility */
BRCMF_FW_NVRAM_DEF(43430A1, "brcmfmac43430-sdio.bin", "brcmfmac43430-sdio.txt"); BRCMF_FW_DEF(43430A1, "brcmfmac43430-sdio");
BRCMF_FW_NVRAM_DEF(43455, "brcmfmac43455-sdio.bin", "brcmfmac43455-sdio.txt"); BRCMF_FW_DEF(43455, "brcmfmac43455-sdio");
BRCMF_FW_NVRAM_DEF(4354, "brcmfmac4354-sdio.bin", "brcmfmac4354-sdio.txt"); BRCMF_FW_DEF(4354, "brcmfmac4354-sdio");
BRCMF_FW_NVRAM_DEF(4356, "brcmfmac4356-sdio.bin", "brcmfmac4356-sdio.txt"); BRCMF_FW_DEF(4356, "brcmfmac4356-sdio");
BRCMF_FW_NVRAM_DEF(4373, "brcmfmac4373-sdio.bin", "brcmfmac4373-sdio.txt"); BRCMF_FW_DEF(4373, "brcmfmac4373-sdio");
static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { static struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0), BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4), BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43241_CHIP_ID, 0xFFFFFFC0, 43241B5), BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0xFFFFFFC0, 43241B5),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, 4329), BRCMF_FW_ENTRY(BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, 4329),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, 4330), BRCMF_FW_ENTRY(BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, 4330),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, 4334), BRCMF_FW_ENTRY(BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, 4334),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, 43340), BRCMF_FW_ENTRY(BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, 43340),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43340), BRCMF_FW_ENTRY(BRCM_CC_43341_CHIP_ID, 0xFFFFFFFF, 43340),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335), BRCMF_FW_ENTRY(BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, 4335),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362), BRCMF_FW_ENTRY(BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, 43362),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339), BRCMF_FW_ENTRY(BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, 4339),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0), BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0x00000001, 43430A0),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1), BRCMF_FW_ENTRY(BRCM_CC_43430_CHIP_ID, 0xFFFFFFFE, 43430A1),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455), BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFFC0, 43455),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
BRCMF_FW_NVRAM_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373) BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373)
}; };
static void pkt_align(struct sk_buff *p, int len, int align) 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, static
u8 *fw_name) 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_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_fw_request *fwreq;
int ret = 0; struct brcmf_fw_name fwnames[] = {
{ ext, fw_name },
};
if (sdiodev->fw_name[0] != '\0') fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
strlcpy(fw_name, sdiodev->fw_name, BRCMF_FW_NAME_LEN); brcmf_sdio_fwnames,
else ARRAY_SIZE(brcmf_sdio_fwnames),
ret = brcmf_fw_map_chip_to_name(chip, chiprev, fwnames, ARRAY_SIZE(fwnames));
brcmf_sdio_fwnames, if (!fwreq)
ARRAY_SIZE(brcmf_sdio_fwnames), return -ENOMEM;
fw_name, NULL);
return ret; kfree(fwreq);
return 0;
} }
static const struct brcmf_bus_ops brcmf_sdio_bus_ops = { 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, .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, static void brcmf_sdio_firmware_callback(struct device *dev, int err,
const struct firmware *code, struct brcmf_fw_request *fwreq)
void *nvram, u32 nvram_len)
{ {
struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiod = bus_if->bus_priv.sdio; struct brcmf_sdio_dev *sdiod = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiod->bus; struct brcmf_sdio *bus = sdiod->bus;
struct brcmf_core *core = bus->sdio_core; struct brcmf_core *core = bus->sdio_core;
const struct firmware *code;
void *nvram;
u32 nvram_len;
u8 saveclk; u8 saveclk;
brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err); 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) if (err)
goto fail; 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 */ /* try to download image and nvram to the dongle */
bus->alp_only = true; bus->alp_only = true;
err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len); err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
@ -4148,11 +4157,34 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
device_release_driver(dev); 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) struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
{ {
int ret; int ret;
struct brcmf_sdio *bus; struct brcmf_sdio *bus;
struct workqueue_struct *wq; struct workqueue_struct *wq;
struct brcmf_fw_request *fwreq;
brcmf_dbg(TRACE, "Enter\n"); 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"); brcmf_dbg(INFO, "completed!!\n");
ret = brcmf_fw_map_chip_to_name(bus->ci->chip, bus->ci->chiprev, fwreq = brcmf_sdio_prepare_fw_request(bus);
brcmf_sdio_fwnames, if (!fwreq) {
ARRAY_SIZE(brcmf_sdio_fwnames), ret = -ENOMEM;
sdiodev->fw_name, sdiodev->nvram_name);
if (ret)
goto fail; goto fail;
}
ret = brcmf_fw_get_firmwares(sdiodev->dev, BRCMF_FW_REQUEST_NVRAM, ret = brcmf_fw_get_firmwares(sdiodev->dev, fwreq,
sdiodev->fw_name, sdiodev->nvram_name,
brcmf_sdio_firmware_callback); brcmf_sdio_firmware_callback);
if (ret != 0) { if (ret != 0) {
brcmf_err("async firmware request failed: %d\n", ret); brcmf_err("async firmware request failed: %d\n", ret);
kfree(fwreq);
goto fail; goto fail;
} }

View File

@ -46,11 +46,11 @@
#define BRCMF_USB_CBCTL_READ 1 #define BRCMF_USB_CBCTL_READ 1
#define BRCMF_USB_MAX_PKT_SIZE 1600 #define BRCMF_USB_MAX_PKT_SIZE 1600
BRCMF_FW_DEF(43143, "brcmfmac43143.bin"); BRCMF_FW_DEF(43143, "brcmfmac43143");
BRCMF_FW_DEF(43236B, "brcmfmac43236b.bin"); BRCMF_FW_DEF(43236B, "brcmfmac43236b");
BRCMF_FW_DEF(43242A, "brcmfmac43242a.bin"); BRCMF_FW_DEF(43242A, "brcmfmac43242a");
BRCMF_FW_DEF(43569, "brcmfmac43569.bin"); BRCMF_FW_DEF(43569, "brcmfmac43569");
BRCMF_FW_DEF(4373, "brcmfmac4373.bin"); BRCMF_FW_DEF(4373, "brcmfmac4373");
static struct brcmf_firmware_mapping brcmf_usb_fwnames[] = { static struct brcmf_firmware_mapping brcmf_usb_fwnames[] = {
BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143), 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); device_set_wakeup_enable(devinfo->dev, false);
} }
static int brcmf_usb_get_fwname(struct device *dev, u32 chip, u32 chiprev, static
u8 *fw_name) int brcmf_usb_get_fwname(struct device *dev, const char *ext, u8 *fw_name)
{ {
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev); struct brcmf_bus *bus = dev_get_drvdata(dev);
int ret = 0; struct brcmf_fw_request *fwreq;
struct brcmf_fw_name fwnames[] = {
{ ext, fw_name },
};
if (devinfo->fw_name[0] != '\0') fwreq = brcmf_fw_alloc_request(bus->chip, bus->chiprev,
strlcpy(fw_name, devinfo->fw_name, BRCMF_FW_NAME_LEN); brcmf_usb_fwnames,
else ARRAY_SIZE(brcmf_usb_fwnames),
ret = brcmf_fw_map_chip_to_name(chip, chiprev, fwnames, ARRAY_SIZE(fwnames));
brcmf_usb_fwnames, if (!fwreq)
ARRAY_SIZE(brcmf_usb_fwnames), return -ENOMEM;
fw_name, NULL);
return ret; kfree(fwreq);
return 0;
} }
static const struct brcmf_bus_ops brcmf_usb_bus_ops = { 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, .get_fwname = brcmf_usb_get_fwname,
}; };
#define BRCMF_USB_FW_CODE 0
static void brcmf_usb_probe_phase2(struct device *dev, int ret, static void brcmf_usb_probe_phase2(struct device *dev, int ret,
const struct firmware *fw, struct brcmf_fw_request *fwreq)
void *nvram, u32 nvlen)
{ {
struct brcmf_bus *bus = dev_get_drvdata(dev); struct brcmf_bus *bus = dev_get_drvdata(dev);
struct brcmf_usbdev_info *devinfo = bus->bus_priv.usb->devinfo; struct brcmf_usbdev_info *devinfo = bus->bus_priv.usb->devinfo;
const struct firmware *fw;
if (ret) if (ret)
goto error; goto error;
brcmf_dbg(USB, "Start fw downloading\n"); brcmf_dbg(USB, "Start fw downloading\n");
fw = fwreq->items[BRCMF_USB_FW_CODE].binary;
kfree(fwreq);
ret = check_file(fw->data); ret = check_file(fw->data);
if (ret < 0) { if (ret < 0) {
brcmf_err("invalid firmware\n"); brcmf_err("invalid firmware\n");
@ -1195,11 +1203,33 @@ static void brcmf_usb_probe_phase2(struct device *dev, int ret,
device_release_driver(dev); 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) static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
{ {
struct brcmf_bus *bus = NULL; struct brcmf_bus *bus = NULL;
struct brcmf_usbdev *bus_pub = NULL; struct brcmf_usbdev *bus_pub = NULL;
struct device *dev = devinfo->dev; struct device *dev = devinfo->dev;
struct brcmf_fw_request *fwreq;
int ret; int ret;
brcmf_dbg(USB, "Enter\n"); 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->chip = bus_pub->devid;
bus->chiprev = bus_pub->chiprev; bus->chiprev = bus_pub->chiprev;
ret = brcmf_fw_map_chip_to_name(bus_pub->devid, bus_pub->chiprev, fwreq = brcmf_usb_prepare_fw_request(devinfo);
brcmf_usb_fwnames, if (!fwreq) {
ARRAY_SIZE(brcmf_usb_fwnames), ret = -ENOMEM;
devinfo->fw_name, NULL);
if (ret)
goto fail; goto fail;
}
/* request firmware here */ /* request firmware here */
ret = brcmf_fw_get_firmwares(dev, 0, devinfo->fw_name, NULL, ret = brcmf_fw_get_firmwares(dev, fwreq, brcmf_usb_probe_phase2);
brcmf_usb_probe_phase2);
if (ret) { if (ret) {
brcmf_err("firmware request failed: %d\n", ret); brcmf_err("firmware request failed: %d\n", ret);
kfree(fwreq);
goto fail; 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 usb_device *usb = interface_to_usbdev(intf);
struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev); struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
struct brcmf_fw_request *fwreq;
int ret;
brcmf_dbg(USB, "Enter\n"); brcmf_dbg(USB, "Enter\n");
return brcmf_fw_get_firmwares(&usb->dev, 0, devinfo->fw_name, NULL, fwreq = brcmf_usb_prepare_fw_request(devinfo);
brcmf_usb_probe_phase2); 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) \ #define BRCMF_USB_DEVICE(dev_id) \

View File

@ -214,7 +214,7 @@ brcms_debugfs_add_entry(struct brcms_pub *drvr, const char *fn,
entry->read = read_fn; entry->read = read_fn;
entry->drvr = drvr; entry->drvr = drvr;
dentry = debugfs_create_file(fn, S_IRUGO, dentry, entry, dentry = debugfs_create_file(fn, 0444, dentry, entry,
&brcms_debugfs_def_ops); &brcms_debugfs_def_ops);
return PTR_ERR_OR_ZERO(dentry); return PTR_ERR_OR_ZERO(dentry);

View File

@ -108,7 +108,7 @@ MODULE_DEVICE_TABLE(bcma, brcms_coreid_table);
* flags are specified by the BRCM_DL_* macros in * flags are specified by the BRCM_DL_* macros in
* drivers/net/wireless/brcm80211/include/defs.h. * 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 #endif
static struct ieee80211_channel brcms_2ghz_chantable[] = { 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) 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) { if (le32_to_cpu(hdr->idx) == idx) {
pdata = wl->fw.fw_bin[i]->data + pdata = wl->fw.fw_bin[i]->data +
le32_to_cpu(hdr->offset); le32_to_cpu(hdr->offset);
*pbuf = kmemdup(pdata, len, GFP_ATOMIC); *pbuf = kmemdup(pdata, len, GFP_KERNEL);
if (*pbuf == NULL) if (*pbuf == NULL)
goto fail; goto fail;

View File

@ -4519,21 +4519,21 @@ static int setup_proc_entry( struct net_device *dev,
proc_set_user(apriv->proc_entry, proc_kuid, proc_kgid); proc_set_user(apriv->proc_entry, proc_kuid, proc_kgid);
/* Setup the StatsDelta */ /* 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); apriv->proc_entry, &proc_statsdelta_ops, dev);
if (!entry) if (!entry)
goto fail; goto fail;
proc_set_user(entry, proc_kuid, proc_kgid); proc_set_user(entry, proc_kuid, proc_kgid);
/* Setup the Stats */ /* 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); apriv->proc_entry, &proc_stats_ops, dev);
if (!entry) if (!entry)
goto fail; goto fail;
proc_set_user(entry, proc_kuid, proc_kgid); proc_set_user(entry, proc_kuid, proc_kgid);
/* Setup the Status */ /* 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); apriv->proc_entry, &proc_status_ops, dev);
if (!entry) if (!entry)
goto fail; goto fail;

View File

@ -3538,7 +3538,7 @@ static ssize_t show_pci(struct device *d, struct device_attribute *attr,
return out - buf; 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, static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
char *buf) 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); 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, static ssize_t show_status(struct device *d, struct device_attribute *attr,
char *buf) 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); 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, static ssize_t show_capability(struct device *d, struct device_attribute *attr,
char *buf) 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); 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 } #define IPW2100_REG(x) { IPW_ ##x, #x }
static const struct { static const struct {
@ -3822,7 +3822,7 @@ static ssize_t show_registers(struct device *d, struct device_attribute *attr,
return out - buf; 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, static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
char *buf) char *buf)
@ -3863,7 +3863,7 @@ static ssize_t show_hardware(struct device *d, struct device_attribute *attr,
return out - buf; 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, static ssize_t show_memory(struct device *d, struct device_attribute *attr,
char *buf) char *buf)
@ -3957,7 +3957,7 @@ static ssize_t store_memory(struct device *d, struct device_attribute *attr,
return count; 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, static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
char *buf) char *buf)
@ -3993,7 +3993,7 @@ static ssize_t show_ordinals(struct device *d, struct device_attribute *attr,
return len; 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, static ssize_t show_stats(struct device *d, struct device_attribute *attr,
char *buf) char *buf)
@ -4014,7 +4014,7 @@ static ssize_t show_stats(struct device *d, struct device_attribute *attr,
return out - buf; 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) 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; 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, static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
char *buf) char *buf)
@ -4157,7 +4157,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr,
return out - buf; return out - buf;
} }
static DEVICE_ATTR(bssinfo, S_IRUGO, show_bssinfo, NULL); static DEVICE_ATTR(bssinfo, 0444, show_bssinfo, NULL);
#ifdef CONFIG_IPW2100_DEBUG #ifdef CONFIG_IPW2100_DEBUG
static ssize_t debug_level_show(struct device_driver *d, char *buf) 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; return count;
} }
static DEVICE_ATTR(fatal_error, S_IWUSR | S_IRUGO, show_fatal_error, static DEVICE_ATTR(fatal_error, 0644, show_fatal_error, store_fatal_error);
store_fatal_error);
static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, static ssize_t show_scan_age(struct device *d, struct device_attribute *attr,
char *buf) char *buf)
@ -4250,7 +4249,7 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr,
return strnlen(buf, count); 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, static ssize_t show_rf_kill(struct device *d, struct device_attribute *attr,
char *buf) char *buf)
@ -4304,7 +4303,7 @@ static ssize_t store_rf_kill(struct device *d, struct device_attribute *attr,
return count; 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[] = { static struct attribute *ipw2100_sysfs_entries[] = {
&dev_attr_hardware.attr, &dev_attr_hardware.attr,

View File

@ -1303,7 +1303,7 @@ static ssize_t show_event_log(struct device *d,
return len; 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, static ssize_t show_error(struct device *d,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
@ -1351,7 +1351,7 @@ static ssize_t clear_error(struct device *d,
return count; 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, static ssize_t show_cmd_log(struct device *d,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
@ -1378,7 +1378,7 @@ static ssize_t show_cmd_log(struct device *d,
return len; 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 #ifdef CONFIG_IPW2200_PROMISCUOUS
static void ipw_prom_free(struct ipw_priv *priv); 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, static DEVICE_ATTR(rtap_iface, 0600, show_rtap_iface, store_rtap_iface);
store_rtap_iface);
static ssize_t store_rtap_filter(struct device *d, static ssize_t store_rtap_filter(struct device *d,
struct device_attribute *attr, 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); priv->prom_priv ? priv->prom_priv->filter : 0);
} }
static DEVICE_ATTR(rtap_filter, S_IWUSR | S_IRUSR, show_rtap_filter, static DEVICE_ATTR(rtap_filter, 0600, show_rtap_filter, store_rtap_filter);
store_rtap_filter);
#endif #endif
static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, 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; 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, static ssize_t show_led(struct device *d, struct device_attribute *attr,
char *buf) char *buf)
@ -1553,7 +1551,7 @@ static ssize_t store_led(struct device *d, struct device_attribute *attr,
return count; 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, static ssize_t show_status(struct device *d,
struct device_attribute *attr, char *buf) 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); 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, static ssize_t show_cfg(struct device *d, struct device_attribute *attr,
char *buf) 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); 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, static ssize_t show_nic_type(struct device *d,
struct device_attribute *attr, char *buf) 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); 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, static ssize_t show_ucode_version(struct device *d,
struct device_attribute *attr, char *buf) 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); 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, static ssize_t show_rtc(struct device *d, struct device_attribute *attr,
char *buf) 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); 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 * 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); return strnlen(buf, count);
} }
static DEVICE_ATTR(eeprom_delay, S_IWUSR | S_IRUGO, static DEVICE_ATTR(eeprom_delay, 0644, show_eeprom_delay, store_eeprom_delay);
show_eeprom_delay, store_eeprom_delay);
static ssize_t show_command_event_reg(struct device *d, static ssize_t show_command_event_reg(struct device *d,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
@ -1654,7 +1651,7 @@ static ssize_t store_command_event_reg(struct device *d,
return strnlen(buf, count); 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); show_command_event_reg, store_command_event_reg);
static ssize_t show_mem_gpio_reg(struct device *d, 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); return strnlen(buf, count);
} }
static DEVICE_ATTR(mem_gpio_reg, S_IWUSR | S_IRUGO, static DEVICE_ATTR(mem_gpio_reg, 0644, show_mem_gpio_reg, store_mem_gpio_reg);
show_mem_gpio_reg, store_mem_gpio_reg);
static ssize_t show_indirect_dword(struct device *d, static ssize_t show_indirect_dword(struct device *d,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
@ -1705,7 +1701,7 @@ static ssize_t store_indirect_dword(struct device *d,
return strnlen(buf, count); 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); show_indirect_dword, store_indirect_dword);
static ssize_t show_indirect_byte(struct device *d, 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); 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); show_indirect_byte, store_indirect_byte);
static ssize_t show_direct_dword(struct device *d, 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); return strnlen(buf, count);
} }
static DEVICE_ATTR(direct_dword, S_IWUSR | S_IRUGO, static DEVICE_ATTR(direct_dword, 0644, show_direct_dword, store_direct_dword);
show_direct_dword, store_direct_dword);
static int rf_kill_active(struct ipw_priv *priv) 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; 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, static ssize_t show_speed_scan(struct device *d, struct device_attribute *attr,
char *buf) char *buf)
@ -1884,8 +1879,7 @@ static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr,
return count; return count;
} }
static DEVICE_ATTR(speed_scan, S_IWUSR | S_IRUGO, show_speed_scan, static DEVICE_ATTR(speed_scan, 0644, show_speed_scan, store_speed_scan);
store_speed_scan);
static ssize_t show_net_stats(struct device *d, struct device_attribute *attr, static ssize_t show_net_stats(struct device *d, struct device_attribute *attr,
char *buf) char *buf)
@ -1906,8 +1900,7 @@ static ssize_t store_net_stats(struct device *d, struct device_attribute *attr,
return count; return count;
} }
static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, static DEVICE_ATTR(net_stats, 0644, show_net_stats, store_net_stats);
show_net_stats, store_net_stats);
static ssize_t show_channels(struct device *d, static ssize_t show_channels(struct device *d,
struct device_attribute *attr, struct device_attribute *attr,
@ -1953,7 +1946,7 @@ static ssize_t show_channels(struct device *d,
return len; 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) static void notify_wx_assoc_event(struct ipw_priv *priv)
{ {

View File

@ -276,7 +276,7 @@ static int __init libipw_init(void)
" proc directory\n"); " proc directory\n");
return -EIO; 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); &debug_level_proc_fops);
if (!e) { if (!e) {
remove_proc_entry(DRV_PROCNAME, init_net.proc_net); remove_proc_entry(DRV_PROCNAME, init_net.proc_net);

View File

@ -3122,7 +3122,7 @@ il3945_store_debug_level(struct device *d, struct device_attribute *attr,
return strnlen(buf, count); 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); il3945_store_debug_level);
#endif /* CONFIG_IWLEGACY_DEBUG */ #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)); 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 static ssize_t
il3945_show_tx_power(struct device *d, struct device_attribute *attr, char *buf) 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; return count;
} }
static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, il3945_show_tx_power, static DEVICE_ATTR(tx_power, 0644, il3945_show_tx_power, il3945_store_tx_power);
il3945_store_tx_power);
static ssize_t static ssize_t
il3945_show_flags(struct device *d, struct device_attribute *attr, char *buf) 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; return count;
} }
static DEVICE_ATTR(flags, S_IWUSR | S_IRUGO, il3945_show_flags, static DEVICE_ATTR(flags, 0644, il3945_show_flags, il3945_store_flags);
il3945_store_flags);
static ssize_t static ssize_t
il3945_show_filter_flags(struct device *d, struct device_attribute *attr, 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; 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); il3945_store_filter_flags);
static ssize_t static ssize_t
@ -3306,7 +3304,7 @@ il3945_store_measurement(struct device *d, struct device_attribute *attr,
return count; return count;
} }
static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, il3945_show_measurement, static DEVICE_ATTR(measurement, 0600, il3945_show_measurement,
il3945_store_measurement); il3945_store_measurement);
static ssize_t 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); 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); il3945_store_retry_rate);
static ssize_t static ssize_t
@ -3340,7 +3338,7 @@ il3945_show_channels(struct device *d, struct device_attribute *attr, char *buf)
return 0; return 0;
} }
static DEVICE_ATTR(channels, S_IRUSR, il3945_show_channels, NULL); static DEVICE_ATTR(channels, 0400, il3945_show_channels, NULL);
static ssize_t static ssize_t
il3945_show_antenna(struct device *d, struct device_attribute *attr, char *buf) 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; return count;
} }
static DEVICE_ATTR(antenna, S_IWUSR | S_IRUGO, il3945_show_antenna, static DEVICE_ATTR(antenna, 0644, il3945_show_antenna, il3945_store_antenna);
il3945_store_antenna);
static ssize_t static ssize_t
il3945_show_status(struct device *d, struct device_attribute *attr, char *buf) 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); 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 static ssize_t
il3945_dump_error_log(struct device *d, struct device_attribute *attr, 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); 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_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_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_PARM_DESC(swcrypto, "using software crypto (default 1 [software])");
module_param_named(disable_hw_scan, il3945_mod_params.disable_hw_scan, int, 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)"); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 1)");
#ifdef CONFIG_IWLEGACY_DEBUG #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"); MODULE_PARM_DESC(debug, "debug output mask");
#endif #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_PARM_DESC(fw_restart, "restart firmware in case of error");
module_exit(il3945_exit); module_exit(il3945_exit);

View File

@ -4591,7 +4591,7 @@ il4965_store_debug_level(struct device *d, struct device_attribute *attr,
return strnlen(buf, count); 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); il4965_store_debug_level);
#endif /* CONFIG_IWLEGACY_DEBUG */ #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); 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 static ssize_t
il4965_show_tx_power(struct device *d, struct device_attribute *attr, char *buf) 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; 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); il4965_store_tx_power);
static struct attribute *il_sysfs_entries[] = { static struct attribute *il_sysfs_entries[] = {
@ -6859,18 +6859,17 @@ module_exit(il4965_exit);
module_init(il4965_init); module_init(il4965_init);
#ifdef CONFIG_IWLEGACY_DEBUG #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"); MODULE_PARM_DESC(debug, "debug output mask");
#endif #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_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_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_PARM_DESC(11n_disable, "disable 11n functionality");
module_param_named(amsdu_size_8K, il4965_mod_params.amsdu_size_8K, int, module_param_named(amsdu_size_8K, il4965_mod_params.amsdu_size_8K, int, 0444);
S_IRUGO);
MODULE_PARM_DESC(amsdu_size_8K, "enable 8K amsdu size (default 0 [disabled])"); 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"); MODULE_PARM_DESC(fw_restart, "restart firmware in case of error");

Some files were not shown because too many files have changed in this diff Show More