提交 abd5f008 编写于 作者: K Kalle Valo

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
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -2439,7 +2440,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar) ...@@ -2439,7 +2440,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ret = ath10k_hif_power_up(ar); ret = ath10k_hif_power_up(ar);
if (ret) { if (ret) {
ath10k_err(ar, "could not start pci hif (%d)\n", ret); ath10k_err(ar, "could not power on hif bus (%d)\n", ret);
return ret; return ret;
} }
......
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -324,6 +325,27 @@ struct ath10k_tpc_stats { ...@@ -324,6 +325,27 @@ struct ath10k_tpc_stats {
struct ath10k_tpc_table tpc_table[WMI_TPC_FLAG]; struct ath10k_tpc_table tpc_table[WMI_TPC_FLAG];
}; };
struct ath10k_tpc_table_final {
u32 pream_idx[WMI_TPC_FINAL_RATE_MAX];
u8 rate_code[WMI_TPC_FINAL_RATE_MAX];
char tpc_value[WMI_TPC_FINAL_RATE_MAX][WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE];
};
struct ath10k_tpc_stats_final {
u32 reg_domain;
u32 chan_freq;
u32 phy_mode;
u32 twice_antenna_reduction;
u32 twice_max_rd_power;
s32 twice_antenna_gain;
u32 power_limit;
u32 num_tx_chain;
u32 ctl;
u32 rate_max;
u8 flag[WMI_TPC_FLAG];
struct ath10k_tpc_table_final tpc_table_final[WMI_TPC_FLAG];
};
struct ath10k_dfs_stats { struct ath10k_dfs_stats {
u32 phy_errors; u32 phy_errors;
u32 pulses_total; u32 pulses_total;
...@@ -354,6 +376,45 @@ struct ath10k_txq { ...@@ -354,6 +376,45 @@ struct ath10k_txq {
unsigned long num_push_allowed; unsigned long num_push_allowed;
}; };
enum ath10k_pkt_rx_err {
ATH10K_PKT_RX_ERR_FCS,
ATH10K_PKT_RX_ERR_TKIP,
ATH10K_PKT_RX_ERR_CRYPT,
ATH10K_PKT_RX_ERR_PEER_IDX_INVAL,
ATH10K_PKT_RX_ERR_MAX,
};
enum ath10k_ampdu_subfrm_num {
ATH10K_AMPDU_SUBFRM_NUM_10,
ATH10K_AMPDU_SUBFRM_NUM_20,
ATH10K_AMPDU_SUBFRM_NUM_30,
ATH10K_AMPDU_SUBFRM_NUM_40,
ATH10K_AMPDU_SUBFRM_NUM_50,
ATH10K_AMPDU_SUBFRM_NUM_60,
ATH10K_AMPDU_SUBFRM_NUM_MORE,
ATH10K_AMPDU_SUBFRM_NUM_MAX,
};
enum ath10k_amsdu_subfrm_num {
ATH10K_AMSDU_SUBFRM_NUM_1,
ATH10K_AMSDU_SUBFRM_NUM_2,
ATH10K_AMSDU_SUBFRM_NUM_3,
ATH10K_AMSDU_SUBFRM_NUM_4,
ATH10K_AMSDU_SUBFRM_NUM_MORE,
ATH10K_AMSDU_SUBFRM_NUM_MAX,
};
struct ath10k_sta_tid_stats {
unsigned long int rx_pkt_from_fw;
unsigned long int rx_pkt_unchained;
unsigned long int rx_pkt_drop_chained;
unsigned long int rx_pkt_drop_filter;
unsigned long int rx_pkt_err[ATH10K_PKT_RX_ERR_MAX];
unsigned long int rx_pkt_queued_for_mac;
unsigned long int rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MAX];
unsigned long int rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MAX];
};
struct ath10k_sta { struct ath10k_sta {
struct ath10k_vif *arvif; struct ath10k_vif *arvif;
...@@ -371,6 +432,9 @@ struct ath10k_sta { ...@@ -371,6 +432,9 @@ struct ath10k_sta {
#ifdef CONFIG_MAC80211_DEBUGFS #ifdef CONFIG_MAC80211_DEBUGFS
/* protected by conf_mutex */ /* protected by conf_mutex */
bool aggr_mode; bool aggr_mode;
/* Protected with ar->data_lock */
struct ath10k_sta_tid_stats tid_stats[IEEE80211_NUM_TIDS + 1];
#endif #endif
}; };
...@@ -487,6 +551,7 @@ struct ath10k_debug { ...@@ -487,6 +551,7 @@ struct ath10k_debug {
/* used for tpc-dump storage, protected by data-lock */ /* used for tpc-dump storage, protected by data-lock */
struct ath10k_tpc_stats *tpc_stats; struct ath10k_tpc_stats *tpc_stats;
struct ath10k_tpc_stats_final *tpc_stats_final;
struct completion tpc_complete; struct completion tpc_complete;
...@@ -1019,6 +1084,8 @@ struct ath10k { ...@@ -1019,6 +1084,8 @@ struct ath10k {
void *ce_priv; void *ce_priv;
u32 sta_tid_stats_mask;
/* must be last */ /* must be last */
u8 drv_priv[0] __aligned(sizeof(void *)); u8 drv_priv[0] __aligned(sizeof(void *));
}; };
......
...@@ -1480,6 +1480,19 @@ void ath10k_debug_tpc_stats_process(struct ath10k *ar, ...@@ -1480,6 +1480,19 @@ void ath10k_debug_tpc_stats_process(struct ath10k *ar,
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
} }
void
ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
struct ath10k_tpc_stats_final *tpc_stats)
{
spin_lock_bh(&ar->data_lock);
kfree(ar->debug.tpc_stats_final);
ar->debug.tpc_stats_final = tpc_stats;
complete(&ar->debug.tpc_complete);
spin_unlock_bh(&ar->data_lock);
}
static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats, static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats,
unsigned int j, char *buf, size_t *len) unsigned int j, char *buf, size_t *len)
{ {
...@@ -2143,6 +2156,137 @@ static const struct file_operations fops_fw_checksums = { ...@@ -2143,6 +2156,137 @@ static const struct file_operations fops_fw_checksums = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static ssize_t ath10k_sta_tid_stats_mask_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
char buf[32];
size_t len;
len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->sta_tid_stats_mask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t ath10k_sta_tid_stats_mask_write(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
char buf[32];
ssize_t len;
u32 mask;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (kstrtoint(buf, 0, &mask))
return -EINVAL;
ar->sta_tid_stats_mask = mask;
return len;
}
static const struct file_operations fops_sta_tid_stats_mask = {
.read = ath10k_sta_tid_stats_mask_read,
.write = ath10k_sta_tid_stats_mask_write,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static int ath10k_debug_tpc_stats_final_request(struct ath10k *ar)
{
int ret;
unsigned long time_left;
lockdep_assert_held(&ar->conf_mutex);
reinit_completion(&ar->debug.tpc_complete);
ret = ath10k_wmi_pdev_get_tpc_table_cmdid(ar, WMI_TPC_CONFIG_PARAM);
if (ret) {
ath10k_warn(ar, "failed to request tpc table cmdid: %d\n", ret);
return ret;
}
time_left = wait_for_completion_timeout(&ar->debug.tpc_complete,
1 * HZ);
if (time_left == 0)
return -ETIMEDOUT;
return 0;
}
static int ath10k_tpc_stats_final_open(struct inode *inode, struct file *file)
{
struct ath10k *ar = inode->i_private;
void *buf;
int ret;
mutex_lock(&ar->conf_mutex);
if (ar->state != ATH10K_STATE_ON) {
ret = -ENETDOWN;
goto err_unlock;
}
buf = vmalloc(ATH10K_TPC_CONFIG_BUF_SIZE);
if (!buf) {
ret = -ENOMEM;
goto err_unlock;
}
ret = ath10k_debug_tpc_stats_final_request(ar);
if (ret) {
ath10k_warn(ar, "failed to request tpc stats final: %d\n",
ret);
goto err_free;
}
ath10k_tpc_stats_fill(ar, ar->debug.tpc_stats, buf);
file->private_data = buf;
mutex_unlock(&ar->conf_mutex);
return 0;
err_free:
vfree(buf);
err_unlock:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static int ath10k_tpc_stats_final_release(struct inode *inode,
struct file *file)
{
vfree(file->private_data);
return 0;
}
static ssize_t ath10k_tpc_stats_final_read(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
const char *buf = file->private_data;
unsigned int len = strlen(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static const struct file_operations fops_tpc_stats_final = {
.open = ath10k_tpc_stats_final_open,
.release = ath10k_tpc_stats_final_release,
.read = ath10k_tpc_stats_final_read,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int ath10k_debug_create(struct ath10k *ar) int ath10k_debug_create(struct ath10k *ar)
{ {
ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN); ar->debug.cal_data = vzalloc(ATH10K_DEBUG_CAL_DATA_LEN);
...@@ -2258,6 +2402,16 @@ int ath10k_debug_register(struct ath10k *ar) ...@@ -2258,6 +2402,16 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar, debugfs_create_file("fw_checksums", 0400, ar->debug.debugfs_phy, ar,
&fops_fw_checksums); &fops_fw_checksums);
if (IS_ENABLED(CONFIG_MAC80211_DEBUGFS))
debugfs_create_file("sta_tid_stats_mask", 0600,
ar->debug.debugfs_phy,
ar, &fops_sta_tid_stats_mask);
if (test_bit(WMI_SERVICE_TPC_STATS_FINAL, ar->wmi.svc_map))
debugfs_create_file("tpc_stats_final", 0400,
ar->debug.debugfs_phy, ar,
&fops_tpc_stats_final);
return 0; return 0;
} }
......
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -101,6 +102,9 @@ void ath10k_debug_unregister(struct ath10k *ar); ...@@ -101,6 +102,9 @@ void ath10k_debug_unregister(struct ath10k *ar);
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb); void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb);
void ath10k_debug_tpc_stats_process(struct ath10k *ar, void ath10k_debug_tpc_stats_process(struct ath10k *ar,
struct ath10k_tpc_stats *tpc_stats); struct ath10k_tpc_stats *tpc_stats);
void
ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
struct ath10k_tpc_stats_final *tpc_stats);
void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len); void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++) #define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
...@@ -164,6 +168,13 @@ static inline void ath10k_debug_tpc_stats_process(struct ath10k *ar, ...@@ -164,6 +168,13 @@ static inline void ath10k_debug_tpc_stats_process(struct ath10k *ar,
kfree(tpc_stats); kfree(tpc_stats);
} }
static inline void
ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
struct ath10k_tpc_stats_final *tpc_stats)
{
kfree(tpc_stats);
}
static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer,
int len) int len)
{ {
...@@ -191,12 +202,42 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ...@@ -191,12 +202,42 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir); struct ieee80211_sta *sta, struct dentry *dir);
void ath10k_sta_update_rx_duration(struct ath10k *ar, void ath10k_sta_update_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats); struct ath10k_fw_stats *stats);
void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
unsigned long int num_msdus,
enum ath10k_pkt_rx_err err,
unsigned long int unchain_cnt,
unsigned long int drop_cnt,
unsigned long int drop_cnt_filter,
unsigned long int queued_msdus);
void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar,
u16 peer_id, u8 tid,
struct htt_rx_indication_mpdu_range *ranges,
int num_ranges);
#else #else
static inline static inline
void ath10k_sta_update_rx_duration(struct ath10k *ar, void ath10k_sta_update_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats) struct ath10k_fw_stats *stats)
{ {
} }
static inline
void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
unsigned long int num_msdus,
enum ath10k_pkt_rx_err err,
unsigned long int unchain_cnt,
unsigned long int drop_cnt,
unsigned long int drop_cnt_filter,
unsigned long int queued_msdus)
{
}
static inline
void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar,
u16 peer_id, u8 tid,
struct htt_rx_indication_mpdu_range *ranges,
int num_ranges)
{
}
#endif /* CONFIG_MAC80211_DEBUGFS */ #endif /* CONFIG_MAC80211_DEBUGFS */
#ifdef CONFIG_ATH10K_DEBUG #ifdef CONFIG_ATH10K_DEBUG
......
/* /*
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -16,8 +17,125 @@ ...@@ -16,8 +17,125 @@
#include "core.h" #include "core.h"
#include "wmi-ops.h" #include "wmi-ops.h"
#include "txrx.h"
#include "debug.h" #include "debug.h"
static void ath10k_rx_stats_update_amsdu_subfrm(struct ath10k *ar,
struct ath10k_sta_tid_stats *stats,
u32 msdu_count)
{
if (msdu_count == 1)
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_1]++;
else if (msdu_count == 2)
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_2]++;
else if (msdu_count == 3)
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_3]++;
else if (msdu_count == 4)
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_4]++;
else if (msdu_count > 4)
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MORE]++;
}
static void ath10k_rx_stats_update_ampdu_subfrm(struct ath10k *ar,
struct ath10k_sta_tid_stats *stats,
u32 mpdu_count)
{
if (mpdu_count <= 10)
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_10]++;
else if (mpdu_count <= 20)
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_20]++;
else if (mpdu_count <= 30)
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_30]++;
else if (mpdu_count <= 40)
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_40]++;
else if (mpdu_count <= 50)
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_50]++;
else if (mpdu_count <= 60)
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_60]++;
else if (mpdu_count > 60)
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MORE]++;
}
void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid,
struct htt_rx_indication_mpdu_range *ranges,
int num_ranges)
{
struct ath10k_sta *arsta;
struct ath10k_peer *peer;
int i;
if (tid > IEEE80211_NUM_TIDS || !(ar->sta_tid_stats_mask & BIT(tid)))
return;
rcu_read_lock();
spin_lock_bh(&ar->data_lock);
peer = ath10k_peer_find_by_id(ar, peer_id);
if (!peer)
goto out;
arsta = (struct ath10k_sta *)peer->sta->drv_priv;
for (i = 0; i < num_ranges; i++)
ath10k_rx_stats_update_ampdu_subfrm(ar,
&arsta->tid_stats[tid],
ranges[i].mpdu_count);
out:
spin_unlock_bh(&ar->data_lock);
rcu_read_unlock();
}
void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
unsigned long int num_msdus,
enum ath10k_pkt_rx_err err,
unsigned long int unchain_cnt,
unsigned long int drop_cnt,
unsigned long int drop_cnt_filter,
unsigned long int queued_msdus)
{
struct ieee80211_sta *sta;
struct ath10k_sta *arsta;
struct ieee80211_hdr *hdr;
struct ath10k_sta_tid_stats *stats;
u8 tid = IEEE80211_NUM_TIDS;
bool non_data_frm = false;
hdr = (struct ieee80211_hdr *)first_hdr;
if (!ieee80211_is_data(hdr->frame_control))
non_data_frm = true;
if (ieee80211_is_data_qos(hdr->frame_control))
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
if (!(ar->sta_tid_stats_mask & BIT(tid)) || non_data_frm)
return;
rcu_read_lock();
sta = ieee80211_find_sta_by_ifaddr(ar->hw, hdr->addr2, NULL);
if (!sta)
goto exit;
arsta = (struct ath10k_sta *)sta->drv_priv;
spin_lock_bh(&ar->data_lock);
stats = &arsta->tid_stats[tid];
stats->rx_pkt_from_fw += num_msdus;
stats->rx_pkt_unchained += unchain_cnt;
stats->rx_pkt_drop_chained += drop_cnt;
stats->rx_pkt_drop_filter += drop_cnt_filter;
if (err != ATH10K_PKT_RX_ERR_MAX)
stats->rx_pkt_err[err] += queued_msdus;
stats->rx_pkt_queued_for_mac += queued_msdus;
ath10k_rx_stats_update_amsdu_subfrm(ar, &arsta->tid_stats[tid],
num_msdus);
spin_unlock_bh(&ar->data_lock);
exit:
rcu_read_unlock();
}
static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar, static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,
struct ath10k_fw_stats *stats) struct ath10k_fw_stats *stats)
{ {
...@@ -342,6 +460,172 @@ static const struct file_operations fops_peer_debug_trigger = { ...@@ -342,6 +460,172 @@ static const struct file_operations fops_peer_debug_trigger = {
.llseek = default_llseek, .llseek = default_llseek,
}; };
static char *get_err_str(enum ath10k_pkt_rx_err i)
{
switch (i) {
case ATH10K_PKT_RX_ERR_FCS:
return "fcs_err";
case ATH10K_PKT_RX_ERR_TKIP:
return "tkip_err";
case ATH10K_PKT_RX_ERR_CRYPT:
return "crypt_err";
case ATH10K_PKT_RX_ERR_PEER_IDX_INVAL:
return "peer_idx_inval";
case ATH10K_PKT_RX_ERR_MAX:
return "unknown";
}
return "unknown";
}
static char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i)
{
switch (i) {
case ATH10K_AMPDU_SUBFRM_NUM_10:
return "upto 10";
case ATH10K_AMPDU_SUBFRM_NUM_20:
return "11-20";
case ATH10K_AMPDU_SUBFRM_NUM_30:
return "21-30";
case ATH10K_AMPDU_SUBFRM_NUM_40:
return "31-40";
case ATH10K_AMPDU_SUBFRM_NUM_50:
return "41-50";
case ATH10K_AMPDU_SUBFRM_NUM_60:
return "51-60";
case ATH10K_AMPDU_SUBFRM_NUM_MORE:
return ">60";
case ATH10K_AMPDU_SUBFRM_NUM_MAX:
return "0";
}
return "0";
}
static char *get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i)
{
switch (i) {
case ATH10K_AMSDU_SUBFRM_NUM_1:
return "1";
case ATH10K_AMSDU_SUBFRM_NUM_2:
return "2";
case ATH10K_AMSDU_SUBFRM_NUM_3:
return "3";
case ATH10K_AMSDU_SUBFRM_NUM_4:
return "4";
case ATH10K_AMSDU_SUBFRM_NUM_MORE:
return ">4";
case ATH10K_AMSDU_SUBFRM_NUM_MAX:
return "0";
}
return "0";
}
#define PRINT_TID_STATS(_field, _tabs) \
do { \
int k = 0; \
for (j = 0; j <= IEEE80211_NUM_TIDS; j++) { \
if (ar->sta_tid_stats_mask & BIT(j)) { \
len += scnprintf(buf + len, buf_len - len, \
"[%02d] %-10lu ", \
j, stats[j]._field); \
k++; \
if (k % 8 == 0) { \
len += scnprintf(buf + len, \
buf_len - len, "\n"); \
len += scnprintf(buf + len, \
buf_len - len, \
_tabs); \
} \
} \
} \
len += scnprintf(buf + len, buf_len - len, "\n"); \
} while (0)
static ssize_t ath10k_dbg_sta_read_tid_stats(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ieee80211_sta *sta = file->private_data;
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
struct ath10k *ar = arsta->arvif->ar;
struct ath10k_sta_tid_stats *stats = arsta->tid_stats;
size_t len = 0, buf_len = 1048 * IEEE80211_NUM_TIDS;
char *buf;
int i, j;
ssize_t ret;
buf = kzalloc(buf_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
len += scnprintf(buf + len, buf_len - len,
"\n\t\tDriver Rx pkt stats per tid, ([tid] count)\n");
len += scnprintf(buf + len, buf_len - len,
"\t\t------------------------------------------\n");
len += scnprintf(buf + len, buf_len - len, "MSDUs from FW\t\t\t");
PRINT_TID_STATS(rx_pkt_from_fw, "\t\t\t\t");
len += scnprintf(buf + len, buf_len - len, "MSDUs unchained\t\t\t");
PRINT_TID_STATS(rx_pkt_unchained, "\t\t\t\t");
len += scnprintf(buf + len, buf_len - len,
"MSDUs locally dropped:chained\t");
PRINT_TID_STATS(rx_pkt_drop_chained, "\t\t\t\t");
len += scnprintf(buf + len, buf_len - len,
"MSDUs locally dropped:filtered\t");
PRINT_TID_STATS(rx_pkt_drop_filter, "\t\t\t\t");
len += scnprintf(buf + len, buf_len - len,
"MSDUs queued for mac80211\t");
PRINT_TID_STATS(rx_pkt_queued_for_mac, "\t\t\t\t");
for (i = 0; i < ATH10K_PKT_RX_ERR_MAX; i++) {
len += scnprintf(buf + len, buf_len - len,
"MSDUs with error:%s\t", get_err_str(i));
PRINT_TID_STATS(rx_pkt_err[i], "\t\t\t\t");
}
len += scnprintf(buf + len, buf_len - len, "\n");
for (i = 0; i < ATH10K_AMPDU_SUBFRM_NUM_MAX; i++) {
len += scnprintf(buf + len, buf_len - len,
"A-MPDU num subframes %s\t",
get_num_ampdu_subfrm_str(i));
PRINT_TID_STATS(rx_pkt_ampdu[i], "\t\t\t\t");
}
len += scnprintf(buf + len, buf_len - len, "\n");
for (i = 0; i < ATH10K_AMSDU_SUBFRM_NUM_MAX; i++) {
len += scnprintf(buf + len, buf_len - len,
"A-MSDU num subframes %s\t\t",
get_num_amsdu_subfrm_str(i));
PRINT_TID_STATS(rx_pkt_amsdu[i], "\t\t\t\t");
}
spin_unlock_bh(&ar->data_lock);
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
kfree(buf);
mutex_unlock(&ar->conf_mutex);
return ret;
}
static const struct file_operations fops_tid_stats_dump = {
.open = simple_open,
.read = ath10k_dbg_sta_read_tid_stats,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir) struct ieee80211_sta *sta, struct dentry *dir)
{ {
...@@ -351,4 +635,6 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ...@@ -351,4 +635,6 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
debugfs_create_file("delba", 0200, dir, sta, &fops_delba); debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
debugfs_create_file("peer_debug_trigger", 0600, dir, sta, debugfs_create_file("peer_debug_trigger", 0600, dir, sta,
&fops_peer_debug_trigger); &fops_peer_debug_trigger);
debugfs_create_file("dump_tid_stats", 0400, dir, sta,
&fops_tid_stats_dump);
} }
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -1502,7 +1503,9 @@ static void ath10k_htt_rx_h_csum_offload(struct sk_buff *msdu) ...@@ -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, static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
struct sk_buff_head *amsdu, struct sk_buff_head *amsdu,
struct ieee80211_rx_status *status, struct ieee80211_rx_status *status,
bool fill_crypt_header) bool fill_crypt_header,
u8 *rx_hdr,
enum ath10k_pkt_rx_err *err)
{ {
struct sk_buff *first; struct sk_buff *first;
struct sk_buff *last; struct sk_buff *last;
...@@ -1538,6 +1541,9 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, ...@@ -1538,6 +1541,9 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
hdr = (void *)rxd->rx_hdr_status; hdr = (void *)rxd->rx_hdr_status;
memcpy(first_hdr, hdr, RX_HTT_HDR_STATUS_LEN); memcpy(first_hdr, hdr, RX_HTT_HDR_STATUS_LEN);
if (rx_hdr)
memcpy(rx_hdr, hdr, RX_HTT_HDR_STATUS_LEN);
/* Each A-MSDU subframe will use the original header as the base and be /* Each A-MSDU subframe will use the original header as the base and be
* reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl. * reported as a separate MSDU so strip the A-MSDU bit from QoS Ctl.
*/ */
...@@ -1581,6 +1587,17 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar, ...@@ -1581,6 +1587,17 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
if (has_tkip_err) if (has_tkip_err)
status->flag |= RX_FLAG_MMIC_ERROR; status->flag |= RX_FLAG_MMIC_ERROR;
if (err) {
if (has_fcs_err)
*err = ATH10K_PKT_RX_ERR_FCS;
else if (has_tkip_err)
*err = ATH10K_PKT_RX_ERR_TKIP;
else if (has_crypto_err)
*err = ATH10K_PKT_RX_ERR_CRYPT;
else if (has_peer_idx_invalid)
*err = ATH10K_PKT_RX_ERR_PEER_IDX_INVAL;
}
/* Firmware reports all necessary management frames via WMI already. /* Firmware reports all necessary management frames via WMI already.
* They are not reported to monitor interfaces at all so pass the ones * They are not reported to monitor interfaces at all so pass the ones
* coming via HTT to monitor interfaces instead. This simplifies * coming via HTT to monitor interfaces instead. This simplifies
...@@ -1651,11 +1668,13 @@ static void ath10k_htt_rx_h_enqueue(struct ath10k *ar, ...@@ -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; struct sk_buff *skb, *first;
int space; int space;
int total_len = 0; int total_len = 0;
int amsdu_len = skb_queue_len(amsdu);
/* TODO: Might could optimize this by using /* TODO: Might could optimize this by using
* skb_try_coalesce or similar method to * skb_try_coalesce or similar method to
...@@ -1691,11 +1710,16 @@ static int ath10k_unchain_msdu(struct sk_buff_head *amsdu) ...@@ -1691,11 +1710,16 @@ static int ath10k_unchain_msdu(struct sk_buff_head *amsdu)
} }
__skb_queue_head(amsdu, first); __skb_queue_head(amsdu, first);
*unchain_cnt += amsdu_len - 1;
return 0; return 0;
} }
static void ath10k_htt_rx_h_unchain(struct ath10k *ar, static void ath10k_htt_rx_h_unchain(struct ath10k *ar,
struct sk_buff_head *amsdu) struct sk_buff_head *amsdu,
unsigned long int *drop_cnt,
unsigned long int *unchain_cnt)
{ {
struct sk_buff *first; struct sk_buff *first;
struct htt_rx_desc *rxd; struct htt_rx_desc *rxd;
...@@ -1713,11 +1737,12 @@ static void ath10k_htt_rx_h_unchain(struct ath10k *ar, ...@@ -1713,11 +1737,12 @@ static void ath10k_htt_rx_h_unchain(struct ath10k *ar,
*/ */
if (decap != RX_MSDU_DECAP_RAW || if (decap != RX_MSDU_DECAP_RAW ||
skb_queue_len(amsdu) != 1 + rxd->frag_info.ring2_more_count) { skb_queue_len(amsdu) != 1 + rxd->frag_info.ring2_more_count) {
*drop_cnt += skb_queue_len(amsdu);
__skb_queue_purge(amsdu); __skb_queue_purge(amsdu);
return; return;
} }
ath10k_unchain_msdu(amsdu); ath10k_unchain_msdu(amsdu, unchain_cnt);
} }
static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar, static bool ath10k_htt_rx_amsdu_allowed(struct ath10k *ar,
...@@ -1743,7 +1768,8 @@ 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, static void ath10k_htt_rx_h_filter(struct ath10k *ar,
struct sk_buff_head *amsdu, struct sk_buff_head *amsdu,
struct ieee80211_rx_status *rx_status) struct ieee80211_rx_status *rx_status,
unsigned long int *drop_cnt)
{ {
if (skb_queue_empty(amsdu)) if (skb_queue_empty(amsdu))
return; return;
...@@ -1751,6 +1777,9 @@ static void ath10k_htt_rx_h_filter(struct ath10k *ar, ...@@ -1751,6 +1777,9 @@ static void ath10k_htt_rx_h_filter(struct ath10k *ar,
if (ath10k_htt_rx_amsdu_allowed(ar, amsdu, rx_status)) if (ath10k_htt_rx_amsdu_allowed(ar, amsdu, rx_status))
return; return;
if (drop_cnt)
*drop_cnt += skb_queue_len(amsdu);
__skb_queue_purge(amsdu); __skb_queue_purge(amsdu);
} }
...@@ -1760,6 +1789,12 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt) ...@@ -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 ieee80211_rx_status *rx_status = &htt->rx_status;
struct sk_buff_head amsdu; struct sk_buff_head amsdu;
int ret; int ret;
unsigned long int drop_cnt = 0;
unsigned long int unchain_cnt = 0;
unsigned long int drop_cnt_filter = 0;
unsigned long int msdus_to_queue, num_msdus;
enum ath10k_pkt_rx_err err = ATH10K_PKT_RX_ERR_MAX;
u8 first_hdr[RX_HTT_HDR_STATUS_LEN];
__skb_queue_head_init(&amsdu); __skb_queue_head_init(&amsdu);
...@@ -1781,16 +1816,23 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt) ...@@ -1781,16 +1816,23 @@ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt)
return ret; return ret;
} }
num_msdus = skb_queue_len(&amsdu);
ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff); ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff);
/* only for ret = 1 indicates chained msdus */ /* only for ret = 1 indicates chained msdus */
if (ret > 0) if (ret > 0)
ath10k_htt_rx_h_unchain(ar, &amsdu); ath10k_htt_rx_h_unchain(ar, &amsdu, &drop_cnt, &unchain_cnt);
ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); ath10k_htt_rx_h_filter(ar, &amsdu, rx_status, &drop_cnt_filter);
ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true); ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status, true, first_hdr, &err);
msdus_to_queue = skb_queue_len(&amsdu);
ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status); ath10k_htt_rx_h_enqueue(ar, &amsdu, rx_status);
ath10k_sta_update_rx_tid_stats(ar, first_hdr, num_msdus, err,
unchain_cnt, drop_cnt, drop_cnt_filter,
msdus_to_queue);
return 0; return 0;
} }
...@@ -1801,9 +1843,14 @@ static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt, ...@@ -1801,9 +1843,14 @@ static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
struct htt_rx_indication_mpdu_range *mpdu_ranges; struct htt_rx_indication_mpdu_range *mpdu_ranges;
int num_mpdu_ranges; int num_mpdu_ranges;
int i, mpdu_count = 0; int i, mpdu_count = 0;
u16 peer_id;
u8 tid;
num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1), num_mpdu_ranges = MS(__le32_to_cpu(rx->hdr.info1),
HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES); HTT_RX_INDICATION_INFO1_NUM_MPDU_RANGES);
peer_id = __le16_to_cpu(rx->hdr.peer_id);
tid = MS(rx->hdr.info0, HTT_RX_INDICATION_INFO0_EXT_TID);
mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx); mpdu_ranges = htt_rx_ind_get_mpdu_ranges(rx);
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ", ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx ind: ",
...@@ -1815,6 +1862,9 @@ static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt, ...@@ -1815,6 +1862,9 @@ static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt,
mpdu_count += mpdu_ranges[i].mpdu_count; mpdu_count += mpdu_ranges[i].mpdu_count;
atomic_add(mpdu_count, &htt->num_mpdus_ready); atomic_add(mpdu_count, &htt->num_mpdus_ready);
ath10k_sta_update_rx_tid_stats_ampdu(ar, peer_id, tid, mpdu_ranges,
num_mpdu_ranges);
} }
static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar, static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar,
...@@ -2124,8 +2174,9 @@ static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) ...@@ -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. * should still give an idea about rx rate to the user.
*/ */
ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id); ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id);
ath10k_htt_rx_h_filter(ar, &amsdu, status); ath10k_htt_rx_h_filter(ar, &amsdu, status, NULL);
ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false); ath10k_htt_rx_h_mpdu(ar, &amsdu, status, false, NULL,
NULL);
ath10k_htt_rx_h_enqueue(ar, &amsdu, status); ath10k_htt_rx_h_enqueue(ar, &amsdu, status);
break; break;
case -EAGAIN: case -EAGAIN:
......
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -3808,6 +3809,7 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) ...@@ -3808,6 +3809,7 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
{ {
struct ath10k *ar = container_of(work, struct ath10k, wmi_mgmt_tx_work); struct ath10k *ar = container_of(work, struct ath10k, wmi_mgmt_tx_work);
struct sk_buff *skb; struct sk_buff *skb;
dma_addr_t paddr;
int ret; int ret;
for (;;) { for (;;) {
...@@ -3815,11 +3817,27 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work) ...@@ -3815,11 +3817,27 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)
if (!skb) if (!skb)
break; break;
ret = ath10k_wmi_mgmt_tx(ar, skb); if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF,
if (ret) { ar->running_fw->fw_file.fw_features)) {
ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n", paddr = dma_map_single(ar->dev, skb->data,
ret); skb->len, DMA_TO_DEVICE);
ieee80211_free_txskb(ar->hw, skb); if (!paddr)
continue;
ret = ath10k_wmi_mgmt_tx_send(ar, skb, paddr);
if (ret) {
ath10k_warn(ar, "failed to transmit management frame by ref via WMI: %d\n",
ret);
dma_unmap_single(ar->dev, paddr, skb->len,
DMA_FROM_DEVICE);
ieee80211_free_txskb(ar->hw, skb);
}
} else {
ret = ath10k_wmi_mgmt_tx(ar, skb);
if (ret) {
ath10k_warn(ar, "failed to transmit management frame via WMI: %d\n",
ret);
ieee80211_free_txskb(ar->hw, skb);
}
} }
} }
} }
...@@ -7085,10 +7103,20 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw, ...@@ -7085,10 +7103,20 @@ static void ath10k_sta_rc_update(struct ieee80211_hw *hw,
{ {
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv; struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
struct ath10k_vif *arvif = (void *)vif->drv_priv;
struct ath10k_peer *peer;
u32 bw, smps; u32 bw, smps;
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
peer = ath10k_peer_find(ar, arvif->vdev_id, sta->addr);
if (!peer) {
spin_unlock_bh(&ar->data_lock);
ath10k_warn(ar, "mac sta rc update failed to find peer %pM on vdev %i\n",
sta->addr, arvif->vdev_id);
return;
}
ath10k_dbg(ar, ATH10K_DBG_MAC, ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n", "mac sta rc update for %pM changed %08x bw %d nss %d smps %d\n",
sta->addr, changed, sta->bandwidth, sta->rx_nss, sta->addr, changed, sta->bandwidth, sta->rx_nss,
......
...@@ -2221,7 +2221,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar) ...@@ -2221,7 +2221,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
} }
break; break;
case QCA9377_1_0_DEVICE_ID: case QCA9377_1_0_DEVICE_ID:
return 4; return 9;
} }
ath10k_warn(ar, "unknown number of banks, assuming 1\n"); ath10k_warn(ar, "unknown number of banks, assuming 1\n");
......
...@@ -152,10 +152,9 @@ TRACE_EVENT(ath10k_log_dbg_dump, ...@@ -152,10 +152,9 @@ TRACE_EVENT(ath10k_log_dbg_dump,
); );
TRACE_EVENT(ath10k_wmi_cmd, TRACE_EVENT(ath10k_wmi_cmd,
TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len, TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len),
int ret),
TP_ARGS(ar, id, buf, buf_len, ret), TP_ARGS(ar, id, buf, buf_len),
TP_STRUCT__entry( TP_STRUCT__entry(
__string(device, dev_name(ar->dev)) __string(device, dev_name(ar->dev))
...@@ -163,7 +162,6 @@ TRACE_EVENT(ath10k_wmi_cmd, ...@@ -163,7 +162,6 @@ TRACE_EVENT(ath10k_wmi_cmd,
__field(unsigned int, id) __field(unsigned int, id)
__field(size_t, buf_len) __field(size_t, buf_len)
__dynamic_array(u8, buf, buf_len) __dynamic_array(u8, buf, buf_len)
__field(int, ret)
), ),
TP_fast_assign( TP_fast_assign(
...@@ -171,17 +169,15 @@ TRACE_EVENT(ath10k_wmi_cmd, ...@@ -171,17 +169,15 @@ TRACE_EVENT(ath10k_wmi_cmd,
__assign_str(driver, dev_driver_string(ar->dev)); __assign_str(driver, dev_driver_string(ar->dev));
__entry->id = id; __entry->id = id;
__entry->buf_len = buf_len; __entry->buf_len = buf_len;
__entry->ret = ret;
memcpy(__get_dynamic_array(buf), buf, buf_len); memcpy(__get_dynamic_array(buf), buf, buf_len);
), ),
TP_printk( TP_printk(
"%s %s id %d len %zu ret %d", "%s %s id %d len %zu",
__get_str(driver), __get_str(driver),
__get_str(device), __get_str(device),
__entry->id, __entry->id,
__entry->buf_len, __entry->buf_len
__entry->ret
) )
); );
......
...@@ -102,11 +102,6 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, ...@@ -102,11 +102,6 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
memset(&info->status, 0, sizeof(info->status)); memset(&info->status, 0, sizeof(info->status));
trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id); trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id);
if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) {
ieee80211_free_txskb(htt->ar->hw, msdu);
return 0;
}
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
info->flags |= IEEE80211_TX_STAT_ACK; info->flags |= IEEE80211_TX_STAT_ACK;
...@@ -117,6 +112,13 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt, ...@@ -117,6 +112,13 @@ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
(info->flags & IEEE80211_TX_CTL_NO_ACK)) (info->flags & IEEE80211_TX_CTL_NO_ACK))
info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) {
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED;
else
info->flags &= ~IEEE80211_TX_STAT_ACK;
}
ieee80211_tx_status(htt->ar->hw, msdu); ieee80211_tx_status(htt->ar->hw, msdu);
/* we do not own the msdu anymore */ /* we do not own the msdu anymore */
......
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -125,6 +126,9 @@ struct wmi_ops { ...@@ -125,6 +126,9 @@ struct wmi_ops {
enum wmi_force_fw_hang_type type, enum wmi_force_fw_hang_type type,
u32 delay_ms); u32 delay_ms);
struct sk_buff *(*gen_mgmt_tx)(struct ath10k *ar, struct sk_buff *skb); struct sk_buff *(*gen_mgmt_tx)(struct ath10k *ar, struct sk_buff *skb);
struct sk_buff *(*gen_mgmt_tx_send)(struct ath10k *ar,
struct sk_buff *skb,
dma_addr_t paddr);
struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u64 module_enable, struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u64 module_enable,
u32 log_level); u32 log_level);
struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter); struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter);
...@@ -197,6 +201,9 @@ struct wmi_ops { ...@@ -197,6 +201,9 @@ struct wmi_ops {
(struct ath10k *ar, (struct ath10k *ar,
enum wmi_bss_survey_req_type type); enum wmi_bss_survey_req_type type);
struct sk_buff *(*gen_echo)(struct ath10k *ar, u32 value); struct sk_buff *(*gen_echo)(struct ath10k *ar, u32 value);
struct sk_buff *(*gen_pdev_get_tpc_table_cmdid)(struct ath10k *ar,
u32 param);
}; };
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
...@@ -371,13 +378,34 @@ ath10k_wmi_get_txbf_conf_scheme(struct ath10k *ar) ...@@ -371,13 +378,34 @@ ath10k_wmi_get_txbf_conf_scheme(struct ath10k *ar)
return ar->wmi.ops->get_txbf_conf_scheme(ar); return ar->wmi.ops->get_txbf_conf_scheme(ar);
} }
static inline int
ath10k_wmi_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
dma_addr_t paddr)
{
struct sk_buff *skb;
int ret;
if (!ar->wmi.ops->gen_mgmt_tx_send)
return -EOPNOTSUPP;
skb = ar->wmi.ops->gen_mgmt_tx_send(ar, msdu, paddr);
if (IS_ERR(skb))
return PTR_ERR(skb);
ret = ath10k_wmi_cmd_send(ar, skb,
ar->wmi.cmd->mgmt_tx_send_cmdid);
if (ret)
return ret;
return 0;
}
static inline int static inline int
ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
{ {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
struct sk_buff *skb; struct sk_buff *skb;
int ret; int ret;
u32 mgmt_tx_cmdid;
if (!ar->wmi.ops->gen_mgmt_tx) if (!ar->wmi.ops->gen_mgmt_tx)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -386,13 +414,8 @@ ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) ...@@ -386,13 +414,8 @@ ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
if (IS_ERR(skb)) if (IS_ERR(skb))
return PTR_ERR(skb); return PTR_ERR(skb);
if (test_bit(ATH10K_FW_FEATURE_MGMT_TX_BY_REF, ret = ath10k_wmi_cmd_send(ar, skb,
ar->running_fw->fw_file.fw_features)) ar->wmi.cmd->mgmt_tx_cmdid);
mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_send_cmdid;
else
mgmt_tx_cmdid = ar->wmi.cmd->mgmt_tx_cmdid;
ret = ath10k_wmi_cmd_send(ar, skb, mgmt_tx_cmdid);
if (ret) if (ret)
return ret; return ret;
...@@ -1425,4 +1448,21 @@ ath10k_wmi_echo(struct ath10k *ar, u32 value) ...@@ -1425,4 +1448,21 @@ ath10k_wmi_echo(struct ath10k *ar, u32 value)
return ath10k_wmi_cmd_send(ar, skb, wmi->cmd->echo_cmdid); return ath10k_wmi_cmd_send(ar, skb, wmi->cmd->echo_cmdid);
} }
static inline int
ath10k_wmi_pdev_get_tpc_table_cmdid(struct ath10k *ar, u32 param)
{
struct sk_buff *skb;
if (!ar->wmi.ops->gen_pdev_get_tpc_table_cmdid)
return -EOPNOTSUPP;
skb = ar->wmi.ops->gen_pdev_get_tpc_table_cmdid(ar, param);
if (IS_ERR(skb))
return PTR_ERR(skb);
return ath10k_wmi_cmd_send(ar, skb,
ar->wmi.cmd->pdev_get_tpc_table_cmdid);
}
#endif #endif
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -2484,19 +2485,19 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask) ...@@ -2484,19 +2485,19 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
} }
static struct sk_buff * static struct sk_buff *
ath10k_wmi_tlv_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,
dma_addr_t paddr)
{ {
struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu); struct ath10k_skb_cb *cb = ATH10K_SKB_CB(msdu);
struct wmi_tlv_mgmt_tx_cmd *cmd; struct wmi_tlv_mgmt_tx_cmd *cmd;
struct wmi_tlv *tlv;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct ath10k_vif *arvif;
u32 buf_len = msdu->len;
struct wmi_tlv *tlv;
struct sk_buff *skb; struct sk_buff *skb;
u32 vdev_id;
void *ptr; void *ptr;
int len; int len;
u32 buf_len = msdu->len;
struct ath10k_vif *arvif;
dma_addr_t mgmt_frame_dma;
u32 vdev_id;
if (!cb->vif) if (!cb->vif)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
...@@ -2537,12 +2538,7 @@ ath10k_wmi_tlv_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu) ...@@ -2537,12 +2538,7 @@ ath10k_wmi_tlv_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
cmd->chanfreq = 0; cmd->chanfreq = 0;
cmd->buf_len = __cpu_to_le32(buf_len); cmd->buf_len = __cpu_to_le32(buf_len);
cmd->frame_len = __cpu_to_le32(msdu->len); cmd->frame_len = __cpu_to_le32(msdu->len);
mgmt_frame_dma = dma_map_single(arvif->ar->dev, msdu->data, cmd->paddr = __cpu_to_le64(paddr);
msdu->len, DMA_TO_DEVICE);
if (!mgmt_frame_dma)
return ERR_PTR(-ENOMEM);
cmd->paddr = __cpu_to_le64(mgmt_frame_dma);
ptr += sizeof(*tlv); ptr += sizeof(*tlv);
ptr += sizeof(*cmd); ptr += sizeof(*cmd);
...@@ -3701,7 +3697,7 @@ static const struct wmi_ops wmi_tlv_ops = { ...@@ -3701,7 +3697,7 @@ static const struct wmi_ops wmi_tlv_ops = {
.gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats, .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
.gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang, .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
/* .gen_mgmt_tx = not implemented; HTT is used */ /* .gen_mgmt_tx = not implemented; HTT is used */
.gen_mgmt_tx = ath10k_wmi_tlv_op_gen_mgmt_tx, .gen_mgmt_tx_send = ath10k_wmi_tlv_op_gen_mgmt_tx_send,
.gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg, .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
.gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
.gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable, .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
......
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -196,6 +197,7 @@ static struct wmi_cmd_map wmi_cmd_map = { ...@@ -196,6 +197,7 @@ static struct wmi_cmd_map wmi_cmd_map = {
.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
}; };
/* 10.X WMI cmd track */ /* 10.X WMI cmd track */
...@@ -362,6 +364,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { ...@@ -362,6 +364,7 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
.mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED,
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
}; };
/* 10.2.4 WMI cmd track */ /* 10.2.4 WMI cmd track */
...@@ -528,6 +531,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = { ...@@ -528,6 +531,7 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = {
.set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_bss_chan_info_request_cmdid = .pdev_bss_chan_info_request_cmdid =
WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID, WMI_10_2_PDEV_BSS_CHAN_INFO_REQUEST_CMDID,
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
}; };
/* 10.4 WMI cmd track */ /* 10.4 WMI cmd track */
...@@ -1480,6 +1484,7 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { ...@@ -1480,6 +1484,7 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = {
.pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED,
.pdev_get_tpc_table_cmdid = WMI_CMD_UNSUPPORTED,
}; };
static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = { static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = {
...@@ -1742,8 +1747,8 @@ int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb, ...@@ -1742,8 +1747,8 @@ int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
cmd_hdr->cmd_id = __cpu_to_le32(cmd); cmd_hdr->cmd_id = __cpu_to_le32(cmd);
memset(skb_cb, 0, sizeof(*skb_cb)); memset(skb_cb, 0, sizeof(*skb_cb));
trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len);
ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb); ret = ath10k_htc_send(&ar->htc, ar->wmi.eid, skb);
trace_ath10k_wmi_cmd(ar, cmd_id, skb->data, skb->len, ret);
if (ret) if (ret)
goto err_pull; goto err_pull;
...@@ -4313,19 +4318,11 @@ static void ath10k_tpc_config_disp_tables(struct ath10k *ar, ...@@ -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; u32 i, j, pream_idx;
u8 rate_code[WMI_TPC_RATE_MAX], rate_idx; u8 rate_idx;
u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
struct wmi_pdev_tpc_config_event *ev;
struct ath10k_tpc_stats *tpc_stats;
ev = (struct wmi_pdev_tpc_config_event *)skb->data;
tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
if (!tpc_stats)
return;
/* Create the rate code table based on the chains supported */ /* Create the rate code table based on the chains supported */
rate_idx = 0; rate_idx = 0;
...@@ -4349,8 +4346,6 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) ...@@ -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_table[pream_idx] = rate_idx;
pream_idx++; pream_idx++;
num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
/* Fill HT20 rate code */ /* Fill HT20 rate code */
for (i = 0; i < num_tx_chain; i++) { for (i = 0; i < num_tx_chain; i++) {
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
...@@ -4374,7 +4369,7 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) ...@@ -4374,7 +4369,7 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
pream_idx++; pream_idx++;
/* Fill VHT20 rate code */ /* Fill VHT20 rate code */
for (i = 0; i < __le32_to_cpu(ev->num_tx_chain); i++) { for (i = 0; i < num_tx_chain; i++) {
for (j = 0; j < 10; j++) { for (j = 0; j < 10; j++) {
rate_code[rate_idx] = rate_code[rate_idx] =
ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT); ATH10K_HW_RATECODE(j, i, WMI_RATE_PREAMBLE_VHT);
...@@ -4418,6 +4413,26 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) ...@@ -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); ATH10K_HW_RATECODE(0, 0, WMI_RATE_PREAMBLE_OFDM);
pream_table[pream_idx] = ATH10K_TPC_PREAM_TABLE_END; pream_table[pream_idx] = ATH10K_TPC_PREAM_TABLE_END;
}
void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
{
u32 num_tx_chain;
u8 rate_code[WMI_TPC_RATE_MAX];
u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
struct wmi_pdev_tpc_config_event *ev;
struct ath10k_tpc_stats *tpc_stats;
ev = (struct wmi_pdev_tpc_config_event *)skb->data;
tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
if (!tpc_stats)
return;
num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table,
num_tx_chain);
tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq); tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq);
tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode); tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode);
...@@ -4457,6 +4472,246 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb) ...@@ -4457,6 +4472,246 @@ void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
__le32_to_cpu(ev->rate_max)); __le32_to_cpu(ev->rate_max));
} }
static u8
ath10k_wmi_tpc_final_get_rate(struct ath10k *ar,
struct wmi_pdev_tpc_final_table_event *ev,
u32 rate_idx, u32 num_chains,
u32 rate_code, u8 type, u32 pream_idx)
{
u8 tpc, num_streams, preamble, ch, stm_idx;
s8 pow_agcdd, pow_agstbc, pow_agtxbf;
int pream;
num_streams = ATH10K_HW_NSS(rate_code);
preamble = ATH10K_HW_PREAMBLE(rate_code);
ch = num_chains - 1;
stm_idx = num_streams - 1;
pream = -1;
if (__le32_to_cpu(ev->chan_freq) <= 2483) {
switch (pream_idx) {
case WMI_TPC_PREAM_2GHZ_CCK:
pream = 0;
break;
case WMI_TPC_PREAM_2GHZ_OFDM:
pream = 1;
break;
case WMI_TPC_PREAM_2GHZ_HT20:
case WMI_TPC_PREAM_2GHZ_VHT20:
pream = 2;
break;
case WMI_TPC_PREAM_2GHZ_HT40:
case WMI_TPC_PREAM_2GHZ_VHT40:
pream = 3;
break;
case WMI_TPC_PREAM_2GHZ_VHT80:
pream = 4;
break;
default:
pream = -1;
break;
}
}
if (__le32_to_cpu(ev->chan_freq) >= 5180) {
switch (pream_idx) {
case WMI_TPC_PREAM_5GHZ_OFDM:
pream = 0;
break;
case WMI_TPC_PREAM_5GHZ_HT20:
case WMI_TPC_PREAM_5GHZ_VHT20:
pream = 1;
break;
case WMI_TPC_PREAM_5GHZ_HT40:
case WMI_TPC_PREAM_5GHZ_VHT40:
pream = 2;
break;
case WMI_TPC_PREAM_5GHZ_VHT80:
pream = 3;
break;
case WMI_TPC_PREAM_5GHZ_HTCUP:
pream = 4;
break;
default:
pream = -1;
break;
}
}
if (pream == 4)
tpc = min_t(u8, ev->rates_array[rate_idx],
ev->max_reg_allow_pow[ch]);
else
tpc = min_t(u8, min_t(u8, ev->rates_array[rate_idx],
ev->max_reg_allow_pow[ch]),
ev->ctl_power_table[0][pream][stm_idx]);
if (__le32_to_cpu(ev->num_tx_chain) <= 1)
goto out;
if (preamble == WMI_RATE_PREAMBLE_CCK)
goto out;
if (num_chains <= num_streams)
goto out;
switch (type) {
case WMI_TPC_TABLE_TYPE_STBC:
pow_agstbc = ev->max_reg_allow_pow_agstbc[ch - 1][stm_idx];
if (pream == 4)
tpc = min_t(u8, tpc, pow_agstbc);
else
tpc = min_t(u8, min_t(u8, tpc, pow_agstbc),
ev->ctl_power_table[0][pream][stm_idx]);
break;
case WMI_TPC_TABLE_TYPE_TXBF:
pow_agtxbf = ev->max_reg_allow_pow_agtxbf[ch - 1][stm_idx];
if (pream == 4)
tpc = min_t(u8, tpc, pow_agtxbf);
else
tpc = min_t(u8, min_t(u8, tpc, pow_agtxbf),
ev->ctl_power_table[1][pream][stm_idx]);
break;
case WMI_TPC_TABLE_TYPE_CDD:
pow_agcdd = ev->max_reg_allow_pow_agcdd[ch - 1][stm_idx];
if (pream == 4)
tpc = min_t(u8, tpc, pow_agcdd);
else
tpc = min_t(u8, min_t(u8, tpc, pow_agcdd),
ev->ctl_power_table[0][pream][stm_idx]);
break;
default:
ath10k_warn(ar, "unknown wmi tpc final table type: %d\n", type);
tpc = 0;
break;
}
out:
return tpc;
}
static void
ath10k_wmi_tpc_stats_final_disp_tables(struct ath10k *ar,
struct wmi_pdev_tpc_final_table_event *ev,
struct ath10k_tpc_stats_final *tpc_stats,
u8 *rate_code, u16 *pream_table, u8 type)
{
u32 i, j, pream_idx, flags;
u8 tpc[WMI_TPC_TX_N_CHAIN];
char tpc_value[WMI_TPC_TX_N_CHAIN * WMI_TPC_BUF_SIZE];
char buff[WMI_TPC_BUF_SIZE];
flags = __le32_to_cpu(ev->flags);
switch (type) {
case WMI_TPC_TABLE_TYPE_CDD:
if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_CDD)) {
ath10k_dbg(ar, ATH10K_DBG_WMI, "CDD not supported\n");
tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
return;
}
break;
case WMI_TPC_TABLE_TYPE_STBC:
if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_STBC)) {
ath10k_dbg(ar, ATH10K_DBG_WMI, "STBC not supported\n");
tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
return;
}
break;
case WMI_TPC_TABLE_TYPE_TXBF:
if (!(flags & WMI_TPC_CONFIG_EVENT_FLAG_TABLE_TXBF)) {
ath10k_dbg(ar, ATH10K_DBG_WMI, "TXBF not supported\n");
tpc_stats->flag[type] = ATH10K_TPC_TABLE_TYPE_FLAG;
return;
}
break;
default:
ath10k_dbg(ar, ATH10K_DBG_WMI,
"invalid table type in wmi tpc event: %d\n", type);
return;
}
pream_idx = 0;
for (i = 0; i < __le32_to_cpu(ev->rate_max); i++) {
memset(tpc_value, 0, sizeof(tpc_value));
memset(buff, 0, sizeof(buff));
if (i == pream_table[pream_idx])
pream_idx++;
for (j = 0; j < WMI_TPC_TX_N_CHAIN; j++) {
if (j >= __le32_to_cpu(ev->num_tx_chain))
break;
tpc[j] = ath10k_wmi_tpc_final_get_rate(ar, ev, i, j + 1,
rate_code[i],
type, pream_idx);
snprintf(buff, sizeof(buff), "%8d ", tpc[j]);
strncat(tpc_value, buff, strlen(buff));
}
tpc_stats->tpc_table_final[type].pream_idx[i] = pream_idx;
tpc_stats->tpc_table_final[type].rate_code[i] = rate_code[i];
memcpy(tpc_stats->tpc_table_final[type].tpc_value[i],
tpc_value, sizeof(tpc_value));
}
}
void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb)
{
u32 num_tx_chain;
u8 rate_code[WMI_TPC_FINAL_RATE_MAX];
u16 pream_table[WMI_TPC_PREAM_TABLE_MAX];
struct wmi_pdev_tpc_final_table_event *ev;
struct ath10k_tpc_stats_final *tpc_stats;
ev = (struct wmi_pdev_tpc_final_table_event *)skb->data;
tpc_stats = kzalloc(sizeof(*tpc_stats), GFP_ATOMIC);
if (!tpc_stats)
return;
num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
ath10k_wmi_tpc_config_get_rate_code(rate_code, pream_table,
num_tx_chain);
tpc_stats->chan_freq = __le32_to_cpu(ev->chan_freq);
tpc_stats->phy_mode = __le32_to_cpu(ev->phy_mode);
tpc_stats->ctl = __le32_to_cpu(ev->ctl);
tpc_stats->reg_domain = __le32_to_cpu(ev->reg_domain);
tpc_stats->twice_antenna_gain = a_sle32_to_cpu(ev->twice_antenna_gain);
tpc_stats->twice_antenna_reduction =
__le32_to_cpu(ev->twice_antenna_reduction);
tpc_stats->power_limit = __le32_to_cpu(ev->power_limit);
tpc_stats->twice_max_rd_power = __le32_to_cpu(ev->twice_max_rd_power);
tpc_stats->num_tx_chain = __le32_to_cpu(ev->num_tx_chain);
tpc_stats->rate_max = __le32_to_cpu(ev->rate_max);
ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
rate_code, pream_table,
WMI_TPC_TABLE_TYPE_CDD);
ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
rate_code, pream_table,
WMI_TPC_TABLE_TYPE_STBC);
ath10k_wmi_tpc_stats_final_disp_tables(ar, ev, tpc_stats,
rate_code, pream_table,
WMI_TPC_TABLE_TYPE_TXBF);
ath10k_debug_tpc_stats_final_process(ar, tpc_stats);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi event tpc final table channel %d mode %d ctl %d regd %d gain %d %d limit %d max_power %d tx_chanins %d rates %d\n",
__le32_to_cpu(ev->chan_freq),
__le32_to_cpu(ev->phy_mode),
__le32_to_cpu(ev->ctl),
__le32_to_cpu(ev->reg_domain),
a_sle32_to_cpu(ev->twice_antenna_gain),
__le32_to_cpu(ev->twice_antenna_reduction),
__le32_to_cpu(ev->power_limit),
__le32_to_cpu(ev->twice_max_rd_power) / 2,
__le32_to_cpu(ev->num_tx_chain),
__le32_to_cpu(ev->rate_max));
}
static void static void
ath10k_wmi_handle_tdls_peer_event(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_handle_tdls_peer_event(struct ath10k *ar, struct sk_buff *skb)
{ {
...@@ -5549,6 +5804,9 @@ static void ath10k_wmi_10_4_op_rx(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: case WMI_10_4_TDLS_PEER_EVENTID:
ath10k_wmi_handle_tdls_peer_event(ar, skb); ath10k_wmi_handle_tdls_peer_event(ar, skb);
break; break;
case WMI_10_4_PDEV_TPC_TABLE_EVENTID:
ath10k_wmi_event_tpc_final_table(ar, skb);
break;
default: default:
ath10k_warn(ar, "Unknown eventid: %d\n", id); ath10k_warn(ar, "Unknown eventid: %d\n", id);
break; break;
...@@ -7989,6 +8247,24 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp) ...@@ -7989,6 +8247,24 @@ static u32 ath10k_wmi_prepare_peer_qos(u8 uapsd_queues, u8 sp)
return peer_qos; return peer_qos;
} }
static struct sk_buff *
ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid(struct ath10k *ar, u32 param)
{
struct wmi_pdev_get_tpc_table_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
return ERR_PTR(-ENOMEM);
cmd = (struct wmi_pdev_get_tpc_table_cmd *)skb->data;
cmd->param = __cpu_to_le32(param);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi pdev get tpc table param:%d\n", param);
return skb;
}
static struct sk_buff * static struct sk_buff *
ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar, ath10k_wmi_10_4_gen_tdls_peer_update(struct ath10k *ar,
const struct wmi_tdls_peer_update_cmd_arg *arg, const struct wmi_tdls_peer_update_cmd_arg *arg,
...@@ -8430,6 +8706,8 @@ static const struct wmi_ops wmi_10_4_ops = { ...@@ -8430,6 +8706,8 @@ static const struct wmi_ops wmi_10_4_ops = {
.ext_resource_config = ath10k_wmi_10_4_ext_resource_config, .ext_resource_config = ath10k_wmi_10_4_ext_resource_config,
.gen_update_fw_tdls_state = ath10k_wmi_10_4_gen_update_fw_tdls_state, .gen_update_fw_tdls_state = ath10k_wmi_10_4_gen_update_fw_tdls_state,
.gen_tdls_peer_update = ath10k_wmi_10_4_gen_tdls_peer_update, .gen_tdls_peer_update = ath10k_wmi_10_4_gen_tdls_peer_update,
.gen_pdev_get_tpc_table_cmdid =
ath10k_wmi_10_4_op_gen_pdev_get_tpc_table_cmdid,
/* shared with 10.2 */ /* shared with 10.2 */
.pull_echo_ev = ath10k_wmi_op_pull_echo_ev, .pull_echo_ev = ath10k_wmi_op_pull_echo_ev,
......
/* /*
* Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2005-2011 Atheros Communications Inc.
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -197,6 +198,9 @@ enum wmi_service { ...@@ -197,6 +198,9 @@ enum wmi_service {
WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
WMI_SERVICE_MGMT_TX_WMI, WMI_SERVICE_MGMT_TX_WMI,
WMI_SERVICE_TDLS_WIDER_BANDWIDTH, WMI_SERVICE_TDLS_WIDER_BANDWIDTH,
WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
WMI_SERVICE_HOST_DFS_CHECK_SUPPORT,
WMI_SERVICE_TPC_STATS_FINAL,
/* keep last */ /* keep last */
WMI_SERVICE_MAX, WMI_SERVICE_MAX,
...@@ -339,6 +343,9 @@ enum wmi_10_4_service { ...@@ -339,6 +343,9 @@ enum wmi_10_4_service {
WMI_10_4_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE, WMI_10_4_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE,
WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY, WMI_10_4_SERVICE_TDLS_EXPLICIT_MODE_ONLY,
WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH, WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH,
WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT,
WMI_10_4_SERVICE_TPC_STATS_FINAL,
}; };
static inline char *wmi_service_name(int service_id) static inline char *wmi_service_name(int service_id)
...@@ -448,6 +455,9 @@ static inline char *wmi_service_name(int service_id) ...@@ -448,6 +455,9 @@ static inline char *wmi_service_name(int service_id)
SVCSTR(WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE); SVCSTR(WMI_SERVICE_TDLS_CONN_TRACKER_IN_HOST_MODE);
SVCSTR(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY); SVCSTR(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY);
SVCSTR(WMI_SERVICE_TDLS_WIDER_BANDWIDTH); SVCSTR(WMI_SERVICE_TDLS_WIDER_BANDWIDTH);
SVCSTR(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS);
SVCSTR(WMI_SERVICE_HOST_DFS_CHECK_SUPPORT);
SVCSTR(WMI_SERVICE_TPC_STATS_FINAL);
default: default:
return NULL; return NULL;
} }
...@@ -746,6 +756,12 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, ...@@ -746,6 +756,12 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, len); WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, len);
SVCMAP(WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH, SVCMAP(WMI_10_4_SERVICE_TDLS_WIDER_BANDWIDTH,
WMI_SERVICE_TDLS_WIDER_BANDWIDTH, len); WMI_SERVICE_TDLS_WIDER_BANDWIDTH, len);
SVCMAP(WMI_10_4_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS,
WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, len);
SVCMAP(WMI_10_4_SERVICE_HOST_DFS_CHECK_SUPPORT,
WMI_SERVICE_HOST_DFS_CHECK_SUPPORT, len);
SVCMAP(WMI_10_4_SERVICE_TPC_STATS_FINAL,
WMI_SERVICE_TPC_STATS_FINAL, len);
} }
#undef SVCMAP #undef SVCMAP
...@@ -3993,10 +4009,12 @@ struct wmi_pdev_get_tpc_config_cmd { ...@@ -3993,10 +4009,12 @@ struct wmi_pdev_get_tpc_config_cmd {
#define WMI_TPC_CONFIG_PARAM 1 #define WMI_TPC_CONFIG_PARAM 1
#define WMI_TPC_RATE_MAX 160 #define WMI_TPC_RATE_MAX 160
#define WMI_TPC_FINAL_RATE_MAX 240
#define WMI_TPC_TX_N_CHAIN 4 #define WMI_TPC_TX_N_CHAIN 4
#define WMI_TPC_PREAM_TABLE_MAX 10 #define WMI_TPC_PREAM_TABLE_MAX 10
#define WMI_TPC_FLAG 3 #define WMI_TPC_FLAG 3
#define WMI_TPC_BUF_SIZE 10 #define WMI_TPC_BUF_SIZE 10
#define WMI_TPC_BEAMFORMING 2
enum wmi_tpc_table_type { enum wmi_tpc_table_type {
WMI_TPC_TABLE_TYPE_CDD = 0, WMI_TPC_TABLE_TYPE_CDD = 0,
...@@ -4039,6 +4057,51 @@ enum wmi_tp_scale { ...@@ -4039,6 +4057,51 @@ enum wmi_tp_scale {
WMI_TP_SCALE_SIZE = 5, /* max num of enum */ WMI_TP_SCALE_SIZE = 5, /* max num of enum */
}; };
struct wmi_pdev_tpc_final_table_event {
__le32 reg_domain;
__le32 chan_freq;
__le32 phy_mode;
__le32 twice_antenna_reduction;
__le32 twice_max_rd_power;
a_sle32 twice_antenna_gain;
__le32 power_limit;
__le32 rate_max;
__le32 num_tx_chain;
__le32 ctl;
__le32 flags;
s8 max_reg_allow_pow[WMI_TPC_TX_N_CHAIN];
s8 max_reg_allow_pow_agcdd[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN];
s8 max_reg_allow_pow_agstbc[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN];
s8 max_reg_allow_pow_agtxbf[WMI_TPC_TX_N_CHAIN][WMI_TPC_TX_N_CHAIN];
u8 rates_array[WMI_TPC_FINAL_RATE_MAX];
u8 ctl_power_table[WMI_TPC_BEAMFORMING][WMI_TPC_TX_N_CHAIN]
[WMI_TPC_TX_N_CHAIN];
} __packed;
struct wmi_pdev_get_tpc_table_cmd {
__le32 param;
} __packed;
enum wmi_tpc_pream_2ghz {
WMI_TPC_PREAM_2GHZ_CCK = 0,
WMI_TPC_PREAM_2GHZ_OFDM,
WMI_TPC_PREAM_2GHZ_HT20,
WMI_TPC_PREAM_2GHZ_HT40,
WMI_TPC_PREAM_2GHZ_VHT20,
WMI_TPC_PREAM_2GHZ_VHT40,
WMI_TPC_PREAM_2GHZ_VHT80,
};
enum wmi_tpc_pream_5ghz {
WMI_TPC_PREAM_5GHZ_OFDM = 1,
WMI_TPC_PREAM_5GHZ_HT20,
WMI_TPC_PREAM_5GHZ_HT40,
WMI_TPC_PREAM_5GHZ_VHT20,
WMI_TPC_PREAM_5GHZ_VHT40,
WMI_TPC_PREAM_5GHZ_VHT80,
WMI_TPC_PREAM_5GHZ_HTCUP,
};
struct wmi_pdev_chanlist_update_event { struct wmi_pdev_chanlist_update_event {
/* number of channels */ /* number of channels */
__le32 num_chan; __le32 num_chan;
...@@ -6979,5 +7042,8 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar, ...@@ -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, int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar,
enum wmi_vdev_subtype subtype); enum wmi_vdev_subtype subtype);
int ath10k_wmi_barrier(struct ath10k *ar); int ath10k_wmi_barrier(struct ath10k *ar);
void ath10k_wmi_tpc_config_get_rate_code(u8 *rate_code, u16 *pream_table,
u32 num_tx_chain);
void ath10k_wmi_event_tpc_final_table(struct ath10k *ar, struct sk_buff *skb);
#endif /* _WMI_H_ */ #endif /* _WMI_H_ */
...@@ -327,8 +327,6 @@ ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) ...@@ -327,8 +327,6 @@ ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num); AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
tq = &ah->ah_txq[queue];
/* Skip if queue inactive or if we are on AR5210 /* Skip if queue inactive or if we are on AR5210
* that doesn't have QCU/DCU */ * that doesn't have QCU/DCU */
if ((ah->ah_version == AR5K_AR5210) || if ((ah->ah_version == AR5K_AR5210) ||
......
...@@ -88,7 +88,7 @@ static const struct ieee80211_channel ath9k_5ghz_chantable[] = { ...@@ -88,7 +88,7 @@ static const struct ieee80211_channel ath9k_5ghz_chantable[] = {
CHAN5G(5825, 37), /* Channel 165 */ CHAN5G(5825, 37), /* Channel 165 */
}; };
/* Atheros hardware rate code addition for short premble */ /* Atheros hardware rate code addition for short preamble */
#define SHPCHECK(__hw_rate, __flags) \ #define SHPCHECK(__hw_rate, __flags) \
((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0) ((__flags & IEEE80211_RATE_SHORT_PREAMBLE) ? (__hw_rate | 0x04 ) : 0)
......
...@@ -479,14 +479,16 @@ ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv) ...@@ -479,14 +479,16 @@ ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv)
{ {
int i = 0; int i = 0;
int ret = 0; int ret = 0;
struct rchan_buf *buf;
struct rchan *rc = spec_priv->rfs_chan_spec_scan; struct rchan *rc = spec_priv->rfs_chan_spec_scan;
for_each_online_cpu(i) for_each_possible_cpu(i) {
ret += relay_buf_full(*per_cpu_ptr(rc->buf, i)); if ((buf = *per_cpu_ptr(rc->buf, i))) {
ret += relay_buf_full(buf);
i = num_online_cpus(); }
}
if (ret == i) if (ret)
return 1; return 1;
else else
return 0; return 0;
......
...@@ -184,7 +184,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah, ...@@ -184,7 +184,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
break; break;
case WLAN_RC_PHY_OFDM: case WLAN_RC_PHY_OFDM:
if (ah->curchan && IS_CHAN_QUARTER_RATE(ah->curchan)) { if (ah->curchan && IS_CHAN_QUARTER_RATE(ah->curchan)) {
bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; bitsPerSymbol =
((kbps >> 2) * OFDM_SYMBOL_TIME_QUARTER) / 1000;
numBits = OFDM_PLCP_BITS + (frameLen << 3); numBits = OFDM_PLCP_BITS + (frameLen << 3);
numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
txTime = OFDM_SIFS_TIME_QUARTER txTime = OFDM_SIFS_TIME_QUARTER
...@@ -192,7 +193,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah, ...@@ -192,7 +193,8 @@ u16 ath9k_hw_computetxtime(struct ath_hw *ah,
+ (numSymbols * OFDM_SYMBOL_TIME_QUARTER); + (numSymbols * OFDM_SYMBOL_TIME_QUARTER);
} else if (ah->curchan && } else if (ah->curchan &&
IS_CHAN_HALF_RATE(ah->curchan)) { IS_CHAN_HALF_RATE(ah->curchan)) {
bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; bitsPerSymbol =
((kbps >> 1) * OFDM_SYMBOL_TIME_HALF) / 1000;
numBits = OFDM_PLCP_BITS + (frameLen << 3); numBits = OFDM_PLCP_BITS + (frameLen << 3);
numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol);
txTime = OFDM_SIFS_TIME_HALF + txTime = OFDM_SIFS_TIME_HALF +
...@@ -1036,7 +1038,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) ...@@ -1036,7 +1038,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
int acktimeout, ctstimeout, ack_offset = 0; int acktimeout, ctstimeout, ack_offset = 0;
int slottime; int slottime;
int sifstime; int sifstime;
int rx_lat = 0, tx_lat = 0, eifs = 0; int rx_lat = 0, tx_lat = 0, eifs = 0, ack_shift = 0;
u32 reg; u32 reg;
ath_dbg(ath9k_hw_common(ah), RESET, "ah->misc_mode 0x%x\n", ath_dbg(ath9k_hw_common(ah), RESET, "ah->misc_mode 0x%x\n",
...@@ -1068,6 +1070,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) ...@@ -1068,6 +1070,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
sifstime = 32; sifstime = 32;
ack_offset = 16; ack_offset = 16;
ack_shift = 3;
slottime = 13; slottime = 13;
} else if (IS_CHAN_QUARTER_RATE(chan)) { } else if (IS_CHAN_QUARTER_RATE(chan)) {
eifs = 340; eifs = 340;
...@@ -1078,6 +1081,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) ...@@ -1078,6 +1081,7 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
sifstime = 64; sifstime = 64;
ack_offset = 32; ack_offset = 32;
ack_shift = 1;
slottime = 21; slottime = 21;
} else { } else {
if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) { if (AR_SREV_9287(ah) && AR_SREV_9287_13_OR_LATER(ah)) {
...@@ -1134,6 +1138,10 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah) ...@@ -1134,6 +1138,10 @@ void ath9k_hw_init_global_settings(struct ath_hw *ah)
SM(tx_lat, AR_USEC_TX_LAT), SM(tx_lat, AR_USEC_TX_LAT),
AR_USEC_TX_LAT | AR_USEC_RX_LAT | AR_USEC_USEC); AR_USEC_TX_LAT | AR_USEC_RX_LAT | AR_USEC_USEC);
if (IS_CHAN_HALF_RATE(chan) || IS_CHAN_QUARTER_RATE(chan))
REG_RMW(ah, AR_TXSIFS,
sifstime | SM(ack_shift, AR_TXSIFS_ACK_SHIFT),
(AR_TXSIFS_TIME | AR_TXSIFS_ACK_SHIFT));
} }
EXPORT_SYMBOL(ath9k_hw_init_global_settings); EXPORT_SYMBOL(ath9k_hw_init_global_settings);
......
...@@ -2892,6 +2892,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) ...@@ -2892,6 +2892,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
struct ath_txq *txq; struct ath_txq *txq;
int tidno; int tidno;
rcu_read_lock();
for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) {
tid = ath_node_to_tid(an, tidno); tid = ath_node_to_tid(an, tidno);
txq = tid->txq; txq = tid->txq;
...@@ -2909,6 +2911,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) ...@@ -2909,6 +2911,8 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
if (!an->sta) if (!an->sta)
break; /* just one multicast ath_atx_tid */ break; /* just one multicast ath_atx_tid */
} }
rcu_read_unlock();
} }
#ifdef CONFIG_ATH9K_TX99 #ifdef CONFIG_ATH9K_TX99
......
...@@ -115,7 +115,7 @@ static const struct radar_detector_specs jp_radar_ref_types[] = { ...@@ -115,7 +115,7 @@ static const struct radar_detector_specs jp_radar_ref_types[] = {
JP_PATTERN(4, 0, 5, 150, 230, 1, 23, 50, false), JP_PATTERN(4, 0, 5, 150, 230, 1, 23, 50, false),
JP_PATTERN(5, 6, 10, 200, 500, 1, 16, 50, false), JP_PATTERN(5, 6, 10, 200, 500, 1, 16, 50, false),
JP_PATTERN(6, 11, 20, 200, 500, 1, 12, 50, false), JP_PATTERN(6, 11, 20, 200, 500, 1, 12, 50, false),
JP_PATTERN(7, 50, 100, 1000, 2000, 1, 3, 50, false), JP_PATTERN(7, 50, 100, 1000, 2000, 1, 3, 50, true),
JP_PATTERN(5, 0, 1, 333, 333, 1, 9, 50, false), JP_PATTERN(5, 0, 1, 333, 333, 1, 9, 50, false),
}; };
......
...@@ -376,7 +376,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) ...@@ -376,7 +376,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
spin_lock_irqsave(&ch->lock, flags); spin_lock_irqsave(&ch->lock, flags);
ctl = ch->tail_blk_ctl; ctl = ch->tail_blk_ctl;
do { do {
if (ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK) if (ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD)
break; break;
if (ctl->skb) { if (ctl->skb) {
dma_unmap_single(wcn->dev, ctl->desc->src_addr_l, dma_unmap_single(wcn->dev, ctl->desc->src_addr_l,
...@@ -397,7 +397,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch) ...@@ -397,7 +397,7 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
} }
ctl = ctl->next; ctl = ctl->next;
} while (ctl != ch->head_blk_ctl && } while (ctl != ch->head_blk_ctl &&
!(ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)); !(ctl->desc->ctrl & WCN36xx_DXE_CTRL_VLD));
ch->tail_blk_ctl = ctl; ch->tail_blk_ctl = ctl;
spin_unlock_irqrestore(&ch->lock, flags); spin_unlock_irqrestore(&ch->lock, flags);
...@@ -415,14 +415,31 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev) ...@@ -415,14 +415,31 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev)
WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_H, WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_H,
&int_reason); &int_reason);
/* TODO: Check int_reason */
wcn36xx_dxe_write_register(wcn, wcn36xx_dxe_write_register(wcn,
WCN36XX_DXE_0_INT_CLR, WCN36XX_DXE_0_INT_CLR,
WCN36XX_INT_MASK_CHAN_TX_H); WCN36XX_INT_MASK_CHAN_TX_H);
wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR, if (int_reason & WCN36XX_CH_STAT_INT_ERR_MASK ) {
WCN36XX_INT_MASK_CHAN_TX_H); wcn36xx_dxe_write_register(wcn,
WCN36XX_DXE_0_INT_ERR_CLR,
WCN36XX_INT_MASK_CHAN_TX_H);
wcn36xx_err("DXE IRQ reported error: 0x%x in high TX channel\n",
int_src);
}
if (int_reason & WCN36XX_CH_STAT_INT_DONE_MASK) {
wcn36xx_dxe_write_register(wcn,
WCN36XX_DXE_0_INT_DONE_CLR,
WCN36XX_INT_MASK_CHAN_TX_H);
}
if (int_reason & WCN36XX_CH_STAT_INT_ED_MASK) {
wcn36xx_dxe_write_register(wcn,
WCN36XX_DXE_0_INT_ED_CLR,
WCN36XX_INT_MASK_CHAN_TX_H);
}
wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready high\n"); wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready high\n");
reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch); reap_tx_dxes(wcn, &wcn->dxe_tx_h_ch);
} }
...@@ -431,14 +448,33 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev) ...@@ -431,14 +448,33 @@ static irqreturn_t wcn36xx_irq_tx_complete(int irq, void *dev)
wcn36xx_dxe_read_register(wcn, wcn36xx_dxe_read_register(wcn,
WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_L, WCN36XX_DXE_CH_STATUS_REG_ADDR_TX_L,
&int_reason); &int_reason);
/* TODO: Check int_reason */
wcn36xx_dxe_write_register(wcn, wcn36xx_dxe_write_register(wcn,
WCN36XX_DXE_0_INT_CLR, WCN36XX_DXE_0_INT_CLR,
WCN36XX_INT_MASK_CHAN_TX_L); WCN36XX_INT_MASK_CHAN_TX_L);
wcn36xx_dxe_write_register(wcn, WCN36XX_DXE_0_INT_ED_CLR,
WCN36XX_INT_MASK_CHAN_TX_L); if (int_reason & WCN36XX_CH_STAT_INT_ERR_MASK ) {
wcn36xx_dxe_write_register(wcn,
WCN36XX_DXE_0_INT_ERR_CLR,
WCN36XX_INT_MASK_CHAN_TX_L);
wcn36xx_err("DXE IRQ reported error: 0x%x in low TX channel\n",
int_src);
}
if (int_reason & WCN36XX_CH_STAT_INT_DONE_MASK) {
wcn36xx_dxe_write_register(wcn,
WCN36XX_DXE_0_INT_DONE_CLR,
WCN36XX_INT_MASK_CHAN_TX_L);
}
if (int_reason & WCN36XX_CH_STAT_INT_ED_MASK) {
wcn36xx_dxe_write_register(wcn,
WCN36XX_DXE_0_INT_ED_CLR,
WCN36XX_INT_MASK_CHAN_TX_L);
}
wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready low\n"); wcn36xx_dbg(WCN36XX_DBG_DXE, "dxe tx ready low\n");
reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch); reap_tx_dxes(wcn, &wcn->dxe_tx_l_ch);
} }
...@@ -503,7 +539,7 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn, ...@@ -503,7 +539,7 @@ static int wcn36xx_rx_handle_packets(struct wcn36xx *wcn,
int_mask = WCN36XX_DXE_INT_CH3_MASK; int_mask = WCN36XX_DXE_INT_CH3_MASK;
} }
while (!(dxe->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)) { while (!(dxe->ctrl & WCN36xx_DXE_CTRL_VLD)) {
skb = ctl->skb; skb = ctl->skb;
dma_addr = dxe->dst_addr_l; dma_addr = dxe->dst_addr_l;
ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl); ret = wcn36xx_dxe_fill_skb(wcn->dev, ctl);
......
...@@ -33,15 +33,106 @@ H2H_TEST_RX_TX = DMA2 ...@@ -33,15 +33,106 @@ H2H_TEST_RX_TX = DMA2
#define WCN36XX_CCU_DXE_INT_SELECT_RIVA 0x310 #define WCN36XX_CCU_DXE_INT_SELECT_RIVA 0x310
#define WCN36XX_CCU_DXE_INT_SELECT_PRONTO 0x10dc #define WCN36XX_CCU_DXE_INT_SELECT_PRONTO 0x10dc
/* TODO This must calculated properly but not hardcoded */ /* Descriptor valid */
#define WCN36XX_DXE_CTRL_TX_L 0x328a44 #define WCN36xx_DXE_CTRL_VLD BIT(0)
#define WCN36XX_DXE_CTRL_TX_H 0x32ce44 /* End of packet */
#define WCN36XX_DXE_CTRL_RX_L 0x12ad2f #define WCN36xx_DXE_CTRL_EOP BIT(3)
#define WCN36XX_DXE_CTRL_RX_H 0x12d12f /* BD handling bit */
#define WCN36XX_DXE_CTRL_TX_H_BD 0x30ce45 #define WCN36xx_DXE_CTRL_BDH BIT(4)
#define WCN36XX_DXE_CTRL_TX_H_SKB 0x32ce4d /* Source is a queue */
#define WCN36XX_DXE_CTRL_TX_L_BD 0x308a45 #define WCN36xx_DXE_CTRL_SIQ BIT(5)
#define WCN36XX_DXE_CTRL_TX_L_SKB 0x328a4d /* Destination is a queue */
#define WCN36xx_DXE_CTRL_DIQ BIT(6)
/* Pointer address is a queue */
#define WCN36xx_DXE_CTRL_PIQ BIT(7)
/* Release PDU when done */
#define WCN36xx_DXE_CTRL_PDU_REL BIT(8)
/* STOP channel processing */
#define WCN36xx_DXE_CTRL_STOP BIT(16)
/* INT on descriptor done */
#define WCN36xx_DXE_CTRL_INT BIT(17)
/* Endian byte swap enable */
#define WCN36xx_DXE_CTRL_SWAP BIT(20)
/* Master endianness */
#define WCN36xx_DXE_CTRL_ENDIANNESS BIT(21)
/* Transfer type */
#define WCN36xx_DXE_CTRL_XTYPE_SHIFT 1
#define WCN36xx_DXE_CTRL_XTYPE_MASK GENMASK(2, WCN36xx_DXE_CTRL_XTYPE_SHIFT)
#define WCN36xx_DXE_CTRL_XTYPE_SET(x) ((x) << WCN36xx_DXE_CTRL_XTYPE_SHIFT)
/* BMU Threshold select */
#define WCN36xx_DXE_CTRL_BTHLD_SEL_SHIFT 9
#define WCN36xx_DXE_CTRL_BTHLD_SEL_MASK GENMASK(12, WCN36xx_DXE_CTRL_BTHLD_SEL_SHIFT)
#define WCN36xx_DXE_CTRL_BTHLD_SEL_SET(x) ((x) << WCN36xx_DXE_CTRL_BTHLD_SEL_SHIFT)
/* Priority */
#define WCN36xx_DXE_CTRL_PRIO_SHIFT 13
#define WCN36xx_DXE_CTRL_PRIO_MASK GENMASK(15, WCN36xx_DXE_CTRL_PRIO_SHIFT)
#define WCN36xx_DXE_CTRL_PRIO_SET(x) ((x) << WCN36xx_DXE_CTRL_PRIO_SHIFT)
/* BD Template index */
#define WCN36xx_DXE_CTRL_BDT_IDX_SHIFT 18
#define WCN36xx_DXE_CTRL_BDT_IDX_MASK GENMASK(19, WCN36xx_DXE_CTRL_BDT_IDX_SHIFT)
#define WCN36xx_DXE_CTRL_BDT_IDX_SET(x) ((x) << WCN36xx_DXE_CTRL_BDT_IDX_SHIFT)
/* Transfer types: */
/* Host to host */
#define WCN36xx_DXE_XTYPE_H2H (0)
/* Host to BMU */
#define WCN36xx_DXE_XTYPE_H2B (2)
/* BMU to host */
#define WCN36xx_DXE_XTYPE_B2H (3)
#define WCN36XX_DXE_CTRL_TX_L (WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(5) | \
WCN36xx_DXE_CTRL_PRIO_SET(4) | WCN36xx_DXE_CTRL_INT | \
WCN36xx_DXE_CTRL_SWAP | WCN36xx_DXE_CTRL_ENDIANNESS)
#define WCN36XX_DXE_CTRL_TX_H (WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(7) | \
WCN36xx_DXE_CTRL_PRIO_SET(6) | WCN36xx_DXE_CTRL_INT | \
WCN36xx_DXE_CTRL_SWAP | WCN36xx_DXE_CTRL_ENDIANNESS)
#define WCN36XX_DXE_CTRL_RX_L (WCN36xx_DXE_CTRL_VLD | \
WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \
WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_SIQ | \
WCN36xx_DXE_CTRL_PDU_REL | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(6) | \
WCN36xx_DXE_CTRL_PRIO_SET(5) | WCN36xx_DXE_CTRL_INT | \
WCN36xx_DXE_CTRL_SWAP)
#define WCN36XX_DXE_CTRL_RX_H (WCN36xx_DXE_CTRL_VLD | \
WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \
WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_SIQ | \
WCN36xx_DXE_CTRL_PDU_REL | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(8) | \
WCN36xx_DXE_CTRL_PRIO_SET(6) | WCN36xx_DXE_CTRL_INT | \
WCN36xx_DXE_CTRL_SWAP)
#define WCN36XX_DXE_CTRL_TX_H_BD (WCN36xx_DXE_CTRL_VLD | \
WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(7) | \
WCN36xx_DXE_CTRL_PRIO_SET(6) | WCN36xx_DXE_CTRL_SWAP | \
WCN36xx_DXE_CTRL_ENDIANNESS)
#define WCN36XX_DXE_CTRL_TX_H_SKB (WCN36xx_DXE_CTRL_VLD | \
WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_DIQ | \
WCN36xx_DXE_CTRL_BTHLD_SEL_SET(7) | WCN36xx_DXE_CTRL_PRIO_SET(6) | \
WCN36xx_DXE_CTRL_INT | WCN36xx_DXE_CTRL_SWAP | \
WCN36xx_DXE_CTRL_ENDIANNESS)
#define WCN36XX_DXE_CTRL_TX_L_BD (WCN36xx_DXE_CTRL_VLD | \
WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
WCN36xx_DXE_CTRL_DIQ | WCN36xx_DXE_CTRL_BTHLD_SEL_SET(5) | \
WCN36xx_DXE_CTRL_PRIO_SET(4) | WCN36xx_DXE_CTRL_SWAP | \
WCN36xx_DXE_CTRL_ENDIANNESS)
#define WCN36XX_DXE_CTRL_TX_L_SKB (WCN36xx_DXE_CTRL_VLD | \
WCN36xx_DXE_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
WCN36xx_DXE_CTRL_EOP | WCN36xx_DXE_CTRL_DIQ | \
WCN36xx_DXE_CTRL_BTHLD_SEL_SET(5) | WCN36xx_DXE_CTRL_PRIO_SET(4) | \
WCN36xx_DXE_CTRL_INT | WCN36xx_DXE_CTRL_SWAP | \
WCN36xx_DXE_CTRL_ENDIANNESS)
/* TODO This must calculated properly but not hardcoded */ /* TODO This must calculated properly but not hardcoded */
#define WCN36XX_DXE_WQ_TX_L 0x17 #define WCN36XX_DXE_WQ_TX_L 0x17
...@@ -49,15 +140,106 @@ H2H_TEST_RX_TX = DMA2 ...@@ -49,15 +140,106 @@ H2H_TEST_RX_TX = DMA2
#define WCN36XX_DXE_WQ_RX_L 0xB #define WCN36XX_DXE_WQ_RX_L 0xB
#define WCN36XX_DXE_WQ_RX_H 0x4 #define WCN36XX_DXE_WQ_RX_H 0x4
/* DXE descriptor control filed */ /* Channel enable or restart */
#define WCN36XX_DXE_CTRL_VALID_MASK (0x00000001) #define WCN36xx_DXE_CH_CTRL_EN BIT(0)
/* End of packet bit */
#define WCN36xx_DXE_CH_CTRL_EOP BIT(3)
/* BD Handling bit */
#define WCN36xx_DXE_CH_CTRL_BDH BIT(4)
/* Source is queue */
#define WCN36xx_DXE_CH_CTRL_SIQ BIT(5)
/* Destination is queue */
#define WCN36xx_DXE_CH_CTRL_DIQ BIT(6)
/* Pointer descriptor is queue */
#define WCN36xx_DXE_CH_CTRL_PIQ BIT(7)
/* Relase PDU when done */
#define WCN36xx_DXE_CH_CTRL_PDU_REL BIT(8)
/* Stop channel processing */
#define WCN36xx_DXE_CH_CTRL_STOP BIT(16)
/* Enable external descriptor interrupt */
#define WCN36xx_DXE_CH_CTRL_INE_ED BIT(17)
/* Enable channel interrupt on errors */
#define WCN36xx_DXE_CH_CTRL_INE_ERR BIT(18)
/* Enable Channel interrupt when done */
#define WCN36xx_DXE_CH_CTRL_INE_DONE BIT(19)
/* External descriptor enable */
#define WCN36xx_DXE_CH_CTRL_EDEN BIT(20)
/* Wait for valid bit */
#define WCN36xx_DXE_CH_CTRL_EDVEN BIT(21)
/* Endianness is little endian*/
#define WCN36xx_DXE_CH_CTRL_ENDIANNESS BIT(26)
/* Abort transfer */
#define WCN36xx_DXE_CH_CTRL_ABORT BIT(27)
/* Long descriptor format */
#define WCN36xx_DXE_CH_CTRL_DFMT BIT(28)
/* Endian byte swap enable */
#define WCN36xx_DXE_CH_CTRL_SWAP BIT(31)
/* Transfer type */
#define WCN36xx_DXE_CH_CTRL_XTYPE_SHIFT 1
#define WCN36xx_DXE_CH_CTRL_XTYPE_MASK GENMASK(2, WCN36xx_DXE_CH_CTRL_XTYPE_SHIFT)
#define WCN36xx_DXE_CH_CTRL_XTYPE_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_XTYPE_SHIFT)
/* Channel BMU Threshold select */
#define WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SHIFT 9
#define WCN36xx_DXE_CH_CTRL_BTHLD_SEL_MASK GENMASK(12, WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SHIFT)
#define WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SHIFT)
/* Channel Priority */
#define WCN36xx_DXE_CH_CTRL_PRIO_SHIFT 13
#define WCN36xx_DXE_CH_CTRL_PRIO_MASK GENMASK(15, WCN36xx_DXE_CH_CTRL_PRIO_SHIFT)
#define WCN36xx_DXE_CH_CTRL_PRIO_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_PRIO_SHIFT)
/* Counter select */
#define WCN36xx_DXE_CH_CTRL_SEL_SHIFT 22
#define WCN36xx_DXE_CH_CTRL_SEL_MASK GENMASK(25, WCN36xx_DXE_CH_CTRL_SEL_SHIFT)
#define WCN36xx_DXE_CH_CTRL_SEL_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_SEL_SHIFT)
/* Channel BD template index */
#define WCN36xx_DXE_CH_CTRL_BDT_IDX_SHIFT 29
#define WCN36xx_DXE_CH_CTRL_BDT_IDX_MASK GENMASK(30, WCN36xx_DXE_CH_CTRL_BDT_IDX_SHIFT)
#define WCN36xx_DXE_CH_CTRL_BDT_IDX_SET(x) ((x) << WCN36xx_DXE_CH_CTRL_BDT_IDX_SHIFT)
/* TODO This must calculated properly but not hardcoded */
/* DXE default control register values */ /* DXE default control register values */
#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_L 0x847EAD2F #define WCN36XX_DXE_CH_DEFAULT_CTL_RX_L (WCN36xx_DXE_CH_CTRL_EN | \
#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_H 0x84FED12F WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \
#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_H 0x853ECF4D WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_SIQ | \
#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_L 0x843e8b4d WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(6) | \
WCN36xx_DXE_CH_CTRL_PRIO_SET(5) | WCN36xx_DXE_CH_CTRL_INE_ED | \
WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \
WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \
WCN36xx_DXE_CH_CTRL_SEL_SET(1) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \
WCN36xx_DXE_CH_CTRL_SWAP)
#define WCN36XX_DXE_CH_DEFAULT_CTL_RX_H (WCN36xx_DXE_CH_CTRL_EN | \
WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_B2H) | \
WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_SIQ | \
WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(8) | \
WCN36xx_DXE_CH_CTRL_PRIO_SET(6) | WCN36xx_DXE_CH_CTRL_INE_ED | \
WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \
WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \
WCN36xx_DXE_CH_CTRL_SEL_SET(3) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \
WCN36xx_DXE_CH_CTRL_SWAP)
#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_H (WCN36xx_DXE_CH_CTRL_EN | \
WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_DIQ | \
WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(7) | \
WCN36xx_DXE_CH_CTRL_PRIO_SET(6) | WCN36xx_DXE_CH_CTRL_INE_ED | \
WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \
WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \
WCN36xx_DXE_CH_CTRL_SEL_SET(4) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \
WCN36xx_DXE_CH_CTRL_SWAP)
#define WCN36XX_DXE_CH_DEFAULT_CTL_TX_L (WCN36xx_DXE_CH_CTRL_EN | \
WCN36xx_DXE_CH_CTRL_XTYPE_SET(WCN36xx_DXE_XTYPE_H2B) | \
WCN36xx_DXE_CH_CTRL_EOP | WCN36xx_DXE_CH_CTRL_DIQ | \
WCN36xx_DXE_CH_CTRL_PDU_REL | WCN36xx_DXE_CH_CTRL_BTHLD_SEL_SET(5) | \
WCN36xx_DXE_CH_CTRL_PRIO_SET(4) | WCN36xx_DXE_CH_CTRL_INE_ED | \
WCN36xx_DXE_CH_CTRL_INE_ERR | WCN36xx_DXE_CH_CTRL_INE_DONE | \
WCN36xx_DXE_CH_CTRL_EDEN | WCN36xx_DXE_CH_CTRL_EDVEN | \
WCN36xx_DXE_CH_CTRL_SEL_SET(0) | WCN36xx_DXE_CH_CTRL_ENDIANNESS | \
WCN36xx_DXE_CH_CTRL_SWAP)
/* Common DXE registers */ /* Common DXE registers */
#define WCN36XX_DXE_MEM_CSR (WCN36XX_DXE_MEM_REG + 0x00) #define WCN36XX_DXE_MEM_CSR (WCN36XX_DXE_MEM_REG + 0x00)
...@@ -80,6 +262,10 @@ H2H_TEST_RX_TX = DMA2 ...@@ -80,6 +262,10 @@ H2H_TEST_RX_TX = DMA2
#define WCN36XX_DXE_0_INT_DONE_CLR (WCN36XX_DXE_MEM_REG + 0x38) #define WCN36XX_DXE_0_INT_DONE_CLR (WCN36XX_DXE_MEM_REG + 0x38)
#define WCN36XX_DXE_0_INT_ERR_CLR (WCN36XX_DXE_MEM_REG + 0x3C) #define WCN36XX_DXE_0_INT_ERR_CLR (WCN36XX_DXE_MEM_REG + 0x3C)
#define WCN36XX_CH_STAT_INT_DONE_MASK 0x00008000
#define WCN36XX_CH_STAT_INT_ERR_MASK 0x00004000
#define WCN36XX_CH_STAT_INT_ED_MASK 0x00002000
#define WCN36XX_DXE_0_CH0_STATUS (WCN36XX_DXE_MEM_REG + 0x404) #define WCN36XX_DXE_0_CH0_STATUS (WCN36XX_DXE_MEM_REG + 0x404)
#define WCN36XX_DXE_0_CH1_STATUS (WCN36XX_DXE_MEM_REG + 0x444) #define WCN36XX_DXE_0_CH1_STATUS (WCN36XX_DXE_MEM_REG + 0x444)
#define WCN36XX_DXE_0_CH2_STATUS (WCN36XX_DXE_MEM_REG + 0x484) #define WCN36XX_DXE_0_CH2_STATUS (WCN36XX_DXE_MEM_REG + 0x484)
......
...@@ -261,7 +261,7 @@ static void wcn36xx_feat_caps_info(struct wcn36xx *wcn) ...@@ -261,7 +261,7 @@ static void wcn36xx_feat_caps_info(struct wcn36xx *wcn)
for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) { for (i = 0; i < MAX_FEATURE_SUPPORTED; i++) {
if (get_feat_caps(wcn->fw_feat_caps, i)) if (get_feat_caps(wcn->fw_feat_caps, i))
wcn36xx_info("FW Cap %s\n", wcn36xx_get_cap_name(i)); wcn36xx_dbg(WCN36XX_DBG_MAC, "FW Cap %s\n", wcn36xx_get_cap_name(i));
} }
} }
...@@ -666,16 +666,13 @@ static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw, ...@@ -666,16 +666,13 @@ static void wcn36xx_cancel_hw_scan(struct ieee80211_hw *hw,
{ {
struct wcn36xx *wcn = hw->priv; struct wcn36xx *wcn = hw->priv;
if (!wcn36xx_smd_stop_hw_scan(wcn)) {
struct cfg80211_scan_info scan_info = { .aborted = true };
ieee80211_scan_completed(wcn->hw, &scan_info);
}
mutex_lock(&wcn->scan_lock); mutex_lock(&wcn->scan_lock);
wcn->scan_aborted = true; wcn->scan_aborted = true;
mutex_unlock(&wcn->scan_lock); mutex_unlock(&wcn->scan_lock);
/* ieee80211_scan_completed will be called on FW scan indication */
wcn36xx_smd_stop_hw_scan(wcn);
cancel_work_sync(&wcn->scan_work); cancel_work_sync(&wcn->scan_work);
} }
...@@ -1283,6 +1280,7 @@ static int wcn36xx_probe(struct platform_device *pdev) ...@@ -1283,6 +1280,7 @@ static int wcn36xx_probe(struct platform_device *pdev)
wcn = hw->priv; wcn = hw->priv;
wcn->hw = hw; wcn->hw = hw;
wcn->dev = &pdev->dev; wcn->dev = &pdev->dev;
wcn->first_boot = true;
mutex_init(&wcn->conf_mutex); mutex_init(&wcn->conf_mutex);
mutex_init(&wcn->hal_mutex); mutex_init(&wcn->hal_mutex);
mutex_init(&wcn->scan_lock); mutex_init(&wcn->scan_lock);
......
...@@ -409,15 +409,17 @@ static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len) ...@@ -409,15 +409,17 @@ static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len)
wcn->fw_minor = rsp->start_rsp_params.version.minor; wcn->fw_minor = rsp->start_rsp_params.version.minor;
wcn->fw_major = rsp->start_rsp_params.version.major; wcn->fw_major = rsp->start_rsp_params.version.major;
wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n", if (wcn->first_boot) {
wcn->wlan_version, wcn->crm_version); wcn->first_boot = false;
wcn36xx_info("firmware WLAN version '%s' and CRM version '%s'\n",
wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n", wcn->wlan_version, wcn->crm_version);
wcn->fw_major, wcn->fw_minor,
wcn->fw_version, wcn->fw_revision,
rsp->start_rsp_params.stations,
rsp->start_rsp_params.bssids);
wcn36xx_info("firmware API %u.%u.%u.%u, %u stations, %u bssids\n",
wcn->fw_major, wcn->fw_minor,
wcn->fw_version, wcn->fw_revision,
rsp->start_rsp_params.stations,
rsp->start_rsp_params.bssids);
}
return 0; return 0;
} }
...@@ -2138,6 +2140,8 @@ static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len) ...@@ -2138,6 +2140,8 @@ static int wcn36xx_smd_hw_scan_ind(struct wcn36xx *wcn, void *buf, size_t len)
case WCN36XX_HAL_SCAN_IND_COMPLETED: case WCN36XX_HAL_SCAN_IND_COMPLETED:
mutex_lock(&wcn->scan_lock); mutex_lock(&wcn->scan_lock);
wcn->scan_req = NULL; wcn->scan_req = NULL;
if (wcn->scan_aborted)
scan_info.aborted = true;
mutex_unlock(&wcn->scan_lock); mutex_unlock(&wcn->scan_lock);
ieee80211_scan_completed(wcn->hw, &scan_info); ieee80211_scan_completed(wcn->hw, &scan_info);
break; break;
......
...@@ -192,6 +192,8 @@ struct wcn36xx { ...@@ -192,6 +192,8 @@ struct wcn36xx {
u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1]; u8 crm_version[WCN36XX_HAL_VERSION_LENGTH + 1];
u8 wlan_version[WCN36XX_HAL_VERSION_LENGTH + 1]; u8 wlan_version[WCN36XX_HAL_VERSION_LENGTH + 1];
bool first_boot;
/* IRQs */ /* IRQs */
int tx_irq; int tx_irq;
int rx_irq; int rx_irq;
......
/* /*
* Copyright (c) 2013,2016 Qualcomm Atheros, Inc. * Copyright (c) 2013,2016 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -25,7 +26,7 @@ void __wil_err(struct wil6210_priv *wil, const char *fmt, ...) ...@@ -25,7 +26,7 @@ void __wil_err(struct wil6210_priv *wil, const char *fmt, ...)
va_start(args, fmt); va_start(args, fmt);
vaf.fmt = fmt; vaf.fmt = fmt;
vaf.va = &args; vaf.va = &args;
netdev_err(wil_to_ndev(wil), "%pV", &vaf); netdev_err(wil->main_ndev, "%pV", &vaf);
trace_wil6210_log_err(&vaf); trace_wil6210_log_err(&vaf);
va_end(args); va_end(args);
} }
...@@ -41,7 +42,7 @@ void __wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...) ...@@ -41,7 +42,7 @@ void __wil_err_ratelimited(struct wil6210_priv *wil, const char *fmt, ...)
va_start(args, fmt); va_start(args, fmt);
vaf.fmt = fmt; vaf.fmt = fmt;
vaf.va = &args; vaf.va = &args;
netdev_err(wil_to_ndev(wil), "%pV", &vaf); netdev_err(wil->main_ndev, "%pV", &vaf);
trace_wil6210_log_err(&vaf); trace_wil6210_log_err(&vaf);
va_end(args); va_end(args);
} }
...@@ -57,7 +58,7 @@ void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...) ...@@ -57,7 +58,7 @@ void wil_dbg_ratelimited(const struct wil6210_priv *wil, const char *fmt, ...)
va_start(args, fmt); va_start(args, fmt);
vaf.fmt = fmt; vaf.fmt = fmt;
vaf.va = &args; vaf.va = &args;
netdev_dbg(wil_to_ndev(wil), "%pV", &vaf); netdev_dbg(wil->main_ndev, "%pV", &vaf);
trace_wil6210_log_dbg(&vaf); trace_wil6210_log_dbg(&vaf);
va_end(args); va_end(args);
} }
...@@ -70,7 +71,7 @@ void __wil_info(struct wil6210_priv *wil, const char *fmt, ...) ...@@ -70,7 +71,7 @@ void __wil_info(struct wil6210_priv *wil, const char *fmt, ...)
va_start(args, fmt); va_start(args, fmt);
vaf.fmt = fmt; vaf.fmt = fmt;
vaf.va = &args; vaf.va = &args;
netdev_info(wil_to_ndev(wil), "%pV", &vaf); netdev_info(wil->main_ndev, "%pV", &vaf);
trace_wil6210_log_info(&vaf); trace_wil6210_log_info(&vaf);
va_end(args); va_end(args);
} }
......
/* /*
* Copyright (c) 2012-2017 Qualcomm Atheros, Inc. * Copyright (c) 2012-2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -621,7 +622,7 @@ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf, ...@@ -621,7 +622,7 @@ static ssize_t wil_write_file_reset(struct file *file, const char __user *buf,
size_t len, loff_t *ppos) size_t len, loff_t *ppos)
{ {
struct wil6210_priv *wil = file->private_data; struct wil6210_priv *wil = file->private_data;
struct net_device *ndev = wil_to_ndev(wil); struct net_device *ndev = wil->main_ndev;
/** /**
* BUG: * BUG:
...@@ -716,27 +717,44 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf, ...@@ -716,27 +717,44 @@ static ssize_t wil_write_back(struct file *file, const char __user *buf,
if (rc < 2) if (rc < 2)
return -EINVAL; return -EINVAL;
if (0 == strcmp(cmd, "add")) { if ((strcmp(cmd, "add") == 0) ||
if (rc < 3) { (strcmp(cmd, "del_tx") == 0)) {
wil_err(wil, "BACK: add require at least 2 params\n"); struct vring_tx_data *txdata;
if (p1 < 0 || p1 >= WIL6210_MAX_TX_RINGS) {
wil_err(wil, "BACK: invalid ring id %d\n", p1);
return -EINVAL; return -EINVAL;
} }
if (rc < 4) txdata = &wil->vring_tx_data[p1];
p3 = 0; if (strcmp(cmd, "add") == 0) {
wmi_addba(wil, p1, p2, p3); if (rc < 3) {
} else if (0 == strcmp(cmd, "del_tx")) { wil_err(wil, "BACK: add require at least 2 params\n");
if (rc < 3) return -EINVAL;
p2 = WLAN_REASON_QSTA_LEAVE_QBSS; }
wmi_delba_tx(wil, p1, p2); if (rc < 4)
} else if (0 == strcmp(cmd, "del_rx")) { p3 = 0;
wmi_addba(wil, txdata->mid, p1, p2, p3);
} else {
if (rc < 3)
p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
wmi_delba_tx(wil, txdata->mid, p1, p2);
}
} else if (strcmp(cmd, "del_rx") == 0) {
struct wil_sta_info *sta;
if (rc < 3) { if (rc < 3) {
wil_err(wil, wil_err(wil,
"BACK: del_rx require at least 2 params\n"); "BACK: del_rx require at least 2 params\n");
return -EINVAL; return -EINVAL;
} }
if (p1 < 0 || p1 >= WIL6210_MAX_CID) {
wil_err(wil, "BACK: invalid CID %d\n", p1);
return -EINVAL;
}
if (rc < 4) if (rc < 4)
p3 = WLAN_REASON_QSTA_LEAVE_QBSS; p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3); sta = &wil->sta[p1];
wmi_delba_rx(wil, sta->mid, mk_cidxtid(p1, p2), p3);
} else { } else {
wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd); wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
return -EINVAL; return -EINVAL;
...@@ -855,7 +873,7 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf, ...@@ -855,7 +873,7 @@ static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
{ {
struct wil6210_priv *wil = file->private_data; struct wil6210_priv *wil = file->private_data;
struct wiphy *wiphy = wil_to_wiphy(wil); struct wiphy *wiphy = wil_to_wiphy(wil);
struct wireless_dev *wdev = wil_to_wdev(wil); struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
struct cfg80211_mgmt_tx_params params; struct cfg80211_mgmt_tx_params params;
int rc; int rc;
void *frame; void *frame;
...@@ -890,6 +908,7 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, ...@@ -890,6 +908,7 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
size_t len, loff_t *ppos) size_t len, loff_t *ppos)
{ {
struct wil6210_priv *wil = file->private_data; struct wil6210_priv *wil = file->private_data;
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_cmd_hdr *wmi; struct wmi_cmd_hdr *wmi;
void *cmd; void *cmd;
int cmdlen = len - sizeof(struct wmi_cmd_hdr); int cmdlen = len - sizeof(struct wmi_cmd_hdr);
...@@ -912,7 +931,7 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf, ...@@ -912,7 +931,7 @@ static ssize_t wil_write_file_wmi(struct file *file, const char __user *buf,
cmd = (cmdlen > 0) ? &wmi[1] : NULL; cmd = (cmdlen > 0) ? &wmi[1] : NULL;
cmdid = le16_to_cpu(wmi->command_id); cmdid = le16_to_cpu(wmi->command_id);
rc1 = wmi_send(wil, cmdid, cmd, cmdlen); rc1 = wmi_send(wil, cmdid, vif->mid, cmd, cmdlen);
kfree(wmi); kfree(wmi);
wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1); wil_info(wil, "0x%04x[%d] -> %d\n", cmdid, cmdlen, rc1);
...@@ -1050,6 +1069,7 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data) ...@@ -1050,6 +1069,7 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data)
int rc; int rc;
int i; int i;
struct wil6210_priv *wil = s->private; struct wil6210_priv *wil = s->private;
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_notify_req_cmd cmd = { struct wmi_notify_req_cmd cmd = {
.interval_usec = 0, .interval_usec = 0,
}; };
...@@ -1062,7 +1082,8 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data) ...@@ -1062,7 +1082,8 @@ static int wil_bf_debugfs_show(struct seq_file *s, void *data)
u32 status; u32 status;
cmd.cid = i; cmd.cid = i;
rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, &cmd, sizeof(cmd), rc = wmi_call(wil, WMI_NOTIFY_REQ_CMDID, vif->mid,
&cmd, sizeof(cmd),
WMI_NOTIFY_REQ_DONE_EVENTID, &reply, WMI_NOTIFY_REQ_DONE_EVENTID, &reply,
sizeof(reply), 20); sizeof(reply), 20);
/* if reply is all-0, ignore this CID */ /* if reply is all-0, ignore this CID */
...@@ -1155,7 +1176,7 @@ static const struct file_operations fops_temp = { ...@@ -1155,7 +1176,7 @@ static const struct file_operations fops_temp = {
static int wil_freq_debugfs_show(struct seq_file *s, void *data) static int wil_freq_debugfs_show(struct seq_file *s, void *data)
{ {
struct wil6210_priv *wil = s->private; struct wil6210_priv *wil = s->private;
struct wireless_dev *wdev = wil_to_wdev(wil); struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0; u16 freq = wdev->chandef.chan ? wdev->chandef.chan->center_freq : 0;
seq_printf(s, "Freq = %d\n", freq); seq_printf(s, "Freq = %d\n", freq);
...@@ -1185,6 +1206,8 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data) ...@@ -1185,6 +1206,8 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) { for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i]; struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown"; char *status = "unknown";
struct wil6210_vif *vif;
u8 mid;
switch (p->status) { switch (p->status) {
case wil_sta_unused: case wil_sta_unused:
...@@ -1197,16 +1220,24 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data) ...@@ -1197,16 +1220,24 @@ static int wil_link_debugfs_show(struct seq_file *s, void *data)
status = "connected"; status = "connected";
break; break;
} }
seq_printf(s, "[%d] %pM %s\n", i, p->addr, status); mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
seq_printf(s, "[%d][MID %d] %pM %s\n",
i, mid, p->addr, status);
if (p->status == wil_sta_connected) { if (p->status != wil_sta_connected)
rc = wil_cid_fill_sinfo(wil, i, &sinfo); continue;
vif = (mid < wil->max_vifs) ? wil->vifs[mid] : NULL;
if (vif) {
rc = wil_cid_fill_sinfo(vif, i, &sinfo);
if (rc) if (rc)
return rc; return rc;
seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs); seq_printf(s, " Tx_mcs = %d\n", sinfo.txrate.mcs);
seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs); seq_printf(s, " Rx_mcs = %d\n", sinfo.rxrate.mcs);
seq_printf(s, " SQ = %d\n", sinfo.signal); seq_printf(s, " SQ = %d\n", sinfo.signal);
} else {
seq_puts(s, " INVALID MID\n");
} }
} }
...@@ -1229,7 +1260,7 @@ static const struct file_operations fops_link = { ...@@ -1229,7 +1260,7 @@ static const struct file_operations fops_link = {
static int wil_info_debugfs_show(struct seq_file *s, void *data) static int wil_info_debugfs_show(struct seq_file *s, void *data)
{ {
struct wil6210_priv *wil = s->private; struct wil6210_priv *wil = s->private;
struct net_device *ndev = wil_to_ndev(wil); struct net_device *ndev = wil->main_ndev;
int is_ac = power_supply_is_system_supplied(); int is_ac = power_supply_is_system_supplied();
int rx = atomic_xchg(&wil->isr_count_rx, 0); int rx = atomic_xchg(&wil->isr_count_rx, 0);
int tx = atomic_xchg(&wil->isr_count_tx, 0); int tx = atomic_xchg(&wil->isr_count_tx, 0);
...@@ -1398,6 +1429,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) ...@@ -1398,6 +1429,7 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
struct wil_sta_info *p = &wil->sta[i]; struct wil_sta_info *p = &wil->sta[i];
char *status = "unknown"; char *status = "unknown";
u8 aid = 0; u8 aid = 0;
u8 mid;
switch (p->status) { switch (p->status) {
case wil_sta_unused: case wil_sta_unused:
...@@ -1411,7 +1443,9 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock) ...@@ -1411,7 +1443,9 @@ __acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
aid = p->aid; aid = p->aid;
break; break;
} }
seq_printf(s, "[%d] %pM %s AID %d\n", i, p->addr, status, aid); mid = (p->status != wil_sta_unused) ? p->mid : U8_MAX;
seq_printf(s, "[%d] %pM %s MID %d AID %d\n", i, p->addr, status,
mid, aid);
if (p->status == wil_sta_connected) { if (p->status == wil_sta_connected) {
spin_lock_bh(&p->tid_rx_lock); spin_lock_bh(&p->tid_rx_lock);
...@@ -1461,6 +1495,42 @@ static const struct file_operations fops_sta = { ...@@ -1461,6 +1495,42 @@ static const struct file_operations fops_sta = {
.llseek = seq_lseek, .llseek = seq_lseek,
}; };
static int wil_mids_debugfs_show(struct seq_file *s, void *data)
{
struct wil6210_priv *wil = s->private;
struct wil6210_vif *vif;
struct net_device *ndev;
int i;
mutex_lock(&wil->vif_mutex);
for (i = 0; i < wil->max_vifs; i++) {
vif = wil->vifs[i];
if (vif) {
ndev = vif_to_ndev(vif);
seq_printf(s, "[%d] %pM %s\n", i, ndev->dev_addr,
ndev->name);
} else {
seq_printf(s, "[%d] unused\n", i);
}
}
mutex_unlock(&wil->vif_mutex);
return 0;
}
static int wil_mids_seq_open(struct inode *inode, struct file *file)
{
return single_open(file, wil_mids_debugfs_show, inode->i_private);
}
static const struct file_operations fops_mids = {
.open = wil_mids_seq_open,
.release = single_release,
.read = seq_read,
.llseek = seq_lseek,
};
static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf, static ssize_t wil_read_file_led_cfg(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
...@@ -1715,6 +1785,7 @@ static const struct { ...@@ -1715,6 +1785,7 @@ static const struct {
{"mbox", 0444, &fops_mbox}, {"mbox", 0444, &fops_mbox},
{"vrings", 0444, &fops_vring}, {"vrings", 0444, &fops_vring},
{"stations", 0444, &fops_sta}, {"stations", 0444, &fops_sta},
{"mids", 0444, &fops_mids},
{"desc", 0444, &fops_txdesc}, {"desc", 0444, &fops_txdesc},
{"bf", 0444, &fops_bf}, {"bf", 0444, &fops_bf},
{"mem_val", 0644, &fops_memread}, {"mem_val", 0644, &fops_memread},
...@@ -1773,11 +1844,9 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil, ...@@ -1773,11 +1844,9 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
/* fields in struct wil6210_priv */ /* fields in struct wil6210_priv */
static const struct dbg_off dbg_wil_off[] = { static const struct dbg_off dbg_wil_off[] = {
WIL_FIELD(privacy, 0444, doff_u32),
WIL_FIELD(status[0], 0644, doff_ulong), WIL_FIELD(status[0], 0644, doff_ulong),
WIL_FIELD(hw_version, 0444, doff_x32), WIL_FIELD(hw_version, 0444, doff_x32),
WIL_FIELD(recovery_count, 0444, doff_u32), WIL_FIELD(recovery_count, 0444, doff_u32),
WIL_FIELD(ap_isolate, 0444, doff_u32),
WIL_FIELD(discovery_mode, 0644, doff_u8), WIL_FIELD(discovery_mode, 0644, doff_u8),
WIL_FIELD(chip_revision, 0444, doff_u8), WIL_FIELD(chip_revision, 0444, doff_u8),
WIL_FIELD(abft_len, 0644, doff_u8), WIL_FIELD(abft_len, 0644, doff_u8),
......
/* /*
* Copyright (c) 2014,2017 Qualcomm Atheros, Inc. * Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -74,12 +75,13 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev, ...@@ -74,12 +75,13 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev,
struct ethtool_coalesce *cp) struct ethtool_coalesce *cp)
{ {
struct wil6210_priv *wil = ndev_to_wil(ndev); struct wil6210_priv *wil = ndev_to_wil(ndev);
struct wireless_dev *wdev = ndev->ieee80211_ptr;
int ret; int ret;
wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n", wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n",
cp->rx_coalesce_usecs, cp->tx_coalesce_usecs); cp->rx_coalesce_usecs, cp->tx_coalesce_usecs);
if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n"); wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#ifndef __WIL_FW_H__
#define __WIL_FW_H__
#define WIL_FW_SIGNATURE (0x36323130) /* '0126' */ #define WIL_FW_SIGNATURE (0x36323130) /* '0126' */
#define WIL_FW_FMT_VERSION (1) /* format version driver supports */ #define WIL_FW_FMT_VERSION (1) /* format version driver supports */
...@@ -71,7 +73,39 @@ struct wil_fw_record_capabilities { /* type == wil_fw_type_comment */ ...@@ -71,7 +73,39 @@ struct wil_fw_record_capabilities { /* type == wil_fw_type_comment */
struct wil_fw_record_comment_hdr hdr; struct wil_fw_record_comment_hdr hdr;
/* capabilities (variable size), see enum wmi_fw_capability */ /* capabilities (variable size), see enum wmi_fw_capability */
u8 capabilities[0]; u8 capabilities[0];
}; } __packed;
/* FW VIF concurrency encoded inside a comment record
* Format is similar to wiphy->iface_combinations
*/
#define WIL_FW_CONCURRENCY_MAGIC (0xfedccdef)
#define WIL_FW_CONCURRENCY_REC_VER 1
struct wil_fw_concurrency_limit {
__le16 max; /* maximum number of interfaces of these types */
__le16 types; /* interface types (bit mask of enum nl80211_iftype) */
} __packed;
struct wil_fw_concurrency_combo {
u8 n_limits; /* number of wil_fw_concurrency_limit entries */
u8 max_interfaces; /* max number of concurrent interfaces allowed */
u8 n_diff_channels; /* total number of different channels allowed */
u8 same_bi; /* for APs, 1 if all APs must have same BI */
/* keep last - concurrency limits, variable size by n_limits */
struct wil_fw_concurrency_limit limits[0];
} __packed;
struct wil_fw_record_concurrency { /* type == wil_fw_type_comment */
/* identifies concurrency record */
__le32 magic;
/* structure version, currently always 1 */
u8 version;
/* maximum number of supported MIDs _in addition_ to MID 0 */
u8 n_mids;
/* number of concurrency combinations that follow */
__le16 n_combos;
/* keep last - combinations, variable size by n_combos */
struct wil_fw_concurrency_combo combos[0];
} __packed;
/* brd file info encoded inside a comment record */ /* brd file info encoded inside a comment record */
#define WIL_BRD_FILE_MAGIC (0xabcddcbb) #define WIL_BRD_FILE_MAGIC (0xabcddcbb)
...@@ -175,3 +209,5 @@ struct wil_fw_record_gateway_data4 { /* type == wil_fw_type_gateway_data4 */ ...@@ -175,3 +209,5 @@ struct wil_fw_record_gateway_data4 { /* type == wil_fw_type_gateway_data4 */
__le32 command; __le32 command;
struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */ struct wil_fw_data_gw4 data[0]; /* total size [data_size], see above */
} __packed; } __packed;
#endif /* __WIL_FW_H__ */
...@@ -136,8 +136,8 @@ fw_handle_capabilities(struct wil6210_priv *wil, const void *data, ...@@ -136,8 +136,8 @@ fw_handle_capabilities(struct wil6210_priv *wil, const void *data,
size_t capa_size; size_t capa_size;
if (size < sizeof(*rec)) { if (size < sizeof(*rec)) {
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, wil_err_fw(wil, "capabilities record too short: %zu\n", size);
data, size, true); /* let the FW load anyway */
return 0; return 0;
} }
...@@ -158,8 +158,7 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data, ...@@ -158,8 +158,7 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data,
const struct wil_fw_record_brd_file *rec = data; const struct wil_fw_record_brd_file *rec = data;
if (size < sizeof(*rec)) { if (size < sizeof(*rec)) {
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1, wil_err_fw(wil, "brd_file record too short: %zu\n", size);
data, size, true);
return 0; return 0;
} }
...@@ -172,6 +171,44 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data, ...@@ -172,6 +171,44 @@ fw_handle_brd_file(struct wil6210_priv *wil, const void *data,
return 0; return 0;
} }
static int
fw_handle_concurrency(struct wil6210_priv *wil, const void *data,
size_t size)
{
const struct wil_fw_record_concurrency *rec = data;
const struct wil_fw_concurrency_combo *combo;
const struct wil_fw_concurrency_limit *limit;
size_t remain, lsize;
int i, n_combos;
if (size < sizeof(*rec)) {
wil_err_fw(wil, "concurrency record too short: %zu\n", size);
/* continue, let the FW load anyway */
return 0;
}
n_combos = le16_to_cpu(rec->n_combos);
remain = size - offsetof(struct wil_fw_record_concurrency, combos);
combo = rec->combos;
for (i = 0; i < n_combos; i++) {
if (remain < sizeof(*combo))
goto out_short;
remain -= sizeof(*combo);
limit = combo->limits;
lsize = combo->n_limits * sizeof(*limit);
if (remain < lsize)
goto out_short;
remain -= lsize;
limit += combo->n_limits;
combo = (struct wil_fw_concurrency_combo *)limit;
}
return wil_cfg80211_iface_combinations_from_fw(wil, rec);
out_short:
wil_err_fw(wil, "concurrency record truncated\n");
return 0;
}
static int static int
fw_handle_comment(struct wil6210_priv *wil, const void *data, fw_handle_comment(struct wil6210_priv *wil, const void *data,
size_t size) size_t size)
...@@ -194,6 +231,13 @@ fw_handle_comment(struct wil6210_priv *wil, const void *data, ...@@ -194,6 +231,13 @@ fw_handle_comment(struct wil6210_priv *wil, const void *data,
wil_dbg_fw(wil, "magic is WIL_BRD_FILE_MAGIC\n"); wil_dbg_fw(wil, "magic is WIL_BRD_FILE_MAGIC\n");
rc = fw_handle_brd_file(wil, data, size); rc = fw_handle_brd_file(wil, data, size);
break; break;
case WIL_FW_CONCURRENCY_MAGIC:
wil_dbg_fw(wil, "magic is WIL_FW_CONCURRENCY_MAGIC\n");
rc = fw_handle_concurrency(wil, data, size);
break;
default:
wil_hex_dump_fw("", DUMP_PREFIX_OFFSET, 16, 1,
data, size, true);
} }
return rc; return rc;
......
...@@ -127,7 +127,7 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil) ...@@ -127,7 +127,7 @@ void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
void wil6210_unmask_irq_rx(struct wil6210_priv *wil) void wil6210_unmask_irq_rx(struct wil6210_priv *wil)
{ {
bool unmask_rx_htrsh = test_bit(wil_status_fwconnected, wil->status); bool unmask_rx_htrsh = atomic_read(&wil->connected_vifs) > 0;
wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC), wil_w(wil, RGF_DMA_EP_RX_ICR + offsetof(struct RGF_ICR, IMC),
unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH); unmask_rx_htrsh ? WIL6210_IMC_RX : WIL6210_IMC_RX_NO_RX_HTRSH);
...@@ -188,12 +188,14 @@ void wil_unmask_irq(struct wil6210_priv *wil) ...@@ -188,12 +188,14 @@ void wil_unmask_irq(struct wil6210_priv *wil)
void wil_configure_interrupt_moderation(struct wil6210_priv *wil) void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
{ {
struct wireless_dev *wdev = wil->main_ndev->ieee80211_ptr;
wil_dbg_irq(wil, "configure_interrupt_moderation\n"); wil_dbg_irq(wil, "configure_interrupt_moderation\n");
/* disable interrupt moderation for monitor /* disable interrupt moderation for monitor
* to get better timestamp precision * to get better timestamp precision
*/ */
if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) if (wdev->iftype == NL80211_IFTYPE_MONITOR)
return; return;
/* Disable and clear tx counter before (re)configuration */ /* Disable and clear tx counter before (re)configuration */
...@@ -340,7 +342,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie) ...@@ -340,7 +342,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
static void wil_notify_fw_error(struct wil6210_priv *wil) static void wil_notify_fw_error(struct wil6210_priv *wil)
{ {
struct device *dev = &wil_to_ndev(wil)->dev; struct device *dev = &wil->main_ndev->dev;
char *envp[3] = { char *envp[3] = {
[0] = "SOURCE=wil6210", [0] = "SOURCE=wil6210",
[1] = "EVENT=FW_ERROR", [1] = "EVENT=FW_ERROR",
......
...@@ -137,6 +137,20 @@ void wil_enable_irq(struct wil6210_priv *wil) ...@@ -137,6 +137,20 @@ void wil_enable_irq(struct wil6210_priv *wil)
enable_irq(wil->pdev->irq); enable_irq(wil->pdev->irq);
} }
static void wil_remove_all_additional_vifs(struct wil6210_priv *wil)
{
struct wil6210_vif *vif;
int i;
for (i = 1; i < wil->max_vifs; i++) {
vif = wil->vifs[i];
if (vif) {
wil_vif_prepare_stop(vif);
wil_vif_remove(wil, vif->mid);
}
}
}
/* Bus ops */ /* Bus ops */
static int wil_if_pcie_enable(struct wil6210_priv *wil) static int wil_if_pcie_enable(struct wil6210_priv *wil)
{ {
...@@ -148,10 +162,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) ...@@ -148,10 +162,8 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
*/ */
int msi_only = pdev->msi_enabled; int msi_only = pdev->msi_enabled;
bool _use_msi = use_msi; bool _use_msi = use_msi;
bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
wil->fw_capabilities);
wil_dbg_misc(wil, "if_pcie_enable, wmi_only %d\n", wmi_only); wil_dbg_misc(wil, "if_pcie_enable\n");
pci_set_master(pdev); pci_set_master(pdev);
...@@ -172,11 +184,9 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) ...@@ -172,11 +184,9 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil)
if (rc) if (rc)
goto stop_master; goto stop_master;
/* need reset here to obtain MAC or in case of WMI-only FW, full reset /* need reset here to obtain MAC */
* and fw loading takes place
*/
mutex_lock(&wil->mutex); mutex_lock(&wil->mutex);
rc = wil_reset(wil, wmi_only); rc = wil_reset(wil, false);
mutex_unlock(&wil->mutex); mutex_unlock(&wil->mutex);
if (rc) if (rc)
goto release_irq; goto release_irq;
...@@ -356,6 +366,18 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -356,6 +366,18 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto bus_disable; goto bus_disable;
} }
/* in case of WMI-only FW, perform full reset and FW loading */
if (test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) {
wil_dbg_misc(wil, "Loading WMI only FW\n");
mutex_lock(&wil->mutex);
rc = wil_reset(wil, true);
mutex_unlock(&wil->mutex);
if (rc) {
wil_err(wil, "failed to load WMI only FW\n");
goto if_remove;
}
}
if (IS_ENABLED(CONFIG_PM)) if (IS_ENABLED(CONFIG_PM))
wil->pm_notify.notifier_call = wil6210_pm_notify; wil->pm_notify.notifier_call = wil6210_pm_notify;
...@@ -372,6 +394,8 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) ...@@ -372,6 +394,8 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0; return 0;
if_remove:
wil_if_remove(wil);
bus_disable: bus_disable:
wil_if_pcie_disable(wil); wil_if_pcie_disable(wil);
err_iounmap: err_iounmap:
...@@ -402,6 +426,7 @@ static void wil_pcie_remove(struct pci_dev *pdev) ...@@ -402,6 +426,7 @@ static void wil_pcie_remove(struct pci_dev *pdev)
wil6210_debugfs_remove(wil); wil6210_debugfs_remove(wil);
rtnl_lock(); rtnl_lock();
wil_p2p_wdev_free(wil); wil_p2p_wdev_free(wil);
wil_remove_all_additional_vifs(wil);
rtnl_unlock(); rtnl_unlock();
wil_if_remove(wil); wil_if_remove(wil);
wil_if_pcie_disable(wil); wil_if_pcie_disable(wil);
...@@ -425,12 +450,15 @@ static int wil6210_suspend(struct device *dev, bool is_runtime) ...@@ -425,12 +450,15 @@ static int wil6210_suspend(struct device *dev, bool is_runtime)
int rc = 0; int rc = 0;
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct wil6210_priv *wil = pci_get_drvdata(pdev); struct wil6210_priv *wil = pci_get_drvdata(pdev);
struct net_device *ndev = wil_to_ndev(wil); bool keep_radio_on, active_ifaces;
bool keep_radio_on = ndev->flags & IFF_UP &&
wil->keep_radio_on_during_sleep;
wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
mutex_lock(&wil->vif_mutex);
active_ifaces = wil_has_active_ifaces(wil, true, false);
mutex_unlock(&wil->vif_mutex);
keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep;
rc = wil_can_suspend(wil, is_runtime); rc = wil_can_suspend(wil, is_runtime);
if (rc) if (rc)
goto out; goto out;
...@@ -457,12 +485,15 @@ static int wil6210_resume(struct device *dev, bool is_runtime) ...@@ -457,12 +485,15 @@ static int wil6210_resume(struct device *dev, bool is_runtime)
int rc = 0; int rc = 0;
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct wil6210_priv *wil = pci_get_drvdata(pdev); struct wil6210_priv *wil = pci_get_drvdata(pdev);
struct net_device *ndev = wil_to_ndev(wil); bool keep_radio_on, active_ifaces;
bool keep_radio_on = ndev->flags & IFF_UP &&
wil->keep_radio_on_during_sleep;
wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
mutex_lock(&wil->vif_mutex);
active_ifaces = wil_has_active_ifaces(wil, true, false);
mutex_unlock(&wil->vif_mutex);
keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep;
/* In case radio stays on, platform device will control /* In case radio stays on, platform device will control
* PCIe master * PCIe master
*/ */
......
/* /*
* Copyright (c) 2012-2015,2017 Qualcomm Atheros, Inc. * Copyright (c) 2012-2015,2017 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -53,6 +54,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil, ...@@ -53,6 +54,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil,
u32 i; u32 i;
struct pmc_ctx *pmc = &wil->pmc; struct pmc_ctx *pmc = &wil->pmc;
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_pmc_cmd pmc_cmd = {0}; struct wmi_pmc_cmd pmc_cmd = {0};
int last_cmd_err = -ENOMEM; int last_cmd_err = -ENOMEM;
...@@ -186,6 +188,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil, ...@@ -186,6 +188,7 @@ void wil_pmc_alloc(struct wil6210_priv *wil,
wil_dbg_misc(wil, "pmc_alloc: send WMI_PMC_CMD with ALLOCATE op\n"); wil_dbg_misc(wil, "pmc_alloc: send WMI_PMC_CMD with ALLOCATE op\n");
pmc->last_cmd_status = wmi_send(wil, pmc->last_cmd_status = wmi_send(wil,
WMI_PMC_CMDID, WMI_PMC_CMDID,
vif->mid,
&pmc_cmd, &pmc_cmd,
sizeof(pmc_cmd)); sizeof(pmc_cmd));
if (pmc->last_cmd_status) { if (pmc->last_cmd_status) {
...@@ -236,6 +239,7 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd) ...@@ -236,6 +239,7 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd)
{ {
struct pmc_ctx *pmc = &wil->pmc; struct pmc_ctx *pmc = &wil->pmc;
struct device *dev = wil_to_dev(wil); struct device *dev = wil_to_dev(wil);
struct wil6210_vif *vif = ndev_to_vif(wil->main_ndev);
struct wmi_pmc_cmd pmc_cmd = {0}; struct wmi_pmc_cmd pmc_cmd = {0};
mutex_lock(&pmc->lock); mutex_lock(&pmc->lock);
...@@ -254,8 +258,8 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd) ...@@ -254,8 +258,8 @@ void wil_pmc_free(struct wil6210_priv *wil, int send_pmc_cmd)
wil_dbg_misc(wil, "send WMI_PMC_CMD with RELEASE op\n"); wil_dbg_misc(wil, "send WMI_PMC_CMD with RELEASE op\n");
pmc_cmd.op = WMI_PMC_RELEASE; pmc_cmd.op = WMI_PMC_RELEASE;
pmc->last_cmd_status = pmc->last_cmd_status =
wmi_send(wil, WMI_PMC_CMDID, &pmc_cmd, wmi_send(wil, WMI_PMC_CMDID, vif->mid,
sizeof(pmc_cmd)); &pmc_cmd, sizeof(pmc_cmd));
if (pmc->last_cmd_status) { if (pmc->last_cmd_status) {
wil_err(wil, wil_err(wil,
"WMI_PMC_CMD with RELEASE op failed, status %d", "WMI_PMC_CMD with RELEASE op failed, status %d",
......
/* /*
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc. * Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted, provided that the above
...@@ -63,7 +64,9 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr, ...@@ -63,7 +64,9 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
* [dword 1] * [dword 1]
* bit 0.. 3 : pkt_mode:4 * bit 0.. 3 : pkt_mode:4
* bit 4 : pkt_mode_en:1 * bit 4 : pkt_mode_en:1
* bit 5..14 : reserved0:10 * bit 5 : mac_id_en:1
* bit 6..7 : mac_id:2
* bit 8..14 : reserved0:7
* bit 15 : ack_policy_en:1 * bit 15 : ack_policy_en:1
* bit 16..19 : dst_index:4 * bit 16..19 : dst_index:4
* bit 20 : dst_index_en:1 * bit 20 : dst_index_en:1
...@@ -132,6 +135,14 @@ struct vring_tx_mac { ...@@ -132,6 +135,14 @@ struct vring_tx_mac {
#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_LEN 1 #define MAC_CFG_DESC_TX_1_PKT_MODE_EN_LEN 1
#define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10 #define MAC_CFG_DESC_TX_1_PKT_MODE_EN_MSK 0x10
#define MAC_CFG_DESC_TX_1_MAC_ID_EN_POS 5
#define MAC_CFG_DESC_TX_1_MAC_ID_EN_LEN 1
#define MAC_CFG_DESC_TX_1_MAC_ID_EN_MSK 0x20
#define MAC_CFG_DESC_TX_1_MAC_ID_POS 6
#define MAC_CFG_DESC_TX_1_MAC_ID_LEN 2
#define MAC_CFG_DESC_TX_1_MAC_ID_MSK 0xc0
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_POS 15 #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_POS 15
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1 #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_LEN 1
#define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000 #define MAC_CFG_DESC_TX_1_ACK_POLICY_EN_MSK 0x8000
...@@ -304,7 +315,7 @@ enum { ...@@ -304,7 +315,7 @@ enum {
* bit 0.. 3 : tid:4 The QoS (b3-0) TID Field * bit 0.. 3 : tid:4 The QoS (b3-0) TID Field
* bit 4.. 6 : cid:3 The Source index that was found during parsing the TA. * bit 4.. 6 : cid:3 The Source index that was found during parsing the TA.
* This field is used to define the source of the packet * This field is used to define the source of the packet
* bit 7 : reserved:1 * bit 7 : MAC_id_valid:1, 1 if MAC virtual number is valid.
* bit 8.. 9 : mid:2 The MAC virtual number * bit 8.. 9 : mid:2 The MAC virtual number
* bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type * bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type
* (management, data, control and extension) * (management, data, control and extension)
...@@ -395,6 +406,7 @@ struct vring_rx_mac { ...@@ -395,6 +406,7 @@ struct vring_rx_mac {
#define RX_DMA_D0_CMD_DMA_EOP BIT(8) #define RX_DMA_D0_CMD_DMA_EOP BIT(8)
#define RX_DMA_D0_CMD_DMA_RT BIT(9) /* always 1 */ #define RX_DMA_D0_CMD_DMA_RT BIT(9) /* always 1 */
#define RX_DMA_D0_CMD_DMA_IT BIT(10) /* interrupt */ #define RX_DMA_D0_CMD_DMA_IT BIT(10) /* interrupt */
#define RX_MAC_D0_MAC_ID_VALID BIT(7)
/* Error field */ /* Error field */
#define RX_DMA_ERROR_FCS BIT(0) #define RX_DMA_ERROR_FCS BIT(0)
...@@ -451,7 +463,8 @@ static inline int wil_rxdesc_cid(struct vring_rx_desc *d) ...@@ -451,7 +463,8 @@ static inline int wil_rxdesc_cid(struct vring_rx_desc *d)
static inline int wil_rxdesc_mid(struct vring_rx_desc *d) static inline int wil_rxdesc_mid(struct vring_rx_desc *d)
{ {
return WIL_GET_BITS(d->mac.d0, 8, 9); return (d->mac.d0 & RX_MAC_D0_MAC_ID_VALID) ?
WIL_GET_BITS(d->mac.d0, 8, 9) : 0;
} }
static inline int wil_rxdesc_ftype(struct vring_rx_desc *d) static inline int wil_rxdesc_ftype(struct vring_rx_desc *d)
...@@ -517,7 +530,8 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb) ...@@ -517,7 +530,8 @@ static inline struct vring_rx_desc *wil_skb_rxdesc(struct sk_buff *skb)
void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev); void wil_netif_rx_any(struct sk_buff *skb, struct net_device *ndev);
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb); void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb);
void wil_rx_bar(struct wil6210_priv *wil, u8 cid, u8 tid, u16 seq); void wil_rx_bar(struct wil6210_priv *wil, struct wil6210_vif *vif,
u8 cid, u8 tid, u16 seq);
struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil, struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
int size, u16 ssn); int size, u16 ssn);
void wil_tid_ampdu_rx_free(struct wil6210_priv *wil, void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册