Commit e3e72f38 authored by Kalle Valo's avatar Kalle Valo

Merge ath-next from ath.git

Major changes in ath10k:

* qca6174: enable STA transmit beamforming (TxBF) support
* disable multi-vif power save by default
parents 0cbfc065 cffb41f3
...@@ -39,7 +39,7 @@ struct ath10k_ce_pipe; ...@@ -39,7 +39,7 @@ struct ath10k_ce_pipe;
#define CE_DESC_FLAGS_GATHER (1 << 0) #define CE_DESC_FLAGS_GATHER (1 << 0)
#define CE_DESC_FLAGS_BYTE_SWAP (1 << 1) #define CE_DESC_FLAGS_BYTE_SWAP (1 << 1)
#define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC #define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC
#define CE_DESC_FLAGS_META_DATA_LSB 3 #define CE_DESC_FLAGS_META_DATA_LSB 2
struct ce_desc { struct ce_desc {
__le32 addr; __le32 addr;
......
...@@ -436,16 +436,16 @@ static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode) ...@@ -436,16 +436,16 @@ static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode)
static void ath10k_core_free_firmware_files(struct ath10k *ar) static void ath10k_core_free_firmware_files(struct ath10k *ar)
{ {
if (ar->board && !IS_ERR(ar->board)) if (!IS_ERR(ar->board))
release_firmware(ar->board); release_firmware(ar->board);
if (ar->otp && !IS_ERR(ar->otp)) if (!IS_ERR(ar->otp))
release_firmware(ar->otp); release_firmware(ar->otp);
if (ar->firmware && !IS_ERR(ar->firmware)) if (!IS_ERR(ar->firmware))
release_firmware(ar->firmware); release_firmware(ar->firmware);
if (ar->cal_file && !IS_ERR(ar->cal_file)) if (!IS_ERR(ar->cal_file))
release_firmware(ar->cal_file); release_firmware(ar->cal_file);
ar->board = NULL; ar->board = NULL;
......
...@@ -159,6 +159,25 @@ struct ath10k_fw_stats_peer { ...@@ -159,6 +159,25 @@ struct ath10k_fw_stats_peer {
u32 peer_rx_rate; /* 10x only */ u32 peer_rx_rate; /* 10x only */
}; };
struct ath10k_fw_stats_vdev {
struct list_head list;
u32 vdev_id;
u32 beacon_snr;
u32 data_snr;
u32 num_tx_frames[4];
u32 num_rx_frames;
u32 num_tx_frames_retries[4];
u32 num_tx_frames_failures[4];
u32 num_rts_fail;
u32 num_rts_success;
u32 num_rx_err;
u32 num_rx_discard;
u32 num_tx_not_acked;
u32 tx_rate_history[10];
u32 beacon_rssi_history[10];
};
struct ath10k_fw_stats_pdev { struct ath10k_fw_stats_pdev {
struct list_head list; struct list_head list;
...@@ -220,6 +239,7 @@ struct ath10k_fw_stats_pdev { ...@@ -220,6 +239,7 @@ struct ath10k_fw_stats_pdev {
struct ath10k_fw_stats { struct ath10k_fw_stats {
struct list_head pdevs; struct list_head pdevs;
struct list_head vdevs;
struct list_head peers; struct list_head peers;
}; };
...@@ -288,6 +308,7 @@ struct ath10k_vif { ...@@ -288,6 +308,7 @@ struct ath10k_vif {
bool is_started; bool is_started;
bool is_up; bool is_up;
bool spectral_enabled; bool spectral_enabled;
bool ps;
u32 aid; u32 aid;
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
...@@ -413,6 +434,12 @@ enum ath10k_fw_features { ...@@ -413,6 +434,12 @@ enum ath10k_fw_features {
*/ */
ATH10K_FW_FEATURE_WMI_10_2 = 4, ATH10K_FW_FEATURE_WMI_10_2 = 4,
/* Some firmware revisions lack proper multi-interface client powersave
* implementation. Enabling PS could result in connection drops,
* traffic stalls, etc.
*/
ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT = 5,
/* keep last */ /* keep last */
ATH10K_FW_FEATURE_COUNT, ATH10K_FW_FEATURE_COUNT,
}; };
......
...@@ -243,6 +243,16 @@ static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head) ...@@ -243,6 +243,16 @@ static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head)
} }
} }
static void ath10k_debug_fw_stats_vdevs_free(struct list_head *head)
{
struct ath10k_fw_stats_vdev *i, *tmp;
list_for_each_entry_safe(i, tmp, head, list) {
list_del(&i->list);
kfree(i);
}
}
static void ath10k_debug_fw_stats_peers_free(struct list_head *head) static void ath10k_debug_fw_stats_peers_free(struct list_head *head)
{ {
struct ath10k_fw_stats_peer *i, *tmp; struct ath10k_fw_stats_peer *i, *tmp;
...@@ -258,6 +268,7 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar) ...@@ -258,6 +268,7 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
ar->debug.fw_stats_done = false; ar->debug.fw_stats_done = false;
ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs); ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
ath10k_debug_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers); ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers);
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
} }
...@@ -273,14 +284,27 @@ static size_t ath10k_debug_fw_stats_num_peers(struct list_head *head) ...@@ -273,14 +284,27 @@ static size_t ath10k_debug_fw_stats_num_peers(struct list_head *head)
return num; return num;
} }
static size_t ath10k_debug_fw_stats_num_vdevs(struct list_head *head)
{
struct ath10k_fw_stats_vdev *i;
size_t num = 0;
list_for_each_entry(i, head, list)
++num;
return num;
}
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)
{ {
struct ath10k_fw_stats stats = {}; struct ath10k_fw_stats stats = {};
bool is_start, is_started, is_end; bool is_start, is_started, is_end;
size_t num_peers; size_t num_peers;
size_t num_vdevs;
int ret; int ret;
INIT_LIST_HEAD(&stats.pdevs); INIT_LIST_HEAD(&stats.pdevs);
INIT_LIST_HEAD(&stats.vdevs);
INIT_LIST_HEAD(&stats.peers); INIT_LIST_HEAD(&stats.peers);
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
...@@ -308,6 +332,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) ...@@ -308,6 +332,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
} }
num_peers = ath10k_debug_fw_stats_num_peers(&ar->debug.fw_stats.peers); num_peers = ath10k_debug_fw_stats_num_peers(&ar->debug.fw_stats.peers);
num_vdevs = ath10k_debug_fw_stats_num_vdevs(&ar->debug.fw_stats.vdevs);
is_start = (list_empty(&ar->debug.fw_stats.pdevs) && is_start = (list_empty(&ar->debug.fw_stats.pdevs) &&
!list_empty(&stats.pdevs)); !list_empty(&stats.pdevs));
is_end = (!list_empty(&ar->debug.fw_stats.pdevs) && is_end = (!list_empty(&ar->debug.fw_stats.pdevs) &&
...@@ -330,7 +355,13 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) ...@@ -330,7 +355,13 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
goto free; goto free;
} }
if (num_vdevs >= BITS_PER_LONG) {
ath10k_warn(ar, "dropping fw vdev stats\n");
goto free;
}
list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers); list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);
list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs);
} }
complete(&ar->debug.fw_stats_complete); complete(&ar->debug.fw_stats_complete);
...@@ -340,6 +371,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb) ...@@ -340,6 +371,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
* resources if that is not the case. * resources if that is not the case.
*/ */
ath10k_debug_fw_stats_pdevs_free(&stats.pdevs); ath10k_debug_fw_stats_pdevs_free(&stats.pdevs);
ath10k_debug_fw_stats_vdevs_free(&stats.vdevs);
ath10k_debug_fw_stats_peers_free(&stats.peers); ath10k_debug_fw_stats_peers_free(&stats.peers);
unlock: unlock:
...@@ -363,7 +395,10 @@ static int ath10k_debug_fw_stats_request(struct ath10k *ar) ...@@ -363,7 +395,10 @@ static int ath10k_debug_fw_stats_request(struct ath10k *ar)
reinit_completion(&ar->debug.fw_stats_complete); reinit_completion(&ar->debug.fw_stats_complete);
ret = ath10k_wmi_request_stats(ar, WMI_REQUEST_PEER_STAT); ret = ath10k_wmi_request_stats(ar,
WMI_STAT_PDEV |
WMI_STAT_VDEV |
WMI_STAT_PEER);
if (ret) { if (ret) {
ath10k_warn(ar, "could not request stats (%d)\n", ret); ath10k_warn(ar, "could not request stats (%d)\n", ret);
return ret; return ret;
...@@ -395,8 +430,11 @@ static void ath10k_fw_stats_fill(struct ath10k *ar, ...@@ -395,8 +430,11 @@ static void ath10k_fw_stats_fill(struct ath10k *ar,
unsigned int len = 0; unsigned int len = 0;
unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE; unsigned int buf_len = ATH10K_FW_STATS_BUF_SIZE;
const struct ath10k_fw_stats_pdev *pdev; const struct ath10k_fw_stats_pdev *pdev;
const struct ath10k_fw_stats_vdev *vdev;
const struct ath10k_fw_stats_peer *peer; const struct ath10k_fw_stats_peer *peer;
size_t num_peers; size_t num_peers;
size_t num_vdevs;
int i;
spin_lock_bh(&ar->data_lock); spin_lock_bh(&ar->data_lock);
...@@ -408,6 +446,7 @@ static void ath10k_fw_stats_fill(struct ath10k *ar, ...@@ -408,6 +446,7 @@ static void ath10k_fw_stats_fill(struct ath10k *ar,
} }
num_peers = ath10k_debug_fw_stats_num_peers(&fw_stats->peers); num_peers = ath10k_debug_fw_stats_num_peers(&fw_stats->peers);
num_vdevs = ath10k_debug_fw_stats_num_vdevs(&fw_stats->vdevs);
len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%30s\n", len += scnprintf(buf + len, buf_len - len, "%30s\n",
...@@ -529,6 +568,65 @@ static void ath10k_fw_stats_fill(struct ath10k *ar, ...@@ -529,6 +568,65 @@ static void ath10k_fw_stats_fill(struct ath10k *ar,
len += scnprintf(buf + len, buf_len - len, "%30s %10d\n", len += scnprintf(buf + len, buf_len - len, "%30s %10d\n",
"MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs); "MPDU errors (FCS, MIC, ENC)", pdev->mpdu_errs);
len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
"ath10k VDEV stats", num_vdevs);
len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
"=================");
list_for_each_entry(vdev, &fw_stats->vdevs, list) {
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"vdev id", vdev->vdev_id);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"beacon snr", vdev->beacon_snr);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"data snr", vdev->data_snr);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"num rx frames", vdev->num_rx_frames);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"num rts fail", vdev->num_rts_fail);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"num rts success", vdev->num_rts_success);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"num rx err", vdev->num_rx_err);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"num rx discard", vdev->num_rx_discard);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"num tx not acked", vdev->num_tx_not_acked);
for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames); i++)
len += scnprintf(buf + len, buf_len - len,
"%25s [%02d] %u\n",
"num tx frames", i,
vdev->num_tx_frames[i]);
for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_retries); i++)
len += scnprintf(buf + len, buf_len - len,
"%25s [%02d] %u\n",
"num tx frames retries", i,
vdev->num_tx_frames_retries[i]);
for (i = 0 ; i < ARRAY_SIZE(vdev->num_tx_frames_failures); i++)
len += scnprintf(buf + len, buf_len - len,
"%25s [%02d] %u\n",
"num tx frames failures", i,
vdev->num_tx_frames_failures[i]);
for (i = 0 ; i < ARRAY_SIZE(vdev->tx_rate_history); i++)
len += scnprintf(buf + len, buf_len - len,
"%25s [%02d] 0x%08x\n",
"tx rate history", i,
vdev->tx_rate_history[i]);
for (i = 0 ; i < ARRAY_SIZE(vdev->beacon_rssi_history); i++)
len += scnprintf(buf + len, buf_len - len,
"%25s [%02d] %u\n",
"beacon rssi history", i,
vdev->beacon_rssi_history[i]);
len += scnprintf(buf + len, buf_len - len, "\n");
}
len += scnprintf(buf + len, buf_len - len, "\n"); len += scnprintf(buf + len, buf_len - len, "\n");
len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n", len += scnprintf(buf + len, buf_len - len, "%30s (%zu)\n",
"ath10k PEER stats", num_peers); "ath10k PEER stats", num_peers);
...@@ -1900,6 +1998,7 @@ int ath10k_debug_create(struct ath10k *ar) ...@@ -1900,6 +1998,7 @@ int ath10k_debug_create(struct ath10k *ar)
return -ENOMEM; return -ENOMEM;
INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs); INIT_LIST_HEAD(&ar->debug.fw_stats.pdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.vdevs);
INIT_LIST_HEAD(&ar->debug.fw_stats.peers); INIT_LIST_HEAD(&ar->debug.fw_stats.peers);
return 0; return 0;
......
...@@ -176,7 +176,7 @@ static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt) ...@@ -176,7 +176,7 @@ static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt)
* automatically balances load wrt to CPU power. * automatically balances load wrt to CPU power.
* *
* This probably comes at a cost of lower maximum throughput but * This probably comes at a cost of lower maximum throughput but
* improves the avarage and stability. */ * improves the average and stability. */
spin_lock_bh(&htt->rx_ring.lock); spin_lock_bh(&htt->rx_ring.lock);
num_deficit = htt->rx_ring.fill_level - htt->rx_ring.fill_cnt; num_deficit = htt->rx_ring.fill_level - htt->rx_ring.fill_cnt;
num_to_fill = min(ATH10K_HTT_MAX_NUM_REFILL, num_deficit); num_to_fill = min(ATH10K_HTT_MAX_NUM_REFILL, num_deficit);
......
...@@ -611,7 +611,7 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) ...@@ -611,7 +611,7 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
ret = ath10k_vdev_setup_sync(ar); ret = ath10k_vdev_setup_sync(ar);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i: %d\n", ath10k_warn(ar, "failed to synchronize setup for monitor vdev %i start: %d\n",
vdev_id, ret); vdev_id, ret);
return ret; return ret;
} }
...@@ -658,7 +658,7 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar) ...@@ -658,7 +658,7 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar)
ret = ath10k_vdev_setup_sync(ar); ret = ath10k_vdev_setup_sync(ar);
if (ret) if (ret)
ath10k_warn(ar, "failed to synchronise monitor vdev %i: %d\n", ath10k_warn(ar, "failed to synchronize monitor vdev %i stop: %d\n",
ar->monitor_vdev_id, ret); ar->monitor_vdev_id, ret);
ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n", ath10k_dbg(ar, ATH10K_DBG_MAC, "mac monitor vdev %i stopped\n",
...@@ -927,8 +927,9 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart) ...@@ -927,8 +927,9 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, bool restart)
ret = ath10k_vdev_setup_sync(ar); ret = ath10k_vdev_setup_sync(ar);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to synchronise setup for vdev %i: %d\n", ath10k_warn(ar,
arg.vdev_id, ret); "failed to synchronize setup for vdev %i restart %d: %d\n",
arg.vdev_id, restart, ret);
return ret; return ret;
} }
...@@ -966,7 +967,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif) ...@@ -966,7 +967,7 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
ret = ath10k_vdev_setup_sync(ar); ret = ath10k_vdev_setup_sync(ar);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to syncronise setup for vdev %i: %d\n", ath10k_warn(ar, "failed to synchronize setup for vdev %i stop: %d\n",
arvif->vdev_id, ret); arvif->vdev_id, ret);
return ret; return ret;
} }
...@@ -1253,6 +1254,20 @@ static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif) ...@@ -1253,6 +1254,20 @@ static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif)
return 0; return 0;
} }
static int ath10k_mac_ps_vif_count(struct ath10k *ar)
{
struct ath10k_vif *arvif;
int num = 0;
lockdep_assert_held(&ar->conf_mutex);
list_for_each_entry(arvif, &ar->arvifs, list)
if (arvif->ps)
num++;
return num;
}
static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
{ {
struct ath10k *ar = arvif->ar; struct ath10k *ar = arvif->ar;
...@@ -1262,13 +1277,24 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) ...@@ -1262,13 +1277,24 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
enum wmi_sta_ps_mode psmode; enum wmi_sta_ps_mode psmode;
int ret; int ret;
int ps_timeout; int ps_timeout;
bool enable_ps;
lockdep_assert_held(&arvif->ar->conf_mutex); lockdep_assert_held(&arvif->ar->conf_mutex);
if (arvif->vif->type != NL80211_IFTYPE_STATION) if (arvif->vif->type != NL80211_IFTYPE_STATION)
return 0; return 0;
if (vif->bss_conf.ps) { enable_ps = arvif->ps;
if (enable_ps && ath10k_mac_ps_vif_count(ar) > 1 &&
!test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT,
ar->fw_features)) {
ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n",
arvif->vdev_id);
enable_ps = false;
}
if (enable_ps) {
psmode = WMI_STA_PS_MODE_ENABLED; psmode = WMI_STA_PS_MODE_ENABLED;
param = WMI_STA_PS_PARAM_INACTIVITY_TIME; param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
...@@ -1781,6 +1807,68 @@ static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif, ...@@ -1781,6 +1807,68 @@ static int ath10k_setup_peer_smps(struct ath10k *ar, struct ath10k_vif *arvif,
ath10k_smps_map[smps]); ath10k_smps_map[smps]);
} }
static int ath10k_mac_vif_recalc_txbf(struct ath10k *ar,
struct ieee80211_vif *vif,
struct ieee80211_sta_vht_cap vht_cap)
{
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
int ret;
u32 param;
u32 value;
if (!(ar->vht_cap_info &
(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)))
return 0;
param = ar->wmi.vdev_param->txbf;
value = 0;
if (WARN_ON(param == WMI_VDEV_PARAM_UNSUPPORTED))
return 0;
/* The following logic is correct. If a remote STA advertises support
* for being a beamformer then we should enable us being a beamformee.
*/
if (ar->vht_cap_info &
(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)) {
if (vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)
value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE;
if (vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)
value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFEE;
}
if (ar->vht_cap_info &
(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
if (vht_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE)
value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER;
if (vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE)
value |= WMI_VDEV_PARAM_TXBF_MU_TX_BFER;
}
if (value & WMI_VDEV_PARAM_TXBF_MU_TX_BFEE)
value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFEE;
if (value & WMI_VDEV_PARAM_TXBF_MU_TX_BFER)
value |= WMI_VDEV_PARAM_TXBF_SU_TX_BFER;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, param, value);
if (ret) {
ath10k_warn(ar, "failed to submit vdev param txbf 0x%x: %d\n",
value, ret);
return ret;
}
return 0;
}
/* can be called only in mac80211 callbacks due to `key_count` usage */ /* can be called only in mac80211 callbacks due to `key_count` usage */
static void ath10k_bss_assoc(struct ieee80211_hw *hw, static void ath10k_bss_assoc(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
...@@ -1789,6 +1877,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ...@@ -1789,6 +1877,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct ieee80211_sta_ht_cap ht_cap; struct ieee80211_sta_ht_cap ht_cap;
struct ieee80211_sta_vht_cap vht_cap;
struct wmi_peer_assoc_complete_arg peer_arg; struct wmi_peer_assoc_complete_arg peer_arg;
struct ieee80211_sta *ap_sta; struct ieee80211_sta *ap_sta;
int ret; int ret;
...@@ -1811,6 +1900,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ...@@ -1811,6 +1900,7 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
/* ap_sta must be accessed only within rcu section which must be left /* ap_sta must be accessed only within rcu section which must be left
* before calling ath10k_setup_peer_smps() which might sleep. */ * before calling ath10k_setup_peer_smps() which might sleep. */
ht_cap = ap_sta->ht_cap; ht_cap = ap_sta->ht_cap;
vht_cap = ap_sta->vht_cap;
ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg); ret = ath10k_peer_assoc_prepare(ar, vif, ap_sta, &peer_arg);
if (ret) { if (ret) {
...@@ -1836,6 +1926,13 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ...@@ -1836,6 +1926,13 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
return; return;
} }
ret = ath10k_mac_vif_recalc_txbf(ar, vif, vht_cap);
if (ret) {
ath10k_warn(ar, "failed to recalc txbf for vdev %i on bss %pM: %d\n",
arvif->vdev_id, bss_conf->bssid, ret);
return;
}
ath10k_dbg(ar, ATH10K_DBG_MAC, ath10k_dbg(ar, ATH10K_DBG_MAC,
"mac vdev %d up (associated) bssid %pM aid %d\n", "mac vdev %d up (associated) bssid %pM aid %d\n",
arvif->vdev_id, bss_conf->bssid, bss_conf->aid); arvif->vdev_id, bss_conf->bssid, bss_conf->aid);
...@@ -1853,6 +1950,18 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw, ...@@ -1853,6 +1950,18 @@ static void ath10k_bss_assoc(struct ieee80211_hw *hw,
} }
arvif->is_up = true; arvif->is_up = true;
/* Workaround: Some firmware revisions (tested with qca6174
* WLAN.RM.2.0-00073) have buggy powersave state machine and must be
* poked with peer param command.
*/
ret = ath10k_wmi_peer_set_param(ar, arvif->vdev_id, arvif->bssid,
WMI_PEER_DUMMY_VAR, 1);
if (ret) {
ath10k_warn(ar, "failed to poke peer %pM param for ps workaround on vdev %i: %d\n",
arvif->bssid, arvif->vdev_id, ret);
return;
}
} }
static void ath10k_bss_disassoc(struct ieee80211_hw *hw, static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
...@@ -1860,6 +1969,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, ...@@ -1860,6 +1969,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
{ {
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct ieee80211_sta_vht_cap vht_cap = {};
int ret; int ret;
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
...@@ -1874,6 +1984,13 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw, ...@@ -1874,6 +1984,13 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
arvif->def_wep_key_idx = -1; arvif->def_wep_key_idx = -1;
ret = ath10k_mac_vif_recalc_txbf(ar, vif, vht_cap);
if (ret) {
ath10k_warn(ar, "failed to recalc txbf for vdev %i: %d\n",
arvif->vdev_id, ret);
return;
}
arvif->is_up = false; arvif->is_up = false;
} }
...@@ -2554,6 +2671,17 @@ static int ath10k_start_scan(struct ath10k *ar, ...@@ -2554,6 +2671,17 @@ static int ath10k_start_scan(struct ath10k *ar,
return -ETIMEDOUT; return -ETIMEDOUT;
} }
/* If we failed to start the scan, return error code at
* this point. This is probably due to some issue in the
* firmware, but no need to wedge the driver due to that...
*/
spin_lock_bh(&ar->data_lock);
if (ar->scan.state == ATH10K_SCAN_IDLE) {
spin_unlock_bh(&ar->data_lock);
return -EINVAL;
}
spin_unlock_bh(&ar->data_lock);
/* Add a 200ms margin to account for event/command processing */ /* Add a 200ms margin to account for event/command processing */
ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout, ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
msecs_to_jiffies(arg->max_scan_time+200)); msecs_to_jiffies(arg->max_scan_time+200));
...@@ -3323,9 +3451,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ...@@ -3323,9 +3451,10 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
list_del(&arvif->list); list_del(&arvif->list);
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath10k_peer_delete(arvif->ar, arvif->vdev_id, vif->addr); ret = ath10k_wmi_peer_delete(arvif->ar, arvif->vdev_id,
vif->addr);
if (ret) if (ret)
ath10k_warn(ar, "failed to remove peer for AP vdev %i: %d\n", ath10k_warn(ar, "failed to submit AP self-peer removal on vdev %i: %d\n",
arvif->vdev_id, ret); arvif->vdev_id, ret);
kfree(arvif->u.ap.noa_data); kfree(arvif->u.ap.noa_data);
...@@ -3339,6 +3468,21 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw, ...@@ -3339,6 +3468,21 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n", ath10k_warn(ar, "failed to delete WMI vdev %i: %d\n",
arvif->vdev_id, ret); arvif->vdev_id, ret);
/* Some firmware revisions don't notify host about self-peer removal
* until after associated vdev is deleted.
*/
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
ret = ath10k_wait_for_peer_deleted(ar, arvif->vdev_id,
vif->addr);
if (ret)
ath10k_warn(ar, "failed to remove AP self-peer on vdev %i: %d\n",
arvif->vdev_id, ret);
spin_lock_bh(&ar->data_lock);
ar->num_peers--;
spin_unlock_bh(&ar->data_lock);
}
ath10k_peer_cleanup(ar, arvif->vdev_id); ath10k_peer_cleanup(ar, arvif->vdev_id);
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
...@@ -3534,7 +3678,9 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, ...@@ -3534,7 +3678,9 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
} }
if (changed & BSS_CHANGED_PS) { if (changed & BSS_CHANGED_PS) {
ret = ath10k_mac_vif_setup_ps(arvif); arvif->ps = vif->bss_conf.ps;
ret = ath10k_config_ps(ar);
if (ret) if (ret)
ath10k_warn(ar, "failed to setup ps on vdev %i: %d\n", ath10k_warn(ar, "failed to setup ps on vdev %i: %d\n",
arvif->vdev_id, ret); arvif->vdev_id, ret);
......
...@@ -104,7 +104,7 @@ static const struct ce_attr host_ce_config_wlan[] = { ...@@ -104,7 +104,7 @@ static const struct ce_attr host_ce_config_wlan[] = {
{ {
.flags = CE_ATTR_FLAGS, .flags = CE_ATTR_FLAGS,
.src_nentries = 0, .src_nentries = 0,
.src_sz_max = 512, .src_sz_max = 2048,
.dest_nentries = 512, .dest_nentries = 512,
}, },
...@@ -174,7 +174,7 @@ static const struct ce_pipe_config target_ce_config_wlan[] = { ...@@ -174,7 +174,7 @@ static const struct ce_pipe_config target_ce_config_wlan[] = {
.pipenum = __cpu_to_le32(1), .pipenum = __cpu_to_le32(1),
.pipedir = __cpu_to_le32(PIPEDIR_IN), .pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32), .nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(512), .nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS), .flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0), .reserved = __cpu_to_le32(0),
}, },
......
...@@ -110,8 +110,7 @@ struct wmi_ops { ...@@ -110,8 +110,7 @@ struct wmi_ops {
bool deliver_cab); bool deliver_cab);
struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar, struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar,
const struct wmi_wmm_params_all_arg *arg); const struct wmi_wmm_params_all_arg *arg);
struct sk_buff *(*gen_request_stats)(struct ath10k *ar, struct sk_buff *(*gen_request_stats)(struct ath10k *ar, u32 stats_mask);
enum wmi_stats_id stats_id);
struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar, struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar,
enum wmi_force_fw_hang_type type, enum wmi_force_fw_hang_type type,
u32 delay_ms); u32 delay_ms);
...@@ -816,14 +815,14 @@ ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar, ...@@ -816,14 +815,14 @@ ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
} }
static inline int static inline int
ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) ath10k_wmi_request_stats(struct ath10k *ar, u32 stats_mask)
{ {
struct sk_buff *skb; struct sk_buff *skb;
if (!ar->wmi.ops->gen_request_stats) if (!ar->wmi.ops->gen_request_stats)
return -EOPNOTSUPP; return -EOPNOTSUPP;
skb = ar->wmi.ops->gen_request_stats(ar, stats_id); skb = ar->wmi.ops->gen_request_stats(ar, stats_mask);
if (IS_ERR(skb)) if (IS_ERR(skb))
return PTR_ERR(skb); return PTR_ERR(skb);
......
...@@ -869,16 +869,57 @@ static int ath10k_wmi_tlv_op_pull_rdy_ev(struct ath10k *ar, ...@@ -869,16 +869,57 @@ static int ath10k_wmi_tlv_op_pull_rdy_ev(struct ath10k *ar,
return 0; return 0;
} }
static void ath10k_wmi_tlv_pull_vdev_stats(const struct wmi_tlv_vdev_stats *src,
struct ath10k_fw_stats_vdev *dst)
{
int i;
dst->vdev_id = __le32_to_cpu(src->vdev_id);
dst->beacon_snr = __le32_to_cpu(src->beacon_snr);
dst->data_snr = __le32_to_cpu(src->data_snr);
dst->num_rx_frames = __le32_to_cpu(src->num_rx_frames);
dst->num_rts_fail = __le32_to_cpu(src->num_rts_fail);
dst->num_rts_success = __le32_to_cpu(src->num_rts_success);
dst->num_rx_err = __le32_to_cpu(src->num_rx_err);
dst->num_rx_discard = __le32_to_cpu(src->num_rx_discard);
dst->num_tx_not_acked = __le32_to_cpu(src->num_tx_not_acked);
for (i = 0; i < ARRAY_SIZE(src->num_tx_frames); i++)
dst->num_tx_frames[i] =
__le32_to_cpu(src->num_tx_frames[i]);
for (i = 0; i < ARRAY_SIZE(src->num_tx_frames_retries); i++)
dst->num_tx_frames_retries[i] =
__le32_to_cpu(src->num_tx_frames_retries[i]);
for (i = 0; i < ARRAY_SIZE(src->num_tx_frames_failures); i++)
dst->num_tx_frames_failures[i] =
__le32_to_cpu(src->num_tx_frames_failures[i]);
for (i = 0; i < ARRAY_SIZE(src->tx_rate_history); i++)
dst->tx_rate_history[i] =
__le32_to_cpu(src->tx_rate_history[i]);
for (i = 0; i < ARRAY_SIZE(src->beacon_rssi_history); i++)
dst->beacon_rssi_history[i] =
__le32_to_cpu(src->beacon_rssi_history[i]);
}
static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar, static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar,
struct sk_buff *skb, struct sk_buff *skb,
struct ath10k_fw_stats *stats) struct ath10k_fw_stats *stats)
{ {
const void **tb; const void **tb;
const struct wmi_stats_event *ev; const struct wmi_tlv_stats_ev *ev;
const void *data; const void *data;
u32 num_pdev_stats, num_vdev_stats, num_peer_stats; u32 num_pdev_stats;
u32 num_vdev_stats;
u32 num_peer_stats;
u32 num_bcnflt_stats;
u32 num_chan_stats;
size_t data_len; size_t data_len;
int ret; int ret;
int i;
tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC); tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
if (IS_ERR(tb)) { if (IS_ERR(tb)) {
...@@ -899,8 +940,73 @@ static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar, ...@@ -899,8 +940,73 @@ static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar,
num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats); num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats); num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
num_peer_stats = __le32_to_cpu(ev->num_peer_stats); num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
num_bcnflt_stats = __le32_to_cpu(ev->num_bcnflt_stats);
num_chan_stats = __le32_to_cpu(ev->num_chan_stats);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi tlv stats update pdev %i vdev %i peer %i bcnflt %i chan %i\n",
num_pdev_stats, num_vdev_stats, num_peer_stats,
num_bcnflt_stats, num_chan_stats);
for (i = 0; i < num_pdev_stats; i++) {
const struct wmi_pdev_stats *src;
struct ath10k_fw_stats_pdev *dst;
src = data;
if (data_len < sizeof(*src))
return -EPROTO;
data += sizeof(*src);
data_len -= sizeof(*src);
dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
if (!dst)
continue;
ath10k_wmi_pull_pdev_stats_base(&src->base, dst);
ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst);
ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst);
list_add_tail(&dst->list, &stats->pdevs);
}
for (i = 0; i < num_vdev_stats; i++) {
const struct wmi_tlv_vdev_stats *src;
struct ath10k_fw_stats_vdev *dst;
src = data;
if (data_len < sizeof(*src))
return -EPROTO;
data += sizeof(*src);
data_len -= sizeof(*src);
dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
if (!dst)
continue;
WARN_ON(1); /* FIXME: not implemented yet */ ath10k_wmi_tlv_pull_vdev_stats(src, dst);
list_add_tail(&dst->list, &stats->vdevs);
}
for (i = 0; i < num_peer_stats; i++) {
const struct wmi_10x_peer_stats *src;
struct ath10k_fw_stats_peer *dst;
src = data;
if (data_len < sizeof(*src))
return -EPROTO;
data += sizeof(*src);
data_len -= sizeof(*src);
dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
if (!dst)
continue;
ath10k_wmi_pull_peer_stats(&src->old, dst);
dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate);
list_add_tail(&dst->list, &stats->peers);
}
kfree(tb); kfree(tb);
return 0; return 0;
...@@ -1604,14 +1710,12 @@ ath10k_wmi_tlv_op_gen_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id, ...@@ -1604,14 +1710,12 @@ ath10k_wmi_tlv_op_gen_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id,
const struct wmi_wmm_params_all_arg *arg) const struct wmi_wmm_params_all_arg *arg)
{ {
struct wmi_tlv_vdev_set_wmm_cmd *cmd; struct wmi_tlv_vdev_set_wmm_cmd *cmd;
struct wmi_wmm_params *wmm;
struct wmi_tlv *tlv; struct wmi_tlv *tlv;
struct sk_buff *skb; struct sk_buff *skb;
size_t len; size_t len;
void *ptr; void *ptr;
len = (sizeof(*tlv) + sizeof(*cmd)) + len = sizeof(*tlv) + sizeof(*cmd);
(4 * (sizeof(*tlv) + sizeof(*wmm)));
skb = ath10k_wmi_alloc_skb(ar, len); skb = ath10k_wmi_alloc_skb(ar, len);
if (!skb) if (!skb)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -1623,13 +1727,10 @@ ath10k_wmi_tlv_op_gen_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id, ...@@ -1623,13 +1727,10 @@ ath10k_wmi_tlv_op_gen_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id,
cmd = (void *)tlv->value; cmd = (void *)tlv->value;
cmd->vdev_id = __cpu_to_le32(vdev_id); cmd->vdev_id = __cpu_to_le32(vdev_id);
ptr += sizeof(*tlv); ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[0].params, &arg->ac_be);
ptr += sizeof(*cmd); ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[1].params, &arg->ac_bk);
ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[2].params, &arg->ac_vi);
ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_be); ath10k_wmi_set_wmm_param(&cmd->vdev_wmm_params[3].params, &arg->ac_vo);
ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_bk);
ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vi);
ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vo);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev wmm conf\n"); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev wmm conf\n");
return skb; return skb;
...@@ -2080,8 +2181,7 @@ ath10k_wmi_tlv_op_gen_pdev_set_wmm(struct ath10k *ar, ...@@ -2080,8 +2181,7 @@ ath10k_wmi_tlv_op_gen_pdev_set_wmm(struct ath10k *ar,
} }
static struct sk_buff * static struct sk_buff *
ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
enum wmi_stats_id stats_id)
{ {
struct wmi_request_stats_cmd *cmd; struct wmi_request_stats_cmd *cmd;
struct wmi_tlv *tlv; struct wmi_tlv *tlv;
...@@ -2095,7 +2195,7 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, ...@@ -2095,7 +2195,7 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar,
tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD); tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD);
tlv->len = __cpu_to_le16(sizeof(*cmd)); tlv->len = __cpu_to_le16(sizeof(*cmd));
cmd = (void *)tlv->value; cmd = (void *)tlv->value;
cmd->stats_id = __cpu_to_le32(stats_id); cmd->stats_id = __cpu_to_le32(stats_mask);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv request stats\n"); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv request stats\n");
return skb; return skb;
......
...@@ -1302,8 +1302,14 @@ struct wmi_tlv_pdev_set_wmm_cmd { ...@@ -1302,8 +1302,14 @@ struct wmi_tlv_pdev_set_wmm_cmd {
__le32 dg_type; /* no idea.. */ __le32 dg_type; /* no idea.. */
} __packed; } __packed;
struct wmi_tlv_vdev_wmm_params {
__le32 dummy;
struct wmi_wmm_params params;
} __packed;
struct wmi_tlv_vdev_set_wmm_cmd { struct wmi_tlv_vdev_set_wmm_cmd {
__le32 vdev_id; __le32 vdev_id;
struct wmi_tlv_vdev_wmm_params vdev_wmm_params[4];
} __packed; } __packed;
struct wmi_tlv_phyerr_ev { struct wmi_tlv_phyerr_ev {
...@@ -1439,6 +1445,15 @@ struct wmi_tlv_sta_keepalive_cmd { ...@@ -1439,6 +1445,15 @@ struct wmi_tlv_sta_keepalive_cmd {
__le32 interval; /* in seconds */ __le32 interval; /* in seconds */
} __packed; } __packed;
struct wmi_tlv_stats_ev {
__le32 stats_id; /* WMI_STAT_ */
__le32 num_pdev_stats;
__le32 num_vdev_stats;
__le32 num_peer_stats;
__le32 num_bcnflt_stats;
__le32 num_chan_stats;
} __packed;
void ath10k_wmi_tlv_attach(struct ath10k *ar); void ath10k_wmi_tlv_attach(struct ath10k *ar);
#endif #endif
...@@ -1125,6 +1125,25 @@ static void ath10k_wmi_event_scan_started(struct ath10k *ar) ...@@ -1125,6 +1125,25 @@ static void ath10k_wmi_event_scan_started(struct ath10k *ar)
} }
} }
static void ath10k_wmi_event_scan_start_failed(struct ath10k *ar)
{
lockdep_assert_held(&ar->data_lock);
switch (ar->scan.state) {
case ATH10K_SCAN_IDLE:
case ATH10K_SCAN_RUNNING:
case ATH10K_SCAN_ABORTING:
ath10k_warn(ar, "received scan start failed event in an invalid scan state: %s (%d)\n",
ath10k_scan_state_str(ar->scan.state),
ar->scan.state);
break;
case ATH10K_SCAN_STARTING:
complete(&ar->scan.started);
__ath10k_scan_finish(ar);
break;
}
}
static void ath10k_wmi_event_scan_completed(struct ath10k *ar) static void ath10k_wmi_event_scan_completed(struct ath10k *ar)
{ {
lockdep_assert_held(&ar->data_lock); lockdep_assert_held(&ar->data_lock);
...@@ -1292,6 +1311,7 @@ int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) ...@@ -1292,6 +1311,7 @@ int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
break; break;
case WMI_SCAN_EVENT_START_FAILED: case WMI_SCAN_EVENT_START_FAILED:
ath10k_warn(ar, "received scan start failure event\n"); ath10k_warn(ar, "received scan start failure event\n");
ath10k_wmi_event_scan_start_failed(ar);
break; break;
case WMI_SCAN_EVENT_DEQUEUED: case WMI_SCAN_EVENT_DEQUEUED:
case WMI_SCAN_EVENT_PREEMPTED: case WMI_SCAN_EVENT_PREEMPTED:
...@@ -4954,7 +4974,7 @@ ath10k_wmi_op_gen_pdev_set_wmm(struct ath10k *ar, ...@@ -4954,7 +4974,7 @@ ath10k_wmi_op_gen_pdev_set_wmm(struct ath10k *ar,
} }
static struct sk_buff * static struct sk_buff *
ath10k_wmi_op_gen_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) ath10k_wmi_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)
{ {
struct wmi_request_stats_cmd *cmd; struct wmi_request_stats_cmd *cmd;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -4964,9 +4984,10 @@ ath10k_wmi_op_gen_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id) ...@@ -4964,9 +4984,10 @@ ath10k_wmi_op_gen_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
cmd = (struct wmi_request_stats_cmd *)skb->data; cmd = (struct wmi_request_stats_cmd *)skb->data;
cmd->stats_id = __cpu_to_le32(stats_id); cmd->stats_id = __cpu_to_le32(stats_mask);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id); ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats 0x%08x\n",
stats_mask);
return skb; return skb;
} }
......
...@@ -3057,8 +3057,12 @@ struct wmi_pdev_stats_peer { ...@@ -3057,8 +3057,12 @@ struct wmi_pdev_stats_peer {
} __packed; } __packed;
enum wmi_stats_id { enum wmi_stats_id {
WMI_REQUEST_PEER_STAT = 0x01, WMI_STAT_PEER = BIT(0),
WMI_REQUEST_AP_STAT = 0x02 WMI_STAT_AP = BIT(1),
WMI_STAT_PDEV = BIT(2),
WMI_STAT_VDEV = BIT(3),
WMI_STAT_BCNFLT = BIT(4),
WMI_STAT_VDEV_RATE = BIT(5),
}; };
struct wlan_inst_rssi_args { struct wlan_inst_rssi_args {
...@@ -3093,7 +3097,7 @@ struct wmi_pdev_suspend_cmd { ...@@ -3093,7 +3097,7 @@ struct wmi_pdev_suspend_cmd {
} __packed; } __packed;
struct wmi_stats_event { struct wmi_stats_event {
__le32 stats_id; /* %WMI_REQUEST_ */ __le32 stats_id; /* WMI_STAT_ */
/* /*
* number of pdev stats event structures * number of pdev stats event structures
* (wmi_pdev_stats) 0 or 1 * (wmi_pdev_stats) 0 or 1
...@@ -3745,6 +3749,11 @@ enum wmi_10x_vdev_param { ...@@ -3745,6 +3749,11 @@ enum wmi_10x_vdev_param {
WMI_10X_VDEV_PARAM_VHT80_RATEMASK, WMI_10X_VDEV_PARAM_VHT80_RATEMASK,
}; };
#define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
#define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1)
#define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2)
#define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3)
/* slot time long */ /* slot time long */
#define WMI_VDEV_SLOT_TIME_LONG 0x1 #define WMI_VDEV_SLOT_TIME_LONG 0x1
/* slot time short */ /* slot time short */
...@@ -4436,7 +4445,8 @@ enum wmi_peer_param { ...@@ -4436,7 +4445,8 @@ enum wmi_peer_param {
WMI_PEER_AUTHORIZE = 0x3, WMI_PEER_AUTHORIZE = 0x3,
WMI_PEER_CHAN_WIDTH = 0x4, WMI_PEER_CHAN_WIDTH = 0x4,
WMI_PEER_NSS = 0x5, WMI_PEER_NSS = 0x5,
WMI_PEER_USE_4ADDR = 0x6 WMI_PEER_USE_4ADDR = 0x6,
WMI_PEER_DUMMY_VAR = 0xff, /* dummy parameter for STA PS workaround */
}; };
struct wmi_peer_set_param_cmd { struct wmi_peer_set_param_cmd {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment