diff options
30 files changed, 568 insertions, 302 deletions
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 767c7bf16975..0969e9bf5d5e 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1098,7 +1098,7 @@ static int ath10k_monitor_vdev_stop(struct ath10k *ar) ret = ath10k_wmi_vdev_stop(ar, ar->monitor_vdev_id); if (ret) - ath10k_warn(ar, "failed to to request monitor vdev %i stop: %d\n", + ath10k_warn(ar, "failed to request monitor vdev %i stop: %d\n", ar->monitor_vdev_id, ret); ret = ath10k_vdev_setup_sync(ar); diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c index 1bffe3fbea3f..7a9b9bbcdbfc 100644 --- a/drivers/net/wireless/ath/ath10k/testmode.c +++ b/drivers/net/wireless/ath/ath10k/testmode.c @@ -65,7 +65,7 @@ bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb) ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_CMD, ATH10K_TM_CMD_WMI); if (ret) { ath10k_warn(ar, - "failed to to put testmode wmi event cmd attribute: %d\n", + "failed to put testmode wmi event cmd attribute: %d\n", ret); kfree_skb(nl_skb); goto out; @@ -74,7 +74,7 @@ bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb) ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_WMI_CMDID, cmd_id); if (ret) { ath10k_warn(ar, - "failed to to put testmode wmi even cmd_id: %d\n", + "failed to put testmode wmi event cmd_id: %d\n", ret); kfree_skb(nl_skb); goto out; diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index a6572b414303..cdd40c8fc867 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -441,6 +441,7 @@ static int ath11k_ce_alloc_pipe(struct ath11k_base *ab, int ce_id) { struct ath11k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id]; const struct ce_attr *attr = &host_ce_config_wlan[ce_id]; + struct ath11k_ce_ring *ring; int nentries; int desc_sz; @@ -450,24 +451,26 @@ static int ath11k_ce_alloc_pipe(struct ath11k_base *ab, int ce_id) pipe->send_cb = ath11k_ce_send_done_cb; nentries = roundup_pow_of_two(attr->src_nentries); desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_SRC); - pipe->src_ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); - if (!pipe->src_ring) - return -ENOMEM; + ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); + if (IS_ERR(ring)) + return PTR_ERR(ring); + pipe->src_ring = ring; } if (attr->dest_nentries) { pipe->recv_cb = attr->recv_cb; nentries = roundup_pow_of_two(attr->dest_nentries); desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST); - pipe->dest_ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); - - if (!pipe->dest_ring) - return -ENOMEM; + ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); + if (IS_ERR(ring)) + return PTR_ERR(ring); + pipe->dest_ring = ring; desc_sz = ath11k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS); - pipe->status_ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); - if (!pipe->status_ring) - return -ENOMEM; + ring = ath11k_ce_alloc_ring(ab, nentries, desc_sz); + if (IS_ERR(ring)) + return PTR_ERR(ring); + pipe->status_ring = ring; } return 0; diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 5cdc9b2aee51..9e823056e673 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -651,7 +651,7 @@ static void ath11k_core_restart(struct work_struct *work) idr_destroy(&ar->txmgmt_idr); } - wake_up(&ab->wmi_sc.tx_credits_wq); + wake_up(&ab->wmi_ab.tx_credits_wq); wake_up(&ab->peer_mapping_wq); ret = ath11k_core_reconfigure_on_crash(ab); @@ -761,7 +761,7 @@ struct ath11k_base *ath11k_core_alloc(struct device *dev) INIT_LIST_HEAD(&ab->peers); init_waitqueue_head(&ab->peer_mapping_wq); - init_waitqueue_head(&ab->wmi_sc.tx_credits_wq); + init_waitqueue_head(&ab->wmi_ab.tx_credits_wq); INIT_WORK(&ab->restart_work, ath11k_core_restart); timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0); ab->dev = dev; diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 06482a5c102d..25cdcf71d0c4 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -578,7 +578,7 @@ struct ath11k_base { struct platform_device *pdev; struct device *dev; struct ath11k_qmi qmi; - struct ath11k_wmi_base wmi_sc; + struct ath11k_wmi_base wmi_ab; struct completion fw_ready; struct rproc *tgt_rproc; int num_radios; diff --git a/drivers/net/wireless/ath/ath11k/debug.c b/drivers/net/wireless/ath/ath11k/debug.c index c27fffd13a5d..f48daf17f2d2 100644 --- a/drivers/net/wireless/ath/ath11k/debug.c +++ b/drivers/net/wireless/ath/ath11k/debug.c @@ -541,7 +541,7 @@ static ssize_t ath11k_write_simulate_fw_crash(struct file *file, struct ath11k *ar = ab->pdevs[0].ar; char buf[32] = {0}; ssize_t rc; - int i, ret, radioup; + int i, ret, radioup = 0; for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; @@ -704,7 +704,7 @@ static ssize_t ath11k_write_extd_rx_stats(struct file *file, DP_RX_BUFFER_SIZE, &tlv_filter); if (ret) { - ath11k_warn(ar->ab, "failed to set rx filter for moniter status ring\n"); + ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n"); goto exit; } @@ -948,7 +948,7 @@ static ssize_t ath11k_write_pktlog_filter(struct file *file, HAL_RXDMA_MONITOR_STATUS, DP_RX_BUFFER_SIZE, &tlv_filter); if (ret) { - ath11k_warn(ar->ab, "failed to set rx filter for moniter status ring\n"); + ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n"); goto out; } diff --git a/drivers/net/wireless/ath/ath11k/debug_htt_stats.c b/drivers/net/wireless/ath/ath11k/debug_htt_stats.c index 27b301bc1a1b..090fffa5e53c 100644 --- a/drivers/net/wireless/ath/ath11k/debug_htt_stats.c +++ b/drivers/net/wireless/ath/ath11k/debug_htt_stats.c @@ -3512,7 +3512,7 @@ htt_print_rx_pdev_fw_stats_phy_err_tlv(const void *tag_buf, len += HTT_DBG_OUT(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_PHY_ERR_TLV:"); len += HTT_DBG_OUT(buf + len, buf_len - len, "mac_id__word = %u", htt_stats_buf->mac_id__word); - len += HTT_DBG_OUT(buf + len, buf_len - len, "tota_phy_err_nct = %u", + len += HTT_DBG_OUT(buf + len, buf_len - len, "total_phy_err_nct = %u", htt_stats_buf->total_phy_err_cnt); ARRAY_TO_STRING(phy_errs, @@ -4287,7 +4287,6 @@ int ath11k_dbg_htt_stats_req(struct ath11k *ar) ret = ath11k_dp_tx_htt_h2t_ext_stats_req(ar, type, &cfg_params, cookie); if (ret) { ath11k_warn(ar->ab, "failed to send htt stats request: %d\n", ret); - mutex_unlock(&ar->conf_mutex); return ret; } diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wireless/ath/ath11k/debugfs_sta.c index 3c5f931e22a9..743760c9bcae 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c @@ -129,12 +129,16 @@ void ath11k_update_per_peer_stats_from_txcompl(struct ath11k *ar, { struct ath11k_base *ab = ar->ab; struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats; + enum hal_tx_rate_stats_pkt_type pkt_type; + enum hal_tx_rate_stats_sgi sgi; + enum hal_tx_rate_stats_bw bw; struct ath11k_peer *peer; struct ath11k_sta *arsta; struct ieee80211_sta *sta; u16 rate; u8 rate_idx; int ret; + u8 mcs; rcu_read_lock(); spin_lock_bh(&ab->base_lock); @@ -150,51 +154,52 @@ void ath11k_update_per_peer_stats_from_txcompl(struct ath11k *ar, arsta = (struct ath11k_sta *)sta->drv_priv; memset(&arsta->txrate, 0, sizeof(arsta->txrate)); - - if (ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A || - ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) { - ret = ath11k_mac_hw_ratecode_to_legacy_rate(ts->mcs, - ts->pkt_type, + pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE, + ts->rate_stats); + mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS, + ts->rate_stats); + sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI, + ts->rate_stats); + bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats); + + if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A || + pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) { + ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs, + pkt_type, &rate_idx, &rate); - if (ret < 0) { - spin_unlock_bh(&ab->base_lock); - rcu_read_unlock(); - return; - } + if (ret < 0) + goto err_out; arsta->txrate.legacy = rate; - } else if (ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) { - if (ts->mcs > 7) { - ath11k_warn(ab, "Invalid HT mcs index %d\n", ts->mcs); - spin_unlock_bh(&ab->base_lock); - rcu_read_unlock(); - return; + } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) { + if (mcs > 7) { + ath11k_warn(ab, "Invalid HT mcs index %d\n", mcs); + goto err_out; } - arsta->txrate.mcs = ts->mcs + 8 * (arsta->last_txrate.nss - 1); + arsta->txrate.mcs = mcs + 8 * (arsta->last_txrate.nss - 1); arsta->txrate.flags = RATE_INFO_FLAGS_MCS; - if (ts->sgi) + if (sgi) arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; - } else if (ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) { - if (ts->mcs > 9) { - ath11k_warn(ab, "Invalid VHT mcs index %d\n", ts->mcs); - spin_unlock_bh(&ab->base_lock); - rcu_read_unlock(); - return; + } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) { + if (mcs > 9) { + ath11k_warn(ab, "Invalid VHT mcs index %d\n", mcs); + goto err_out; } - arsta->txrate.mcs = ts->mcs; + arsta->txrate.mcs = mcs; arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS; - if (ts->sgi) + if (sgi) arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; - } else { - /*TODO: update HE rates */ + } else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) { + /* TODO */ } arsta->txrate.nss = arsta->last_txrate.nss; - arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(ts->bw); + arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw); ath11k_accumulate_per_peer_tx_stats(arsta, peer_stats, rate_idx); +err_out: spin_unlock_bh(&ab->base_lock); rcu_read_unlock(); } diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index b966a16a930f..b112825a52ed 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -3,7 +3,6 @@ * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. */ -#include <linux/kfifo.h> #include "core.h" #include "dp_tx.h" #include "hal_tx.h" @@ -828,10 +827,7 @@ void ath11k_dp_free(struct ath11k_base *ab) ath11k_dp_tx_pending_cleanup, ab); idr_destroy(&dp->tx_ring[i].txbuf_idr); spin_unlock_bh(&dp->tx_ring[i].tx_idr_lock); - - spin_lock_bh(&dp->tx_ring[i].tx_status_lock); - kfifo_free(&dp->tx_ring[i].tx_status_fifo); - spin_unlock_bh(&dp->tx_ring[i].tx_status_lock); + kfree(dp->tx_ring[i].tx_status); } /* Deinit any SOC level resource */ @@ -871,17 +867,17 @@ int ath11k_dp_alloc(struct ath11k_base *ab) if (ret) goto fail_link_desc_cleanup; - size = roundup_pow_of_two(DP_TX_COMP_RING_SIZE); + size = sizeof(struct hal_wbm_release_ring) * DP_TX_COMP_RING_SIZE; for (i = 0; i < DP_TCL_NUM_RING_MAX; i++) { idr_init(&dp->tx_ring[i].txbuf_idr); spin_lock_init(&dp->tx_ring[i].tx_idr_lock); dp->tx_ring[i].tcl_data_ring_id = i; - spin_lock_init(&dp->tx_ring[i].tx_status_lock); - ret = kfifo_alloc(&dp->tx_ring[i].tx_status_fifo, size, - GFP_KERNEL); - if (ret) + dp->tx_ring[i].tx_status_head = 0; + dp->tx_ring[i].tx_status_tail = DP_TX_COMP_RING_SIZE - 1; + dp->tx_ring[i].tx_status = kmalloc(size, GFP_KERNEL); + if (!dp->tx_ring[i].tx_status) goto fail_cmn_srng_cleanup; } diff --git a/drivers/net/wireless/ath/ath11k/dp.h b/drivers/net/wireless/ath/ath11k/dp.h index f7e53509ae07..2f0980f2c762 100644 --- a/drivers/net/wireless/ath/ath11k/dp.h +++ b/drivers/net/wireless/ath/ath11k/dp.h @@ -6,7 +6,6 @@ #ifndef ATH11K_DP_H #define ATH11K_DP_H -#include <linux/kfifo.h> #include "hal_rx.h" struct ath11k_base; @@ -58,6 +57,8 @@ struct dp_rxdma_ring { int bufs_max; }; +#define ATH11K_TX_COMPL_NEXT(x) (((x) + 1) % DP_TX_COMP_RING_SIZE) + struct dp_tx_ring { u8 tcl_data_ring_id; struct dp_srng tcl_data_ring; @@ -65,11 +66,9 @@ struct dp_tx_ring { struct idr txbuf_idr; /* Protects txbuf_idr and num_pending */ spinlock_t tx_idr_lock; - DECLARE_KFIFO_PTR(tx_status_fifo, struct hal_wbm_release_ring); - /* lock to protect tx_status_fifo because tx_status_fifo can be - * accessed concurrently. - */ - spinlock_t tx_status_lock; + struct hal_wbm_release_ring *tx_status; + int tx_status_head; + int tx_status_tail; }; struct ath11k_pdev_mon_stats { diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 1b3b65c0038c..3a3dc7680622 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -1225,12 +1225,12 @@ static struct htt_ppdu_stats_info *ath11k_dp_htt_get_ppdu_desc(struct ath11k *ar, u32 ppdu_id) { - struct htt_ppdu_stats_info *ppdu_info = NULL; + struct htt_ppdu_stats_info *ppdu_info; spin_lock_bh(&ar->data_lock); if (!list_empty(&ar->ppdu_stats_info)) { list_for_each_entry(ppdu_info, &ar->ppdu_stats_info, list) { - if (ppdu_info && ppdu_info->ppdu_id == ppdu_id) { + if (ppdu_info->ppdu_id == ppdu_id) { spin_unlock_bh(&ar->data_lock); return ppdu_info; } diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index a8b9557c2346..918305dda106 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -79,7 +79,6 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, struct hal_srng *tcl_ring; struct ieee80211_hdr *hdr = (void *)skb->data; struct dp_tx_ring *tx_ring; - u8 cached_desc[HAL_TCL_DESC_LEN]; void *hal_tcl_desc; u8 pool_id; u8 hal_ring_id; @@ -167,10 +166,6 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, skb_cb->vif = arvif->vif; skb_cb->ar = ar; - memset(cached_desc, 0, HAL_TCL_DESC_LEN); - - ath11k_hal_tx_cmd_desc_setup(ab, cached_desc, &ti); - hal_ring_id = tx_ring->tcl_data_ring.ring_id; tcl_ring = &ab->hal.srng_list[hal_ring_id]; @@ -190,7 +185,8 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, goto fail_unmap_dma; } - ath11k_hal_tx_desc_sync(cached_desc, hal_tcl_desc); + ath11k_hal_tx_cmd_desc_setup(ab, hal_tcl_desc + + sizeof(struct hal_tlv_hdr), &ti); ath11k_hal_srng_access_end(ab, tcl_ring); @@ -427,6 +423,37 @@ exit: rcu_read_unlock(); } +static inline void ath11k_dp_tx_status_parse(struct ath11k_base *ab, + struct hal_wbm_release_ring *desc, + struct hal_tx_status *ts) +{ + ts->buf_rel_source = + FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE, desc->info0); + if (ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW && + ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM) + return; + + if (ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) + return; + + ts->status = FIELD_GET(HAL_WBM_RELEASE_INFO0_TQM_RELEASE_REASON, + desc->info0); + ts->ppdu_id = FIELD_GET(HAL_WBM_RELEASE_INFO1_TQM_STATUS_NUMBER, + desc->info1); + ts->try_cnt = FIELD_GET(HAL_WBM_RELEASE_INFO1_TRANSMIT_COUNT, + desc->info1); + ts->ack_rssi = FIELD_GET(HAL_WBM_RELEASE_INFO2_ACK_FRAME_RSSI, + desc->info2); + if (desc->info2 & HAL_WBM_RELEASE_INFO2_FIRST_MSDU) + ts->flags |= HAL_TX_STATUS_FLAGS_FIRST_MSDU; + ts->peer_id = FIELD_GET(HAL_WBM_RELEASE_INFO3_PEER_ID, desc->info3); + ts->tid = FIELD_GET(HAL_WBM_RELEASE_INFO3_TID, desc->info3); + if (desc->rate_stats.info0 & HAL_TX_RATE_STATS_INFO0_VALID) + ts->rate_stats = desc->rate_stats.info0; + else + ts->rate_stats = 0; +} + void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id) { struct ath11k *ar; @@ -434,47 +461,48 @@ void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id) int hal_ring_id = dp->tx_ring[ring_id].tcl_comp_ring.ring_id; struct hal_srng *status_ring = &ab->hal.srng_list[hal_ring_id]; struct sk_buff *msdu; - struct hal_wbm_release_ring tx_status; struct hal_tx_status ts; struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id]; u32 *desc; u32 msdu_id; u8 mac_id; - spin_lock_bh(&status_ring->lock); - ath11k_hal_srng_access_begin(ab, status_ring); - spin_lock_bh(&tx_ring->tx_status_lock); - while (!kfifo_is_full(&tx_ring->tx_status_fifo) && + while ((ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) != + tx_ring->tx_status_tail) && (desc = ath11k_hal_srng_dst_get_next_entry(ab, status_ring))) { - ath11k_hal_tx_status_desc_sync((void *)desc, - (void *)&tx_status); - kfifo_put(&tx_ring->tx_status_fifo, tx_status); + memcpy(&tx_ring->tx_status[tx_ring->tx_status_head], + desc, sizeof(struct hal_wbm_release_ring)); + tx_ring->tx_status_head = + ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head); } if ((ath11k_hal_srng_dst_peek(ab, status_ring) != NULL) && - kfifo_is_full(&tx_ring->tx_status_fifo)) { + (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) == tx_ring->tx_status_tail)) { /* TODO: Process pending tx_status messages when kfifo_is_full() */ ath11k_warn(ab, "Unable to process some of the tx_status ring desc because status_fifo is full\n"); } - spin_unlock_bh(&tx_ring->tx_status_lock); - ath11k_hal_srng_access_end(ab, status_ring); - spin_unlock_bh(&status_ring->lock); - spin_lock_bh(&tx_ring->tx_status_lock); - while (kfifo_get(&tx_ring->tx_status_fifo, &tx_status)) { - memset(&ts, 0, sizeof(ts)); - ath11k_hal_tx_status_parse(ab, &tx_status, &ts); + while (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_tail) != tx_ring->tx_status_head) { + struct hal_wbm_release_ring *tx_status; + u32 desc_id; + + tx_ring->tx_status_tail = + ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_tail); + tx_status = &tx_ring->tx_status[tx_ring->tx_status_tail]; + ath11k_dp_tx_status_parse(ab, tx_status, &ts); - mac_id = FIELD_GET(DP_TX_DESC_ID_MAC_ID, ts.desc_id); - msdu_id = FIELD_GET(DP_TX_DESC_ID_MSDU_ID, ts.desc_id); + desc_id = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, + tx_status->buf_addr_info.info1); + mac_id = FIELD_GET(DP_TX_DESC_ID_MAC_ID, desc_id); + msdu_id = FIELD_GET(DP_TX_DESC_ID_MSDU_ID, desc_id); if (ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) { ath11k_dp_tx_process_htt_tx_complete(ab, - (void *)&tx_status, + (void *)tx_status, mac_id, msdu_id, tx_ring); continue; @@ -496,12 +524,8 @@ void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id) if (atomic_dec_and_test(&ar->dp.num_tx_pending)) wake_up(&ar->dp.tx_empty_waitq); - /* TODO: Locking optimization so that tx_completion for an msdu - * is not called with tx_status_lock acquired - */ ath11k_dp_tx_complete_msdu(ar, msdu, &ts); } - spin_unlock_bh(&tx_ring->tx_status_lock); } int ath11k_dp_tx_send_reo_cmd(struct ath11k_base *ab, struct dp_rx_tid *rx_tid, @@ -645,8 +669,10 @@ int ath11k_dp_tx_htt_srng_setup(struct ath11k_base *ab, u32 ring_id, HAL_ADDR_MSB_REG_SHIFT; ret = ath11k_hal_srng_get_entrysize(ring_type); - if (ret < 0) - return -EINVAL; + if (ret < 0) { + ret = -EINVAL; + goto err_free; + } ring_entry_sz = ret; diff --git a/drivers/net/wireless/ath/ath11k/hal_tx.c b/drivers/net/wireless/ath/ath11k/hal_tx.c index cbe549798762..e4aa7e8a1284 100644 --- a/drivers/net/wireless/ath/ath11k/hal_tx.c +++ b/drivers/net/wireless/ath/ath11k/hal_tx.c @@ -71,79 +71,7 @@ void ath11k_hal_tx_cmd_desc_setup(struct ath11k_base *ab, void *cmd, ti->dscp_tid_tbl_idx) | FIELD_PREP(HAL_TCL_DATA_CMD_INFO3_SEARCH_INDEX, ti->bss_ast_hash); -} - -/* Commit the descriptor to hardware */ -void ath11k_hal_tx_desc_sync(void *tx_desc_cached, void *hw_desc) -{ - memcpy(hw_desc + sizeof(struct hal_tlv_hdr), tx_desc_cached, - sizeof(struct hal_tcl_data_cmd)); -} - -/* Get the descriptor status from hardware */ -void ath11k_hal_tx_status_desc_sync(void *hw_desc, void *local_desc) -{ - memcpy(local_desc, hw_desc, HAL_TX_STATUS_DESC_LEN); -} - -void ath11k_hal_tx_status_parse(struct ath11k_base *ab, - struct hal_wbm_release_ring *desc, - struct hal_tx_status *ts) -{ - ts->buf_rel_source = - FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE, desc->info0); - if (ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW && - ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM) - return; - - ts->desc_id = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, - desc->buf_addr_info.info1); - - if (ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) - return; - - ts->status = FIELD_GET(HAL_WBM_RELEASE_INFO0_TQM_RELEASE_REASON, - desc->info0); - ts->ppdu_id = FIELD_GET(HAL_WBM_RELEASE_INFO1_TQM_STATUS_NUMBER, - desc->info1); - ts->try_cnt = FIELD_GET(HAL_WBM_RELEASE_INFO1_TRANSMIT_COUNT, - desc->info1); - - ts->ack_rssi = FIELD_GET(HAL_WBM_RELEASE_INFO2_ACK_FRAME_RSSI, - desc->info2); - if (desc->info2 & HAL_WBM_RELEASE_INFO2_FIRST_MSDU) - ts->flags |= HAL_TX_STATUS_FLAGS_FIRST_MSDU; - - if (desc->info2 & HAL_WBM_RELEASE_INFO2_LAST_MSDU) - ts->flags |= HAL_TX_STATUS_FLAGS_LAST_MSDU; - - if (desc->info2 & HAL_WBM_RELEASE_INFO2_MSDU_IN_AMSDU) - ts->flags |= HAL_TX_STATUS_FLAGS_MSDU_IN_AMSDU; - - ts->peer_id = FIELD_GET(HAL_WBM_RELEASE_INFO3_PEER_ID, desc->info3); - ts->tid = FIELD_GET(HAL_WBM_RELEASE_INFO3_TID, desc->info3); - - if (!(desc->rate_stats.info0 & HAL_TX_RATE_STATS_INFO0_VALID)) - return; - - ts->flags |= HAL_TX_STATUS_FLAGS_RATE_STATS_VALID; - ts->tsf = desc->rate_stats.tsf; - ts->bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, desc->rate_stats.info0); - ts->pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE, - desc->rate_stats.info0); - if (desc->rate_stats.info0 & HAL_TX_RATE_STATS_INFO0_STBC) - ts->flags |= HAL_TX_STATUS_FLAGS_RATE_STBC; - if (desc->rate_stats.info0 & HAL_TX_RATE_STATS_INFO0_LDPC) - ts->flags |= HAL_TX_STATUS_FLAGS_RATE_LDPC; - if (desc->rate_stats.info0 & HAL_TX_RATE_STATS_INFO0_OFDMA_TX) - ts->flags |= HAL_TX_STATUS_FLAGS_OFDMA; - - ts->sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI, - desc->rate_stats.info0); - ts->mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS, - desc->rate_stats.info0); - ts->num_tones_in_ru = FIELD_GET(HAL_TX_RATE_STATS_INFO0_TONES_IN_RU, - desc->rate_stats.info0); + tcl_cmd->info4 = 0; } void ath11k_hal_tx_set_dscp_tid_map(struct ath11k_base *ab, int id) diff --git a/drivers/net/wireless/ath/ath11k/hal_tx.h b/drivers/net/wireless/ath/ath11k/hal_tx.h index 5217eaf9da50..ce48a61bfb66 100644 --- a/drivers/net/wireless/ath/ath11k/hal_tx.h +++ b/drivers/net/wireless/ath/ath11k/hal_tx.h @@ -48,29 +48,18 @@ struct hal_tx_info { /* Tx status parsed from srng desc */ struct hal_tx_status { enum hal_wbm_rel_src_module buf_rel_source; - u32 desc_id; enum hal_wbm_tqm_rel_reason status; u8 ack_rssi; - enum hal_tx_rate_stats_bw bw; - enum hal_tx_rate_stats_pkt_type pkt_type; - enum hal_tx_rate_stats_sgi sgi; - u8 mcs; - u16 num_tones_in_ru; u32 flags; /* %HAL_TX_STATUS_FLAGS_ */ - u32 tsf; u32 ppdu_id; u8 try_cnt; u8 tid; u16 peer_id; + u32 rate_stats; }; void ath11k_hal_tx_cmd_desc_setup(struct ath11k_base *ab, void *cmd, struct hal_tx_info *ti); -void ath11k_hal_tx_desc_sync(void *tx_desc_cached, void *hw_desc); -void ath11k_hal_tx_status_parse(struct ath11k_base *ab, - struct hal_wbm_release_ring *desc, - struct hal_tx_status *ts); -void ath11k_hal_tx_status_desc_sync(void *hw_desc, void *local_desc); void ath11k_hal_tx_set_dscp_tid_map(struct ath11k_base *ab, int id); int ath11k_hal_reo_cmd_send(struct ath11k_base *ab, struct hal_srng *srng, enum hal_reo_cmd_type type, diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c index 9d4115f25ceb..8f54f58b83e6 100644 --- a/drivers/net/wireless/ath/ath11k/htc.c +++ b/drivers/net/wireless/ath/ath11k/htc.c @@ -736,7 +736,7 @@ int ath11k_htc_init(struct ath11k_base *ab) htc->ab = ab; - switch (ab->wmi_sc.preferred_hw_mode) { + switch (ab->wmi_ab.preferred_hw_mode) { case WMI_HOST_HW_MODE_SINGLE: htc->wmi_ep_count = 1; break; diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 978d8768d68a..556eef9881a7 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1758,6 +1758,20 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (ret) ath11k_warn(ar->ab, "failed to update bcn template: %d\n", ret); + + if (vif->bss_conf.he_support) { + ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + WMI_VDEV_PARAM_BA_MODE, + WMI_BA_MODE_BUFFER_SIZE_256); + if (ret) + ath11k_warn(ar->ab, + "failed to set BA BUFFER SIZE 256 for vdev: %d\n", + arvif->vdev_id); + else + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "Set BA BUFFER SIZE 256 for VDEV: %d\n", + arvif->vdev_id); + } } if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) { @@ -1917,9 +1931,9 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_TWT) { if (info->twt_requester || info->twt_responder) - ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev_idx); + ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id); else - ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev_idx); + ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id); } if (changed & BSS_CHANGED_HE_OBSS_PD) @@ -3346,6 +3360,77 @@ static void ath11k_gen_ppe_thresh(struct ath11k_ppe_threshold *fw_ppet, } } +static void +ath11k_mac_filter_he_cap_mesh(struct ieee80211_he_cap_elem *he_cap_elem) +{ + u8 m; + + m = IEEE80211_HE_MAC_CAP0_TWT_RES | + IEEE80211_HE_MAC_CAP0_TWT_REQ; + he_cap_elem->mac_cap_info[0] &= ~m; + + m = IEEE80211_HE_MAC_CAP2_TRS | + IEEE80211_HE_MAC_CAP2_BCAST_TWT | + IEEE80211_HE_MAC_CAP2_MU_CASCADING; + he_cap_elem->mac_cap_info[2] &= ~m; + + m = IEEE80211_HE_MAC_CAP3_FLEX_TWT_SCHED | + IEEE80211_HE_MAC_CAP2_BCAST_TWT | + IEEE80211_HE_MAC_CAP2_MU_CASCADING; + he_cap_elem->mac_cap_info[3] &= ~m; + + m = IEEE80211_HE_MAC_CAP4_BSRP_BQRP_A_MPDU_AGG | + IEEE80211_HE_MAC_CAP4_BQR; + he_cap_elem->mac_cap_info[4] &= ~m; + + m = IEEE80211_HE_MAC_CAP5_SUBCHAN_SELECVITE_TRANSMISSION | + IEEE80211_HE_MAC_CAP5_UL_2x996_TONE_RU | + IEEE80211_HE_MAC_CAP5_PUNCTURED_SOUNDING | + IEEE80211_HE_MAC_CAP5_HT_VHT_TRIG_FRAME_RX; + he_cap_elem->mac_cap_info[5] &= ~m; + + m = IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO | + IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO; + he_cap_elem->phy_cap_info[2] &= ~m; + + m = IEEE80211_HE_PHY_CAP3_RX_HE_MU_PPDU_FROM_NON_AP_STA | + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK | + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK; + he_cap_elem->phy_cap_info[3] &= ~m; + + m = IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER; + he_cap_elem->phy_cap_info[4] &= ~m; + + m = IEEE80211_HE_PHY_CAP5_NG16_MU_FEEDBACK; + he_cap_elem->phy_cap_info[5] &= ~m; + + m = IEEE80211_HE_PHY_CAP6_CODEBOOK_SIZE_75_MU | + IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMER_FB | + IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB | + IEEE80211_HE_PHY_CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO; + he_cap_elem->phy_cap_info[6] &= ~m; + + m = IEEE80211_HE_PHY_CAP7_SRP_BASED_SR | + IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_AR | + IEEE80211_HE_PHY_CAP7_STBC_TX_ABOVE_80MHZ | + IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ; + he_cap_elem->phy_cap_info[7] &= ~m; + + m = IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | + IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | + IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | + IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; + he_cap_elem->phy_cap_info[8] &= ~m; + + m = IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM | + IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK | + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB; + he_cap_elem->phy_cap_info[9] &= ~m; +} + static int ath11k_mac_copy_he_cap(struct ath11k *ar, struct ath11k_pdev_cap *cap, struct ieee80211_sband_iftype_data *data, @@ -3362,6 +3447,7 @@ static int ath11k_mac_copy_he_cap(struct ath11k *ar, switch (i) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: break; default: @@ -3402,6 +3488,9 @@ static int ath11k_mac_copy_he_cap(struct ath11k *ar, he_cap_elem->phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; break; + case NL80211_IFTYPE_MESH_POINT: + ath11k_mac_filter_he_cap_mesh(he_cap_elem); + break; } he_cap->he_mcs_nss_supp.rx_mcs_80 = @@ -4097,6 +4186,13 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, arvif->vdev_id, ret); goto err_peer_del; } + + ret = ath11k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, false); + if (ret) { + ath11k_warn(ar->ab, "failed to disable vdev %d ps mode: %d\n", + arvif->vdev_id, ret); + goto err_peer_del; + } break; default: break; @@ -5238,7 +5334,7 @@ ath11k_mac_update_bss_chan_survey(struct ath11k *ar, lockdep_assert_held(&ar->conf_mutex); - if (!test_bit(WMI_TLV_SERVICE_BSS_CHANNEL_INFO_64, ar->ab->wmi_sc.svc_map) || + if (!test_bit(WMI_TLV_SERVICE_BSS_CHANNEL_INFO_64, ar->ab->wmi_ab.svc_map) || ar->rx_channel != channel) return; @@ -5756,7 +5852,7 @@ int ath11k_mac_allocate(struct ath11k_base *ab) ar->pdev_idx = i; ar->lmac_id = ath11k_core_get_hw_mac_id(ab, i); - ar->wmi = &ab->wmi_sc.wmi[i]; + ar->wmi = &ab->wmi_ab.wmi[i]; /* FIXME wmi[0] is already initialized during attach, * Should we do this again? */ diff --git a/drivers/net/wireless/ath/ath11k/testmode.c b/drivers/net/wireless/ath/ath11k/testmode.c index 932bee6d1740..d2dc9db01491 100644 --- a/drivers/net/wireless/ath/ath11k/testmode.c +++ b/drivers/net/wireless/ath/ath11k/testmode.c @@ -150,7 +150,7 @@ static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[]) ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", buf, buf_len); - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, buf_len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, buf_len); if (!skb) { ret = -ENOMEM; goto out; diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index b05642617b78..a9b301ceb24b 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -205,7 +205,7 @@ static int ath11k_wmi_cmd_send_nowait(struct ath11k_pdev_wmi *wmi, struct sk_buf u32 cmd_id) { struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb); - struct ath11k_base *ab = wmi->wmi_sc->ab; + struct ath11k_base *ab = wmi->wmi_ab->ab; struct wmi_cmd_hdr *cmd_hdr; int ret; u32 cmd = 0; @@ -234,7 +234,7 @@ err_pull: int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb, u32 cmd_id) { - struct ath11k_wmi_base *wmi_sc = wmi->wmi_sc; + struct ath11k_wmi_base *wmi_sc = wmi->wmi_ab; int ret = -EOPNOTSUPP; might_sleep(); @@ -448,7 +448,7 @@ static void ath11k_wmi_service_bitmap_copy(struct ath11k_pdev_wmi *wmi, for (i = 0, j = 0; i < WMI_SERVICE_BM_SIZE && j < WMI_MAX_SERVICE; i++) { do { if (wmi_svc_bm[i] & BIT(j % WMI_SERVICE_BITS_IN_SIZE32)) - set_bit(j, wmi->wmi_sc->svc_map); + set_bit(j, wmi->wmi_ab->svc_map); } while (++j % WMI_SERVICE_BITS_IN_SIZE32); } } @@ -457,7 +457,7 @@ static int ath11k_wmi_tlv_svc_rdy_parse(struct ath11k_base *ab, u16 tag, u16 len const void *ptr, void *data) { struct wmi_tlv_svc_ready_parse *svc_ready = data; - struct ath11k_pdev_wmi *wmi_handle = &ab->wmi_sc.wmi[0]; + struct ath11k_pdev_wmi *wmi_handle = &ab->wmi_ab.wmi[0]; u16 expect_len; switch (tag) { @@ -538,7 +538,7 @@ int ath11k_wmi_mgmt_send(struct ath11k *ar, u32 vdev_id, u32 buf_id, len = sizeof(*cmd) + sizeof(*frame_tlv) + roundup(buf_len, 4); - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; @@ -590,7 +590,7 @@ int ath11k_wmi_vdev_create(struct ath11k *ar, u8 *macaddr, len = sizeof(*cmd) + TLV_HDR_SIZE + (WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams)); - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; @@ -656,7 +656,7 @@ int ath11k_wmi_vdev_delete(struct ath11k *ar, u8 vdev_id) struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -683,7 +683,7 @@ int ath11k_wmi_vdev_stop(struct ath11k *ar, u8 vdev_id) struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -711,7 +711,7 @@ int ath11k_wmi_vdev_down(struct ath11k *ar, u8 vdev_id) struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -789,7 +789,7 @@ int ath11k_wmi_vdev_start(struct ath11k *ar, struct wmi_vdev_start_req_arg *arg, len = sizeof(*cmd) + sizeof(*chan) + TLV_HDR_SIZE; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; @@ -867,7 +867,7 @@ int ath11k_wmi_vdev_up(struct ath11k *ar, u32 vdev_id, u32 aid, const u8 *bssid) struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -901,7 +901,7 @@ int ath11k_wmi_send_peer_create_cmd(struct ath11k *ar, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -934,7 +934,7 @@ int ath11k_wmi_send_peer_delete_cmd(struct ath11k *ar, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -966,7 +966,7 @@ int ath11k_wmi_send_pdev_set_regdomain(struct ath11k *ar, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1006,7 +1006,7 @@ int ath11k_wmi_set_peer_param(struct ath11k *ar, const u8 *peer_addr, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1040,7 +1040,7 @@ int ath11k_wmi_send_peer_flush_tids_cmd(struct ath11k *ar, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1076,7 +1076,7 @@ int ath11k_wmi_peer_rx_reorder_queue_setup(struct ath11k *ar, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1118,7 +1118,7 @@ ath11k_wmi_rx_reord_queue_remove(struct ath11k *ar, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1154,7 +1154,7 @@ int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1178,6 +1178,36 @@ int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id, return ret; } +int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, u32 enable) +{ + struct ath11k_pdev_wmi *wmi = ar->wmi; + struct wmi_pdev_set_ps_mode_cmd *cmd; + struct sk_buff *skb; + int ret; + + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_pdev_set_ps_mode_cmd *)skb->data; + cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_STA_POWERSAVE_MODE_CMD) | + FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); + cmd->vdev_id = vdev_id; + cmd->sta_ps_mode = enable; + + ret = ath11k_wmi_cmd_send(wmi, skb, WMI_STA_POWERSAVE_MODE_CMDID); + if (ret) { + ath11k_warn(ar->ab, "failed to send WMI_PDEV_SET_PARAM cmd\n"); + dev_kfree_skb(skb); + } + + ath11k_dbg(ar->ab, ATH11K_DBG_WMI, + "WMI vdev set psmode %d vdev id %d\n", + enable, vdev_id); + + return ret; +} + int ath11k_wmi_pdev_suspend(struct ath11k *ar, u32 suspend_opt, u32 pdev_id) { @@ -1186,7 +1216,7 @@ int ath11k_wmi_pdev_suspend(struct ath11k *ar, u32 suspend_opt, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1217,7 +1247,7 @@ int ath11k_wmi_pdev_resume(struct ath11k *ar, u32 pdev_id) struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1251,7 +1281,7 @@ int ath11k_wmi_pdev_bss_chan_info_request(struct ath11k *ar, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1284,7 +1314,7 @@ int ath11k_wmi_send_set_ap_ps_param_cmd(struct ath11k *ar, u8 *peer_addr, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1319,7 +1349,7 @@ int ath11k_wmi_set_sta_ps_param(struct ath11k *ar, u32 vdev_id, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1354,7 +1384,7 @@ int ath11k_wmi_force_fw_hang_cmd(struct ath11k *ar, u32 type, u32 delay_time_ms) len = sizeof(*cmd); - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; @@ -1382,7 +1412,7 @@ int ath11k_wmi_vdev_set_param_cmd(struct ath11k *ar, u32 vdev_id, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1416,7 +1446,7 @@ int ath11k_wmi_send_stats_request_cmd(struct ath11k *ar, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1449,7 +1479,7 @@ int ath11k_wmi_send_bcn_offload_control_cmd(struct ath11k *ar, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -1490,7 +1520,7 @@ int ath11k_wmi_bcn_tmpl(struct ath11k *ar, u32 vdev_id, len = sizeof(*cmd) + sizeof(*bcn_prb_info) + TLV_HDR_SIZE + aligned_len; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; @@ -1541,7 +1571,7 @@ int ath11k_wmi_vdev_install_key(struct ath11k *ar, len = sizeof(*cmd) + TLV_HDR_SIZE + key_len_aligned; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; @@ -1687,7 +1717,7 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar, sizeof(*mcs) + TLV_HDR_SIZE + (sizeof(*he_mcs) * param->peer_he_mcs_count); - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; @@ -1953,7 +1983,7 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, roundup(params->extraie.len, sizeof(u32)); len += extraie_len_with_pad; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; @@ -2069,7 +2099,7 @@ int ath11k_wmi_send_scan_stop_cmd(struct ath11k *ar, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -2125,7 +2155,7 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar, len = sizeof(*cmd) + TLV_HDR_SIZE + sizeof(*chan_info) * chan_list->nallchans; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; @@ -2217,7 +2247,7 @@ int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id, struct sk_buff *skb; int ret, ac; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -2284,7 +2314,7 @@ int ath11k_wmi_send_dfs_phyerr_offload_enable_cmd(struct ath11k *ar, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -2321,7 +2351,7 @@ int ath11k_wmi_pdev_peer_pktlog_filter(struct ath11k *ar, u8 *addr, u8 enable) int ret, len; len = sizeof(*cmd) + sizeof(*info) + TLV_HDR_SIZE; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; @@ -2367,7 +2397,7 @@ ath11k_wmi_send_init_country_cmd(struct ath11k *ar, struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -2419,7 +2449,7 @@ int ath11k_wmi_pdev_pktlog_enable(struct ath11k *ar, u32 pktlog_filter) struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -2449,7 +2479,7 @@ int ath11k_wmi_pdev_pktlog_disable(struct ath11k *ar) struct sk_buff *skb; int ret; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, sizeof(*cmd)); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd)); if (!skb) return -ENOMEM; @@ -2474,18 +2504,18 @@ int ath11k_wmi_send_twt_enable_cmd(struct ath11k *ar, u32 pdev_id) { struct ath11k_pdev_wmi *wmi = ar->wmi; - struct ath11k_base *ab = wmi->wmi_sc->ab; + struct ath11k_base *ab = wmi->wmi_ab->ab; struct wmi_twt_enable_params_cmd *cmd; struct sk_buff *skb; int ret, len; len = sizeof(*cmd); - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; - cmd = (void *)skb->data; + cmd = (struct wmi_twt_enable_params_cmd *)skb->data; cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_TWT_ENABLE_CMD) | FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); cmd->pdev_id = pdev_id; @@ -2525,18 +2555,18 @@ int ath11k_wmi_send_twt_disable_cmd(struct ath11k *ar, u32 pdev_id) { struct ath11k_pdev_wmi *wmi = ar->wmi; - struct ath11k_base *ab = wmi->wmi_sc->ab; + struct ath11k_base *ab = wmi->wmi_ab->ab; struct wmi_twt_disable_params_cmd *cmd; struct sk_buff *skb; int ret, len; len = sizeof(*cmd); - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; - cmd = (void *)skb->data; + cmd = (struct wmi_twt_disable_params_cmd *)skb->data; cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_TWT_DISABLE_CMD) | FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); cmd->pdev_id = pdev_id; @@ -2544,7 +2574,7 @@ ath11k_wmi_send_twt_disable_cmd(struct ath11k *ar, u32 pdev_id) ret = ath11k_wmi_cmd_send(wmi, skb, WMI_TWT_DISABLE_CMDID); if (ret) { - ath11k_warn(ab, "Failed to send WMI_TWT_DIeABLE_CMDID"); + ath11k_warn(ab, "Failed to send WMI_TWT_DISABLE_CMDID"); dev_kfree_skb(skb); } return ret; @@ -2555,18 +2585,18 @@ ath11k_wmi_send_obss_spr_cmd(struct ath11k *ar, u32 vdev_id, struct ieee80211_he_obss_pd *he_obss_pd) { struct ath11k_pdev_wmi *wmi = ar->wmi; - struct ath11k_base *ab = wmi->wmi_sc->ab; + struct ath11k_base *ab = wmi->wmi_ab->ab; struct wmi_obss_spatial_reuse_params_cmd *cmd; struct sk_buff *skb; int ret, len; len = sizeof(*cmd); - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; - cmd = (void *)skb->data; + cmd = (struct wmi_obss_spatial_reuse_params_cmd *)skb->data; cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_OBSS_SPATIAL_REUSE_SET_CMD) | FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); @@ -2684,7 +2714,7 @@ ath11k_wmi_copy_resource_config(struct wmi_resource_config *wmi_cfg, static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi, struct wmi_init_cmd_param *param) { - struct ath11k_base *ab = wmi->wmi_sc->ab; + struct ath11k_base *ab = wmi->wmi_ab->ab; struct sk_buff *skb; struct wmi_init_cmd *cmd; struct wmi_resource_config *cfg; @@ -2704,7 +2734,7 @@ static int ath11k_init_cmd_send(struct ath11k_pdev_wmi *wmi, len = sizeof(*cmd) + TLV_HDR_SIZE + sizeof(*cfg) + hw_mode_len + (sizeof(*host_mem_chunks) * WMI_MAX_MEM_REQS); - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) return -ENOMEM; @@ -2799,7 +2829,7 @@ int ath11k_wmi_wait_for_service_ready(struct ath11k_base *ab) { unsigned long time_left; - time_left = wait_for_completion_timeout(&ab->wmi_sc.service_ready, + time_left = wait_for_completion_timeout(&ab->wmi_ab.service_ready, WMI_SERVICE_READY_TIMEOUT_HZ); if (!time_left) return -ETIMEDOUT; @@ -2811,7 +2841,7 @@ int ath11k_wmi_wait_for_unified_ready(struct ath11k_base *ab) { unsigned long time_left; - time_left = wait_for_completion_timeout(&ab->wmi_sc.unified_ready, + time_left = wait_for_completion_timeout(&ab->wmi_ab.unified_ready, WMI_SERVICE_READY_TIMEOUT_HZ); if (!time_left) return -ETIMEDOUT; @@ -2821,7 +2851,7 @@ int ath11k_wmi_wait_for_unified_ready(struct ath11k_base *ab) int ath11k_wmi_cmd_init(struct ath11k_base *ab) { - struct ath11k_wmi_base *wmi_sc = &ab->wmi_sc; + struct ath11k_wmi_base *wmi_sc = &ab->wmi_ab; struct wmi_init_cmd_param init_param; struct target_resource_config config; @@ -2941,16 +2971,16 @@ static int ath11k_wmi_tlv_hw_mode_caps(struct ath11k_base *soc, while (i < svc_rdy_ext->n_hw_mode_caps) { hw_mode_caps = &svc_rdy_ext->hw_mode_caps[i]; mode = hw_mode_caps->hw_mode_id; - pref = soc->wmi_sc.preferred_hw_mode; + pref = soc->wmi_ab.preferred_hw_mode; if (ath11k_hw_mode_pri_map[mode] < ath11k_hw_mode_pri_map[pref]) { svc_rdy_ext->pref_hw_mode_caps = *hw_mode_caps; - soc->wmi_sc.preferred_hw_mode = mode; + soc->wmi_ab.preferred_hw_mode = mode; } i++; } - if (soc->wmi_sc.preferred_hw_mode == WMI_HOST_HW_MODE_MAX) + if (soc->wmi_ab.preferred_hw_mode == WMI_HOST_HW_MODE_MAX) return -EINVAL; return 0; @@ -3000,7 +3030,7 @@ static int ath11k_wmi_tlv_ext_hal_reg_caps_parse(struct ath11k_base *soc, static int ath11k_wmi_tlv_ext_hal_reg_caps(struct ath11k_base *soc, u16 len, const void *ptr, void *data) { - struct ath11k_pdev_wmi *wmi_handle = &soc->wmi_sc.wmi[0]; + struct ath11k_pdev_wmi *wmi_handle = &soc->wmi_ab.wmi[0]; struct wmi_tlv_svc_rdy_ext_parse *svc_rdy_ext = data; struct ath11k_hal_reg_capabilities_ext reg_cap; int ret; @@ -3036,7 +3066,7 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc, u16 len, const void *ptr, void *data) { - struct ath11k_pdev_wmi *wmi_handle = &soc->wmi_sc.wmi[0]; + struct ath11k_pdev_wmi *wmi_handle = &soc->wmi_ab.wmi[0]; struct wmi_tlv_svc_rdy_ext_parse *svc_rdy_ext = data; u8 hw_mode_id = svc_rdy_ext->pref_hw_mode_caps.hw_mode_id; u32 phy_id_map; @@ -3074,7 +3104,7 @@ static int ath11k_wmi_tlv_svc_rdy_ext_parse(struct ath11k_base *ab, u16 tag, u16 len, const void *ptr, void *data) { - struct ath11k_pdev_wmi *wmi_handle = &ab->wmi_sc.wmi[0]; + struct ath11k_pdev_wmi *wmi_handle = &ab->wmi_ab.wmi[0]; struct wmi_tlv_svc_rdy_ext_parse *svc_rdy_ext = data; int ret; @@ -3126,7 +3156,7 @@ static int ath11k_wmi_tlv_svc_rdy_ext_parse(struct ath11k_base *ab, return ret; svc_rdy_ext->ext_hal_reg_done = true; - complete(&ab->wmi_sc.service_ready); + complete(&ab->wmi_ab.service_ready); } break; @@ -4468,7 +4498,7 @@ unlock: static void ath11k_wmi_op_ep_tx_credits(struct ath11k_base *ab) { /* try to send pending beacons first. they take priority */ - wake_up(&ab->wmi_sc.tx_credits_wq); + wake_up(&ab->wmi_ab.tx_credits_wq); } static void ath11k_wmi_htc_tx_complete(struct ath11k_base *ab, @@ -4522,7 +4552,7 @@ static int ath11k_reg_chan_list_event(struct ath11k_base *ab, struct sk_buff *sk if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] && !memcmp((char *)ab->default_regd[pdev_idx]->alpha2, (char *)reg_info->alpha2, 2)) - return 0; + goto mem_free; /* Intersect new rules with default regd if a new country setting was * requested, i.e a default regd was already set during initialization @@ -4638,7 +4668,7 @@ static int ath11k_ready_event(struct ath11k_base *ab, struct sk_buff *skb) return ret; } - complete(&ab->wmi_sc.unified_ready); + complete(&ab->wmi_ab.unified_ready); return 0; } @@ -5289,7 +5319,7 @@ static void ath11k_service_available_event(struct ath11k_base *ab, struct sk_buf do { if (ev->wmi_service_segment_bitmap[i] & BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32)) - set_bit(j, ab->wmi_sc.svc_map); + set_bit(j, ab->wmi_ab.svc_map); } while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32); } @@ -5609,9 +5639,9 @@ static int ath11k_connect_pdev_htc_service(struct ath11k_base *ab, return status; } - ab->wmi_sc.wmi_endpoint_id[pdev_idx] = conn_resp.eid; - ab->wmi_sc.wmi[pdev_idx].eid = conn_resp.eid; - ab->wmi_sc.max_msg_len[pdev_idx] = conn_resp.max_msg_len; + ab->wmi_ab.wmi_endpoint_id[pdev_idx] = conn_resp.eid; + ab->wmi_ab.wmi[pdev_idx].eid = conn_resp.eid; + ab->wmi_ab.max_msg_len[pdev_idx] = conn_resp.max_msg_len; return 0; } @@ -5634,7 +5664,7 @@ ath11k_wmi_send_unit_test_cmd(struct ath11k *ar, arg_len = sizeof(u32) * ut_cmd.num_args; buf_len = sizeof(ut_cmd) + arg_len + TLV_HDR_SIZE; - skb = ath11k_wmi_alloc_skb(wmi->wmi_sc, buf_len); + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, buf_len); if (!skb) return -ENOMEM; @@ -5741,11 +5771,11 @@ int ath11k_wmi_pdev_attach(struct ath11k_base *ab, if (pdev_id >= MAX_RADIOS) return -EINVAL; - wmi_handle = &ab->wmi_sc.wmi[pdev_id]; + wmi_handle = &ab->wmi_ab.wmi[pdev_id]; - wmi_handle->wmi_sc = &ab->wmi_sc; + wmi_handle->wmi_ab = &ab->wmi_ab; - ab->wmi_sc.ab = ab; + ab->wmi_ab.ab = ab; /* TODO: Init remaining resource specific to pdev */ return 0; @@ -5759,12 +5789,12 @@ int ath11k_wmi_attach(struct ath11k_base *ab) if (ret) return ret; - ab->wmi_sc.ab = ab; - ab->wmi_sc.preferred_hw_mode = WMI_HOST_HW_MODE_MAX; + ab->wmi_ab.ab = ab; + ab->wmi_ab.preferred_hw_mode = WMI_HOST_HW_MODE_MAX; /* TODO: Init remaining wmi soc resources required */ - init_completion(&ab->wmi_sc.service_ready); - init_completion(&ab->wmi_sc.unified_ready); + init_completion(&ab->wmi_ab.service_ready); + init_completion(&ab->wmi_ab.unified_ready); return 0; } diff --git a/drivers/net/wireless/ath/ath11k/wmi.h b/drivers/net/wireless/ath/ath11k/wmi.h index 4a518d406bc5..1fde15c762ad 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.h +++ b/drivers/net/wireless/ath/ath11k/wmi.h @@ -44,7 +44,7 @@ struct wmi_tlv { #define WMI_TLV_LEN GENMASK(15, 0) #define WMI_TLV_TAG GENMASK(31, 16) -#define TLV_HDR_SIZE FIELD_SIZEOF(struct wmi_tlv, header) +#define TLV_HDR_SIZE sizeof_field(struct wmi_tlv, header) #define WMI_CMD_HDR_CMD_ID GENMASK(23, 0) #define WMI_MAX_MEM_REQS 32 @@ -54,6 +54,7 @@ struct wmi_tlv { #define WLAN_SCAN_PARAMS_MAX_BSSID 4 #define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 +#define WMI_BA_MODE_BUFFER_SIZE_256 3 /* * HW mode config type replicated from FW header * @WMI_HOST_HW_MODE_SINGLE: Only one PHY is active. @@ -1003,6 +1004,7 @@ enum wmi_tlv_vdev_param { WMI_VDEV_PARAM_HE_RANGE_EXT, WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE, WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME, + WMI_VDEV_PARAM_BA_MODE = 0x7e, WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE = 0x87, WMI_VDEV_PARAM_PROTOTYPE = 0x8000, WMI_VDEV_PARAM_BSS_COLOR, @@ -2354,7 +2356,7 @@ struct wmi_service_available_event { } __packed; struct ath11k_pdev_wmi { - struct ath11k_wmi_base *wmi_sc; + struct ath11k_wmi_base *wmi_ab; enum ath11k_htc_ep_id eid; const struct wmi_peer_flags_map *peer_flags; u32 rx_decap_mode; @@ -2567,7 +2569,7 @@ static inline const char *ath11k_wmi_phymode_str(enum wmi_phy_mode mode) /* no default handler to allow compiler to check that the * enum is fully handled */ - }; + } return "<unknown>"; } @@ -2827,6 +2829,12 @@ struct wmi_pdev_set_param_cmd { u32 param_value; } __packed; +struct wmi_pdev_set_ps_mode_cmd { + u32 tlv_header; + u32 vdev_id; + u32 sta_ps_mode; +} __packed; + struct wmi_pdev_suspend_cmd { u32 tlv_header; u32 pdev_id; @@ -2896,15 +2904,6 @@ struct wmi_bcn_offload_ctrl_cmd { u32 bcn_ctrl_op; } __packed; -enum scan_priority { - SCAN_PRIORITY_VERY_LOW, - SCAN_PRIORITY_LOW, - SCAN_PRIORITY_MEDIUM, - SCAN_PRIORITY_HIGH, - SCAN_PRIORITY_VERY_HIGH, - SCAN_PRIORITY_COUNT, -}; - enum scan_dwelltime_adaptive_mode { SCAN_DWELL_MODE_DEFAULT = 0, SCAN_DWELL_MODE_CONSERVATIVE = 1, @@ -3056,7 +3055,7 @@ struct scan_req_params { u32 scan_req_id; u32 vdev_id; u32 pdev_id; - enum scan_priority scan_priority; + enum wmi_scan_priority scan_priority; union { struct { u32 scan_ev_started:1, @@ -4556,12 +4555,12 @@ struct wmi_twt_enable_params_cmd { u32 mode_check_interval; u32 add_sta_slot_interval; u32 remove_sta_slot_interval; -}; +} __packed; struct wmi_twt_disable_params_cmd { u32 tlv_header; u32 pdev_id; -}; +} __packed; struct wmi_obss_spatial_reuse_params_cmd { u32 tlv_header; @@ -4570,7 +4569,7 @@ struct wmi_obss_spatial_reuse_params_cmd { s32 obss_min; s32 obss_max; u32 vdev_id; -}; +} __packed; struct target_resource_config { u32 num_vdevs; @@ -4682,6 +4681,7 @@ int ath11k_wmi_set_peer_param(struct ath11k *ar, const u8 *peer_addr, u32 vdev_id, u32 param_id, u32 param_val); int ath11k_wmi_pdev_set_param(struct ath11k *ar, u32 param_id, u32 param_value, u8 pdev_id); +int ath11k_wmi_pdev_set_ps_mode(struct ath11k *ar, int vdev_id, u32 enable); int ath11k_wmi_wait_for_unified_ready(struct ath11k_base *ab); int ath11k_wmi_cmd_init(struct ath11k_base *ab); int ath11k_wmi_wait_for_service_ready(struct ath11k_base *ab); diff --git a/drivers/net/wireless/ath/ath9k/hif_usb.c b/drivers/net/wireless/ath/ath9k/hif_usb.c index fb649d85b8fc..dd0c32379375 100644 --- a/drivers/net/wireless/ath/ath9k/hif_usb.c +++ b/drivers/net/wireless/ath/ath9k/hif_usb.c @@ -1216,7 +1216,7 @@ err_fw: static int send_eject_command(struct usb_interface *interface) { struct usb_device *udev = interface_to_usbdev(interface); - struct usb_host_interface *iface_desc = &interface->altsetting[0]; + struct usb_host_interface *iface_desc = interface->cur_altsetting; struct usb_endpoint_descriptor *endpoint; unsigned char *cmd; u8 bulk_out_ep; diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index c30fdd0cbf1e..e49c306e0eef 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -1169,7 +1169,6 @@ static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) ieee80211_hw_set(wcn->hw, TIMING_BEACON_ONLY); ieee80211_hw_set(wcn->hw, AMPDU_AGGREGATION); - ieee80211_hw_set(wcn->hw, CONNECTION_MONITOR); ieee80211_hw_set(wcn->hw, SUPPORTS_PS); ieee80211_hw_set(wcn->hw, SIGNAL_DBM); ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL); diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 7d6f14420855..0851d2bede89 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -2579,6 +2579,38 @@ wil_cfg80211_update_ft_ies(struct wiphy *wiphy, struct net_device *dev, return rc; } +static int wil_cfg80211_set_multicast_to_unicast(struct wiphy *wiphy, + struct net_device *dev, + const bool enabled) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + + if (wil->multicast_to_unicast == enabled) + return 0; + + wil_info(wil, "set multicast to unicast, enabled=%d\n", enabled); + wil->multicast_to_unicast = enabled; + + return 0; +} + +static int wil_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, + struct net_device *dev, + s32 rssi_thold, u32 rssi_hyst) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + + wil->cqm_rssi_thold = rssi_thold; + + rc = wmi_set_cqm_rssi_config(wil, rssi_thold, rssi_hyst); + if (rc) + /* reset stored value upon failure */ + wil->cqm_rssi_thold = 0; + + return rc; +} + static const struct cfg80211_ops wil_cfg80211_ops = { .add_virtual_intf = wil_cfg80211_add_iface, .del_virtual_intf = wil_cfg80211_del_iface, @@ -2610,11 +2642,13 @@ static const struct cfg80211_ops wil_cfg80211_ops = { .start_p2p_device = wil_cfg80211_start_p2p_device, .stop_p2p_device = wil_cfg80211_stop_p2p_device, .set_power_mgmt = wil_cfg80211_set_power_mgmt, + .set_cqm_rssi_config = wil_cfg80211_set_cqm_rssi_config, .suspend = wil_cfg80211_suspend, .resume = wil_cfg80211_resume, .sched_scan_start = wil_cfg80211_sched_scan_start, .sched_scan_stop = wil_cfg80211_sched_scan_stop, .update_ft_ies = wil_cfg80211_update_ft_ies, + .set_multicast_to_unicast = wil_cfg80211_set_multicast_to_unicast, }; static void wil_wiphy_init(struct wiphy *wiphy) diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c index 06091d8a9e23..6d39547e20fd 100644 --- a/drivers/net/wireless/ath/wil6210/main.c +++ b/drivers/net/wireless/ath/wil6210/main.c @@ -1654,6 +1654,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) /* Disable device led before reset*/ wmi_led_cfg(wil, false); + down_write(&wil->mem_lock); + /* prevent NAPI from being scheduled and prevent wmi commands */ mutex_lock(&wil->wmi_mutex); if (test_bit(wil_status_suspending, wil->status)) @@ -1702,6 +1704,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) if (wil->secured_boot) { wil_err(wil, "secured boot is not supported\n"); + up_write(&wil->mem_lock); return -ENOTSUPP; } @@ -1737,6 +1740,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) clear_bit(wil_status_resetting, wil->status); + up_write(&wil->mem_lock); + if (load_fw) { wil_unmask_irq(wil); @@ -1786,6 +1791,7 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) return rc; out: + up_write(&wil->mem_lock); clear_bit(wil_status_resetting, wil->status); return rc; } @@ -1811,9 +1817,7 @@ int __wil_up(struct wil6210_priv *wil) WARN_ON(!mutex_is_locked(&wil->mutex)); - down_write(&wil->mem_lock); rc = wil_reset(wil, true); - up_write(&wil->mem_lock); if (rc) return rc; @@ -1905,9 +1909,7 @@ int __wil_down(struct wil6210_priv *wil) wil_abort_scan_all_vifs(wil, false); mutex_unlock(&wil->vif_mutex); - down_write(&wil->mem_lock); rc = wil_reset(wil, false); - up_write(&wil->mem_lock); return rc; } diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 8ebc6d59aa74..17118d643d7e 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -10,6 +10,7 @@ #include <linux/moduleparam.h> #include <linux/ip.h> #include <linux/ipv6.h> +#include <linux/if_vlan.h> #include <net/ipv6.h> #include <linux/prefetch.h> @@ -1529,6 +1530,35 @@ static struct wil_ring *wil_find_tx_bcast_1(struct wil6210_priv *wil, return v; } +/* apply multicast to unicast only for ARP and IP packets + * (see NL80211_CMD_SET_MULTICAST_TO_UNICAST for more info) + */ +static bool wil_check_multicast_to_unicast(struct wil6210_priv *wil, + struct sk_buff *skb) +{ + const struct ethhdr *eth = (void *)skb->data; + const struct vlan_ethhdr *ethvlan = (void *)skb->data; + __be16 ethertype; + + if (!wil->multicast_to_unicast) + return false; + + /* multicast to unicast conversion only for some payload */ + ethertype = eth->h_proto; + if (ethertype == htons(ETH_P_8021Q) && skb->len >= VLAN_ETH_HLEN) + ethertype = ethvlan->h_vlan_encapsulated_proto; + switch (ethertype) { + case htons(ETH_P_ARP): + case htons(ETH_P_IP): + case htons(ETH_P_IPV6): + break; + default: + return false; + } + + return true; +} + static void wil_set_da_for_vring(struct wil6210_priv *wil, struct sk_buff *skb, int vring_index) { @@ -2336,7 +2366,7 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* in STA mode (ESS), all to same VRING (to AP) */ ring = wil_find_tx_ring_sta(wil, vif, skb); } else if (bcast) { - if (vif->pbss) + if (vif->pbss || wil_check_multicast_to_unicast(wil, skb)) /* in pbss, no bcast VRING - duplicate skb in * all stations VRINGs */ diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.c b/drivers/net/wireless/ath/wil6210/txrx_edma.c index 02548d40253c..7bfe867c7509 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.c +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.c @@ -903,6 +903,11 @@ again: if (unlikely(!wil_val_in_range(buff_id, 1, wil->rx_buff_mgmt.size))) { wil_err(wil, "Corrupt buff_id=%d, sring->swhead=%d\n", buff_id, sring->swhead); + print_hex_dump(KERN_ERR, "RxS ", DUMP_PREFIX_OFFSET, 16, 1, + msg, wil->use_compressed_rx_status ? + sizeof(struct wil_rx_status_compressed) : + sizeof(struct wil_rx_status_extended), false); + wil_rx_status_reset_buff_id(sring); wil_sring_advance_swhead(sring); sring->invalid_buff_id_cnt++; @@ -963,6 +968,11 @@ again: if (unlikely(dmalen > sz)) { wil_err(wil, "Rx size too large: %d bytes!\n", dmalen); + print_hex_dump(KERN_ERR, "RxS ", DUMP_PREFIX_OFFSET, 16, 1, + msg, wil->use_compressed_rx_status ? + sizeof(struct wil_rx_status_compressed) : + sizeof(struct wil_rx_status_extended), false); + stats->rx_large_frame++; rxdata->skipping = true; } diff --git a/drivers/net/wireless/ath/wil6210/txrx_edma.h b/drivers/net/wireless/ath/wil6210/txrx_edma.h index c744c65225da..c736f7413a35 100644 --- a/drivers/net/wireless/ath/wil6210/txrx_edma.h +++ b/drivers/net/wireless/ath/wil6210/txrx_edma.h @@ -46,7 +46,7 @@ #define WIL_RX_EDMA_DLPF_LU_MISS_TID_POS 5 -#define WIL_RX_EDMA_MID_VALID_BIT BIT(22) +#define WIL_RX_EDMA_MID_VALID_BIT BIT(20) #define WIL_EDMA_DESC_TX_MAC_CFG_0_QID_POS 16 #define WIL_EDMA_DESC_TX_MAC_CFG_0_QID_LEN 6 @@ -244,8 +244,8 @@ struct wil_ring_tx_status { * calculated, Bit1- L4Err - TCP/UDP Checksum Error * bit 7 : Reserved:1 * bit 8..19 : Flow ID:12 - MSDU flow ID - * bit 20..21 : MID:2 - The MAC ID - * bit 22 : MID_V:1 - The MAC ID field is valid + * bit 20 : MID_V:1 - The MAC ID field is valid + * bit 21..22 : MID:2 - The MAC ID * bit 23 : L3T:1 - IP types: 0-IPv6, 1-IPv4 * bit 24 : L4T:1 - Layer 4 Type: 0-UDP, 1-TCP * bit 25 : BC:1 - The received MPDU is broadcast @@ -479,7 +479,7 @@ static inline int wil_rx_status_get_mid(void *msg) return 0; /* use the default MID */ return WIL_GET_BITS(((struct wil_rx_status_compressed *)msg)->d0, - 20, 21); + 21, 22); } static inline int wil_rx_status_get_error(void *msg) diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 97626bfd4dac..5dc881d3c057 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -1059,6 +1059,8 @@ struct wil6210_priv { u32 max_agg_wsize; u32 max_ampdu_size; + u8 multicast_to_unicast; + s32 cqm_rssi_thold; }; #define wil_to_wiphy(i) (i->wiphy) @@ -1148,7 +1150,7 @@ static inline void wil_c(struct wil6210_priv *wil, u32 reg, u32 val) */ static inline bool wil_cid_valid(struct wil6210_priv *wil, int cid) { - return (cid >= 0 && cid < wil->max_assoc_sta); + return (cid >= 0 && cid < wil->max_assoc_sta && cid < WIL6210_MAX_CID); } void wil_get_board_file(struct wil6210_priv *wil, char *buf, size_t len); @@ -1440,4 +1442,6 @@ int wmi_addba_rx_resp_edma(struct wil6210_priv *wil, u8 mid, u8 cid, void update_supported_bands(struct wil6210_priv *wil); void wil_clear_fw_log_addr(struct wil6210_priv *wil); +int wmi_set_cqm_rssi_config(struct wil6210_priv *wil, + s32 rssi_thold, u32 rssi_hyst); #endif /* __WIL6210_H__ */ diff --git a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c index 1332eb8c831f..89c12cb2aaab 100644 --- a/drivers/net/wireless/ath/wil6210/wil_crash_dump.c +++ b/drivers/net/wireless/ath/wil6210/wil_crash_dump.c @@ -46,7 +46,7 @@ static int wil_fw_get_crash_dump_bounds(struct wil6210_priv *wil, int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size) { - int i, rc; + int i; const struct fw_map *map; void *data; u32 host_min, dump_size, offset, len; @@ -62,9 +62,15 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size) return -EINVAL; } - rc = wil_mem_access_lock(wil); - if (rc) - return rc; + down_write(&wil->mem_lock); + + if (test_bit(wil_status_suspending, wil->status) || + test_bit(wil_status_suspended, wil->status)) { + wil_err(wil, + "suspend/resume in progress. cannot copy crash dump\n"); + up_write(&wil->mem_lock); + return -EBUSY; + } /* copy to crash dump area */ for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { @@ -84,7 +90,8 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size) wil_memcpy_fromio_32((void * __force)(dest + offset), (const void __iomem * __force)data, len); } - wil_mem_access_unlock(wil); + + up_write(&wil->mem_lock); return 0; } diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 7a0d934eb271..dcba0a4c47b4 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -196,8 +196,8 @@ const struct fw_map talyn_mb_fw_mapping[] = { {0x8c0000, 0x8c0210, 0x8c0000, "dum_user_rgf", true, true}, /* DMA OFU 296b */ {0x8c2000, 0x8c2128, 0x8c2000, "dma_ofu", true, true}, - /* ucode debug 4k */ - {0x8c3000, 0x8c4000, 0x8c3000, "ucode_debug", true, true}, + /* ucode debug 256b */ + {0x8c3000, 0x8c3100, 0x8c3000, "ucode_debug", true, true}, /* upper area 1536k */ {0x900000, 0xa80000, 0x900000, "upper", true, true}, /* UCODE areas - accessible by debugfs blobs but not by @@ -476,6 +476,8 @@ static const char *cmdid2name(u16 cmdid) return "WMI_RBUFCAP_CFG_CMD"; case WMI_TEMP_SENSE_ALL_CMDID: return "WMI_TEMP_SENSE_ALL_CMDID"; + case WMI_SET_LINK_MONITOR_CMDID: + return "WMI_SET_LINK_MONITOR_CMD"; default: return "Untracked CMD"; } @@ -624,6 +626,10 @@ static const char *eventid2name(u16 eventid) return "WMI_RBUFCAP_CFG_EVENT"; case WMI_TEMP_SENSE_ALL_DONE_EVENTID: return "WMI_TEMP_SENSE_ALL_DONE_EVENTID"; + case WMI_SET_LINK_MONITOR_EVENTID: + return "WMI_SET_LINK_MONITOR_EVENT"; + case WMI_LINK_MONITOR_EVENTID: + return "WMI_LINK_MONITOR_EVENT"; default: return "Untracked EVENT"; } @@ -1836,6 +1842,32 @@ fail: wil6210_disconnect(vif, NULL, WLAN_REASON_PREV_AUTH_NOT_VALID); } +static void +wmi_evt_link_monitor(struct wil6210_vif *vif, int id, void *d, int len) +{ + struct wil6210_priv *wil = vif_to_wil(vif); + struct net_device *ndev = vif_to_ndev(vif); + struct wmi_link_monitor_event *evt = d; + enum nl80211_cqm_rssi_threshold_event event_type; + + if (len < sizeof(*evt)) { + wil_err(wil, "link monitor event too short %d\n", len); + return; + } + + wil_dbg_wmi(wil, "link monitor event, type %d rssi %d (stored %d)\n", + evt->type, evt->rssi_level, wil->cqm_rssi_thold); + + if (evt->type != WMI_LINK_MONITOR_NOTIF_RSSI_THRESHOLD_EVT) + /* ignore */ + return; + + event_type = (evt->rssi_level > wil->cqm_rssi_thold ? + NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH : + NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW); + cfg80211_cqm_rssi_notify(ndev, event_type, evt->rssi_level, GFP_KERNEL); +} + /** * Some events are ignored for purpose; and need not be interpreted as * "unhandled events" @@ -1869,6 +1901,7 @@ static const struct { {WMI_LINK_STATS_EVENTID, wmi_evt_link_stats}, {WMI_FT_AUTH_STATUS_EVENTID, wmi_evt_auth_status}, {WMI_FT_REASSOC_STATUS_EVENTID, wmi_evt_reassoc_status}, + {WMI_LINK_MONITOR_EVENTID, wmi_evt_link_monitor}, }; /* @@ -3981,3 +4014,46 @@ int wmi_link_stats_cfg(struct wil6210_vif *vif, u32 type, u8 cid, u32 interval) return 0; } + +int wmi_set_cqm_rssi_config(struct wil6210_priv *wil, + s32 rssi_thold, u32 rssi_hyst) +{ + struct net_device *ndev = wil->main_ndev; + struct wil6210_vif *vif = ndev_to_vif(ndev); + int rc; + struct { + struct wmi_set_link_monitor_cmd cmd; + s8 rssi_thold; + } __packed cmd = { + .cmd = { + .rssi_hyst = rssi_hyst, + .rssi_thresholds_list_size = 1, + }, + .rssi_thold = rssi_thold, + }; + struct { + struct wmi_cmd_hdr hdr; + struct wmi_set_link_monitor_event evt; + } __packed reply = { + .evt = {.status = WMI_FW_STATUS_FAILURE}, + }; + + if (rssi_thold > S8_MAX || rssi_thold < S8_MIN || rssi_hyst > U8_MAX) + return -EINVAL; + + rc = wmi_call(wil, WMI_SET_LINK_MONITOR_CMDID, vif->mid, &cmd, + sizeof(cmd), WMI_SET_LINK_MONITOR_EVENTID, + &reply, sizeof(reply), WIL_WMI_CALL_GENERAL_TO_MS); + if (rc) { + wil_err(wil, "WMI_SET_LINK_MONITOR_CMDID failed, rc %d\n", rc); + return rc; + } + + if (reply.evt.status != WMI_FW_STATUS_SUCCESS) { + wil_err(wil, "WMI_SET_LINK_MONITOR_CMDID failed, status %d\n", + reply.evt.status); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 6bd4ccee28ab..e3558136e0c4 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -192,6 +192,7 @@ enum wmi_command_id { WMI_RCP_ADDBA_RESP_EDMA_CMDID = 0x83B, WMI_LINK_MAINTAIN_CFG_WRITE_CMDID = 0x842, WMI_LINK_MAINTAIN_CFG_READ_CMDID = 0x843, + WMI_SET_LINK_MONITOR_CMDID = 0x845, WMI_SET_SECTORS_CMDID = 0x849, WMI_MAINTAIN_PAUSE_CMDID = 0x850, WMI_MAINTAIN_RESUME_CMDID = 0x851, @@ -1973,6 +1974,7 @@ enum wmi_event_id { WMI_REPORT_STATISTICS_EVENTID = 0x100B, WMI_FT_AUTH_STATUS_EVENTID = 0x100C, WMI_FT_REASSOC_STATUS_EVENTID = 0x100D, + WMI_LINK_MONITOR_EVENTID = 0x100E, WMI_RADAR_GENERAL_CONFIG_EVENTID = 0x1100, WMI_RADAR_CONFIG_SELECT_EVENTID = 0x1101, WMI_RADAR_PARAMS_CONFIG_EVENTID = 0x1102, @@ -2024,6 +2026,7 @@ enum wmi_event_id { WMI_TX_MGMT_PACKET_EVENTID = 0x1841, WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID = 0x1842, WMI_LINK_MAINTAIN_CFG_READ_DONE_EVENTID = 0x1843, + WMI_SET_LINK_MONITOR_EVENTID = 0x1845, WMI_RF_XPM_READ_RESULT_EVENTID = 0x1856, WMI_RF_XPM_WRITE_RESULT_EVENTID = 0x1857, WMI_LED_CFG_DONE_EVENTID = 0x1858, @@ -3312,6 +3315,36 @@ struct wmi_link_maintain_cfg_read_cmd { __le32 cid; } __packed; +/* WMI_SET_LINK_MONITOR_CMDID */ +struct wmi_set_link_monitor_cmd { + u8 rssi_hyst; + u8 reserved[12]; + u8 rssi_thresholds_list_size; + s8 rssi_thresholds_list[0]; +} __packed; + +/* wmi_link_monitor_event_type */ +enum wmi_link_monitor_event_type { + WMI_LINK_MONITOR_NOTIF_RSSI_THRESHOLD_EVT = 0x00, + WMI_LINK_MONITOR_NOTIF_TX_ERR_EVT = 0x01, + WMI_LINK_MONITOR_NOTIF_THERMAL_EVT = 0x02, +}; + +/* WMI_SET_LINK_MONITOR_EVENTID */ +struct wmi_set_link_monitor_event { + /* wmi_fw_status */ + u8 status; + u8 reserved[3]; +} __packed; + +/* WMI_LINK_MONITOR_EVENTID */ +struct wmi_link_monitor_event { + /* link_monitor_event_type */ + u8 type; + s8 rssi_level; + u8 reserved[2]; +} __packed; + /* WMI_LINK_MAINTAIN_CFG_WRITE_DONE_EVENTID */ struct wmi_link_maintain_cfg_write_done_event { /* requested connection ID */ |