Path: blob/main/sys/contrib/dev/athk/ath11k/dp_tx.c
106507 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/*2* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.3* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.4* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.5*/67#include "core.h"8#include "dp_tx.h"9#include "debug.h"10#include "debugfs_sta.h"11#include "hw.h"12#include "peer.h"13#include "mac.h"1415static enum hal_tcl_encap_type16ath11k_dp_tx_get_encap_type(struct ath11k_vif *arvif, struct sk_buff *skb)17{18struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);19struct ath11k_base *ab = arvif->ar->ab;2021if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags))22return HAL_TCL_ENCAP_TYPE_RAW;2324if (tx_info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)25return HAL_TCL_ENCAP_TYPE_ETHERNET;2627return HAL_TCL_ENCAP_TYPE_NATIVE_WIFI;28}2930static void ath11k_dp_tx_encap_nwifi(struct sk_buff *skb)31{32struct ieee80211_hdr *hdr = (void *)skb->data;33u8 *qos_ctl;3435if (!ieee80211_is_data_qos(hdr->frame_control))36return;3738qos_ctl = ieee80211_get_qos_ctl(hdr);39memmove(skb->data + IEEE80211_QOS_CTL_LEN,40#if defined(__linux__)41skb->data, (void *)qos_ctl - (void *)skb->data);42#elif defined(__FreeBSD__)43skb->data, qos_ctl - (u8 *)skb->data);44#endif45skb_pull(skb, IEEE80211_QOS_CTL_LEN);4647hdr = (void *)skb->data;48hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);49}5051static u8 ath11k_dp_tx_get_tid(struct sk_buff *skb)52{53struct ieee80211_hdr *hdr = (void *)skb->data;54struct ath11k_skb_cb *cb = ATH11K_SKB_CB(skb);5556if (cb->flags & ATH11K_SKB_HW_80211_ENCAP)57return skb->priority & IEEE80211_QOS_CTL_TID_MASK;58else if (!ieee80211_is_data_qos(hdr->frame_control))59return HAL_DESC_REO_NON_QOS_TID;60else61return skb->priority & IEEE80211_QOS_CTL_TID_MASK;62}6364enum hal_encrypt_type ath11k_dp_tx_get_encrypt_type(u32 cipher)65{66switch (cipher) {67case WLAN_CIPHER_SUITE_WEP40:68return HAL_ENCRYPT_TYPE_WEP_40;69case WLAN_CIPHER_SUITE_WEP104:70return HAL_ENCRYPT_TYPE_WEP_104;71case WLAN_CIPHER_SUITE_TKIP:72return HAL_ENCRYPT_TYPE_TKIP_MIC;73case WLAN_CIPHER_SUITE_CCMP:74return HAL_ENCRYPT_TYPE_CCMP_128;75case WLAN_CIPHER_SUITE_CCMP_256:76return HAL_ENCRYPT_TYPE_CCMP_256;77case WLAN_CIPHER_SUITE_GCMP:78return HAL_ENCRYPT_TYPE_GCMP_128;79case WLAN_CIPHER_SUITE_GCMP_256:80return HAL_ENCRYPT_TYPE_AES_GCMP_256;81default:82return HAL_ENCRYPT_TYPE_OPEN;83}84}8586int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,87struct ath11k_sta *arsta, struct sk_buff *skb)88{89struct ath11k_base *ab = ar->ab;90struct ath11k_dp *dp = &ab->dp;91struct hal_tx_info ti = {};92struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);93struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);94struct hal_srng *tcl_ring;95struct ieee80211_hdr *hdr = (void *)skb->data;96struct dp_tx_ring *tx_ring;97#if defined(__linux__)98void *hal_tcl_desc;99#elif defined(__FreeBSD__)100u8 *hal_tcl_desc;101#endif102u8 pool_id;103u8 hal_ring_id;104int ret;105u32 ring_selector = 0;106u8 ring_map = 0;107bool tcl_ring_retry;108109if (unlikely(test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)))110return -ESHUTDOWN;111112if (unlikely(!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&113!ieee80211_is_data(hdr->frame_control)))114return -EOPNOTSUPP;115116pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1);117118ring_selector = ab->hw_params.hw_ops->get_ring_selector(skb);119120tcl_ring_sel:121tcl_ring_retry = false;122123ti.ring_id = ring_selector % ab->hw_params.max_tx_ring;124ti.rbm_id = ab->hw_params.hal_params->tcl2wbm_rbm_map[ti.ring_id].rbm_id;125126ring_map |= BIT(ti.ring_id);127128tx_ring = &dp->tx_ring[ti.ring_id];129130spin_lock_bh(&tx_ring->tx_idr_lock);131ret = idr_alloc(&tx_ring->txbuf_idr, skb, 0,132DP_TX_IDR_SIZE - 1, GFP_ATOMIC);133spin_unlock_bh(&tx_ring->tx_idr_lock);134135if (unlikely(ret < 0)) {136if (ring_map == (BIT(ab->hw_params.max_tx_ring) - 1) ||137!ab->hw_params.tcl_ring_retry) {138atomic_inc(&ab->soc_stats.tx_err.misc_fail);139return -ENOSPC;140}141142/* Check if the next ring is available */143ring_selector++;144goto tcl_ring_sel;145}146147ti.desc_id = FIELD_PREP(DP_TX_DESC_ID_MAC_ID, ar->pdev_idx) |148FIELD_PREP(DP_TX_DESC_ID_MSDU_ID, ret) |149FIELD_PREP(DP_TX_DESC_ID_POOL_ID, pool_id);150ti.encap_type = ath11k_dp_tx_get_encap_type(arvif, skb);151152if (ieee80211_has_a4(hdr->frame_control) &&153is_multicast_ether_addr(hdr->addr3) && arsta &&154arsta->use_4addr_set) {155ti.meta_data_flags = arsta->tcl_metadata;156ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TO_FW, 1);157} else {158ti.meta_data_flags = arvif->tcl_metadata;159}160161if (unlikely(ti.encap_type == HAL_TCL_ENCAP_TYPE_RAW)) {162if (skb_cb->flags & ATH11K_SKB_CIPHER_SET) {163ti.encrypt_type =164ath11k_dp_tx_get_encrypt_type(skb_cb->cipher);165166if (ieee80211_has_protected(hdr->frame_control))167skb_put(skb, IEEE80211_CCMP_MIC_LEN);168} else {169ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN;170}171}172173ti.addr_search_flags = arvif->hal_addr_search_flags;174ti.search_type = arvif->search_type;175ti.type = HAL_TCL_DESC_TYPE_BUFFER;176ti.pkt_offset = 0;177ti.lmac_id = ar->lmac_id;178ti.bss_ast_hash = arvif->ast_hash;179ti.bss_ast_idx = arvif->ast_idx;180ti.dscp_tid_tbl_idx = 0;181182if (likely(skb->ip_summed == CHECKSUM_PARTIAL &&183ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW)) {184ti.flags0 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_IP4_CKSUM_EN, 1) |185FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP4_CKSUM_EN, 1) |186FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_UDP6_CKSUM_EN, 1) |187FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TCP4_CKSUM_EN, 1) |188FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_TCP6_CKSUM_EN, 1);189}190191if (ieee80211_vif_is_mesh(arvif->vif))192ti.enable_mesh = true;193194ti.flags1 |= FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_TID_OVERWRITE, 1);195196ti.tid = ath11k_dp_tx_get_tid(skb);197198switch (ti.encap_type) {199case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI:200ath11k_dp_tx_encap_nwifi(skb);201break;202case HAL_TCL_ENCAP_TYPE_RAW:203if (!test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags)) {204ret = -EINVAL;205goto fail_remove_idr;206}207break;208case HAL_TCL_ENCAP_TYPE_ETHERNET:209/* no need to encap */210break;211case HAL_TCL_ENCAP_TYPE_802_3:212default:213/* TODO: Take care of other encap modes as well */214ret = -EINVAL;215atomic_inc(&ab->soc_stats.tx_err.misc_fail);216goto fail_remove_idr;217}218219ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);220if (unlikely(dma_mapping_error(ab->dev, ti.paddr))) {221atomic_inc(&ab->soc_stats.tx_err.misc_fail);222ath11k_warn(ab, "failed to DMA map data Tx buffer\n");223ret = -ENOMEM;224goto fail_remove_idr;225}226227ti.data_len = skb->len;228skb_cb->paddr = ti.paddr;229skb_cb->vif = arvif->vif;230skb_cb->ar = ar;231232hal_ring_id = tx_ring->tcl_data_ring.ring_id;233tcl_ring = &ab->hal.srng_list[hal_ring_id];234235spin_lock_bh(&tcl_ring->lock);236237ath11k_hal_srng_access_begin(ab, tcl_ring);238239hal_tcl_desc = (void *)ath11k_hal_srng_src_get_next_entry(ab, tcl_ring);240if (unlikely(!hal_tcl_desc)) {241/* NOTE: It is highly unlikely we'll be running out of tcl_ring242* desc because the desc is directly enqueued onto hw queue.243*/244ath11k_hal_srng_access_end(ab, tcl_ring);245ab->soc_stats.tx_err.desc_na[ti.ring_id]++;246spin_unlock_bh(&tcl_ring->lock);247ret = -ENOMEM;248249/* Checking for available tcl descriptors in another ring in250* case of failure due to full tcl ring now, is better than251* checking this ring earlier for each pkt tx.252* Restart ring selection if some rings are not checked yet.253*/254if (unlikely(ring_map != (BIT(ab->hw_params.max_tx_ring)) - 1) &&255ab->hw_params.tcl_ring_retry && ab->hw_params.max_tx_ring > 1) {256tcl_ring_retry = true;257ring_selector++;258}259260goto fail_unmap_dma;261}262263ath11k_hal_tx_cmd_desc_setup(ab, hal_tcl_desc +264sizeof(struct hal_tlv_hdr), &ti);265266ath11k_hal_srng_access_end(ab, tcl_ring);267268ath11k_dp_shadow_start_timer(ab, tcl_ring, &dp->tx_ring_timer[ti.ring_id]);269270spin_unlock_bh(&tcl_ring->lock);271272ath11k_dbg_dump(ab, ATH11K_DBG_DP_TX, NULL, "dp tx msdu: ",273skb->data, skb->len);274275atomic_inc(&ar->dp.num_tx_pending);276277return 0;278279fail_unmap_dma:280dma_unmap_single(ab->dev, ti.paddr, ti.data_len, DMA_TO_DEVICE);281282fail_remove_idr:283spin_lock_bh(&tx_ring->tx_idr_lock);284idr_remove(&tx_ring->txbuf_idr,285FIELD_GET(DP_TX_DESC_ID_MSDU_ID, ti.desc_id));286spin_unlock_bh(&tx_ring->tx_idr_lock);287288if (tcl_ring_retry)289goto tcl_ring_sel;290291return ret;292}293294static void ath11k_dp_tx_free_txbuf(struct ath11k_base *ab, u8 mac_id,295int msdu_id,296struct dp_tx_ring *tx_ring)297{298struct ath11k *ar;299struct sk_buff *msdu;300struct ath11k_skb_cb *skb_cb;301302spin_lock(&tx_ring->tx_idr_lock);303msdu = idr_remove(&tx_ring->txbuf_idr, msdu_id);304spin_unlock(&tx_ring->tx_idr_lock);305306if (unlikely(!msdu)) {307ath11k_warn(ab, "tx completion for unknown msdu_id %d\n",308msdu_id);309return;310}311312skb_cb = ATH11K_SKB_CB(msdu);313314dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);315dev_kfree_skb_any(msdu);316317ar = ab->pdevs[mac_id].ar;318if (atomic_dec_and_test(&ar->dp.num_tx_pending))319wake_up(&ar->dp.tx_empty_waitq);320}321322static void323ath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab,324struct dp_tx_ring *tx_ring,325struct ath11k_dp_htt_wbm_tx_status *ts)326{327struct ieee80211_tx_status status = {};328struct sk_buff *msdu;329struct ieee80211_tx_info *info;330struct ath11k_skb_cb *skb_cb;331struct ath11k *ar;332struct ath11k_peer *peer;333334spin_lock(&tx_ring->tx_idr_lock);335msdu = idr_remove(&tx_ring->txbuf_idr, ts->msdu_id);336spin_unlock(&tx_ring->tx_idr_lock);337338if (unlikely(!msdu)) {339ath11k_warn(ab, "htt tx completion for unknown msdu_id %d\n",340ts->msdu_id);341return;342}343344skb_cb = ATH11K_SKB_CB(msdu);345info = IEEE80211_SKB_CB(msdu);346347ar = skb_cb->ar;348349if (atomic_dec_and_test(&ar->dp.num_tx_pending))350wake_up(&ar->dp.tx_empty_waitq);351352dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);353354if (!skb_cb->vif) {355ieee80211_free_txskb(ar->hw, msdu);356return;357}358359memset(&info->status, 0, sizeof(info->status));360361if (ts->acked) {362if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {363info->flags |= IEEE80211_TX_STAT_ACK;364info->status.ack_signal = ts->ack_rssi;365366if (!test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT,367ab->wmi_ab.svc_map))368info->status.ack_signal += ATH11K_DEFAULT_NOISE_FLOOR;369370info->status.flags |=371IEEE80211_TX_STATUS_ACK_SIGNAL_VALID;372} else {373info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;374}375}376377spin_lock_bh(&ab->base_lock);378peer = ath11k_peer_find_by_id(ab, ts->peer_id);379if (!peer || !peer->sta) {380ath11k_dbg(ab, ATH11K_DBG_DATA,381"dp_tx: failed to find the peer with peer_id %d\n",382ts->peer_id);383spin_unlock_bh(&ab->base_lock);384ieee80211_free_txskb(ar->hw, msdu);385return;386}387spin_unlock_bh(&ab->base_lock);388389status.sta = peer->sta;390status.info = info;391status.skb = msdu;392393ieee80211_tx_status_ext(ar->hw, &status);394}395396static void397ath11k_dp_tx_process_htt_tx_complete(struct ath11k_base *ab,398#if defined(__linux__)399void *desc, u8 mac_id,400#elif defined(__FreeBSD__)401u8 *desc, u8 mac_id,402#endif403u32 msdu_id, struct dp_tx_ring *tx_ring)404{405struct htt_tx_wbm_completion *status_desc;406struct ath11k_dp_htt_wbm_tx_status ts = {};407enum hal_wbm_htt_tx_comp_status wbm_status;408409#if defined(__linux__)410status_desc = desc + HTT_TX_WBM_COMP_STATUS_OFFSET;411#elif defined(__FreeBSD__)412status_desc = (void *)(desc + HTT_TX_WBM_COMP_STATUS_OFFSET);413#endif414415wbm_status = FIELD_GET(HTT_TX_WBM_COMP_INFO0_STATUS,416status_desc->info0);417switch (wbm_status) {418case HAL_WBM_REL_HTT_TX_COMP_STATUS_OK:419case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP:420case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL:421ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK);422ts.msdu_id = msdu_id;423ts.ack_rssi = FIELD_GET(HTT_TX_WBM_COMP_INFO1_ACK_RSSI,424status_desc->info1);425426if (FIELD_GET(HTT_TX_WBM_COMP_INFO2_VALID, status_desc->info2))427ts.peer_id = FIELD_GET(HTT_TX_WBM_COMP_INFO2_SW_PEER_ID,428status_desc->info2);429else430ts.peer_id = HTT_INVALID_PEER_ID;431432ath11k_dp_tx_htt_tx_complete_buf(ab, tx_ring, &ts);433434break;435case HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ:436case HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT:437ath11k_dp_tx_free_txbuf(ab, mac_id, msdu_id, tx_ring);438break;439case HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY:440/* This event is to be handled only when the driver decides to441* use WDS offload functionality.442*/443break;444default:445ath11k_warn(ab, "Unknown htt tx status %d\n", wbm_status);446break;447}448}449450static void ath11k_dp_tx_cache_peer_stats(struct ath11k *ar,451struct sk_buff *msdu,452struct hal_tx_status *ts)453{454struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats;455456if (ts->try_cnt > 1) {457peer_stats->retry_pkts += ts->try_cnt - 1;458peer_stats->retry_bytes += (ts->try_cnt - 1) * msdu->len;459460if (ts->status != HAL_WBM_TQM_REL_REASON_FRAME_ACKED) {461peer_stats->failed_pkts += 1;462peer_stats->failed_bytes += msdu->len;463}464}465}466467void ath11k_dp_tx_update_txcompl(struct ath11k *ar, struct hal_tx_status *ts)468{469struct ath11k_base *ab = ar->ab;470struct ath11k_per_peer_tx_stats *peer_stats = &ar->cached_stats;471enum hal_tx_rate_stats_pkt_type pkt_type;472enum hal_tx_rate_stats_sgi sgi;473enum hal_tx_rate_stats_bw bw;474struct ath11k_peer *peer;475struct ath11k_sta *arsta;476struct ieee80211_sta *sta;477u16 rate, ru_tones;478u8 mcs, rate_idx = 0, ofdma;479int ret;480481spin_lock_bh(&ab->base_lock);482peer = ath11k_peer_find_by_id(ab, ts->peer_id);483if (!peer || !peer->sta) {484ath11k_dbg(ab, ATH11K_DBG_DP_TX,485"failed to find the peer by id %u\n", ts->peer_id);486goto err_out;487}488489sta = peer->sta;490arsta = ath11k_sta_to_arsta(sta);491492memset(&arsta->txrate, 0, sizeof(arsta->txrate));493pkt_type = FIELD_GET(HAL_TX_RATE_STATS_INFO0_PKT_TYPE,494ts->rate_stats);495mcs = FIELD_GET(HAL_TX_RATE_STATS_INFO0_MCS,496ts->rate_stats);497sgi = FIELD_GET(HAL_TX_RATE_STATS_INFO0_SGI,498ts->rate_stats);499bw = FIELD_GET(HAL_TX_RATE_STATS_INFO0_BW, ts->rate_stats);500ru_tones = FIELD_GET(HAL_TX_RATE_STATS_INFO0_TONES_IN_RU, ts->rate_stats);501ofdma = FIELD_GET(HAL_TX_RATE_STATS_INFO0_OFDMA_TX, ts->rate_stats);502503/* This is to prefer choose the real NSS value arsta->last_txrate.nss,504* if it is invalid, then choose the NSS value while assoc.505*/506if (arsta->last_txrate.nss)507arsta->txrate.nss = arsta->last_txrate.nss;508else509arsta->txrate.nss = arsta->peer_nss;510511if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11A ||512pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11B) {513ret = ath11k_mac_hw_ratecode_to_legacy_rate(mcs,514pkt_type,515&rate_idx,516&rate);517if (ret < 0)518goto err_out;519arsta->txrate.legacy = rate;520} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11N) {521if (mcs > 7) {522ath11k_warn(ab, "Invalid HT mcs index %d\n", mcs);523goto err_out;524}525526if (arsta->txrate.nss != 0)527arsta->txrate.mcs = mcs + 8 * (arsta->txrate.nss - 1);528arsta->txrate.flags = RATE_INFO_FLAGS_MCS;529if (sgi)530arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;531} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AC) {532if (mcs > 9) {533ath11k_warn(ab, "Invalid VHT mcs index %d\n", mcs);534goto err_out;535}536537arsta->txrate.mcs = mcs;538arsta->txrate.flags = RATE_INFO_FLAGS_VHT_MCS;539if (sgi)540arsta->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;541} else if (pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) {542if (mcs > 11) {543ath11k_warn(ab, "Invalid HE mcs index %d\n", mcs);544goto err_out;545}546547arsta->txrate.mcs = mcs;548arsta->txrate.flags = RATE_INFO_FLAGS_HE_MCS;549arsta->txrate.he_gi = ath11k_mac_he_gi_to_nl80211_he_gi(sgi);550}551552arsta->txrate.bw = ath11k_mac_bw_to_mac80211_bw(bw);553if (ofdma && pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) {554arsta->txrate.bw = RATE_INFO_BW_HE_RU;555arsta->txrate.he_ru_alloc =556ath11k_mac_he_ru_tones_to_nl80211_he_ru_alloc(ru_tones);557}558559if (ath11k_debugfs_is_extd_tx_stats_enabled(ar))560ath11k_debugfs_sta_add_tx_stats(arsta, peer_stats, rate_idx);561562err_out:563spin_unlock_bh(&ab->base_lock);564}565566static void ath11k_dp_tx_complete_msdu(struct ath11k *ar,567struct sk_buff *msdu,568struct hal_tx_status *ts)569{570struct ieee80211_tx_status status = {};571struct ieee80211_rate_status status_rate = {};572struct ath11k_base *ab = ar->ab;573struct ieee80211_tx_info *info;574struct ath11k_skb_cb *skb_cb;575struct ath11k_peer *peer;576struct ath11k_sta *arsta;577struct rate_info rate;578579if (WARN_ON_ONCE(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) {580/* Must not happen */581return;582}583584skb_cb = ATH11K_SKB_CB(msdu);585586dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);587588if (unlikely(!rcu_access_pointer(ab->pdevs_active[ar->pdev_idx]))) {589ieee80211_free_txskb(ar->hw, msdu);590return;591}592593if (unlikely(!skb_cb->vif)) {594ieee80211_free_txskb(ar->hw, msdu);595return;596}597598info = IEEE80211_SKB_CB(msdu);599memset(&info->status, 0, sizeof(info->status));600601/* skip tx rate update from ieee80211_status*/602info->status.rates[0].idx = -1;603604if (ts->status == HAL_WBM_TQM_REL_REASON_FRAME_ACKED &&605!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {606info->flags |= IEEE80211_TX_STAT_ACK;607info->status.ack_signal = ts->ack_rssi;608609if (!test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT,610ab->wmi_ab.svc_map))611info->status.ack_signal += ATH11K_DEFAULT_NOISE_FLOOR;612613info->status.flags |= IEEE80211_TX_STATUS_ACK_SIGNAL_VALID;614}615616if (ts->status == HAL_WBM_TQM_REL_REASON_CMD_REMOVE_TX &&617(info->flags & IEEE80211_TX_CTL_NO_ACK))618info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;619620if (unlikely(ath11k_debugfs_is_extd_tx_stats_enabled(ar)) ||621ab->hw_params.single_pdev_only) {622if (ts->flags & HAL_TX_STATUS_FLAGS_FIRST_MSDU) {623if (ar->last_ppdu_id == 0) {624ar->last_ppdu_id = ts->ppdu_id;625} else if (ar->last_ppdu_id == ts->ppdu_id ||626ar->cached_ppdu_id == ar->last_ppdu_id) {627ar->cached_ppdu_id = ar->last_ppdu_id;628ar->cached_stats.is_ampdu = true;629ath11k_dp_tx_update_txcompl(ar, ts);630memset(&ar->cached_stats, 0,631sizeof(struct ath11k_per_peer_tx_stats));632} else {633ar->cached_stats.is_ampdu = false;634ath11k_dp_tx_update_txcompl(ar, ts);635memset(&ar->cached_stats, 0,636sizeof(struct ath11k_per_peer_tx_stats));637}638ar->last_ppdu_id = ts->ppdu_id;639}640641ath11k_dp_tx_cache_peer_stats(ar, msdu, ts);642}643644spin_lock_bh(&ab->base_lock);645peer = ath11k_peer_find_by_id(ab, ts->peer_id);646if (!peer || !peer->sta) {647ath11k_dbg(ab, ATH11K_DBG_DATA,648"dp_tx: failed to find the peer with peer_id %d\n",649ts->peer_id);650spin_unlock_bh(&ab->base_lock);651ieee80211_free_txskb(ar->hw, msdu);652return;653}654arsta = ath11k_sta_to_arsta(peer->sta);655status.sta = peer->sta;656status.skb = msdu;657status.info = info;658rate = arsta->last_txrate;659660status_rate.rate_idx = rate;661status_rate.try_count = 1;662663status.rates = &status_rate;664status.n_rates = 1;665666spin_unlock_bh(&ab->base_lock);667668ieee80211_tx_status_ext(ar->hw, &status);669}670671static inline void ath11k_dp_tx_status_parse(struct ath11k_base *ab,672struct hal_wbm_release_ring *desc,673struct hal_tx_status *ts)674{675ts->buf_rel_source =676FIELD_GET(HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE, desc->info0);677if (unlikely(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW &&678ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM))679return;680681if (unlikely(ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW))682return;683684ts->status = FIELD_GET(HAL_WBM_RELEASE_INFO0_TQM_RELEASE_REASON,685desc->info0);686ts->ppdu_id = FIELD_GET(HAL_WBM_RELEASE_INFO1_TQM_STATUS_NUMBER,687desc->info1);688ts->try_cnt = FIELD_GET(HAL_WBM_RELEASE_INFO1_TRANSMIT_COUNT,689desc->info1);690ts->ack_rssi = FIELD_GET(HAL_WBM_RELEASE_INFO2_ACK_FRAME_RSSI,691desc->info2);692if (desc->info2 & HAL_WBM_RELEASE_INFO2_FIRST_MSDU)693ts->flags |= HAL_TX_STATUS_FLAGS_FIRST_MSDU;694ts->peer_id = FIELD_GET(HAL_WBM_RELEASE_INFO3_PEER_ID, desc->info3);695ts->tid = FIELD_GET(HAL_WBM_RELEASE_INFO3_TID, desc->info3);696if (desc->rate_stats.info0 & HAL_TX_RATE_STATS_INFO0_VALID)697ts->rate_stats = desc->rate_stats.info0;698else699ts->rate_stats = 0;700}701702void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id)703{704struct ath11k *ar;705struct ath11k_dp *dp = &ab->dp;706int hal_ring_id = dp->tx_ring[ring_id].tcl_comp_ring.ring_id;707struct hal_srng *status_ring = &ab->hal.srng_list[hal_ring_id];708struct sk_buff *msdu;709struct hal_tx_status ts = {};710struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id];711u32 *desc;712u32 msdu_id;713u8 mac_id;714715spin_lock_bh(&status_ring->lock);716717ath11k_hal_srng_access_begin(ab, status_ring);718719while ((ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) !=720tx_ring->tx_status_tail) &&721(desc = ath11k_hal_srng_dst_get_next_entry(ab, status_ring))) {722memcpy(&tx_ring->tx_status[tx_ring->tx_status_head],723desc, sizeof(struct hal_wbm_release_ring));724tx_ring->tx_status_head =725ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head);726}727728if (unlikely((ath11k_hal_srng_dst_peek(ab, status_ring) != NULL) &&729(ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_head) ==730tx_ring->tx_status_tail))) {731/* TODO: Process pending tx_status messages when kfifo_is_full() */732ath11k_warn(ab, "Unable to process some of the tx_status ring desc because status_fifo is full\n");733}734735ath11k_hal_srng_access_end(ab, status_ring);736737spin_unlock_bh(&status_ring->lock);738739while (ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_tail) != tx_ring->tx_status_head) {740struct hal_wbm_release_ring *tx_status;741u32 desc_id;742743tx_ring->tx_status_tail =744ATH11K_TX_COMPL_NEXT(tx_ring->tx_status_tail);745tx_status = &tx_ring->tx_status[tx_ring->tx_status_tail];746ath11k_dp_tx_status_parse(ab, tx_status, &ts);747748desc_id = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE,749tx_status->buf_addr_info.info1);750mac_id = FIELD_GET(DP_TX_DESC_ID_MAC_ID, desc_id);751msdu_id = FIELD_GET(DP_TX_DESC_ID_MSDU_ID, desc_id);752753if (unlikely(ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW)) {754ath11k_dp_tx_process_htt_tx_complete(ab,755(void *)tx_status,756mac_id, msdu_id,757tx_ring);758continue;759}760761spin_lock(&tx_ring->tx_idr_lock);762msdu = idr_remove(&tx_ring->txbuf_idr, msdu_id);763if (unlikely(!msdu)) {764ath11k_warn(ab, "tx completion for unknown msdu_id %d\n",765msdu_id);766spin_unlock(&tx_ring->tx_idr_lock);767continue;768}769770spin_unlock(&tx_ring->tx_idr_lock);771772ar = ab->pdevs[mac_id].ar;773774if (atomic_dec_and_test(&ar->dp.num_tx_pending))775wake_up(&ar->dp.tx_empty_waitq);776777ath11k_dp_tx_complete_msdu(ar, msdu, &ts);778}779}780781int ath11k_dp_tx_send_reo_cmd(struct ath11k_base *ab, struct dp_rx_tid *rx_tid,782enum hal_reo_cmd_type type,783struct ath11k_hal_reo_cmd *cmd,784void (*cb)(struct ath11k_dp *, void *,785enum hal_reo_cmd_status))786{787struct ath11k_dp *dp = &ab->dp;788struct dp_reo_cmd *dp_cmd;789struct hal_srng *cmd_ring;790int cmd_num;791792if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))793return -ESHUTDOWN;794795cmd_ring = &ab->hal.srng_list[dp->reo_cmd_ring.ring_id];796cmd_num = ath11k_hal_reo_cmd_send(ab, cmd_ring, type, cmd);797798/* cmd_num should start from 1, during failure return the error code */799if (cmd_num < 0)800return cmd_num;801802/* reo cmd ring descriptors has cmd_num starting from 1 */803if (cmd_num == 0)804return -EINVAL;805806if (!cb)807return 0;808809/* Can this be optimized so that we keep the pending command list only810* for tid delete command to free up the resource on the command status811* indication?812*/813dp_cmd = kzalloc(sizeof(*dp_cmd), GFP_ATOMIC);814815if (!dp_cmd)816return -ENOMEM;817818memcpy(&dp_cmd->data, rx_tid, sizeof(struct dp_rx_tid));819dp_cmd->cmd_num = cmd_num;820dp_cmd->handler = cb;821822spin_lock_bh(&dp->reo_cmd_lock);823list_add_tail(&dp_cmd->list, &dp->reo_cmd_list);824spin_unlock_bh(&dp->reo_cmd_lock);825826return 0;827}828829static int830ath11k_dp_tx_get_ring_id_type(struct ath11k_base *ab,831int mac_id, u32 ring_id,832enum hal_ring_type ring_type,833enum htt_srng_ring_type *htt_ring_type,834enum htt_srng_ring_id *htt_ring_id)835{836int lmac_ring_id_offset = 0;837int ret = 0;838839switch (ring_type) {840case HAL_RXDMA_BUF:841lmac_ring_id_offset = mac_id * HAL_SRNG_RINGS_PER_LMAC;842843/* for QCA6390, host fills rx buffer to fw and fw fills to844* rxbuf ring for each rxdma845*/846if (!ab->hw_params.rx_mac_buf_ring) {847if (!(ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF +848lmac_ring_id_offset) ||849ring_id == (HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_BUF +850lmac_ring_id_offset))) {851ret = -EINVAL;852}853*htt_ring_id = HTT_RXDMA_HOST_BUF_RING;854*htt_ring_type = HTT_SW_TO_HW_RING;855} else {856if (ring_id == HAL_SRNG_RING_ID_WMAC1_SW2RXDMA0_BUF) {857*htt_ring_id = HTT_HOST1_TO_FW_RXBUF_RING;858*htt_ring_type = HTT_SW_TO_SW_RING;859} else {860*htt_ring_id = HTT_RXDMA_HOST_BUF_RING;861*htt_ring_type = HTT_SW_TO_HW_RING;862}863}864break;865case HAL_RXDMA_DST:866*htt_ring_id = HTT_RXDMA_NON_MONITOR_DEST_RING;867*htt_ring_type = HTT_HW_TO_SW_RING;868break;869case HAL_RXDMA_MONITOR_BUF:870*htt_ring_id = HTT_RXDMA_MONITOR_BUF_RING;871*htt_ring_type = HTT_SW_TO_HW_RING;872break;873case HAL_RXDMA_MONITOR_STATUS:874*htt_ring_id = HTT_RXDMA_MONITOR_STATUS_RING;875*htt_ring_type = HTT_SW_TO_HW_RING;876break;877case HAL_RXDMA_MONITOR_DST:878*htt_ring_id = HTT_RXDMA_MONITOR_DEST_RING;879*htt_ring_type = HTT_HW_TO_SW_RING;880break;881case HAL_RXDMA_MONITOR_DESC:882*htt_ring_id = HTT_RXDMA_MONITOR_DESC_RING;883*htt_ring_type = HTT_SW_TO_HW_RING;884break;885default:886ath11k_warn(ab, "Unsupported ring type in DP :%d\n", ring_type);887ret = -EINVAL;888}889return ret;890}891892int ath11k_dp_tx_htt_srng_setup(struct ath11k_base *ab, u32 ring_id,893int mac_id, enum hal_ring_type ring_type)894{895struct htt_srng_setup_cmd *cmd;896struct hal_srng *srng = &ab->hal.srng_list[ring_id];897struct hal_srng_params params;898struct sk_buff *skb;899u32 ring_entry_sz;900int len = sizeof(*cmd);901dma_addr_t hp_addr, tp_addr;902enum htt_srng_ring_type htt_ring_type;903enum htt_srng_ring_id htt_ring_id;904int ret;905906skb = ath11k_htc_alloc_skb(ab, len);907if (!skb)908return -ENOMEM;909910memset(¶ms, 0, sizeof(params));911ath11k_hal_srng_get_params(ab, srng, ¶ms);912913hp_addr = ath11k_hal_srng_get_hp_addr(ab, srng);914tp_addr = ath11k_hal_srng_get_tp_addr(ab, srng);915916ret = ath11k_dp_tx_get_ring_id_type(ab, mac_id, ring_id,917ring_type, &htt_ring_type,918&htt_ring_id);919if (ret)920goto err_free;921922skb_put(skb, len);923cmd = (struct htt_srng_setup_cmd *)skb->data;924cmd->info0 = FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_MSG_TYPE,925HTT_H2T_MSG_TYPE_SRING_SETUP);926if (htt_ring_type == HTT_SW_TO_HW_RING ||927htt_ring_type == HTT_HW_TO_SW_RING)928cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_PDEV_ID,929DP_SW2HW_MACID(mac_id));930else931cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_PDEV_ID,932mac_id);933cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_RING_TYPE,934htt_ring_type);935cmd->info0 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO0_RING_ID, htt_ring_id);936937cmd->ring_base_addr_lo = params.ring_base_paddr &938HAL_ADDR_LSB_REG_MASK;939940cmd->ring_base_addr_hi = (u64)params.ring_base_paddr >>941HAL_ADDR_MSB_REG_SHIFT;942943ret = ath11k_hal_srng_get_entrysize(ab, ring_type);944if (ret < 0)945goto err_free;946947ring_entry_sz = ret;948949ring_entry_sz >>= 2;950cmd->info1 = FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO1_RING_ENTRY_SIZE,951ring_entry_sz);952cmd->info1 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO1_RING_SIZE,953params.num_entries * ring_entry_sz);954cmd->info1 |= FIELD_PREP(HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_MSI_SWAP,955!!(params.flags & HAL_SRNG_FLAGS_MSI_SWAP));956cmd->info1 |= FIELD_PREP(957HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_TLV_SWAP,958!!(params.flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP));959cmd->info1 |= FIELD_PREP(960HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_HOST_FW_SWAP,961!!(params.flags & HAL_SRNG_FLAGS_RING_PTR_SWAP));962if (htt_ring_type == HTT_SW_TO_HW_RING)963cmd->info1 |= HTT_SRNG_SETUP_CMD_INFO1_RING_LOOP_CNT_DIS;964965cmd->ring_head_off32_remote_addr_lo = hp_addr & HAL_ADDR_LSB_REG_MASK;966cmd->ring_head_off32_remote_addr_hi = (u64)hp_addr >>967HAL_ADDR_MSB_REG_SHIFT;968969cmd->ring_tail_off32_remote_addr_lo = tp_addr & HAL_ADDR_LSB_REG_MASK;970cmd->ring_tail_off32_remote_addr_hi = (u64)tp_addr >>971HAL_ADDR_MSB_REG_SHIFT;972973cmd->ring_msi_addr_lo = lower_32_bits(params.msi_addr);974cmd->ring_msi_addr_hi = upper_32_bits(params.msi_addr);975cmd->msi_data = params.msi_data;976977cmd->intr_info = FIELD_PREP(978HTT_SRNG_SETUP_CMD_INTR_INFO_BATCH_COUNTER_THRESH,979params.intr_batch_cntr_thres_entries * ring_entry_sz);980cmd->intr_info |= FIELD_PREP(981HTT_SRNG_SETUP_CMD_INTR_INFO_INTR_TIMER_THRESH,982params.intr_timer_thres_us >> 3);983984cmd->info2 = 0;985if (params.flags & HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN) {986cmd->info2 = FIELD_PREP(987HTT_SRNG_SETUP_CMD_INFO2_INTR_LOW_THRESH,988params.low_threshold);989}990991ath11k_dbg(ab, ATH11K_DBG_DP_TX,992"htt srng setup msi_addr_lo 0x%x msi_addr_hi 0x%x msi_data 0x%x ring_id %d ring_type %d intr_info 0x%x flags 0x%x\n",993cmd->ring_msi_addr_lo, cmd->ring_msi_addr_hi,994cmd->msi_data, ring_id, ring_type, cmd->intr_info, cmd->info2);995996ret = ath11k_htc_send(&ab->htc, ab->dp.eid, skb);997if (ret)998goto err_free;9991000return 0;10011002err_free:1003dev_kfree_skb_any(skb);10041005return ret;1006}10071008#define HTT_TARGET_VERSION_TIMEOUT_HZ (3 * HZ)10091010int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab)1011{1012struct ath11k_dp *dp = &ab->dp;1013struct sk_buff *skb;1014struct htt_ver_req_cmd *cmd;1015int len = sizeof(*cmd);1016int ret;10171018init_completion(&dp->htt_tgt_version_received);10191020skb = ath11k_htc_alloc_skb(ab, len);1021if (!skb)1022return -ENOMEM;10231024skb_put(skb, len);1025cmd = (struct htt_ver_req_cmd *)skb->data;1026cmd->ver_reg_info = FIELD_PREP(HTT_VER_REQ_INFO_MSG_ID,1027HTT_H2T_MSG_TYPE_VERSION_REQ);10281029ret = ath11k_htc_send(&ab->htc, dp->eid, skb);1030if (ret) {1031dev_kfree_skb_any(skb);1032return ret;1033}10341035ret = wait_for_completion_timeout(&dp->htt_tgt_version_received,1036HTT_TARGET_VERSION_TIMEOUT_HZ);1037if (ret == 0) {1038ath11k_warn(ab, "htt target version request timed out\n");1039return -ETIMEDOUT;1040}10411042if (dp->htt_tgt_ver_major != HTT_TARGET_VERSION_MAJOR) {1043ath11k_err(ab, "unsupported htt major version %d supported version is %d\n",1044dp->htt_tgt_ver_major, HTT_TARGET_VERSION_MAJOR);1045return -EOPNOTSUPP;1046}10471048return 0;1049}10501051int ath11k_dp_tx_htt_h2t_ppdu_stats_req(struct ath11k *ar, u32 mask)1052{1053struct ath11k_base *ab = ar->ab;1054struct ath11k_dp *dp = &ab->dp;1055struct sk_buff *skb;1056struct htt_ppdu_stats_cfg_cmd *cmd;1057int len = sizeof(*cmd);1058u8 pdev_mask;1059int ret;1060int i;10611062for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) {1063skb = ath11k_htc_alloc_skb(ab, len);1064if (!skb)1065return -ENOMEM;10661067skb_put(skb, len);1068cmd = (struct htt_ppdu_stats_cfg_cmd *)skb->data;1069cmd->msg = FIELD_PREP(HTT_PPDU_STATS_CFG_MSG_TYPE,1070HTT_H2T_MSG_TYPE_PPDU_STATS_CFG);10711072pdev_mask = 1 << (ar->pdev_idx + i);1073cmd->msg |= FIELD_PREP(HTT_PPDU_STATS_CFG_PDEV_ID, pdev_mask);1074cmd->msg |= FIELD_PREP(HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK, mask);10751076ret = ath11k_htc_send(&ab->htc, dp->eid, skb);1077if (ret) {1078dev_kfree_skb_any(skb);1079return ret;1080}1081}10821083return 0;1084}10851086int ath11k_dp_tx_htt_rx_filter_setup(struct ath11k_base *ab, u32 ring_id,1087int mac_id, enum hal_ring_type ring_type,1088int rx_buf_size,1089struct htt_rx_ring_tlv_filter *tlv_filter)1090{1091struct htt_rx_ring_selection_cfg_cmd *cmd;1092struct hal_srng *srng = &ab->hal.srng_list[ring_id];1093struct hal_srng_params params;1094struct sk_buff *skb;1095int len = sizeof(*cmd);1096enum htt_srng_ring_type htt_ring_type;1097enum htt_srng_ring_id htt_ring_id;1098int ret;10991100skb = ath11k_htc_alloc_skb(ab, len);1101if (!skb)1102return -ENOMEM;11031104memset(¶ms, 0, sizeof(params));1105ath11k_hal_srng_get_params(ab, srng, ¶ms);11061107ret = ath11k_dp_tx_get_ring_id_type(ab, mac_id, ring_id,1108ring_type, &htt_ring_type,1109&htt_ring_id);1110if (ret)1111goto err_free;11121113skb_put(skb, len);1114cmd = (struct htt_rx_ring_selection_cfg_cmd *)skb->data;1115cmd->info0 = FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_MSG_TYPE,1116HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG);1117if (htt_ring_type == HTT_SW_TO_HW_RING ||1118htt_ring_type == HTT_HW_TO_SW_RING)1119cmd->info0 |=1120FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PDEV_ID,1121DP_SW2HW_MACID(mac_id));1122else1123cmd->info0 |=1124FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PDEV_ID,1125mac_id);1126cmd->info0 |= FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_RING_ID,1127htt_ring_id);1128cmd->info0 |= FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_SS,1129!!(params.flags & HAL_SRNG_FLAGS_MSI_SWAP));1130cmd->info0 |= FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PS,1131!!(params.flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP));11321133cmd->info1 = FIELD_PREP(HTT_RX_RING_SELECTION_CFG_CMD_INFO1_BUF_SIZE,1134rx_buf_size);1135cmd->pkt_type_en_flags0 = tlv_filter->pkt_filter_flags0;1136cmd->pkt_type_en_flags1 = tlv_filter->pkt_filter_flags1;1137cmd->pkt_type_en_flags2 = tlv_filter->pkt_filter_flags2;1138cmd->pkt_type_en_flags3 = tlv_filter->pkt_filter_flags3;1139cmd->rx_filter_tlv = tlv_filter->rx_filter;11401141ret = ath11k_htc_send(&ab->htc, ab->dp.eid, skb);1142if (ret)1143goto err_free;11441145return 0;11461147err_free:1148dev_kfree_skb_any(skb);11491150return ret;1151}11521153int1154ath11k_dp_tx_htt_h2t_ext_stats_req(struct ath11k *ar, u8 type,1155struct htt_ext_stats_cfg_params *cfg_params,1156u64 cookie)1157{1158struct ath11k_base *ab = ar->ab;1159struct ath11k_dp *dp = &ab->dp;1160struct sk_buff *skb;1161struct htt_ext_stats_cfg_cmd *cmd;1162u32 pdev_id;1163int len = sizeof(*cmd);1164int ret;11651166skb = ath11k_htc_alloc_skb(ab, len);1167if (!skb)1168return -ENOMEM;11691170skb_put(skb, len);11711172cmd = (struct htt_ext_stats_cfg_cmd *)skb->data;1173memset(cmd, 0, sizeof(*cmd));1174cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_EXT_STATS_CFG;11751176if (ab->hw_params.single_pdev_only)1177pdev_id = ath11k_mac_get_target_pdev_id(ar);1178else1179pdev_id = ar->pdev->pdev_id;11801181cmd->hdr.pdev_mask = 1 << pdev_id;11821183cmd->hdr.stats_type = type;1184cmd->cfg_param0 = cfg_params->cfg0;1185cmd->cfg_param1 = cfg_params->cfg1;1186cmd->cfg_param2 = cfg_params->cfg2;1187cmd->cfg_param3 = cfg_params->cfg3;1188cmd->cookie_lsb = lower_32_bits(cookie);1189cmd->cookie_msb = upper_32_bits(cookie);11901191ret = ath11k_htc_send(&ab->htc, dp->eid, skb);1192if (ret) {1193ath11k_warn(ab, "failed to send htt type stats request: %d",1194ret);1195dev_kfree_skb_any(skb);1196return ret;1197}11981199return 0;1200}12011202int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset)1203{1204struct ath11k_pdev_dp *dp = &ar->dp;1205struct ath11k_base *ab = ar->ab;1206struct htt_rx_ring_tlv_filter tlv_filter = {};1207int ret = 0, ring_id = 0, i;12081209if (ab->hw_params.full_monitor_mode) {1210ret = ath11k_dp_tx_htt_rx_full_mon_setup(ab,1211dp->mac_id, !reset);1212if (ret < 0) {1213ath11k_err(ab, "failed to setup full monitor %d\n", ret);1214return ret;1215}1216}12171218ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id;12191220if (!reset) {1221tlv_filter.rx_filter = HTT_RX_MON_FILTER_TLV_FLAGS_MON_BUF_RING;1222tlv_filter.pkt_filter_flags0 =1223HTT_RX_MON_FP_MGMT_FILTER_FLAGS0 |1224HTT_RX_MON_MO_MGMT_FILTER_FLAGS0;1225tlv_filter.pkt_filter_flags1 =1226HTT_RX_MON_FP_MGMT_FILTER_FLAGS1 |1227HTT_RX_MON_MO_MGMT_FILTER_FLAGS1;1228tlv_filter.pkt_filter_flags2 =1229HTT_RX_MON_FP_CTRL_FILTER_FLASG2 |1230HTT_RX_MON_MO_CTRL_FILTER_FLASG2;1231tlv_filter.pkt_filter_flags3 =1232HTT_RX_MON_FP_CTRL_FILTER_FLASG3 |1233HTT_RX_MON_MO_CTRL_FILTER_FLASG3 |1234HTT_RX_MON_FP_DATA_FILTER_FLASG3 |1235HTT_RX_MON_MO_DATA_FILTER_FLASG3;1236}12371238if (ab->hw_params.rxdma1_enable) {1239ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, dp->mac_id,1240HAL_RXDMA_MONITOR_BUF,1241DP_RXDMA_REFILL_RING_SIZE,1242&tlv_filter);1243} else if (!reset) {1244/* set in monitor mode only */1245for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) {1246ring_id = dp->rx_mac_buf_ring[i].ring_id;1247ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id,1248dp->mac_id + i,1249HAL_RXDMA_BUF,12501024,1251&tlv_filter);1252}1253}12541255if (ret)1256return ret;12571258for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) {1259ring_id = dp->rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;1260if (!reset) {1261tlv_filter.rx_filter =1262HTT_RX_MON_FILTER_TLV_FLAGS_MON_STATUS_RING;1263} else {1264tlv_filter = ath11k_mac_mon_status_filter_default;12651266if (ath11k_debugfs_is_extd_rx_stats_enabled(ar))1267tlv_filter.rx_filter = ath11k_debugfs_rx_filter(ar);1268}12691270ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id,1271dp->mac_id + i,1272HAL_RXDMA_MONITOR_STATUS,1273DP_RXDMA_REFILL_RING_SIZE,1274&tlv_filter);1275}12761277if (!ar->ab->hw_params.rxdma1_enable)1278mod_timer(&ar->ab->mon_reap_timer, jiffies +1279msecs_to_jiffies(ATH11K_MON_TIMER_INTERVAL));12801281return ret;1282}12831284int ath11k_dp_tx_htt_rx_full_mon_setup(struct ath11k_base *ab, int mac_id,1285bool config)1286{1287struct htt_rx_full_monitor_mode_cfg_cmd *cmd;1288struct sk_buff *skb;1289int ret, len = sizeof(*cmd);12901291skb = ath11k_htc_alloc_skb(ab, len);1292if (!skb)1293return -ENOMEM;12941295skb_put(skb, len);1296cmd = (struct htt_rx_full_monitor_mode_cfg_cmd *)skb->data;1297memset(cmd, 0, sizeof(*cmd));1298cmd->info0 = FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_MSG_TYPE,1299HTT_H2T_MSG_TYPE_RX_FULL_MONITOR_MODE);13001301cmd->info0 |= FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_INFO0_PDEV_ID, mac_id);13021303cmd->cfg = HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ENABLE |1304FIELD_PREP(HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_RELEASE_RING,1305HTT_RX_MON_RING_SW);1306if (config) {1307cmd->cfg |= HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_ZERO_MPDUS_END |1308HTT_RX_FULL_MON_MODE_CFG_CMD_CFG_NON_ZERO_MPDUS_END;1309}13101311ret = ath11k_htc_send(&ab->htc, ab->dp.eid, skb);1312if (ret)1313goto err_free;13141315return 0;13161317err_free:1318dev_kfree_skb_any(skb);13191320return ret;1321}132213231324