From 9600bc899bd28386375f5b5902a33f1984ce9da8 Mon Sep 17 00:00:00 2001 From: Venkateswara Naralasetty Date: Thu, 18 Nov 2021 13:11:02 +0530 Subject: [PATCH] ath11k: add simple tx handler for AP mode Add simple tx handler for AP mode to skip cheks which are not applicable for AP mode. Signed-off-by: Venkateswara Naralasetty --- drivers/net/wireless/ath/ath11k/dp_tx.c | 123 +++++++++++++++++++++++++++++ drivers/net/wireless/ath/ath11k/dp_tx.h | 2 + drivers/net/wireless/ath/ath11k/hal_desc.h | 6 ++ drivers/net/wireless/ath/ath11k/mac.c | 3 + 4 files changed, 134 insertions(+) --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -92,6 +92,128 @@ static int ath11k_dp_prepare_htt_metadat return 0; } +int ath11k_dp_tx_simple(struct ath11k *ar, struct ath11k_vif *arvif, + struct sk_buff *skb, struct ath11k_sta *arsta) +{ + struct ath11k_base *ab = ar->ab; + struct ath11k_dp *dp = &ab->dp; + struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb); + struct hal_srng *tcl_ring; + struct dp_tx_ring *tx_ring; + struct hal_tcl_data_cmd *tcl_desc; + void *hal_tcl_desc; + dma_addr_t paddr; + u8 pool_id; + u8 hal_ring_id; + int ret; + u32 idr; + u8 tcl_ring_id, ring_id, max_tx_ring; + u8 buf_id; + u32 desc_id; + u8 ring_selector; + + max_tx_ring = ab->hw_params.max_tx_ring; + + if (unlikely(atomic_read(&ab->num_max_allowed) > DP_TX_COMP_MAX_ALLOWED)) { + atomic_inc(&ab->soc_stats.tx_err.max_fail); + ret = -EINVAL; + } + + ring_selector = smp_processor_id(); + pool_id = ring_selector; + + if (ar->ab->hw_params.tcl_0_only) { + ring_id = 0; + tcl_ring_id = 0; + } else { + ring_id = ring_selector % max_tx_ring; + tcl_ring_id = (ring_id == DP_TCL_NUM_RING_MAX) ? + DP_TCL_NUM_RING_MAX - 1 : ring_id; + } + + buf_id = tcl_ring_id + HAL_RX_BUF_RBM_SW0_BM; + tx_ring = &dp->tx_ring[tcl_ring_id]; + + spin_lock_bh(&tx_ring->tx_idr_lock); + idr = find_first_zero_bit(tx_ring->idrs, DP_TX_IDR_SIZE); + if (unlikely(idr >= DP_TX_IDR_SIZE)) { + spin_unlock_bh(&tx_ring->tx_idr_lock); + return -ENOSPC; + } + + set_bit(idr, tx_ring->idrs); + tx_ring->idr_pool[idr].id = idr; + tx_ring->idr_pool[idr].buf = skb; + spin_unlock_bh(&tx_ring->tx_idr_lock); + + desc_id = FIELD_PREP(DP_TX_DESC_ID_MAC_ID, ar->pdev_idx) | + FIELD_PREP(DP_TX_DESC_ID_MSDU_ID, idr) | + FIELD_PREP(DP_TX_DESC_ID_POOL_ID, pool_id); + + skb_cb->vif = arvif->vif; + skb_cb->ar = ar; + + paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(ab->dev, paddr))) { + atomic_inc(&ab->soc_stats.tx_err.misc_fail); + ath11k_warn(ab, "failed to DMA map data Tx buffer\n"); + ret = -ENOMEM; + goto fail_remove_idr; + } + + skb_cb->paddr = paddr; + + hal_ring_id = tx_ring->tcl_data_ring.ring_id; + tcl_ring = &ab->hal.srng_list[hal_ring_id]; + + spin_lock_bh(&tcl_ring->lock); + ath11k_hal_srng_access_begin(ab, tcl_ring); + + hal_tcl_desc = (void *)ath11k_hal_srng_src_get_next_entry(ab, tcl_ring); + if (unlikely(!hal_tcl_desc)) { + ath11k_hal_srng_access_end(ab, tcl_ring); + spin_unlock_bh(&tcl_ring->lock); + ab->soc_stats.tx_err.desc_na[tcl_ring_id]++; + ret = -ENOMEM; + goto fail_remove_idr; + } + + tcl_desc = (struct hal_tcl_data_cmd *)(hal_tcl_desc + sizeof(struct hal_tlv_hdr)); + tcl_desc->info3 = 0; + tcl_desc->info4 = 0; + + tcl_desc->buf_addr_info.info0 = FIELD_PREP(BUFFER_ADDR_INFO0_ADDR, paddr); + tcl_desc->buf_addr_info.info1 = FIELD_PREP(BUFFER_ADDR_INFO1_ADDR, + ((uint64_t)paddr >> HAL_ADDR_MSB_REG_SHIFT)); + tcl_desc->buf_addr_info.info1 |= FIELD_PREP(BUFFER_ADDR_INFO1_RET_BUF_MGR, buf_id) | + FIELD_PREP(BUFFER_ADDR_INFO1_SW_COOKIE, desc_id); + tcl_desc->info0 = FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_SEARCH_TYPE, + arvif->search_type) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_ENCAP_TYPE, HAL_TCL_ENCAP_TYPE_ETHERNET) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_ADDR_EN, arvif->hal_addr_search_flags) | + FIELD_PREP(HAL_TCL_DATA_CMD_INFO0_CMD_NUM, arvif->tcl_metadata); + + tcl_desc->info1 = FIELD_PREP(HAL_TCL_DATA_CMD_INFO1_DATA_LEN, skb->len); + + if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) + tcl_desc->info1 |= TX_IP_CHECKSUM; + + tcl_desc->info2 = FIELD_PREP(HAL_TCL_DATA_CMD_INFO2_LMAC_ID, ar->lmac_id); + + ath11k_hal_srng_access_end(ab, tcl_ring); + spin_unlock_bh(&tcl_ring->lock); + + atomic_inc(&ar->dp.num_tx_pending); + atomic_inc(&ab->num_max_allowed); + + return 0; + +fail_remove_idr: + tx_ring->idr_pool[idr].id = -1; + clear_bit(idr, tx_ring->idrs); + return ret; +} + int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, struct sk_buff *skb, struct ath11k_sta *arsta) { --- a/drivers/net/wireless/ath/ath11k/dp_tx.h +++ b/drivers/net/wireless/ath/ath11k/dp_tx.h @@ -220,6 +220,8 @@ struct htt_tx_msdu_desc_ext { int ath11k_dp_tx_htt_h2t_ver_req_msg(struct ath11k_base *ab); int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, struct sk_buff *skb, struct ath11k_sta *arsta); +int ath11k_dp_tx_simple(struct ath11k *ar, struct ath11k_vif *arvif, + struct sk_buff *skb, struct ath11k_sta *arsta); void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id); int ath11k_dp_tx_send_reo_cmd(struct ath11k_base *ab, struct dp_rx_tid *rx_tid, enum hal_reo_cmd_type type, --- a/drivers/net/wireless/ath/ath11k/hal_desc.h +++ b/drivers/net/wireless/ath/ath11k/hal_desc.h @@ -952,6 +952,12 @@ struct hal_reo_flush_cache { u32 rsvd0[6]; } __packed; +#define TX_IP_CHECKSUM HAL_TCL_DATA_CMD_INFO1_IP4_CKSUM_EN | \ + HAL_TCL_DATA_CMD_INFO1_UDP4_CKSUM_EN | \ + HAL_TCL_DATA_CMD_INFO1_UDP6_CKSUM_EN | \ + HAL_TCL_DATA_CMD_INFO1_TCP4_CKSUM_EN | \ + HAL_TCL_DATA_CMD_INFO1_TCP6_CKSUM_EN + #define HAL_TCL_DATA_CMD_INFO0_DESC_TYPE BIT(0) #define HAL_TCL_DATA_CMD_INFO0_EPD BIT(1) #define HAL_TCL_DATA_CMD_INFO0_ENCAP_TYPE GENMASK(3, 2) --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -6784,6 +6784,9 @@ static void ath11k_mac_op_tx(struct ieee if (ar->ab->nss.enabled) ret = ath11k_nss_tx(arvif, skb); + else if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) + ret = ath11k_dp_tx_simple(ar, arvif, skb, + (control->sta) ? control->sta->drv_priv : NULL); else ret = ath11k_dp_tx(ar, arvif, skb, (control->sta) ? control->sta->drv_priv : NULL);