162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause-Clear 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "core.h" 862306a36Sopenharmony_ci#include "dp_tx.h" 962306a36Sopenharmony_ci#include "debug.h" 1062306a36Sopenharmony_ci#include "hw.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_cistatic enum hal_tcl_encap_type 1362306a36Sopenharmony_ciath12k_dp_tx_get_encap_type(struct ath12k_vif *arvif, struct sk_buff *skb) 1462306a36Sopenharmony_ci{ 1562306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 1662306a36Sopenharmony_ci struct ath12k_base *ab = arvif->ar->ab; 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) 1962306a36Sopenharmony_ci return HAL_TCL_ENCAP_TYPE_RAW; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) 2262306a36Sopenharmony_ci return HAL_TCL_ENCAP_TYPE_ETHERNET; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci return HAL_TCL_ENCAP_TYPE_NATIVE_WIFI; 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic void ath12k_dp_tx_encap_nwifi(struct sk_buff *skb) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 3062306a36Sopenharmony_ci u8 *qos_ctl; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (!ieee80211_is_data_qos(hdr->frame_control)) 3362306a36Sopenharmony_ci return; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci qos_ctl = ieee80211_get_qos_ctl(hdr); 3662306a36Sopenharmony_ci memmove(skb->data + IEEE80211_QOS_CTL_LEN, 3762306a36Sopenharmony_ci skb->data, (void *)qos_ctl - (void *)skb->data); 3862306a36Sopenharmony_ci skb_pull(skb, IEEE80211_QOS_CTL_LEN); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci hdr = (void *)skb->data; 4162306a36Sopenharmony_ci hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic u8 ath12k_dp_tx_get_tid(struct sk_buff *skb) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 4762306a36Sopenharmony_ci struct ath12k_skb_cb *cb = ATH12K_SKB_CB(skb); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (cb->flags & ATH12K_SKB_HW_80211_ENCAP) 5062306a36Sopenharmony_ci return skb->priority & IEEE80211_QOS_CTL_TID_MASK; 5162306a36Sopenharmony_ci else if (!ieee80211_is_data_qos(hdr->frame_control)) 5262306a36Sopenharmony_ci return HAL_DESC_REO_NON_QOS_TID; 5362306a36Sopenharmony_ci else 5462306a36Sopenharmony_ci return skb->priority & IEEE80211_QOS_CTL_TID_MASK; 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cienum hal_encrypt_type ath12k_dp_tx_get_encrypt_type(u32 cipher) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci switch (cipher) { 6062306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP40: 6162306a36Sopenharmony_ci return HAL_ENCRYPT_TYPE_WEP_40; 6262306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_WEP104: 6362306a36Sopenharmony_ci return HAL_ENCRYPT_TYPE_WEP_104; 6462306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_TKIP: 6562306a36Sopenharmony_ci return HAL_ENCRYPT_TYPE_TKIP_MIC; 6662306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP: 6762306a36Sopenharmony_ci return HAL_ENCRYPT_TYPE_CCMP_128; 6862306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_CCMP_256: 6962306a36Sopenharmony_ci return HAL_ENCRYPT_TYPE_CCMP_256; 7062306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP: 7162306a36Sopenharmony_ci return HAL_ENCRYPT_TYPE_GCMP_128; 7262306a36Sopenharmony_ci case WLAN_CIPHER_SUITE_GCMP_256: 7362306a36Sopenharmony_ci return HAL_ENCRYPT_TYPE_AES_GCMP_256; 7462306a36Sopenharmony_ci default: 7562306a36Sopenharmony_ci return HAL_ENCRYPT_TYPE_OPEN; 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void ath12k_dp_tx_release_txbuf(struct ath12k_dp *dp, 8062306a36Sopenharmony_ci struct ath12k_tx_desc_info *tx_desc, 8162306a36Sopenharmony_ci u8 pool_id) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci spin_lock_bh(&dp->tx_desc_lock[pool_id]); 8462306a36Sopenharmony_ci list_move_tail(&tx_desc->list, &dp->tx_desc_free_list[pool_id]); 8562306a36Sopenharmony_ci spin_unlock_bh(&dp->tx_desc_lock[pool_id]); 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic struct ath12k_tx_desc_info *ath12k_dp_tx_assign_buffer(struct ath12k_dp *dp, 8962306a36Sopenharmony_ci u8 pool_id) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct ath12k_tx_desc_info *desc; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci spin_lock_bh(&dp->tx_desc_lock[pool_id]); 9462306a36Sopenharmony_ci desc = list_first_entry_or_null(&dp->tx_desc_free_list[pool_id], 9562306a36Sopenharmony_ci struct ath12k_tx_desc_info, 9662306a36Sopenharmony_ci list); 9762306a36Sopenharmony_ci if (!desc) { 9862306a36Sopenharmony_ci spin_unlock_bh(&dp->tx_desc_lock[pool_id]); 9962306a36Sopenharmony_ci ath12k_warn(dp->ab, "failed to allocate data Tx buffer\n"); 10062306a36Sopenharmony_ci return NULL; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci list_move_tail(&desc->list, &dp->tx_desc_used_list[pool_id]); 10462306a36Sopenharmony_ci spin_unlock_bh(&dp->tx_desc_lock[pool_id]); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci return desc; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void ath12k_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab, void *cmd, 11062306a36Sopenharmony_ci struct hal_tx_info *ti) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct hal_tx_msdu_ext_desc *tcl_ext_cmd = (struct hal_tx_msdu_ext_desc *)cmd; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci tcl_ext_cmd->info0 = le32_encode_bits(ti->paddr, 11562306a36Sopenharmony_ci HAL_TX_MSDU_EXT_INFO0_BUF_PTR_LO); 11662306a36Sopenharmony_ci tcl_ext_cmd->info1 = le32_encode_bits(0x0, 11762306a36Sopenharmony_ci HAL_TX_MSDU_EXT_INFO1_BUF_PTR_HI) | 11862306a36Sopenharmony_ci le32_encode_bits(ti->data_len, 11962306a36Sopenharmony_ci HAL_TX_MSDU_EXT_INFO1_BUF_LEN); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci tcl_ext_cmd->info1 = le32_encode_bits(1, HAL_TX_MSDU_EXT_INFO1_EXTN_OVERRIDE) | 12262306a36Sopenharmony_ci le32_encode_bits(ti->encap_type, 12362306a36Sopenharmony_ci HAL_TX_MSDU_EXT_INFO1_ENCAP_TYPE) | 12462306a36Sopenharmony_ci le32_encode_bits(ti->encrypt_type, 12562306a36Sopenharmony_ci HAL_TX_MSDU_EXT_INFO1_ENCRYPT_TYPE); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ciint ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, 12962306a36Sopenharmony_ci struct sk_buff *skb) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 13262306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 13362306a36Sopenharmony_ci struct hal_tx_info ti = {0}; 13462306a36Sopenharmony_ci struct ath12k_tx_desc_info *tx_desc; 13562306a36Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 13662306a36Sopenharmony_ci struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb); 13762306a36Sopenharmony_ci struct hal_tcl_data_cmd *hal_tcl_desc; 13862306a36Sopenharmony_ci struct hal_tx_msdu_ext_desc *msg; 13962306a36Sopenharmony_ci struct sk_buff *skb_ext_desc; 14062306a36Sopenharmony_ci struct hal_srng *tcl_ring; 14162306a36Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 14262306a36Sopenharmony_ci struct dp_tx_ring *tx_ring; 14362306a36Sopenharmony_ci u8 pool_id; 14462306a36Sopenharmony_ci u8 hal_ring_id; 14562306a36Sopenharmony_ci int ret; 14662306a36Sopenharmony_ci u8 ring_selector, ring_map = 0; 14762306a36Sopenharmony_ci bool tcl_ring_retry; 14862306a36Sopenharmony_ci bool msdu_ext_desc = false; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) 15162306a36Sopenharmony_ci return -ESHUTDOWN; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && 15462306a36Sopenharmony_ci !ieee80211_is_data(hdr->frame_control)) 15562306a36Sopenharmony_ci return -ENOTSUPP; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci pool_id = skb_get_queue_mapping(skb) & (ATH12K_HW_MAX_QUEUES - 1); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* Let the default ring selection be based on current processor 16062306a36Sopenharmony_ci * number, where one of the 3 tcl rings are selected based on 16162306a36Sopenharmony_ci * the smp_processor_id(). In case that ring 16262306a36Sopenharmony_ci * is full/busy, we resort to other available rings. 16362306a36Sopenharmony_ci * If all rings are full, we drop the packet. 16462306a36Sopenharmony_ci * TODO: Add throttling logic when all rings are full 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci ring_selector = ab->hw_params->hw_ops->get_ring_selector(skb); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_citcl_ring_sel: 16962306a36Sopenharmony_ci tcl_ring_retry = false; 17062306a36Sopenharmony_ci ti.ring_id = ring_selector % ab->hw_params->max_tx_ring; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci ring_map |= BIT(ti.ring_id); 17362306a36Sopenharmony_ci ti.rbm_id = ab->hw_params->hal_ops->tcl_to_wbm_rbm_map[ti.ring_id].rbm_id; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci tx_ring = &dp->tx_ring[ti.ring_id]; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci tx_desc = ath12k_dp_tx_assign_buffer(dp, pool_id); 17862306a36Sopenharmony_ci if (!tx_desc) 17962306a36Sopenharmony_ci return -ENOMEM; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci ti.bank_id = arvif->bank_id; 18262306a36Sopenharmony_ci ti.meta_data_flags = arvif->tcl_metadata; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (arvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW && 18562306a36Sopenharmony_ci test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) { 18662306a36Sopenharmony_ci if (skb_cb->flags & ATH12K_SKB_CIPHER_SET) { 18762306a36Sopenharmony_ci ti.encrypt_type = 18862306a36Sopenharmony_ci ath12k_dp_tx_get_encrypt_type(skb_cb->cipher); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci if (ieee80211_has_protected(hdr->frame_control)) 19162306a36Sopenharmony_ci skb_put(skb, IEEE80211_CCMP_MIC_LEN); 19262306a36Sopenharmony_ci } else { 19362306a36Sopenharmony_ci ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci msdu_ext_desc = true; 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci ti.encap_type = ath12k_dp_tx_get_encap_type(arvif, skb); 20062306a36Sopenharmony_ci ti.addr_search_flags = arvif->hal_addr_search_flags; 20162306a36Sopenharmony_ci ti.search_type = arvif->search_type; 20262306a36Sopenharmony_ci ti.type = HAL_TCL_DESC_TYPE_BUFFER; 20362306a36Sopenharmony_ci ti.pkt_offset = 0; 20462306a36Sopenharmony_ci ti.lmac_id = ar->lmac_id; 20562306a36Sopenharmony_ci ti.vdev_id = arvif->vdev_id; 20662306a36Sopenharmony_ci ti.bss_ast_hash = arvif->ast_hash; 20762306a36Sopenharmony_ci ti.bss_ast_idx = arvif->ast_idx; 20862306a36Sopenharmony_ci ti.dscp_tid_tbl_idx = 0; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL && 21162306a36Sopenharmony_ci ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW) { 21262306a36Sopenharmony_ci ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_IP4_CKSUM_EN) | 21362306a36Sopenharmony_ci u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_UDP4_CKSUM_EN) | 21462306a36Sopenharmony_ci u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_UDP6_CKSUM_EN) | 21562306a36Sopenharmony_ci u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TCP4_CKSUM_EN) | 21662306a36Sopenharmony_ci u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TCP6_CKSUM_EN); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci ti.flags1 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO3_TID_OVERWRITE); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci ti.tid = ath12k_dp_tx_get_tid(skb); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci switch (ti.encap_type) { 22462306a36Sopenharmony_ci case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI: 22562306a36Sopenharmony_ci ath12k_dp_tx_encap_nwifi(skb); 22662306a36Sopenharmony_ci break; 22762306a36Sopenharmony_ci case HAL_TCL_ENCAP_TYPE_RAW: 22862306a36Sopenharmony_ci if (!test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) { 22962306a36Sopenharmony_ci ret = -EINVAL; 23062306a36Sopenharmony_ci goto fail_remove_tx_buf; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci break; 23362306a36Sopenharmony_ci case HAL_TCL_ENCAP_TYPE_ETHERNET: 23462306a36Sopenharmony_ci /* no need to encap */ 23562306a36Sopenharmony_ci break; 23662306a36Sopenharmony_ci case HAL_TCL_ENCAP_TYPE_802_3: 23762306a36Sopenharmony_ci default: 23862306a36Sopenharmony_ci /* TODO: Take care of other encap modes as well */ 23962306a36Sopenharmony_ci ret = -EINVAL; 24062306a36Sopenharmony_ci atomic_inc(&ab->soc_stats.tx_err.misc_fail); 24162306a36Sopenharmony_ci goto fail_remove_tx_buf; 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE); 24562306a36Sopenharmony_ci if (dma_mapping_error(ab->dev, ti.paddr)) { 24662306a36Sopenharmony_ci atomic_inc(&ab->soc_stats.tx_err.misc_fail); 24762306a36Sopenharmony_ci ath12k_warn(ab, "failed to DMA map data Tx buffer\n"); 24862306a36Sopenharmony_ci ret = -ENOMEM; 24962306a36Sopenharmony_ci goto fail_remove_tx_buf; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci tx_desc->skb = skb; 25362306a36Sopenharmony_ci tx_desc->mac_id = ar->pdev_idx; 25462306a36Sopenharmony_ci ti.desc_id = tx_desc->desc_id; 25562306a36Sopenharmony_ci ti.data_len = skb->len; 25662306a36Sopenharmony_ci skb_cb->paddr = ti.paddr; 25762306a36Sopenharmony_ci skb_cb->vif = arvif->vif; 25862306a36Sopenharmony_ci skb_cb->ar = ar; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (msdu_ext_desc) { 26162306a36Sopenharmony_ci skb_ext_desc = dev_alloc_skb(sizeof(struct hal_tx_msdu_ext_desc)); 26262306a36Sopenharmony_ci if (!skb_ext_desc) { 26362306a36Sopenharmony_ci ret = -ENOMEM; 26462306a36Sopenharmony_ci goto fail_unmap_dma; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci skb_put(skb_ext_desc, sizeof(struct hal_tx_msdu_ext_desc)); 26862306a36Sopenharmony_ci memset(skb_ext_desc->data, 0, skb_ext_desc->len); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci msg = (struct hal_tx_msdu_ext_desc *)skb_ext_desc->data; 27162306a36Sopenharmony_ci ath12k_hal_tx_cmd_ext_desc_setup(ab, msg, &ti); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci ti.paddr = dma_map_single(ab->dev, skb_ext_desc->data, 27462306a36Sopenharmony_ci skb_ext_desc->len, DMA_TO_DEVICE); 27562306a36Sopenharmony_ci ret = dma_mapping_error(ab->dev, ti.paddr); 27662306a36Sopenharmony_ci if (ret) { 27762306a36Sopenharmony_ci kfree_skb(skb_ext_desc); 27862306a36Sopenharmony_ci goto fail_unmap_dma; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci ti.data_len = skb_ext_desc->len; 28262306a36Sopenharmony_ci ti.type = HAL_TCL_DESC_TYPE_EXT_DESC; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci skb_cb->paddr_ext_desc = ti.paddr; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci hal_ring_id = tx_ring->tcl_data_ring.ring_id; 28862306a36Sopenharmony_ci tcl_ring = &ab->hal.srng_list[hal_ring_id]; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci spin_lock_bh(&tcl_ring->lock); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci ath12k_hal_srng_access_begin(ab, tcl_ring); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci hal_tcl_desc = ath12k_hal_srng_src_get_next_entry(ab, tcl_ring); 29562306a36Sopenharmony_ci if (!hal_tcl_desc) { 29662306a36Sopenharmony_ci /* NOTE: It is highly unlikely we'll be running out of tcl_ring 29762306a36Sopenharmony_ci * desc because the desc is directly enqueued onto hw queue. 29862306a36Sopenharmony_ci */ 29962306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, tcl_ring); 30062306a36Sopenharmony_ci ab->soc_stats.tx_err.desc_na[ti.ring_id]++; 30162306a36Sopenharmony_ci spin_unlock_bh(&tcl_ring->lock); 30262306a36Sopenharmony_ci ret = -ENOMEM; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* Checking for available tcl descriptors in another ring in 30562306a36Sopenharmony_ci * case of failure due to full tcl ring now, is better than 30662306a36Sopenharmony_ci * checking this ring earlier for each pkt tx. 30762306a36Sopenharmony_ci * Restart ring selection if some rings are not checked yet. 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_ci if (ring_map != (BIT(ab->hw_params->max_tx_ring) - 1) && 31062306a36Sopenharmony_ci ab->hw_params->tcl_ring_retry) { 31162306a36Sopenharmony_ci tcl_ring_retry = true; 31262306a36Sopenharmony_ci ring_selector++; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci goto fail_unmap_dma; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci ath12k_hal_tx_cmd_desc_setup(ab, hal_tcl_desc, &ti); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, tcl_ring); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci spin_unlock_bh(&tcl_ring->lock); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci ath12k_dbg_dump(ab, ATH12K_DBG_DP_TX, NULL, "dp tx msdu: ", 32562306a36Sopenharmony_ci skb->data, skb->len); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci atomic_inc(&ar->dp.num_tx_pending); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cifail_unmap_dma: 33262306a36Sopenharmony_ci dma_unmap_single(ab->dev, ti.paddr, ti.data_len, DMA_TO_DEVICE); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (skb_cb->paddr_ext_desc) 33562306a36Sopenharmony_ci dma_unmap_single(ab->dev, skb_cb->paddr_ext_desc, 33662306a36Sopenharmony_ci sizeof(struct hal_tx_msdu_ext_desc), 33762306a36Sopenharmony_ci DMA_TO_DEVICE); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cifail_remove_tx_buf: 34062306a36Sopenharmony_ci ath12k_dp_tx_release_txbuf(dp, tx_desc, pool_id); 34162306a36Sopenharmony_ci if (tcl_ring_retry) 34262306a36Sopenharmony_ci goto tcl_ring_sel; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return ret; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic void ath12k_dp_tx_free_txbuf(struct ath12k_base *ab, 34862306a36Sopenharmony_ci struct sk_buff *msdu, u8 mac_id, 34962306a36Sopenharmony_ci struct dp_tx_ring *tx_ring) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct ath12k *ar; 35262306a36Sopenharmony_ci struct ath12k_skb_cb *skb_cb; 35362306a36Sopenharmony_ci u8 pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci skb_cb = ATH12K_SKB_CB(msdu); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); 35862306a36Sopenharmony_ci if (skb_cb->paddr_ext_desc) 35962306a36Sopenharmony_ci dma_unmap_single(ab->dev, skb_cb->paddr_ext_desc, 36062306a36Sopenharmony_ci sizeof(struct hal_tx_msdu_ext_desc), DMA_TO_DEVICE); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci ar = ab->pdevs[pdev_id].ar; 36562306a36Sopenharmony_ci if (atomic_dec_and_test(&ar->dp.num_tx_pending)) 36662306a36Sopenharmony_ci wake_up(&ar->dp.tx_empty_waitq); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic void 37062306a36Sopenharmony_ciath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, 37162306a36Sopenharmony_ci struct sk_buff *msdu, 37262306a36Sopenharmony_ci struct dp_tx_ring *tx_ring, 37362306a36Sopenharmony_ci struct ath12k_dp_htt_wbm_tx_status *ts) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci struct ieee80211_tx_info *info; 37662306a36Sopenharmony_ci struct ath12k_skb_cb *skb_cb; 37762306a36Sopenharmony_ci struct ath12k *ar; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci skb_cb = ATH12K_SKB_CB(msdu); 38062306a36Sopenharmony_ci info = IEEE80211_SKB_CB(msdu); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci ar = skb_cb->ar; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (atomic_dec_and_test(&ar->dp.num_tx_pending)) 38562306a36Sopenharmony_ci wake_up(&ar->dp.tx_empty_waitq); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); 38862306a36Sopenharmony_ci if (skb_cb->paddr_ext_desc) 38962306a36Sopenharmony_ci dma_unmap_single(ab->dev, skb_cb->paddr_ext_desc, 39062306a36Sopenharmony_ci sizeof(struct hal_tx_msdu_ext_desc), DMA_TO_DEVICE); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci memset(&info->status, 0, sizeof(info->status)); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci if (ts->acked) { 39562306a36Sopenharmony_ci if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { 39662306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 39762306a36Sopenharmony_ci info->status.ack_signal = ATH12K_DEFAULT_NOISE_FLOOR + 39862306a36Sopenharmony_ci ts->ack_rssi; 39962306a36Sopenharmony_ci info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; 40062306a36Sopenharmony_ci } else { 40162306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci ieee80211_tx_status(ar->hw, msdu); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic void 40962306a36Sopenharmony_ciath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab, 41062306a36Sopenharmony_ci void *desc, u8 mac_id, 41162306a36Sopenharmony_ci struct sk_buff *msdu, 41262306a36Sopenharmony_ci struct dp_tx_ring *tx_ring) 41362306a36Sopenharmony_ci{ 41462306a36Sopenharmony_ci struct htt_tx_wbm_completion *status_desc; 41562306a36Sopenharmony_ci struct ath12k_dp_htt_wbm_tx_status ts = {0}; 41662306a36Sopenharmony_ci enum hal_wbm_htt_tx_comp_status wbm_status; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci status_desc = desc + HTT_TX_WBM_COMP_STATUS_OFFSET; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci wbm_status = le32_get_bits(status_desc->info0, 42162306a36Sopenharmony_ci HTT_TX_WBM_COMP_INFO0_STATUS); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci switch (wbm_status) { 42462306a36Sopenharmony_ci case HAL_WBM_REL_HTT_TX_COMP_STATUS_OK: 42562306a36Sopenharmony_ci case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP: 42662306a36Sopenharmony_ci case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL: 42762306a36Sopenharmony_ci ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK); 42862306a36Sopenharmony_ci ts.ack_rssi = le32_get_bits(status_desc->info2, 42962306a36Sopenharmony_ci HTT_TX_WBM_COMP_INFO2_ACK_RSSI); 43062306a36Sopenharmony_ci ath12k_dp_tx_htt_tx_complete_buf(ab, msdu, tx_ring, &ts); 43162306a36Sopenharmony_ci break; 43262306a36Sopenharmony_ci case HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ: 43362306a36Sopenharmony_ci case HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT: 43462306a36Sopenharmony_ci ath12k_dp_tx_free_txbuf(ab, msdu, mac_id, tx_ring); 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci case HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY: 43762306a36Sopenharmony_ci /* This event is to be handled only when the driver decides to 43862306a36Sopenharmony_ci * use WDS offload functionality. 43962306a36Sopenharmony_ci */ 44062306a36Sopenharmony_ci break; 44162306a36Sopenharmony_ci default: 44262306a36Sopenharmony_ci ath12k_warn(ab, "Unknown htt tx status %d\n", wbm_status); 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic void ath12k_dp_tx_complete_msdu(struct ath12k *ar, 44862306a36Sopenharmony_ci struct sk_buff *msdu, 44962306a36Sopenharmony_ci struct hal_tx_status *ts) 45062306a36Sopenharmony_ci{ 45162306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 45262306a36Sopenharmony_ci struct ieee80211_tx_info *info; 45362306a36Sopenharmony_ci struct ath12k_skb_cb *skb_cb; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci if (WARN_ON_ONCE(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) { 45662306a36Sopenharmony_ci /* Must not happen */ 45762306a36Sopenharmony_ci return; 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci skb_cb = ATH12K_SKB_CB(msdu); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci dma_unmap_single(ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); 46362306a36Sopenharmony_ci if (skb_cb->paddr_ext_desc) 46462306a36Sopenharmony_ci dma_unmap_single(ab->dev, skb_cb->paddr_ext_desc, 46562306a36Sopenharmony_ci sizeof(struct hal_tx_msdu_ext_desc), DMA_TO_DEVICE); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci rcu_read_lock(); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (!rcu_dereference(ab->pdevs_active[ar->pdev_idx])) { 47062306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 47162306a36Sopenharmony_ci goto exit; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (!skb_cb->vif) { 47562306a36Sopenharmony_ci dev_kfree_skb_any(msdu); 47662306a36Sopenharmony_ci goto exit; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci info = IEEE80211_SKB_CB(msdu); 48062306a36Sopenharmony_ci memset(&info->status, 0, sizeof(info->status)); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* skip tx rate update from ieee80211_status*/ 48362306a36Sopenharmony_ci info->status.rates[0].idx = -1; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (ts->status == HAL_WBM_TQM_REL_REASON_FRAME_ACKED && 48662306a36Sopenharmony_ci !(info->flags & IEEE80211_TX_CTL_NO_ACK)) { 48762306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_ACK; 48862306a36Sopenharmony_ci info->status.ack_signal = ATH12K_DEFAULT_NOISE_FLOOR + 48962306a36Sopenharmony_ci ts->ack_rssi; 49062306a36Sopenharmony_ci info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (ts->status == HAL_WBM_TQM_REL_REASON_CMD_REMOVE_TX && 49462306a36Sopenharmony_ci (info->flags & IEEE80211_TX_CTL_NO_ACK)) 49562306a36Sopenharmony_ci info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci /* NOTE: Tx rate status reporting. Tx completion status does not have 49862306a36Sopenharmony_ci * necessary information (for example nss) to build the tx rate. 49962306a36Sopenharmony_ci * Might end up reporting it out-of-band from HTT stats. 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci ieee80211_tx_status(ar->hw, msdu); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ciexit: 50562306a36Sopenharmony_ci rcu_read_unlock(); 50662306a36Sopenharmony_ci} 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic void ath12k_dp_tx_status_parse(struct ath12k_base *ab, 50962306a36Sopenharmony_ci struct hal_wbm_completion_ring_tx *desc, 51062306a36Sopenharmony_ci struct hal_tx_status *ts) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci ts->buf_rel_source = 51362306a36Sopenharmony_ci le32_get_bits(desc->info0, HAL_WBM_COMPL_TX_INFO0_REL_SRC_MODULE); 51462306a36Sopenharmony_ci if (ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW && 51562306a36Sopenharmony_ci ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM) 51662306a36Sopenharmony_ci return; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) 51962306a36Sopenharmony_ci return; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci ts->status = le32_get_bits(desc->info0, 52262306a36Sopenharmony_ci HAL_WBM_COMPL_TX_INFO0_TQM_RELEASE_REASON); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci ts->ppdu_id = le32_get_bits(desc->info1, 52562306a36Sopenharmony_ci HAL_WBM_COMPL_TX_INFO1_TQM_STATUS_NUMBER); 52662306a36Sopenharmony_ci if (le32_to_cpu(desc->rate_stats.info0) & HAL_TX_RATE_STATS_INFO0_VALID) 52762306a36Sopenharmony_ci ts->rate_stats = le32_to_cpu(desc->rate_stats.info0); 52862306a36Sopenharmony_ci else 52962306a36Sopenharmony_ci ts->rate_stats = 0; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_civoid ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci struct ath12k *ar; 53562306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 53662306a36Sopenharmony_ci int hal_ring_id = dp->tx_ring[ring_id].tcl_comp_ring.ring_id; 53762306a36Sopenharmony_ci struct hal_srng *status_ring = &ab->hal.srng_list[hal_ring_id]; 53862306a36Sopenharmony_ci struct ath12k_tx_desc_info *tx_desc = NULL; 53962306a36Sopenharmony_ci struct sk_buff *msdu; 54062306a36Sopenharmony_ci struct hal_tx_status ts = { 0 }; 54162306a36Sopenharmony_ci struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id]; 54262306a36Sopenharmony_ci struct hal_wbm_release_ring *desc; 54362306a36Sopenharmony_ci u8 mac_id, pdev_id; 54462306a36Sopenharmony_ci u64 desc_va; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci spin_lock_bh(&status_ring->lock); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci ath12k_hal_srng_access_begin(ab, status_ring); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci while (ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_head) != tx_ring->tx_status_tail) { 55162306a36Sopenharmony_ci desc = ath12k_hal_srng_dst_get_next_entry(ab, status_ring); 55262306a36Sopenharmony_ci if (!desc) 55362306a36Sopenharmony_ci break; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci memcpy(&tx_ring->tx_status[tx_ring->tx_status_head], 55662306a36Sopenharmony_ci desc, sizeof(*desc)); 55762306a36Sopenharmony_ci tx_ring->tx_status_head = 55862306a36Sopenharmony_ci ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_head); 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (ath12k_hal_srng_dst_peek(ab, status_ring) && 56262306a36Sopenharmony_ci (ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_head) == tx_ring->tx_status_tail)) { 56362306a36Sopenharmony_ci /* TODO: Process pending tx_status messages when kfifo_is_full() */ 56462306a36Sopenharmony_ci ath12k_warn(ab, "Unable to process some of the tx_status ring desc because status_fifo is full\n"); 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci ath12k_hal_srng_access_end(ab, status_ring); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci spin_unlock_bh(&status_ring->lock); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci while (ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_tail) != tx_ring->tx_status_head) { 57262306a36Sopenharmony_ci struct hal_wbm_completion_ring_tx *tx_status; 57362306a36Sopenharmony_ci u32 desc_id; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci tx_ring->tx_status_tail = 57662306a36Sopenharmony_ci ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_tail); 57762306a36Sopenharmony_ci tx_status = &tx_ring->tx_status[tx_ring->tx_status_tail]; 57862306a36Sopenharmony_ci ath12k_dp_tx_status_parse(ab, tx_status, &ts); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci if (le32_get_bits(tx_status->info0, HAL_WBM_COMPL_TX_INFO0_CC_DONE)) { 58162306a36Sopenharmony_ci /* HW done cookie conversion */ 58262306a36Sopenharmony_ci desc_va = ((u64)le32_to_cpu(tx_status->buf_va_hi) << 32 | 58362306a36Sopenharmony_ci le32_to_cpu(tx_status->buf_va_lo)); 58462306a36Sopenharmony_ci tx_desc = (struct ath12k_tx_desc_info *)((unsigned long)desc_va); 58562306a36Sopenharmony_ci } else { 58662306a36Sopenharmony_ci /* SW does cookie conversion to VA */ 58762306a36Sopenharmony_ci desc_id = le32_get_bits(tx_status->buf_va_hi, 58862306a36Sopenharmony_ci BUFFER_ADDR_INFO1_SW_COOKIE); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci tx_desc = ath12k_dp_get_tx_desc(ab, desc_id); 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci if (!tx_desc) { 59362306a36Sopenharmony_ci ath12k_warn(ab, "unable to retrieve tx_desc!"); 59462306a36Sopenharmony_ci continue; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci msdu = tx_desc->skb; 59862306a36Sopenharmony_ci mac_id = tx_desc->mac_id; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci /* Release descriptor as soon as extracting necessary info 60162306a36Sopenharmony_ci * to reduce contention 60262306a36Sopenharmony_ci */ 60362306a36Sopenharmony_ci ath12k_dp_tx_release_txbuf(dp, tx_desc, tx_desc->pool_id); 60462306a36Sopenharmony_ci if (ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) { 60562306a36Sopenharmony_ci ath12k_dp_tx_process_htt_tx_complete(ab, 60662306a36Sopenharmony_ci (void *)tx_status, 60762306a36Sopenharmony_ci mac_id, msdu, 60862306a36Sopenharmony_ci tx_ring); 60962306a36Sopenharmony_ci continue; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); 61362306a36Sopenharmony_ci ar = ab->pdevs[pdev_id].ar; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci if (atomic_dec_and_test(&ar->dp.num_tx_pending)) 61662306a36Sopenharmony_ci wake_up(&ar->dp.tx_empty_waitq); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci ath12k_dp_tx_complete_msdu(ar, msdu, &ts); 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic int 62362306a36Sopenharmony_ciath12k_dp_tx_get_ring_id_type(struct ath12k_base *ab, 62462306a36Sopenharmony_ci int mac_id, u32 ring_id, 62562306a36Sopenharmony_ci enum hal_ring_type ring_type, 62662306a36Sopenharmony_ci enum htt_srng_ring_type *htt_ring_type, 62762306a36Sopenharmony_ci enum htt_srng_ring_id *htt_ring_id) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci int ret = 0; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci switch (ring_type) { 63262306a36Sopenharmony_ci case HAL_RXDMA_BUF: 63362306a36Sopenharmony_ci /* for some targets, host fills rx buffer to fw and fw fills to 63462306a36Sopenharmony_ci * rxbuf ring for each rxdma 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_ci if (!ab->hw_params->rx_mac_buf_ring) { 63762306a36Sopenharmony_ci if (!(ring_id == HAL_SRNG_SW2RXDMA_BUF0 || 63862306a36Sopenharmony_ci ring_id == HAL_SRNG_SW2RXDMA_BUF1)) { 63962306a36Sopenharmony_ci ret = -EINVAL; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci *htt_ring_id = HTT_RXDMA_HOST_BUF_RING; 64262306a36Sopenharmony_ci *htt_ring_type = HTT_SW_TO_HW_RING; 64362306a36Sopenharmony_ci } else { 64462306a36Sopenharmony_ci if (ring_id == HAL_SRNG_SW2RXDMA_BUF0) { 64562306a36Sopenharmony_ci *htt_ring_id = HTT_HOST1_TO_FW_RXBUF_RING; 64662306a36Sopenharmony_ci *htt_ring_type = HTT_SW_TO_SW_RING; 64762306a36Sopenharmony_ci } else { 64862306a36Sopenharmony_ci *htt_ring_id = HTT_RXDMA_HOST_BUF_RING; 64962306a36Sopenharmony_ci *htt_ring_type = HTT_SW_TO_HW_RING; 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci break; 65362306a36Sopenharmony_ci case HAL_RXDMA_DST: 65462306a36Sopenharmony_ci *htt_ring_id = HTT_RXDMA_NON_MONITOR_DEST_RING; 65562306a36Sopenharmony_ci *htt_ring_type = HTT_HW_TO_SW_RING; 65662306a36Sopenharmony_ci break; 65762306a36Sopenharmony_ci case HAL_RXDMA_MONITOR_BUF: 65862306a36Sopenharmony_ci *htt_ring_id = HTT_RXDMA_MONITOR_BUF_RING; 65962306a36Sopenharmony_ci *htt_ring_type = HTT_SW_TO_HW_RING; 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci case HAL_RXDMA_MONITOR_STATUS: 66262306a36Sopenharmony_ci *htt_ring_id = HTT_RXDMA_MONITOR_STATUS_RING; 66362306a36Sopenharmony_ci *htt_ring_type = HTT_SW_TO_HW_RING; 66462306a36Sopenharmony_ci break; 66562306a36Sopenharmony_ci case HAL_RXDMA_MONITOR_DST: 66662306a36Sopenharmony_ci *htt_ring_id = HTT_RXDMA_MONITOR_DEST_RING; 66762306a36Sopenharmony_ci *htt_ring_type = HTT_HW_TO_SW_RING; 66862306a36Sopenharmony_ci break; 66962306a36Sopenharmony_ci case HAL_RXDMA_MONITOR_DESC: 67062306a36Sopenharmony_ci *htt_ring_id = HTT_RXDMA_MONITOR_DESC_RING; 67162306a36Sopenharmony_ci *htt_ring_type = HTT_SW_TO_HW_RING; 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci case HAL_TX_MONITOR_BUF: 67462306a36Sopenharmony_ci *htt_ring_id = HTT_TX_MON_HOST2MON_BUF_RING; 67562306a36Sopenharmony_ci *htt_ring_type = HTT_SW_TO_HW_RING; 67662306a36Sopenharmony_ci break; 67762306a36Sopenharmony_ci case HAL_TX_MONITOR_DST: 67862306a36Sopenharmony_ci *htt_ring_id = HTT_TX_MON_MON2HOST_DEST_RING; 67962306a36Sopenharmony_ci *htt_ring_type = HTT_HW_TO_SW_RING; 68062306a36Sopenharmony_ci break; 68162306a36Sopenharmony_ci default: 68262306a36Sopenharmony_ci ath12k_warn(ab, "Unsupported ring type in DP :%d\n", ring_type); 68362306a36Sopenharmony_ci ret = -EINVAL; 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci return ret; 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ciint ath12k_dp_tx_htt_srng_setup(struct ath12k_base *ab, u32 ring_id, 68962306a36Sopenharmony_ci int mac_id, enum hal_ring_type ring_type) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci struct htt_srng_setup_cmd *cmd; 69262306a36Sopenharmony_ci struct hal_srng *srng = &ab->hal.srng_list[ring_id]; 69362306a36Sopenharmony_ci struct hal_srng_params params; 69462306a36Sopenharmony_ci struct sk_buff *skb; 69562306a36Sopenharmony_ci u32 ring_entry_sz; 69662306a36Sopenharmony_ci int len = sizeof(*cmd); 69762306a36Sopenharmony_ci dma_addr_t hp_addr, tp_addr; 69862306a36Sopenharmony_ci enum htt_srng_ring_type htt_ring_type; 69962306a36Sopenharmony_ci enum htt_srng_ring_id htt_ring_id; 70062306a36Sopenharmony_ci int ret; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci skb = ath12k_htc_alloc_skb(ab, len); 70362306a36Sopenharmony_ci if (!skb) 70462306a36Sopenharmony_ci return -ENOMEM; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 70762306a36Sopenharmony_ci ath12k_hal_srng_get_params(ab, srng, ¶ms); 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci hp_addr = ath12k_hal_srng_get_hp_addr(ab, srng); 71062306a36Sopenharmony_ci tp_addr = ath12k_hal_srng_get_tp_addr(ab, srng); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci ret = ath12k_dp_tx_get_ring_id_type(ab, mac_id, ring_id, 71362306a36Sopenharmony_ci ring_type, &htt_ring_type, 71462306a36Sopenharmony_ci &htt_ring_id); 71562306a36Sopenharmony_ci if (ret) 71662306a36Sopenharmony_ci goto err_free; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci skb_put(skb, len); 71962306a36Sopenharmony_ci cmd = (struct htt_srng_setup_cmd *)skb->data; 72062306a36Sopenharmony_ci cmd->info0 = le32_encode_bits(HTT_H2T_MSG_TYPE_SRING_SETUP, 72162306a36Sopenharmony_ci HTT_SRNG_SETUP_CMD_INFO0_MSG_TYPE); 72262306a36Sopenharmony_ci if (htt_ring_type == HTT_SW_TO_HW_RING || 72362306a36Sopenharmony_ci htt_ring_type == HTT_HW_TO_SW_RING) 72462306a36Sopenharmony_ci cmd->info0 |= le32_encode_bits(DP_SW2HW_MACID(mac_id), 72562306a36Sopenharmony_ci HTT_SRNG_SETUP_CMD_INFO0_PDEV_ID); 72662306a36Sopenharmony_ci else 72762306a36Sopenharmony_ci cmd->info0 |= le32_encode_bits(mac_id, 72862306a36Sopenharmony_ci HTT_SRNG_SETUP_CMD_INFO0_PDEV_ID); 72962306a36Sopenharmony_ci cmd->info0 |= le32_encode_bits(htt_ring_type, 73062306a36Sopenharmony_ci HTT_SRNG_SETUP_CMD_INFO0_RING_TYPE); 73162306a36Sopenharmony_ci cmd->info0 |= le32_encode_bits(htt_ring_id, 73262306a36Sopenharmony_ci HTT_SRNG_SETUP_CMD_INFO0_RING_ID); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci cmd->ring_base_addr_lo = cpu_to_le32(params.ring_base_paddr & 73562306a36Sopenharmony_ci HAL_ADDR_LSB_REG_MASK); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci cmd->ring_base_addr_hi = cpu_to_le32((u64)params.ring_base_paddr >> 73862306a36Sopenharmony_ci HAL_ADDR_MSB_REG_SHIFT); 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci ret = ath12k_hal_srng_get_entrysize(ab, ring_type); 74162306a36Sopenharmony_ci if (ret < 0) 74262306a36Sopenharmony_ci goto err_free; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci ring_entry_sz = ret; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci ring_entry_sz >>= 2; 74762306a36Sopenharmony_ci cmd->info1 = le32_encode_bits(ring_entry_sz, 74862306a36Sopenharmony_ci HTT_SRNG_SETUP_CMD_INFO1_RING_ENTRY_SIZE); 74962306a36Sopenharmony_ci cmd->info1 |= le32_encode_bits(params.num_entries * ring_entry_sz, 75062306a36Sopenharmony_ci HTT_SRNG_SETUP_CMD_INFO1_RING_SIZE); 75162306a36Sopenharmony_ci cmd->info1 |= le32_encode_bits(!!(params.flags & HAL_SRNG_FLAGS_MSI_SWAP), 75262306a36Sopenharmony_ci HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_MSI_SWAP); 75362306a36Sopenharmony_ci cmd->info1 |= le32_encode_bits(!!(params.flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP), 75462306a36Sopenharmony_ci HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_TLV_SWAP); 75562306a36Sopenharmony_ci cmd->info1 |= le32_encode_bits(!!(params.flags & HAL_SRNG_FLAGS_RING_PTR_SWAP), 75662306a36Sopenharmony_ci HTT_SRNG_SETUP_CMD_INFO1_RING_FLAGS_HOST_FW_SWAP); 75762306a36Sopenharmony_ci if (htt_ring_type == HTT_SW_TO_HW_RING) 75862306a36Sopenharmony_ci cmd->info1 |= cpu_to_le32(HTT_SRNG_SETUP_CMD_INFO1_RING_LOOP_CNT_DIS); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci cmd->ring_head_off32_remote_addr_lo = cpu_to_le32(lower_32_bits(hp_addr)); 76162306a36Sopenharmony_ci cmd->ring_head_off32_remote_addr_hi = cpu_to_le32(upper_32_bits(hp_addr)); 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci cmd->ring_tail_off32_remote_addr_lo = cpu_to_le32(lower_32_bits(tp_addr)); 76462306a36Sopenharmony_ci cmd->ring_tail_off32_remote_addr_hi = cpu_to_le32(upper_32_bits(tp_addr)); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci cmd->ring_msi_addr_lo = cpu_to_le32(lower_32_bits(params.msi_addr)); 76762306a36Sopenharmony_ci cmd->ring_msi_addr_hi = cpu_to_le32(upper_32_bits(params.msi_addr)); 76862306a36Sopenharmony_ci cmd->msi_data = cpu_to_le32(params.msi_data); 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci cmd->intr_info = 77162306a36Sopenharmony_ci le32_encode_bits(params.intr_batch_cntr_thres_entries * ring_entry_sz, 77262306a36Sopenharmony_ci HTT_SRNG_SETUP_CMD_INTR_INFO_BATCH_COUNTER_THRESH); 77362306a36Sopenharmony_ci cmd->intr_info |= 77462306a36Sopenharmony_ci le32_encode_bits(params.intr_timer_thres_us >> 3, 77562306a36Sopenharmony_ci HTT_SRNG_SETUP_CMD_INTR_INFO_INTR_TIMER_THRESH); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci cmd->info2 = 0; 77862306a36Sopenharmony_ci if (params.flags & HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN) { 77962306a36Sopenharmony_ci cmd->info2 = le32_encode_bits(params.low_threshold, 78062306a36Sopenharmony_ci HTT_SRNG_SETUP_CMD_INFO2_INTR_LOW_THRESH); 78162306a36Sopenharmony_ci } 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_HAL, 78462306a36Sopenharmony_ci "%s msi_addr_lo:0x%x, msi_addr_hi:0x%x, msi_data:0x%x\n", 78562306a36Sopenharmony_ci __func__, cmd->ring_msi_addr_lo, cmd->ring_msi_addr_hi, 78662306a36Sopenharmony_ci cmd->msi_data); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci ath12k_dbg(ab, ATH12K_DBG_HAL, 78962306a36Sopenharmony_ci "ring_id:%d, ring_type:%d, intr_info:0x%x, flags:0x%x\n", 79062306a36Sopenharmony_ci ring_id, ring_type, cmd->intr_info, cmd->info2); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci ret = ath12k_htc_send(&ab->htc, ab->dp.eid, skb); 79362306a36Sopenharmony_ci if (ret) 79462306a36Sopenharmony_ci goto err_free; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci return 0; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cierr_free: 79962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci return ret; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci#define HTT_TARGET_VERSION_TIMEOUT_HZ (3 * HZ) 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ciint ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 80962306a36Sopenharmony_ci struct sk_buff *skb; 81062306a36Sopenharmony_ci struct htt_ver_req_cmd *cmd; 81162306a36Sopenharmony_ci int len = sizeof(*cmd); 81262306a36Sopenharmony_ci int ret; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci init_completion(&dp->htt_tgt_version_received); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci skb = ath12k_htc_alloc_skb(ab, len); 81762306a36Sopenharmony_ci if (!skb) 81862306a36Sopenharmony_ci return -ENOMEM; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci skb_put(skb, len); 82162306a36Sopenharmony_ci cmd = (struct htt_ver_req_cmd *)skb->data; 82262306a36Sopenharmony_ci cmd->ver_reg_info = le32_encode_bits(HTT_H2T_MSG_TYPE_VERSION_REQ, 82362306a36Sopenharmony_ci HTT_VER_REQ_INFO_MSG_ID); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci ret = ath12k_htc_send(&ab->htc, dp->eid, skb); 82662306a36Sopenharmony_ci if (ret) { 82762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 82862306a36Sopenharmony_ci return ret; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci ret = wait_for_completion_timeout(&dp->htt_tgt_version_received, 83262306a36Sopenharmony_ci HTT_TARGET_VERSION_TIMEOUT_HZ); 83362306a36Sopenharmony_ci if (ret == 0) { 83462306a36Sopenharmony_ci ath12k_warn(ab, "htt target version request timed out\n"); 83562306a36Sopenharmony_ci return -ETIMEDOUT; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci if (dp->htt_tgt_ver_major != HTT_TARGET_VERSION_MAJOR) { 83962306a36Sopenharmony_ci ath12k_err(ab, "unsupported htt major version %d supported version is %d\n", 84062306a36Sopenharmony_ci dp->htt_tgt_ver_major, HTT_TARGET_VERSION_MAJOR); 84162306a36Sopenharmony_ci return -ENOTSUPP; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci return 0; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ciint ath12k_dp_tx_htt_h2t_ppdu_stats_req(struct ath12k *ar, u32 mask) 84862306a36Sopenharmony_ci{ 84962306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 85062306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 85162306a36Sopenharmony_ci struct sk_buff *skb; 85262306a36Sopenharmony_ci struct htt_ppdu_stats_cfg_cmd *cmd; 85362306a36Sopenharmony_ci int len = sizeof(*cmd); 85462306a36Sopenharmony_ci u8 pdev_mask; 85562306a36Sopenharmony_ci int ret; 85662306a36Sopenharmony_ci int i; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci for (i = 0; i < ab->hw_params->num_rxmda_per_pdev; i++) { 85962306a36Sopenharmony_ci skb = ath12k_htc_alloc_skb(ab, len); 86062306a36Sopenharmony_ci if (!skb) 86162306a36Sopenharmony_ci return -ENOMEM; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci skb_put(skb, len); 86462306a36Sopenharmony_ci cmd = (struct htt_ppdu_stats_cfg_cmd *)skb->data; 86562306a36Sopenharmony_ci cmd->msg = le32_encode_bits(HTT_H2T_MSG_TYPE_PPDU_STATS_CFG, 86662306a36Sopenharmony_ci HTT_PPDU_STATS_CFG_MSG_TYPE); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci pdev_mask = 1 << (i + 1); 86962306a36Sopenharmony_ci cmd->msg |= le32_encode_bits(pdev_mask, HTT_PPDU_STATS_CFG_PDEV_ID); 87062306a36Sopenharmony_ci cmd->msg |= le32_encode_bits(mask, HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci ret = ath12k_htc_send(&ab->htc, dp->eid, skb); 87362306a36Sopenharmony_ci if (ret) { 87462306a36Sopenharmony_ci dev_kfree_skb_any(skb); 87562306a36Sopenharmony_ci return ret; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci return 0; 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ciint ath12k_dp_tx_htt_rx_filter_setup(struct ath12k_base *ab, u32 ring_id, 88362306a36Sopenharmony_ci int mac_id, enum hal_ring_type ring_type, 88462306a36Sopenharmony_ci int rx_buf_size, 88562306a36Sopenharmony_ci struct htt_rx_ring_tlv_filter *tlv_filter) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci struct htt_rx_ring_selection_cfg_cmd *cmd; 88862306a36Sopenharmony_ci struct hal_srng *srng = &ab->hal.srng_list[ring_id]; 88962306a36Sopenharmony_ci struct hal_srng_params params; 89062306a36Sopenharmony_ci struct sk_buff *skb; 89162306a36Sopenharmony_ci int len = sizeof(*cmd); 89262306a36Sopenharmony_ci enum htt_srng_ring_type htt_ring_type; 89362306a36Sopenharmony_ci enum htt_srng_ring_id htt_ring_id; 89462306a36Sopenharmony_ci int ret; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci skb = ath12k_htc_alloc_skb(ab, len); 89762306a36Sopenharmony_ci if (!skb) 89862306a36Sopenharmony_ci return -ENOMEM; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 90162306a36Sopenharmony_ci ath12k_hal_srng_get_params(ab, srng, ¶ms); 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci ret = ath12k_dp_tx_get_ring_id_type(ab, mac_id, ring_id, 90462306a36Sopenharmony_ci ring_type, &htt_ring_type, 90562306a36Sopenharmony_ci &htt_ring_id); 90662306a36Sopenharmony_ci if (ret) 90762306a36Sopenharmony_ci goto err_free; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci skb_put(skb, len); 91062306a36Sopenharmony_ci cmd = (struct htt_rx_ring_selection_cfg_cmd *)skb->data; 91162306a36Sopenharmony_ci cmd->info0 = le32_encode_bits(HTT_H2T_MSG_TYPE_RX_RING_SELECTION_CFG, 91262306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_CMD_INFO0_MSG_TYPE); 91362306a36Sopenharmony_ci if (htt_ring_type == HTT_SW_TO_HW_RING || 91462306a36Sopenharmony_ci htt_ring_type == HTT_HW_TO_SW_RING) 91562306a36Sopenharmony_ci cmd->info0 |= 91662306a36Sopenharmony_ci le32_encode_bits(DP_SW2HW_MACID(mac_id), 91762306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PDEV_ID); 91862306a36Sopenharmony_ci else 91962306a36Sopenharmony_ci cmd->info0 |= 92062306a36Sopenharmony_ci le32_encode_bits(mac_id, 92162306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PDEV_ID); 92262306a36Sopenharmony_ci cmd->info0 |= le32_encode_bits(htt_ring_id, 92362306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_CMD_INFO0_RING_ID); 92462306a36Sopenharmony_ci cmd->info0 |= le32_encode_bits(!!(params.flags & HAL_SRNG_FLAGS_MSI_SWAP), 92562306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_CMD_INFO0_SS); 92662306a36Sopenharmony_ci cmd->info0 |= le32_encode_bits(!!(params.flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP), 92762306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_CMD_INFO0_PS); 92862306a36Sopenharmony_ci cmd->info0 |= le32_encode_bits(tlv_filter->offset_valid, 92962306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_CMD_OFFSET_VALID); 93062306a36Sopenharmony_ci cmd->info1 = le32_encode_bits(rx_buf_size, 93162306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_CMD_INFO1_BUF_SIZE); 93262306a36Sopenharmony_ci cmd->pkt_type_en_flags0 = cpu_to_le32(tlv_filter->pkt_filter_flags0); 93362306a36Sopenharmony_ci cmd->pkt_type_en_flags1 = cpu_to_le32(tlv_filter->pkt_filter_flags1); 93462306a36Sopenharmony_ci cmd->pkt_type_en_flags2 = cpu_to_le32(tlv_filter->pkt_filter_flags2); 93562306a36Sopenharmony_ci cmd->pkt_type_en_flags3 = cpu_to_le32(tlv_filter->pkt_filter_flags3); 93662306a36Sopenharmony_ci cmd->rx_filter_tlv = cpu_to_le32(tlv_filter->rx_filter); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci if (tlv_filter->offset_valid) { 93962306a36Sopenharmony_ci cmd->rx_packet_offset = 94062306a36Sopenharmony_ci le32_encode_bits(tlv_filter->rx_packet_offset, 94162306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_RX_PACKET_OFFSET); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci cmd->rx_packet_offset |= 94462306a36Sopenharmony_ci le32_encode_bits(tlv_filter->rx_header_offset, 94562306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_RX_HEADER_OFFSET); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci cmd->rx_mpdu_offset = 94862306a36Sopenharmony_ci le32_encode_bits(tlv_filter->rx_mpdu_end_offset, 94962306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_RX_MPDU_END_OFFSET); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci cmd->rx_mpdu_offset |= 95262306a36Sopenharmony_ci le32_encode_bits(tlv_filter->rx_mpdu_start_offset, 95362306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_RX_MPDU_START_OFFSET); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci cmd->rx_msdu_offset = 95662306a36Sopenharmony_ci le32_encode_bits(tlv_filter->rx_msdu_end_offset, 95762306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_RX_MSDU_END_OFFSET); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci cmd->rx_msdu_offset |= 96062306a36Sopenharmony_ci le32_encode_bits(tlv_filter->rx_msdu_start_offset, 96162306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_RX_MSDU_START_OFFSET); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci cmd->rx_attn_offset = 96462306a36Sopenharmony_ci le32_encode_bits(tlv_filter->rx_attn_offset, 96562306a36Sopenharmony_ci HTT_RX_RING_SELECTION_CFG_RX_ATTENTION_OFFSET); 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci ret = ath12k_htc_send(&ab->htc, ab->dp.eid, skb); 96962306a36Sopenharmony_ci if (ret) 97062306a36Sopenharmony_ci goto err_free; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci return 0; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_cierr_free: 97562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci return ret; 97862306a36Sopenharmony_ci} 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ciint 98162306a36Sopenharmony_ciath12k_dp_tx_htt_h2t_ext_stats_req(struct ath12k *ar, u8 type, 98262306a36Sopenharmony_ci struct htt_ext_stats_cfg_params *cfg_params, 98362306a36Sopenharmony_ci u64 cookie) 98462306a36Sopenharmony_ci{ 98562306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 98662306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 98762306a36Sopenharmony_ci struct sk_buff *skb; 98862306a36Sopenharmony_ci struct htt_ext_stats_cfg_cmd *cmd; 98962306a36Sopenharmony_ci int len = sizeof(*cmd); 99062306a36Sopenharmony_ci int ret; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci skb = ath12k_htc_alloc_skb(ab, len); 99362306a36Sopenharmony_ci if (!skb) 99462306a36Sopenharmony_ci return -ENOMEM; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci skb_put(skb, len); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci cmd = (struct htt_ext_stats_cfg_cmd *)skb->data; 99962306a36Sopenharmony_ci memset(cmd, 0, sizeof(*cmd)); 100062306a36Sopenharmony_ci cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_EXT_STATS_CFG; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci cmd->hdr.pdev_mask = 1 << ar->pdev->pdev_id; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci cmd->hdr.stats_type = type; 100562306a36Sopenharmony_ci cmd->cfg_param0 = cpu_to_le32(cfg_params->cfg0); 100662306a36Sopenharmony_ci cmd->cfg_param1 = cpu_to_le32(cfg_params->cfg1); 100762306a36Sopenharmony_ci cmd->cfg_param2 = cpu_to_le32(cfg_params->cfg2); 100862306a36Sopenharmony_ci cmd->cfg_param3 = cpu_to_le32(cfg_params->cfg3); 100962306a36Sopenharmony_ci cmd->cookie_lsb = cpu_to_le32(lower_32_bits(cookie)); 101062306a36Sopenharmony_ci cmd->cookie_msb = cpu_to_le32(upper_32_bits(cookie)); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci ret = ath12k_htc_send(&ab->htc, dp->eid, skb); 101362306a36Sopenharmony_ci if (ret) { 101462306a36Sopenharmony_ci ath12k_warn(ab, "failed to send htt type stats request: %d", 101562306a36Sopenharmony_ci ret); 101662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 101762306a36Sopenharmony_ci return ret; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci return 0; 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ciint ath12k_dp_tx_htt_monitor_mode_ring_config(struct ath12k *ar, bool reset) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 102662306a36Sopenharmony_ci int ret; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_tx_monitor_mode_ring_config(ar, reset); 102962306a36Sopenharmony_ci if (ret) { 103062306a36Sopenharmony_ci ath12k_err(ab, "failed to setup tx monitor filter %d\n", ret); 103162306a36Sopenharmony_ci return ret; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_tx_monitor_mode_ring_config(ar, reset); 103562306a36Sopenharmony_ci if (ret) { 103662306a36Sopenharmony_ci ath12k_err(ab, "failed to setup rx monitor filter %d\n", ret); 103762306a36Sopenharmony_ci return ret; 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci return 0; 104162306a36Sopenharmony_ci} 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ciint ath12k_dp_tx_htt_rx_monitor_mode_ring_config(struct ath12k *ar, bool reset) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 104662306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 104762306a36Sopenharmony_ci struct htt_rx_ring_tlv_filter tlv_filter = {0}; 104862306a36Sopenharmony_ci int ret, ring_id; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci ring_id = dp->rxdma_mon_buf_ring.refill_buf_ring.ring_id; 105162306a36Sopenharmony_ci tlv_filter.offset_valid = false; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if (!reset) { 105462306a36Sopenharmony_ci tlv_filter.rx_filter = HTT_RX_MON_FILTER_TLV_FLAGS_MON_BUF_RING; 105562306a36Sopenharmony_ci tlv_filter.pkt_filter_flags0 = 105662306a36Sopenharmony_ci HTT_RX_MON_FP_MGMT_FILTER_FLAGS0 | 105762306a36Sopenharmony_ci HTT_RX_MON_MO_MGMT_FILTER_FLAGS0; 105862306a36Sopenharmony_ci tlv_filter.pkt_filter_flags1 = 105962306a36Sopenharmony_ci HTT_RX_MON_FP_MGMT_FILTER_FLAGS1 | 106062306a36Sopenharmony_ci HTT_RX_MON_MO_MGMT_FILTER_FLAGS1; 106162306a36Sopenharmony_ci tlv_filter.pkt_filter_flags2 = 106262306a36Sopenharmony_ci HTT_RX_MON_FP_CTRL_FILTER_FLASG2 | 106362306a36Sopenharmony_ci HTT_RX_MON_MO_CTRL_FILTER_FLASG2; 106462306a36Sopenharmony_ci tlv_filter.pkt_filter_flags3 = 106562306a36Sopenharmony_ci HTT_RX_MON_FP_CTRL_FILTER_FLASG3 | 106662306a36Sopenharmony_ci HTT_RX_MON_MO_CTRL_FILTER_FLASG3 | 106762306a36Sopenharmony_ci HTT_RX_MON_FP_DATA_FILTER_FLASG3 | 106862306a36Sopenharmony_ci HTT_RX_MON_MO_DATA_FILTER_FLASG3; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci if (ab->hw_params->rxdma1_enable) { 107262306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, 0, 107362306a36Sopenharmony_ci HAL_RXDMA_MONITOR_BUF, 107462306a36Sopenharmony_ci DP_RXDMA_REFILL_RING_SIZE, 107562306a36Sopenharmony_ci &tlv_filter); 107662306a36Sopenharmony_ci if (ret) { 107762306a36Sopenharmony_ci ath12k_err(ab, 107862306a36Sopenharmony_ci "failed to setup filter for monitor buf %d\n", ret); 107962306a36Sopenharmony_ci return ret; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci return 0; 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ciint ath12k_dp_tx_htt_tx_filter_setup(struct ath12k_base *ab, u32 ring_id, 108762306a36Sopenharmony_ci int mac_id, enum hal_ring_type ring_type, 108862306a36Sopenharmony_ci int tx_buf_size, 108962306a36Sopenharmony_ci struct htt_tx_ring_tlv_filter *htt_tlv_filter) 109062306a36Sopenharmony_ci{ 109162306a36Sopenharmony_ci struct htt_tx_ring_selection_cfg_cmd *cmd; 109262306a36Sopenharmony_ci struct hal_srng *srng = &ab->hal.srng_list[ring_id]; 109362306a36Sopenharmony_ci struct hal_srng_params params; 109462306a36Sopenharmony_ci struct sk_buff *skb; 109562306a36Sopenharmony_ci int len = sizeof(*cmd); 109662306a36Sopenharmony_ci enum htt_srng_ring_type htt_ring_type; 109762306a36Sopenharmony_ci enum htt_srng_ring_id htt_ring_id; 109862306a36Sopenharmony_ci int ret; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci skb = ath12k_htc_alloc_skb(ab, len); 110162306a36Sopenharmony_ci if (!skb) 110262306a36Sopenharmony_ci return -ENOMEM; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 110562306a36Sopenharmony_ci ath12k_hal_srng_get_params(ab, srng, ¶ms); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci ret = ath12k_dp_tx_get_ring_id_type(ab, mac_id, ring_id, 110862306a36Sopenharmony_ci ring_type, &htt_ring_type, 110962306a36Sopenharmony_ci &htt_ring_id); 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci if (ret) 111262306a36Sopenharmony_ci goto err_free; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci skb_put(skb, len); 111562306a36Sopenharmony_ci cmd = (struct htt_tx_ring_selection_cfg_cmd *)skb->data; 111662306a36Sopenharmony_ci cmd->info0 = le32_encode_bits(HTT_H2T_MSG_TYPE_TX_MONITOR_CFG, 111762306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO0_MSG_TYPE); 111862306a36Sopenharmony_ci if (htt_ring_type == HTT_SW_TO_HW_RING || 111962306a36Sopenharmony_ci htt_ring_type == HTT_HW_TO_SW_RING) 112062306a36Sopenharmony_ci cmd->info0 |= 112162306a36Sopenharmony_ci le32_encode_bits(DP_SW2HW_MACID(mac_id), 112262306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO0_PDEV_ID); 112362306a36Sopenharmony_ci else 112462306a36Sopenharmony_ci cmd->info0 |= 112562306a36Sopenharmony_ci le32_encode_bits(mac_id, 112662306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO0_PDEV_ID); 112762306a36Sopenharmony_ci cmd->info0 |= le32_encode_bits(htt_ring_id, 112862306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO0_RING_ID); 112962306a36Sopenharmony_ci cmd->info0 |= le32_encode_bits(!!(params.flags & HAL_SRNG_FLAGS_MSI_SWAP), 113062306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO0_SS); 113162306a36Sopenharmony_ci cmd->info0 |= le32_encode_bits(!!(params.flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP), 113262306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO0_PS); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci cmd->info1 |= 113562306a36Sopenharmony_ci le32_encode_bits(tx_buf_size, 113662306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO1_RING_BUFF_SIZE); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci if (htt_tlv_filter->tx_mon_mgmt_filter) { 113962306a36Sopenharmony_ci cmd->info1 |= 114062306a36Sopenharmony_ci le32_encode_bits(HTT_STATS_FRAME_CTRL_TYPE_MGMT, 114162306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO1_PKT_TYPE); 114262306a36Sopenharmony_ci cmd->info1 |= 114362306a36Sopenharmony_ci le32_encode_bits(htt_tlv_filter->tx_mon_pkt_dma_len, 114462306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO1_CONF_LEN_MGMT); 114562306a36Sopenharmony_ci cmd->info2 |= 114662306a36Sopenharmony_ci le32_encode_bits(HTT_STATS_FRAME_CTRL_TYPE_MGMT, 114762306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO2_PKT_TYPE_EN_FLAG); 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci if (htt_tlv_filter->tx_mon_data_filter) { 115162306a36Sopenharmony_ci cmd->info1 |= 115262306a36Sopenharmony_ci le32_encode_bits(HTT_STATS_FRAME_CTRL_TYPE_CTRL, 115362306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO1_PKT_TYPE); 115462306a36Sopenharmony_ci cmd->info1 |= 115562306a36Sopenharmony_ci le32_encode_bits(htt_tlv_filter->tx_mon_pkt_dma_len, 115662306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO1_CONF_LEN_CTRL); 115762306a36Sopenharmony_ci cmd->info2 |= 115862306a36Sopenharmony_ci le32_encode_bits(HTT_STATS_FRAME_CTRL_TYPE_CTRL, 115962306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO2_PKT_TYPE_EN_FLAG); 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci if (htt_tlv_filter->tx_mon_ctrl_filter) { 116362306a36Sopenharmony_ci cmd->info1 |= 116462306a36Sopenharmony_ci le32_encode_bits(HTT_STATS_FRAME_CTRL_TYPE_DATA, 116562306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO1_PKT_TYPE); 116662306a36Sopenharmony_ci cmd->info1 |= 116762306a36Sopenharmony_ci le32_encode_bits(htt_tlv_filter->tx_mon_pkt_dma_len, 116862306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO1_CONF_LEN_DATA); 116962306a36Sopenharmony_ci cmd->info2 |= 117062306a36Sopenharmony_ci le32_encode_bits(HTT_STATS_FRAME_CTRL_TYPE_DATA, 117162306a36Sopenharmony_ci HTT_TX_RING_SELECTION_CFG_CMD_INFO2_PKT_TYPE_EN_FLAG); 117262306a36Sopenharmony_ci } 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci cmd->tlv_filter_mask_in0 = 117562306a36Sopenharmony_ci cpu_to_le32(htt_tlv_filter->tx_mon_downstream_tlv_flags); 117662306a36Sopenharmony_ci cmd->tlv_filter_mask_in1 = 117762306a36Sopenharmony_ci cpu_to_le32(htt_tlv_filter->tx_mon_upstream_tlv_flags0); 117862306a36Sopenharmony_ci cmd->tlv_filter_mask_in2 = 117962306a36Sopenharmony_ci cpu_to_le32(htt_tlv_filter->tx_mon_upstream_tlv_flags1); 118062306a36Sopenharmony_ci cmd->tlv_filter_mask_in3 = 118162306a36Sopenharmony_ci cpu_to_le32(htt_tlv_filter->tx_mon_upstream_tlv_flags2); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci ret = ath12k_htc_send(&ab->htc, ab->dp.eid, skb); 118462306a36Sopenharmony_ci if (ret) 118562306a36Sopenharmony_ci goto err_free; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci return 0; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_cierr_free: 119062306a36Sopenharmony_ci dev_kfree_skb_any(skb); 119162306a36Sopenharmony_ci return ret; 119262306a36Sopenharmony_ci} 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ciint ath12k_dp_tx_htt_tx_monitor_mode_ring_config(struct ath12k *ar, bool reset) 119562306a36Sopenharmony_ci{ 119662306a36Sopenharmony_ci struct ath12k_base *ab = ar->ab; 119762306a36Sopenharmony_ci struct ath12k_dp *dp = &ab->dp; 119862306a36Sopenharmony_ci struct htt_tx_ring_tlv_filter tlv_filter = {0}; 119962306a36Sopenharmony_ci int ret, ring_id; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci ring_id = dp->tx_mon_buf_ring.refill_buf_ring.ring_id; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci /* TODO: Need to set upstream/downstream tlv filters 120462306a36Sopenharmony_ci * here 120562306a36Sopenharmony_ci */ 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci if (ab->hw_params->rxdma1_enable) { 120862306a36Sopenharmony_ci ret = ath12k_dp_tx_htt_tx_filter_setup(ar->ab, ring_id, 0, 120962306a36Sopenharmony_ci HAL_TX_MONITOR_BUF, 121062306a36Sopenharmony_ci DP_RXDMA_REFILL_RING_SIZE, 121162306a36Sopenharmony_ci &tlv_filter); 121262306a36Sopenharmony_ci if (ret) { 121362306a36Sopenharmony_ci ath12k_err(ab, 121462306a36Sopenharmony_ci "failed to setup filter for monitor buf %d\n", ret); 121562306a36Sopenharmony_ci return ret; 121662306a36Sopenharmony_ci } 121762306a36Sopenharmony_ci } 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci return 0; 122062306a36Sopenharmony_ci} 1221