18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2005-2011 Atheros Communications Inc. 48c2ecf20Sopenharmony_ci * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 88c2ecf20Sopenharmony_ci#include "htt.h" 98c2ecf20Sopenharmony_ci#include "mac.h" 108c2ecf20Sopenharmony_ci#include "hif.h" 118c2ecf20Sopenharmony_ci#include "txrx.h" 128c2ecf20Sopenharmony_ci#include "debug.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_cistatic u8 ath10k_htt_tx_txq_calc_size(size_t count) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci int exp; 178c2ecf20Sopenharmony_ci int factor; 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci exp = 0; 208c2ecf20Sopenharmony_ci factor = count >> 7; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci while (factor >= 64 && exp < 4) { 238c2ecf20Sopenharmony_ci factor >>= 3; 248c2ecf20Sopenharmony_ci exp++; 258c2ecf20Sopenharmony_ci } 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci if (exp == 4) 288c2ecf20Sopenharmony_ci return 0xff; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (count > 0) 318c2ecf20Sopenharmony_ci factor = max(1, factor); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci return SM(exp, HTT_TX_Q_STATE_ENTRY_EXP) | 348c2ecf20Sopenharmony_ci SM(factor, HTT_TX_Q_STATE_ENTRY_FACTOR); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic void __ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw, 388c2ecf20Sopenharmony_ci struct ieee80211_txq *txq) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct ath10k *ar = hw->priv; 418c2ecf20Sopenharmony_ci struct ath10k_sta *arsta; 428c2ecf20Sopenharmony_ci struct ath10k_vif *arvif = (void *)txq->vif->drv_priv; 438c2ecf20Sopenharmony_ci unsigned long frame_cnt; 448c2ecf20Sopenharmony_ci unsigned long byte_cnt; 458c2ecf20Sopenharmony_ci int idx; 468c2ecf20Sopenharmony_ci u32 bit; 478c2ecf20Sopenharmony_ci u16 peer_id; 488c2ecf20Sopenharmony_ci u8 tid; 498c2ecf20Sopenharmony_ci u8 count; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci lockdep_assert_held(&ar->htt.tx_lock); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (!ar->htt.tx_q_state.enabled) 548c2ecf20Sopenharmony_ci return; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (ar->htt.tx_q_state.mode != HTT_TX_MODE_SWITCH_PUSH_PULL) 578c2ecf20Sopenharmony_ci return; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if (txq->sta) { 608c2ecf20Sopenharmony_ci arsta = (void *)txq->sta->drv_priv; 618c2ecf20Sopenharmony_ci peer_id = arsta->peer_id; 628c2ecf20Sopenharmony_ci } else { 638c2ecf20Sopenharmony_ci peer_id = arvif->peer_id; 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci tid = txq->tid; 678c2ecf20Sopenharmony_ci bit = BIT(peer_id % 32); 688c2ecf20Sopenharmony_ci idx = peer_id / 32; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci ieee80211_txq_get_depth(txq, &frame_cnt, &byte_cnt); 718c2ecf20Sopenharmony_ci count = ath10k_htt_tx_txq_calc_size(byte_cnt); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci if (unlikely(peer_id >= ar->htt.tx_q_state.num_peers) || 748c2ecf20Sopenharmony_ci unlikely(tid >= ar->htt.tx_q_state.num_tids)) { 758c2ecf20Sopenharmony_ci ath10k_warn(ar, "refusing to update txq for peer_id %hu tid %hhu due to out of bounds\n", 768c2ecf20Sopenharmony_ci peer_id, tid); 778c2ecf20Sopenharmony_ci return; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci ar->htt.tx_q_state.vaddr->count[tid][peer_id] = count; 818c2ecf20Sopenharmony_ci ar->htt.tx_q_state.vaddr->map[tid][idx] &= ~bit; 828c2ecf20Sopenharmony_ci ar->htt.tx_q_state.vaddr->map[tid][idx] |= count ? bit : 0; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx txq state update peer_id %hu tid %hhu count %hhu\n", 858c2ecf20Sopenharmony_ci peer_id, tid, count); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void __ath10k_htt_tx_txq_sync(struct ath10k *ar) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci u32 seq; 918c2ecf20Sopenharmony_ci size_t size; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci lockdep_assert_held(&ar->htt.tx_lock); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (!ar->htt.tx_q_state.enabled) 968c2ecf20Sopenharmony_ci return; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (ar->htt.tx_q_state.mode != HTT_TX_MODE_SWITCH_PUSH_PULL) 998c2ecf20Sopenharmony_ci return; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci seq = le32_to_cpu(ar->htt.tx_q_state.vaddr->seq); 1028c2ecf20Sopenharmony_ci seq++; 1038c2ecf20Sopenharmony_ci ar->htt.tx_q_state.vaddr->seq = cpu_to_le32(seq); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx txq state update commit seq %u\n", 1068c2ecf20Sopenharmony_ci seq); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci size = sizeof(*ar->htt.tx_q_state.vaddr); 1098c2ecf20Sopenharmony_ci dma_sync_single_for_device(ar->dev, 1108c2ecf20Sopenharmony_ci ar->htt.tx_q_state.paddr, 1118c2ecf20Sopenharmony_ci size, 1128c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_civoid ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw, 1168c2ecf20Sopenharmony_ci struct ieee80211_txq *txq) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct ath10k *ar = hw->priv; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 1218c2ecf20Sopenharmony_ci __ath10k_htt_tx_txq_recalc(hw, txq); 1228c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_civoid ath10k_htt_tx_txq_sync(struct ath10k *ar) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 1288c2ecf20Sopenharmony_ci __ath10k_htt_tx_txq_sync(ar); 1298c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_civoid ath10k_htt_tx_txq_update(struct ieee80211_hw *hw, 1338c2ecf20Sopenharmony_ci struct ieee80211_txq *txq) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct ath10k *ar = hw->priv; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci spin_lock_bh(&ar->htt.tx_lock); 1388c2ecf20Sopenharmony_ci __ath10k_htt_tx_txq_recalc(hw, txq); 1398c2ecf20Sopenharmony_ci __ath10k_htt_tx_txq_sync(ar); 1408c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->htt.tx_lock); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_civoid ath10k_htt_tx_dec_pending(struct ath10k_htt *htt) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci lockdep_assert_held(&htt->tx_lock); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci htt->num_pending_tx--; 1488c2ecf20Sopenharmony_ci if (htt->num_pending_tx == htt->max_num_pending_tx - 1) 1498c2ecf20Sopenharmony_ci ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (htt->num_pending_tx == 0) 1528c2ecf20Sopenharmony_ci wake_up(&htt->empty_tx_wq); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ciint ath10k_htt_tx_inc_pending(struct ath10k_htt *htt) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci lockdep_assert_held(&htt->tx_lock); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (htt->num_pending_tx >= htt->max_num_pending_tx) 1608c2ecf20Sopenharmony_ci return -EBUSY; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci htt->num_pending_tx++; 1638c2ecf20Sopenharmony_ci if (htt->num_pending_tx == htt->max_num_pending_tx) 1648c2ecf20Sopenharmony_ci ath10k_mac_tx_lock(htt->ar, ATH10K_TX_PAUSE_Q_FULL); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return 0; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ciint ath10k_htt_tx_mgmt_inc_pending(struct ath10k_htt *htt, bool is_mgmt, 1708c2ecf20Sopenharmony_ci bool is_presp) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci lockdep_assert_held(&htt->tx_lock); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (!is_mgmt || !ar->hw_params.max_probe_resp_desc_thres) 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (is_presp && 1808c2ecf20Sopenharmony_ci ar->hw_params.max_probe_resp_desc_thres < htt->num_pending_mgmt_tx) 1818c2ecf20Sopenharmony_ci return -EBUSY; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci htt->num_pending_mgmt_tx++; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return 0; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_civoid ath10k_htt_tx_mgmt_dec_pending(struct ath10k_htt *htt) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci lockdep_assert_held(&htt->tx_lock); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (!htt->ar->hw_params.max_probe_resp_desc_thres) 1938c2ecf20Sopenharmony_ci return; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci htt->num_pending_mgmt_tx--; 1968c2ecf20Sopenharmony_ci} 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ciint ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 2018c2ecf20Sopenharmony_ci int ret; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci spin_lock_bh(&htt->tx_lock); 2048c2ecf20Sopenharmony_ci ret = idr_alloc(&htt->pending_tx, skb, 0, 2058c2ecf20Sopenharmony_ci htt->max_num_pending_tx, GFP_ATOMIC); 2068c2ecf20Sopenharmony_ci spin_unlock_bh(&htt->tx_lock); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", ret); 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci return ret; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_civoid ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci lockdep_assert_held(&htt->tx_lock); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci idr_remove(&htt->pending_tx, msdu_id); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic void ath10k_htt_tx_free_cont_txbuf_32(struct ath10k_htt *htt) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 2278c2ecf20Sopenharmony_ci size_t size; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (!htt->txbuf.vaddr_txbuff_32) 2308c2ecf20Sopenharmony_ci return; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci size = htt->txbuf.size; 2338c2ecf20Sopenharmony_ci dma_free_coherent(ar->dev, size, htt->txbuf.vaddr_txbuff_32, 2348c2ecf20Sopenharmony_ci htt->txbuf.paddr); 2358c2ecf20Sopenharmony_ci htt->txbuf.vaddr_txbuff_32 = NULL; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int ath10k_htt_tx_alloc_cont_txbuf_32(struct ath10k_htt *htt) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 2418c2ecf20Sopenharmony_ci size_t size; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci size = htt->max_num_pending_tx * 2448c2ecf20Sopenharmony_ci sizeof(struct ath10k_htt_txbuf_32); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci htt->txbuf.vaddr_txbuff_32 = dma_alloc_coherent(ar->dev, size, 2478c2ecf20Sopenharmony_ci &htt->txbuf.paddr, 2488c2ecf20Sopenharmony_ci GFP_KERNEL); 2498c2ecf20Sopenharmony_ci if (!htt->txbuf.vaddr_txbuff_32) 2508c2ecf20Sopenharmony_ci return -ENOMEM; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci htt->txbuf.size = size; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return 0; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void ath10k_htt_tx_free_cont_txbuf_64(struct ath10k_htt *htt) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 2608c2ecf20Sopenharmony_ci size_t size; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (!htt->txbuf.vaddr_txbuff_64) 2638c2ecf20Sopenharmony_ci return; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci size = htt->txbuf.size; 2668c2ecf20Sopenharmony_ci dma_free_coherent(ar->dev, size, htt->txbuf.vaddr_txbuff_64, 2678c2ecf20Sopenharmony_ci htt->txbuf.paddr); 2688c2ecf20Sopenharmony_ci htt->txbuf.vaddr_txbuff_64 = NULL; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int ath10k_htt_tx_alloc_cont_txbuf_64(struct ath10k_htt *htt) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 2748c2ecf20Sopenharmony_ci size_t size; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci size = htt->max_num_pending_tx * 2778c2ecf20Sopenharmony_ci sizeof(struct ath10k_htt_txbuf_64); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci htt->txbuf.vaddr_txbuff_64 = dma_alloc_coherent(ar->dev, size, 2808c2ecf20Sopenharmony_ci &htt->txbuf.paddr, 2818c2ecf20Sopenharmony_ci GFP_KERNEL); 2828c2ecf20Sopenharmony_ci if (!htt->txbuf.vaddr_txbuff_64) 2838c2ecf20Sopenharmony_ci return -ENOMEM; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci htt->txbuf.size = size; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic void ath10k_htt_tx_free_cont_frag_desc_32(struct ath10k_htt *htt) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci size_t size; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (!htt->frag_desc.vaddr_desc_32) 2958c2ecf20Sopenharmony_ci return; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci size = htt->max_num_pending_tx * 2988c2ecf20Sopenharmony_ci sizeof(struct htt_msdu_ext_desc); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci dma_free_coherent(htt->ar->dev, 3018c2ecf20Sopenharmony_ci size, 3028c2ecf20Sopenharmony_ci htt->frag_desc.vaddr_desc_32, 3038c2ecf20Sopenharmony_ci htt->frag_desc.paddr); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci htt->frag_desc.vaddr_desc_32 = NULL; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic int ath10k_htt_tx_alloc_cont_frag_desc_32(struct ath10k_htt *htt) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 3118c2ecf20Sopenharmony_ci size_t size; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (!ar->hw_params.continuous_frag_desc) 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci size = htt->max_num_pending_tx * 3178c2ecf20Sopenharmony_ci sizeof(struct htt_msdu_ext_desc); 3188c2ecf20Sopenharmony_ci htt->frag_desc.vaddr_desc_32 = dma_alloc_coherent(ar->dev, size, 3198c2ecf20Sopenharmony_ci &htt->frag_desc.paddr, 3208c2ecf20Sopenharmony_ci GFP_KERNEL); 3218c2ecf20Sopenharmony_ci if (!htt->frag_desc.vaddr_desc_32) { 3228c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to alloc fragment desc memory\n"); 3238c2ecf20Sopenharmony_ci return -ENOMEM; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci htt->frag_desc.size = size; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic void ath10k_htt_tx_free_cont_frag_desc_64(struct ath10k_htt *htt) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci size_t size; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (!htt->frag_desc.vaddr_desc_64) 3358c2ecf20Sopenharmony_ci return; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci size = htt->max_num_pending_tx * 3388c2ecf20Sopenharmony_ci sizeof(struct htt_msdu_ext_desc_64); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci dma_free_coherent(htt->ar->dev, 3418c2ecf20Sopenharmony_ci size, 3428c2ecf20Sopenharmony_ci htt->frag_desc.vaddr_desc_64, 3438c2ecf20Sopenharmony_ci htt->frag_desc.paddr); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci htt->frag_desc.vaddr_desc_64 = NULL; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic int ath10k_htt_tx_alloc_cont_frag_desc_64(struct ath10k_htt *htt) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 3518c2ecf20Sopenharmony_ci size_t size; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci if (!ar->hw_params.continuous_frag_desc) 3548c2ecf20Sopenharmony_ci return 0; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci size = htt->max_num_pending_tx * 3578c2ecf20Sopenharmony_ci sizeof(struct htt_msdu_ext_desc_64); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci htt->frag_desc.vaddr_desc_64 = dma_alloc_coherent(ar->dev, size, 3608c2ecf20Sopenharmony_ci &htt->frag_desc.paddr, 3618c2ecf20Sopenharmony_ci GFP_KERNEL); 3628c2ecf20Sopenharmony_ci if (!htt->frag_desc.vaddr_desc_64) { 3638c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to alloc fragment desc memory\n"); 3648c2ecf20Sopenharmony_ci return -ENOMEM; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci htt->frag_desc.size = size; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return 0; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic void ath10k_htt_tx_free_txq(struct ath10k_htt *htt) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 3748c2ecf20Sopenharmony_ci size_t size; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, 3778c2ecf20Sopenharmony_ci ar->running_fw->fw_file.fw_features)) 3788c2ecf20Sopenharmony_ci return; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci size = sizeof(*htt->tx_q_state.vaddr); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci dma_unmap_single(ar->dev, htt->tx_q_state.paddr, size, DMA_TO_DEVICE); 3838c2ecf20Sopenharmony_ci kfree(htt->tx_q_state.vaddr); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic int ath10k_htt_tx_alloc_txq(struct ath10k_htt *htt) 3878c2ecf20Sopenharmony_ci{ 3888c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 3898c2ecf20Sopenharmony_ci size_t size; 3908c2ecf20Sopenharmony_ci int ret; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, 3938c2ecf20Sopenharmony_ci ar->running_fw->fw_file.fw_features)) 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci htt->tx_q_state.num_peers = HTT_TX_Q_STATE_NUM_PEERS; 3978c2ecf20Sopenharmony_ci htt->tx_q_state.num_tids = HTT_TX_Q_STATE_NUM_TIDS; 3988c2ecf20Sopenharmony_ci htt->tx_q_state.type = HTT_Q_DEPTH_TYPE_BYTES; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci size = sizeof(*htt->tx_q_state.vaddr); 4018c2ecf20Sopenharmony_ci htt->tx_q_state.vaddr = kzalloc(size, GFP_KERNEL); 4028c2ecf20Sopenharmony_ci if (!htt->tx_q_state.vaddr) 4038c2ecf20Sopenharmony_ci return -ENOMEM; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci htt->tx_q_state.paddr = dma_map_single(ar->dev, htt->tx_q_state.vaddr, 4068c2ecf20Sopenharmony_ci size, DMA_TO_DEVICE); 4078c2ecf20Sopenharmony_ci ret = dma_mapping_error(ar->dev, htt->tx_q_state.paddr); 4088c2ecf20Sopenharmony_ci if (ret) { 4098c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to dma map tx_q_state: %d\n", ret); 4108c2ecf20Sopenharmony_ci kfree(htt->tx_q_state.vaddr); 4118c2ecf20Sopenharmony_ci return -EIO; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci return 0; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic void ath10k_htt_tx_free_txdone_fifo(struct ath10k_htt *htt) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci WARN_ON(!kfifo_is_empty(&htt->txdone_fifo)); 4208c2ecf20Sopenharmony_ci kfifo_free(&htt->txdone_fifo); 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic int ath10k_htt_tx_alloc_txdone_fifo(struct ath10k_htt *htt) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci int ret; 4268c2ecf20Sopenharmony_ci size_t size; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci size = roundup_pow_of_two(htt->max_num_pending_tx); 4298c2ecf20Sopenharmony_ci ret = kfifo_alloc(&htt->txdone_fifo, size, GFP_KERNEL); 4308c2ecf20Sopenharmony_ci return ret; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic int ath10k_htt_tx_alloc_buf(struct ath10k_htt *htt) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 4368c2ecf20Sopenharmony_ci int ret; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci ret = ath10k_htt_alloc_txbuff(htt); 4398c2ecf20Sopenharmony_ci if (ret) { 4408c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to alloc cont tx buffer: %d\n", ret); 4418c2ecf20Sopenharmony_ci return ret; 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci ret = ath10k_htt_alloc_frag_desc(htt); 4458c2ecf20Sopenharmony_ci if (ret) { 4468c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to alloc cont frag desc: %d\n", ret); 4478c2ecf20Sopenharmony_ci goto free_txbuf; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci ret = ath10k_htt_tx_alloc_txq(htt); 4518c2ecf20Sopenharmony_ci if (ret) { 4528c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to alloc txq: %d\n", ret); 4538c2ecf20Sopenharmony_ci goto free_frag_desc; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci ret = ath10k_htt_tx_alloc_txdone_fifo(htt); 4578c2ecf20Sopenharmony_ci if (ret) { 4588c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to alloc txdone fifo: %d\n", ret); 4598c2ecf20Sopenharmony_ci goto free_txq; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return 0; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cifree_txq: 4658c2ecf20Sopenharmony_ci ath10k_htt_tx_free_txq(htt); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cifree_frag_desc: 4688c2ecf20Sopenharmony_ci ath10k_htt_free_frag_desc(htt); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cifree_txbuf: 4718c2ecf20Sopenharmony_ci ath10k_htt_free_txbuff(htt); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci return ret; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ciint ath10k_htt_tx_start(struct ath10k_htt *htt) 4778c2ecf20Sopenharmony_ci{ 4788c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 4798c2ecf20Sopenharmony_ci int ret; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", 4828c2ecf20Sopenharmony_ci htt->max_num_pending_tx); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci spin_lock_init(&htt->tx_lock); 4858c2ecf20Sopenharmony_ci idr_init(&htt->pending_tx); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci if (htt->tx_mem_allocated) 4888c2ecf20Sopenharmony_ci return 0; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL) 4918c2ecf20Sopenharmony_ci return 0; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci ret = ath10k_htt_tx_alloc_buf(htt); 4948c2ecf20Sopenharmony_ci if (ret) 4958c2ecf20Sopenharmony_ci goto free_idr_pending_tx; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci htt->tx_mem_allocated = true; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci return 0; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cifree_idr_pending_tx: 5028c2ecf20Sopenharmony_ci idr_destroy(&htt->pending_tx); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return ret; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) 5088c2ecf20Sopenharmony_ci{ 5098c2ecf20Sopenharmony_ci struct ath10k *ar = ctx; 5108c2ecf20Sopenharmony_ci struct ath10k_htt *htt = &ar->htt; 5118c2ecf20Sopenharmony_ci struct htt_tx_done tx_done = {0}; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n", msdu_id); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci tx_done.msdu_id = msdu_id; 5168c2ecf20Sopenharmony_ci tx_done.status = HTT_TX_COMPL_STATE_DISCARD; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci ath10k_txrx_tx_unref(htt, &tx_done); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return 0; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_civoid ath10k_htt_tx_destroy(struct ath10k_htt *htt) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci if (!htt->tx_mem_allocated) 5268c2ecf20Sopenharmony_ci return; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci ath10k_htt_free_txbuff(htt); 5298c2ecf20Sopenharmony_ci ath10k_htt_tx_free_txq(htt); 5308c2ecf20Sopenharmony_ci ath10k_htt_free_frag_desc(htt); 5318c2ecf20Sopenharmony_ci ath10k_htt_tx_free_txdone_fifo(htt); 5328c2ecf20Sopenharmony_ci htt->tx_mem_allocated = false; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic void ath10k_htt_flush_tx_queue(struct ath10k_htt *htt) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci ath10k_htc_stop_hl(htt->ar); 5388c2ecf20Sopenharmony_ci idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_civoid ath10k_htt_tx_stop(struct ath10k_htt *htt) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci ath10k_htt_flush_tx_queue(htt); 5448c2ecf20Sopenharmony_ci idr_destroy(&htt->pending_tx); 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_civoid ath10k_htt_tx_free(struct ath10k_htt *htt) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci ath10k_htt_tx_stop(htt); 5508c2ecf20Sopenharmony_ci ath10k_htt_tx_destroy(htt); 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_civoid ath10k_htt_op_ep_tx_credits(struct ath10k *ar) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci queue_work(ar->workqueue, &ar->bundle_tx_work); 5568c2ecf20Sopenharmony_ci} 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_civoid ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci struct ath10k_htt *htt = &ar->htt; 5618c2ecf20Sopenharmony_ci struct htt_tx_done tx_done = {0}; 5628c2ecf20Sopenharmony_ci struct htt_cmd_hdr *htt_hdr; 5638c2ecf20Sopenharmony_ci struct htt_data_tx_desc *desc_hdr = NULL; 5648c2ecf20Sopenharmony_ci u16 flags1 = 0; 5658c2ecf20Sopenharmony_ci u8 msg_type = 0; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci if (htt->disable_tx_comp) { 5688c2ecf20Sopenharmony_ci htt_hdr = (struct htt_cmd_hdr *)skb->data; 5698c2ecf20Sopenharmony_ci msg_type = htt_hdr->msg_type; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (msg_type == HTT_H2T_MSG_TYPE_TX_FRM) { 5728c2ecf20Sopenharmony_ci desc_hdr = (struct htt_data_tx_desc *) 5738c2ecf20Sopenharmony_ci (skb->data + sizeof(*htt_hdr)); 5748c2ecf20Sopenharmony_ci flags1 = __le16_to_cpu(desc_hdr->flags1); 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if ((!htt->disable_tx_comp) || (msg_type != HTT_H2T_MSG_TYPE_TX_FRM)) 5818c2ecf20Sopenharmony_ci return; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_HTT, 5848c2ecf20Sopenharmony_ci "htt tx complete msdu id:%u ,flags1:%x\n", 5858c2ecf20Sopenharmony_ci __le16_to_cpu(desc_hdr->id), flags1); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (flags1 & HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE) 5888c2ecf20Sopenharmony_ci return; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci tx_done.status = HTT_TX_COMPL_STATE_ACK; 5918c2ecf20Sopenharmony_ci tx_done.msdu_id = __le16_to_cpu(desc_hdr->id); 5928c2ecf20Sopenharmony_ci ath10k_txrx_tx_unref(&ar->htt, &tx_done); 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_civoid ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ath10k_htt_hif_tx_complete); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ciint ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 6048c2ecf20Sopenharmony_ci struct sk_buff *skb; 6058c2ecf20Sopenharmony_ci struct htt_cmd *cmd; 6068c2ecf20Sopenharmony_ci int len = 0; 6078c2ecf20Sopenharmony_ci int ret; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci len += sizeof(cmd->hdr); 6108c2ecf20Sopenharmony_ci len += sizeof(cmd->ver_req); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci skb = ath10k_htc_alloc_skb(ar, len); 6138c2ecf20Sopenharmony_ci if (!skb) 6148c2ecf20Sopenharmony_ci return -ENOMEM; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci skb_put(skb, len); 6178c2ecf20Sopenharmony_ci cmd = (struct htt_cmd *)skb->data; 6188c2ecf20Sopenharmony_ci cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_VERSION_REQ; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); 6218c2ecf20Sopenharmony_ci if (ret) { 6228c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 6238c2ecf20Sopenharmony_ci return ret; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci return 0; 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ciint ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u32 mask, u32 reset_mask, 6308c2ecf20Sopenharmony_ci u64 cookie) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 6338c2ecf20Sopenharmony_ci struct htt_stats_req *req; 6348c2ecf20Sopenharmony_ci struct sk_buff *skb; 6358c2ecf20Sopenharmony_ci struct htt_cmd *cmd; 6368c2ecf20Sopenharmony_ci int len = 0, ret; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci len += sizeof(cmd->hdr); 6398c2ecf20Sopenharmony_ci len += sizeof(cmd->stats_req); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci skb = ath10k_htc_alloc_skb(ar, len); 6428c2ecf20Sopenharmony_ci if (!skb) 6438c2ecf20Sopenharmony_ci return -ENOMEM; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci skb_put(skb, len); 6468c2ecf20Sopenharmony_ci cmd = (struct htt_cmd *)skb->data; 6478c2ecf20Sopenharmony_ci cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_STATS_REQ; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci req = &cmd->stats_req; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci memset(req, 0, sizeof(*req)); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci /* currently we support only max 24 bit masks so no need to worry 6548c2ecf20Sopenharmony_ci * about endian support 6558c2ecf20Sopenharmony_ci */ 6568c2ecf20Sopenharmony_ci memcpy(req->upload_types, &mask, 3); 6578c2ecf20Sopenharmony_ci memcpy(req->reset_types, &reset_mask, 3); 6588c2ecf20Sopenharmony_ci req->stat_type = HTT_STATS_REQ_CFG_STAT_TYPE_INVALID; 6598c2ecf20Sopenharmony_ci req->cookie_lsb = cpu_to_le32(cookie & 0xffffffff); 6608c2ecf20Sopenharmony_ci req->cookie_msb = cpu_to_le32((cookie & 0xffffffff00000000ULL) >> 32); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); 6638c2ecf20Sopenharmony_ci if (ret) { 6648c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to send htt type stats request: %d", 6658c2ecf20Sopenharmony_ci ret); 6668c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 6678c2ecf20Sopenharmony_ci return ret; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci return 0; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic int ath10k_htt_send_frag_desc_bank_cfg_32(struct ath10k_htt *htt) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 6768c2ecf20Sopenharmony_ci struct sk_buff *skb; 6778c2ecf20Sopenharmony_ci struct htt_cmd *cmd; 6788c2ecf20Sopenharmony_ci struct htt_frag_desc_bank_cfg32 *cfg; 6798c2ecf20Sopenharmony_ci int ret, size; 6808c2ecf20Sopenharmony_ci u8 info; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci if (!ar->hw_params.continuous_frag_desc) 6838c2ecf20Sopenharmony_ci return 0; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci if (!htt->frag_desc.paddr) { 6868c2ecf20Sopenharmony_ci ath10k_warn(ar, "invalid frag desc memory\n"); 6878c2ecf20Sopenharmony_ci return -EINVAL; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci size = sizeof(cmd->hdr) + sizeof(cmd->frag_desc_bank_cfg32); 6918c2ecf20Sopenharmony_ci skb = ath10k_htc_alloc_skb(ar, size); 6928c2ecf20Sopenharmony_ci if (!skb) 6938c2ecf20Sopenharmony_ci return -ENOMEM; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci skb_put(skb, size); 6968c2ecf20Sopenharmony_ci cmd = (struct htt_cmd *)skb->data; 6978c2ecf20Sopenharmony_ci cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci info = 0; 7008c2ecf20Sopenharmony_ci info |= SM(htt->tx_q_state.type, 7018c2ecf20Sopenharmony_ci HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE); 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, 7048c2ecf20Sopenharmony_ci ar->running_fw->fw_file.fw_features)) 7058c2ecf20Sopenharmony_ci info |= HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_VALID; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci cfg = &cmd->frag_desc_bank_cfg32; 7088c2ecf20Sopenharmony_ci cfg->info = info; 7098c2ecf20Sopenharmony_ci cfg->num_banks = 1; 7108c2ecf20Sopenharmony_ci cfg->desc_size = sizeof(struct htt_msdu_ext_desc); 7118c2ecf20Sopenharmony_ci cfg->bank_base_addrs[0] = __cpu_to_le32(htt->frag_desc.paddr); 7128c2ecf20Sopenharmony_ci cfg->bank_id[0].bank_min_id = 0; 7138c2ecf20Sopenharmony_ci cfg->bank_id[0].bank_max_id = __cpu_to_le16(htt->max_num_pending_tx - 7148c2ecf20Sopenharmony_ci 1); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci cfg->q_state.paddr = cpu_to_le32(htt->tx_q_state.paddr); 7178c2ecf20Sopenharmony_ci cfg->q_state.num_peers = cpu_to_le16(htt->tx_q_state.num_peers); 7188c2ecf20Sopenharmony_ci cfg->q_state.num_tids = cpu_to_le16(htt->tx_q_state.num_tids); 7198c2ecf20Sopenharmony_ci cfg->q_state.record_size = HTT_TX_Q_STATE_ENTRY_SIZE; 7208c2ecf20Sopenharmony_ci cfg->q_state.record_multiplier = HTT_TX_Q_STATE_ENTRY_MULTIPLIER; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_HTT, "htt frag desc bank cmd\n"); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); 7258c2ecf20Sopenharmony_ci if (ret) { 7268c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to send frag desc bank cfg request: %d\n", 7278c2ecf20Sopenharmony_ci ret); 7288c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 7298c2ecf20Sopenharmony_ci return ret; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci return 0; 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic int ath10k_htt_send_frag_desc_bank_cfg_64(struct ath10k_htt *htt) 7368c2ecf20Sopenharmony_ci{ 7378c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 7388c2ecf20Sopenharmony_ci struct sk_buff *skb; 7398c2ecf20Sopenharmony_ci struct htt_cmd *cmd; 7408c2ecf20Sopenharmony_ci struct htt_frag_desc_bank_cfg64 *cfg; 7418c2ecf20Sopenharmony_ci int ret, size; 7428c2ecf20Sopenharmony_ci u8 info; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (!ar->hw_params.continuous_frag_desc) 7458c2ecf20Sopenharmony_ci return 0; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (!htt->frag_desc.paddr) { 7488c2ecf20Sopenharmony_ci ath10k_warn(ar, "invalid frag desc memory\n"); 7498c2ecf20Sopenharmony_ci return -EINVAL; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci size = sizeof(cmd->hdr) + sizeof(cmd->frag_desc_bank_cfg64); 7538c2ecf20Sopenharmony_ci skb = ath10k_htc_alloc_skb(ar, size); 7548c2ecf20Sopenharmony_ci if (!skb) 7558c2ecf20Sopenharmony_ci return -ENOMEM; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci skb_put(skb, size); 7588c2ecf20Sopenharmony_ci cmd = (struct htt_cmd *)skb->data; 7598c2ecf20Sopenharmony_ci cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci info = 0; 7628c2ecf20Sopenharmony_ci info |= SM(htt->tx_q_state.type, 7638c2ecf20Sopenharmony_ci HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE); 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, 7668c2ecf20Sopenharmony_ci ar->running_fw->fw_file.fw_features)) 7678c2ecf20Sopenharmony_ci info |= HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_VALID; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci cfg = &cmd->frag_desc_bank_cfg64; 7708c2ecf20Sopenharmony_ci cfg->info = info; 7718c2ecf20Sopenharmony_ci cfg->num_banks = 1; 7728c2ecf20Sopenharmony_ci cfg->desc_size = sizeof(struct htt_msdu_ext_desc_64); 7738c2ecf20Sopenharmony_ci cfg->bank_base_addrs[0] = __cpu_to_le64(htt->frag_desc.paddr); 7748c2ecf20Sopenharmony_ci cfg->bank_id[0].bank_min_id = 0; 7758c2ecf20Sopenharmony_ci cfg->bank_id[0].bank_max_id = __cpu_to_le16(htt->max_num_pending_tx - 7768c2ecf20Sopenharmony_ci 1); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci cfg->q_state.paddr = cpu_to_le32(htt->tx_q_state.paddr); 7798c2ecf20Sopenharmony_ci cfg->q_state.num_peers = cpu_to_le16(htt->tx_q_state.num_peers); 7808c2ecf20Sopenharmony_ci cfg->q_state.num_tids = cpu_to_le16(htt->tx_q_state.num_tids); 7818c2ecf20Sopenharmony_ci cfg->q_state.record_size = HTT_TX_Q_STATE_ENTRY_SIZE; 7828c2ecf20Sopenharmony_ci cfg->q_state.record_multiplier = HTT_TX_Q_STATE_ENTRY_MULTIPLIER; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_HTT, "htt frag desc bank cmd\n"); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); 7878c2ecf20Sopenharmony_ci if (ret) { 7888c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to send frag desc bank cfg request: %d\n", 7898c2ecf20Sopenharmony_ci ret); 7908c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 7918c2ecf20Sopenharmony_ci return ret; 7928c2ecf20Sopenharmony_ci } 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ci return 0; 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistatic void ath10k_htt_fill_rx_desc_offset_32(void *rx_ring) 7988c2ecf20Sopenharmony_ci{ 7998c2ecf20Sopenharmony_ci struct htt_rx_ring_setup_ring32 *ring = 8008c2ecf20Sopenharmony_ci (struct htt_rx_ring_setup_ring32 *)rx_ring; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci#define desc_offset(x) (offsetof(struct htt_rx_desc, x) / 4) 8038c2ecf20Sopenharmony_ci ring->mac80211_hdr_offset = __cpu_to_le16(desc_offset(rx_hdr_status)); 8048c2ecf20Sopenharmony_ci ring->msdu_payload_offset = __cpu_to_le16(desc_offset(msdu_payload)); 8058c2ecf20Sopenharmony_ci ring->ppdu_start_offset = __cpu_to_le16(desc_offset(ppdu_start)); 8068c2ecf20Sopenharmony_ci ring->ppdu_end_offset = __cpu_to_le16(desc_offset(ppdu_end)); 8078c2ecf20Sopenharmony_ci ring->mpdu_start_offset = __cpu_to_le16(desc_offset(mpdu_start)); 8088c2ecf20Sopenharmony_ci ring->mpdu_end_offset = __cpu_to_le16(desc_offset(mpdu_end)); 8098c2ecf20Sopenharmony_ci ring->msdu_start_offset = __cpu_to_le16(desc_offset(msdu_start)); 8108c2ecf20Sopenharmony_ci ring->msdu_end_offset = __cpu_to_le16(desc_offset(msdu_end)); 8118c2ecf20Sopenharmony_ci ring->rx_attention_offset = __cpu_to_le16(desc_offset(attention)); 8128c2ecf20Sopenharmony_ci ring->frag_info_offset = __cpu_to_le16(desc_offset(frag_info)); 8138c2ecf20Sopenharmony_ci#undef desc_offset 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cistatic void ath10k_htt_fill_rx_desc_offset_64(void *rx_ring) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci struct htt_rx_ring_setup_ring64 *ring = 8198c2ecf20Sopenharmony_ci (struct htt_rx_ring_setup_ring64 *)rx_ring; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci#define desc_offset(x) (offsetof(struct htt_rx_desc, x) / 4) 8228c2ecf20Sopenharmony_ci ring->mac80211_hdr_offset = __cpu_to_le16(desc_offset(rx_hdr_status)); 8238c2ecf20Sopenharmony_ci ring->msdu_payload_offset = __cpu_to_le16(desc_offset(msdu_payload)); 8248c2ecf20Sopenharmony_ci ring->ppdu_start_offset = __cpu_to_le16(desc_offset(ppdu_start)); 8258c2ecf20Sopenharmony_ci ring->ppdu_end_offset = __cpu_to_le16(desc_offset(ppdu_end)); 8268c2ecf20Sopenharmony_ci ring->mpdu_start_offset = __cpu_to_le16(desc_offset(mpdu_start)); 8278c2ecf20Sopenharmony_ci ring->mpdu_end_offset = __cpu_to_le16(desc_offset(mpdu_end)); 8288c2ecf20Sopenharmony_ci ring->msdu_start_offset = __cpu_to_le16(desc_offset(msdu_start)); 8298c2ecf20Sopenharmony_ci ring->msdu_end_offset = __cpu_to_le16(desc_offset(msdu_end)); 8308c2ecf20Sopenharmony_ci ring->rx_attention_offset = __cpu_to_le16(desc_offset(attention)); 8318c2ecf20Sopenharmony_ci ring->frag_info_offset = __cpu_to_le16(desc_offset(frag_info)); 8328c2ecf20Sopenharmony_ci#undef desc_offset 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_cistatic int ath10k_htt_send_rx_ring_cfg_32(struct ath10k_htt *htt) 8368c2ecf20Sopenharmony_ci{ 8378c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 8388c2ecf20Sopenharmony_ci struct sk_buff *skb; 8398c2ecf20Sopenharmony_ci struct htt_cmd *cmd; 8408c2ecf20Sopenharmony_ci struct htt_rx_ring_setup_ring32 *ring; 8418c2ecf20Sopenharmony_ci const int num_rx_ring = 1; 8428c2ecf20Sopenharmony_ci u16 flags; 8438c2ecf20Sopenharmony_ci u32 fw_idx; 8448c2ecf20Sopenharmony_ci int len; 8458c2ecf20Sopenharmony_ci int ret; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci /* 8488c2ecf20Sopenharmony_ci * the HW expects the buffer to be an integral number of 4-byte 8498c2ecf20Sopenharmony_ci * "words" 8508c2ecf20Sopenharmony_ci */ 8518c2ecf20Sopenharmony_ci BUILD_BUG_ON(!IS_ALIGNED(HTT_RX_BUF_SIZE, 4)); 8528c2ecf20Sopenharmony_ci BUILD_BUG_ON((HTT_RX_BUF_SIZE & HTT_MAX_CACHE_LINE_SIZE_MASK) != 0); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup_32.hdr) 8558c2ecf20Sopenharmony_ci + (sizeof(*ring) * num_rx_ring); 8568c2ecf20Sopenharmony_ci skb = ath10k_htc_alloc_skb(ar, len); 8578c2ecf20Sopenharmony_ci if (!skb) 8588c2ecf20Sopenharmony_ci return -ENOMEM; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci skb_put(skb, len); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci cmd = (struct htt_cmd *)skb->data; 8638c2ecf20Sopenharmony_ci ring = &cmd->rx_setup_32.rings[0]; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_RX_RING_CFG; 8668c2ecf20Sopenharmony_ci cmd->rx_setup_32.hdr.num_rings = 1; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci /* FIXME: do we need all of this? */ 8698c2ecf20Sopenharmony_ci flags = 0; 8708c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MAC80211_HDR; 8718c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MSDU_PAYLOAD; 8728c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_PPDU_START; 8738c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_PPDU_END; 8748c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MPDU_START; 8758c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MPDU_END; 8768c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MSDU_START; 8778c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MSDU_END; 8788c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_RX_ATTENTION; 8798c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_FRAG_INFO; 8808c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_UNICAST_RX; 8818c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MULTICAST_RX; 8828c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_CTRL_RX; 8838c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MGMT_RX; 8848c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_NULL_RX; 8858c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_PHY_DATA_RX; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci fw_idx = __le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci ring->fw_idx_shadow_reg_paddr = 8908c2ecf20Sopenharmony_ci __cpu_to_le32(htt->rx_ring.alloc_idx.paddr); 8918c2ecf20Sopenharmony_ci ring->rx_ring_base_paddr = __cpu_to_le32(htt->rx_ring.base_paddr); 8928c2ecf20Sopenharmony_ci ring->rx_ring_len = __cpu_to_le16(htt->rx_ring.size); 8938c2ecf20Sopenharmony_ci ring->rx_ring_bufsize = __cpu_to_le16(HTT_RX_BUF_SIZE); 8948c2ecf20Sopenharmony_ci ring->flags = __cpu_to_le16(flags); 8958c2ecf20Sopenharmony_ci ring->fw_idx_init_val = __cpu_to_le16(fw_idx); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci ath10k_htt_fill_rx_desc_offset_32(ring); 8988c2ecf20Sopenharmony_ci ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); 8998c2ecf20Sopenharmony_ci if (ret) { 9008c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 9018c2ecf20Sopenharmony_ci return ret; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci return 0; 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic int ath10k_htt_send_rx_ring_cfg_64(struct ath10k_htt *htt) 9088c2ecf20Sopenharmony_ci{ 9098c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 9108c2ecf20Sopenharmony_ci struct sk_buff *skb; 9118c2ecf20Sopenharmony_ci struct htt_cmd *cmd; 9128c2ecf20Sopenharmony_ci struct htt_rx_ring_setup_ring64 *ring; 9138c2ecf20Sopenharmony_ci const int num_rx_ring = 1; 9148c2ecf20Sopenharmony_ci u16 flags; 9158c2ecf20Sopenharmony_ci u32 fw_idx; 9168c2ecf20Sopenharmony_ci int len; 9178c2ecf20Sopenharmony_ci int ret; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci /* HW expects the buffer to be an integral number of 4-byte 9208c2ecf20Sopenharmony_ci * "words" 9218c2ecf20Sopenharmony_ci */ 9228c2ecf20Sopenharmony_ci BUILD_BUG_ON(!IS_ALIGNED(HTT_RX_BUF_SIZE, 4)); 9238c2ecf20Sopenharmony_ci BUILD_BUG_ON((HTT_RX_BUF_SIZE & HTT_MAX_CACHE_LINE_SIZE_MASK) != 0); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup_64.hdr) 9268c2ecf20Sopenharmony_ci + (sizeof(*ring) * num_rx_ring); 9278c2ecf20Sopenharmony_ci skb = ath10k_htc_alloc_skb(ar, len); 9288c2ecf20Sopenharmony_ci if (!skb) 9298c2ecf20Sopenharmony_ci return -ENOMEM; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci skb_put(skb, len); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci cmd = (struct htt_cmd *)skb->data; 9348c2ecf20Sopenharmony_ci ring = &cmd->rx_setup_64.rings[0]; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_RX_RING_CFG; 9378c2ecf20Sopenharmony_ci cmd->rx_setup_64.hdr.num_rings = 1; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci flags = 0; 9408c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MAC80211_HDR; 9418c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MSDU_PAYLOAD; 9428c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_PPDU_START; 9438c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_PPDU_END; 9448c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MPDU_START; 9458c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MPDU_END; 9468c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MSDU_START; 9478c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MSDU_END; 9488c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_RX_ATTENTION; 9498c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_FRAG_INFO; 9508c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_UNICAST_RX; 9518c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MULTICAST_RX; 9528c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_CTRL_RX; 9538c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MGMT_RX; 9548c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_NULL_RX; 9558c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_PHY_DATA_RX; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci fw_idx = __le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci ring->fw_idx_shadow_reg_paddr = __cpu_to_le64(htt->rx_ring.alloc_idx.paddr); 9608c2ecf20Sopenharmony_ci ring->rx_ring_base_paddr = __cpu_to_le64(htt->rx_ring.base_paddr); 9618c2ecf20Sopenharmony_ci ring->rx_ring_len = __cpu_to_le16(htt->rx_ring.size); 9628c2ecf20Sopenharmony_ci ring->rx_ring_bufsize = __cpu_to_le16(HTT_RX_BUF_SIZE); 9638c2ecf20Sopenharmony_ci ring->flags = __cpu_to_le16(flags); 9648c2ecf20Sopenharmony_ci ring->fw_idx_init_val = __cpu_to_le16(fw_idx); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci ath10k_htt_fill_rx_desc_offset_64(ring); 9678c2ecf20Sopenharmony_ci ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); 9688c2ecf20Sopenharmony_ci if (ret) { 9698c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 9708c2ecf20Sopenharmony_ci return ret; 9718c2ecf20Sopenharmony_ci } 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci return 0; 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_cistatic int ath10k_htt_send_rx_ring_cfg_hl(struct ath10k_htt *htt) 9778c2ecf20Sopenharmony_ci{ 9788c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 9798c2ecf20Sopenharmony_ci struct sk_buff *skb; 9808c2ecf20Sopenharmony_ci struct htt_cmd *cmd; 9818c2ecf20Sopenharmony_ci struct htt_rx_ring_setup_ring32 *ring; 9828c2ecf20Sopenharmony_ci const int num_rx_ring = 1; 9838c2ecf20Sopenharmony_ci u16 flags; 9848c2ecf20Sopenharmony_ci int len; 9858c2ecf20Sopenharmony_ci int ret; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* 9888c2ecf20Sopenharmony_ci * the HW expects the buffer to be an integral number of 4-byte 9898c2ecf20Sopenharmony_ci * "words" 9908c2ecf20Sopenharmony_ci */ 9918c2ecf20Sopenharmony_ci BUILD_BUG_ON(!IS_ALIGNED(HTT_RX_BUF_SIZE, 4)); 9928c2ecf20Sopenharmony_ci BUILD_BUG_ON((HTT_RX_BUF_SIZE & HTT_MAX_CACHE_LINE_SIZE_MASK) != 0); 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci len = sizeof(cmd->hdr) + sizeof(cmd->rx_setup_32.hdr) 9958c2ecf20Sopenharmony_ci + (sizeof(*ring) * num_rx_ring); 9968c2ecf20Sopenharmony_ci skb = ath10k_htc_alloc_skb(ar, len); 9978c2ecf20Sopenharmony_ci if (!skb) 9988c2ecf20Sopenharmony_ci return -ENOMEM; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci skb_put(skb, len); 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_ci cmd = (struct htt_cmd *)skb->data; 10038c2ecf20Sopenharmony_ci ring = &cmd->rx_setup_32.rings[0]; 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_RX_RING_CFG; 10068c2ecf20Sopenharmony_ci cmd->rx_setup_32.hdr.num_rings = 1; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci flags = 0; 10098c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MSDU_PAYLOAD; 10108c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_UNICAST_RX; 10118c2ecf20Sopenharmony_ci flags |= HTT_RX_RING_FLAGS_MULTICAST_RX; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci memset(ring, 0, sizeof(*ring)); 10148c2ecf20Sopenharmony_ci ring->rx_ring_len = __cpu_to_le16(HTT_RX_RING_SIZE_MIN); 10158c2ecf20Sopenharmony_ci ring->rx_ring_bufsize = __cpu_to_le16(HTT_RX_BUF_SIZE); 10168c2ecf20Sopenharmony_ci ring->flags = __cpu_to_le16(flags); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); 10198c2ecf20Sopenharmony_ci if (ret) { 10208c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 10218c2ecf20Sopenharmony_ci return ret; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci return 0; 10258c2ecf20Sopenharmony_ci} 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_cistatic int ath10k_htt_h2t_aggr_cfg_msg_32(struct ath10k_htt *htt, 10288c2ecf20Sopenharmony_ci u8 max_subfrms_ampdu, 10298c2ecf20Sopenharmony_ci u8 max_subfrms_amsdu) 10308c2ecf20Sopenharmony_ci{ 10318c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 10328c2ecf20Sopenharmony_ci struct htt_aggr_conf *aggr_conf; 10338c2ecf20Sopenharmony_ci struct sk_buff *skb; 10348c2ecf20Sopenharmony_ci struct htt_cmd *cmd; 10358c2ecf20Sopenharmony_ci int len; 10368c2ecf20Sopenharmony_ci int ret; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci /* Firmware defaults are: amsdu = 3 and ampdu = 64 */ 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci if (max_subfrms_ampdu == 0 || max_subfrms_ampdu > 64) 10418c2ecf20Sopenharmony_ci return -EINVAL; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (max_subfrms_amsdu == 0 || max_subfrms_amsdu > 31) 10448c2ecf20Sopenharmony_ci return -EINVAL; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci len = sizeof(cmd->hdr); 10478c2ecf20Sopenharmony_ci len += sizeof(cmd->aggr_conf); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci skb = ath10k_htc_alloc_skb(ar, len); 10508c2ecf20Sopenharmony_ci if (!skb) 10518c2ecf20Sopenharmony_ci return -ENOMEM; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci skb_put(skb, len); 10548c2ecf20Sopenharmony_ci cmd = (struct htt_cmd *)skb->data; 10558c2ecf20Sopenharmony_ci cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_AGGR_CFG; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci aggr_conf = &cmd->aggr_conf; 10588c2ecf20Sopenharmony_ci aggr_conf->max_num_ampdu_subframes = max_subfrms_ampdu; 10598c2ecf20Sopenharmony_ci aggr_conf->max_num_amsdu_subframes = max_subfrms_amsdu; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d", 10628c2ecf20Sopenharmony_ci aggr_conf->max_num_amsdu_subframes, 10638c2ecf20Sopenharmony_ci aggr_conf->max_num_ampdu_subframes); 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); 10668c2ecf20Sopenharmony_ci if (ret) { 10678c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 10688c2ecf20Sopenharmony_ci return ret; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci return 0; 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_cistatic int ath10k_htt_h2t_aggr_cfg_msg_v2(struct ath10k_htt *htt, 10758c2ecf20Sopenharmony_ci u8 max_subfrms_ampdu, 10768c2ecf20Sopenharmony_ci u8 max_subfrms_amsdu) 10778c2ecf20Sopenharmony_ci{ 10788c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 10798c2ecf20Sopenharmony_ci struct htt_aggr_conf_v2 *aggr_conf; 10808c2ecf20Sopenharmony_ci struct sk_buff *skb; 10818c2ecf20Sopenharmony_ci struct htt_cmd *cmd; 10828c2ecf20Sopenharmony_ci int len; 10838c2ecf20Sopenharmony_ci int ret; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci /* Firmware defaults are: amsdu = 3 and ampdu = 64 */ 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci if (max_subfrms_ampdu == 0 || max_subfrms_ampdu > 64) 10888c2ecf20Sopenharmony_ci return -EINVAL; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci if (max_subfrms_amsdu == 0 || max_subfrms_amsdu > 31) 10918c2ecf20Sopenharmony_ci return -EINVAL; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci len = sizeof(cmd->hdr); 10948c2ecf20Sopenharmony_ci len += sizeof(cmd->aggr_conf_v2); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci skb = ath10k_htc_alloc_skb(ar, len); 10978c2ecf20Sopenharmony_ci if (!skb) 10988c2ecf20Sopenharmony_ci return -ENOMEM; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci skb_put(skb, len); 11018c2ecf20Sopenharmony_ci cmd = (struct htt_cmd *)skb->data; 11028c2ecf20Sopenharmony_ci cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_AGGR_CFG; 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci aggr_conf = &cmd->aggr_conf_v2; 11058c2ecf20Sopenharmony_ci aggr_conf->max_num_ampdu_subframes = max_subfrms_ampdu; 11068c2ecf20Sopenharmony_ci aggr_conf->max_num_amsdu_subframes = max_subfrms_amsdu; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_HTT, "htt h2t aggr cfg msg amsdu %d ampdu %d", 11098c2ecf20Sopenharmony_ci aggr_conf->max_num_amsdu_subframes, 11108c2ecf20Sopenharmony_ci aggr_conf->max_num_ampdu_subframes); 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); 11138c2ecf20Sopenharmony_ci if (ret) { 11148c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 11158c2ecf20Sopenharmony_ci return ret; 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci return 0; 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ciint ath10k_htt_tx_fetch_resp(struct ath10k *ar, 11228c2ecf20Sopenharmony_ci __le32 token, 11238c2ecf20Sopenharmony_ci __le16 fetch_seq_num, 11248c2ecf20Sopenharmony_ci struct htt_tx_fetch_record *records, 11258c2ecf20Sopenharmony_ci size_t num_records) 11268c2ecf20Sopenharmony_ci{ 11278c2ecf20Sopenharmony_ci struct sk_buff *skb; 11288c2ecf20Sopenharmony_ci struct htt_cmd *cmd; 11298c2ecf20Sopenharmony_ci const u16 resp_id = 0; 11308c2ecf20Sopenharmony_ci int len = 0; 11318c2ecf20Sopenharmony_ci int ret; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci /* Response IDs are echo-ed back only for host driver convienence 11348c2ecf20Sopenharmony_ci * purposes. They aren't used for anything in the driver yet so use 0. 11358c2ecf20Sopenharmony_ci */ 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci len += sizeof(cmd->hdr); 11388c2ecf20Sopenharmony_ci len += sizeof(cmd->tx_fetch_resp); 11398c2ecf20Sopenharmony_ci len += sizeof(cmd->tx_fetch_resp.records[0]) * num_records; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci skb = ath10k_htc_alloc_skb(ar, len); 11428c2ecf20Sopenharmony_ci if (!skb) 11438c2ecf20Sopenharmony_ci return -ENOMEM; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci skb_put(skb, len); 11468c2ecf20Sopenharmony_ci cmd = (struct htt_cmd *)skb->data; 11478c2ecf20Sopenharmony_ci cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FETCH_RESP; 11488c2ecf20Sopenharmony_ci cmd->tx_fetch_resp.resp_id = cpu_to_le16(resp_id); 11498c2ecf20Sopenharmony_ci cmd->tx_fetch_resp.fetch_seq_num = fetch_seq_num; 11508c2ecf20Sopenharmony_ci cmd->tx_fetch_resp.num_records = cpu_to_le16(num_records); 11518c2ecf20Sopenharmony_ci cmd->tx_fetch_resp.token = token; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci memcpy(cmd->tx_fetch_resp.records, records, 11548c2ecf20Sopenharmony_ci sizeof(records[0]) * num_records); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci ret = ath10k_htc_send(&ar->htc, ar->htt.eid, skb); 11578c2ecf20Sopenharmony_ci if (ret) { 11588c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to submit htc command: %d\n", ret); 11598c2ecf20Sopenharmony_ci goto err_free_skb; 11608c2ecf20Sopenharmony_ci } 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci return 0; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_cierr_free_skb: 11658c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci return ret; 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic u8 ath10k_htt_tx_get_vdev_id(struct ath10k *ar, struct sk_buff *skb) 11718c2ecf20Sopenharmony_ci{ 11728c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 11738c2ecf20Sopenharmony_ci struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb); 11748c2ecf20Sopenharmony_ci struct ath10k_vif *arvif; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { 11778c2ecf20Sopenharmony_ci return ar->scan.vdev_id; 11788c2ecf20Sopenharmony_ci } else if (cb->vif) { 11798c2ecf20Sopenharmony_ci arvif = (void *)cb->vif->drv_priv; 11808c2ecf20Sopenharmony_ci return arvif->vdev_id; 11818c2ecf20Sopenharmony_ci } else if (ar->monitor_started) { 11828c2ecf20Sopenharmony_ci return ar->monitor_vdev_id; 11838c2ecf20Sopenharmony_ci } else { 11848c2ecf20Sopenharmony_ci return 0; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci} 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_cistatic u8 ath10k_htt_tx_get_tid(struct sk_buff *skb, bool is_eth) 11898c2ecf20Sopenharmony_ci{ 11908c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (void *)skb->data; 11918c2ecf20Sopenharmony_ci struct ath10k_skb_cb *cb = ATH10K_SKB_CB(skb); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci if (!is_eth && ieee80211_is_mgmt(hdr->frame_control)) 11948c2ecf20Sopenharmony_ci return HTT_DATA_TX_EXT_TID_MGMT; 11958c2ecf20Sopenharmony_ci else if (cb->flags & ATH10K_SKB_F_QOS) 11968c2ecf20Sopenharmony_ci return skb->priority & IEEE80211_QOS_CTL_TID_MASK; 11978c2ecf20Sopenharmony_ci else 11988c2ecf20Sopenharmony_ci return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST; 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ciint ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) 12028c2ecf20Sopenharmony_ci{ 12038c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 12048c2ecf20Sopenharmony_ci struct device *dev = ar->dev; 12058c2ecf20Sopenharmony_ci struct sk_buff *txdesc = NULL; 12068c2ecf20Sopenharmony_ci struct htt_cmd *cmd; 12078c2ecf20Sopenharmony_ci struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); 12088c2ecf20Sopenharmony_ci u8 vdev_id = ath10k_htt_tx_get_vdev_id(ar, msdu); 12098c2ecf20Sopenharmony_ci int len = 0; 12108c2ecf20Sopenharmony_ci int msdu_id = -1; 12118c2ecf20Sopenharmony_ci int res; 12128c2ecf20Sopenharmony_ci const u8 *peer_addr; 12138c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci len += sizeof(cmd->hdr); 12168c2ecf20Sopenharmony_ci len += sizeof(cmd->mgmt_tx); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); 12198c2ecf20Sopenharmony_ci if (res < 0) 12208c2ecf20Sopenharmony_ci goto err; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci msdu_id = res; 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci if ((ieee80211_is_action(hdr->frame_control) || 12258c2ecf20Sopenharmony_ci ieee80211_is_deauth(hdr->frame_control) || 12268c2ecf20Sopenharmony_ci ieee80211_is_disassoc(hdr->frame_control)) && 12278c2ecf20Sopenharmony_ci ieee80211_has_protected(hdr->frame_control)) { 12288c2ecf20Sopenharmony_ci peer_addr = hdr->addr1; 12298c2ecf20Sopenharmony_ci if (is_multicast_ether_addr(peer_addr)) { 12308c2ecf20Sopenharmony_ci skb_put(msdu, sizeof(struct ieee80211_mmie_16)); 12318c2ecf20Sopenharmony_ci } else { 12328c2ecf20Sopenharmony_ci if (skb_cb->ucast_cipher == WLAN_CIPHER_SUITE_GCMP || 12338c2ecf20Sopenharmony_ci skb_cb->ucast_cipher == WLAN_CIPHER_SUITE_GCMP_256) 12348c2ecf20Sopenharmony_ci skb_put(msdu, IEEE80211_GCMP_MIC_LEN); 12358c2ecf20Sopenharmony_ci else 12368c2ecf20Sopenharmony_ci skb_put(msdu, IEEE80211_CCMP_MIC_LEN); 12378c2ecf20Sopenharmony_ci } 12388c2ecf20Sopenharmony_ci } 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci txdesc = ath10k_htc_alloc_skb(ar, len); 12418c2ecf20Sopenharmony_ci if (!txdesc) { 12428c2ecf20Sopenharmony_ci res = -ENOMEM; 12438c2ecf20Sopenharmony_ci goto err_free_msdu_id; 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, 12478c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 12488c2ecf20Sopenharmony_ci res = dma_mapping_error(dev, skb_cb->paddr); 12498c2ecf20Sopenharmony_ci if (res) { 12508c2ecf20Sopenharmony_ci res = -EIO; 12518c2ecf20Sopenharmony_ci goto err_free_txdesc; 12528c2ecf20Sopenharmony_ci } 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci skb_put(txdesc, len); 12558c2ecf20Sopenharmony_ci cmd = (struct htt_cmd *)txdesc->data; 12568c2ecf20Sopenharmony_ci memset(cmd, 0, len); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_MGMT_TX; 12598c2ecf20Sopenharmony_ci cmd->mgmt_tx.msdu_paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr); 12608c2ecf20Sopenharmony_ci cmd->mgmt_tx.len = __cpu_to_le32(msdu->len); 12618c2ecf20Sopenharmony_ci cmd->mgmt_tx.desc_id = __cpu_to_le32(msdu_id); 12628c2ecf20Sopenharmony_ci cmd->mgmt_tx.vdev_id = __cpu_to_le32(vdev_id); 12638c2ecf20Sopenharmony_ci memcpy(cmd->mgmt_tx.hdr, msdu->data, 12648c2ecf20Sopenharmony_ci min_t(int, msdu->len, HTT_MGMT_FRM_HDR_DOWNLOAD_LEN)); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci res = ath10k_htc_send(&htt->ar->htc, htt->eid, txdesc); 12678c2ecf20Sopenharmony_ci if (res) 12688c2ecf20Sopenharmony_ci goto err_unmap_msdu; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci return 0; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_cierr_unmap_msdu: 12738c2ecf20Sopenharmony_ci if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL) 12748c2ecf20Sopenharmony_ci dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); 12758c2ecf20Sopenharmony_cierr_free_txdesc: 12768c2ecf20Sopenharmony_ci dev_kfree_skb_any(txdesc); 12778c2ecf20Sopenharmony_cierr_free_msdu_id: 12788c2ecf20Sopenharmony_ci spin_lock_bh(&htt->tx_lock); 12798c2ecf20Sopenharmony_ci ath10k_htt_tx_free_msdu_id(htt, msdu_id); 12808c2ecf20Sopenharmony_ci spin_unlock_bh(&htt->tx_lock); 12818c2ecf20Sopenharmony_cierr: 12828c2ecf20Sopenharmony_ci return res; 12838c2ecf20Sopenharmony_ci} 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci#define HTT_TX_HL_NEEDED_HEADROOM \ 12868c2ecf20Sopenharmony_ci (unsigned int)(sizeof(struct htt_cmd_hdr) + \ 12878c2ecf20Sopenharmony_ci sizeof(struct htt_data_tx_desc) + \ 12888c2ecf20Sopenharmony_ci sizeof(struct ath10k_htc_hdr)) 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_cistatic int ath10k_htt_tx_hl(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode, 12918c2ecf20Sopenharmony_ci struct sk_buff *msdu) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 12948c2ecf20Sopenharmony_ci int res, data_len; 12958c2ecf20Sopenharmony_ci struct htt_cmd_hdr *cmd_hdr; 12968c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; 12978c2ecf20Sopenharmony_ci struct htt_data_tx_desc *tx_desc; 12988c2ecf20Sopenharmony_ci struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); 12998c2ecf20Sopenharmony_ci struct sk_buff *tmp_skb; 13008c2ecf20Sopenharmony_ci bool is_eth = (txmode == ATH10K_HW_TXRX_ETHERNET); 13018c2ecf20Sopenharmony_ci u8 vdev_id = ath10k_htt_tx_get_vdev_id(ar, msdu); 13028c2ecf20Sopenharmony_ci u8 tid = ath10k_htt_tx_get_tid(msdu, is_eth); 13038c2ecf20Sopenharmony_ci u8 flags0 = 0; 13048c2ecf20Sopenharmony_ci u16 flags1 = 0; 13058c2ecf20Sopenharmony_ci u16 msdu_id = 0; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci if ((ieee80211_is_action(hdr->frame_control) || 13088c2ecf20Sopenharmony_ci ieee80211_is_deauth(hdr->frame_control) || 13098c2ecf20Sopenharmony_ci ieee80211_is_disassoc(hdr->frame_control)) && 13108c2ecf20Sopenharmony_ci ieee80211_has_protected(hdr->frame_control)) { 13118c2ecf20Sopenharmony_ci skb_put(msdu, IEEE80211_CCMP_MIC_LEN); 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci data_len = msdu->len; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci switch (txmode) { 13178c2ecf20Sopenharmony_ci case ATH10K_HW_TXRX_RAW: 13188c2ecf20Sopenharmony_ci case ATH10K_HW_TXRX_NATIVE_WIFI: 13198c2ecf20Sopenharmony_ci flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; 13208c2ecf20Sopenharmony_ci fallthrough; 13218c2ecf20Sopenharmony_ci case ATH10K_HW_TXRX_ETHERNET: 13228c2ecf20Sopenharmony_ci flags0 |= SM(txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); 13238c2ecf20Sopenharmony_ci break; 13248c2ecf20Sopenharmony_ci case ATH10K_HW_TXRX_MGMT: 13258c2ecf20Sopenharmony_ci flags0 |= SM(ATH10K_HW_TXRX_MGMT, 13268c2ecf20Sopenharmony_ci HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); 13278c2ecf20Sopenharmony_ci flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci if (htt->disable_tx_comp) 13308c2ecf20Sopenharmony_ci flags1 |= HTT_DATA_TX_DESC_FLAGS1_TX_COMPLETE; 13318c2ecf20Sopenharmony_ci break; 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci if (skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) 13358c2ecf20Sopenharmony_ci flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); 13388c2ecf20Sopenharmony_ci flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); 13398c2ecf20Sopenharmony_ci if (msdu->ip_summed == CHECKSUM_PARTIAL && 13408c2ecf20Sopenharmony_ci !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { 13418c2ecf20Sopenharmony_ci flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; 13428c2ecf20Sopenharmony_ci flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; 13438c2ecf20Sopenharmony_ci } 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci /* Prepend the HTT header and TX desc struct to the data message 13468c2ecf20Sopenharmony_ci * and realloc the skb if it does not have enough headroom. 13478c2ecf20Sopenharmony_ci */ 13488c2ecf20Sopenharmony_ci if (skb_headroom(msdu) < HTT_TX_HL_NEEDED_HEADROOM) { 13498c2ecf20Sopenharmony_ci tmp_skb = msdu; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci ath10k_dbg(htt->ar, ATH10K_DBG_HTT, 13528c2ecf20Sopenharmony_ci "Not enough headroom in skb. Current headroom: %u, needed: %u. Reallocating...\n", 13538c2ecf20Sopenharmony_ci skb_headroom(msdu), HTT_TX_HL_NEEDED_HEADROOM); 13548c2ecf20Sopenharmony_ci msdu = skb_realloc_headroom(msdu, HTT_TX_HL_NEEDED_HEADROOM); 13558c2ecf20Sopenharmony_ci kfree_skb(tmp_skb); 13568c2ecf20Sopenharmony_ci if (!msdu) { 13578c2ecf20Sopenharmony_ci ath10k_warn(htt->ar, "htt hl tx: Unable to realloc skb!\n"); 13588c2ecf20Sopenharmony_ci res = -ENOMEM; 13598c2ecf20Sopenharmony_ci goto out; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci } 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ci if (ar->bus_param.hl_msdu_ids) { 13648c2ecf20Sopenharmony_ci flags1 |= HTT_DATA_TX_DESC_FLAGS1_POSTPONED; 13658c2ecf20Sopenharmony_ci res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); 13668c2ecf20Sopenharmony_ci if (res < 0) { 13678c2ecf20Sopenharmony_ci ath10k_err(ar, "msdu_id allocation failed %d\n", res); 13688c2ecf20Sopenharmony_ci goto out; 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ci msdu_id = res; 13718c2ecf20Sopenharmony_ci } 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci /* As msdu is freed by mac80211 (in ieee80211_tx_status()) and by 13748c2ecf20Sopenharmony_ci * ath10k (in ath10k_htt_htc_tx_complete()) we have to increase 13758c2ecf20Sopenharmony_ci * reference by one to avoid a use-after-free case and a double 13768c2ecf20Sopenharmony_ci * free. 13778c2ecf20Sopenharmony_ci */ 13788c2ecf20Sopenharmony_ci skb_get(msdu); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci skb_push(msdu, sizeof(*cmd_hdr)); 13818c2ecf20Sopenharmony_ci skb_push(msdu, sizeof(*tx_desc)); 13828c2ecf20Sopenharmony_ci cmd_hdr = (struct htt_cmd_hdr *)msdu->data; 13838c2ecf20Sopenharmony_ci tx_desc = (struct htt_data_tx_desc *)(msdu->data + sizeof(*cmd_hdr)); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci cmd_hdr->msg_type = HTT_H2T_MSG_TYPE_TX_FRM; 13868c2ecf20Sopenharmony_ci tx_desc->flags0 = flags0; 13878c2ecf20Sopenharmony_ci tx_desc->flags1 = __cpu_to_le16(flags1); 13888c2ecf20Sopenharmony_ci tx_desc->len = __cpu_to_le16(data_len); 13898c2ecf20Sopenharmony_ci tx_desc->id = __cpu_to_le16(msdu_id); 13908c2ecf20Sopenharmony_ci tx_desc->frags_paddr = 0; /* always zero */ 13918c2ecf20Sopenharmony_ci /* Initialize peer_id to INVALID_PEER because this is NOT 13928c2ecf20Sopenharmony_ci * Reinjection path 13938c2ecf20Sopenharmony_ci */ 13948c2ecf20Sopenharmony_ci tx_desc->peerid = __cpu_to_le32(HTT_INVALID_PEERID); 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci res = ath10k_htc_send_hl(&htt->ar->htc, htt->eid, msdu); 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_ciout: 13998c2ecf20Sopenharmony_ci return res; 14008c2ecf20Sopenharmony_ci} 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_cistatic int ath10k_htt_tx_32(struct ath10k_htt *htt, 14038c2ecf20Sopenharmony_ci enum ath10k_hw_txrx_mode txmode, 14048c2ecf20Sopenharmony_ci struct sk_buff *msdu) 14058c2ecf20Sopenharmony_ci{ 14068c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 14078c2ecf20Sopenharmony_ci struct device *dev = ar->dev; 14088c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; 14098c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu); 14108c2ecf20Sopenharmony_ci struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); 14118c2ecf20Sopenharmony_ci struct ath10k_hif_sg_item sg_items[2]; 14128c2ecf20Sopenharmony_ci struct ath10k_htt_txbuf_32 *txbuf; 14138c2ecf20Sopenharmony_ci struct htt_data_tx_desc_frag *frags; 14148c2ecf20Sopenharmony_ci bool is_eth = (txmode == ATH10K_HW_TXRX_ETHERNET); 14158c2ecf20Sopenharmony_ci u8 vdev_id = ath10k_htt_tx_get_vdev_id(ar, msdu); 14168c2ecf20Sopenharmony_ci u8 tid = ath10k_htt_tx_get_tid(msdu, is_eth); 14178c2ecf20Sopenharmony_ci int prefetch_len; 14188c2ecf20Sopenharmony_ci int res; 14198c2ecf20Sopenharmony_ci u8 flags0 = 0; 14208c2ecf20Sopenharmony_ci u16 msdu_id, flags1 = 0; 14218c2ecf20Sopenharmony_ci u16 freq = 0; 14228c2ecf20Sopenharmony_ci u32 frags_paddr = 0; 14238c2ecf20Sopenharmony_ci u32 txbuf_paddr; 14248c2ecf20Sopenharmony_ci struct htt_msdu_ext_desc *ext_desc = NULL; 14258c2ecf20Sopenharmony_ci struct htt_msdu_ext_desc *ext_desc_t = NULL; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); 14288c2ecf20Sopenharmony_ci if (res < 0) 14298c2ecf20Sopenharmony_ci goto err; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci msdu_id = res; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci prefetch_len = min(htt->prefetch_len, msdu->len); 14348c2ecf20Sopenharmony_ci prefetch_len = roundup(prefetch_len, 4); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci txbuf = htt->txbuf.vaddr_txbuff_32 + msdu_id; 14378c2ecf20Sopenharmony_ci txbuf_paddr = htt->txbuf.paddr + 14388c2ecf20Sopenharmony_ci (sizeof(struct ath10k_htt_txbuf_32) * msdu_id); 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci if ((ieee80211_is_action(hdr->frame_control) || 14418c2ecf20Sopenharmony_ci ieee80211_is_deauth(hdr->frame_control) || 14428c2ecf20Sopenharmony_ci ieee80211_is_disassoc(hdr->frame_control)) && 14438c2ecf20Sopenharmony_ci ieee80211_has_protected(hdr->frame_control)) { 14448c2ecf20Sopenharmony_ci skb_put(msdu, IEEE80211_CCMP_MIC_LEN); 14458c2ecf20Sopenharmony_ci } else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) && 14468c2ecf20Sopenharmony_ci txmode == ATH10K_HW_TXRX_RAW && 14478c2ecf20Sopenharmony_ci ieee80211_has_protected(hdr->frame_control)) { 14488c2ecf20Sopenharmony_ci skb_put(msdu, IEEE80211_CCMP_MIC_LEN); 14498c2ecf20Sopenharmony_ci } 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, 14528c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 14538c2ecf20Sopenharmony_ci res = dma_mapping_error(dev, skb_cb->paddr); 14548c2ecf20Sopenharmony_ci if (res) { 14558c2ecf20Sopenharmony_ci res = -EIO; 14568c2ecf20Sopenharmony_ci goto err_free_msdu_id; 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci if (unlikely(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)) 14608c2ecf20Sopenharmony_ci freq = ar->scan.roc_freq; 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ci switch (txmode) { 14638c2ecf20Sopenharmony_ci case ATH10K_HW_TXRX_RAW: 14648c2ecf20Sopenharmony_ci case ATH10K_HW_TXRX_NATIVE_WIFI: 14658c2ecf20Sopenharmony_ci flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; 14668c2ecf20Sopenharmony_ci fallthrough; 14678c2ecf20Sopenharmony_ci case ATH10K_HW_TXRX_ETHERNET: 14688c2ecf20Sopenharmony_ci if (ar->hw_params.continuous_frag_desc) { 14698c2ecf20Sopenharmony_ci ext_desc_t = htt->frag_desc.vaddr_desc_32; 14708c2ecf20Sopenharmony_ci memset(&ext_desc_t[msdu_id], 0, 14718c2ecf20Sopenharmony_ci sizeof(struct htt_msdu_ext_desc)); 14728c2ecf20Sopenharmony_ci frags = (struct htt_data_tx_desc_frag *) 14738c2ecf20Sopenharmony_ci &ext_desc_t[msdu_id].frags; 14748c2ecf20Sopenharmony_ci ext_desc = &ext_desc_t[msdu_id]; 14758c2ecf20Sopenharmony_ci frags[0].tword_addr.paddr_lo = 14768c2ecf20Sopenharmony_ci __cpu_to_le32(skb_cb->paddr); 14778c2ecf20Sopenharmony_ci frags[0].tword_addr.paddr_hi = 0; 14788c2ecf20Sopenharmony_ci frags[0].tword_addr.len_16 = __cpu_to_le16(msdu->len); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci frags_paddr = htt->frag_desc.paddr + 14818c2ecf20Sopenharmony_ci (sizeof(struct htt_msdu_ext_desc) * msdu_id); 14828c2ecf20Sopenharmony_ci } else { 14838c2ecf20Sopenharmony_ci frags = txbuf->frags; 14848c2ecf20Sopenharmony_ci frags[0].dword_addr.paddr = 14858c2ecf20Sopenharmony_ci __cpu_to_le32(skb_cb->paddr); 14868c2ecf20Sopenharmony_ci frags[0].dword_addr.len = __cpu_to_le32(msdu->len); 14878c2ecf20Sopenharmony_ci frags[1].dword_addr.paddr = 0; 14888c2ecf20Sopenharmony_ci frags[1].dword_addr.len = 0; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci frags_paddr = txbuf_paddr; 14918c2ecf20Sopenharmony_ci } 14928c2ecf20Sopenharmony_ci flags0 |= SM(txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); 14938c2ecf20Sopenharmony_ci break; 14948c2ecf20Sopenharmony_ci case ATH10K_HW_TXRX_MGMT: 14958c2ecf20Sopenharmony_ci flags0 |= SM(ATH10K_HW_TXRX_MGMT, 14968c2ecf20Sopenharmony_ci HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); 14978c2ecf20Sopenharmony_ci flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci frags_paddr = skb_cb->paddr; 15008c2ecf20Sopenharmony_ci break; 15018c2ecf20Sopenharmony_ci } 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci /* Normally all commands go through HTC which manages tx credits for 15048c2ecf20Sopenharmony_ci * each endpoint and notifies when tx is completed. 15058c2ecf20Sopenharmony_ci * 15068c2ecf20Sopenharmony_ci * HTT endpoint is creditless so there's no need to care about HTC 15078c2ecf20Sopenharmony_ci * flags. In that case it is trivial to fill the HTC header here. 15088c2ecf20Sopenharmony_ci * 15098c2ecf20Sopenharmony_ci * MSDU transmission is considered completed upon HTT event. This 15108c2ecf20Sopenharmony_ci * implies no relevant resources can be freed until after the event is 15118c2ecf20Sopenharmony_ci * received. That's why HTC tx completion handler itself is ignored by 15128c2ecf20Sopenharmony_ci * setting NULL to transfer_context for all sg items. 15138c2ecf20Sopenharmony_ci * 15148c2ecf20Sopenharmony_ci * There is simply no point in pushing HTT TX_FRM through HTC tx path 15158c2ecf20Sopenharmony_ci * as it's a waste of resources. By bypassing HTC it is possible to 15168c2ecf20Sopenharmony_ci * avoid extra memory allocations, compress data structures and thus 15178c2ecf20Sopenharmony_ci * improve performance. 15188c2ecf20Sopenharmony_ci */ 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci txbuf->htc_hdr.eid = htt->eid; 15218c2ecf20Sopenharmony_ci txbuf->htc_hdr.len = __cpu_to_le16(sizeof(txbuf->cmd_hdr) + 15228c2ecf20Sopenharmony_ci sizeof(txbuf->cmd_tx) + 15238c2ecf20Sopenharmony_ci prefetch_len); 15248c2ecf20Sopenharmony_ci txbuf->htc_hdr.flags = 0; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if (skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) 15278c2ecf20Sopenharmony_ci flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); 15308c2ecf20Sopenharmony_ci flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); 15318c2ecf20Sopenharmony_ci if (msdu->ip_summed == CHECKSUM_PARTIAL && 15328c2ecf20Sopenharmony_ci !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { 15338c2ecf20Sopenharmony_ci flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; 15348c2ecf20Sopenharmony_ci flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; 15358c2ecf20Sopenharmony_ci if (ar->hw_params.continuous_frag_desc) 15368c2ecf20Sopenharmony_ci ext_desc->flags |= HTT_MSDU_CHECKSUM_ENABLE; 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci /* Prevent firmware from sending up tx inspection requests. There's 15408c2ecf20Sopenharmony_ci * nothing ath10k can do with frames requested for inspection so force 15418c2ecf20Sopenharmony_ci * it to simply rely a regular tx completion with discard status. 15428c2ecf20Sopenharmony_ci */ 15438c2ecf20Sopenharmony_ci flags1 |= HTT_DATA_TX_DESC_FLAGS1_POSTPONED; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; 15468c2ecf20Sopenharmony_ci txbuf->cmd_tx.flags0 = flags0; 15478c2ecf20Sopenharmony_ci txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1); 15488c2ecf20Sopenharmony_ci txbuf->cmd_tx.len = __cpu_to_le16(msdu->len); 15498c2ecf20Sopenharmony_ci txbuf->cmd_tx.id = __cpu_to_le16(msdu_id); 15508c2ecf20Sopenharmony_ci txbuf->cmd_tx.frags_paddr = __cpu_to_le32(frags_paddr); 15518c2ecf20Sopenharmony_ci if (ath10k_mac_tx_frm_has_freq(ar)) { 15528c2ecf20Sopenharmony_ci txbuf->cmd_tx.offchan_tx.peerid = 15538c2ecf20Sopenharmony_ci __cpu_to_le16(HTT_INVALID_PEERID); 15548c2ecf20Sopenharmony_ci txbuf->cmd_tx.offchan_tx.freq = 15558c2ecf20Sopenharmony_ci __cpu_to_le16(freq); 15568c2ecf20Sopenharmony_ci } else { 15578c2ecf20Sopenharmony_ci txbuf->cmd_tx.peerid = 15588c2ecf20Sopenharmony_ci __cpu_to_le32(HTT_INVALID_PEERID); 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid); 15628c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_HTT, 15638c2ecf20Sopenharmony_ci "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %pad, msdu_paddr %pad vdev %hhu tid %hhu freq %hu\n", 15648c2ecf20Sopenharmony_ci flags0, flags1, msdu->len, msdu_id, &frags_paddr, 15658c2ecf20Sopenharmony_ci &skb_cb->paddr, vdev_id, tid, freq); 15668c2ecf20Sopenharmony_ci ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", 15678c2ecf20Sopenharmony_ci msdu->data, msdu->len); 15688c2ecf20Sopenharmony_ci trace_ath10k_tx_hdr(ar, msdu->data, msdu->len); 15698c2ecf20Sopenharmony_ci trace_ath10k_tx_payload(ar, msdu->data, msdu->len); 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci sg_items[0].transfer_id = 0; 15728c2ecf20Sopenharmony_ci sg_items[0].transfer_context = NULL; 15738c2ecf20Sopenharmony_ci sg_items[0].vaddr = &txbuf->htc_hdr; 15748c2ecf20Sopenharmony_ci sg_items[0].paddr = txbuf_paddr + 15758c2ecf20Sopenharmony_ci sizeof(txbuf->frags); 15768c2ecf20Sopenharmony_ci sg_items[0].len = sizeof(txbuf->htc_hdr) + 15778c2ecf20Sopenharmony_ci sizeof(txbuf->cmd_hdr) + 15788c2ecf20Sopenharmony_ci sizeof(txbuf->cmd_tx); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci sg_items[1].transfer_id = 0; 15818c2ecf20Sopenharmony_ci sg_items[1].transfer_context = NULL; 15828c2ecf20Sopenharmony_ci sg_items[1].vaddr = msdu->data; 15838c2ecf20Sopenharmony_ci sg_items[1].paddr = skb_cb->paddr; 15848c2ecf20Sopenharmony_ci sg_items[1].len = prefetch_len; 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci res = ath10k_hif_tx_sg(htt->ar, 15878c2ecf20Sopenharmony_ci htt->ar->htc.endpoint[htt->eid].ul_pipe_id, 15888c2ecf20Sopenharmony_ci sg_items, ARRAY_SIZE(sg_items)); 15898c2ecf20Sopenharmony_ci if (res) 15908c2ecf20Sopenharmony_ci goto err_unmap_msdu; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci return 0; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_cierr_unmap_msdu: 15958c2ecf20Sopenharmony_ci dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); 15968c2ecf20Sopenharmony_cierr_free_msdu_id: 15978c2ecf20Sopenharmony_ci spin_lock_bh(&htt->tx_lock); 15988c2ecf20Sopenharmony_ci ath10k_htt_tx_free_msdu_id(htt, msdu_id); 15998c2ecf20Sopenharmony_ci spin_unlock_bh(&htt->tx_lock); 16008c2ecf20Sopenharmony_cierr: 16018c2ecf20Sopenharmony_ci return res; 16028c2ecf20Sopenharmony_ci} 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_cistatic int ath10k_htt_tx_64(struct ath10k_htt *htt, 16058c2ecf20Sopenharmony_ci enum ath10k_hw_txrx_mode txmode, 16068c2ecf20Sopenharmony_ci struct sk_buff *msdu) 16078c2ecf20Sopenharmony_ci{ 16088c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 16098c2ecf20Sopenharmony_ci struct device *dev = ar->dev; 16108c2ecf20Sopenharmony_ci struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; 16118c2ecf20Sopenharmony_ci struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu); 16128c2ecf20Sopenharmony_ci struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu); 16138c2ecf20Sopenharmony_ci struct ath10k_hif_sg_item sg_items[2]; 16148c2ecf20Sopenharmony_ci struct ath10k_htt_txbuf_64 *txbuf; 16158c2ecf20Sopenharmony_ci struct htt_data_tx_desc_frag *frags; 16168c2ecf20Sopenharmony_ci bool is_eth = (txmode == ATH10K_HW_TXRX_ETHERNET); 16178c2ecf20Sopenharmony_ci u8 vdev_id = ath10k_htt_tx_get_vdev_id(ar, msdu); 16188c2ecf20Sopenharmony_ci u8 tid = ath10k_htt_tx_get_tid(msdu, is_eth); 16198c2ecf20Sopenharmony_ci int prefetch_len; 16208c2ecf20Sopenharmony_ci int res; 16218c2ecf20Sopenharmony_ci u8 flags0 = 0; 16228c2ecf20Sopenharmony_ci u16 msdu_id, flags1 = 0; 16238c2ecf20Sopenharmony_ci u16 freq = 0; 16248c2ecf20Sopenharmony_ci dma_addr_t frags_paddr = 0; 16258c2ecf20Sopenharmony_ci dma_addr_t txbuf_paddr; 16268c2ecf20Sopenharmony_ci struct htt_msdu_ext_desc_64 *ext_desc = NULL; 16278c2ecf20Sopenharmony_ci struct htt_msdu_ext_desc_64 *ext_desc_t = NULL; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); 16308c2ecf20Sopenharmony_ci if (res < 0) 16318c2ecf20Sopenharmony_ci goto err; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci msdu_id = res; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci prefetch_len = min(htt->prefetch_len, msdu->len); 16368c2ecf20Sopenharmony_ci prefetch_len = roundup(prefetch_len, 4); 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci txbuf = htt->txbuf.vaddr_txbuff_64 + msdu_id; 16398c2ecf20Sopenharmony_ci txbuf_paddr = htt->txbuf.paddr + 16408c2ecf20Sopenharmony_ci (sizeof(struct ath10k_htt_txbuf_64) * msdu_id); 16418c2ecf20Sopenharmony_ci 16428c2ecf20Sopenharmony_ci if ((ieee80211_is_action(hdr->frame_control) || 16438c2ecf20Sopenharmony_ci ieee80211_is_deauth(hdr->frame_control) || 16448c2ecf20Sopenharmony_ci ieee80211_is_disassoc(hdr->frame_control)) && 16458c2ecf20Sopenharmony_ci ieee80211_has_protected(hdr->frame_control)) { 16468c2ecf20Sopenharmony_ci skb_put(msdu, IEEE80211_CCMP_MIC_LEN); 16478c2ecf20Sopenharmony_ci } else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) && 16488c2ecf20Sopenharmony_ci txmode == ATH10K_HW_TXRX_RAW && 16498c2ecf20Sopenharmony_ci ieee80211_has_protected(hdr->frame_control)) { 16508c2ecf20Sopenharmony_ci skb_put(msdu, IEEE80211_CCMP_MIC_LEN); 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, 16548c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 16558c2ecf20Sopenharmony_ci res = dma_mapping_error(dev, skb_cb->paddr); 16568c2ecf20Sopenharmony_ci if (res) { 16578c2ecf20Sopenharmony_ci res = -EIO; 16588c2ecf20Sopenharmony_ci goto err_free_msdu_id; 16598c2ecf20Sopenharmony_ci } 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci if (unlikely(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)) 16628c2ecf20Sopenharmony_ci freq = ar->scan.roc_freq; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci switch (txmode) { 16658c2ecf20Sopenharmony_ci case ATH10K_HW_TXRX_RAW: 16668c2ecf20Sopenharmony_ci case ATH10K_HW_TXRX_NATIVE_WIFI: 16678c2ecf20Sopenharmony_ci flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; 16688c2ecf20Sopenharmony_ci fallthrough; 16698c2ecf20Sopenharmony_ci case ATH10K_HW_TXRX_ETHERNET: 16708c2ecf20Sopenharmony_ci if (ar->hw_params.continuous_frag_desc) { 16718c2ecf20Sopenharmony_ci ext_desc_t = htt->frag_desc.vaddr_desc_64; 16728c2ecf20Sopenharmony_ci memset(&ext_desc_t[msdu_id], 0, 16738c2ecf20Sopenharmony_ci sizeof(struct htt_msdu_ext_desc_64)); 16748c2ecf20Sopenharmony_ci frags = (struct htt_data_tx_desc_frag *) 16758c2ecf20Sopenharmony_ci &ext_desc_t[msdu_id].frags; 16768c2ecf20Sopenharmony_ci ext_desc = &ext_desc_t[msdu_id]; 16778c2ecf20Sopenharmony_ci frags[0].tword_addr.paddr_lo = 16788c2ecf20Sopenharmony_ci __cpu_to_le32(skb_cb->paddr); 16798c2ecf20Sopenharmony_ci frags[0].tword_addr.paddr_hi = 16808c2ecf20Sopenharmony_ci __cpu_to_le16(upper_32_bits(skb_cb->paddr)); 16818c2ecf20Sopenharmony_ci frags[0].tword_addr.len_16 = __cpu_to_le16(msdu->len); 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci frags_paddr = htt->frag_desc.paddr + 16848c2ecf20Sopenharmony_ci (sizeof(struct htt_msdu_ext_desc_64) * msdu_id); 16858c2ecf20Sopenharmony_ci } else { 16868c2ecf20Sopenharmony_ci frags = txbuf->frags; 16878c2ecf20Sopenharmony_ci frags[0].tword_addr.paddr_lo = 16888c2ecf20Sopenharmony_ci __cpu_to_le32(skb_cb->paddr); 16898c2ecf20Sopenharmony_ci frags[0].tword_addr.paddr_hi = 16908c2ecf20Sopenharmony_ci __cpu_to_le16(upper_32_bits(skb_cb->paddr)); 16918c2ecf20Sopenharmony_ci frags[0].tword_addr.len_16 = __cpu_to_le16(msdu->len); 16928c2ecf20Sopenharmony_ci frags[1].tword_addr.paddr_lo = 0; 16938c2ecf20Sopenharmony_ci frags[1].tword_addr.paddr_hi = 0; 16948c2ecf20Sopenharmony_ci frags[1].tword_addr.len_16 = 0; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci flags0 |= SM(txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); 16978c2ecf20Sopenharmony_ci break; 16988c2ecf20Sopenharmony_ci case ATH10K_HW_TXRX_MGMT: 16998c2ecf20Sopenharmony_ci flags0 |= SM(ATH10K_HW_TXRX_MGMT, 17008c2ecf20Sopenharmony_ci HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); 17018c2ecf20Sopenharmony_ci flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci frags_paddr = skb_cb->paddr; 17048c2ecf20Sopenharmony_ci break; 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci /* Normally all commands go through HTC which manages tx credits for 17088c2ecf20Sopenharmony_ci * each endpoint and notifies when tx is completed. 17098c2ecf20Sopenharmony_ci * 17108c2ecf20Sopenharmony_ci * HTT endpoint is creditless so there's no need to care about HTC 17118c2ecf20Sopenharmony_ci * flags. In that case it is trivial to fill the HTC header here. 17128c2ecf20Sopenharmony_ci * 17138c2ecf20Sopenharmony_ci * MSDU transmission is considered completed upon HTT event. This 17148c2ecf20Sopenharmony_ci * implies no relevant resources can be freed until after the event is 17158c2ecf20Sopenharmony_ci * received. That's why HTC tx completion handler itself is ignored by 17168c2ecf20Sopenharmony_ci * setting NULL to transfer_context for all sg items. 17178c2ecf20Sopenharmony_ci * 17188c2ecf20Sopenharmony_ci * There is simply no point in pushing HTT TX_FRM through HTC tx path 17198c2ecf20Sopenharmony_ci * as it's a waste of resources. By bypassing HTC it is possible to 17208c2ecf20Sopenharmony_ci * avoid extra memory allocations, compress data structures and thus 17218c2ecf20Sopenharmony_ci * improve performance. 17228c2ecf20Sopenharmony_ci */ 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci txbuf->htc_hdr.eid = htt->eid; 17258c2ecf20Sopenharmony_ci txbuf->htc_hdr.len = __cpu_to_le16(sizeof(txbuf->cmd_hdr) + 17268c2ecf20Sopenharmony_ci sizeof(txbuf->cmd_tx) + 17278c2ecf20Sopenharmony_ci prefetch_len); 17288c2ecf20Sopenharmony_ci txbuf->htc_hdr.flags = 0; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci if (skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) 17318c2ecf20Sopenharmony_ci flags0 |= HTT_DATA_TX_DESC_FLAGS0_NO_ENCRYPT; 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID); 17348c2ecf20Sopenharmony_ci flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID); 17358c2ecf20Sopenharmony_ci if (msdu->ip_summed == CHECKSUM_PARTIAL && 17368c2ecf20Sopenharmony_ci !test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) { 17378c2ecf20Sopenharmony_ci flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; 17388c2ecf20Sopenharmony_ci flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; 17398c2ecf20Sopenharmony_ci if (ar->hw_params.continuous_frag_desc) { 17408c2ecf20Sopenharmony_ci memset(ext_desc->tso_flag, 0, sizeof(ext_desc->tso_flag)); 17418c2ecf20Sopenharmony_ci ext_desc->tso_flag[3] |= 17428c2ecf20Sopenharmony_ci __cpu_to_le32(HTT_MSDU_CHECKSUM_ENABLE_64); 17438c2ecf20Sopenharmony_ci } 17448c2ecf20Sopenharmony_ci } 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci /* Prevent firmware from sending up tx inspection requests. There's 17478c2ecf20Sopenharmony_ci * nothing ath10k can do with frames requested for inspection so force 17488c2ecf20Sopenharmony_ci * it to simply rely a regular tx completion with discard status. 17498c2ecf20Sopenharmony_ci */ 17508c2ecf20Sopenharmony_ci flags1 |= HTT_DATA_TX_DESC_FLAGS1_POSTPONED; 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci txbuf->cmd_hdr.msg_type = HTT_H2T_MSG_TYPE_TX_FRM; 17538c2ecf20Sopenharmony_ci txbuf->cmd_tx.flags0 = flags0; 17548c2ecf20Sopenharmony_ci txbuf->cmd_tx.flags1 = __cpu_to_le16(flags1); 17558c2ecf20Sopenharmony_ci txbuf->cmd_tx.len = __cpu_to_le16(msdu->len); 17568c2ecf20Sopenharmony_ci txbuf->cmd_tx.id = __cpu_to_le16(msdu_id); 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci /* fill fragment descriptor */ 17598c2ecf20Sopenharmony_ci txbuf->cmd_tx.frags_paddr = __cpu_to_le64(frags_paddr); 17608c2ecf20Sopenharmony_ci if (ath10k_mac_tx_frm_has_freq(ar)) { 17618c2ecf20Sopenharmony_ci txbuf->cmd_tx.offchan_tx.peerid = 17628c2ecf20Sopenharmony_ci __cpu_to_le16(HTT_INVALID_PEERID); 17638c2ecf20Sopenharmony_ci txbuf->cmd_tx.offchan_tx.freq = 17648c2ecf20Sopenharmony_ci __cpu_to_le16(freq); 17658c2ecf20Sopenharmony_ci } else { 17668c2ecf20Sopenharmony_ci txbuf->cmd_tx.peerid = 17678c2ecf20Sopenharmony_ci __cpu_to_le32(HTT_INVALID_PEERID); 17688c2ecf20Sopenharmony_ci } 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid); 17718c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_HTT, 17728c2ecf20Sopenharmony_ci "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %pad, msdu_paddr %pad vdev %hhu tid %hhu freq %hu\n", 17738c2ecf20Sopenharmony_ci flags0, flags1, msdu->len, msdu_id, &frags_paddr, 17748c2ecf20Sopenharmony_ci &skb_cb->paddr, vdev_id, tid, freq); 17758c2ecf20Sopenharmony_ci ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ", 17768c2ecf20Sopenharmony_ci msdu->data, msdu->len); 17778c2ecf20Sopenharmony_ci trace_ath10k_tx_hdr(ar, msdu->data, msdu->len); 17788c2ecf20Sopenharmony_ci trace_ath10k_tx_payload(ar, msdu->data, msdu->len); 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci sg_items[0].transfer_id = 0; 17818c2ecf20Sopenharmony_ci sg_items[0].transfer_context = NULL; 17828c2ecf20Sopenharmony_ci sg_items[0].vaddr = &txbuf->htc_hdr; 17838c2ecf20Sopenharmony_ci sg_items[0].paddr = txbuf_paddr + 17848c2ecf20Sopenharmony_ci sizeof(txbuf->frags); 17858c2ecf20Sopenharmony_ci sg_items[0].len = sizeof(txbuf->htc_hdr) + 17868c2ecf20Sopenharmony_ci sizeof(txbuf->cmd_hdr) + 17878c2ecf20Sopenharmony_ci sizeof(txbuf->cmd_tx); 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci sg_items[1].transfer_id = 0; 17908c2ecf20Sopenharmony_ci sg_items[1].transfer_context = NULL; 17918c2ecf20Sopenharmony_ci sg_items[1].vaddr = msdu->data; 17928c2ecf20Sopenharmony_ci sg_items[1].paddr = skb_cb->paddr; 17938c2ecf20Sopenharmony_ci sg_items[1].len = prefetch_len; 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci res = ath10k_hif_tx_sg(htt->ar, 17968c2ecf20Sopenharmony_ci htt->ar->htc.endpoint[htt->eid].ul_pipe_id, 17978c2ecf20Sopenharmony_ci sg_items, ARRAY_SIZE(sg_items)); 17988c2ecf20Sopenharmony_ci if (res) 17998c2ecf20Sopenharmony_ci goto err_unmap_msdu; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci return 0; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_cierr_unmap_msdu: 18048c2ecf20Sopenharmony_ci dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); 18058c2ecf20Sopenharmony_cierr_free_msdu_id: 18068c2ecf20Sopenharmony_ci spin_lock_bh(&htt->tx_lock); 18078c2ecf20Sopenharmony_ci ath10k_htt_tx_free_msdu_id(htt, msdu_id); 18088c2ecf20Sopenharmony_ci spin_unlock_bh(&htt->tx_lock); 18098c2ecf20Sopenharmony_cierr: 18108c2ecf20Sopenharmony_ci return res; 18118c2ecf20Sopenharmony_ci} 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_cistatic const struct ath10k_htt_tx_ops htt_tx_ops_32 = { 18148c2ecf20Sopenharmony_ci .htt_send_rx_ring_cfg = ath10k_htt_send_rx_ring_cfg_32, 18158c2ecf20Sopenharmony_ci .htt_send_frag_desc_bank_cfg = ath10k_htt_send_frag_desc_bank_cfg_32, 18168c2ecf20Sopenharmony_ci .htt_alloc_frag_desc = ath10k_htt_tx_alloc_cont_frag_desc_32, 18178c2ecf20Sopenharmony_ci .htt_free_frag_desc = ath10k_htt_tx_free_cont_frag_desc_32, 18188c2ecf20Sopenharmony_ci .htt_tx = ath10k_htt_tx_32, 18198c2ecf20Sopenharmony_ci .htt_alloc_txbuff = ath10k_htt_tx_alloc_cont_txbuf_32, 18208c2ecf20Sopenharmony_ci .htt_free_txbuff = ath10k_htt_tx_free_cont_txbuf_32, 18218c2ecf20Sopenharmony_ci .htt_h2t_aggr_cfg_msg = ath10k_htt_h2t_aggr_cfg_msg_32, 18228c2ecf20Sopenharmony_ci}; 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_cistatic const struct ath10k_htt_tx_ops htt_tx_ops_64 = { 18258c2ecf20Sopenharmony_ci .htt_send_rx_ring_cfg = ath10k_htt_send_rx_ring_cfg_64, 18268c2ecf20Sopenharmony_ci .htt_send_frag_desc_bank_cfg = ath10k_htt_send_frag_desc_bank_cfg_64, 18278c2ecf20Sopenharmony_ci .htt_alloc_frag_desc = ath10k_htt_tx_alloc_cont_frag_desc_64, 18288c2ecf20Sopenharmony_ci .htt_free_frag_desc = ath10k_htt_tx_free_cont_frag_desc_64, 18298c2ecf20Sopenharmony_ci .htt_tx = ath10k_htt_tx_64, 18308c2ecf20Sopenharmony_ci .htt_alloc_txbuff = ath10k_htt_tx_alloc_cont_txbuf_64, 18318c2ecf20Sopenharmony_ci .htt_free_txbuff = ath10k_htt_tx_free_cont_txbuf_64, 18328c2ecf20Sopenharmony_ci .htt_h2t_aggr_cfg_msg = ath10k_htt_h2t_aggr_cfg_msg_v2, 18338c2ecf20Sopenharmony_ci}; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_cistatic const struct ath10k_htt_tx_ops htt_tx_ops_hl = { 18368c2ecf20Sopenharmony_ci .htt_send_rx_ring_cfg = ath10k_htt_send_rx_ring_cfg_hl, 18378c2ecf20Sopenharmony_ci .htt_send_frag_desc_bank_cfg = ath10k_htt_send_frag_desc_bank_cfg_32, 18388c2ecf20Sopenharmony_ci .htt_tx = ath10k_htt_tx_hl, 18398c2ecf20Sopenharmony_ci .htt_h2t_aggr_cfg_msg = ath10k_htt_h2t_aggr_cfg_msg_32, 18408c2ecf20Sopenharmony_ci .htt_flush_tx = ath10k_htt_flush_tx_queue, 18418c2ecf20Sopenharmony_ci}; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_civoid ath10k_htt_set_tx_ops(struct ath10k_htt *htt) 18448c2ecf20Sopenharmony_ci{ 18458c2ecf20Sopenharmony_ci struct ath10k *ar = htt->ar; 18468c2ecf20Sopenharmony_ci 18478c2ecf20Sopenharmony_ci if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL) 18488c2ecf20Sopenharmony_ci htt->tx_ops = &htt_tx_ops_hl; 18498c2ecf20Sopenharmony_ci else if (ar->hw_params.target_64bit) 18508c2ecf20Sopenharmony_ci htt->tx_ops = &htt_tx_ops_64; 18518c2ecf20Sopenharmony_ci else 18528c2ecf20Sopenharmony_ci htt->tx_ops = &htt_tx_ops_32; 18538c2ecf20Sopenharmony_ci} 1854