Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git
ath.git patches for 4.17. Major changes: wil6210 * support multiple virtual interfaces
This commit is contained in:
commit
abd5f00844
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -2439,7 +2440,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
|
|||
|
||||
ret = ath10k_hif_power_up(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "could not start pci hif (%d)\n", ret);
|
||||
ath10k_err(ar, "could not power on hif bus (%d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -324,6 +325,27 @@ struct ath10k_tpc_stats {
|
|||
struct ath10k_tpc_table tpc_table[WMI_TPC_FLAG];
|
||||
};
|
||||
|
||||
struct ath10k_tpc_table_final {
|
||||
u32 pream_idx[WMI_TPC_FINAL_RATE_MAX];
|
||||
u8 rate_code[WMI_TPC_FINAL_RATE_MAX];
|
||||
char tpc_value[WMI_TPC_FINAL_RATE_MAX][WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE];
|
||||
};
|
||||
|
||||
struct ath10k_tpc_stats_final {
|
||||
u32 reg_domain;
|
||||
u32 chan_freq;
|
||||
u32 phy_mode;
|
||||
u32 twice_antenna_reduction;
|
||||
u32 twice_max_rd_power;
|
||||
s32 twice_antenna_gain;
|
||||
u32 power_limit;
|
||||
u32 num_tx_chain;
|
||||
u32 ctl;
|
||||
u32 rate_max;
|
||||
u8 flag[WMI_TPC_FLAG];
|
||||
struct ath10k_tpc_table_final tpc_table_final[WMI_TPC_FLAG];
|
||||
};
|
||||
|
||||
struct ath10k_dfs_stats {
|
||||
u32 phy_errors;
|
||||
u32 pulses_total;
|
||||
|
@ -354,6 +376,45 @@ struct ath10k_txq {
|
|||
unsigned long num_push_allowed;
|
||||
};
|
||||
|
||||
enum ath10k_pkt_rx_err {
|
||||
ATH10K_PKT_RX_ERR_FCS,
|
||||
ATH10K_PKT_RX_ERR_TKIP,
|
||||
ATH10K_PKT_RX_ERR_CRYPT,
|
||||
ATH10K_PKT_RX_ERR_PEER_IDX_INVAL,
|
||||
ATH10K_PKT_RX_ERR_MAX,
|
||||
};
|
||||
|
||||
enum ath10k_ampdu_subfrm_num {
|
||||
ATH10K_AMPDU_SUBFRM_NUM_10,
|
||||
ATH10K_AMPDU_SUBFRM_NUM_20,
|
||||
ATH10K_AMPDU_SUBFRM_NUM_30,
|
||||
ATH10K_AMPDU_SUBFRM_NUM_40,
|
||||
ATH10K_AMPDU_SUBFRM_NUM_50,
|
||||
ATH10K_AMPDU_SUBFRM_NUM_60,
|
||||
ATH10K_AMPDU_SUBFRM_NUM_MORE,
|
||||
ATH10K_AMPDU_SUBFRM_NUM_MAX,
|
||||
};
|
||||
|
||||
enum ath10k_amsdu_subfrm_num {
|
||||
ATH10K_AMSDU_SUBFRM_NUM_1,
|
||||
ATH10K_AMSDU_SUBFRM_NUM_2,
|
||||
ATH10K_AMSDU_SUBFRM_NUM_3,
|
||||
ATH10K_AMSDU_SUBFRM_NUM_4,
|
||||
ATH10K_AMSDU_SUBFRM_NUM_MORE,
|
||||
ATH10K_AMSDU_SUBFRM_NUM_MAX,
|
||||
};
|
||||
|
||||
struct ath10k_sta_tid_stats {
|
||||
unsigned long int rx_pkt_from_fw;
|
||||
unsigned long int rx_pkt_unchained;
|
||||
unsigned long int rx_pkt_drop_chained;
|
||||
unsigned long int rx_pkt_drop_filter;
|
||||
unsigned long int rx_pkt_err[ATH10K_PKT_RX_ERR_MAX];
|
||||
unsigned long int rx_pkt_queued_for_mac;
|
||||
unsigned long int rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MAX];
|
||||
unsigned long int rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MAX];
|
||||
};
|
||||
|
||||
struct ath10k_sta {
|
||||
struct ath10k_vif *arvif;
|
||||
|
||||
|
@ -371,6 +432,9 @@ struct ath10k_sta {
|
|||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
/* protected by conf_mutex */
|
||||
bool aggr_mode;
|
||||
|
||||
/* Protected with ar->data_lock */
|
||||
struct ath10k_sta_tid_stats tid_stats[IEEE80211_NUM_TIDS + 1];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -487,6 +551,7 @@ struct ath10k_debug {
|
|||
|
||||
/* used for tpc-dump storage, protected by data-lock */
|
||||
struct ath10k_tpc_stats *tpc_stats;
|
||||
struct ath10k_tpc_stats_final *tpc_stats_final;
|
||||
|
||||
struct completion tpc_complete;
|
||||
|
||||
|
@ -1019,6 +1084,8 @@ struct ath10k {
|
|||
|
||||
void *ce_priv;
|
||||
|
||||
u32 sta_tid_stats_mask;
|
||||
|
||||
/* must be last */
|
||||
u8 drv_priv[0] __aligned(sizeof(void *));
|
||||
};
|
||||
|
|
|
@ -1480,6 +1480,19 @@ void ath10k_debug_tpc_stats_process(struct ath10k *ar,
|
|||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
void
|
||||
ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
|
||||
struct ath10k_tpc_stats_final *tpc_stats)
|
||||
{
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
kfree(ar->debug.tpc_stats_final);
|
||||
ar->debug.tpc_stats_final = tpc_stats;
|
||||
complete(&ar->debug.tpc_complete);
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats,
|
||||
unsigned int j, char *buf, size_t *len)
|
||||
{
|
||||
|
@ -2143,6 +2156,137 @@ static const struct file_operations fops_fw_checksums = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t ath10k_sta_tid_stats_mask_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
char buf[32];
|
||||
size_t len;
|
||||
|
||||
len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->sta_tid_stats_mask);
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static ssize_t ath10k_sta_tid_stats_mask_write(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
char buf[32];
|
||||
ssize_t len;
|
||||
u32 mask;
|
||||
|
||||
len = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, len))
|
||||
return -EFAULT;
|
||||
|
||||
buf[len] = '\0';
|
||||
if (kstrtoint(buf, 0, &mask))
|
||||
return -EINVAL;
|
||||
|
||||
ar->sta_tid_stats_mask = mask;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_sta_tid_stats_mask = {
|
||||
.read = ath10k_sta_tid_stats_mask_read,
|
||||
.write = ath10k_sta_tid_stats_mask_write,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static int ath10k_debug_tpc_stats_final_request(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
unsigned long time_left;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
reinit_completion(&ar->debug.tpc_complete);
|
||||
|
||||
ret = ath10k_wmi_pdev_get_tpc_table_cmdid(ar, WMI_TPC_CONFIG_PARAM);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to request tpc table cmdid: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
time_left = wait_for_completion_timeout(&ar->debug.tpc_complete,
|
||||
1 * HZ);
|
||||
if (time_left == 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_tpc_stats_final_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct ath10k *ar = inode->i_private;
|
||||
void *buf;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (ar->state != ATH10K_STATE_ON) {
|
||||
ret = -ENETDOWN;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE);
|
||||
if (!buf) {
|
||||
ret = -ENOMEM;
|
||||
goto err_unlock;
|
||||
}
|
||||
|
||||
ret = ath10k_debug_tpc_stats_final_request(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to request tpc stats final: %d\n",
|
||||
ret);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);
|
||||
file->private_data = buf;
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return 0;
|
||||
|
||||
err_free:
|
||||
vfree(buf);
|
||||
|
||||
err_unlock:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_tpc_stats_final_release(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
vfree(file->private_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t ath10k_tpc_stats_final_read(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
const char *buf = file->private_data;
|
||||
unsigned int len = strlen(buf);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_tpc_stats_final = {
|
||||
.open = ath10k_tpc_stats_final_open,
|
||||
.release = ath10k_tpc_stats_final_release,
|
||||
.read = ath10k_tpc_stats_final_read,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
int ath10k_debug_create(struct ath10k *ar)
|
||||
{
|
||||
ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
|
||||
|
@ -2258,6 +2402,16 @@ int ath10k_debug_register(struct ath10k *ar)
|
|||
debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar,
|
||||
&fops_fw_checksums);
|
||||
|
||||
if (IS_ENABLED(CONFIG_MAC80211_DEBUGFS))
|
||||
debugfs_create_file("sta_tid_stats_mask", 0600,
|
||||
ar->debug.debugfs_phy,
|
||||
ar, &fops_sta_tid_stats_mask);
|
||||
|
||||
if (test_bit(WMI_SERVICE_TPC_STATS_FINAL, ar->wmi.svc_map))
|
||||
debugfs_create_file("tpc_stats_final", 0400,
|
||||
ar->debug.debugfs_phy, ar,
|
||||
&fops_tpc_stats_final);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -101,6 +102,9 @@ void ath10k_debug_unregister(struct ath10k *ar);
|
|||
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_debug_tpc_stats_process(struct ath10k *ar,
|
||||
struct ath10k_tpc_stats *tpc_stats);
|
||||
void
|
||||
ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
|
||||
struct ath10k_tpc_stats_final *tpc_stats);
|
||||
void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
|
||||
|
||||
#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
|
||||
|
@ -164,6 +168,13 @@ static inline void ath10k_debug_tpc_stats_process(struct ath10k *ar,
|
|||
kfree(tpc_stats);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
|
||||
struct ath10k_tpc_stats_final *tpc_stats)
|
||||
{
|
||||
kfree(tpc_stats);
|
||||
}
|
||||
|
||||
static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer,
|
||||
int len)
|
||||
{
|
||||
|
@ -191,12 +202,42 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||
struct ieee80211_sta *sta, struct dentry *dir);
|
||||
void ath10k_sta_update_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats);
|
||||
void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
|
||||
unsigned long int num_msdus,
|
||||
enum ath10k_pkt_rx_err err,
|
||||
unsigned long int unchain_cnt,
|
||||
unsigned long int drop_cnt,
|
||||
unsigned long int drop_cnt_filter,
|
||||
unsigned long int queued_msdus);
|
||||
void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar,
|
||||
u16 peer_id, u8 tid,
|
||||
struct htt_rx_indication_mpdu_range *ranges,
|
||||
int num_ranges);
|
||||
#else
|
||||
static inline
|
||||
void ath10k_sta_update_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats)
|
||||
{
|
||||
}
|
||||
|
||||
static inline
|
||||
void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
|
||||
unsigned long int num_msdus,
|
||||
enum ath10k_pkt_rx_err err,
|
||||
unsigned long int unchain_cnt,
|
||||
unsigned long int drop_cnt,
|
||||
unsigned long int drop_cnt_filter,
|
||||
unsigned long int queued_msdus)
|
||||
{
|
||||
}
|
||||
|
||||
static inline
|
||||
void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar,
|
||||
u16 peer_id, u8 tid,
|
||||
struct htt_rx_indication_mpdu_range *ranges,
|
||||
int num_ranges)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_MAC80211_DEBUGFS */
|
||||
|
||||
#ifdef CONFIG_ATH10K_DEBUG
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -16,8 +17,125 @@
|
|||
|
||||
#include "core.h"
|
||||
#include "wmi-ops.h"
|
||||
#include "txrx.h"
|
||||
#include "debug.h"
|
||||
|
||||
static void ath10k_rx_stats_update_amsdu_subfrm(struct ath10k *ar,
|
||||
struct ath10k_sta_tid_stats *stats,
|
||||
u32 msdu_count)
|
||||
{
|
||||
if (msdu_count == 1)
|
||||
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_1]++;
|
||||
else if (msdu_count == 2)
|
||||
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_2]++;
|
||||
else if (msdu_count == 3)
|
||||
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_3]++;
|
||||
else if (msdu_count == 4)
|
||||
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_4]++;
|
||||
else if (msdu_count > 4)
|
||||
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MORE]++;
|
||||
}
|
||||
|
||||
static void ath10k_rx_stats_update_ampdu_subfrm(struct ath10k *ar,
|
||||
struct ath10k_sta_tid_stats *stats,
|
||||
u32 mpdu_count)
|
||||
{
|
||||
if (mpdu_count <= 10)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_10]++;
|
||||
else if (mpdu_count <= 20)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_20]++;
|
||||
else if (mpdu_count <= 30)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_30]++;
|
||||
else if (mpdu_count <= 40)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_40]++;
|
||||
else if (mpdu_count <= 50)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_50]++;
|
||||
else if (mpdu_count <= 60)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_60]++;
|
||||
else if (mpdu_count > 60)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MORE]++;
|
||||
}
|
||||
|
||||
void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid,
|
||||
struct htt_rx_indication_mpdu_range *ranges,
|
||||
int num_ranges)
|
||||
{
|
||||
struct ath10k_sta *arsta;
|
||||
struct ath10k_peer *peer;
|
||||
int i;
|
||||
|
||||
if (tid > IEEE80211_NUM_TIDS || !(ar->sta_tid_stats_mask & BIT(tid)))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
peer = ath10k_peer_find_by_id(ar, peer_id);
|
||||
if (!peer)
|
||||
goto out;
|
||||
|
||||
arsta = (struct ath10k_sta *)peer->sta->drv_priv;
|
||||
|
||||
for (i = 0; i < num_ranges; i++)
|
||||
ath10k_rx_stats_update_ampdu_subfrm(ar,
|
||||
&arsta->tid_stats[tid],
|
||||
ranges[i].mpdu_count);
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
|
||||
unsigned long int num_msdus,
|
||||
enum ath10k_pkt_rx_err err,
|
||||
unsigned long int unchain_cnt,
|
||||
unsigned long int drop_cnt,
|
||||
unsigned long int drop_cnt_filter,
|
||||
unsigned long int queued_msdus)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath10k_sta *arsta;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ath10k_sta_tid_stats *stats;
|
||||
u8 tid = IEEE80211_NUM_TIDS;
|
||||
bool non_data_frm = false;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)first_hdr;
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
non_data_frm = true;
|
||||
|
||||
if (ieee80211_is_data_qos(hdr->frame_control))
|
||||
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
|
||||
|
||||
if (!(ar->sta_tid_stats_mask & BIT(tid)) || non_data_frm)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = ieee80211_find_sta_by_ifaddr(ar->hw, hdr->addr2, NULL);
|
||||
if (!sta)
|
||||
goto exit;
|
||||
|
||||
arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
stats = &arsta->tid_stats[tid];
|
||||
stats->rx_pkt_from_fw += num_msdus;
|
||||
stats->rx_pkt_unchained += unchain_cnt;
|
||||
stats->rx_pkt_drop_chained += drop_cnt;
|
||||
stats->rx_pkt_drop_filter += drop_cnt_filter;
|
||||
if (err != ATH10K_PKT_RX_ERR_MAX)
|
||||
stats->rx_pkt_err[err] += queued_msdus;
|
||||
stats->rx_pkt_queued_for_mac += queued_msdus;
|
||||
ath10k_rx_stats_update_amsdu_subfrm(ar, &arsta->tid_stats[tid],
|
||||
num_msdus);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
exit:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats)
|
||||
{
|
||||
|
@ -342,6 +460,172 @@ static const struct file_operations fops_peer_debug_trigger = {
|
|||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static char *get_err_str(enum ath10k_pkt_rx_err i)
|
||||
{
|
||||
switch (i) {
|
||||
case ATH10K_PKT_RX_ERR_FCS:
|
||||
return "fcs_err";
|
||||
case ATH10K_PKT_RX_ERR_TKIP:
|
||||
return "tkip_err";
|
||||
case ATH10K_PKT_RX_ERR_CRYPT:
|
||||
return "crypt_err";
|
||||
case ATH10K_PKT_RX_ERR_PEER_IDX_INVAL:
|
||||
return "peer_idx_inval";
|
||||
case ATH10K_PKT_RX_ERR_MAX:
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i)
|
||||
{
|
||||
switch (i) {
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_10:
|
||||
return "upto 10";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_20:
|
||||
return "11-20";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_30:
|
||||
return "21-30";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_40:
|
||||
return "31-40";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_50:
|
||||
return "41-50";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_60:
|
||||
return "51-60";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_MORE:
|
||||
return ">60";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_MAX:
|
||||
return "0";
|
||||
}
|
||||
|
||||
return "0";
|
||||
}
|
||||
|
||||
static char *get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i)
|
||||
{
|
||||
switch (i) {
|
||||
case ATH10K_AMSDU_SUBFRM_NUM_1:
|
||||
return "1";
|
||||
case ATH10K_AMSDU_SUBFRM_NUM_2:
|
||||
return "2";
|
||||
case ATH10K_AMSDU_SUBFRM_NUM_3:
|
||||
return "3";
|
||||
case ATH10K_AMSDU_SUBFRM_NUM_4:
|
||||
return "4";
|
||||
case ATH10K_AMSDU_SUBFRM_NUM_MORE:
|
||||
return ">4";
|
||||
case ATH10K_AMSDU_SUBFRM_NUM_MAX:
|
||||
return "0";
|
||||
}
|
||||
|
||||
return "0";
|
||||
}
|
||||
|
||||
#define PRINT_TID_STATS(_field, _tabs) \
|
||||
do { \
|
||||
int k = 0; \
|
||||
for (j = 0; j <= IEEE80211_NUM_TIDS; j++) { \
|
||||
if (ar->sta_tid_stats_mask & BIT(j)) { \
|
||||
len += scnprintf(buf + len, buf_len - len, \
|
||||
"[%02d] %-10lu ", \
|
||||
j, stats[j]._field); \
|
||||
k++; \
|
||||
if (k % 8 == 0) { \
|
||||
len += scnprintf(buf + len, \
|
||||
buf_len - len, "\n"); \
|
||||
len += scnprintf(buf + len, \
|
||||
buf_len - len, \
|
||||
_tabs); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
len += scnprintf(buf + len, buf_len - len, "\n"); \
|
||||
} while (0)
|
||||
|
||||
static ssize_t ath10k_dbg_sta_read_tid_stats(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
struct ath10k_sta_tid_stats *stats = arsta->tid_stats;
|
||||
size_t len = 0, buf_len = 1048 * IEEE80211_NUM_TIDS;
|
||||
char *buf;
|
||||
int i, j;
|
||||
ssize_t ret;
|
||||
|
||||
buf = kzalloc(buf_len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"\n\t\tDriver Rx pkt stats per tid, ([tid] count)\n");
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"\t\t------------------------------------------\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "MSDUs from FW\t\t\t");
|
||||
PRINT_TID_STATS(rx_pkt_from_fw, "\t\t\t\t");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "MSDUs unchained\t\t\t");
|
||||
PRINT_TID_STATS(rx_pkt_unchained, "\t\t\t\t");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"MSDUs locally dropped:chained\t");
|
||||
PRINT_TID_STATS(rx_pkt_drop_chained, "\t\t\t\t");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"MSDUs locally dropped:filtered\t");
|
||||
PRINT_TID_STATS(rx_pkt_drop_filter, "\t\t\t\t");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"MSDUs queued for mac80211\t");
|
||||
PRINT_TID_STATS(rx_pkt_queued_for_mac, "\t\t\t\t");
|
||||
|
||||
for (i = 0; i < ATH10K_PKT_RX_ERR_MAX; i++) {
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"MSDUs with error:%s\t", get_err_str(i));
|
||||
PRINT_TID_STATS(rx_pkt_err[i], "\t\t\t\t");
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
for (i = 0; i < ATH10K_AMPDU_SUBFRM_NUM_MAX; i++) {
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"A-MPDU num subframes %s\t",
|
||||
get_num_ampdu_subfrm_str(i));
|
||||
PRINT_TID_STATS(rx_pkt_ampdu[i], "\t\t\t\t");
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
for (i = 0; i < ATH10K_AMSDU_SUBFRM_NUM_MAX; i++) {
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"A-MSDU num subframes %s\t\t",
|
||||
get_num_amsdu_subfrm_str(i));
|
||||
PRINT_TID_STATS(rx_pkt_amsdu[i], "\t\t\t\t");
|
||||
}
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_tid_stats_dump = {
|
||||
.open = simple_open,
|
||||
.read = ath10k_dbg_sta_read_tid_stats,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, struct dentry *dir)
|
||||
{
|
||||
|
@ -351,4 +635,6 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||
debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
|
||||
debugfs_create_file("peer_debug_trigger", 0600, dir, sta,
|
||||
&fops_peer_debug_trigger);
|
||||
debugfs_create_file("dump_tid_stats", 0400, dir, sta,
|
||||
&fops_tid_stats_dump);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -1502,7 +1503,9 @@ static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu)
|
|||
static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
||||
struct sk_buff_head *amsdu,
|
||||
struct ieee80211_rx_status *status,
|
||||
bool fill_crypt_header)
|
||||
bool fill_crypt_header,
|
||||
u8 *rx_hdr,
|
||||
enum ath10k_pkt_rx_err *err)
|
||||
{
|
||||
struct sk_buff *first;
|
||||
struct sk_buff *last;
|
||||
|
@ -1538,6 +1541,9 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
|||
hdr = (void *)rxd->rx_hdr_status;
|
||||
memcpy(first_hdr, hdr, RX_HTT_HDR_STATUS_LEN);
|
||||
|
||||
if (rx_hdr)
|
||||
memcpy(rx_hdr, hdr, RX_HTT_HDR_STATUS_LEN);
|
||||
|
||||
/* Each A-MSDU subframe will use the original header as the base and be
|
||||
* reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl.
|
||||
*/
|
||||
|
@ -1581,6 +1587,17 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
|
|||
if (has_tkip_err)
|
||||
status->flag |= RX_FLAG_MMIC_ERROR;
|
||||
|
||||
if (err) {
|
||||
if (has_fcs_err)
|
||||
*err = ATH10K_PKT_RX_ERR_FCS;
|
||||
else if (has_tkip_err)
|
||||
*err = ATH10K_PKT_RX_ERR_TKIP;
|
||||
else if (has_crypto_err)
|
||||
*err = ATH10K_PKT_RX_ERR_CRYPT;
|
||||
else if (has_peer_idx_invalid)
|
||||
*err = ATH10K_PKT_RX_ERR_PEER_IDX_INVAL;
|
||||
}
|
||||
|
||||
/* Firmware reports all necessary management frames via WMI already.
|
||||
* They are not reported to monitor interfaces at all so pass the ones
|
||||
* coming via HTT to monitor interfaces instead. This simplifies
|
||||
|
@ -1651,11 +1668,13 @@ static void ath10k_htt_rx_h_enqueue(struct ath10k *ar,
|
|||
}
|
||||
}
|
||||
|
||||
static int ath10k_unchain_msdu(struct sk_buff_head *amsdu)
|
||||
static int ath10k_unchain_msdu(struct sk_buff_head *amsdu,
|
||||
unsigned long int *unchain_cnt)
|
||||
{
|
||||
struct sk_buff *skb, *first;
|
||||
int space;
|
||||
int total_len = 0;
|
||||
int amsdu_len = skb_queue_len(amsdu);
|
||||
|
||||
/* TODO: Might could optimize this by using
|
||||
* skb_try_coalesce or similar method to
|
||||
|
@ -1691,11 +1710,16 @@ static int ath10k_unchain_msdu(struct sk_buff_head *amsdu)
|
|||
}
|
||||
|
||||
__skb_queue_head(amsdu, first);
|
||||
|
||||
*unchain_cnt += amsdu_len - 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_h_unchain(struct ath10k *ar,
|
||||
struct sk_buff_head *amsdu)
|
||||
struct sk_buff_head *amsdu,
|
||||
unsigned long int *drop_cnt,
|
||||
unsigned long int *unchain_cnt)
|
||||
{
|
||||
struct sk_buff *first;
|
||||
struct htt_rx_desc *rxd;
|
||||
|
@ -1713,11 +1737,12 @@ static void ath10k_htt_rx_h_unchain(struct ath10k *ar,
|
|||
*/
|
||||
if (decap != RX_MSDU_DECAP_RAW ||
|
||||
skb_queue_len(amsdu) != 1 + rxd->frag_info.ring2_more_count) {
|
||||
*drop_cnt += skb_queue_len(amsdu);
|
||||
__skb_queue_purge(amsdu);
|
||||
return;
|
||||
}
|
||||
|
||||
ath10k_unchain_msdu(amsdu);
|
||||
ath10k_unchain_msdu(amsdu, unchain_cnt);
|
||||
}
|
||||
|
||||
static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
|
||||
|
@ -1743,7 +1768,8 @@ static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
|
|||
|
||||
static void ath10k_htt_rx_h_filter(struct ath10k *ar,
|
||||
struct sk_buff_head *amsdu,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
struct ieee80211_rx_status *rx_status,
|
||||
unsigned long int *drop_cnt)
|
||||
{
|
||||
if (skb_queue_empty(amsdu))
|
||||
return;
|
||||
|
@ -1751,6 +1777,9 @@ static void ath10k_htt_rx_h_filter(struct ath10k *ar,
|
|||
if (ath10k_htt_rx_amsdu_allowed(ar, amsdu, rx_status))
|
||||
return;
|
||||
|
||||
if (drop_cnt)
|
||||
*drop_cnt += skb_queue_len(amsdu);
|
||||
|
||||
__skb_queue_purge(amsdu);
|
||||
}
|
||||
|
||||
|
@ -1760,6 +1789,12 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
|
|||
struct ieee80211_rx_status *rx_status = &htt->rx_status;
|
||||
struct sk_buff_head amsdu;
|
||||
int ret;
|
||||
unsigned long int drop_cnt = 0;
|
||||
unsigned long int unchain_cnt = 0;
|
||||
unsigned long int drop_cnt_filter = 0;
|
||||
unsigned long int msdus_to_queue, num_msdus;
|
||||
enum ath10k_pkt_rx_err err = ATH10K_PKT_RX_ERR_MAX;
|
||||
u8 first_hdr[RX_HTT_HDR_STATUS_LEN];
|
||||
|
||||
__skb_queue_head_init(&amsdu);
|
||||
|
||||
|
@ -1781,16 +1816,23 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
|
|||
return ret;
|
||||
}
|
||||
|
||||
num_msdus = skb_queue_len(&amsdu);
|
||||
|
||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
|
||||
|
||||
/* only for ret = 1 indicates chained msdus */
|
||||
if (ret > 0)
|
||||
ath10k_htt_rx_h_unchain(ar, &amsdu);
|
||||
ath10k_htt_rx_h_unchain(ar, &amsdu, &drop_cnt, &unchain_cnt);
|
||||
|
||||
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status);
|
||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true);
|
||||
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status, &drop_cnt_filter);
|
||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err);
|
||||
msdus_to_queue = skb_queue_len(&amsdu);
|
||||
ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status);
|
||||
|
||||
ath10k_sta_update_rx_tid_stats(ar, first_hdr, num_msdus, err,
|
||||
unchain_cnt, drop_cnt, drop_cnt_filter,
|
||||
msdus_to_queue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1801,9 +1843,14 @@ static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
|
|||
struct htt_rx_indication_mpdu_range *mpdu_ranges;
|
||||
int num_mpdu_ranges;
|
||||
int i, mpdu_count = 0;
|
||||
u16 peer_id;
|
||||
u8 tid;
|
||||
|
||||
num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1),
|
||||
HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
|
||||
peer_id = __le16_to_cpu(rx->hdr.peer_id);
|
||||
tid = MS(rx->hdr.info0, HTT_RX_INDICATION_INFO0_EXT_TID);
|
||||
|
||||
mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx);
|
||||
|
||||
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
|
||||
|
@ -1815,6 +1862,9 @@ static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
|
|||
mpdu_count += mpdu_ranges[i].mpdu_count;
|
||||
|
||||
atomic_add(mpdu_count, &htt->num_mpdus_ready);
|
||||
|
||||
ath10k_sta_update_rx_tid_stats_ampdu(ar, peer_id, tid, mpdu_ranges,
|
||||
num_mpdu_ranges);
|
||||
}
|
||||
|
||||
static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
|
||||
|
@ -2124,8 +2174,9 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
|
|||
* should still give an idea about rx rate to the user.
|
||||
*/
|
||||
ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
|
||||
ath10k_htt_rx_h_filter(ar, &amsdu, status);
|
||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false);
|
||||
ath10k_htt_rx_h_filter(ar, &amsdu, status, NULL);
|
||||
ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false, NULL,
|
||||
NULL);
|
||||
ath10k_htt_rx_h_enqueue(ar, &amsdu, status);
|
||||
break;
|
||||
case -EAGAIN:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -3808,6 +3809,7 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
|
|||
{
|
||||
struct ath10k *ar = container_of(work, struct ath10k, wmi_mgmt_tx_work);
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t paddr;
|
||||
int ret;
|
||||
|
||||
for (;;) {
|
||||
|
@ -3815,11 +3817,27 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
|
|||
if (!skb)
|
||||
break;
|
||||
|
||||
ret = ath10k_wmi_mgmt_tx(ar, skb);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n",
|
||||
ret);
|
||||
ieee80211_free_txskb(ar->hw, skb);
|
||||
if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
|
||||
ar->running_fw->fw_file.fw_features)) {
|
||||
paddr = dma_map_single(ar->dev, skb->data,
|
||||
skb->len, DMA_TO_DEVICE);
|
||||
if (!paddr)
|
||||
continue;
|
||||
ret = ath10k_wmi_mgmt_tx_send(ar, skb, paddr);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to transmit management frame by ref via WMI: %d\n",
|
||||
ret);
|
||||
dma_unmap_single(ar->dev, paddr, skb->len,
|
||||
DMA_FROM_DEVICE);
|
||||
ieee80211_free_txskb(ar->hw, skb);
|
||||
}
|
||||
} else {
|
||||
ret = ath10k_wmi_mgmt_tx(ar, skb);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n",
|
||||
ret);
|
||||
ieee80211_free_txskb(ar->hw, skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7085,10 +7103,20 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k_vif *arvif = (void *)vif->drv_priv;
|
||||
struct ath10k_peer *peer;
|
||||
u32 bw, smps;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
peer = ath10k_peer_find(ar, arvif->vdev_id, sta->addr);
|
||||
if (!peer) {
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
ath10k_warn(ar, "mac sta rc update failed to find peer %pM on vdev %i\n",
|
||||
sta->addr, arvif->vdev_id);
|
||||
return;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_MAC,
|
||||
"mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
|
||||
sta->addr, changed, sta->bandwidth, sta->rx_nss,
|
||||
|
|
|
@ -2221,7 +2221,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
|
|||
}
|
||||
break;
|
||||
case QCA9377_1_0_DEVICE_ID:
|
||||
return 4;
|
||||
return 9;
|
||||
}
|
||||
|
||||
ath10k_warn(ar, "unknown number of banks, assuming 1\n");
|
||||
|
|
|
@ -152,10 +152,9 @@ TRACE_EVENT(ath10k_log_dbg_dump,
|
|||
);
|
||||
|
||||
TRACE_EVENT(ath10k_wmi_cmd,
|
||||
TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len,
|
||||
int ret),
|
||||
TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len),
|
||||
|
||||
TP_ARGS(ar, id, buf, buf_len, ret),
|
||||
TP_ARGS(ar, id, buf, buf_len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
|
@ -163,7 +162,6 @@ TRACE_EVENT(ath10k_wmi_cmd,
|
|||
__field(unsigned int, id)
|
||||
__field(size_t, buf_len)
|
||||
__dynamic_array(u8, buf, buf_len)
|
||||
__field(int, ret)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
|
@ -171,17 +169,15 @@ TRACE_EVENT(ath10k_wmi_cmd,
|
|||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->id = id;
|
||||
__entry->buf_len = buf_len;
|
||||
__entry->ret = ret;
|
||||
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s id %d len %zu ret %d",
|
||||
"%s %s id %d len %zu",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__entry->id,
|
||||
__entry->buf_len,
|
||||
__entry->ret
|
||||
__entry->buf_len
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -102,11 +102,6 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
|||
memset(&info->status, 0, sizeof(info->status));
|
||||
trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id);
|
||||
|
||||
if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) {
|
||||
ieee80211_free_txskb(htt->ar->hw, msdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
|
||||
|
@ -117,6 +112,13 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
|||
(info->flags & IEEE80211_TX_CTL_NO_ACK))
|
||||
info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
|
||||
|
||||
if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) {
|
||||
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
|
||||
info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED;
|
||||
else
|
||||
info->flags &= ~IEEE80211_TX_STAT_ACK;
|
||||
}
|
||||
|
||||
ieee80211_tx_status(htt->ar->hw, msdu);
|
||||
/* we do not own the msdu anymore */
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -125,6 +126,9 @@ struct wmi_ops {
|
|||
enum wmi_force_fw_hang_type type,
|
||||
u32 delay_ms);
|
||||
struct sk_buff *(*gen_mgmt_tx)(struct ath10k *ar, struct sk_buff *skb);
|
||||
struct sk_buff *(*gen_mgmt_tx_send)(struct ath10k *ar,
|
||||
struct sk_buff *skb,
|
||||
dma_addr_t paddr);
|
||||
struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u64 module_enable,
|
||||
u32 log_level);
|
||||
struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter);
|
||||
|
@ -197,6 +201,9 @@ struct wmi_ops {
|
|||
(struct ath10k *ar,
|
||||
enum wmi_bss_survey_req_type type);
|
||||
struct sk_buff *(*gen_echo)(struct ath10k *ar, u32 value);
|
||||
struct sk_buff *(*gen_pdev_get_tpc_table_cmdid)(struct ath10k *ar,
|
||||
u32 param);
|
||||
|
||||
};
|
||||
|
||||
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
|
||||
|
@ -371,13 +378,34 @@ ath10k_wmi_get_txbf_conf_scheme(struct ath10k *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
|
||||
ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
u32 mgmt_tx_cmdid;
|
||||
|
||||
if (!ar->wmi.ops->gen_mgmt_tx)
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -386,13 +414,8 @@ ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
|
|||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
|
||||
ar->running_fw->fw_file.fw_features))
|
||||
mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_send_cmdid;
|
||||
else
|
||||
mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_cmdid;
|
||||
|
||||
ret = ath10k_wmi_cmd_send(ar, skb, mgmt_tx_cmdid);
|
||||
ret = ath10k_wmi_cmd_send(ar, skb,
|
||||
ar->wmi.cmd->mgmt_tx_cmdid);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -1425,4 +1448,21 @@ ath10k_wmi_echo(struct ath10k *ar, u32 value)
|
|||
return ath10k_wmi_cmd_send(ar, skb, wmi->cmd->echo_cmdid);
|
||||
}
|
||||
|
||||
static inline int
|
||||
ath10k_wmi_pdev_get_tpc_table_cmdid(struct ath10k *ar, u32 param)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (!ar->wmi.ops->gen_pdev_get_tpc_table_cmdid)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
skb = ar->wmi.ops->gen_pdev_get_tpc_table_cmdid(ar, param);
|
||||
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
return ath10k_wmi_cmd_send(ar, skb,
|
||||
ar->wmi.cmd->pdev_get_tpc_table_cmdid);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -2484,19 +2485,19 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
|
|||
}
|
||||
|
||||
static struct sk_buff *
|
||||
ath10k_wmi_tlv_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
|
||||
ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
|
||||
dma_addr_t paddr)
|
||||
{
|
||||
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
|
||||
struct wmi_tlv_mgmt_tx_cmd *cmd;
|
||||
struct wmi_tlv *tlv;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ath10k_vif *arvif;
|
||||
u32 buf_len = msdu->len;
|
||||
struct wmi_tlv *tlv;
|
||||
struct sk_buff *skb;
|
||||
u32 vdev_id;
|
||||
void *ptr;
|
||||
int len;
|
||||
u32 buf_len = msdu->len;
|
||||
struct ath10k_vif *arvif;
|
||||
dma_addr_t mgmt_frame_dma;
|
||||
u32 vdev_id;
|
||||
|
||||
if (!cb->vif)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
@ -2537,12 +2538,7 @@ ath10k_wmi_tlv_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
|
|||
cmd->chanfreq = 0;
|
||||
cmd->buf_len = __cpu_to_le32(buf_len);
|
||||
cmd->frame_len = __cpu_to_le32(msdu->len);
|
||||
mgmt_frame_dma = dma_map_single(arvif->ar->dev, msdu->data,
|
||||
msdu->len, DMA_TO_DEVICE);
|
||||
if (!mgmt_frame_dma)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
cmd->paddr = __cpu_to_le64(mgmt_frame_dma);
|
||||
cmd->paddr = __cpu_to_le64(paddr);
|
||||
|
||||
ptr += sizeof(*tlv);
|
||||
ptr += sizeof(*cmd);
|
||||
|
@ -3701,7 +3697,7 @@ static const struct wmi_ops wmi_tlv_ops = {
|
|||
.gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
|
||||
.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
|
||||
/* .gen_mgmt_tx = not implemented; HTT is used */
|
||||
.gen_mgmt_tx = ath10k_wmi_tlv_op_gen_mgmt_tx,
|
||||
.gen_mgmt_tx_send = ath10k_wmi_tlv_op_gen_mgmt_tx_send,
|
||||
.gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
|
||||
.gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
|
||||
.gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -196,6 +197,7 @@ static struct wmi_cmd_map wmi_cmd_map = {
|
|||
.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
};
|
||||
|
||||
/* 10.X WMI cmd track */
|
||||
|
@ -362,6 +364,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
|
|||
.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
};
|
||||
|
||||
/* 10.2.4 WMI cmd track */
|
||||
|
@ -528,6 +531,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = {
|
|||
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.pdev_bss_chan_info_request_cmdid =
|
||||
WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,
|
||||
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
};
|
||||
|
||||
/* 10.4 WMI cmd track */
|
||||
|
@ -1480,6 +1484,7 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = {
|
|||
.pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
|
||||
};
|
||||
|
||||
static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = {
|
||||
|
@ -1742,8 +1747,8 @@ int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
|
|||
cmd_hdr->cmd_id = __cpu_to_le32(cmd);
|
||||
|
||||
memset(skb_cb, 0, sizeof(*skb_cb));
|
||||
trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len);
|
||||
ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb);
|
||||
trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len, ret);
|
||||
|
||||
if (ret)
|
||||
goto err_pull;
|
||||
|
@ -4313,19 +4318,11 @@ static void ath10k_tpc_config_disp_tables(struct ath10k *ar,
|
|||
}
|
||||
}
|
||||
|
||||
void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
||||
void ath10k_wmi_tpc_config_get_rate_code(u8 *rate_code, u16 *pream_table,
|
||||
u32 num_tx_chain)
|
||||
{
|
||||
u32 i, j, pream_idx, num_tx_chain;
|
||||
u8 rate_code[WMI_TPC_RATE_MAX], rate_idx;
|
||||
u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
|
||||
struct wmi_pdev_tpc_config_event *ev;
|
||||
struct ath10k_tpc_stats *tpc_stats;
|
||||
|
||||
ev = (struct wmi_pdev_tpc_config_event *)skb->data;
|
||||
|
||||
tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
|
||||
if (!tpc_stats)
|
||||
return;
|
||||
u32 i, j, pream_idx;
|
||||
u8 rate_idx;
|
||||
|
||||
/* Create the rate code table based on the chains supported */
|
||||
rate_idx = 0;
|
||||
|
@ -4349,8 +4346,6 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
|||
pream_table[pream_idx] = rate_idx;
|
||||
pream_idx++;
|
||||
|
||||
num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
|
||||
|
||||
/* Fill HT20 rate code */
|
||||
for (i = 0; i < num_tx_chain; i++) {
|
||||
for (j = 0; j < 8; j++) {
|
||||
|
@ -4374,7 +4369,7 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
|||
pream_idx++;
|
||||
|
||||
/* Fill VHT20 rate code */
|
||||
for (i = 0; i < __le32_to_cpu(ev->num_tx_chain); i++) {
|
||||
for (i = 0; i < num_tx_chain; i++) {
|
||||
for (j = 0; j < 10; j++) {
|
||||
rate_code[rate_idx] =
|
||||
ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT);
|
||||
|
@ -4418,6 +4413,26 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
|||
ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_OFDM);
|
||||
|
||||
pream_table[pream_idx] = ATH10K_TPC_PREAM_TABLE_END;
|
||||
}
|
||||
|
||||
void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
u32 num_tx_chain;
|
||||
u8 rate_code[WMI_TPC_RATE_MAX];
|
||||
u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
|
||||
struct wmi_pdev_tpc_config_event *ev;
|
||||
struct ath10k_tpc_stats *tpc_stats;
|
||||
|
||||
ev = (struct wmi_pdev_tpc_config_event *)skb->data;
|
||||
|
||||
tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
|
||||
if (!tpc_stats)
|
||||
return;
|
||||
|
||||
num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
|
||||
|
||||
ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table,
|
||||
num_tx_chain);
|
||||
|
||||
tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq);
|
||||
tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode);
|
||||
|
@ -4457,6 +4472,246 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
|
|||
__le32_to_cpu(ev->rate_max));
|
||||
}
|
||||
|
||||
static u8
|
||||
ath10k_wmi_tpc_final_get_rate(struct ath10k *ar,
|
||||
struct wmi_pdev_tpc_final_table_event *ev,
|
||||
u32 rate_idx, u32 num_chains,
|
||||
u32 rate_code, u8 type, u32 pream_idx)
|
||||
{
|
||||
u8 tpc, num_streams, preamble, ch, stm_idx;
|
||||
s8 pow_agcdd, pow_agstbc, pow_agtxbf;
|
||||
int pream;
|
||||
|
||||
num_streams = ATH10K_HW_NSS(rate_code);
|
||||
preamble = ATH10K_HW_PREAMBLE(rate_code);
|
||||
ch = num_chains - 1;
|
||||
stm_idx = num_streams - 1;
|
||||
pream = -1;
|
||||
|
||||
if (__le32_to_cpu(ev->chan_freq) <= 2483) {
|
||||
switch (pream_idx) {
|
||||
case WMI_TPC_PREAM_2GHZ_CCK:
|
||||
pream = 0;
|
||||
break;
|
||||
case WMI_TPC_PREAM_2GHZ_OFDM:
|
||||
pream = 1;
|
||||
break;
|
||||
case WMI_TPC_PREAM_2GHZ_HT20:
|
||||
case WMI_TPC_PREAM_2GHZ_VHT20:
|
||||
pream = 2;
|
||||
break;
|
||||
case WMI_TPC_PREAM_2GHZ_HT40:
|
||||
case WMI_TPC_PREAM_2GHZ_VHT40:
|
||||
pream = 3;
|
||||
break;
|
||||
case WMI_TPC_PREAM_2GHZ_VHT80:
|
||||
pream = 4;
|
||||
break;
|
||||
default:
|
||||
pream = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (__le32_to_cpu(ev->chan_freq) >= 5180) {
|
||||
switch (pream_idx) {
|
||||
case WMI_TPC_PREAM_5GHZ_OFDM:
|
||||
pream = 0;
|
||||
break;
|
||||
case WMI_TPC_PREAM_5GHZ_HT20:
|
||||
case WMI_TPC_PREAM_5GHZ_VHT20:
|
||||
pream = 1;
|
||||
break;
|
||||
case WMI_TPC_PREAM_5GHZ_HT40:
|
||||
case WMI_TPC_PREAM_5GHZ_VHT40:
|
||||
pream = 2;
|
||||
break;
|
||||
case WMI_TPC_PREAM_5GHZ_VHT80:
|
||||
pream = 3;
|
||||
break;
|
||||
case WMI_TPC_PREAM_5GHZ_HTCUP:
|
||||
pream = 4;
|
||||
break;
|
||||
default:
|
||||
pream = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pream == 4)
|
||||
tpc = min_t(u8, ev->rates_array[rate_idx],
|
||||
ev->max_reg_allow_pow[ch]);
|
||||
else
|
||||
tpc = min_t(u8, min_t(u8, ev->rates_array[rate_idx],
|
||||
ev->max_reg_allow_pow[ch]),
|
||||
ev->ctl_power_table[0][pream][stm_idx]);
|
||||
|
||||
if (__le32_to_cpu(ev->num_tx_chain) <= 1)
|
||||
goto out;
|
||||
|
||||
if (preamble == WMI_RATE_PREAMBLE_CCK)
|
||||
goto out;
|
||||
|
||||
if (num_chains <= num_streams)
|
||||
goto out;
|
||||
|
||||
switch (type) {
|
||||
case WMI_TPC_TABLE_TYPE_STBC:
|
||||
pow_agstbc = ev->max_reg_allow_pow_agstbc[ch - 1][stm_idx];
|
||||
if (pream == 4)
|
||||
tpc = min_t(u8, tpc, pow_agstbc);
|
||||
else
|
||||
tpc = min_t(u8, min_t(u8, tpc, pow_agstbc),
|
||||
ev->ctl_power_table[0][pream][stm_idx]);
|
||||
break;
|
||||
case WMI_TPC_TABLE_TYPE_TXBF:
|
||||
pow_agtxbf = ev->max_reg_allow_pow_agtxbf[ch - 1][stm_idx];
|
||||
if (pream == 4)
|
||||
tpc = min_t(u8, tpc, pow_agtxbf);
|
||||
else
|
||||
tpc = min_t(u8, min_t(u8, tpc, pow_agtxbf),
|
||||
ev->ctl_power_table[1][pream][stm_idx]);
|
||||
break;
|
||||
case WMI_TPC_TABLE_TYPE_CDD:
|
||||
pow_agcdd = ev->max_reg_allow_pow_agcdd[ch - 1][stm_idx];
|
||||
if (pream == 4)
|
||||
tpc = min_t(u8, tpc, pow_agcdd);
|
||||
else
|
||||
tpc = min_t(u8, min_t(u8, tpc, pow_agcdd),
|
||||
ev->ctl_power_table[0][pream][stm_idx]);
|
||||
break;
|
||||
default:
|
||||
ath10k_warn(ar, "unknown wmi tpc final table type: %d\n", type);
|
||||
tpc = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return tpc;
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_wmi_tpc_stats_final_disp_tables(struct ath10k *ar,
|
||||
struct wmi_pdev_tpc_final_table_event *ev,
|
||||
struct ath10k_tpc_stats_final *tpc_stats,
|
||||
u8 *rate_code, u16 *pream_table, u8 type)
|
||||
{
|
||||
u32 i, j, pream_idx, flags;
|
||||
u8 tpc[WMI_TPC_TX_N_CHAIN];
|
||||
char tpc_value[WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE];
|
||||
char buff[WMI_TPC_BUF_SIZE];
|
||||
|
||||
flags = __le32_to_cpu(ev->flags);
|
||||
|
||||
switch (type) {
|
||||
case WMI_TPC_TABLE_TYPE_CDD:
|
||||
if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_CDD)) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "CDD not supported\n");
|
||||
tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case WMI_TPC_TABLE_TYPE_STBC:
|
||||
if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_STBC)) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "STBC not supported\n");
|
||||
tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case WMI_TPC_TABLE_TYPE_TXBF:
|
||||
if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_TXBF)) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI, "TXBF not supported\n");
|
||||
tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"invalid table type in wmi tpc event: %d\n", type);
|
||||
return;
|
||||
}
|
||||
|
||||
pream_idx = 0;
|
||||
for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) {
|
||||
memset(tpc_value, 0, sizeof(tpc_value));
|
||||
memset(buff, 0, sizeof(buff));
|
||||
if (i == pream_table[pream_idx])
|
||||
pream_idx++;
|
||||
|
||||
for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) {
|
||||
if (j >= __le32_to_cpu(ev->num_tx_chain))
|
||||
break;
|
||||
|
||||
tpc[j] = ath10k_wmi_tpc_final_get_rate(ar, ev, i, j + 1,
|
||||
rate_code[i],
|
||||
type, pream_idx);
|
||||
snprintf(buff, sizeof(buff), "%8d ", tpc[j]);
|
||||
strncat(tpc_value, buff, strlen(buff));
|
||||
}
|
||||
tpc_stats->tpc_table_final[type].pream_idx[i] = pream_idx;
|
||||
tpc_stats->tpc_table_final[type].rate_code[i] = rate_code[i];
|
||||
memcpy(tpc_stats->tpc_table_final[type].tpc_value[i],
|
||||
tpc_value, sizeof(tpc_value));
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
u32 num_tx_chain;
|
||||
u8 rate_code[WMI_TPC_FINAL_RATE_MAX];
|
||||
u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
|
||||
struct wmi_pdev_tpc_final_table_event *ev;
|
||||
struct ath10k_tpc_stats_final *tpc_stats;
|
||||
|
||||
ev = (struct wmi_pdev_tpc_final_table_event *)skb->data;
|
||||
|
||||
tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
|
||||
if (!tpc_stats)
|
||||
return;
|
||||
|
||||
num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
|
||||
|
||||
ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table,
|
||||
num_tx_chain);
|
||||
|
||||
tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq);
|
||||
tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode);
|
||||
tpc_stats->ctl = __le32_to_cpu(ev->ctl);
|
||||
tpc_stats->reg_domain = __le32_to_cpu(ev->reg_domain);
|
||||
tpc_stats->twice_antenna_gain = a_sle32_to_cpu(ev->twice_antenna_gain);
|
||||
tpc_stats->twice_antenna_reduction =
|
||||
__le32_to_cpu(ev->twice_antenna_reduction);
|
||||
tpc_stats->power_limit = __le32_to_cpu(ev->power_limit);
|
||||
tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power);
|
||||
tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
|
||||
tpc_stats->rate_max = __le32_to_cpu(ev->rate_max);
|
||||
|
||||
ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
|
||||
rate_code, pream_table,
|
||||
WMI_TPC_TABLE_TYPE_CDD);
|
||||
ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
|
||||
rate_code, pream_table,
|
||||
WMI_TPC_TABLE_TYPE_STBC);
|
||||
ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
|
||||
rate_code, pream_table,
|
||||
WMI_TPC_TABLE_TYPE_TXBF);
|
||||
|
||||
ath10k_debug_tpc_stats_final_process(ar, tpc_stats);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_WMI,
|
||||
"wmi event tpc final table channel %d mode %d ctl %d regd %d gain %d %d limit %d max_power %d tx_chanins %d rates %d\n",
|
||||
__le32_to_cpu(ev->chan_freq),
|
||||
__le32_to_cpu(ev->phy_mode),
|
||||
__le32_to_cpu(ev->ctl),
|
||||
__le32_to_cpu(ev->reg_domain),
|
||||
a_sle32_to_cpu(ev->twice_antenna_gain),
|
||||
__le32_to_cpu(ev->twice_antenna_reduction),
|
||||
__le32_to_cpu(ev->power_limit),
|
||||
__le32_to_cpu(ev->twice_max_rd_power) / 2,
|
||||
__le32_to_cpu(ev->num_tx_chain),
|
||||
__le32_to_cpu(ev->rate_max));
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_wmi_handle_tdls_peer_event(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
|
@ -5549,6 +5804,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb)
|
|||
case WMI_10_4_TDLS_PEER_EVENTID:
|
||||
ath10k_wmi_handle_tdls_peer_event(ar, skb);
|
||||
break;
|
||||
case WMI_10_4_PDEV_TPC_TABLE_EVENTID:
|
||||
ath10k_wmi_event_tpc_final_table(ar, skb);
|
||||
break;
|
||||
default:
|
||||
ath10k_warn(ar, "Unknown eventid: %d\n", id);
|
||||
break;
|
||||
|
@ -7989,6 +8247,24 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp)
|
|||
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 *
|
||||
ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar,
|
||||
const struct wmi_tdls_peer_update_cmd_arg *arg,
|
||||
|
@ -8430,6 +8706,8 @@ static const struct wmi_ops wmi_10_4_ops = {
|
|||
.ext_resource_config = ath10k_wmi_10_4_ext_resource_config,
|
||||
.gen_update_fw_tdls_state = ath10k_wmi_10_4_gen_update_fw_tdls_state,
|
||||
.gen_tdls_peer_update = ath10k_wmi_10_4_gen_tdls_peer_update,
|
||||
.gen_pdev_get_tpc_table_cmdid =
|
||||
ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid,
|
||||
|
||||
/* shared with 10.2 */
|
||||
.pull_echo_ev = ath10k_wmi_op_pull_echo_ev,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -197,6 +198,9 @@ enum wmi_service {
|
|||
WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
|
||||
WMI_SERVICE_MGMT_TX_WMI,
|
||||
WMI_SERVICE_TDLS_WIDER_BANDWIDTH,
|
||||
WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
|
||||
WMI_SERVICE_HOST_DFS_CHECK_SUPPORT,
|
||||
WMI_SERVICE_TPC_STATS_FINAL,
|
||||
|
||||
/* keep last */
|
||||
WMI_SERVICE_MAX,
|
||||
|
@ -339,6 +343,9 @@ enum wmi_10_4_service {
|
|||
WMI_10_4_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE,
|
||||
WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
|
||||
WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH,
|
||||
WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
|
||||
WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT,
|
||||
WMI_10_4_SERVICE_TPC_STATS_FINAL,
|
||||
};
|
||||
|
||||
static inline char *wmi_service_name(int service_id)
|
||||
|
@ -448,6 +455,9 @@ static inline char *wmi_service_name(int service_id)
|
|||
SVCSTR(WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE);
|
||||
SVCSTR(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY);
|
||||
SVCSTR(WMI_SERVICE_TDLS_WIDER_BANDWIDTH);
|
||||
SVCSTR(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS);
|
||||
SVCSTR(WMI_SERVICE_HOST_DFS_CHECK_SUPPORT);
|
||||
SVCSTR(WMI_SERVICE_TPC_STATS_FINAL);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
@ -746,6 +756,12 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
|
|||
WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, len);
|
||||
SVCMAP(WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH,
|
||||
WMI_SERVICE_TDLS_WIDER_BANDWIDTH, len);
|
||||
SVCMAP(WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
|
||||
WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, len);
|
||||
SVCMAP(WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT,
|
||||
WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, len);
|
||||
SVCMAP(WMI_10_4_SERVICE_TPC_STATS_FINAL,
|
||||
WMI_SERVICE_TPC_STATS_FINAL, len);
|
||||
}
|
||||
|
||||
#undef SVCMAP
|
||||
|
@ -3993,10 +4009,12 @@ struct wmi_pdev_get_tpc_config_cmd {
|
|||
|
||||
#define WMI_TPC_CONFIG_PARAM 1
|
||||
#define WMI_TPC_RATE_MAX 160
|
||||
#define WMI_TPC_FINAL_RATE_MAX 240
|
||||
#define WMI_TPC_TX_N_CHAIN 4
|
||||
#define WMI_TPC_PREAM_TABLE_MAX 10
|
||||
#define WMI_TPC_FLAG 3
|
||||
#define WMI_TPC_BUF_SIZE 10
|
||||
#define WMI_TPC_BEAMFORMING 2
|
||||
|
||||
enum wmi_tpc_table_type {
|
||||
WMI_TPC_TABLE_TYPE_CDD = 0,
|
||||
|
@ -4039,6 +4057,51 @@ enum wmi_tp_scale {
|
|||
WMI_TP_SCALE_SIZE = 5, /* max num of enum */
|
||||
};
|
||||
|
||||
struct wmi_pdev_tpc_final_table_event {
|
||||
__le32 reg_domain;
|
||||
__le32 chan_freq;
|
||||
__le32 phy_mode;
|
||||
__le32 twice_antenna_reduction;
|
||||
__le32 twice_max_rd_power;
|
||||
a_sle32 twice_antenna_gain;
|
||||
__le32 power_limit;
|
||||
__le32 rate_max;
|
||||
__le32 num_tx_chain;
|
||||
__le32 ctl;
|
||||
__le32 flags;
|
||||
s8 max_reg_allow_pow[WMI_TPC_TX_N_CHAIN];
|
||||
s8 max_reg_allow_pow_agcdd[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN];
|
||||
s8 max_reg_allow_pow_agstbc[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN];
|
||||
s8 max_reg_allow_pow_agtxbf[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN];
|
||||
u8 rates_array[WMI_TPC_FINAL_RATE_MAX];
|
||||
u8 ctl_power_table[WMI_TPC_BEAMFORMING][WMI_TPC_TX_N_CHAIN]
|
||||
[WMI_TPC_TX_N_CHAIN];
|
||||
} __packed;
|
||||
|
||||
struct wmi_pdev_get_tpc_table_cmd {
|
||||
__le32 param;
|
||||
} __packed;
|
||||
|
||||
enum wmi_tpc_pream_2ghz {
|
||||
WMI_TPC_PREAM_2GHZ_CCK = 0,
|
||||
WMI_TPC_PREAM_2GHZ_OFDM,
|
||||
WMI_TPC_PREAM_2GHZ_HT20,
|
||||
WMI_TPC_PREAM_2GHZ_HT40,
|
||||
WMI_TPC_PREAM_2GHZ_VHT20,
|
||||
WMI_TPC_PREAM_2GHZ_VHT40,
|
||||
WMI_TPC_PREAM_2GHZ_VHT80,
|
||||
};
|
||||
|
||||
enum wmi_tpc_pream_5ghz {
|
||||
WMI_TPC_PREAM_5GHZ_OFDM = 1,
|
||||
WMI_TPC_PREAM_5GHZ_HT20,
|
||||
WMI_TPC_PREAM_5GHZ_HT40,
|
||||
WMI_TPC_PREAM_5GHZ_VHT20,
|
||||
WMI_TPC_PREAM_5GHZ_VHT40,
|
||||
WMI_TPC_PREAM_5GHZ_VHT80,
|
||||
WMI_TPC_PREAM_5GHZ_HTCUP,
|
||||
};
|
||||
|
||||
struct wmi_pdev_chanlist_update_event {
|
||||
/* number of channels */
|
||||
__le32 num_chan;
|
||||
|
@ -6979,5 +7042,8 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
|
|||
int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar,
|
||||
enum wmi_vdev_subtype subtype);
|
||||
int ath10k_wmi_barrier(struct ath10k *ar);
|
||||
void ath10k_wmi_tpc_config_get_rate_code(u8 *rate_code, u16 *pream_table,
|
||||
u32 num_tx_chain);
|
||||
void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb);
|
||||
|
||||
#endif /* _WMI_H_ */
|
||||
|
|
|
@ -327,8 +327,6 @@ ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
|
|||
|
||||
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
|
||||
|
||||
tq = &ah->ah_txq[queue];
|
||||
|
||||
/* Skip if queue inactive or if we are on AR5210
|
||||
* that doesn't have QCU/DCU */
|
||||
if ((ah->ah_version == AR5K_AR5210) ||
|
||||
|
|
|
@ -88,7 +88,7 @@ static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
|
|||
CHAN5G(5825, 37), /* Channel 165 */
|
||||
};
|
||||
|
||||
/* Atheros hardware rate code addition for short premble */
|
||||
/* Atheros hardware rate code addition for short preamble */
|
||||
#define SHPCHECK(__hw_rate, __flags) \
|
||||
((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
|
||||
|
||||
|
|
|
@ -479,14 +479,16 @@ ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv)
|
|||
{
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
struct rchan_buf *buf;
|
||||
struct rchan *rc = spec_priv->rfs_chan_spec_scan;
|
||||
|
||||
for_each_online_cpu(i)
|
||||
ret += relay_buf_full(*per_cpu_ptr(rc->buf, i));
|
||||
for_each_possible_cpu(i) {
|
||||
if ((buf = *per_cpu_ptr(rc->buf, i))) {
|
||||
ret += relay_buf_full(buf);
|
||||
}
|
||||
}
|
||||
|
||||
i = num_online_cpus();
|
||||
|
||||
if (ret == i)
|
||||
if (ret)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
|
|
|
@ -184,7 +184,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
|
|||
break;
|
||||
case WLAN_RC_PHY_OFDM:
|
||||
if (ah->curchan && IS_CHAN_QUARTER_RATE(ah->curchan)) {
|
||||
bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000;
|
||||
bitsPerSymbol =
|
||||
((kbps >> 2) * OFDM_SYMBOL_TIME_QUARTER) / 1000;
|
||||
numBits = OFDM_PLCP_BITS + (frameLen << 3);
|
||||
numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
|
||||
txTime = OFDM_SIFS_TIME_QUARTER
|
||||
|
@ -192,7 +193,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
|
|||
+ (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
|
||||
} else if (ah->curchan &&
|
||||
IS_CHAN_HALF_RATE(ah->curchan)) {
|
||||
bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000;
|
||||
bitsPerSymbol =
|
||||
((kbps >> 1) * OFDM_SYMBOL_TIME_HALF) / 1000;
|
||||
numBits = OFDM_PLCP_BITS + (frameLen << 3);
|
||||
numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
|
||||
txTime = OFDM_SIFS_TIME_HALF +
|
||||
|
@ -1036,7 +1038,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
|
|||
int acktimeout, ctstimeout, ack_offset = 0;
|
||||
int slottime;
|
||||
int sifstime;
|
||||
int rx_lat = 0, tx_lat = 0, eifs = 0;
|
||||
int rx_lat = 0, tx_lat = 0, eifs = 0, ack_shift = 0;
|
||||
u32 reg;
|
||||
|
||||
ath_dbg(ath9k_hw_common(ah), RESET, "ah->misc_mode 0x%x\n",
|
||||
|
@ -1068,6 +1070,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
|
|||
|
||||
sifstime = 32;
|
||||
ack_offset = 16;
|
||||
ack_shift = 3;
|
||||
slottime = 13;
|
||||
} else if (IS_CHAN_QUARTER_RATE(chan)) {
|
||||
eifs = 340;
|
||||
|
@ -1078,6 +1081,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
|
|||
|
||||
sifstime = 64;
|
||||
ack_offset = 32;
|
||||
ack_shift = 1;
|
||||
slottime = 21;
|
||||
} else {
|
||||
if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) {
|
||||
|
@ -1134,6 +1138,10 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
|
|||
SM(tx_lat, AR_USEC_TX_LAT),
|
||||
AR_USEC_TX_LAT | AR_USEC_RX_LAT | AR_USEC_USEC);
|
||||
|
||||
if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))
|
||||
REG_RMW(ah, AR_TXSIFS,
|
||||
sifstime | SM(ack_shift, AR_TXSIFS_ACK_SHIFT),
|
||||
(AR_TXSIFS_TIME | AR_TXSIFS_ACK_SHIFT));
|
||||
}
|
||||
EXPORT_SYMBOL(ath9k_hw_init_global_settings);
|
||||
|
||||
|
|
|
@ -2892,6 +2892,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
|
|||
struct ath_txq *txq;
|
||||
int tidno;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
|
||||
tid = ath_node_to_tid(an, tidno);
|
||||
txq = tid->txq;
|
||||
|
@ -2909,6 +2911,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
|
|||
if (!an->sta)
|
||||
break; /* just one multicast ath_atx_tid */
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ATH9K_TX99
|
||||
|
|
|
@ -115,7 +115,7 @@ static const struct radar_detector_specs jp_radar_ref_types[] = {
|
|||
JP_PATTERN(4, 0, 5, 150, 230, 1, 23, 50, false),
|
||||
JP_PATTERN(5, 6, 10, 200, 500, 1, 16, 50, false),
|
||||
JP_PATTERN(6, 11, 20, 200, 500, 1, 12, 50, false),
|
||||
JP_PATTERN(7, 50, 100, 1000, 2000, 1, 3, 50, false),
|
||||
JP_PATTERN(7, 50, 100, 1000, 2000, 1, 3, 50, true),
|
||||
JP_PATTERN(5, 0, 1, 333, 333, 1, 9, 50, false),
|
||||
};
|
||||
|
||||
|
|
|
@ -376,7 +376,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
|
|||
spin_lock_irqsave(&ch->lock, flags);
|
||||
ctl = ch->tail_blk_ctl;
|
||||
do {
|
||||
if (ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)
|
||||
if (ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD)
|
||||
break;
|
||||
if (ctl->skb) {
|
||||
dma_unmap_single(wcn->dev, ctl->desc->src_addr_l,
|
||||
|
@ -397,7 +397,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
|
|||
}
|
||||
ctl = ctl->next;
|
||||
} while (ctl != ch->head_blk_ctl &&
|
||||
!(ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK));
|
||||
!(ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD));
|
||||
|
||||
ch->tail_blk_ctl = ctl;
|
||||
spin_unlock_irqrestore(&ch->lock, flags);
|
||||
|
@ -415,14 +415,31 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev)
|
|||
WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_H,
|
||||
&int_reason);
|
||||
|
||||
/* TODO: Check int_reason */
|
||||
|
||||
wcn36xx_dxe_write_register(wcn,
|
||||
WCN36XX_DXE_0_INT_CLR,
|
||||
WCN36XX_INT_MASK_CHAN_TX_H);
|
||||
|
||||
wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR,
|
||||
WCN36XX_INT_MASK_CHAN_TX_H);
|
||||
if (int_reason & WCN36XX_CH_STAT_INT_ERR_MASK ) {
|
||||
wcn36xx_dxe_write_register(wcn,
|
||||
WCN36XX_DXE_0_INT_ERR_CLR,
|
||||
WCN36XX_INT_MASK_CHAN_TX_H);
|
||||
|
||||
wcn36xx_err("DXE IRQ reported error: 0x%x in high TX channel\n",
|
||||
int_src);
|
||||
}
|
||||
|
||||
if (int_reason & WCN36XX_CH_STAT_INT_DONE_MASK) {
|
||||
wcn36xx_dxe_write_register(wcn,
|
||||
WCN36XX_DXE_0_INT_DONE_CLR,
|
||||
WCN36XX_INT_MASK_CHAN_TX_H);
|
||||
}
|
||||
|
||||
if (int_reason & WCN36XX_CH_STAT_INT_ED_MASK) {
|
||||
wcn36xx_dxe_write_register(wcn,
|
||||
WCN36XX_DXE_0_INT_ED_CLR,
|
||||
WCN36XX_INT_MASK_CHAN_TX_H);
|
||||
}
|
||||
|
||||
wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready high\n");
|
||||
reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch);
|
||||
}
|
||||
|
@ -431,14 +448,33 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev)
|
|||
wcn36xx_dxe_read_register(wcn,
|
||||
WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_L,
|
||||
&int_reason);
|
||||
/* TODO: Check int_reason */
|
||||
|
||||
wcn36xx_dxe_write_register(wcn,
|
||||
WCN36XX_DXE_0_INT_CLR,
|
||||
WCN36XX_INT_MASK_CHAN_TX_L);
|
||||
|
||||
wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR,
|
||||
WCN36XX_INT_MASK_CHAN_TX_L);
|
||||
|
||||
if (int_reason & WCN36XX_CH_STAT_INT_ERR_MASK ) {
|
||||
wcn36xx_dxe_write_register(wcn,
|
||||
WCN36XX_DXE_0_INT_ERR_CLR,
|
||||
WCN36XX_INT_MASK_CHAN_TX_L);
|
||||
|
||||
wcn36xx_err("DXE IRQ reported error: 0x%x in low TX channel\n",
|
||||
int_src);
|
||||
}
|
||||
|
||||
if (int_reason & WCN36XX_CH_STAT_INT_DONE_MASK) {
|
||||
wcn36xx_dxe_write_register(wcn,
|
||||
WCN36XX_DXE_0_INT_DONE_CLR,
|
||||
WCN36XX_INT_MASK_CHAN_TX_L);
|
||||
}
|
||||
|
||||
if (int_reason & WCN36XX_CH_STAT_INT_ED_MASK) {
|
||||
wcn36xx_dxe_write_register(wcn,
|
||||
WCN36XX_DXE_0_INT_ED_CLR,
|
||||
WCN36XX_INT_MASK_CHAN_TX_L);
|
||||
}
|
||||
|
||||
wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready low\n");
|
||||
reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch);
|
||||
}
|
||||
|
@ -503,7 +539,7 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn,
|
|||
int_mask = WCN36XX_DXE_INT_CH3_MASK;
|
||||
}
|
||||
|
||||
while (!(dxe->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) {
|
||||
while (!(dxe->ctrl & WCN36xx_DXE_CTRL_VLD)) {
|
||||
skb = ctl->skb;
|
||||
dma_addr = dxe->dst_addr_l;
|
||||
ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl);
|
||||
|
|
|
@ -33,15 +33,106 @@ H2H_TEST_RX_TX = DMA2
|
|||
#define WCN36XX_CCU_DXE_INT_SELECT_RIVA 0x310
|
||||
#define WCN36XX_CCU_DXE_INT_SELECT_PRONTO 0x10dc
|
||||
|
||||
/* TODO This must calculated properly but not hardcoded */
|
||||
#define WCN36XX_DXE_CTRL_TX_L 0x328a44
|
||||
#define WCN36XX_DXE_CTRL_TX_H 0x32ce44
|
||||
#define WCN36XX_DXE_CTRL_RX_L 0x12ad2f
|
||||
#define WCN36XX_DXE_CTRL_RX_H 0x12d12f
|
||||
#define WCN36XX_DXE_CTRL_TX_H_BD 0x30ce45
|
||||
#define WCN36XX_DXE_CTRL_TX_H_SKB 0x32ce4d
|
||||
#define WCN36XX_DXE_CTRL_TX_L_BD 0x308a45
|
||||
#define WCN36XX_DXE_CTRL_TX_L_SKB 0x328a4d
|
||||
/* Descriptor valid */
|
||||
#define WCN36xx_DXE_CTRL_VLD BIT(0)
|
||||
/* End of packet */
|
||||
#define WCN36xx_DXE_CTRL_EOP BIT(3)
|
||||
/* BD handling bit */
|
||||
#define WCN36xx_DXE_CTRL_BDH BIT(4)
|
||||
/* Source is a queue */
|
||||
#define WCN36xx_DXE_CTRL_SIQ BIT(5)
|
||||
/* Destination is a queue */
|
||||
#define WCN36xx_DXE_CTRL_DIQ BIT(6)
|
||||
/* Pointer address is a queue */
|
||||
#define WCN36xx_DXE_CTRL_PIQ BIT(7)
|
||||
/* Release PDU when done */
|
||||
#define WCN36xx_DXE_CTRL_PDU_REL BIT(8)
|
||||
/* STOP channel processing */
|
||||
#define WCN36xx_DXE_CTRL_STOP BIT(16)
|
||||
/* INT on descriptor done */
|
||||
#define WCN36xx_DXE_CTRL_INT BIT(17)
|
||||
/* Endian byte swap enable */
|
||||
#define WCN36xx_DXE_CTRL_SWAP BIT(20)
|
||||
/* Master endianness */
|
||||
#define WCN36xx_DXE_CTRL_ENDIANNESS BIT(21)
|
||||
|
||||
/* Transfer type */
|
||||
#define WCN36xx_DXE_CTRL_XTYPE_SHIFT 1
|
||||
#define WCN36xx_DXE_CTRL_XTYPE_MASK GENMASK(2, WCN36xx_DXE_CTRL_XTYPE_SHIFT)
|
||||
#define WCN36xx_DXE_CTRL_XTYPE_SET(x) ((x) << WCN36xx_DXE_CTRL_XTYPE_SHIFT)
|
||||
|
||||
/* BMU Threshold select */
|
||||
#define WCN36xx_DXE_CTRL_BTHLD_SEL_SHIFT 9
|
||||
#define WCN36xx_DXE_CTRL_BTHLD_SEL_MASK GENMASK(12, WCN36xx_DXE_CTRL_BTHLD_SEL_SHIFT)
|
||||
#define WCN36xx_DXE_CTRL_BTHLD_SEL_SET(x) ((x) << WCN36xx_DXE_CTRL_BTHLD_SEL_SHIFT)
|
||||
|
||||
/* Priority */
|
||||
#define WCN36xx_DXE_CTRL_PRIO_SHIFT 13
|
||||
#define WCN36xx_DXE_CTRL_PRIO_MASK GENMASK(15, WCN36xx_DXE_CTRL_PRIO_SHIFT)
|
||||
#define WCN36xx_DXE_CTRL_PRIO_SET(x) ((x) << WCN36xx_DXE_CTRL_PRIO_SHIFT)
|
||||
|
||||
/* BD Template index */
|
||||
#define WCN36xx_DXE_CTRL_BDT_IDX_SHIFT 18
|
||||
#define WCN36xx_DXE_CTRL_BDT_IDX_MASK GENMASK(19, WCN36xx_DXE_CTRL_BDT_IDX_SHIFT)
|
||||
#define WCN36xx_DXE_CTRL_BDT_IDX_SET(x) ((x) << WCN36xx_DXE_CTRL_BDT_IDX_SHIFT)
|
||||
|
||||
/* Transfer types: */
|
||||
/* Host to host */
|
||||
#define WCN36xx_DXE_XTYPE_H2H (0)
|
||||
/* Host to BMU */
|
||||
#define WCN36xx_DXE_XTYPE_H2B (2)
|
||||
/* BMU to host */
|
||||
#define WCN36xx_DXE_XTYPE_B2H (3)
|
||||
|
||||
#define WCN36XX_DXE_CTRL_TX_L (WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
|
||||
WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(5) | \
|
||||
WCN36xx_DXE_CTRL_PRIO_SET(4) | WCN36xx_DXE_CTRL_INT | \
|
||||
WCN36xx_DXE_CTRL_SWAP | WCN36xx_DXE_CTRL_ENDIANNESS)
|
||||
|
||||
#define WCN36XX_DXE_CTRL_TX_H (WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
|
||||
WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(7) | \
|
||||
WCN36xx_DXE_CTRL_PRIO_SET(6) | WCN36xx_DXE_CTRL_INT | \
|
||||
WCN36xx_DXE_CTRL_SWAP | WCN36xx_DXE_CTRL_ENDIANNESS)
|
||||
|
||||
#define WCN36XX_DXE_CTRL_RX_L (WCN36xx_DXE_CTRL_VLD | \
|
||||
WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \
|
||||
WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_SIQ | \
|
||||
WCN36xx_DXE_CTRL_PDU_REL | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(6) | \
|
||||
WCN36xx_DXE_CTRL_PRIO_SET(5) | WCN36xx_DXE_CTRL_INT | \
|
||||
WCN36xx_DXE_CTRL_SWAP)
|
||||
|
||||
#define WCN36XX_DXE_CTRL_RX_H (WCN36xx_DXE_CTRL_VLD | \
|
||||
WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \
|
||||
WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_SIQ | \
|
||||
WCN36xx_DXE_CTRL_PDU_REL | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(8) | \
|
||||
WCN36xx_DXE_CTRL_PRIO_SET(6) | WCN36xx_DXE_CTRL_INT | \
|
||||
WCN36xx_DXE_CTRL_SWAP)
|
||||
|
||||
#define WCN36XX_DXE_CTRL_TX_H_BD (WCN36xx_DXE_CTRL_VLD | \
|
||||
WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
|
||||
WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(7) | \
|
||||
WCN36xx_DXE_CTRL_PRIO_SET(6) | WCN36xx_DXE_CTRL_SWAP | \
|
||||
WCN36xx_DXE_CTRL_ENDIANNESS)
|
||||
|
||||
#define WCN36XX_DXE_CTRL_TX_H_SKB (WCN36xx_DXE_CTRL_VLD | \
|
||||
WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
|
||||
WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_DIQ | \
|
||||
WCN36xx_DXE_CTRL_BTHLD_SEL_SET(7) | WCN36xx_DXE_CTRL_PRIO_SET(6) | \
|
||||
WCN36xx_DXE_CTRL_INT | WCN36xx_DXE_CTRL_SWAP | \
|
||||
WCN36xx_DXE_CTRL_ENDIANNESS)
|
||||
|
||||
#define WCN36XX_DXE_CTRL_TX_L_BD (WCN36xx_DXE_CTRL_VLD | \
|
||||
WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
|
||||
WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(5) | \
|
||||
WCN36xx_DXE_CTRL_PRIO_SET(4) | WCN36xx_DXE_CTRL_SWAP | \
|
||||
WCN36xx_DXE_CTRL_ENDIANNESS)
|
||||
|
||||
#define WCN36XX_DXE_CTRL_TX_L_SKB (WCN36xx_DXE_CTRL_VLD | \
|
||||
WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
|
||||
WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_DIQ | \
|
||||
WCN36xx_DXE_CTRL_BTHLD_SEL_SET(5) | WCN36xx_DXE_CTRL_PRIO_SET(4) | \
|
||||
WCN36xx_DXE_CTRL_INT | WCN36xx_DXE_CTRL_SWAP | \
|
||||
WCN36xx_DXE_CTRL_ENDIANNESS)
|
||||
|
||||
/* TODO This must calculated properly but not hardcoded */
|
||||
#define WCN36XX_DXE_WQ_TX_L 0x17
|
||||
|
@ -49,15 +140,106 @@ H2H_TEST_RX_TX = DMA2
|
|||
#define WCN36XX_DXE_WQ_RX_L 0xB
|
||||
#define WCN36XX_DXE_WQ_RX_H 0x4
|
||||
|
||||
/* DXE descriptor control filed */
|
||||
#define WCN36XX_DXE_CTRL_VALID_MASK (0x00000001)
|
||||
/* Channel enable or restart */
|
||||
#define WCN36xx_DXE_CH_CTRL_EN BIT(0)
|
||||
/* End of packet bit */
|
||||
#define WCN36xx_DXE_CH_CTRL_EOP BIT(3)
|
||||
/* BD Handling bit */
|
||||
#define WCN36xx_DXE_CH_CTRL_BDH BIT(4)
|
||||
/* Source is queue */
|
||||
#define WCN36xx_DXE_CH_CTRL_SIQ BIT(5)
|
||||
/* Destination is queue */
|
||||
#define WCN36xx_DXE_CH_CTRL_DIQ BIT(6)
|
||||
/* Pointer descriptor is queue */
|
||||
#define WCN36xx_DXE_CH_CTRL_PIQ BIT(7)
|
||||
/* Relase PDU when done */
|
||||
#define WCN36xx_DXE_CH_CTRL_PDU_REL BIT(8)
|
||||
/* Stop channel processing */
|
||||
#define WCN36xx_DXE_CH_CTRL_STOP BIT(16)
|
||||
/* Enable external descriptor interrupt */
|
||||
#define WCN36xx_DXE_CH_CTRL_INE_ED BIT(17)
|
||||
/* Enable channel interrupt on errors */
|
||||
#define WCN36xx_DXE_CH_CTRL_INE_ERR BIT(18)
|
||||
/* Enable Channel interrupt when done */
|
||||
#define WCN36xx_DXE_CH_CTRL_INE_DONE BIT(19)
|
||||
/* External descriptor enable */
|
||||
#define WCN36xx_DXE_CH_CTRL_EDEN BIT(20)
|
||||
/* Wait for valid bit */
|
||||
#define WCN36xx_DXE_CH_CTRL_EDVEN BIT(21)
|
||||
/* Endianness is little endian*/
|
||||
#define WCN36xx_DXE_CH_CTRL_ENDIANNESS BIT(26)
|
||||
/* Abort transfer */
|
||||
#define WCN36xx_DXE_CH_CTRL_ABORT BIT(27)
|
||||
/* Long descriptor format */
|
||||
#define WCN36xx_DXE_CH_CTRL_DFMT BIT(28)
|
||||
/* Endian byte swap enable */
|
||||
#define WCN36xx_DXE_CH_CTRL_SWAP BIT(31)
|
||||
|
||||
/* Transfer type */
|
||||
#define WCN36xx_DXE_CH_CTRL_XTYPE_SHIFT 1
|
||||
#define WCN36xx_DXE_CH_CTRL_XTYPE_MASK GENMASK(2, WCN36xx_DXE_CH_CTRL_XTYPE_SHIFT)
|
||||
#define WCN36xx_DXE_CH_CTRL_XTYPE_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_XTYPE_SHIFT)
|
||||
|
||||
/* Channel BMU Threshold select */
|
||||
#define WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SHIFT 9
|
||||
#define WCN36xx_DXE_CH_CTRL_BTHLD_SEL_MASK GENMASK(12, WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SHIFT)
|
||||
#define WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SHIFT)
|
||||
|
||||
/* Channel Priority */
|
||||
#define WCN36xx_DXE_CH_CTRL_PRIO_SHIFT 13
|
||||
#define WCN36xx_DXE_CH_CTRL_PRIO_MASK GENMASK(15, WCN36xx_DXE_CH_CTRL_PRIO_SHIFT)
|
||||
#define WCN36xx_DXE_CH_CTRL_PRIO_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_PRIO_SHIFT)
|
||||
|
||||
/* Counter select */
|
||||
#define WCN36xx_DXE_CH_CTRL_SEL_SHIFT 22
|
||||
#define WCN36xx_DXE_CH_CTRL_SEL_MASK GENMASK(25, WCN36xx_DXE_CH_CTRL_SEL_SHIFT)
|
||||
#define WCN36xx_DXE_CH_CTRL_SEL_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_SEL_SHIFT)
|
||||
|
||||
/* Channel BD template index */
|
||||
#define WCN36xx_DXE_CH_CTRL_BDT_IDX_SHIFT 29
|
||||
#define WCN36xx_DXE_CH_CTRL_BDT_IDX_MASK GENMASK(30, WCN36xx_DXE_CH_CTRL_BDT_IDX_SHIFT)
|
||||
#define WCN36xx_DXE_CH_CTRL_BDT_IDX_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_BDT_IDX_SHIFT)
|
||||
|
||||
/* TODO This must calculated properly but not hardcoded */
|
||||
/* DXE default control register values */
|
||||
#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_L 0x847EAD2F
|
||||
#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_H 0x84FED12F
|
||||
#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_H 0x853ECF4D
|
||||
#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_L 0x843e8b4d
|
||||
#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_L (WCN36xx_DXE_CH_CTRL_EN | \
|
||||
WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \
|
||||
WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_SIQ | \
|
||||
WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(6) | \
|
||||
WCN36xx_DXE_CH_CTRL_PRIO_SET(5) | WCN36xx_DXE_CH_CTRL_INE_ED | \
|
||||
WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \
|
||||
WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \
|
||||
WCN36xx_DXE_CH_CTRL_SEL_SET(1) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \
|
||||
WCN36xx_DXE_CH_CTRL_SWAP)
|
||||
|
||||
#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_H (WCN36xx_DXE_CH_CTRL_EN | \
|
||||
WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \
|
||||
WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_SIQ | \
|
||||
WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(8) | \
|
||||
WCN36xx_DXE_CH_CTRL_PRIO_SET(6) | WCN36xx_DXE_CH_CTRL_INE_ED | \
|
||||
WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \
|
||||
WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \
|
||||
WCN36xx_DXE_CH_CTRL_SEL_SET(3) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \
|
||||
WCN36xx_DXE_CH_CTRL_SWAP)
|
||||
|
||||
#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_H (WCN36xx_DXE_CH_CTRL_EN | \
|
||||
WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
|
||||
WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_DIQ | \
|
||||
WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(7) | \
|
||||
WCN36xx_DXE_CH_CTRL_PRIO_SET(6) | WCN36xx_DXE_CH_CTRL_INE_ED | \
|
||||
WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \
|
||||
WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \
|
||||
WCN36xx_DXE_CH_CTRL_SEL_SET(4) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \
|
||||
WCN36xx_DXE_CH_CTRL_SWAP)
|
||||
|
||||
#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_L (WCN36xx_DXE_CH_CTRL_EN | \
|
||||
WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
|
||||
WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_DIQ | \
|
||||
WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(5) | \
|
||||
WCN36xx_DXE_CH_CTRL_PRIO_SET(4) | WCN36xx_DXE_CH_CTRL_INE_ED | \
|
||||
WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \
|
||||
WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \
|
||||
WCN36xx_DXE_CH_CTRL_SEL_SET(0) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \
|
||||
WCN36xx_DXE_CH_CTRL_SWAP)
|
||||
|
||||
/* Common DXE registers */
|
||||
#define WCN36XX_DXE_MEM_CSR (WCN36XX_DXE_MEM_REG + 0x00)
|
||||
|
@ -80,6 +262,10 @@ H2H_TEST_RX_TX = DMA2
|
|||
#define WCN36XX_DXE_0_INT_DONE_CLR (WCN36XX_DXE_MEM_REG + 0x38)
|
||||
#define WCN36XX_DXE_0_INT_ERR_CLR (WCN36XX_DXE_MEM_REG + 0x3C)
|
||||
|
||||
#define WCN36XX_CH_STAT_INT_DONE_MASK 0x00008000
|
||||
#define WCN36XX_CH_STAT_INT_ERR_MASK 0x00004000
|
||||
#define WCN36XX_CH_STAT_INT_ED_MASK 0x00002000
|
||||
|
||||
#define WCN36XX_DXE_0_CH0_STATUS (WCN36XX_DXE_MEM_REG + 0x404)
|
||||
#define WCN36XX_DXE_0_CH1_STATUS (WCN36XX_DXE_MEM_REG + 0x444)
|
||||
#define WCN36XX_DXE_0_CH2_STATUS (WCN36XX_DXE_MEM_REG + 0x484)
|
||||
|
|
|
@ -261,7 +261,7 @@ static void wcn36xx_feat_caps_info(struct wcn36xx *wcn)
|
|||
|
||||
for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) {
|
||||
if (get_feat_caps(wcn->fw_feat_caps, i))
|
||||
wcn36xx_info("FW Cap %s\n", wcn36xx_get_cap_name(i));
|
||||
wcn36xx_dbg(WCN36XX_DBG_MAC, "FW Cap %s\n", wcn36xx_get_cap_name(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -666,16 +666,13 @@ static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct wcn36xx *wcn = hw->priv;
|
||||
|
||||
if (!wcn36xx_smd_stop_hw_scan(wcn)) {
|
||||
struct cfg80211_scan_info scan_info = { .aborted = true };
|
||||
|
||||
ieee80211_scan_completed(wcn->hw, &scan_info);
|
||||
}
|
||||
|
||||
mutex_lock(&wcn->scan_lock);
|
||||
wcn->scan_aborted = true;
|
||||
mutex_unlock(&wcn->scan_lock);
|
||||
|
||||
/* ieee80211_scan_completed will be called on FW scan indication */
|
||||
wcn36xx_smd_stop_hw_scan(wcn);
|
||||
|
||||
cancel_work_sync(&wcn->scan_work);
|
||||
}
|
||||
|
||||
|
@ -1283,6 +1280,7 @@ static int wcn36xx_probe(struct platform_device *pdev)
|
|||
wcn = hw->priv;
|
||||
wcn->hw = hw;
|
||||
wcn->dev = &pdev->dev;
|
||||
wcn->first_boot = true;
|
||||
mutex_init(&wcn->conf_mutex);
|
||||
mutex_init(&wcn->hal_mutex);
|
||||
mutex_init(&wcn->scan_lock);
|
||||
|
|
|
@ -409,15 +409,17 @@ static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len)
|
|||
wcn->fw_minor = rsp->start_rsp_params.version.minor;
|
||||
wcn->fw_major = rsp->start_rsp_params.version.major;
|
||||
|
||||
wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n",
|
||||
wcn->wlan_version, wcn->crm_version);
|
||||
|
||||
wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n",
|
||||
wcn->fw_major, wcn->fw_minor,
|
||||
wcn->fw_version, wcn->fw_revision,
|
||||
rsp->start_rsp_params.stations,
|
||||
rsp->start_rsp_params.bssids);
|
||||
if (wcn->first_boot) {
|
||||
wcn->first_boot = false;
|
||||
wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n",
|
||||
wcn->wlan_version, wcn->crm_version);
|
||||
|
||||
wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n",
|
||||
wcn->fw_major, wcn->fw_minor,
|
||||
wcn->fw_version, wcn->fw_revision,
|
||||
rsp->start_rsp_params.stations,
|
||||
rsp->start_rsp_params.bssids);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2138,6 +2140,8 @@ static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len)
|
|||
case WCN36XX_HAL_SCAN_IND_COMPLETED:
|
||||
mutex_lock(&wcn->scan_lock);
|
||||
wcn->scan_req = NULL;
|
||||
if (wcn->scan_aborted)
|
||||
scan_info.aborted = true;
|
||||
mutex_unlock(&wcn->scan_lock);
|
||||
ieee80211_scan_completed(wcn->hw, &scan_info);
|
||||
break;
|
||||
|
|
|
@ -192,6 +192,8 @@ struct wcn36xx {
|
|||
u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1];
|
||||
u8 wlan_version[WCN36XX_HAL_VERSION_LENGTH + 1];
|
||||
|
||||
bool first_boot;
|
||||
|
||||
/* IRQs */
|
||||
int tx_irq;
|
||||
int rx_irq;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2013,2016 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -25,7 +26,7 @@ void __wil_err(struct wil6210_priv *wil, const char *fmt, ...)
|
|||
va_start(args, fmt);
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
netdev_err(wil_to_ndev(wil), "%pV", &vaf);
|
||||
netdev_err(wil->main_ndev, "%pV", &vaf);
|
||||
trace_wil6210_log_err(&vaf);
|
||||
va_end(args);
|
||||
}
|
||||
|
@ -41,7 +42,7 @@ void __wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...)
|
|||
va_start(args, fmt);
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
netdev_err(wil_to_ndev(wil), "%pV", &vaf);
|
||||
netdev_err(wil->main_ndev, "%pV", &vaf);
|
||||
trace_wil6210_log_err(&vaf);
|
||||
va_end(args);
|
||||
}
|
||||
|
@ -57,7 +58,7 @@ void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...)
|
|||
va_start(args, fmt);
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
netdev_dbg(wil_to_ndev(wil), "%pV", &vaf);
|
||||
netdev_dbg(wil->main_ndev, "%pV", &vaf);
|
||||
trace_wil6210_log_dbg(&vaf);
|
||||
va_end(args);
|
||||
}
|
||||
|
@ -70,7 +71,7 @@ void __wil_info(struct wil6210_priv *wil, const char *fmt, ...)
|
|||
va_start(args, fmt);
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
netdev_info(wil_to_ndev(wil), "%pV", &vaf);
|
||||
netdev_info(wil->main_ndev, "%pV", &vaf);
|
||||
trace_wil6210_log_info(&vaf);
|
||||
va_end(args);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -621,7 +622,7 @@ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
|
|||
size_t len, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
|
||||
/**
|
||||
* BUG:
|
||||
|
@ -716,27 +717,44 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf,
|
|||
if (rc < 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (0 == strcmp(cmd, "add")) {
|
||||
if (rc < 3) {
|
||||
wil_err(wil, "BACK: add require at least 2 params\n");
|
||||
if ((strcmp(cmd, "add") == 0) ||
|
||||
(strcmp(cmd, "del_tx") == 0)) {
|
||||
struct vring_tx_data *txdata;
|
||||
|
||||
if (p1 < 0 || p1 >= WIL6210_MAX_TX_RINGS) {
|
||||
wil_err(wil, "BACK: invalid ring id %d\n", p1);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (rc < 4)
|
||||
p3 = 0;
|
||||
wmi_addba(wil, p1, p2, p3);
|
||||
} else if (0 == strcmp(cmd, "del_tx")) {
|
||||
if (rc < 3)
|
||||
p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
|
||||
wmi_delba_tx(wil, p1, p2);
|
||||
} else if (0 == strcmp(cmd, "del_rx")) {
|
||||
txdata = &wil->vring_tx_data[p1];
|
||||
if (strcmp(cmd, "add") == 0) {
|
||||
if (rc < 3) {
|
||||
wil_err(wil, "BACK: add require at least 2 params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (rc < 4)
|
||||
p3 = 0;
|
||||
wmi_addba(wil, txdata->mid, p1, p2, p3);
|
||||
} else {
|
||||
if (rc < 3)
|
||||
p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
|
||||
wmi_delba_tx(wil, txdata->mid, p1, p2);
|
||||
}
|
||||
} else if (strcmp(cmd, "del_rx") == 0) {
|
||||
struct wil_sta_info *sta;
|
||||
|
||||
if (rc < 3) {
|
||||
wil_err(wil,
|
||||
"BACK: del_rx require at least 2 params\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (p1 < 0 || p1 >= WIL6210_MAX_CID) {
|
||||
wil_err(wil, "BACK: invalid CID %d\n", p1);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (rc < 4)
|
||||
p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
|
||||
wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3);
|
||||
sta = &wil->sta[p1];
|
||||
wmi_delba_rx(wil, sta->mid, mk_cidxtid(p1, p2), p3);
|
||||
} else {
|
||||
wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
|
||||
return -EINVAL;
|
||||
|
@ -855,7 +873,7 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
|
|||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
struct wiphy *wiphy = wil_to_wiphy(wil);
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
|
||||
struct cfg80211_mgmt_tx_params params;
|
||||
int rc;
|
||||
void *frame;
|
||||
|
@ -890,6 +908,7 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
|
|||
size_t len, loff_t *ppos)
|
||||
{
|
||||
struct wil6210_priv *wil = file->private_data;
|
||||
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
|
||||
struct wmi_cmd_hdr *wmi;
|
||||
void *cmd;
|
||||
int cmdlen = len - sizeof(struct wmi_cmd_hdr);
|
||||
|
@ -912,7 +931,7 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
|
|||
cmd = (cmdlen > 0) ? &wmi[1] : NULL;
|
||||
cmdid = le16_to_cpu(wmi->command_id);
|
||||
|
||||
rc1 = wmi_send(wil, cmdid, cmd, cmdlen);
|
||||
rc1 = wmi_send(wil, cmdid, vif->mid, cmd, cmdlen);
|
||||
kfree(wmi);
|
||||
|
||||
wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1);
|
||||
|
@ -1050,6 +1069,7 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data)
|
|||
int rc;
|
||||
int i;
|
||||
struct wil6210_priv *wil = s->private;
|
||||
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
|
||||
struct wmi_notify_req_cmd cmd = {
|
||||
.interval_usec = 0,
|
||||
};
|
||||
|
@ -1062,7 +1082,8 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data)
|
|||
u32 status;
|
||||
|
||||
cmd.cid = i;
|
||||
rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd),
|
||||
rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid,
|
||||
&cmd, sizeof(cmd),
|
||||
WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
|
||||
sizeof(reply), 20);
|
||||
/* if reply is all-0, ignore this CID */
|
||||
|
@ -1155,7 +1176,7 @@ static const struct file_operations fops_temp = {
|
|||
static int wil_freq_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
|
||||
u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
|
||||
|
||||
seq_printf(s, "Freq = %d\n", freq);
|
||||
|
@ -1185,6 +1206,8 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
|
|||
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
|
||||
struct wil_sta_info *p = &wil->sta[i];
|
||||
char *status = "unknown";
|
||||
struct wil6210_vif *vif;
|
||||
u8 mid;
|
||||
|
||||
switch (p->status) {
|
||||
case wil_sta_unused:
|
||||
|
@ -1197,16 +1220,24 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
|
|||
status = "connected";
|
||||
break;
|
||||
}
|
||||
seq_printf(s, "[%d] %pM %s\n", i, p->addr, status);
|
||||
mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
|
||||
seq_printf(s, "[%d][MID %d] %pM %s\n",
|
||||
i, mid, p->addr, status);
|
||||
|
||||
if (p->status == wil_sta_connected) {
|
||||
rc = wil_cid_fill_sinfo(wil, i, &sinfo);
|
||||
if (p->status != wil_sta_connected)
|
||||
continue;
|
||||
|
||||
vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL;
|
||||
if (vif) {
|
||||
rc = wil_cid_fill_sinfo(vif, i, &sinfo);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs);
|
||||
seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs);
|
||||
seq_printf(s, " SQ = %d\n", sinfo.signal);
|
||||
} else {
|
||||
seq_puts(s, " INVALID MID\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1229,7 +1260,7 @@ static const struct file_operations fops_link = {
|
|||
static int wil_info_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
int is_ac = power_supply_is_system_supplied();
|
||||
int rx = atomic_xchg(&wil->isr_count_rx, 0);
|
||||
int tx = atomic_xchg(&wil->isr_count_tx, 0);
|
||||
|
@ -1398,6 +1429,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
|
|||
struct wil_sta_info *p = &wil->sta[i];
|
||||
char *status = "unknown";
|
||||
u8 aid = 0;
|
||||
u8 mid;
|
||||
|
||||
switch (p->status) {
|
||||
case wil_sta_unused:
|
||||
|
@ -1411,7 +1443,9 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
|
|||
aid = p->aid;
|
||||
break;
|
||||
}
|
||||
seq_printf(s, "[%d] %pM %s AID %d\n", i, p->addr, status, aid);
|
||||
mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
|
||||
seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
|
||||
mid, aid);
|
||||
|
||||
if (p->status == wil_sta_connected) {
|
||||
spin_lock_bh(&p->tid_rx_lock);
|
||||
|
@ -1461,6 +1495,42 @@ static const struct file_operations fops_sta = {
|
|||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
static int wil_mids_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct wil6210_priv *wil = s->private;
|
||||
struct wil6210_vif *vif;
|
||||
struct net_device *ndev;
|
||||
int i;
|
||||
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
for (i = 0; i < wil->max_vifs; i++) {
|
||||
vif = wil->vifs[i];
|
||||
|
||||
if (vif) {
|
||||
ndev = vif_to_ndev(vif);
|
||||
seq_printf(s, "[%d] %pM %s\n", i, ndev->dev_addr,
|
||||
ndev->name);
|
||||
} else {
|
||||
seq_printf(s, "[%d] unused\n", i);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wil_mids_seq_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, wil_mids_debugfs_show, inode->i_private);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_mids = {
|
||||
.open = wil_mids_seq_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
|
@ -1715,6 +1785,7 @@ static const struct {
|
|||
{"mbox", 0444, &fops_mbox},
|
||||
{"vrings", 0444, &fops_vring},
|
||||
{"stations", 0444, &fops_sta},
|
||||
{"mids", 0444, &fops_mids},
|
||||
{"desc", 0444, &fops_txdesc},
|
||||
{"bf", 0444, &fops_bf},
|
||||
{"mem_val", 0644, &fops_memread},
|
||||
|
@ -1773,11 +1844,9 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
|
|||
|
||||
/* fields in struct wil6210_priv */
|
||||
static const struct dbg_off dbg_wil_off[] = {
|
||||
WIL_FIELD(privacy, 0444, doff_u32),
|
||||
WIL_FIELD(status[0], 0644, doff_ulong),
|
||||
WIL_FIELD(hw_version, 0444, doff_x32),
|
||||
WIL_FIELD(recovery_count, 0444, doff_u32),
|
||||
WIL_FIELD(ap_isolate, 0444, doff_u32),
|
||||
WIL_FIELD(discovery_mode, 0644, doff_u8),
|
||||
WIL_FIELD(chip_revision, 0444, doff_u8),
|
||||
WIL_FIELD(abft_len, 0644, doff_u8),
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -74,12 +75,13 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev,
|
|||
struct ethtool_coalesce *cp)
|
||||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
struct wireless_dev *wdev = ndev->ieee80211_ptr;
|
||||
int ret;
|
||||
|
||||
wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n",
|
||||
cp->rx_coalesce_usecs, cp->tx_coalesce_usecs);
|
||||
|
||||
if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
|
||||
if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
|
||||
wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#ifndef __WIL_FW_H__
|
||||
#define __WIL_FW_H__
|
||||
|
||||
#define WIL_FW_SIGNATURE (0x36323130) /* '0126' */
|
||||
#define WIL_FW_FMT_VERSION (1) /* format version driver supports */
|
||||
|
@ -71,7 +73,39 @@ struct wil_fw_record_capabilities { /* type == wil_fw_type_comment */
|
|||
struct wil_fw_record_comment_hdr hdr;
|
||||
/* capabilities (variable size), see enum wmi_fw_capability */
|
||||
u8 capabilities[0];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
/* FW VIF concurrency encoded inside a comment record
|
||||
* Format is similar to wiphy->iface_combinations
|
||||
*/
|
||||
#define WIL_FW_CONCURRENCY_MAGIC (0xfedccdef)
|
||||
#define WIL_FW_CONCURRENCY_REC_VER 1
|
||||
struct wil_fw_concurrency_limit {
|
||||
__le16 max; /* maximum number of interfaces of these types */
|
||||
__le16 types; /* interface types (bit mask of enum nl80211_iftype) */
|
||||
} __packed;
|
||||
|
||||
struct wil_fw_concurrency_combo {
|
||||
u8 n_limits; /* number of wil_fw_concurrency_limit entries */
|
||||
u8 max_interfaces; /* max number of concurrent interfaces allowed */
|
||||
u8 n_diff_channels; /* total number of different channels allowed */
|
||||
u8 same_bi; /* for APs, 1 if all APs must have same BI */
|
||||
/* keep last - concurrency limits, variable size by n_limits */
|
||||
struct wil_fw_concurrency_limit limits[0];
|
||||
} __packed;
|
||||
|
||||
struct wil_fw_record_concurrency { /* type == wil_fw_type_comment */
|
||||
/* identifies concurrency record */
|
||||
__le32 magic;
|
||||
/* structure version, currently always 1 */
|
||||
u8 version;
|
||||
/* maximum number of supported MIDs _in addition_ to MID 0 */
|
||||
u8 n_mids;
|
||||
/* number of concurrency combinations that follow */
|
||||
__le16 n_combos;
|
||||
/* keep last - combinations, variable size by n_combos */
|
||||
struct wil_fw_concurrency_combo combos[0];
|
||||
} __packed;
|
||||
|
||||
/* brd file info encoded inside a comment record */
|
||||
#define WIL_BRD_FILE_MAGIC (0xabcddcbb)
|
||||
|
@ -175,3 +209,5 @@ struct wil_fw_record_gateway_data4 { /* type == wil_fw_type_gateway_data4 */
|
|||
__le32 command;
|
||||
struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */
|
||||
} __packed;
|
||||
|
||||
#endif /* __WIL_FW_H__ */
|
||||
|
|
|
@ -136,8 +136,8 @@ fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
|
|||
size_t capa_size;
|
||||
|
||||
if (size < sizeof(*rec)) {
|
||||
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
data, size, true);
|
||||
wil_err_fw(wil, "capabilities record too short: %zu\n", size);
|
||||
/* let the FW load anyway */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -158,8 +158,7 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data,
|
|||
const struct wil_fw_record_brd_file *rec = data;
|
||||
|
||||
if (size < sizeof(*rec)) {
|
||||
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
data, size, true);
|
||||
wil_err_fw(wil, "brd_file record too short: %zu\n", size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -172,6 +171,44 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data,
|
|||
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
|
||||
fw_handle_comment(struct wil6210_priv *wil, const void *data,
|
||||
size_t size)
|
||||
|
@ -194,6 +231,13 @@ fw_handle_comment(struct wil6210_priv *wil, const void *data,
|
|||
wil_dbg_fw(wil, "magic is WIL_BRD_FILE_MAGIC\n");
|
||||
rc = fw_handle_brd_file(wil, data, size);
|
||||
break;
|
||||
case WIL_FW_CONCURRENCY_MAGIC:
|
||||
wil_dbg_fw(wil, "magic is WIL_FW_CONCURRENCY_MAGIC\n");
|
||||
rc = fw_handle_concurrency(wil, data, size);
|
||||
break;
|
||||
default:
|
||||
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
|
||||
data, size, true);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
|
|
@ -127,7 +127,7 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
|
|||
|
||||
void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
|
||||
{
|
||||
bool unmask_rx_htrsh = test_bit(wil_status_fwconnected, wil->status);
|
||||
bool unmask_rx_htrsh = atomic_read(&wil->connected_vifs) > 0;
|
||||
|
||||
wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC),
|
||||
unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH);
|
||||
|
@ -188,12 +188,14 @@ void wil_unmask_irq(struct wil6210_priv *wil)
|
|||
|
||||
void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
|
||||
|
||||
wil_dbg_irq(wil, "configure_interrupt_moderation\n");
|
||||
|
||||
/* disable interrupt moderation for monitor
|
||||
* to get better timestamp precision
|
||||
*/
|
||||
if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR)
|
||||
if (wdev->iftype == NL80211_IFTYPE_MONITOR)
|
||||
return;
|
||||
|
||||
/* Disable and clear tx counter before (re)configuration */
|
||||
|
@ -340,7 +342,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
|
|||
|
||||
static void wil_notify_fw_error(struct wil6210_priv *wil)
|
||||
{
|
||||
struct device *dev = &wil_to_ndev(wil)->dev;
|
||||
struct device *dev = &wil->main_ndev->dev;
|
||||
char *envp[3] = {
|
||||
[0] = "SOURCE=wil6210",
|
||||
[1] = "EVENT=FW_ERROR",
|
||||
|
|
|
@ -160,24 +160,34 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
|
|||
}
|
||||
}
|
||||
|
||||
static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
|
||||
static void wil_disconnect_cid(struct wil6210_vif *vif, int cid,
|
||||
u16 reason_code, bool from_event)
|
||||
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
{
|
||||
uint i;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct net_device *ndev = vif_to_ndev(vif);
|
||||
struct wireless_dev *wdev = vif_to_wdev(vif);
|
||||
struct wil_sta_info *sta = &wil->sta[cid];
|
||||
|
||||
might_sleep();
|
||||
wil_dbg_misc(wil, "disconnect_cid: CID %d, status %d\n",
|
||||
cid, sta->status);
|
||||
wil_dbg_misc(wil, "disconnect_cid: CID %d, MID %d, status %d\n",
|
||||
cid, sta->mid, sta->status);
|
||||
/* inform upper/lower layers */
|
||||
if (sta->status != wil_sta_unused) {
|
||||
if (vif->mid != sta->mid) {
|
||||
wil_err(wil, "STA MID mismatch with VIF MID(%d)\n",
|
||||
vif->mid);
|
||||
/* let FW override sta->mid but be more strict with
|
||||
* user space requests
|
||||
*/
|
||||
if (!from_event)
|
||||
return;
|
||||
}
|
||||
if (!from_event) {
|
||||
bool del_sta = (wdev->iftype == NL80211_IFTYPE_AP) ?
|
||||
disable_ap_sme : false;
|
||||
wmi_disconnect_sta(wil, sta->addr, reason_code,
|
||||
wmi_disconnect_sta(vif, sta->addr, reason_code,
|
||||
true, del_sta);
|
||||
}
|
||||
|
||||
|
@ -191,6 +201,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
|||
break;
|
||||
}
|
||||
sta->status = wil_sta_unused;
|
||||
sta->mid = U8_MAX;
|
||||
}
|
||||
/* reorder buffers */
|
||||
for (i = 0; i < WIL_STA_TID_NUM; i++) {
|
||||
|
@ -216,28 +227,33 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
|||
memset(&sta->stats, 0, sizeof(sta->stats));
|
||||
}
|
||||
|
||||
static bool wil_is_connected(struct wil6210_priv *wil)
|
||||
static bool wil_vif_is_connected(struct wil6210_priv *wil, u8 mid)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
|
||||
if (wil->sta[i].status == wil_sta_connected)
|
||||
if (wil->sta[i].mid == mid &&
|
||||
wil->sta[i].status == wil_sta_connected)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
|
||||
static void _wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
|
||||
u16 reason_code, bool from_event)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int cid = -ENOENT;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct net_device *ndev;
|
||||
struct wireless_dev *wdev;
|
||||
|
||||
if (unlikely(!ndev))
|
||||
if (unlikely(!vif))
|
||||
return;
|
||||
|
||||
ndev = vif_to_ndev(vif);
|
||||
wdev = vif_to_wdev(vif);
|
||||
|
||||
might_sleep();
|
||||
wil_info(wil, "bssid=%pM, reason=%d, ev%s\n", bssid,
|
||||
reason_code, from_event ? "+" : "-");
|
||||
|
@ -254,48 +270,51 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
|
|||
*/
|
||||
if (bssid && !is_broadcast_ether_addr(bssid) &&
|
||||
!ether_addr_equal_unaligned(ndev->dev_addr, bssid)) {
|
||||
cid = wil_find_cid(wil, bssid);
|
||||
cid = wil_find_cid(wil, vif->mid, bssid);
|
||||
wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n",
|
||||
bssid, cid, reason_code);
|
||||
if (cid >= 0) /* disconnect 1 peer */
|
||||
wil_disconnect_cid(wil, cid, reason_code, from_event);
|
||||
wil_disconnect_cid(vif, cid, reason_code, from_event);
|
||||
} else { /* all */
|
||||
wil_dbg_misc(wil, "Disconnect all\n");
|
||||
for (cid = 0; cid < WIL6210_MAX_CID; cid++)
|
||||
wil_disconnect_cid(wil, cid, reason_code, from_event);
|
||||
wil_disconnect_cid(vif, cid, reason_code, from_event);
|
||||
}
|
||||
|
||||
/* link state */
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
wil_bcast_fini(wil);
|
||||
wil_update_net_queues_bh(wil, NULL, true);
|
||||
wil_bcast_fini(vif);
|
||||
wil_update_net_queues_bh(wil, vif, NULL, true);
|
||||
netif_carrier_off(ndev);
|
||||
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
|
||||
if (!wil_has_other_active_ifaces(wil, ndev, false, true))
|
||||
wil6210_bus_request(wil, WIL_DEFAULT_BUS_REQUEST_KBPS);
|
||||
|
||||
if (test_bit(wil_status_fwconnected, wil->status)) {
|
||||
clear_bit(wil_status_fwconnected, wil->status);
|
||||
if (test_and_clear_bit(wil_vif_fwconnected, vif->status)) {
|
||||
atomic_dec(&wil->connected_vifs);
|
||||
cfg80211_disconnected(ndev, reason_code,
|
||||
NULL, 0,
|
||||
wil->locally_generated_disc,
|
||||
vif->locally_generated_disc,
|
||||
GFP_KERNEL);
|
||||
wil->locally_generated_disc = false;
|
||||
} else if (test_bit(wil_status_fwconnecting, wil->status)) {
|
||||
vif->locally_generated_disc = false;
|
||||
} else if (test_bit(wil_vif_fwconnecting, vif->status)) {
|
||||
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||
GFP_KERNEL);
|
||||
wil->bss = NULL;
|
||||
vif->bss = NULL;
|
||||
}
|
||||
clear_bit(wil_status_fwconnecting, wil->status);
|
||||
clear_bit(wil_vif_fwconnecting, vif->status);
|
||||
break;
|
||||
case NL80211_IFTYPE_AP:
|
||||
case NL80211_IFTYPE_P2P_GO:
|
||||
if (!wil_is_connected(wil)) {
|
||||
wil_update_net_queues_bh(wil, NULL, true);
|
||||
clear_bit(wil_status_fwconnected, wil->status);
|
||||
if (!wil_vif_is_connected(wil, vif->mid)) {
|
||||
wil_update_net_queues_bh(wil, vif, NULL, true);
|
||||
if (test_and_clear_bit(wil_vif_fwconnected,
|
||||
vif->status))
|
||||
atomic_dec(&wil->connected_vifs);
|
||||
} else {
|
||||
wil_update_net_queues_bh(wil, NULL, false);
|
||||
wil_update_net_queues_bh(wil, vif, NULL, false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -303,26 +322,27 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
|
|||
}
|
||||
}
|
||||
|
||||
static void wil_disconnect_worker(struct work_struct *work)
|
||||
void wil_disconnect_worker(struct work_struct *work)
|
||||
{
|
||||
struct wil6210_priv *wil = container_of(work,
|
||||
struct wil6210_priv, disconnect_worker);
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wil6210_vif *vif = container_of(work,
|
||||
struct wil6210_vif, disconnect_worker);
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct net_device *ndev = vif_to_ndev(vif);
|
||||
int rc;
|
||||
struct {
|
||||
struct wmi_cmd_hdr wmi;
|
||||
struct wmi_disconnect_event evt;
|
||||
} __packed reply;
|
||||
|
||||
if (test_bit(wil_status_fwconnected, wil->status))
|
||||
if (test_bit(wil_vif_fwconnected, vif->status))
|
||||
/* connect succeeded after all */
|
||||
return;
|
||||
|
||||
if (!test_bit(wil_status_fwconnecting, wil->status))
|
||||
if (!test_bit(wil_vif_fwconnecting, vif->status))
|
||||
/* already disconnected */
|
||||
return;
|
||||
|
||||
rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
|
||||
rc = wmi_call(wil, WMI_DISCONNECT_CMDID, vif->mid, NULL, 0,
|
||||
WMI_DISCONNECT_EVENTID, &reply, sizeof(reply),
|
||||
WIL6210_DISCONNECT_TO_MS);
|
||||
if (rc) {
|
||||
|
@ -330,35 +350,11 @@ static void wil_disconnect_worker(struct work_struct *work)
|
|||
return;
|
||||
}
|
||||
|
||||
wil_update_net_queues_bh(wil, NULL, true);
|
||||
wil_update_net_queues_bh(wil, vif, NULL, true);
|
||||
netif_carrier_off(ndev);
|
||||
cfg80211_connect_result(ndev, NULL, NULL, 0, NULL, 0,
|
||||
WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL);
|
||||
clear_bit(wil_status_fwconnecting, wil->status);
|
||||
}
|
||||
|
||||
static void wil_connect_timer_fn(struct timer_list *t)
|
||||
{
|
||||
struct wil6210_priv *wil = from_timer(wil, t, connect_timer);
|
||||
bool q;
|
||||
|
||||
wil_err(wil, "Connect timeout detected, disconnect station\n");
|
||||
|
||||
/* reschedule to thread context - disconnect won't
|
||||
* run from atomic context.
|
||||
* queue on wmi_wq to prevent race with connect event.
|
||||
*/
|
||||
q = queue_work(wil->wmi_wq, &wil->disconnect_worker);
|
||||
wil_dbg_wmi(wil, "queue_work of disconnect_worker -> %d\n", q);
|
||||
}
|
||||
|
||||
static void wil_scan_timer_fn(struct timer_list *t)
|
||||
{
|
||||
struct wil6210_priv *wil = from_timer(wil, t, scan_timer);
|
||||
|
||||
clear_bit(wil_status_fwready, wil->status);
|
||||
wil_err(wil, "Scan timeout detected, start fw error recovery\n");
|
||||
wil_fw_error_recovery(wil);
|
||||
clear_bit(wil_vif_fwconnecting, vif->status);
|
||||
}
|
||||
|
||||
static int wil_wait_for_recovery(struct wil6210_priv *wil)
|
||||
|
@ -394,12 +390,12 @@ static void wil_fw_error_worker(struct work_struct *work)
|
|||
{
|
||||
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
|
||||
fw_error_worker);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct wireless_dev *wdev = ndev->ieee80211_ptr;
|
||||
|
||||
wil_dbg_misc(wil, "fw error worker\n");
|
||||
|
||||
if (!(ndev->flags & IFF_UP)) {
|
||||
if (!ndev || !(ndev->flags & IFF_UP)) {
|
||||
wil_info(wil, "No recovery - interface is down\n");
|
||||
return;
|
||||
}
|
||||
|
@ -429,6 +425,10 @@ static void wil_fw_error_worker(struct work_struct *work)
|
|||
return;
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
/* Needs adaptation for multiple VIFs
|
||||
* need to go over all VIFs and consider the appropriate
|
||||
* recovery.
|
||||
*/
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
|
@ -461,8 +461,9 @@ static int wil_find_free_vring(struct wil6210_priv *wil)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
int wil_tx_init(struct wil6210_priv *wil, int cid)
|
||||
int wil_tx_init(struct wil6210_vif *vif, int cid)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int rc = -EINVAL, ringid;
|
||||
|
||||
if (cid < 0) {
|
||||
|
@ -475,21 +476,22 @@ int wil_tx_init(struct wil6210_priv *wil, int cid)
|
|||
goto out;
|
||||
}
|
||||
|
||||
wil_dbg_wmi(wil, "Configure for connection CID %d vring %d\n",
|
||||
cid, ringid);
|
||||
wil_dbg_wmi(wil, "Configure for connection CID %d MID %d vring %d\n",
|
||||
cid, vif->mid, ringid);
|
||||
|
||||
rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
|
||||
rc = wil_vring_init_tx(vif, ringid, 1 << tx_ring_order, cid, 0);
|
||||
if (rc)
|
||||
wil_err(wil, "wil_vring_init_tx for CID %d vring %d failed\n",
|
||||
cid, ringid);
|
||||
wil_err(wil, "init TX for CID %d MID %d vring %d failed\n",
|
||||
cid, vif->mid, ringid);
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
int wil_bcast_init(struct wil6210_priv *wil)
|
||||
int wil_bcast_init(struct wil6210_vif *vif)
|
||||
{
|
||||
int ri = wil->bcast_vring, rc;
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int ri = vif->bcast_vring, rc;
|
||||
|
||||
if ((ri >= 0) && wil->vring_tx[ri].va)
|
||||
return 0;
|
||||
|
@ -498,25 +500,38 @@ int wil_bcast_init(struct wil6210_priv *wil)
|
|||
if (ri < 0)
|
||||
return ri;
|
||||
|
||||
wil->bcast_vring = ri;
|
||||
rc = wil_vring_init_bcast(wil, ri, 1 << bcast_ring_order);
|
||||
vif->bcast_vring = ri;
|
||||
rc = wil_vring_init_bcast(vif, ri, 1 << bcast_ring_order);
|
||||
if (rc)
|
||||
wil->bcast_vring = -1;
|
||||
vif->bcast_vring = -1;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void wil_bcast_fini(struct wil6210_priv *wil)
|
||||
void wil_bcast_fini(struct wil6210_vif *vif)
|
||||
{
|
||||
int ri = wil->bcast_vring;
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int ri = vif->bcast_vring;
|
||||
|
||||
if (ri < 0)
|
||||
return;
|
||||
|
||||
wil->bcast_vring = -1;
|
||||
vif->bcast_vring = -1;
|
||||
wil_vring_fini_tx(wil, ri);
|
||||
}
|
||||
|
||||
void wil_bcast_fini_all(struct wil6210_priv *wil)
|
||||
{
|
||||
int i;
|
||||
struct wil6210_vif *vif;
|
||||
|
||||
for (i = 0; i < wil->max_vifs; i++) {
|
||||
vif = wil->vifs[i];
|
||||
if (vif)
|
||||
wil_bcast_fini(vif);
|
||||
}
|
||||
}
|
||||
|
||||
int wil_priv_init(struct wil6210_priv *wil)
|
||||
{
|
||||
uint i;
|
||||
|
@ -524,38 +539,29 @@ int wil_priv_init(struct wil6210_priv *wil)
|
|||
wil_dbg_misc(wil, "priv_init\n");
|
||||
|
||||
memset(wil->sta, 0, sizeof(wil->sta));
|
||||
for (i = 0; i < WIL6210_MAX_CID; i++)
|
||||
for (i = 0; i < WIL6210_MAX_CID; i++) {
|
||||
spin_lock_init(&wil->sta[i].tid_rx_lock);
|
||||
wil->sta[i].mid = U8_MAX;
|
||||
}
|
||||
|
||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++)
|
||||
spin_lock_init(&wil->vring_tx_data[i].lock);
|
||||
|
||||
mutex_init(&wil->mutex);
|
||||
mutex_init(&wil->vif_mutex);
|
||||
mutex_init(&wil->wmi_mutex);
|
||||
mutex_init(&wil->probe_client_mutex);
|
||||
mutex_init(&wil->p2p_wdev_mutex);
|
||||
mutex_init(&wil->halp.lock);
|
||||
|
||||
init_completion(&wil->wmi_ready);
|
||||
init_completion(&wil->wmi_call);
|
||||
init_completion(&wil->halp.comp);
|
||||
|
||||
wil->bcast_vring = -1;
|
||||
timer_setup(&wil->connect_timer, wil_connect_timer_fn, 0);
|
||||
timer_setup(&wil->scan_timer, wil_scan_timer_fn, 0);
|
||||
timer_setup(&wil->p2p.discovery_timer, wil_p2p_discovery_timer_fn, 0);
|
||||
|
||||
INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
|
||||
INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
|
||||
INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
|
||||
INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker);
|
||||
INIT_WORK(&wil->p2p.delayed_listen_work, wil_p2p_delayed_listen_work);
|
||||
|
||||
INIT_LIST_HEAD(&wil->pending_wmi_ev);
|
||||
INIT_LIST_HEAD(&wil->probe_client_pending);
|
||||
spin_lock_init(&wil->wmi_ev_lock);
|
||||
spin_lock_init(&wil->net_queue_lock);
|
||||
wil->net_queue_stopped = 1;
|
||||
init_waitqueue_head(&wil->wq);
|
||||
|
||||
wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
|
||||
|
@ -582,6 +588,9 @@ int wil_priv_init(struct wil6210_priv *wil)
|
|||
memset(&wil->suspend_stats, 0, sizeof(wil->suspend_stats));
|
||||
wil->vring_idle_trsh = 16;
|
||||
|
||||
wil->reply_mid = U8_MAX;
|
||||
wil->max_vifs = 1;
|
||||
|
||||
return 0;
|
||||
|
||||
out_wmi_wq:
|
||||
|
@ -600,7 +609,7 @@ void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps)
|
|||
|
||||
/**
|
||||
* wil6210_disconnect - disconnect one connection
|
||||
* @wil: driver context
|
||||
* @vif: virtual interface context
|
||||
* @bssid: peer to disconnect, NULL to disconnect all
|
||||
* @reason_code: Reason code for the Disassociation frame
|
||||
* @from_event: whether is invoked from FW event handler
|
||||
|
@ -608,13 +617,15 @@ void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps)
|
|||
* Disconnect and release associated resources. If invoked not from the
|
||||
* FW event handler, issue WMI command(s) to trigger MAC disconnect.
|
||||
*/
|
||||
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
|
||||
void wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
|
||||
u16 reason_code, bool from_event)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
|
||||
wil_dbg_misc(wil, "disconnect\n");
|
||||
|
||||
del_timer_sync(&wil->connect_timer);
|
||||
_wil6210_disconnect(wil, bssid, reason_code, from_event);
|
||||
del_timer_sync(&vif->connect_timer);
|
||||
_wil6210_disconnect(vif, bssid, reason_code, from_event);
|
||||
}
|
||||
|
||||
void wil_priv_deinit(struct wil6210_priv *wil)
|
||||
|
@ -622,18 +633,8 @@ void wil_priv_deinit(struct wil6210_priv *wil)
|
|||
wil_dbg_misc(wil, "priv_deinit\n");
|
||||
|
||||
wil_set_recovery_state(wil, fw_recovery_idle);
|
||||
del_timer_sync(&wil->scan_timer);
|
||||
del_timer_sync(&wil->p2p.discovery_timer);
|
||||
cancel_work_sync(&wil->disconnect_worker);
|
||||
cancel_work_sync(&wil->fw_error_worker);
|
||||
cancel_work_sync(&wil->p2p.discovery_expired_work);
|
||||
cancel_work_sync(&wil->p2p.delayed_listen_work);
|
||||
mutex_lock(&wil->mutex);
|
||||
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
mutex_unlock(&wil->mutex);
|
||||
wmi_event_flush(wil);
|
||||
wil_probe_client_flush(wil);
|
||||
cancel_work_sync(&wil->probe_client_worker);
|
||||
destroy_workqueue(wil->wq_service);
|
||||
destroy_workqueue(wil->wmi_wq);
|
||||
}
|
||||
|
@ -715,7 +716,7 @@ static void wil_bl_prepare_halt(struct wil6210_priv *wil)
|
|||
offsetof(struct bl_dedicated_registers_v0,
|
||||
boot_loader_struct_version));
|
||||
if (!tmp) {
|
||||
wil_dbg_misc(wil, "old BL, skipping halt preperation\n");
|
||||
wil_dbg_misc(wil, "old BL, skipping halt preparation\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -943,7 +944,7 @@ void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r)
|
|||
|
||||
static int wil_get_bl_info(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct wiphy *wiphy = wil_to_wiphy(wil);
|
||||
union {
|
||||
struct bl_dedicated_registers_v0 bl0;
|
||||
|
@ -1035,7 +1036,7 @@ static void wil_bl_crash_info(struct wil6210_priv *wil, bool is_err)
|
|||
|
||||
static int wil_get_otp_info(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct wiphy *wiphy = wil_to_wiphy(wil);
|
||||
u8 mac[8];
|
||||
|
||||
|
@ -1069,31 +1070,46 @@ static int wil_wait_for_fw_ready(struct wil6210_priv *wil)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void wil_abort_scan(struct wil6210_priv *wil, bool sync)
|
||||
void wil_abort_scan(struct wil6210_vif *vif, bool sync)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int rc;
|
||||
struct cfg80211_scan_info info = {
|
||||
.aborted = true,
|
||||
};
|
||||
|
||||
lockdep_assert_held(&wil->p2p_wdev_mutex);
|
||||
lockdep_assert_held(&wil->vif_mutex);
|
||||
|
||||
if (!wil->scan_request)
|
||||
if (!vif->scan_request)
|
||||
return;
|
||||
|
||||
wil_dbg_misc(wil, "Abort scan_request 0x%p\n", wil->scan_request);
|
||||
del_timer_sync(&wil->scan_timer);
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
rc = wmi_abort_scan(wil);
|
||||
wil_dbg_misc(wil, "Abort scan_request 0x%p\n", vif->scan_request);
|
||||
del_timer_sync(&vif->scan_timer);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
rc = wmi_abort_scan(vif);
|
||||
if (!rc && sync)
|
||||
wait_event_interruptible_timeout(wil->wq, !wil->scan_request,
|
||||
wait_event_interruptible_timeout(wil->wq, !vif->scan_request,
|
||||
msecs_to_jiffies(
|
||||
WAIT_FOR_SCAN_ABORT_MS));
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
if (wil->scan_request) {
|
||||
cfg80211_scan_done(wil->scan_request, &info);
|
||||
wil->scan_request = NULL;
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
if (vif->scan_request) {
|
||||
cfg80211_scan_done(vif->scan_request, &info);
|
||||
vif->scan_request = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync)
|
||||
{
|
||||
int i;
|
||||
|
||||
lockdep_assert_held(&wil->vif_mutex);
|
||||
|
||||
for (i = 0; i < wil->max_vifs; i++) {
|
||||
struct wil6210_vif *vif = wil->vifs[i];
|
||||
|
||||
if (vif)
|
||||
wil_abort_scan(vif, sync);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1138,6 +1154,34 @@ static void wil_pre_fw_config(struct wil6210_priv *wil)
|
|||
}
|
||||
}
|
||||
|
||||
static int wil_restore_vifs(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wil6210_vif *vif;
|
||||
struct net_device *ndev;
|
||||
struct wireless_dev *wdev;
|
||||
int i, rc;
|
||||
|
||||
for (i = 0; i < wil->max_vifs; i++) {
|
||||
vif = wil->vifs[i];
|
||||
if (!vif)
|
||||
continue;
|
||||
vif->ap_isolate = 0;
|
||||
if (vif->mid) {
|
||||
ndev = vif_to_ndev(vif);
|
||||
wdev = vif_to_wdev(vif);
|
||||
rc = wmi_port_allocate(wil, vif->mid, ndev->dev_addr,
|
||||
wdev->iftype);
|
||||
if (rc) {
|
||||
wil_err(wil, "fail to restore VIF %d type %d, rc %d\n",
|
||||
i, wdev->iftype, rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We reset all the structures, and we reset the UMAC.
|
||||
* After calling this routine, you're expected to reload
|
||||
|
@ -1145,9 +1189,10 @@ static void wil_pre_fw_config(struct wil6210_priv *wil)
|
|||
*/
|
||||
int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||
{
|
||||
int rc;
|
||||
int rc, i;
|
||||
unsigned long status_flags = BIT(wil_status_resetting);
|
||||
int no_flash;
|
||||
struct wil6210_vif *vif;
|
||||
|
||||
wil_dbg_misc(wil, "reset\n");
|
||||
|
||||
|
@ -1158,7 +1203,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
|||
static const u8 mac[ETH_ALEN] = {
|
||||
0x00, 0xde, 0xad, 0x12, 0x34, 0x56,
|
||||
};
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
|
||||
ether_addr_copy(ndev->perm_addr, mac);
|
||||
ether_addr_copy(ndev->dev_addr, ndev->perm_addr);
|
||||
|
@ -1196,17 +1241,23 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
|||
goto out;
|
||||
}
|
||||
|
||||
cancel_work_sync(&wil->disconnect_worker);
|
||||
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
wil_bcast_fini(wil);
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
wil_abort_scan_all_vifs(wil, false);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
|
||||
for (i = 0; i < wil->max_vifs; i++) {
|
||||
vif = wil->vifs[i];
|
||||
if (vif) {
|
||||
cancel_work_sync(&vif->disconnect_worker);
|
||||
wil6210_disconnect(vif, NULL,
|
||||
WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
}
|
||||
}
|
||||
wil_bcast_fini_all(wil);
|
||||
|
||||
/* Disable device led before reset*/
|
||||
wmi_led_cfg(wil, false);
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
wil_abort_scan(wil, false);
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
|
||||
/* prevent NAPI from being scheduled and prevent wmi commands */
|
||||
mutex_lock(&wil->wmi_mutex);
|
||||
if (test_bit(wil_status_suspending, wil->status))
|
||||
|
@ -1276,7 +1327,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
|||
}
|
||||
|
||||
/* init after reset */
|
||||
wil->ap_isolate = 0;
|
||||
reinit_completion(&wil->wmi_ready);
|
||||
reinit_completion(&wil->wmi_call);
|
||||
reinit_completion(&wil->halp.comp);
|
||||
|
@ -1299,6 +1349,12 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
|||
return rc;
|
||||
}
|
||||
|
||||
rc = wil_restore_vifs(wil);
|
||||
if (rc) {
|
||||
wil_err(wil, "failed to restore vifs, rc %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
wil_collect_fw_info(wil);
|
||||
|
||||
if (wil->ps_profile != WMI_PS_PROFILE_TYPE_DEFAULT)
|
||||
|
@ -1337,8 +1393,8 @@ void wil_fw_error_recovery(struct wil6210_priv *wil)
|
|||
|
||||
int __wil_up(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct wireless_dev *wdev = ndev->ieee80211_ptr;
|
||||
int rc;
|
||||
|
||||
WARN_ON(!mutex_is_locked(&wil->mutex));
|
||||
|
@ -1420,10 +1476,10 @@ int __wil_down(struct wil6210_priv *wil)
|
|||
}
|
||||
wil_enable_irq(wil);
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
wil_p2p_stop_radio_operations(wil);
|
||||
wil_abort_scan(wil, false);
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
wil_abort_scan_all_vifs(wil, false);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
|
||||
return wil_reset(wil, false);
|
||||
}
|
||||
|
@ -1442,13 +1498,14 @@ int wil_down(struct wil6210_priv *wil)
|
|||
return rc;
|
||||
}
|
||||
|
||||
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac)
|
||||
int wil_find_cid(struct wil6210_priv *wil, u8 mid, const u8 *mac)
|
||||
{
|
||||
int i;
|
||||
int rc = -ENOENT;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
|
||||
if ((wil->sta[i].status != wil_sta_unused) &&
|
||||
if (wil->sta[i].mid == mid &&
|
||||
wil->sta[i].status != wil_sta_unused &&
|
||||
ether_addr_equal(wil->sta[i].addr, mac)) {
|
||||
rc = i;
|
||||
break;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -15,13 +16,41 @@
|
|||
*/
|
||||
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include "wil6210.h"
|
||||
#include "txrx.h"
|
||||
|
||||
bool wil_has_other_active_ifaces(struct wil6210_priv *wil,
|
||||
struct net_device *ndev, bool up, bool ok)
|
||||
{
|
||||
int i;
|
||||
struct wil6210_vif *vif;
|
||||
struct net_device *ndev_i;
|
||||
|
||||
for (i = 0; i < wil->max_vifs; i++) {
|
||||
vif = wil->vifs[i];
|
||||
if (vif) {
|
||||
ndev_i = vif_to_ndev(vif);
|
||||
if (ndev_i != ndev)
|
||||
if ((up && (ndev_i->flags & IFF_UP)) ||
|
||||
(ok && netif_carrier_ok(ndev_i)))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok)
|
||||
{
|
||||
/* use NULL ndev argument to check all interfaces */
|
||||
return wil_has_other_active_ifaces(wil, NULL, up, ok);
|
||||
}
|
||||
|
||||
static int wil_open(struct net_device *ndev)
|
||||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
wil_dbg_misc(wil, "open\n");
|
||||
|
||||
|
@ -31,13 +60,16 @@ static int wil_open(struct net_device *ndev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
rc = wil_pm_runtime_get(wil);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
|
||||
wil_dbg_misc(wil, "open, first iface\n");
|
||||
rc = wil_pm_runtime_get(wil);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = wil_up(wil);
|
||||
if (rc)
|
||||
wil_pm_runtime_put(wil);
|
||||
rc = wil_up(wil);
|
||||
if (rc)
|
||||
wil_pm_runtime_put(wil);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -45,13 +77,16 @@ static int wil_open(struct net_device *ndev)
|
|||
static int wil_stop(struct net_device *ndev)
|
||||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
wil_dbg_misc(wil, "stop\n");
|
||||
|
||||
rc = wil_down(wil);
|
||||
if (!rc)
|
||||
wil_pm_runtime_put(wil);
|
||||
if (!wil_has_other_active_ifaces(wil, ndev, true, false)) {
|
||||
wil_dbg_misc(wil, "stop, last iface\n");
|
||||
rc = wil_down(wil);
|
||||
if (!rc)
|
||||
wil_pm_runtime_put(wil);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -96,11 +131,19 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
|
|||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
struct vring *vring = &wil->vring_tx[i];
|
||||
struct vring_tx_data *txdata = &wil->vring_tx_data[i];
|
||||
struct wil6210_vif *vif;
|
||||
|
||||
if (!vring->va || !txdata->enabled)
|
||||
if (!vring->va || !txdata->enabled ||
|
||||
txdata->mid >= wil->max_vifs)
|
||||
continue;
|
||||
|
||||
tx_done += wil_tx_complete(wil, i);
|
||||
vif = wil->vifs[txdata->mid];
|
||||
if (unlikely(!vif)) {
|
||||
wil_dbg_txrx(wil, "Invalid MID %d\n", txdata->mid);
|
||||
continue;
|
||||
}
|
||||
|
||||
tx_done += wil_tx_complete(vif, i);
|
||||
}
|
||||
|
||||
if (tx_done < budget) {
|
||||
|
@ -121,43 +164,136 @@ static void wil_dev_setup(struct net_device *dev)
|
|||
dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT;
|
||||
}
|
||||
|
||||
void *wil_if_alloc(struct device *dev)
|
||||
static void wil_vif_deinit(struct wil6210_vif *vif)
|
||||
{
|
||||
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 wireless_dev *wdev;
|
||||
struct wil6210_priv *wil;
|
||||
struct ieee80211_channel *ch;
|
||||
int rc = 0;
|
||||
struct wil6210_vif *vif;
|
||||
u8 mid;
|
||||
|
||||
wdev = wil_cfg80211_init(dev);
|
||||
if (IS_ERR(wdev)) {
|
||||
dev_err(dev, "wil_cfg80211_init failed\n");
|
||||
return wdev;
|
||||
mid = wil_vif_find_free_mid(wil);
|
||||
if (mid == U8_MAX) {
|
||||
wil_err(wil, "no available virtual interface\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
wil = wdev_to_wil(wdev);
|
||||
wil->wdev = wdev;
|
||||
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);
|
||||
ndev = alloc_netdev(sizeof(*vif), name, name_assign_type,
|
||||
wil_dev_setup);
|
||||
if (!ndev) {
|
||||
dev_err(dev, "alloc_netdev_mqs failed\n");
|
||||
rc = -ENOMEM;
|
||||
goto out_priv;
|
||||
dev_err(wil_to_dev(wil), "alloc_netdev failed\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
if (mid == 0) {
|
||||
wil->main_ndev = ndev;
|
||||
} else {
|
||||
ndev->priv_destructor = wil_ndev_destructor;
|
||||
ndev->needs_free_netdev = true;
|
||||
}
|
||||
|
||||
vif = ndev_to_vif(ndev);
|
||||
vif->ndev = ndev;
|
||||
vif->wil = wil;
|
||||
vif->mid = mid;
|
||||
wil_vif_init(vif);
|
||||
|
||||
wdev = &vif->wdev;
|
||||
wdev->wiphy = wil->wiphy;
|
||||
wdev->iftype = iftype;
|
||||
|
||||
ndev->netdev_ops = &wil_netdev_ops;
|
||||
wil_set_ethtoolops(ndev);
|
||||
|
@ -170,21 +306,53 @@ void *wil_if_alloc(struct device *dev)
|
|||
ndev->features |= ndev->hw_features;
|
||||
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
|
||||
wdev->netdev = ndev;
|
||||
return vif;
|
||||
}
|
||||
|
||||
void *wil_if_alloc(struct device *dev)
|
||||
{
|
||||
struct wil6210_priv *wil;
|
||||
struct wil6210_vif *vif;
|
||||
int rc = 0;
|
||||
|
||||
wil = wil_cfg80211_init(dev);
|
||||
if (IS_ERR(wil)) {
|
||||
dev_err(dev, "wil_cfg80211_init failed\n");
|
||||
return wil;
|
||||
}
|
||||
|
||||
rc = wil_priv_init(wil);
|
||||
if (rc) {
|
||||
dev_err(dev, "wil_priv_init failed\n");
|
||||
goto out_cfg;
|
||||
}
|
||||
|
||||
wil_dbg_misc(wil, "if_alloc\n");
|
||||
|
||||
vif = wil_vif_alloc(wil, "wlan%d", NET_NAME_UNKNOWN,
|
||||
NL80211_IFTYPE_STATION);
|
||||
if (IS_ERR(vif)) {
|
||||
dev_err(dev, "wil_vif_alloc failed\n");
|
||||
rc = -ENOMEM;
|
||||
goto out_priv;
|
||||
}
|
||||
|
||||
wil->radio_wdev = vif_to_wdev(vif);
|
||||
|
||||
return wil;
|
||||
|
||||
out_priv:
|
||||
out_priv:
|
||||
wil_priv_deinit(wil);
|
||||
|
||||
out_wdev:
|
||||
wil_wdev_free(wil);
|
||||
out_cfg:
|
||||
wil_cfg80211_deinit(wil);
|
||||
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
void wil_if_free(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
|
||||
wil_dbg_misc(wil, "if_free\n");
|
||||
|
||||
|
@ -193,17 +361,50 @@ void wil_if_free(struct wil6210_priv *wil)
|
|||
|
||||
wil_priv_deinit(wil);
|
||||
|
||||
wil_to_ndev(wil) = NULL;
|
||||
wil->main_ndev = NULL;
|
||||
wil_ndev_destructor(ndev);
|
||||
free_netdev(ndev);
|
||||
|
||||
wil_wdev_free(wil);
|
||||
wil_cfg80211_deinit(wil);
|
||||
}
|
||||
|
||||
int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif)
|
||||
{
|
||||
struct net_device *ndev = vif_to_ndev(vif);
|
||||
struct wireless_dev *wdev = vif_to_wdev(vif);
|
||||
bool any_active = wil_has_active_ifaces(wil, true, false);
|
||||
int rc;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
if (wil->vifs[vif->mid]) {
|
||||
dev_err(&ndev->dev, "VIF with mid %d already in use\n",
|
||||
vif->mid);
|
||||
return -EEXIST;
|
||||
}
|
||||
if (any_active && vif->mid != 0) {
|
||||
rc = wmi_port_allocate(wil, vif->mid, ndev->dev_addr,
|
||||
wdev->iftype);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
rc = register_netdevice(ndev);
|
||||
if (rc < 0) {
|
||||
dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
|
||||
if (any_active && vif->mid != 0)
|
||||
wmi_port_delete(wil, vif->mid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
wil->vifs[vif->mid] = vif;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wil_if_add(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
struct wiphy *wiphy = wdev->wiphy;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wiphy *wiphy = wil->wiphy;
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct wil6210_vif *vif = ndev_to_vif(ndev);
|
||||
int rc;
|
||||
|
||||
wil_dbg_misc(wil, "entered");
|
||||
|
@ -216,33 +417,94 @@ int wil_if_add(struct wil6210_priv *wil)
|
|||
return rc;
|
||||
}
|
||||
|
||||
netif_napi_add(ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
|
||||
init_dummy_netdev(&wil->napi_ndev);
|
||||
netif_napi_add(&wil->napi_ndev, &wil->napi_rx, wil6210_netdev_poll_rx,
|
||||
WIL6210_NAPI_BUDGET);
|
||||
netif_tx_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
|
||||
netif_tx_napi_add(&wil->napi_ndev,
|
||||
&wil->napi_tx, wil6210_netdev_poll_tx,
|
||||
WIL6210_NAPI_BUDGET);
|
||||
|
||||
wil_update_net_queues_bh(wil, NULL, true);
|
||||
wil_update_net_queues_bh(wil, vif, NULL, true);
|
||||
|
||||
rc = register_netdev(ndev);
|
||||
if (rc < 0) {
|
||||
dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
|
||||
rtnl_lock();
|
||||
rc = wil_vif_add(wil, vif);
|
||||
rtnl_unlock();
|
||||
if (rc < 0)
|
||||
goto out_wiphy;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_wiphy:
|
||||
wiphy_unregister(wdev->wiphy);
|
||||
wiphy_unregister(wiphy);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void wil_vif_remove(struct wil6210_priv *wil, u8 mid)
|
||||
{
|
||||
struct wil6210_vif *vif;
|
||||
struct net_device *ndev;
|
||||
bool any_active = wil_has_active_ifaces(wil, true, false);
|
||||
|
||||
ASSERT_RTNL();
|
||||
if (mid >= wil->max_vifs) {
|
||||
wil_err(wil, "invalid MID: %d\n", mid);
|
||||
return;
|
||||
}
|
||||
|
||||
vif = wil->vifs[mid];
|
||||
if (!vif) {
|
||||
wil_err(wil, "MID %d not registered\n", mid);
|
||||
return;
|
||||
}
|
||||
|
||||
ndev = vif_to_ndev(vif);
|
||||
/* during unregister_netdevice cfg80211_leave may perform operations
|
||||
* such as stop AP, disconnect, so we only clear the VIF afterwards
|
||||
*/
|
||||
unregister_netdevice(ndev);
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
wil6210_disconnect(vif, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
if (any_active && vif->mid != 0)
|
||||
wmi_port_delete(wil, vif->mid);
|
||||
|
||||
/* make sure no one is accessing the VIF before removing */
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
wil->vifs[mid] = NULL;
|
||||
/* ensure NAPI code will see the NULL VIF */
|
||||
wmb();
|
||||
if (test_bit(wil_status_napi_en, wil->status)) {
|
||||
napi_synchronize(&wil->napi_rx);
|
||||
napi_synchronize(&wil->napi_tx);
|
||||
}
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
|
||||
flush_work(&wil->wmi_event_worker);
|
||||
del_timer_sync(&vif->connect_timer);
|
||||
cancel_work_sync(&vif->disconnect_worker);
|
||||
wil_probe_client_flush(vif);
|
||||
cancel_work_sync(&vif->probe_client_worker);
|
||||
/* for VIFs, ndev will be freed by destructor after RTNL is unlocked.
|
||||
* the main interface will be freed in wil_if_free, we need to keep it
|
||||
* a bit longer so logging macros will work.
|
||||
*/
|
||||
}
|
||||
|
||||
void wil_if_remove(struct wil6210_priv *wil)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct wireless_dev *wdev = ndev->ieee80211_ptr;
|
||||
|
||||
wil_dbg_misc(wil, "if_remove\n");
|
||||
|
||||
unregister_netdev(ndev);
|
||||
rtnl_lock();
|
||||
wil_vif_remove(wil, 0);
|
||||
rtnl_unlock();
|
||||
|
||||
netif_napi_del(&wil->napi_tx);
|
||||
netif_napi_del(&wil->napi_rx);
|
||||
|
||||
wiphy_unregister(wdev->wiphy);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -22,27 +23,28 @@
|
|||
#define P2P_SEARCH_DURATION_MS 500
|
||||
#define P2P_DEFAULT_BI 100
|
||||
|
||||
static int wil_p2p_start_listen(struct wil6210_priv *wil)
|
||||
static int wil_p2p_start_listen(struct wil6210_vif *vif)
|
||||
{
|
||||
struct wil_p2p_info *p2p = &wil->p2p;
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct wil_p2p_info *p2p = &vif->p2p;
|
||||
u8 channel = p2p->listen_chan.hw_value;
|
||||
int rc;
|
||||
|
||||
lockdep_assert_held(&wil->mutex);
|
||||
|
||||
rc = wmi_p2p_cfg(wil, channel, P2P_DEFAULT_BI);
|
||||
rc = wmi_p2p_cfg(vif, channel, P2P_DEFAULT_BI);
|
||||
if (rc) {
|
||||
wil_err(wil, "wmi_p2p_cfg failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
|
||||
rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
|
||||
if (rc) {
|
||||
wil_err(wil, "wmi_set_ssid failed\n");
|
||||
goto out_stop;
|
||||
}
|
||||
|
||||
rc = wmi_start_listen(wil);
|
||||
rc = wmi_start_listen(vif);
|
||||
if (rc) {
|
||||
wil_err(wil, "wmi_start_listen failed\n");
|
||||
goto out_stop;
|
||||
|
@ -53,7 +55,7 @@ static int wil_p2p_start_listen(struct wil6210_priv *wil)
|
|||
jiffies + msecs_to_jiffies(p2p->listen_duration));
|
||||
out_stop:
|
||||
if (rc)
|
||||
wmi_stop_discovery(wil);
|
||||
wmi_stop_discovery(vif);
|
||||
|
||||
out:
|
||||
return rc;
|
||||
|
@ -65,20 +67,12 @@ bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request)
|
|||
(request->channels[0]->hw_value == P2P_DMG_SOCIAL_CHANNEL);
|
||||
}
|
||||
|
||||
void wil_p2p_discovery_timer_fn(struct timer_list *t)
|
||||
{
|
||||
struct wil6210_priv *wil = from_timer(wil, t, p2p.discovery_timer);
|
||||
|
||||
wil_dbg_misc(wil, "p2p_discovery_timer_fn\n");
|
||||
|
||||
schedule_work(&wil->p2p.discovery_expired_work);
|
||||
}
|
||||
|
||||
int wil_p2p_search(struct wil6210_priv *wil,
|
||||
int wil_p2p_search(struct wil6210_vif *vif,
|
||||
struct cfg80211_scan_request *request)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int rc;
|
||||
struct wil_p2p_info *p2p = &wil->p2p;
|
||||
struct wil_p2p_info *p2p = &vif->p2p;
|
||||
|
||||
wil_dbg_misc(wil, "p2p_search: channel %d\n", P2P_DMG_SOCIAL_CHANNEL);
|
||||
|
||||
|
@ -90,20 +84,20 @@ int wil_p2p_search(struct wil6210_priv *wil,
|
|||
goto out;
|
||||
}
|
||||
|
||||
rc = wmi_p2p_cfg(wil, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
|
||||
rc = wmi_p2p_cfg(vif, P2P_DMG_SOCIAL_CHANNEL, P2P_DEFAULT_BI);
|
||||
if (rc) {
|
||||
wil_err(wil, "wmi_p2p_cfg failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = wmi_set_ssid(wil, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
|
||||
rc = wmi_set_ssid(vif, strlen(P2P_WILDCARD_SSID), P2P_WILDCARD_SSID);
|
||||
if (rc) {
|
||||
wil_err(wil, "wmi_set_ssid failed\n");
|
||||
goto out_stop;
|
||||
}
|
||||
|
||||
/* Set application IE to probe request and probe response */
|
||||
rc = wmi_set_ie(wil, WMI_FRAME_PROBE_REQ,
|
||||
rc = wmi_set_ie(vif, WMI_FRAME_PROBE_REQ,
|
||||
request->ie_len, request->ie);
|
||||
if (rc) {
|
||||
wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_REQ) failed\n");
|
||||
|
@ -113,14 +107,14 @@ int wil_p2p_search(struct wil6210_priv *wil,
|
|||
/* supplicant doesn't provide Probe Response IEs. As a workaround -
|
||||
* re-use Probe Request IEs
|
||||
*/
|
||||
rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP,
|
||||
rc = wmi_set_ie(vif, WMI_FRAME_PROBE_RESP,
|
||||
request->ie_len, request->ie);
|
||||
if (rc) {
|
||||
wil_err(wil, "wmi_set_ie(WMI_FRAME_PROBE_RESP) failed\n");
|
||||
goto out_stop;
|
||||
}
|
||||
|
||||
rc = wmi_start_search(wil);
|
||||
rc = wmi_start_search(vif);
|
||||
if (rc) {
|
||||
wil_err(wil, "wmi_start_search failed\n");
|
||||
goto out_stop;
|
||||
|
@ -133,7 +127,7 @@ int wil_p2p_search(struct wil6210_priv *wil,
|
|||
|
||||
out_stop:
|
||||
if (rc)
|
||||
wmi_stop_discovery(wil);
|
||||
wmi_stop_discovery(vif);
|
||||
|
||||
out:
|
||||
return rc;
|
||||
|
@ -143,7 +137,8 @@ int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
|
|||
unsigned int duration, struct ieee80211_channel *chan,
|
||||
u64 *cookie)
|
||||
{
|
||||
struct wil_p2p_info *p2p = &wil->p2p;
|
||||
struct wil6210_vif *vif = wdev_to_vif(wil, wdev);
|
||||
struct wil_p2p_info *p2p = &vif->p2p;
|
||||
int rc;
|
||||
|
||||
if (!chan)
|
||||
|
@ -163,23 +158,24 @@ int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
|
|||
*cookie = ++p2p->cookie;
|
||||
p2p->listen_duration = duration;
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
if (wil->scan_request) {
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
if (vif->scan_request) {
|
||||
wil_dbg_misc(wil, "Delaying p2p listen until scan done\n");
|
||||
p2p->pending_listen_wdev = wdev;
|
||||
p2p->discovery_started = 1;
|
||||
rc = 0;
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
goto out;
|
||||
}
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
|
||||
rc = wil_p2p_start_listen(wil);
|
||||
rc = wil_p2p_start_listen(vif);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
p2p->discovery_started = 1;
|
||||
wil->radio_wdev = wdev;
|
||||
if (vif->mid == 0)
|
||||
wil->radio_wdev = wdev;
|
||||
|
||||
cfg80211_ready_on_channel(wdev, *cookie, chan, duration,
|
||||
GFP_KERNEL);
|
||||
|
@ -189,9 +185,9 @@ out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
|
||||
u8 wil_p2p_stop_discovery(struct wil6210_vif *vif)
|
||||
{
|
||||
struct wil_p2p_info *p2p = &wil->p2p;
|
||||
struct wil_p2p_info *p2p = &vif->p2p;
|
||||
u8 started = p2p->discovery_started;
|
||||
|
||||
if (p2p->discovery_started) {
|
||||
|
@ -200,7 +196,7 @@ u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
|
|||
p2p->pending_listen_wdev = NULL;
|
||||
} else {
|
||||
del_timer_sync(&p2p->discovery_timer);
|
||||
wmi_stop_discovery(wil);
|
||||
wmi_stop_discovery(vif);
|
||||
}
|
||||
p2p->discovery_started = 0;
|
||||
}
|
||||
|
@ -208,9 +204,10 @@ u8 wil_p2p_stop_discovery(struct wil6210_priv *wil)
|
|||
return started;
|
||||
}
|
||||
|
||||
int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
|
||||
int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie)
|
||||
{
|
||||
struct wil_p2p_info *p2p = &wil->p2p;
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct wil_p2p_info *p2p = &vif->p2p;
|
||||
u8 started;
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
|
@ -222,7 +219,7 @@ int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
started = wil_p2p_stop_discovery(wil);
|
||||
started = wil_p2p_stop_discovery(vif);
|
||||
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
|
@ -231,13 +228,14 @@ int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
cfg80211_remain_on_channel_expired(wil->radio_wdev,
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
|
||||
p2p->cookie,
|
||||
&p2p->listen_chan,
|
||||
GFP_KERNEL);
|
||||
wil->radio_wdev = wil->wdev;
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
if (vif->mid == 0)
|
||||
wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -245,40 +243,43 @@ void wil_p2p_listen_expired(struct work_struct *work)
|
|||
{
|
||||
struct wil_p2p_info *p2p = container_of(work,
|
||||
struct wil_p2p_info, discovery_expired_work);
|
||||
struct wil6210_priv *wil = container_of(p2p,
|
||||
struct wil6210_priv, p2p);
|
||||
struct wil6210_vif *vif = container_of(p2p,
|
||||
struct wil6210_vif, p2p);
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
u8 started;
|
||||
|
||||
wil_dbg_misc(wil, "p2p_listen_expired\n");
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
started = wil_p2p_stop_discovery(wil);
|
||||
started = wil_p2p_stop_discovery(vif);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
if (started) {
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
cfg80211_remain_on_channel_expired(wil->radio_wdev,
|
||||
p2p->cookie,
|
||||
&p2p->listen_chan,
|
||||
GFP_KERNEL);
|
||||
wil->radio_wdev = wil->wdev;
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
}
|
||||
if (!started)
|
||||
return;
|
||||
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
cfg80211_remain_on_channel_expired(vif_to_radio_wdev(wil, vif),
|
||||
p2p->cookie,
|
||||
&p2p->listen_chan,
|
||||
GFP_KERNEL);
|
||||
if (vif->mid == 0)
|
||||
wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
}
|
||||
|
||||
void wil_p2p_search_expired(struct work_struct *work)
|
||||
{
|
||||
struct wil_p2p_info *p2p = container_of(work,
|
||||
struct wil_p2p_info, discovery_expired_work);
|
||||
struct wil6210_priv *wil = container_of(p2p,
|
||||
struct wil6210_priv, p2p);
|
||||
struct wil6210_vif *vif = container_of(p2p,
|
||||
struct wil6210_vif, p2p);
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
u8 started;
|
||||
|
||||
wil_dbg_misc(wil, "p2p_search_expired\n");
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
started = wil_p2p_stop_discovery(wil);
|
||||
started = wil_p2p_stop_discovery(vif);
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
||||
if (started) {
|
||||
|
@ -286,13 +287,15 @@ void wil_p2p_search_expired(struct work_struct *work)
|
|||
.aborted = false,
|
||||
};
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
if (wil->scan_request) {
|
||||
cfg80211_scan_done(wil->scan_request, &info);
|
||||
wil->scan_request = NULL;
|
||||
wil->radio_wdev = wil->wdev;
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
if (vif->scan_request) {
|
||||
cfg80211_scan_done(vif->scan_request, &info);
|
||||
vif->scan_request = NULL;
|
||||
if (vif->mid == 0)
|
||||
wil->radio_wdev =
|
||||
wil->main_ndev->ieee80211_ptr;
|
||||
}
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -300,8 +303,9 @@ void wil_p2p_delayed_listen_work(struct work_struct *work)
|
|||
{
|
||||
struct wil_p2p_info *p2p = container_of(work,
|
||||
struct wil_p2p_info, delayed_listen_work);
|
||||
struct wil6210_priv *wil = container_of(p2p,
|
||||
struct wil6210_priv, p2p);
|
||||
struct wil6210_vif *vif = container_of(p2p,
|
||||
struct wil6210_vif, p2p);
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int rc;
|
||||
|
||||
mutex_lock(&wil->mutex);
|
||||
|
@ -310,31 +314,33 @@ void wil_p2p_delayed_listen_work(struct work_struct *work)
|
|||
if (!p2p->discovery_started || !p2p->pending_listen_wdev)
|
||||
goto out;
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
if (wil->scan_request) {
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
if (vif->scan_request) {
|
||||
/* another scan started, wait again... */
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
goto out;
|
||||
}
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
|
||||
rc = wil_p2p_start_listen(wil);
|
||||
rc = wil_p2p_start_listen(vif);
|
||||
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
if (rc) {
|
||||
cfg80211_remain_on_channel_expired(p2p->pending_listen_wdev,
|
||||
p2p->cookie,
|
||||
&p2p->listen_chan,
|
||||
GFP_KERNEL);
|
||||
wil->radio_wdev = wil->wdev;
|
||||
if (vif->mid == 0)
|
||||
wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
|
||||
} else {
|
||||
cfg80211_ready_on_channel(p2p->pending_listen_wdev, p2p->cookie,
|
||||
&p2p->listen_chan,
|
||||
p2p->listen_duration, GFP_KERNEL);
|
||||
wil->radio_wdev = p2p->pending_listen_wdev;
|
||||
if (vif->mid == 0)
|
||||
wil->radio_wdev = p2p->pending_listen_wdev;
|
||||
}
|
||||
p2p->pending_listen_wdev = NULL;
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
|
||||
out:
|
||||
mutex_unlock(&wil->mutex);
|
||||
|
@ -342,34 +348,35 @@ out:
|
|||
|
||||
void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wil_p2p_info *p2p = &wil->p2p;
|
||||
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
|
||||
struct wil_p2p_info *p2p = &vif->p2p;
|
||||
struct cfg80211_scan_info info = {
|
||||
.aborted = true,
|
||||
};
|
||||
|
||||
lockdep_assert_held(&wil->mutex);
|
||||
lockdep_assert_held(&wil->p2p_wdev_mutex);
|
||||
lockdep_assert_held(&wil->vif_mutex);
|
||||
|
||||
if (wil->radio_wdev != wil->p2p_wdev)
|
||||
goto out;
|
||||
|
||||
if (!p2p->discovery_started) {
|
||||
/* Regular scan on the p2p device */
|
||||
if (wil->scan_request &&
|
||||
wil->scan_request->wdev == wil->p2p_wdev)
|
||||
wil_abort_scan(wil, true);
|
||||
if (vif->scan_request &&
|
||||
vif->scan_request->wdev == wil->p2p_wdev)
|
||||
wil_abort_scan(vif, true);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Search or listen on p2p device */
|
||||
mutex_unlock(&wil->p2p_wdev_mutex);
|
||||
wil_p2p_stop_discovery(wil);
|
||||
mutex_lock(&wil->p2p_wdev_mutex);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
wil_p2p_stop_discovery(vif);
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
|
||||
if (wil->scan_request) {
|
||||
if (vif->scan_request) {
|
||||
/* search */
|
||||
cfg80211_scan_done(wil->scan_request, &info);
|
||||
wil->scan_request = NULL;
|
||||
cfg80211_scan_done(vif->scan_request, &info);
|
||||
vif->scan_request = NULL;
|
||||
} else {
|
||||
/* listen */
|
||||
cfg80211_remain_on_channel_expired(wil->radio_wdev,
|
||||
|
@ -379,5 +386,5 @@ void wil_p2p_stop_radio_operations(struct wil6210_priv *wil)
|
|||
}
|
||||
|
||||
out:
|
||||
wil->radio_wdev = wil->wdev;
|
||||
wil->radio_wdev = wil->main_ndev->ieee80211_ptr;
|
||||
}
|
||||
|
|
|
@ -137,6 +137,20 @@ void wil_enable_irq(struct wil6210_priv *wil)
|
|||
enable_irq(wil->pdev->irq);
|
||||
}
|
||||
|
||||
static void wil_remove_all_additional_vifs(struct wil6210_priv *wil)
|
||||
{
|
||||
struct wil6210_vif *vif;
|
||||
int i;
|
||||
|
||||
for (i = 1; i < wil->max_vifs; i++) {
|
||||
vif = wil->vifs[i];
|
||||
if (vif) {
|
||||
wil_vif_prepare_stop(vif);
|
||||
wil_vif_remove(wil, vif->mid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Bus ops */
|
||||
static int wil_if_pcie_enable(struct wil6210_priv *wil)
|
||||
{
|
||||
|
@ -148,10 +162,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
|
|||
*/
|
||||
int msi_only = pdev->msi_enabled;
|
||||
bool _use_msi = use_msi;
|
||||
bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
|
||||
wil->fw_capabilities);
|
||||
|
||||
wil_dbg_misc(wil, "if_pcie_enable, wmi_only %d\n", wmi_only);
|
||||
wil_dbg_misc(wil, "if_pcie_enable\n");
|
||||
|
||||
pci_set_master(pdev);
|
||||
|
||||
|
@ -172,11 +184,9 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
|
|||
if (rc)
|
||||
goto stop_master;
|
||||
|
||||
/* need reset here to obtain MAC or in case of WMI-only FW, full reset
|
||||
* and fw loading takes place
|
||||
*/
|
||||
/* need reset here to obtain MAC */
|
||||
mutex_lock(&wil->mutex);
|
||||
rc = wil_reset(wil, wmi_only);
|
||||
rc = wil_reset(wil, false);
|
||||
mutex_unlock(&wil->mutex);
|
||||
if (rc)
|
||||
goto release_irq;
|
||||
|
@ -356,6 +366,18 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
goto bus_disable;
|
||||
}
|
||||
|
||||
/* in case of WMI-only FW, perform full reset and FW loading */
|
||||
if (test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) {
|
||||
wil_dbg_misc(wil, "Loading WMI only FW\n");
|
||||
mutex_lock(&wil->mutex);
|
||||
rc = wil_reset(wil, true);
|
||||
mutex_unlock(&wil->mutex);
|
||||
if (rc) {
|
||||
wil_err(wil, "failed to load WMI only FW\n");
|
||||
goto if_remove;
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_PM))
|
||||
wil->pm_notify.notifier_call = wil6210_pm_notify;
|
||||
|
||||
|
@ -372,6 +394,8 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
|
||||
return 0;
|
||||
|
||||
if_remove:
|
||||
wil_if_remove(wil);
|
||||
bus_disable:
|
||||
wil_if_pcie_disable(wil);
|
||||
err_iounmap:
|
||||
|
@ -402,6 +426,7 @@ static void wil_pcie_remove(struct pci_dev *pdev)
|
|||
wil6210_debugfs_remove(wil);
|
||||
rtnl_lock();
|
||||
wil_p2p_wdev_free(wil);
|
||||
wil_remove_all_additional_vifs(wil);
|
||||
rtnl_unlock();
|
||||
wil_if_remove(wil);
|
||||
wil_if_pcie_disable(wil);
|
||||
|
@ -425,12 +450,15 @@ static int wil6210_suspend(struct device *dev, bool is_runtime)
|
|||
int rc = 0;
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct wil6210_priv *wil = pci_get_drvdata(pdev);
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
bool keep_radio_on = ndev->flags & IFF_UP &&
|
||||
wil->keep_radio_on_during_sleep;
|
||||
bool keep_radio_on, active_ifaces;
|
||||
|
||||
wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
|
||||
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
active_ifaces = wil_has_active_ifaces(wil, true, false);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep;
|
||||
|
||||
rc = wil_can_suspend(wil, is_runtime);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
@ -457,12 +485,15 @@ static int wil6210_resume(struct device *dev, bool is_runtime)
|
|||
int rc = 0;
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
struct wil6210_priv *wil = pci_get_drvdata(pdev);
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
bool keep_radio_on = ndev->flags & IFF_UP &&
|
||||
wil->keep_radio_on_during_sleep;
|
||||
bool keep_radio_on, active_ifaces;
|
||||
|
||||
wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
|
||||
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
active_ifaces = wil_has_active_ifaces(wil, true, false);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep;
|
||||
|
||||
/* In case radio stays on, platform device will control
|
||||
* PCIe master
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -20,13 +21,72 @@
|
|||
|
||||
#define WIL6210_AUTOSUSPEND_DELAY_MS (1000)
|
||||
|
||||
static void wil_pm_wake_connected_net_queues(struct wil6210_priv *wil)
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
for (i = 0; i < wil->max_vifs; i++) {
|
||||
struct wil6210_vif *vif = wil->vifs[i];
|
||||
|
||||
if (vif && test_bit(wil_vif_fwconnected, vif->status))
|
||||
wil_update_net_queues_bh(wil, vif, NULL, false);
|
||||
}
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
}
|
||||
|
||||
static void wil_pm_stop_all_net_queues(struct wil6210_priv *wil)
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
for (i = 0; i < wil->max_vifs; i++) {
|
||||
struct wil6210_vif *vif = wil->vifs[i];
|
||||
|
||||
if (vif)
|
||||
wil_update_net_queues_bh(wil, vif, NULL, true);
|
||||
}
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
}
|
||||
|
||||
static bool
|
||||
wil_can_suspend_vif(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
||||
bool is_runtime)
|
||||
{
|
||||
struct wireless_dev *wdev = vif_to_wdev(vif);
|
||||
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
wil_dbg_pm(wil, "Sniffer\n");
|
||||
return false;
|
||||
|
||||
/* for STA-like interface, don't runtime suspend */
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
if (test_bit(wil_vif_fwconnecting, vif->status)) {
|
||||
wil_dbg_pm(wil, "Delay suspend when connecting\n");
|
||||
return false;
|
||||
}
|
||||
if (is_runtime) {
|
||||
wil_dbg_pm(wil, "STA-like interface\n");
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
/* AP-like interface - can't suspend */
|
||||
default:
|
||||
wil_dbg_pm(wil, "AP-like interface\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
|
||||
{
|
||||
int rc = 0;
|
||||
struct wireless_dev *wdev = wil->wdev;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
int rc = 0, i;
|
||||
bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
|
||||
wil->fw_capabilities);
|
||||
bool active_ifaces;
|
||||
|
||||
wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system");
|
||||
|
||||
|
@ -40,7 +100,12 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
|
|||
rc = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
if (!(ndev->flags & IFF_UP)) {
|
||||
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
active_ifaces = wil_has_active_ifaces(wil, true, false);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
|
||||
if (!active_ifaces) {
|
||||
/* can always sleep when down */
|
||||
wil_dbg_pm(wil, "Interface is down\n");
|
||||
goto out;
|
||||
|
@ -57,32 +122,19 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
|
|||
}
|
||||
|
||||
/* interface is running */
|
||||
switch (wdev->iftype) {
|
||||
case NL80211_IFTYPE_MONITOR:
|
||||
wil_dbg_pm(wil, "Sniffer\n");
|
||||
rc = -EBUSY;
|
||||
goto out;
|
||||
/* for STA-like interface, don't runtime suspend */
|
||||
case NL80211_IFTYPE_STATION:
|
||||
case NL80211_IFTYPE_P2P_CLIENT:
|
||||
if (test_bit(wil_status_fwconnecting, wil->status)) {
|
||||
wil_dbg_pm(wil, "Delay suspend when connecting\n");
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
for (i = 0; i < wil->max_vifs; i++) {
|
||||
struct wil6210_vif *vif = wil->vifs[i];
|
||||
|
||||
if (!vif)
|
||||
continue;
|
||||
if (!wil_can_suspend_vif(wil, vif, is_runtime)) {
|
||||
rc = -EBUSY;
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
goto out;
|
||||
}
|
||||
/* 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:
|
||||
wil_dbg_pm(wil, "can_suspend: %s => %s (%d)\n",
|
||||
|
@ -127,8 +179,7 @@ static int wil_resume_keep_radio_on(struct wil6210_priv *wil)
|
|||
}
|
||||
|
||||
/* Wake all queues */
|
||||
if (test_bit(wil_status_fwconnected, wil->status))
|
||||
wil_update_net_queues_bh(wil, NULL, false);
|
||||
wil_pm_wake_connected_net_queues(wil);
|
||||
|
||||
out:
|
||||
if (rc)
|
||||
|
@ -152,7 +203,7 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
|
|||
wil->suspend_stats.rejected_by_host++;
|
||||
return -EBUSY;
|
||||
}
|
||||
wil_update_net_queues_bh(wil, NULL, true);
|
||||
wil_pm_stop_all_net_queues(wil);
|
||||
|
||||
if (!wil_is_tx_idle(wil)) {
|
||||
wil_dbg_pm(wil, "Pending TX data, reject suspend\n");
|
||||
|
@ -243,22 +294,20 @@ resume_after_fail:
|
|||
/* if resume succeeded, reject the suspend */
|
||||
if (!rc) {
|
||||
rc = -EBUSY;
|
||||
if (test_bit(wil_status_fwconnected, wil->status))
|
||||
wil_update_net_queues_bh(wil, NULL, false);
|
||||
wil_pm_wake_connected_net_queues(wil);
|
||||
}
|
||||
return rc;
|
||||
|
||||
reject_suspend:
|
||||
clear_bit(wil_status_suspending, wil->status);
|
||||
if (test_bit(wil_status_fwconnected, wil->status))
|
||||
wil_update_net_queues_bh(wil, NULL, false);
|
||||
wil_pm_wake_connected_net_queues(wil);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int wil_suspend_radio_off(struct wil6210_priv *wil)
|
||||
{
|
||||
int rc = 0;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
bool active_ifaces;
|
||||
|
||||
wil_dbg_pm(wil, "suspend radio off\n");
|
||||
|
||||
|
@ -272,7 +321,11 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)
|
|||
}
|
||||
|
||||
/* if netif up, hardware is alive, shut it down */
|
||||
if (ndev->flags & IFF_UP) {
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
active_ifaces = wil_has_active_ifaces(wil, true, false);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
|
||||
if (active_ifaces) {
|
||||
rc = wil_down(wil);
|
||||
if (rc) {
|
||||
wil_err(wil, "wil_down : %d\n", rc);
|
||||
|
@ -306,16 +359,19 @@ out:
|
|||
static int wil_resume_radio_off(struct wil6210_priv *wil)
|
||||
{
|
||||
int rc = 0;
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
bool active_ifaces;
|
||||
|
||||
wil_dbg_pm(wil, "Enabling PCIe IRQ\n");
|
||||
wil_enable_irq(wil);
|
||||
/* if netif up, bring hardware up
|
||||
/* if any netif up, bring hardware up
|
||||
* During open(), IFF_UP set after actual device method
|
||||
* invocation. This prevent recursive call to wil_up()
|
||||
* wil_status_suspended will be cleared in wil_reset
|
||||
*/
|
||||
if (ndev->flags & IFF_UP)
|
||||
mutex_lock(&wil->vif_mutex);
|
||||
active_ifaces = wil_has_active_ifaces(wil, true, false);
|
||||
mutex_unlock(&wil->vif_mutex);
|
||||
if (active_ifaces)
|
||||
rc = wil_up(wil);
|
||||
else
|
||||
clear_bit(wil_status_suspended, wil->status);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2015,2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -53,6 +54,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil,
|
|||
u32 i;
|
||||
struct pmc_ctx *pmc = &wil->pmc;
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
|
||||
struct wmi_pmc_cmd pmc_cmd = {0};
|
||||
int last_cmd_err = -ENOMEM;
|
||||
|
||||
|
@ -186,6 +188,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil,
|
|||
wil_dbg_misc(wil, "pmc_alloc: send WMI_PMC_CMD with ALLOCATE op\n");
|
||||
pmc->last_cmd_status = wmi_send(wil,
|
||||
WMI_PMC_CMDID,
|
||||
vif->mid,
|
||||
&pmc_cmd,
|
||||
sizeof(pmc_cmd));
|
||||
if (pmc->last_cmd_status) {
|
||||
|
@ -236,6 +239,7 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd)
|
|||
{
|
||||
struct pmc_ctx *pmc = &wil->pmc;
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
|
||||
struct wmi_pmc_cmd pmc_cmd = {0};
|
||||
|
||||
mutex_lock(&pmc->lock);
|
||||
|
@ -254,8 +258,8 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd)
|
|||
wil_dbg_misc(wil, "send WMI_PMC_CMD with RELEASE op\n");
|
||||
pmc_cmd.op = WMI_PMC_RELEASE;
|
||||
pmc->last_cmd_status =
|
||||
wmi_send(wil, WMI_PMC_CMDID, &pmc_cmd,
|
||||
sizeof(pmc_cmd));
|
||||
wmi_send(wil, WMI_PMC_CMDID, vif->mid,
|
||||
&pmc_cmd, sizeof(pmc_cmd));
|
||||
if (pmc->last_cmd_status) {
|
||||
wil_err(wil,
|
||||
"WMI_PMC_CMD with RELEASE op failed, status %d",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -40,11 +41,10 @@ static inline int reorder_index(struct wil_tid_ampdu_rx *r, u16 seq)
|
|||
return seq_sub(seq, r->ssn) % r->buf_size;
|
||||
}
|
||||
|
||||
static void wil_release_reorder_frame(struct wil6210_priv *wil,
|
||||
static void wil_release_reorder_frame(struct net_device *ndev,
|
||||
struct wil_tid_ampdu_rx *r,
|
||||
int index)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct sk_buff *skb = r->reorder_buf[index];
|
||||
|
||||
if (!skb)
|
||||
|
@ -59,7 +59,7 @@ no_frame:
|
|||
r->head_seq_num = seq_inc(r->head_seq_num);
|
||||
}
|
||||
|
||||
static void wil_release_reorder_frames(struct wil6210_priv *wil,
|
||||
static void wil_release_reorder_frames(struct net_device *ndev,
|
||||
struct wil_tid_ampdu_rx *r,
|
||||
u16 hseq)
|
||||
{
|
||||
|
@ -73,18 +73,18 @@ static void wil_release_reorder_frames(struct wil6210_priv *wil,
|
|||
*/
|
||||
while (seq_less(r->head_seq_num, hseq) && r->stored_mpdu_num) {
|
||||
index = reorder_index(r, r->head_seq_num);
|
||||
wil_release_reorder_frame(wil, r, index);
|
||||
wil_release_reorder_frame(ndev, r, index);
|
||||
}
|
||||
r->head_seq_num = hseq;
|
||||
}
|
||||
|
||||
static void wil_reorder_release(struct wil6210_priv *wil,
|
||||
static void wil_reorder_release(struct net_device *ndev,
|
||||
struct wil_tid_ampdu_rx *r)
|
||||
{
|
||||
int index = reorder_index(r, r->head_seq_num);
|
||||
|
||||
while (r->reorder_buf[index]) {
|
||||
wil_release_reorder_frame(wil, r, index);
|
||||
wil_release_reorder_frame(ndev, r, index);
|
||||
index = reorder_index(r, r->head_seq_num);
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,8 @@ static void wil_reorder_release(struct wil6210_priv *wil,
|
|||
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
|
||||
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wil6210_vif *vif;
|
||||
struct net_device *ndev;
|
||||
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
|
||||
int tid = wil_rxdesc_tid(d);
|
||||
int cid = wil_rxdesc_cid(d);
|
||||
|
@ -108,6 +109,14 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
|||
wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n",
|
||||
mid, cid, tid, seq, mcast);
|
||||
|
||||
vif = wil->vifs[mid];
|
||||
if (unlikely(!vif)) {
|
||||
wil_dbg_txrx(wil, "invalid VIF, mid %d\n", mid);
|
||||
dev_kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
ndev = vif_to_ndev(vif);
|
||||
|
||||
if (unlikely(mcast)) {
|
||||
wil_netif_rx_any(skb, ndev);
|
||||
return;
|
||||
|
@ -168,7 +177,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
|||
if (!seq_less(seq, r->head_seq_num + r->buf_size)) {
|
||||
hseq = seq_inc(seq_sub(seq, r->buf_size));
|
||||
/* release stored frames up to new head to stack */
|
||||
wil_release_reorder_frames(wil, r, hseq);
|
||||
wil_release_reorder_frames(ndev, r, hseq);
|
||||
}
|
||||
|
||||
/* Now the new frame is always in the range of the reordering buffer */
|
||||
|
@ -199,16 +208,18 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
|||
r->reorder_buf[index] = skb;
|
||||
r->reorder_time[index] = jiffies;
|
||||
r->stored_mpdu_num++;
|
||||
wil_reorder_release(wil, r);
|
||||
wil_reorder_release(ndev, r);
|
||||
|
||||
out:
|
||||
spin_unlock(&sta->tid_rx_lock);
|
||||
}
|
||||
|
||||
/* process BAR frame, called in NAPI context */
|
||||
void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq)
|
||||
void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
||||
u8 cid, u8 tid, u16 seq)
|
||||
{
|
||||
struct wil_sta_info *sta = &wil->sta[cid];
|
||||
struct net_device *ndev = vif_to_ndev(vif);
|
||||
struct wil_tid_ampdu_rx *r;
|
||||
|
||||
spin_lock(&sta->tid_rx_lock);
|
||||
|
@ -223,9 +234,9 @@ void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq)
|
|||
seq, r->head_seq_num);
|
||||
goto out;
|
||||
}
|
||||
wil_dbg_txrx(wil, "BAR: CID %d TID %d Seq 0x%03x head 0x%03x\n",
|
||||
cid, tid, seq, r->head_seq_num);
|
||||
wil_release_reorder_frames(wil, r, seq);
|
||||
wil_dbg_txrx(wil, "BAR: CID %d MID %d TID %d Seq 0x%03x head 0x%03x\n",
|
||||
cid, vif->mid, tid, seq, r->head_seq_num);
|
||||
wil_release_reorder_frames(ndev, r, seq);
|
||||
|
||||
out:
|
||||
spin_unlock(&sta->tid_rx_lock);
|
||||
|
@ -292,8 +303,8 @@ static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize)
|
|||
}
|
||||
|
||||
/* Block Ack - Rx side (recipient) */
|
||||
int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
|
||||
u8 dialog_token, __le16 ba_param_set,
|
||||
int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid,
|
||||
u8 cidxtid, u8 dialog_token, __le16 ba_param_set,
|
||||
__le16 ba_timeout, __le16 ba_seq_ctrl)
|
||||
__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||
{
|
||||
|
@ -354,7 +365,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
|||
}
|
||||
}
|
||||
|
||||
rc = wmi_addba_rx_resp(wil, cid, tid, dialog_token, status,
|
||||
rc = wmi_addba_rx_resp(wil, mid, cid, tid, dialog_token, status,
|
||||
agg_amsdu, agg_wsize, agg_timeout);
|
||||
if (rc || (status != WLAN_STATUS_SUCCESS)) {
|
||||
wil_err(wil, "do not apply ba, rc(%d), status(%d)\n", rc,
|
||||
|
@ -393,7 +404,7 @@ int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize)
|
|||
goto out;
|
||||
}
|
||||
txdata->addba_in_progress = true;
|
||||
rc = wmi_addba(wil, ringid, agg_wsize, agg_timeout);
|
||||
rc = wmi_addba(wil, txdata->mid, ringid, agg_wsize, agg_timeout);
|
||||
if (rc) {
|
||||
wil_err(wil, "wmi_addba failed, rc (%d)", rc);
|
||||
txdata->addba_in_progress = false;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -474,7 +475,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
|
|||
struct vring *vring)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wil6210_vif *vif;
|
||||
struct net_device *ndev;
|
||||
volatile struct vring_rx_desc *_d;
|
||||
struct vring_rx_desc *d;
|
||||
struct sk_buff *skb;
|
||||
|
@ -483,7 +485,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
|
|||
unsigned int sz = wil->rx_buf_len + ETH_HLEN + snaplen;
|
||||
u16 dmalen;
|
||||
u8 ftype;
|
||||
int cid;
|
||||
int cid, mid;
|
||||
int i;
|
||||
struct wil_net_stats *stats;
|
||||
|
||||
|
@ -520,6 +522,16 @@ again:
|
|||
(const void *)d, sizeof(*d), false);
|
||||
|
||||
cid = wil_rxdesc_cid(d);
|
||||
mid = wil_rxdesc_mid(d);
|
||||
vif = wil->vifs[mid];
|
||||
|
||||
if (unlikely(!vif)) {
|
||||
wil_dbg_txrx(wil, "skipped RX descriptor with invalid mid %d",
|
||||
mid);
|
||||
kfree_skb(skb);
|
||||
goto again;
|
||||
}
|
||||
ndev = vif_to_ndev(vif);
|
||||
stats = &wil->sta[cid].stats;
|
||||
|
||||
if (unlikely(dmalen > sz)) {
|
||||
|
@ -553,7 +565,6 @@ again:
|
|||
ftype = wil_rxdesc_ftype(d) << 2;
|
||||
if (unlikely(ftype != IEEE80211_FTYPE_DATA)) {
|
||||
u8 fc1 = wil_rxdesc_fc1(d);
|
||||
int mid = wil_rxdesc_mid(d);
|
||||
int tid = wil_rxdesc_tid(d);
|
||||
u16 seq = wil_rxdesc_seq(d);
|
||||
|
||||
|
@ -565,7 +576,7 @@ again:
|
|||
wil_dbg_txrx(wil,
|
||||
"BAR: MID %d CID %d TID %d Seq 0x%03x\n",
|
||||
mid, cid, tid, seq);
|
||||
wil_rx_bar(wil, cid, tid, seq);
|
||||
wil_rx_bar(wil, vif, cid, tid, seq);
|
||||
} else {
|
||||
/* print again all info. One can enable only this
|
||||
* without overhead for printing every Rx frame
|
||||
|
@ -621,10 +632,15 @@ again:
|
|||
/**
|
||||
* allocate and fill up to @count buffers in rx ring
|
||||
* buffers posted at @swtail
|
||||
* Note: we have a single RX queue for servicing all VIFs, but we
|
||||
* allocate skbs with headroom according to main interface only. This
|
||||
* means it will not work with monitor interface together with other VIFs.
|
||||
* Currently we only support monitor interface on its own without other VIFs,
|
||||
* and we will need to fix this code once we add support.
|
||||
*/
|
||||
static int wil_rx_refill(struct wil6210_priv *wil, int count)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct vring *v = &wil->vring_rx;
|
||||
u32 next_tail;
|
||||
int rc = 0;
|
||||
|
@ -713,8 +729,9 @@ static int wil_rx_crypto_check(struct wil6210_priv *wil, struct sk_buff *skb)
|
|||
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
||||
{
|
||||
gro_result_t rc = GRO_NORMAL;
|
||||
struct wil6210_vif *vif = ndev_to_vif(ndev);
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
struct wireless_dev *wdev = wil_to_wdev(wil);
|
||||
struct wireless_dev *wdev = vif_to_wdev(vif);
|
||||
unsigned int len = skb->len;
|
||||
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
|
||||
int cid = wil_rxdesc_cid(d); /* always 0..7, no need to check */
|
||||
|
@ -751,14 +768,15 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
|||
goto stats;
|
||||
}
|
||||
|
||||
if (wdev->iftype == NL80211_IFTYPE_AP && !wil->ap_isolate) {
|
||||
if (wdev->iftype == NL80211_IFTYPE_AP && !vif->ap_isolate) {
|
||||
if (mcast) {
|
||||
/* send multicast frames both to higher layers in
|
||||
* local net stack and back to the wireless medium
|
||||
*/
|
||||
xmit_skb = skb_copy(skb, GFP_ATOMIC);
|
||||
} else {
|
||||
int xmit_cid = wil_find_cid(wil, eth->h_dest);
|
||||
int xmit_cid = wil_find_cid(wil, vif->mid,
|
||||
eth->h_dest);
|
||||
|
||||
if (xmit_cid >= 0) {
|
||||
/* The destination station is associated to
|
||||
|
@ -786,8 +804,8 @@ void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev)
|
|||
}
|
||||
|
||||
if (skb) { /* deliver to local stack */
|
||||
|
||||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
skb->dev = ndev;
|
||||
rc = napi_gro_receive(&wil->napi_rx, skb);
|
||||
wil_dbg_txrx(wil, "Rx complete %d bytes => %s\n",
|
||||
len, gro_res_str[rc]);
|
||||
|
@ -815,7 +833,8 @@ stats:
|
|||
*/
|
||||
void wil_rx_handle(struct wil6210_priv *wil, int *quota)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct net_device *ndev = wil->main_ndev;
|
||||
struct wireless_dev *wdev = ndev->ieee80211_ptr;
|
||||
struct vring *v = &wil->vring_rx;
|
||||
struct sk_buff *skb;
|
||||
|
||||
|
@ -827,7 +846,8 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
|
|||
while ((*quota > 0) && (NULL != (skb = wil_vring_reap_rx(wil, v)))) {
|
||||
(*quota)--;
|
||||
|
||||
if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
|
||||
/* monitor is currently supported on main interface only */
|
||||
if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
|
||||
skb->dev = ndev;
|
||||
skb_reset_mac_header(skb);
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
|
@ -911,12 +931,14 @@ static inline void wil_tx_data_init(struct vring_tx_data *txdata)
|
|||
txdata->agg_timeout = 0;
|
||||
txdata->agg_amsdu = 0;
|
||||
txdata->addba_in_progress = false;
|
||||
txdata->mid = U8_MAX;
|
||||
spin_unlock_bh(&txdata->lock);
|
||||
}
|
||||
|
||||
int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
||||
int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
|
||||
int cid, int tid)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int rc;
|
||||
struct wmi_vring_cfg_cmd cmd = {
|
||||
.action = cpu_to_le32(WMI_VRING_CMD_ADD),
|
||||
|
@ -966,9 +988,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
|||
|
||||
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
|
||||
|
||||
if (!wil->privacy)
|
||||
if (!vif->privacy)
|
||||
txdata->dot1x_open = true;
|
||||
rc = wmi_call(wil, WMI_VRING_CFG_CMDID, &cmd, sizeof(cmd),
|
||||
rc = wmi_call(wil, WMI_VRING_CFG_CMDID, vif->mid, &cmd, sizeof(cmd),
|
||||
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
|
@ -982,6 +1004,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
|||
|
||||
spin_lock_bh(&txdata->lock);
|
||||
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
|
||||
txdata->mid = vif->mid;
|
||||
txdata->enabled = 1;
|
||||
spin_unlock_bh(&txdata->lock);
|
||||
|
||||
|
@ -1003,8 +1026,9 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
|||
return rc;
|
||||
}
|
||||
|
||||
int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
|
||||
int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size)
|
||||
{
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
int rc;
|
||||
struct wmi_bcast_vring_cfg_cmd cmd = {
|
||||
.action = cpu_to_le32(WMI_VRING_CMD_ADD),
|
||||
|
@ -1046,9 +1070,10 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
|
|||
|
||||
cmd.vring_cfg.tx_sw_ring.ring_mem_base = cpu_to_le64(vring->pa);
|
||||
|
||||
if (!wil->privacy)
|
||||
if (!vif->privacy)
|
||||
txdata->dot1x_open = true;
|
||||
rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, &cmd, sizeof(cmd),
|
||||
rc = wmi_call(wil, WMI_BCAST_VRING_CFG_CMDID, vif->mid,
|
||||
&cmd, sizeof(cmd),
|
||||
WMI_VRING_CFG_DONE_EVENTID, &reply, sizeof(reply), 100);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
|
@ -1062,6 +1087,7 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
|
|||
|
||||
spin_lock_bh(&txdata->lock);
|
||||
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
|
||||
txdata->mid = vif->mid;
|
||||
txdata->enabled = 1;
|
||||
spin_unlock_bh(&txdata->lock);
|
||||
|
||||
|
@ -1091,6 +1117,7 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
|
|||
|
||||
spin_lock_bh(&txdata->lock);
|
||||
txdata->dot1x_open = false;
|
||||
txdata->mid = U8_MAX;
|
||||
txdata->enabled = 0; /* no Tx can be in progress or start anew */
|
||||
spin_unlock_bh(&txdata->lock);
|
||||
/* napi_synchronize waits for completion of the current NAPI but will
|
||||
|
@ -1108,11 +1135,12 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
|
|||
}
|
||||
|
||||
static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
|
||||
struct wil6210_vif *vif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
int i;
|
||||
struct ethhdr *eth = (void *)skb->data;
|
||||
int cid = wil_find_cid(wil, eth->h_dest);
|
||||
int cid = wil_find_cid(wil, vif->mid, eth->h_dest);
|
||||
|
||||
if (cid < 0)
|
||||
return NULL;
|
||||
|
@ -1142,10 +1170,11 @@ static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
||||
struct sk_buff *skb);
|
||||
static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
||||
struct vring *vring, struct sk_buff *skb);
|
||||
|
||||
static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
|
||||
struct wil6210_vif *vif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct vring *v;
|
||||
|
@ -1160,7 +1189,7 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
|
|||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
v = &wil->vring_tx[i];
|
||||
txdata = &wil->vring_tx_data[i];
|
||||
if (!v->va || !txdata->enabled)
|
||||
if (!v->va || !txdata->enabled || txdata->mid != vif->mid)
|
||||
continue;
|
||||
|
||||
cid = wil->vring2cid_tid[i][0];
|
||||
|
@ -1193,11 +1222,12 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
|
|||
* - for PBSS
|
||||
*/
|
||||
static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
|
||||
struct wil6210_vif *vif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct vring *v;
|
||||
struct vring_tx_data *txdata;
|
||||
int i = wil->bcast_vring;
|
||||
int i = vif->bcast_vring;
|
||||
|
||||
if (i < 0)
|
||||
return NULL;
|
||||
|
@ -1222,6 +1252,7 @@ static void wil_set_da_for_vring(struct wil6210_priv *wil,
|
|||
}
|
||||
|
||||
static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
|
||||
struct wil6210_vif *vif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct vring *v, *v2;
|
||||
|
@ -1230,13 +1261,13 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
|
|||
u8 cid;
|
||||
struct ethhdr *eth = (void *)skb->data;
|
||||
char *src = eth->h_source;
|
||||
struct vring_tx_data *txdata;
|
||||
struct vring_tx_data *txdata, *txdata2;
|
||||
|
||||
/* find 1-st vring eligible for data */
|
||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
v = &wil->vring_tx[i];
|
||||
txdata = &wil->vring_tx_data[i];
|
||||
if (!v->va || !txdata->enabled)
|
||||
if (!v->va || !txdata->enabled || txdata->mid != vif->mid)
|
||||
continue;
|
||||
|
||||
cid = wil->vring2cid_tid[i][0];
|
||||
|
@ -1264,7 +1295,8 @@ found:
|
|||
/* find other active vrings and duplicate skb for each */
|
||||
for (i++; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||
v2 = &wil->vring_tx[i];
|
||||
if (!v2->va)
|
||||
txdata2 = &wil->vring_tx_data[i];
|
||||
if (!v2->va || txdata2->mid != vif->mid)
|
||||
continue;
|
||||
cid = wil->vring2cid_tid[i][0];
|
||||
if (cid >= WIL6210_MAX_CID) /* skip BCAST */
|
||||
|
@ -1280,7 +1312,7 @@ found:
|
|||
if (skb2) {
|
||||
wil_dbg_txrx(wil, "BCAST DUP -> ring %d\n", i);
|
||||
wil_set_da_for_vring(wil, skb2, i);
|
||||
wil_tx_vring(wil, v2, skb2);
|
||||
wil_tx_vring(wil, vif, v2, skb2);
|
||||
} else {
|
||||
wil_err(wil, "skb_copy failed\n");
|
||||
}
|
||||
|
@ -1417,8 +1449,8 @@ static inline void wil_set_tx_desc_last_tso(volatile struct vring_tx_desc *d)
|
|||
DMA_CFG_DESC_TX_0_SEGMENT_BUF_DETAILS_POS;
|
||||
}
|
||||
|
||||
static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct vring *vring,
|
||||
struct sk_buff *skb)
|
||||
static int __wil_tx_vring_tso(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
||||
struct vring *vring, struct sk_buff *skb)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
|
||||
|
@ -1710,8 +1742,8 @@ err_exit:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
||||
struct sk_buff *skb)
|
||||
static int __wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
||||
struct vring *vring, struct sk_buff *skb)
|
||||
{
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct vring_tx_desc dd, *d = ⅆ
|
||||
|
@ -1725,7 +1757,7 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
|||
uint i = swhead;
|
||||
dma_addr_t pa;
|
||||
int used;
|
||||
bool mcast = (vring_index == wil->bcast_vring);
|
||||
bool mcast = (vring_index == vif->bcast_vring);
|
||||
uint len = skb_headlen(skb);
|
||||
|
||||
wil_dbg_txrx(wil, "tx_vring: %d bytes to vring %d\n", skb->len,
|
||||
|
@ -1860,8 +1892,8 @@ static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
||||
struct sk_buff *skb)
|
||||
static int wil_tx_vring(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
||||
struct vring *vring, struct sk_buff *skb)
|
||||
{
|
||||
int vring_index = vring - wil->vring_tx;
|
||||
struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index];
|
||||
|
@ -1879,7 +1911,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
|||
}
|
||||
|
||||
rc = (skb_is_gso(skb) ? __wil_tx_vring_tso : __wil_tx_vring)
|
||||
(wil, vring, skb);
|
||||
(wil, vif, vring, skb);
|
||||
|
||||
spin_unlock(&txdata->lock);
|
||||
|
||||
|
@ -1888,6 +1920,7 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
|||
|
||||
/**
|
||||
* Check status of tx vrings and stop/wake net queues if needed
|
||||
* It will start/stop net queues of a specific VIF net_device.
|
||||
*
|
||||
* This function does one of two checks:
|
||||
* In case check_stop is true, will check if net queues need to be stopped. If
|
||||
|
@ -1903,28 +1936,32 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
|
|||
* availability and modified vring has high descriptor availability.
|
||||
*/
|
||||
static inline void __wil_update_net_queues(struct wil6210_priv *wil,
|
||||
struct wil6210_vif *vif,
|
||||
struct vring *vring,
|
||||
bool check_stop)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (vring)
|
||||
wil_dbg_txrx(wil, "vring %d, check_stop=%d, stopped=%d",
|
||||
(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 (unlikely(!vif))
|
||||
return;
|
||||
|
||||
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 */
|
||||
return;
|
||||
|
||||
if (check_stop) {
|
||||
if (!vring || unlikely(wil_vring_avail_low(vring))) {
|
||||
/* not enough room in the vring */
|
||||
netif_tx_stop_all_queues(wil_to_ndev(wil));
|
||||
wil->net_queue_stopped = true;
|
||||
netif_tx_stop_all_queues(vif_to_ndev(vif));
|
||||
vif->net_queue_stopped = true;
|
||||
wil_dbg_txrx(wil, "netif_tx_stop called\n");
|
||||
}
|
||||
return;
|
||||
|
@ -1940,7 +1977,8 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
|
|||
struct vring *cur_vring = &wil->vring_tx[i];
|
||||
struct vring_tx_data *txdata = &wil->vring_tx_data[i];
|
||||
|
||||
if (!cur_vring->va || !txdata->enabled || cur_vring == vring)
|
||||
if (txdata->mid != vif->mid || !cur_vring->va ||
|
||||
!txdata->enabled || cur_vring == vring)
|
||||
continue;
|
||||
|
||||
if (wil_vring_avail_low(cur_vring)) {
|
||||
|
@ -1953,30 +1991,31 @@ static inline void __wil_update_net_queues(struct wil6210_priv *wil,
|
|||
if (!vring || wil_vring_avail_high(vring)) {
|
||||
/* enough room in the vring */
|
||||
wil_dbg_txrx(wil, "calling netif_tx_wake\n");
|
||||
netif_tx_wake_all_queues(wil_to_ndev(wil));
|
||||
wil->net_queue_stopped = false;
|
||||
netif_tx_wake_all_queues(vif_to_ndev(vif));
|
||||
vif->net_queue_stopped = false;
|
||||
}
|
||||
}
|
||||
|
||||
void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring,
|
||||
bool check_stop)
|
||||
void wil_update_net_queues(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
||||
struct vring *vring, bool check_stop)
|
||||
{
|
||||
spin_lock(&wil->net_queue_lock);
|
||||
__wil_update_net_queues(wil, vring, check_stop);
|
||||
__wil_update_net_queues(wil, vif, vring, check_stop);
|
||||
spin_unlock(&wil->net_queue_lock);
|
||||
}
|
||||
|
||||
void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring,
|
||||
bool check_stop)
|
||||
void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
||||
struct vring *vring, bool check_stop)
|
||||
{
|
||||
spin_lock_bh(&wil->net_queue_lock);
|
||||
__wil_update_net_queues(wil, vring, check_stop);
|
||||
__wil_update_net_queues(wil, vif, vring, check_stop);
|
||||
spin_unlock_bh(&wil->net_queue_lock);
|
||||
}
|
||||
|
||||
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||
{
|
||||
struct wil6210_priv *wil = ndev_to_wil(ndev);
|
||||
struct wil6210_vif *vif = ndev_to_vif(ndev);
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct ethhdr *eth = (void *)skb->data;
|
||||
bool bcast = is_multicast_ether_addr(eth->h_dest);
|
||||
struct vring *vring;
|
||||
|
@ -1991,49 +2030,50 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
|||
}
|
||||
goto drop;
|
||||
}
|
||||
if (unlikely(!test_bit(wil_status_fwconnected, wil->status))) {
|
||||
wil_dbg_ratelimited(wil, "FW not connected, packet dropped\n");
|
||||
if (unlikely(!test_bit(wil_vif_fwconnected, vif->status))) {
|
||||
wil_dbg_ratelimited(wil,
|
||||
"VIF not connected, packet dropped\n");
|
||||
goto drop;
|
||||
}
|
||||
if (unlikely(wil->wdev->iftype == NL80211_IFTYPE_MONITOR)) {
|
||||
if (unlikely(vif->wdev.iftype == NL80211_IFTYPE_MONITOR)) {
|
||||
wil_err(wil, "Xmit in monitor mode not supported\n");
|
||||
goto drop;
|
||||
}
|
||||
pr_once_fw = false;
|
||||
|
||||
/* find vring */
|
||||
if (wil->wdev->iftype == NL80211_IFTYPE_STATION && !wil->pbss) {
|
||||
if (vif->wdev.iftype == NL80211_IFTYPE_STATION && !vif->pbss) {
|
||||
/* in STA mode (ESS), all to same VRING (to AP) */
|
||||
vring = wil_find_tx_vring_sta(wil, skb);
|
||||
vring = wil_find_tx_vring_sta(wil, vif, skb);
|
||||
} else if (bcast) {
|
||||
if (wil->pbss)
|
||||
if (vif->pbss)
|
||||
/* in pbss, no bcast VRING - duplicate skb in
|
||||
* all stations VRINGs
|
||||
*/
|
||||
vring = wil_find_tx_bcast_2(wil, skb);
|
||||
else if (wil->wdev->iftype == NL80211_IFTYPE_AP)
|
||||
vring = wil_find_tx_bcast_2(wil, vif, skb);
|
||||
else if (vif->wdev.iftype == NL80211_IFTYPE_AP)
|
||||
/* AP has a dedicated bcast VRING */
|
||||
vring = wil_find_tx_bcast_1(wil, skb);
|
||||
vring = wil_find_tx_bcast_1(wil, vif, skb);
|
||||
else
|
||||
/* unexpected combination, fallback to duplicating
|
||||
* the skb in all stations VRINGs
|
||||
*/
|
||||
vring = wil_find_tx_bcast_2(wil, skb);
|
||||
vring = wil_find_tx_bcast_2(wil, vif, skb);
|
||||
} else {
|
||||
/* unicast, find specific VRING by dest. address */
|
||||
vring = wil_find_tx_ucast(wil, skb);
|
||||
vring = wil_find_tx_ucast(wil, vif, skb);
|
||||
}
|
||||
if (unlikely(!vring)) {
|
||||
wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest);
|
||||
goto drop;
|
||||
}
|
||||
/* set up vring entry */
|
||||
rc = wil_tx_vring(wil, vring, skb);
|
||||
rc = wil_tx_vring(wil, vif, vring, skb);
|
||||
|
||||
switch (rc) {
|
||||
case 0:
|
||||
/* shall we stop net queues? */
|
||||
wil_update_net_queues_bh(wil, vring, true);
|
||||
wil_update_net_queues_bh(wil, vif, vring, true);
|
||||
/* statistics will be updated on the tx_complete */
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
|
@ -2072,9 +2112,10 @@ static inline void wil_consume_skb(struct sk_buff *skb, bool acked)
|
|||
*
|
||||
* Safe to call from IRQ
|
||||
*/
|
||||
int wil_tx_complete(struct wil6210_priv *wil, int ringid)
|
||||
int wil_tx_complete(struct wil6210_vif *vif, int ringid)
|
||||
{
|
||||
struct net_device *ndev = wil_to_ndev(wil);
|
||||
struct wil6210_priv *wil = vif_to_wil(vif);
|
||||
struct net_device *ndev = vif_to_ndev(vif);
|
||||
struct device *dev = wil_to_dev(wil);
|
||||
struct vring *vring = &wil->vring_tx[ringid];
|
||||
struct vring_tx_data *txdata = &wil->vring_tx_data[ringid];
|
||||
|
@ -2184,7 +2225,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
|
|||
|
||||
/* shall we wake net queues? */
|
||||
if (done)
|
||||
wil_update_net_queues(wil, vring, false);
|
||||
wil_update_net_queues(wil, vif, vring, false);
|
||||
|
||||
return done;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -63,7 +64,9 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
|
|||
* [dword 1]
|
||||
* bit 0.. 3 : pkt_mode:4
|
||||
* bit 4 : pkt_mode_en:1
|
||||
* bit 5..14 : reserved0:10
|
||||
* bit 5 : mac_id_en:1
|
||||
* bit 6..7 : mac_id:2
|
||||
* bit 8..14 : reserved0:7
|
||||
* bit 15 : ack_policy_en:1
|
||||
* bit 16..19 : dst_index:4
|
||||
* bit 20 : dst_index_en:1
|
||||
|
@ -132,6 +135,14 @@ struct vring_tx_mac {
|
|||
#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_LEN 1
|
||||
#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10
|
||||
|
||||
#define MAC_CFG_DESC_TX_1_MAC_ID_EN_POS 5
|
||||
#define MAC_CFG_DESC_TX_1_MAC_ID_EN_LEN 1
|
||||
#define MAC_CFG_DESC_TX_1_MAC_ID_EN_MSK 0x20
|
||||
|
||||
#define MAC_CFG_DESC_TX_1_MAC_ID_POS 6
|
||||
#define MAC_CFG_DESC_TX_1_MAC_ID_LEN 2
|
||||
#define MAC_CFG_DESC_TX_1_MAC_ID_MSK 0xc0
|
||||
|
||||
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_POS 15
|
||||
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1
|
||||
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000
|
||||
|
@ -304,7 +315,7 @@ enum {
|
|||
* bit 0.. 3 : tid:4 The QoS (b3-0) TID Field
|
||||
* bit 4.. 6 : cid:3 The Source index that was found during parsing the TA.
|
||||
* This field is used to define the source of the packet
|
||||
* bit 7 : reserved:1
|
||||
* bit 7 : MAC_id_valid:1, 1 if MAC virtual number is valid.
|
||||
* bit 8.. 9 : mid:2 The MAC virtual number
|
||||
* bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type
|
||||
* (management, data, control and extension)
|
||||
|
@ -395,6 +406,7 @@ struct vring_rx_mac {
|
|||
#define RX_DMA_D0_CMD_DMA_EOP BIT(8)
|
||||
#define RX_DMA_D0_CMD_DMA_RT BIT(9) /* always 1 */
|
||||
#define RX_DMA_D0_CMD_DMA_IT BIT(10) /* interrupt */
|
||||
#define RX_MAC_D0_MAC_ID_VALID BIT(7)
|
||||
|
||||
/* Error field */
|
||||
#define RX_DMA_ERROR_FCS BIT(0)
|
||||
|
@ -451,7 +463,8 @@ static inline int wil_rxdesc_cid(struct vring_rx_desc *d)
|
|||
|
||||
static inline int wil_rxdesc_mid(struct vring_rx_desc *d)
|
||||
{
|
||||
return WIL_GET_BITS(d->mac.d0, 8, 9);
|
||||
return (d->mac.d0 & RX_MAC_D0_MAC_ID_VALID) ?
|
||||
WIL_GET_BITS(d->mac.d0, 8, 9) : 0;
|
||||
}
|
||||
|
||||
static inline int wil_rxdesc_ftype(struct vring_rx_desc *d)
|
||||
|
@ -517,7 +530,8 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)
|
|||
|
||||
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
|
||||
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb);
|
||||
void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq);
|
||||
void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
||||
u8 cid, u8 tid, u16 seq);
|
||||
struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
|
||||
int size, u16 ssn);
|
||||
void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <linux/types.h>
|
||||
#include "wmi.h"
|
||||
#include "wil_platform.h"
|
||||
#include "fw.h"
|
||||
|
||||
extern bool no_fw_recovery;
|
||||
extern unsigned int mtu_max;
|
||||
|
@ -49,6 +50,11 @@ extern bool disable_ap_sme;
|
|||
#define WIL_DEFAULT_BUS_REQUEST_KBPS 128000 /* ~1Gbps */
|
||||
#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
|
||||
|
||||
/* maximum number of virtual interfaces the driver supports
|
||||
* (including the main interface)
|
||||
*/
|
||||
#define WIL_MAX_VIFS 4
|
||||
|
||||
/**
|
||||
* extract bits [@b0:@b1] (inclusive) from the value @x
|
||||
* it should be @b0 <= @b1, or result is incorrect
|
||||
|
@ -463,13 +469,12 @@ struct vring_tx_data {
|
|||
u16 agg_timeout;
|
||||
u8 agg_amsdu;
|
||||
bool addba_in_progress; /* if set, agg_xxx is for request in progress */
|
||||
u8 mid;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
enum { /* for wil6210_priv.status */
|
||||
wil_status_fwready = 0, /* FW operational */
|
||||
wil_status_fwconnecting,
|
||||
wil_status_fwconnected,
|
||||
wil_status_dontscan,
|
||||
wil_status_mbox_ready, /* MBOX structures ready */
|
||||
wil_status_irqen, /* interrupts enabled - for debug */
|
||||
|
@ -541,7 +546,6 @@ struct wil_tid_crypto_rx {
|
|||
struct wil_p2p_info {
|
||||
struct ieee80211_channel listen_chan;
|
||||
u8 discovery_started;
|
||||
u8 p2p_dev_started;
|
||||
u64 cookie;
|
||||
struct wireless_dev *pending_listen_wdev;
|
||||
unsigned int listen_duration;
|
||||
|
@ -584,6 +588,7 @@ struct wil_net_stats {
|
|||
*/
|
||||
struct wil_sta_info {
|
||||
u8 addr[ETH_ALEN];
|
||||
u8 mid;
|
||||
enum wil_sta_status status;
|
||||
struct wil_net_stats stats;
|
||||
/* Rx BACK */
|
||||
|
@ -669,10 +674,44 @@ extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST];
|
|||
extern u8 led_id;
|
||||
extern u8 led_polarity;
|
||||
|
||||
enum wil6210_vif_status {
|
||||
wil_vif_fwconnecting,
|
||||
wil_vif_fwconnected,
|
||||
wil_vif_status_last /* keep last */
|
||||
};
|
||||
|
||||
struct wil6210_vif {
|
||||
struct wireless_dev wdev;
|
||||
struct net_device *ndev;
|
||||
struct wil6210_priv *wil;
|
||||
u8 mid;
|
||||
DECLARE_BITMAP(status, wil_vif_status_last);
|
||||
u32 privacy; /* secure connection? */
|
||||
u16 channel; /* relevant in AP mode */
|
||||
u8 hidden_ssid; /* relevant in AP mode */
|
||||
u32 ap_isolate; /* no intra-BSS communication */
|
||||
bool pbss;
|
||||
int bcast_vring;
|
||||
struct cfg80211_bss *bss; /* connected bss, relevant in STA mode */
|
||||
int locally_generated_disc; /* relevant in STA mode */
|
||||
struct timer_list connect_timer;
|
||||
struct work_struct disconnect_worker;
|
||||
/* scan */
|
||||
struct cfg80211_scan_request *scan_request;
|
||||
struct timer_list scan_timer; /* detect scan timeout */
|
||||
struct wil_p2p_info p2p;
|
||||
/* keep alive */
|
||||
struct list_head probe_client_pending;
|
||||
struct mutex probe_client_mutex; /* protect @probe_client_pending */
|
||||
struct work_struct probe_client_worker;
|
||||
int net_queue_stopped; /* netif_tx_stop_all_queues invoked */
|
||||
};
|
||||
|
||||
struct wil6210_priv {
|
||||
struct pci_dev *pdev;
|
||||
u32 bar_size;
|
||||
struct wireless_dev *wdev;
|
||||
struct wiphy *wiphy;
|
||||
struct net_device *main_ndev;
|
||||
void __iomem *csr;
|
||||
DECLARE_BITMAP(status, wil_status_last);
|
||||
u8 fw_version[ETHTOOL_FWVERS_LEN];
|
||||
|
@ -686,21 +725,18 @@ struct wil6210_priv {
|
|||
DECLARE_BITMAP(hw_capa, hw_capa_last);
|
||||
DECLARE_BITMAP(fw_capabilities, WMI_FW_CAPABILITY_MAX);
|
||||
DECLARE_BITMAP(platform_capa, WIL_PLATFORM_CAPA_MAX);
|
||||
u8 n_mids; /* number of additional MIDs as reported by FW */
|
||||
u32 recovery_count; /* num of FW recovery attempts in a short time */
|
||||
u32 recovery_state; /* FW recovery state machine */
|
||||
unsigned long last_fw_recovery; /* jiffies of last fw recovery */
|
||||
wait_queue_head_t wq; /* for all wait_event() use */
|
||||
u8 max_vifs; /* maximum number of interfaces, including main */
|
||||
struct wil6210_vif *vifs[WIL_MAX_VIFS];
|
||||
struct mutex vif_mutex; /* protects access to VIF entries */
|
||||
atomic_t connected_vifs;
|
||||
/* profile */
|
||||
struct cfg80211_chan_def monitor_chandef;
|
||||
u32 monitor_flags;
|
||||
u32 privacy; /* secure connection? */
|
||||
u8 hidden_ssid; /* relevant in AP mode */
|
||||
u16 channel; /* relevant in AP mode */
|
||||
int sinfo_gen;
|
||||
u32 ap_isolate; /* no intra-BSS communication */
|
||||
struct cfg80211_bss *bss; /* connected bss, relevant in STA mode */
|
||||
int locally_generated_disc; /* relevant in STA mode */
|
||||
/* interrupt moderation */
|
||||
u32 tx_max_burst_duration;
|
||||
u32 tx_interframe_timeout;
|
||||
|
@ -715,15 +751,13 @@ struct wil6210_priv {
|
|||
struct completion wmi_call;
|
||||
u16 wmi_seq;
|
||||
u16 reply_id; /**< wait for this WMI event */
|
||||
u8 reply_mid;
|
||||
void *reply_buf;
|
||||
u16 reply_size;
|
||||
struct workqueue_struct *wmi_wq; /* for deferred calls */
|
||||
struct work_struct wmi_event_worker;
|
||||
struct workqueue_struct *wq_service;
|
||||
struct work_struct disconnect_worker;
|
||||
struct work_struct fw_error_worker; /* for FW error recovery */
|
||||
struct timer_list connect_timer;
|
||||
struct timer_list scan_timer; /* detect scan timeout */
|
||||
struct list_head pending_wmi_ev;
|
||||
/*
|
||||
* protect pending_wmi_ev
|
||||
|
@ -732,13 +766,10 @@ struct wil6210_priv {
|
|||
*/
|
||||
spinlock_t wmi_ev_lock;
|
||||
spinlock_t net_queue_lock; /* guarding stop/wake netif queue */
|
||||
int net_queue_stopped; /* netif_tx_stop_all_queues invoked */
|
||||
struct napi_struct napi_rx;
|
||||
struct napi_struct napi_tx;
|
||||
/* keep alive */
|
||||
struct list_head probe_client_pending;
|
||||
struct mutex probe_client_mutex; /* protect @probe_client_pending */
|
||||
struct work_struct probe_client_worker;
|
||||
struct net_device napi_ndev; /* dummy net_device serving all VIFs */
|
||||
|
||||
/* DMA related */
|
||||
struct vring vring_rx;
|
||||
unsigned int rx_buf_len;
|
||||
|
@ -746,11 +777,8 @@ struct wil6210_priv {
|
|||
struct vring_tx_data vring_tx_data[WIL6210_MAX_TX_RINGS];
|
||||
u8 vring2cid_tid[WIL6210_MAX_TX_RINGS][2]; /* [0] - CID, [1] - TID */
|
||||
struct wil_sta_info sta[WIL6210_MAX_CID];
|
||||
int bcast_vring;
|
||||
u32 vring_idle_trsh; /* HW fetches up to 16 descriptors at once */
|
||||
u32 dma_addr_size; /* indicates dma addr size */
|
||||
/* scan */
|
||||
struct cfg80211_scan_request *scan_request;
|
||||
|
||||
struct mutex mutex; /* for wil6210_priv access in wil_{up|down} */
|
||||
/* statistics */
|
||||
|
@ -770,13 +798,10 @@ struct wil6210_priv {
|
|||
|
||||
struct pmc_ctx pmc;
|
||||
|
||||
bool pbss;
|
||||
|
||||
struct wil_p2p_info p2p;
|
||||
u8 p2p_dev_started;
|
||||
|
||||
/* P2P_DEVICE vif */
|
||||
struct wireless_dev *p2p_wdev;
|
||||
struct mutex p2p_wdev_mutex; /* protect @p2p_wdev and @scan_request */
|
||||
struct wireless_dev *radio_wdev;
|
||||
|
||||
/* High Access Latency Policy voting */
|
||||
|
@ -798,13 +823,35 @@ struct wil6210_priv {
|
|||
u32 iccm_base;
|
||||
};
|
||||
|
||||
#define wil_to_wiphy(i) (i->wdev->wiphy)
|
||||
#define wil_to_wiphy(i) (i->wiphy)
|
||||
#define wil_to_dev(i) (wiphy_dev(wil_to_wiphy(i)))
|
||||
#define wiphy_to_wil(w) (struct wil6210_priv *)(wiphy_priv(w))
|
||||
#define wil_to_wdev(i) (i->wdev)
|
||||
#define wdev_to_wil(w) (struct wil6210_priv *)(wdev_priv(w))
|
||||
#define wil_to_ndev(i) (wil_to_wdev(i)->netdev)
|
||||
#define ndev_to_wil(n) (wdev_to_wil(n->ieee80211_ptr))
|
||||
#define ndev_to_vif(n) (struct wil6210_vif *)(netdev_priv(n))
|
||||
#define vif_to_wil(v) (v->wil)
|
||||
#define vif_to_ndev(v) (v->ndev)
|
||||
#define vif_to_wdev(v) (&v->wdev)
|
||||
|
||||
static inline struct wil6210_vif *wdev_to_vif(struct wil6210_priv *wil,
|
||||
struct wireless_dev *wdev)
|
||||
{
|
||||
/* main interface is shared with P2P device */
|
||||
if (wdev == wil->p2p_wdev)
|
||||
return ndev_to_vif(wil->main_ndev);
|
||||
else
|
||||
return container_of(wdev, struct wil6210_vif, wdev);
|
||||
}
|
||||
|
||||
static inline struct wireless_dev *
|
||||
vif_to_radio_wdev(struct wil6210_priv *wil, struct wil6210_vif *vif)
|
||||
{
|
||||
/* main interface is shared with P2P device */
|
||||
if (vif->mid)
|
||||
return vif_to_wdev(vif);
|
||||
else
|
||||
return wil->radio_wdev;
|
||||
}
|
||||
|
||||
__printf(2, 3)
|
||||
void wil_dbg_trace(struct wil6210_priv *wil, const char *fmt, ...);
|
||||
|
@ -817,7 +864,7 @@ void __wil_info(struct wil6210_priv *wil, const char *fmt, ...);
|
|||
__printf(2, 3)
|
||||
void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...);
|
||||
#define wil_dbg(wil, fmt, arg...) do { \
|
||||
netdev_dbg(wil_to_ndev(wil), fmt, ##arg); \
|
||||
netdev_dbg(wil->main_ndev, fmt, ##arg); \
|
||||
wil_dbg_trace(wil, fmt, ##arg); \
|
||||
} while (0)
|
||||
|
||||
|
@ -900,9 +947,18 @@ void wil_memcpy_fromio_32(void *dst, const volatile void __iomem *src,
|
|||
void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
|
||||
size_t count);
|
||||
|
||||
struct wil6210_vif *
|
||||
wil_vif_alloc(struct wil6210_priv *wil, const char *name,
|
||||
unsigned char name_assign_type, enum nl80211_iftype iftype);
|
||||
void wil_vif_free(struct wil6210_vif *vif);
|
||||
void *wil_if_alloc(struct device *dev);
|
||||
bool wil_has_other_active_ifaces(struct wil6210_priv *wil,
|
||||
struct net_device *ndev, bool up, bool ok);
|
||||
bool wil_has_active_ifaces(struct wil6210_priv *wil, bool up, bool ok);
|
||||
void wil_if_free(struct wil6210_priv *wil);
|
||||
int wil_vif_add(struct wil6210_priv *wil, struct wil6210_vif *vif);
|
||||
int wil_if_add(struct wil6210_priv *wil);
|
||||
void wil_vif_remove(struct wil6210_priv *wil, u8 mid);
|
||||
void wil_if_remove(struct wil6210_priv *wil);
|
||||
int wil_priv_init(struct wil6210_priv *wil);
|
||||
void wil_priv_deinit(struct wil6210_priv *wil);
|
||||
|
@ -918,7 +974,7 @@ int wil_down(struct wil6210_priv *wil);
|
|||
int __wil_down(struct wil6210_priv *wil);
|
||||
void wil_refresh_fw_capabilities(struct wil6210_priv *wil);
|
||||
void wil_mbox_ring_le2cpus(struct wil6210_mbox_ring *r);
|
||||
int wil_find_cid(struct wil6210_priv *wil, const u8 *mac);
|
||||
int wil_find_cid(struct wil6210_priv *wil, u8 mid, const u8 *mac);
|
||||
void wil_set_ethtoolops(struct net_device *ndev);
|
||||
|
||||
struct fw_map *wil_find_fw_mapping(const char *section);
|
||||
|
@ -927,40 +983,45 @@ void __iomem *wmi_buffer(struct wil6210_priv *wil, __le32 ptr);
|
|||
void __iomem *wmi_addr(struct wil6210_priv *wil, u32 ptr);
|
||||
int wmi_read_hdr(struct wil6210_priv *wil, __le32 ptr,
|
||||
struct wil6210_mbox_hdr *hdr);
|
||||
int wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len);
|
||||
int wmi_send(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len);
|
||||
void wmi_recv_cmd(struct wil6210_priv *wil);
|
||||
int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
|
||||
int wmi_call(struct wil6210_priv *wil, u16 cmdid, u8 mid, void *buf, u16 len,
|
||||
u16 reply_id, void *reply, u8 reply_size, int to_msec);
|
||||
void wmi_event_worker(struct work_struct *work);
|
||||
void wmi_event_flush(struct wil6210_priv *wil);
|
||||
int wmi_set_ssid(struct wil6210_priv *wil, u8 ssid_len, const void *ssid);
|
||||
int wmi_get_ssid(struct wil6210_priv *wil, u8 *ssid_len, void *ssid);
|
||||
int wmi_set_ssid(struct wil6210_vif *vif, u8 ssid_len, const void *ssid);
|
||||
int wmi_get_ssid(struct wil6210_vif *vif, u8 *ssid_len, void *ssid);
|
||||
int wmi_set_channel(struct wil6210_priv *wil, int channel);
|
||||
int wmi_get_channel(struct wil6210_priv *wil, int *channel);
|
||||
int wmi_del_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
||||
int wmi_del_cipher_key(struct wil6210_vif *vif, u8 key_index,
|
||||
const void *mac_addr, int key_usage);
|
||||
int wmi_add_cipher_key(struct wil6210_priv *wil, u8 key_index,
|
||||
int wmi_add_cipher_key(struct wil6210_vif *vif, u8 key_index,
|
||||
const void *mac_addr, int key_len, const void *key,
|
||||
int key_usage);
|
||||
int wmi_echo(struct wil6210_priv *wil);
|
||||
int wmi_set_ie(struct wil6210_priv *wil, u8 type, u16 ie_len, const void *ie);
|
||||
int wmi_set_ie(struct wil6210_vif *vif, u8 type, u16 ie_len, const void *ie);
|
||||
int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
|
||||
int wmi_rxon(struct wil6210_priv *wil, bool on);
|
||||
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
|
||||
int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac,
|
||||
int wmi_disconnect_sta(struct wil6210_vif *vif, const u8 *mac,
|
||||
u16 reason, bool full_disconnect, bool del_sta);
|
||||
int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout);
|
||||
int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason);
|
||||
int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason);
|
||||
int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
|
||||
int wmi_addba(struct wil6210_priv *wil, u8 mid,
|
||||
u8 ringid, u8 size, u16 timeout);
|
||||
int wmi_delba_tx(struct wil6210_priv *wil, u8 mid, u8 ringid, u16 reason);
|
||||
int wmi_delba_rx(struct wil6210_priv *wil, u8 mid, u8 cidxtid, u16 reason);
|
||||
int wmi_addba_rx_resp(struct wil6210_priv *wil,
|
||||
u8 mid, u8 cid, u8 tid, u8 token,
|
||||
u16 status, bool amsdu, u16 agg_wsize, u16 timeout);
|
||||
int wmi_ps_dev_profile_cfg(struct wil6210_priv *wil,
|
||||
enum wmi_ps_profile_type ps_profile);
|
||||
int wmi_set_mgmt_retry(struct wil6210_priv *wil, u8 retry_short);
|
||||
int wmi_get_mgmt_retry(struct wil6210_priv *wil, u8 *retry_short);
|
||||
int wmi_new_sta(struct wil6210_priv *wil, const u8 *mac, u8 aid);
|
||||
int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
|
||||
u8 dialog_token, __le16 ba_param_set,
|
||||
int wmi_new_sta(struct wil6210_vif *vif, const u8 *mac, u8 aid);
|
||||
int wmi_port_allocate(struct wil6210_priv *wil, u8 mid,
|
||||
const u8 *mac, enum nl80211_iftype iftype);
|
||||
int wmi_port_delete(struct wil6210_priv *wil, u8 mid);
|
||||
int wil_addba_rx_request(struct wil6210_priv *wil, u8 mid,
|
||||
u8 cidxtid, u8 dialog_token, __le16 ba_param_set,
|
||||
__le16 ba_timeout, __le16 ba_seq_ctrl);
|
||||
int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize);
|
||||
|
||||
|
@ -976,28 +1037,31 @@ void wil6210_mask_halp(struct wil6210_priv *wil);
|
|||
|
||||
/* P2P */
|
||||
bool wil_p2p_is_social_scan(struct cfg80211_scan_request *request);
|
||||
void wil_p2p_discovery_timer_fn(struct timer_list *t);
|
||||
int wil_p2p_search(struct wil6210_priv *wil,
|
||||
int wil_p2p_search(struct wil6210_vif *vif,
|
||||
struct cfg80211_scan_request *request);
|
||||
int wil_p2p_listen(struct wil6210_priv *wil, struct wireless_dev *wdev,
|
||||
unsigned int duration, struct ieee80211_channel *chan,
|
||||
u64 *cookie);
|
||||
u8 wil_p2p_stop_discovery(struct wil6210_priv *wil);
|
||||
int wil_p2p_cancel_listen(struct wil6210_priv *wil, u64 cookie);
|
||||
u8 wil_p2p_stop_discovery(struct wil6210_vif *vif);
|
||||
int wil_p2p_cancel_listen(struct wil6210_vif *vif, u64 cookie);
|
||||
void wil_p2p_listen_expired(struct work_struct *work);
|
||||
void wil_p2p_search_expired(struct work_struct *work);
|
||||
void wil_p2p_stop_radio_operations(struct wil6210_priv *wil);
|
||||
void wil_p2p_delayed_listen_work(struct work_struct *work);
|
||||
|
||||
/* WMI for P2P */
|
||||
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel, int bi);
|
||||
int wmi_start_listen(struct wil6210_priv *wil);
|
||||
int wmi_start_search(struct wil6210_priv *wil);
|
||||
int wmi_stop_discovery(struct wil6210_priv *wil);
|
||||
int wmi_p2p_cfg(struct wil6210_vif *vif, int channel, int bi);
|
||||
int wmi_start_listen(struct wil6210_vif *vif);
|
||||
int wmi_start_search(struct wil6210_vif *vif);
|
||||
int wmi_stop_discovery(struct wil6210_vif *vif);
|
||||
|
||||
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
struct cfg80211_mgmt_tx_params *params,
|
||||
u64 *cookie);
|
||||
int wil_cfg80211_iface_combinations_from_fw(
|
||||
struct wil6210_priv *wil,
|
||||
const struct wil_fw_record_concurrency *conc);
|
||||
int wil_vif_prepare_stop(struct wil6210_vif *vif);
|
||||
|
||||
#if defined(CONFIG_WIL6210_DEBUGFS)
|
||||
int wil6210_debugfs_init(struct wil6210_priv *wil);
|
||||
|
@ -1007,44 +1071,47 @@ static inline int wil6210_debugfs_init(struct wil6210_priv *wil) { return 0; }
|
|||
static inline void wil6210_debugfs_remove(struct wil6210_priv *wil) {}
|
||||
#endif
|
||||
|
||||
int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
|
||||
int wil_cid_fill_sinfo(struct wil6210_vif *vif, int cid,
|
||||
struct station_info *sinfo);
|
||||
|
||||
struct wireless_dev *wil_cfg80211_init(struct device *dev);
|
||||
void wil_wdev_free(struct wil6210_priv *wil);
|
||||
struct wil6210_priv *wil_cfg80211_init(struct device *dev);
|
||||
void wil_cfg80211_deinit(struct wil6210_priv *wil);
|
||||
void wil_p2p_wdev_free(struct wil6210_priv *wil);
|
||||
|
||||
int wmi_set_mac_address(struct wil6210_priv *wil, void *addr);
|
||||
int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype,
|
||||
u8 chan, u8 hidden_ssid, u8 is_go);
|
||||
int wmi_pcp_stop(struct wil6210_priv *wil);
|
||||
int wmi_pcp_start(struct wil6210_vif *vif, int bi, u8 wmi_nettype, u8 chan,
|
||||
u8 hidden_ssid, u8 is_go);
|
||||
int wmi_pcp_stop(struct wil6210_vif *vif);
|
||||
int wmi_led_cfg(struct wil6210_priv *wil, bool enable);
|
||||
int wmi_abort_scan(struct wil6210_priv *wil);
|
||||
void wil_abort_scan(struct wil6210_priv *wil, bool sync);
|
||||
int wmi_abort_scan(struct wil6210_vif *vif);
|
||||
void wil_abort_scan(struct wil6210_vif *vif, bool sync);
|
||||
void wil_abort_scan_all_vifs(struct wil6210_priv *wil, bool sync);
|
||||
void wil6210_bus_request(struct wil6210_priv *wil, u32 kbps);
|
||||
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
|
||||
void wil6210_disconnect(struct wil6210_vif *vif, const u8 *bssid,
|
||||
u16 reason_code, bool from_event);
|
||||
void wil_probe_client_flush(struct wil6210_priv *wil);
|
||||
void wil_probe_client_flush(struct wil6210_vif *vif);
|
||||
void wil_probe_client_worker(struct work_struct *work);
|
||||
void wil_disconnect_worker(struct work_struct *work);
|
||||
|
||||
int wil_rx_init(struct wil6210_priv *wil, u16 size);
|
||||
void wil_rx_fini(struct wil6210_priv *wil);
|
||||
|
||||
/* TX API */
|
||||
int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
||||
int wil_vring_init_tx(struct wil6210_vif *vif, int id, int size,
|
||||
int cid, int tid);
|
||||
void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
|
||||
int wil_tx_init(struct wil6210_priv *wil, int cid);
|
||||
int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size);
|
||||
int wil_bcast_init(struct wil6210_priv *wil);
|
||||
void wil_bcast_fini(struct wil6210_priv *wil);
|
||||
int wil_tx_init(struct wil6210_vif *vif, int cid);
|
||||
int wil_vring_init_bcast(struct wil6210_vif *vif, int id, int size);
|
||||
int wil_bcast_init(struct wil6210_vif *vif);
|
||||
void wil_bcast_fini(struct wil6210_vif *vif);
|
||||
void wil_bcast_fini_all(struct wil6210_priv *wil);
|
||||
|
||||
void wil_update_net_queues(struct wil6210_priv *wil, struct vring *vring,
|
||||
bool should_stop);
|
||||
void wil_update_net_queues_bh(struct wil6210_priv *wil, struct vring *vring,
|
||||
bool check_stop);
|
||||
void wil_update_net_queues(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
||||
struct vring *vring, bool should_stop);
|
||||
void wil_update_net_queues_bh(struct wil6210_priv *wil, struct wil6210_vif *vif,
|
||||
struct vring *vring, bool check_stop);
|
||||
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev);
|
||||
int wil_tx_complete(struct wil6210_priv *wil, int ringid);
|
||||
int wil_tx_complete(struct wil6210_vif *vif, int ringid);
|
||||
void wil6210_unmask_irq_tx(struct wil6210_priv *wil);
|
||||
|
||||
/* RX API */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue