mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
wifi: ath12k: Move ath12k_dp_tx and related APIs to wifi7 directory
Move arch specific TX data path to wifi7 directory as part of Next Generation (NG) Driver Framework. Architecture specific APIs: ath12k_hal_tx_cmd_ext_desc_setup ath12k_dp_prepare_htt_metadata ath12k_dp_tx The moved APIs will be a part of dp_tx.c file inside wifi7 directory. wifi7/dp_tx.c file will continue to be part of ath12k.ko temporarily until the corresponding infra for movement to ath12k_wifi7.ko arrives in upcoming patches. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Pavankumar Nandeshwar <quic_pnandesh@quicinc.com> Signed-off-by: Ripan Deuri <quic_rdeuri@quicinc.com> Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com> Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com> Link: https://patch.msgid.link/20250828173553.3341351-17-quic_rdeuri@quicinc.com Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
This commit is contained in:
parent
8527d81ee6
commit
a45d0e81b2
|
|
@ -109,26 +109,6 @@ struct ath12k_tx_desc_info *ath12k_dp_tx_assign_buffer(struct ath12k_dp *dp,
|
|||
return desc;
|
||||
}
|
||||
|
||||
static void ath12k_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab,
|
||||
struct hal_tx_msdu_ext_desc *tcl_ext_cmd,
|
||||
struct hal_tx_info *ti)
|
||||
{
|
||||
tcl_ext_cmd->info0 = le32_encode_bits(ti->paddr,
|
||||
HAL_TX_MSDU_EXT_INFO0_BUF_PTR_LO);
|
||||
tcl_ext_cmd->info1 = le32_encode_bits(0x0,
|
||||
HAL_TX_MSDU_EXT_INFO1_BUF_PTR_HI) |
|
||||
le32_encode_bits(ti->data_len,
|
||||
HAL_TX_MSDU_EXT_INFO1_BUF_LEN);
|
||||
|
||||
tcl_ext_cmd->info1 |= le32_encode_bits(1, HAL_TX_MSDU_EXT_INFO1_EXTN_OVERRIDE) |
|
||||
le32_encode_bits(ti->encap_type,
|
||||
HAL_TX_MSDU_EXT_INFO1_ENCAP_TYPE) |
|
||||
le32_encode_bits(ti->encrypt_type,
|
||||
HAL_TX_MSDU_EXT_INFO1_ENCRYPT_TYPE);
|
||||
}
|
||||
|
||||
#define HTT_META_DATA_ALIGNMENT 0x8
|
||||
|
||||
void *ath12k_dp_metadata_align_skb(struct sk_buff *skb, u8 tail_len)
|
||||
{
|
||||
struct sk_buff *tail;
|
||||
|
|
@ -142,29 +122,6 @@ void *ath12k_dp_metadata_align_skb(struct sk_buff *skb, u8 tail_len)
|
|||
return metadata;
|
||||
}
|
||||
|
||||
/* Preparing HTT Metadata when utilized with ext MSDU */
|
||||
static int ath12k_dp_prepare_htt_metadata(struct sk_buff *skb)
|
||||
{
|
||||
struct hal_tx_msdu_metadata *desc_ext;
|
||||
u8 htt_desc_size;
|
||||
/* Size rounded of multiple of 8 bytes */
|
||||
u8 htt_desc_size_aligned;
|
||||
|
||||
htt_desc_size = sizeof(struct hal_tx_msdu_metadata);
|
||||
htt_desc_size_aligned = ALIGN(htt_desc_size, HTT_META_DATA_ALIGNMENT);
|
||||
|
||||
desc_ext = ath12k_dp_metadata_align_skb(skb, htt_desc_size_aligned);
|
||||
if (!desc_ext)
|
||||
return -ENOMEM;
|
||||
|
||||
desc_ext->info0 = le32_encode_bits(1, HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_FLAG) |
|
||||
le32_encode_bits(0, HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_TYPE) |
|
||||
le32_encode_bits(1,
|
||||
HAL_TX_MSDU_METADATA_INFO0_HOST_TX_DESC_POOL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath12k_dp_tx_move_payload(struct sk_buff *skb,
|
||||
unsigned long delta,
|
||||
bool head)
|
||||
|
|
@ -219,326 +176,6 @@ int ath12k_dp_tx_align_payload(struct ath12k_base *ab,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
|
||||
struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
|
||||
bool is_mcast)
|
||||
{
|
||||
struct ath12k_base *ab = ar->ab;
|
||||
struct ath12k_dp *dp = &ab->dp;
|
||||
struct hal_tx_info ti = {};
|
||||
struct ath12k_tx_desc_info *tx_desc;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb);
|
||||
struct hal_tcl_data_cmd *hal_tcl_desc;
|
||||
struct hal_tx_msdu_ext_desc *msg;
|
||||
struct sk_buff *skb_ext_desc = NULL;
|
||||
struct hal_srng *tcl_ring;
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct ath12k_vif *ahvif = arvif->ahvif;
|
||||
struct dp_tx_ring *tx_ring;
|
||||
u8 pool_id;
|
||||
u8 hal_ring_id;
|
||||
int ret;
|
||||
u8 ring_selector, ring_map = 0;
|
||||
bool tcl_ring_retry;
|
||||
bool msdu_ext_desc = false;
|
||||
bool add_htt_metadata = false;
|
||||
u32 iova_mask = ab->hw_params->iova_mask;
|
||||
bool is_diff_encap = false;
|
||||
bool is_null_frame = false;
|
||||
|
||||
if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
|
||||
return -ESHUTDOWN;
|
||||
|
||||
if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
|
||||
!ieee80211_is_data(hdr->frame_control))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
pool_id = skb_get_queue_mapping(skb) & (ATH12K_HW_MAX_QUEUES - 1);
|
||||
|
||||
/* Let the default ring selection be based on current processor
|
||||
* number, where one of the 3 tcl rings are selected based on
|
||||
* the smp_processor_id(). In case that ring
|
||||
* is full/busy, we resort to other available rings.
|
||||
* If all rings are full, we drop the packet.
|
||||
* TODO: Add throttling logic when all rings are full
|
||||
*/
|
||||
ring_selector = ab->hw_params->hw_ops->get_ring_selector(skb);
|
||||
|
||||
tcl_ring_sel:
|
||||
tcl_ring_retry = false;
|
||||
ti.ring_id = ring_selector % ab->hw_params->max_tx_ring;
|
||||
|
||||
ring_map |= BIT(ti.ring_id);
|
||||
ti.rbm_id = ab->hw_params->hal_ops->tcl_to_wbm_rbm_map[ti.ring_id].rbm_id;
|
||||
|
||||
tx_ring = &dp->tx_ring[ti.ring_id];
|
||||
|
||||
tx_desc = ath12k_dp_tx_assign_buffer(dp, pool_id);
|
||||
if (!tx_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
ti.bank_id = arvif->bank_id;
|
||||
ti.meta_data_flags = arvif->tcl_metadata;
|
||||
|
||||
if (ahvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
|
||||
test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) {
|
||||
if (skb_cb->flags & ATH12K_SKB_CIPHER_SET) {
|
||||
ti.encrypt_type =
|
||||
ath12k_dp_tx_get_encrypt_type(skb_cb->cipher);
|
||||
|
||||
if (ieee80211_has_protected(hdr->frame_control))
|
||||
skb_put(skb, IEEE80211_CCMP_MIC_LEN);
|
||||
} else {
|
||||
ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN;
|
||||
}
|
||||
|
||||
msdu_ext_desc = true;
|
||||
}
|
||||
|
||||
if (gsn_valid) {
|
||||
/* Reset and Initialize meta_data_flags with Global Sequence
|
||||
* Number (GSN) info.
|
||||
*/
|
||||
ti.meta_data_flags =
|
||||
u32_encode_bits(HTT_TCL_META_DATA_TYPE_GLOBAL_SEQ_NUM,
|
||||
HTT_TCL_META_DATA_TYPE) |
|
||||
u32_encode_bits(mcbc_gsn, HTT_TCL_META_DATA_GLOBAL_SEQ_NUM);
|
||||
}
|
||||
|
||||
ti.encap_type = ath12k_dp_tx_get_encap_type(ab, skb);
|
||||
ti.addr_search_flags = arvif->hal_addr_search_flags;
|
||||
ti.search_type = arvif->search_type;
|
||||
ti.type = HAL_TCL_DESC_TYPE_BUFFER;
|
||||
ti.pkt_offset = 0;
|
||||
ti.lmac_id = ar->lmac_id;
|
||||
|
||||
ti.vdev_id = arvif->vdev_id;
|
||||
if (gsn_valid)
|
||||
ti.vdev_id += HTT_TX_MLO_MCAST_HOST_REINJECT_BASE_VDEV_ID;
|
||||
|
||||
ti.bss_ast_hash = arvif->ast_hash;
|
||||
ti.bss_ast_idx = arvif->ast_idx;
|
||||
ti.dscp_tid_tbl_idx = 0;
|
||||
|
||||
if (skb->ip_summed == CHECKSUM_PARTIAL &&
|
||||
ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW) {
|
||||
ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_IP4_CKSUM_EN) |
|
||||
u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_UDP4_CKSUM_EN) |
|
||||
u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_UDP6_CKSUM_EN) |
|
||||
u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TCP4_CKSUM_EN) |
|
||||
u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TCP6_CKSUM_EN);
|
||||
}
|
||||
|
||||
ti.flags1 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO3_TID_OVERWRITE);
|
||||
|
||||
ti.tid = ath12k_dp_tx_get_tid(skb);
|
||||
|
||||
switch (ti.encap_type) {
|
||||
case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI:
|
||||
is_null_frame = ieee80211_is_nullfunc(hdr->frame_control);
|
||||
if (ahvif->vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) {
|
||||
if (skb->protocol == cpu_to_be16(ETH_P_PAE) || is_null_frame)
|
||||
is_diff_encap = true;
|
||||
|
||||
/* Firmware expects msdu ext descriptor for nwifi/raw packets
|
||||
* received in ETH mode. Without this, observed tx fail for
|
||||
* Multicast packets in ETH mode.
|
||||
*/
|
||||
msdu_ext_desc = true;
|
||||
} else {
|
||||
ath12k_dp_tx_encap_nwifi(skb);
|
||||
}
|
||||
break;
|
||||
case HAL_TCL_ENCAP_TYPE_RAW:
|
||||
if (!test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) {
|
||||
ret = -EINVAL;
|
||||
goto fail_remove_tx_buf;
|
||||
}
|
||||
break;
|
||||
case HAL_TCL_ENCAP_TYPE_ETHERNET:
|
||||
/* no need to encap */
|
||||
break;
|
||||
case HAL_TCL_ENCAP_TYPE_802_3:
|
||||
default:
|
||||
/* TODO: Take care of other encap modes as well */
|
||||
ret = -EINVAL;
|
||||
atomic_inc(&ab->device_stats.tx_err.misc_fail);
|
||||
goto fail_remove_tx_buf;
|
||||
}
|
||||
|
||||
if (iova_mask &&
|
||||
(unsigned long)skb->data & iova_mask) {
|
||||
ret = ath12k_dp_tx_align_payload(ab, &skb);
|
||||
if (ret) {
|
||||
ath12k_warn(ab, "failed to align TX buffer %d\n", ret);
|
||||
/* don't bail out, give original buffer
|
||||
* a chance even unaligned.
|
||||
*/
|
||||
goto map;
|
||||
}
|
||||
|
||||
/* hdr is pointing to a wrong place after alignment,
|
||||
* so refresh it for later use.
|
||||
*/
|
||||
hdr = (void *)skb->data;
|
||||
}
|
||||
map:
|
||||
ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(ab->dev, ti.paddr)) {
|
||||
atomic_inc(&ab->device_stats.tx_err.misc_fail);
|
||||
ath12k_warn(ab, "failed to DMA map data Tx buffer\n");
|
||||
ret = -ENOMEM;
|
||||
goto fail_remove_tx_buf;
|
||||
}
|
||||
|
||||
if ((!test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags) &&
|
||||
!(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) &&
|
||||
!(skb_cb->flags & ATH12K_SKB_CIPHER_SET) &&
|
||||
ieee80211_has_protected(hdr->frame_control)) ||
|
||||
is_diff_encap) {
|
||||
/* Firmware is not expecting meta data for qos null
|
||||
* nwifi packet received in ETH encap mode.
|
||||
*/
|
||||
if (is_null_frame && msdu_ext_desc)
|
||||
goto skip_htt_meta;
|
||||
|
||||
/* Add metadata for sw encrypted vlan group traffic
|
||||
* and EAPOL nwifi packet received in ETH encap mode.
|
||||
*/
|
||||
add_htt_metadata = true;
|
||||
msdu_ext_desc = true;
|
||||
ti.meta_data_flags |= HTT_TCL_META_DATA_VALID_HTT;
|
||||
skip_htt_meta:
|
||||
ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW);
|
||||
ti.encap_type = HAL_TCL_ENCAP_TYPE_RAW;
|
||||
ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN;
|
||||
}
|
||||
|
||||
tx_desc->skb = skb;
|
||||
tx_desc->mac_id = ar->pdev_idx;
|
||||
ti.desc_id = tx_desc->desc_id;
|
||||
ti.data_len = skb->len;
|
||||
skb_cb->paddr = ti.paddr;
|
||||
skb_cb->vif = ahvif->vif;
|
||||
skb_cb->ar = ar;
|
||||
|
||||
if (msdu_ext_desc) {
|
||||
skb_ext_desc = dev_alloc_skb(sizeof(struct hal_tx_msdu_ext_desc));
|
||||
if (!skb_ext_desc) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_unmap_dma;
|
||||
}
|
||||
|
||||
skb_put(skb_ext_desc, sizeof(struct hal_tx_msdu_ext_desc));
|
||||
memset(skb_ext_desc->data, 0, skb_ext_desc->len);
|
||||
|
||||
msg = (struct hal_tx_msdu_ext_desc *)skb_ext_desc->data;
|
||||
ath12k_hal_tx_cmd_ext_desc_setup(ab, msg, &ti);
|
||||
|
||||
if (add_htt_metadata) {
|
||||
ret = ath12k_dp_prepare_htt_metadata(skb_ext_desc);
|
||||
if (ret < 0) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_DP_TX,
|
||||
"Failed to add HTT meta data, dropping packet\n");
|
||||
goto fail_free_ext_skb;
|
||||
}
|
||||
}
|
||||
|
||||
ti.paddr = dma_map_single(ab->dev, skb_ext_desc->data,
|
||||
skb_ext_desc->len, DMA_TO_DEVICE);
|
||||
ret = dma_mapping_error(ab->dev, ti.paddr);
|
||||
if (ret)
|
||||
goto fail_free_ext_skb;
|
||||
|
||||
ti.data_len = skb_ext_desc->len;
|
||||
ti.type = HAL_TCL_DESC_TYPE_EXT_DESC;
|
||||
|
||||
skb_cb->paddr_ext_desc = ti.paddr;
|
||||
tx_desc->skb_ext_desc = skb_ext_desc;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
ath12k_hal_srng_access_begin(ab, tcl_ring);
|
||||
|
||||
hal_tcl_desc = ath12k_hal_srng_src_get_next_entry(ab, tcl_ring);
|
||||
if (!hal_tcl_desc) {
|
||||
/* NOTE: It is highly unlikely we'll be running out of tcl_ring
|
||||
* desc because the desc is directly enqueued onto hw queue.
|
||||
*/
|
||||
ath12k_hal_srng_access_end(ab, tcl_ring);
|
||||
ab->device_stats.tx_err.desc_na[ti.ring_id]++;
|
||||
spin_unlock_bh(&tcl_ring->lock);
|
||||
ret = -ENOMEM;
|
||||
|
||||
/* Checking for available tcl descriptors in another ring in
|
||||
* case of failure due to full tcl ring now, is better than
|
||||
* checking this ring earlier for each pkt tx.
|
||||
* Restart ring selection if some rings are not checked yet.
|
||||
*/
|
||||
if (ring_map != (BIT(ab->hw_params->max_tx_ring) - 1) &&
|
||||
ab->hw_params->tcl_ring_retry) {
|
||||
tcl_ring_retry = true;
|
||||
ring_selector++;
|
||||
}
|
||||
|
||||
goto fail_unmap_dma_ext;
|
||||
}
|
||||
|
||||
spin_lock_bh(&arvif->link_stats_lock);
|
||||
arvif->link_stats.tx_encap_type[ti.encap_type]++;
|
||||
arvif->link_stats.tx_encrypt_type[ti.encrypt_type]++;
|
||||
arvif->link_stats.tx_desc_type[ti.type]++;
|
||||
|
||||
if (is_mcast)
|
||||
arvif->link_stats.tx_bcast_mcast++;
|
||||
else
|
||||
arvif->link_stats.tx_enqueued++;
|
||||
spin_unlock_bh(&arvif->link_stats_lock);
|
||||
|
||||
ab->device_stats.tx_enqueued[ti.ring_id]++;
|
||||
|
||||
ath12k_hal_tx_cmd_desc_setup(ab, hal_tcl_desc, &ti);
|
||||
|
||||
ath12k_hal_srng_access_end(ab, tcl_ring);
|
||||
|
||||
spin_unlock_bh(&tcl_ring->lock);
|
||||
|
||||
ath12k_dbg_dump(ab, ATH12K_DBG_DP_TX, NULL, "dp tx msdu: ",
|
||||
skb->data, skb->len);
|
||||
|
||||
atomic_inc(&ar->dp.num_tx_pending);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_unmap_dma_ext:
|
||||
if (skb_cb->paddr_ext_desc)
|
||||
dma_unmap_single(ab->dev, skb_cb->paddr_ext_desc,
|
||||
skb_ext_desc->len,
|
||||
DMA_TO_DEVICE);
|
||||
fail_free_ext_skb:
|
||||
kfree_skb(skb_ext_desc);
|
||||
|
||||
fail_unmap_dma:
|
||||
dma_unmap_single(ab->dev, ti.paddr, ti.data_len, DMA_TO_DEVICE);
|
||||
|
||||
fail_remove_tx_buf:
|
||||
ath12k_dp_tx_release_txbuf(dp, tx_desc, pool_id);
|
||||
|
||||
spin_lock_bh(&arvif->link_stats_lock);
|
||||
arvif->link_stats.tx_dropped++;
|
||||
spin_unlock_bh(&arvif->link_stats_lock);
|
||||
|
||||
if (tcl_ring_retry)
|
||||
goto tcl_ring_sel;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ath12k_dp_tx_free_txbuf(struct ath12k_base *ab,
|
||||
struct dp_tx_ring *tx_ring,
|
||||
struct ath12k_tx_desc_params *desc_params)
|
||||
|
|
|
|||
|
|
@ -16,9 +16,6 @@ struct ath12k_dp_htt_wbm_tx_status {
|
|||
};
|
||||
|
||||
int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab);
|
||||
int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
|
||||
struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
|
||||
bool is_mcast);
|
||||
int ath12k_dp_tx_htt_h2t_ppdu_stats_req(struct ath12k *ar, u32 mask);
|
||||
int
|
||||
ath12k_dp_tx_htt_h2t_ext_stats_req(struct ath12k *ar, u8 type,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,369 @@
|
|||
#include "../peer.h"
|
||||
#include "dp_tx.h"
|
||||
|
||||
static void ath12k_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab,
|
||||
struct hal_tx_msdu_ext_desc *tcl_ext_cmd,
|
||||
struct hal_tx_info *ti)
|
||||
{
|
||||
tcl_ext_cmd->info0 = le32_encode_bits(ti->paddr,
|
||||
HAL_TX_MSDU_EXT_INFO0_BUF_PTR_LO);
|
||||
tcl_ext_cmd->info1 = le32_encode_bits(0x0,
|
||||
HAL_TX_MSDU_EXT_INFO1_BUF_PTR_HI) |
|
||||
le32_encode_bits(ti->data_len,
|
||||
HAL_TX_MSDU_EXT_INFO1_BUF_LEN);
|
||||
|
||||
tcl_ext_cmd->info1 |= le32_encode_bits(1, HAL_TX_MSDU_EXT_INFO1_EXTN_OVERRIDE) |
|
||||
le32_encode_bits(ti->encap_type,
|
||||
HAL_TX_MSDU_EXT_INFO1_ENCAP_TYPE) |
|
||||
le32_encode_bits(ti->encrypt_type,
|
||||
HAL_TX_MSDU_EXT_INFO1_ENCRYPT_TYPE);
|
||||
}
|
||||
|
||||
#define HTT_META_DATA_ALIGNMENT 0x8
|
||||
|
||||
/* Preparing HTT Metadata when utilized with ext MSDU */
|
||||
static int ath12k_dp_prepare_htt_metadata(struct sk_buff *skb)
|
||||
{
|
||||
struct hal_tx_msdu_metadata *desc_ext;
|
||||
u8 htt_desc_size;
|
||||
/* Size rounded of multiple of 8 bytes */
|
||||
u8 htt_desc_size_aligned;
|
||||
|
||||
htt_desc_size = sizeof(struct hal_tx_msdu_metadata);
|
||||
htt_desc_size_aligned = ALIGN(htt_desc_size, HTT_META_DATA_ALIGNMENT);
|
||||
|
||||
desc_ext = ath12k_dp_metadata_align_skb(skb, htt_desc_size_aligned);
|
||||
if (!desc_ext)
|
||||
return -ENOMEM;
|
||||
|
||||
desc_ext->info0 = le32_encode_bits(1, HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_FLAG) |
|
||||
le32_encode_bits(0, HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_TYPE) |
|
||||
le32_encode_bits(1,
|
||||
HAL_TX_MSDU_METADATA_INFO0_HOST_TX_DESC_POOL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
|
||||
struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
|
||||
bool is_mcast)
|
||||
{
|
||||
struct ath12k_base *ab = ar->ab;
|
||||
struct ath12k_dp *dp = &ab->dp;
|
||||
struct hal_tx_info ti = {};
|
||||
struct ath12k_tx_desc_info *tx_desc;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb);
|
||||
struct hal_tcl_data_cmd *hal_tcl_desc;
|
||||
struct hal_tx_msdu_ext_desc *msg;
|
||||
struct sk_buff *skb_ext_desc = NULL;
|
||||
struct hal_srng *tcl_ring;
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct ath12k_vif *ahvif = arvif->ahvif;
|
||||
struct dp_tx_ring *tx_ring;
|
||||
u8 pool_id;
|
||||
u8 hal_ring_id;
|
||||
int ret;
|
||||
u8 ring_selector, ring_map = 0;
|
||||
bool tcl_ring_retry;
|
||||
bool msdu_ext_desc = false;
|
||||
bool add_htt_metadata = false;
|
||||
u32 iova_mask = ab->hw_params->iova_mask;
|
||||
bool is_diff_encap = false;
|
||||
bool is_null_frame = false;
|
||||
|
||||
if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
|
||||
return -ESHUTDOWN;
|
||||
|
||||
if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
|
||||
!ieee80211_is_data(hdr->frame_control))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
pool_id = skb_get_queue_mapping(skb) & (ATH12K_HW_MAX_QUEUES - 1);
|
||||
|
||||
/* Let the default ring selection be based on current processor
|
||||
* number, where one of the 3 tcl rings are selected based on
|
||||
* the smp_processor_id(). In case that ring
|
||||
* is full/busy, we resort to other available rings.
|
||||
* If all rings are full, we drop the packet.
|
||||
* TODO: Add throttling logic when all rings are full
|
||||
*/
|
||||
ring_selector = ab->hw_params->hw_ops->get_ring_selector(skb);
|
||||
|
||||
tcl_ring_sel:
|
||||
tcl_ring_retry = false;
|
||||
ti.ring_id = ring_selector % ab->hw_params->max_tx_ring;
|
||||
|
||||
ring_map |= BIT(ti.ring_id);
|
||||
ti.rbm_id = ab->hw_params->hal_ops->tcl_to_wbm_rbm_map[ti.ring_id].rbm_id;
|
||||
|
||||
tx_ring = &dp->tx_ring[ti.ring_id];
|
||||
|
||||
tx_desc = ath12k_dp_tx_assign_buffer(dp, pool_id);
|
||||
if (!tx_desc)
|
||||
return -ENOMEM;
|
||||
|
||||
ti.bank_id = arvif->bank_id;
|
||||
ti.meta_data_flags = arvif->tcl_metadata;
|
||||
|
||||
if (ahvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
|
||||
test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) {
|
||||
if (skb_cb->flags & ATH12K_SKB_CIPHER_SET) {
|
||||
ti.encrypt_type =
|
||||
ath12k_dp_tx_get_encrypt_type(skb_cb->cipher);
|
||||
|
||||
if (ieee80211_has_protected(hdr->frame_control))
|
||||
skb_put(skb, IEEE80211_CCMP_MIC_LEN);
|
||||
} else {
|
||||
ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN;
|
||||
}
|
||||
|
||||
msdu_ext_desc = true;
|
||||
}
|
||||
|
||||
if (gsn_valid) {
|
||||
/* Reset and Initialize meta_data_flags with Global Sequence
|
||||
* Number (GSN) info.
|
||||
*/
|
||||
ti.meta_data_flags =
|
||||
u32_encode_bits(HTT_TCL_META_DATA_TYPE_GLOBAL_SEQ_NUM,
|
||||
HTT_TCL_META_DATA_TYPE) |
|
||||
u32_encode_bits(mcbc_gsn, HTT_TCL_META_DATA_GLOBAL_SEQ_NUM);
|
||||
}
|
||||
|
||||
ti.encap_type = ath12k_dp_tx_get_encap_type(ab, skb);
|
||||
ti.addr_search_flags = arvif->hal_addr_search_flags;
|
||||
ti.search_type = arvif->search_type;
|
||||
ti.type = HAL_TCL_DESC_TYPE_BUFFER;
|
||||
ti.pkt_offset = 0;
|
||||
ti.lmac_id = ar->lmac_id;
|
||||
|
||||
ti.vdev_id = arvif->vdev_id;
|
||||
if (gsn_valid)
|
||||
ti.vdev_id += HTT_TX_MLO_MCAST_HOST_REINJECT_BASE_VDEV_ID;
|
||||
|
||||
ti.bss_ast_hash = arvif->ast_hash;
|
||||
ti.bss_ast_idx = arvif->ast_idx;
|
||||
ti.dscp_tid_tbl_idx = 0;
|
||||
|
||||
if (skb->ip_summed == CHECKSUM_PARTIAL &&
|
||||
ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW) {
|
||||
ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_IP4_CKSUM_EN) |
|
||||
u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_UDP4_CKSUM_EN) |
|
||||
u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_UDP6_CKSUM_EN) |
|
||||
u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TCP4_CKSUM_EN) |
|
||||
u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TCP6_CKSUM_EN);
|
||||
}
|
||||
|
||||
ti.flags1 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO3_TID_OVERWRITE);
|
||||
|
||||
ti.tid = ath12k_dp_tx_get_tid(skb);
|
||||
|
||||
switch (ti.encap_type) {
|
||||
case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI:
|
||||
is_null_frame = ieee80211_is_nullfunc(hdr->frame_control);
|
||||
if (ahvif->vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) {
|
||||
if (skb->protocol == cpu_to_be16(ETH_P_PAE) || is_null_frame)
|
||||
is_diff_encap = true;
|
||||
|
||||
/* Firmware expects msdu ext descriptor for nwifi/raw packets
|
||||
* received in ETH mode. Without this, observed tx fail for
|
||||
* Multicast packets in ETH mode.
|
||||
*/
|
||||
msdu_ext_desc = true;
|
||||
} else {
|
||||
ath12k_dp_tx_encap_nwifi(skb);
|
||||
}
|
||||
break;
|
||||
case HAL_TCL_ENCAP_TYPE_RAW:
|
||||
if (!test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) {
|
||||
ret = -EINVAL;
|
||||
goto fail_remove_tx_buf;
|
||||
}
|
||||
break;
|
||||
case HAL_TCL_ENCAP_TYPE_ETHERNET:
|
||||
/* no need to encap */
|
||||
break;
|
||||
case HAL_TCL_ENCAP_TYPE_802_3:
|
||||
default:
|
||||
/* TODO: Take care of other encap modes as well */
|
||||
ret = -EINVAL;
|
||||
atomic_inc(&ab->device_stats.tx_err.misc_fail);
|
||||
goto fail_remove_tx_buf;
|
||||
}
|
||||
|
||||
if (iova_mask &&
|
||||
(unsigned long)skb->data & iova_mask) {
|
||||
ret = ath12k_dp_tx_align_payload(ab, &skb);
|
||||
if (ret) {
|
||||
ath12k_warn(ab, "failed to align TX buffer %d\n", ret);
|
||||
/* don't bail out, give original buffer
|
||||
* a chance even unaligned.
|
||||
*/
|
||||
goto map;
|
||||
}
|
||||
|
||||
/* hdr is pointing to a wrong place after alignment,
|
||||
* so refresh it for later use.
|
||||
*/
|
||||
hdr = (void *)skb->data;
|
||||
}
|
||||
map:
|
||||
ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(ab->dev, ti.paddr)) {
|
||||
atomic_inc(&ab->device_stats.tx_err.misc_fail);
|
||||
ath12k_warn(ab, "failed to DMA map data Tx buffer\n");
|
||||
ret = -ENOMEM;
|
||||
goto fail_remove_tx_buf;
|
||||
}
|
||||
|
||||
if ((!test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags) &&
|
||||
!(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) &&
|
||||
!(skb_cb->flags & ATH12K_SKB_CIPHER_SET) &&
|
||||
ieee80211_has_protected(hdr->frame_control)) ||
|
||||
is_diff_encap) {
|
||||
/* Firmware is not expecting meta data for qos null
|
||||
* nwifi packet received in ETH encap mode.
|
||||
*/
|
||||
if (is_null_frame && msdu_ext_desc)
|
||||
goto skip_htt_meta;
|
||||
|
||||
/* Add metadata for sw encrypted vlan group traffic
|
||||
* and EAPOL nwifi packet received in ETH encap mode.
|
||||
*/
|
||||
add_htt_metadata = true;
|
||||
msdu_ext_desc = true;
|
||||
ti.meta_data_flags |= HTT_TCL_META_DATA_VALID_HTT;
|
||||
skip_htt_meta:
|
||||
ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW);
|
||||
ti.encap_type = HAL_TCL_ENCAP_TYPE_RAW;
|
||||
ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN;
|
||||
}
|
||||
|
||||
tx_desc->skb = skb;
|
||||
tx_desc->mac_id = ar->pdev_idx;
|
||||
ti.desc_id = tx_desc->desc_id;
|
||||
ti.data_len = skb->len;
|
||||
skb_cb->paddr = ti.paddr;
|
||||
skb_cb->vif = ahvif->vif;
|
||||
skb_cb->ar = ar;
|
||||
|
||||
if (msdu_ext_desc) {
|
||||
skb_ext_desc = dev_alloc_skb(sizeof(struct hal_tx_msdu_ext_desc));
|
||||
if (!skb_ext_desc) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_unmap_dma;
|
||||
}
|
||||
|
||||
skb_put(skb_ext_desc, sizeof(struct hal_tx_msdu_ext_desc));
|
||||
memset(skb_ext_desc->data, 0, skb_ext_desc->len);
|
||||
|
||||
msg = (struct hal_tx_msdu_ext_desc *)skb_ext_desc->data;
|
||||
ath12k_hal_tx_cmd_ext_desc_setup(ab, msg, &ti);
|
||||
|
||||
if (add_htt_metadata) {
|
||||
ret = ath12k_dp_prepare_htt_metadata(skb_ext_desc);
|
||||
if (ret < 0) {
|
||||
ath12k_dbg(ab, ATH12K_DBG_DP_TX,
|
||||
"Failed to add HTT meta data, dropping packet\n");
|
||||
goto fail_free_ext_skb;
|
||||
}
|
||||
}
|
||||
|
||||
ti.paddr = dma_map_single(ab->dev, skb_ext_desc->data,
|
||||
skb_ext_desc->len, DMA_TO_DEVICE);
|
||||
ret = dma_mapping_error(ab->dev, ti.paddr);
|
||||
if (ret)
|
||||
goto fail_free_ext_skb;
|
||||
|
||||
ti.data_len = skb_ext_desc->len;
|
||||
ti.type = HAL_TCL_DESC_TYPE_EXT_DESC;
|
||||
|
||||
skb_cb->paddr_ext_desc = ti.paddr;
|
||||
tx_desc->skb_ext_desc = skb_ext_desc;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
ath12k_hal_srng_access_begin(ab, tcl_ring);
|
||||
|
||||
hal_tcl_desc = ath12k_hal_srng_src_get_next_entry(ab, tcl_ring);
|
||||
if (!hal_tcl_desc) {
|
||||
/* NOTE: It is highly unlikely we'll be running out of tcl_ring
|
||||
* desc because the desc is directly enqueued onto hw queue.
|
||||
*/
|
||||
ath12k_hal_srng_access_end(ab, tcl_ring);
|
||||
ab->device_stats.tx_err.desc_na[ti.ring_id]++;
|
||||
spin_unlock_bh(&tcl_ring->lock);
|
||||
ret = -ENOMEM;
|
||||
|
||||
/* Checking for available tcl descriptors in another ring in
|
||||
* case of failure due to full tcl ring now, is better than
|
||||
* checking this ring earlier for each pkt tx.
|
||||
* Restart ring selection if some rings are not checked yet.
|
||||
*/
|
||||
if (ring_map != (BIT(ab->hw_params->max_tx_ring) - 1) &&
|
||||
ab->hw_params->tcl_ring_retry) {
|
||||
tcl_ring_retry = true;
|
||||
ring_selector++;
|
||||
}
|
||||
|
||||
goto fail_unmap_dma_ext;
|
||||
}
|
||||
|
||||
spin_lock_bh(&arvif->link_stats_lock);
|
||||
arvif->link_stats.tx_encap_type[ti.encap_type]++;
|
||||
arvif->link_stats.tx_encrypt_type[ti.encrypt_type]++;
|
||||
arvif->link_stats.tx_desc_type[ti.type]++;
|
||||
|
||||
if (is_mcast)
|
||||
arvif->link_stats.tx_bcast_mcast++;
|
||||
else
|
||||
arvif->link_stats.tx_enqueued++;
|
||||
spin_unlock_bh(&arvif->link_stats_lock);
|
||||
|
||||
ab->device_stats.tx_enqueued[ti.ring_id]++;
|
||||
|
||||
ath12k_hal_tx_cmd_desc_setup(ab, hal_tcl_desc, &ti);
|
||||
|
||||
ath12k_hal_srng_access_end(ab, tcl_ring);
|
||||
|
||||
spin_unlock_bh(&tcl_ring->lock);
|
||||
|
||||
ath12k_dbg_dump(ab, ATH12K_DBG_DP_TX, NULL, "dp tx msdu: ",
|
||||
skb->data, skb->len);
|
||||
|
||||
atomic_inc(&ar->dp.num_tx_pending);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_unmap_dma_ext:
|
||||
if (skb_cb->paddr_ext_desc)
|
||||
dma_unmap_single(ab->dev, skb_cb->paddr_ext_desc,
|
||||
skb_ext_desc->len,
|
||||
DMA_TO_DEVICE);
|
||||
fail_free_ext_skb:
|
||||
kfree_skb(skb_ext_desc);
|
||||
|
||||
fail_unmap_dma:
|
||||
dma_unmap_single(ab->dev, ti.paddr, ti.data_len, DMA_TO_DEVICE);
|
||||
|
||||
fail_remove_tx_buf:
|
||||
ath12k_dp_tx_release_txbuf(dp, tx_desc, pool_id);
|
||||
|
||||
spin_lock_bh(&arvif->link_stats_lock);
|
||||
arvif->link_stats.tx_dropped++;
|
||||
spin_unlock_bh(&arvif->link_stats_lock);
|
||||
|
||||
if (tcl_ring_retry)
|
||||
goto tcl_ring_sel;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab,
|
||||
struct ath12k_tx_desc_params *desc_params,
|
||||
|
|
|
|||
|
|
@ -7,5 +7,8 @@
|
|||
#ifndef ATH12K_DP_TX_WIFI7_H
|
||||
#define ATH12K_DP_TX_WIFI7_H
|
||||
|
||||
int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
|
||||
struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
|
||||
bool is_mcast);
|
||||
void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id);
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user