wifi: ath12k: Advertise multicast Ethernet encapsulation offload support

Advertise IEEE80211_OFFLOAD_ENCAP_MCAST to inform mac80211 that
multicast frame encapsulation is handled in hardware. This allows
mac80211 to pass Ethernet-formatted multicast frames directly to
the driver.

In ath12k_wifi7_mac_op_tx(), refine the logic that selects the MLO
multicast replication path. Add a sta pointer check so that only unicast
Hardware-encap frames use the direct transmit path, while multicast
Hardware-encap frames fall through to the MLO replication loop and are
transmitted on each active link.

In the MLO replication loop, use skb_clone() for Hardware-encap frames.
These frames are already in Ethernet format and do not require
802.11 link address rewriting by ath12k_mlo_mcast_update_tx_link_address().

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1

Signed-off-by: Tamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Link: https://patch.msgid.link/20260623100501.2100119-1-tamizh.raja@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
This commit is contained in:
Tamizh Chelvam Raja
2026-06-23 15:35:01 +05:30
committed by Jeff Johnson
parent 784f7dabf5
commit e47d6c9bb4
2 changed files with 53 additions and 14 deletions

View File

@@ -10117,7 +10117,8 @@ static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif)
if (vif->type != NL80211_IFTYPE_STATION &&
vif->type != NL80211_IFTYPE_AP)
vif->offload_flags &= ~(IEEE80211_OFFLOAD_ENCAP_ENABLED |
IEEE80211_OFFLOAD_DECAP_ENABLED);
IEEE80211_OFFLOAD_DECAP_ENABLED |
IEEE80211_OFFLOAD_ENCAP_MCAST);
if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) {
ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_ETHERNET;
@@ -10136,6 +10137,9 @@ static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif)
vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
}
if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_MCAST;
param_id = WMI_VDEV_PARAM_RX_DECAP_TYPE;
if (vif->offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED)
param_value = ATH12K_HW_TXRX_ETHERNET;

View File

@@ -903,6 +903,7 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
struct ethhdr *eth;
bool is_prb_rsp;
u16 mcbc_gsn;
u8 cb_flags;
u8 link_id;
int ret;
struct ath12k_dp *tmp_dp;
@@ -996,8 +997,13 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
ieee80211_has_protected(hdr->frame_control))
is_dvlan = true;
/*
* Add a sta pointer check to differentiate multicast encapsulation
* offload packets, as the ATH12K_SKB_HW_80211_ENCAP flag is also set
* for such packets.
*/
if (!vif->valid_links || !is_mcast || is_dvlan ||
(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) ||
((skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) && sta) ||
test_bit(ATH12K_FLAG_RAW_MODE, &ar->ab->dev_flags)) {
ret = ath12k_wifi7_dp_tx(dp_pdev, arvif, arsta, skb, false, 0, is_mcast);
if (unlikely(ret)) {
@@ -1009,6 +1015,7 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
mcbc_gsn = atomic_inc_return(&ahvif->dp_vif.mcbc_gsn) & 0xfff;
links_map = ahvif->links_map;
cb_flags = skb_cb->flags;
for_each_set_bit(link_id, &links_map,
IEEE80211_MLD_MAX_NUM_LINKS) {
tmp_arvif = rcu_dereference(ahvif->link[link_id]);
@@ -1016,21 +1023,45 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
continue;
tmp_ar = tmp_arvif->ar;
tmp_dp_pdev = ath12k_dp_to_pdev_dp(tmp_ar->ab->dp,
tmp_dp = ath12k_ab_to_dp(tmp_ar->ab);
tmp_dp_pdev = ath12k_dp_to_pdev_dp(tmp_dp,
tmp_ar->pdev_idx);
if (!tmp_dp_pdev)
continue;
msdu_copied = skb_copy(skb, GFP_ATOMIC);
if (!msdu_copied) {
ath12k_err(ar->ab,
"skb copy failure link_id 0x%X vdevid 0x%X\n",
link_id, tmp_arvif->vdev_id);
continue;
}
ath12k_mlo_mcast_update_tx_link_address(vif, link_id,
msdu_copied,
info_flags);
if (cb_flags & ATH12K_SKB_HW_80211_ENCAP) {
/*
* skb->data may be modified for the iova_mask devices.
* It is better to use skb_copy() for such devices
* to avoid any potential skb corruption related issues.
*/
if (tmp_dp->hw_params->iova_mask)
msdu_copied = skb_copy(skb, GFP_ATOMIC);
else
/*
* ath12k_wifi7_dp_tx() should treat cloned HW-encap
* Ethernet multicast frames as read-only.
*/
msdu_copied = skb_clone(skb, GFP_ATOMIC);
if (!msdu_copied) {
ath12k_err(ar->ab,
"skb copy/clone failure link_id 0x%X vdevid 0x%X\n",
link_id, tmp_arvif->vdev_id);
continue;
}
} else {
msdu_copied = skb_copy(skb, GFP_ATOMIC);
if (!msdu_copied) {
ath12k_err(ar->ab,
"skb copy failure link_id 0x%X vdevid 0x%X\n",
link_id, tmp_arvif->vdev_id);
continue;
}
ath12k_mlo_mcast_update_tx_link_address(vif, link_id,
msdu_copied,
info_flags);
}
skb_cb = ATH12K_SKB_CB(msdu_copied);
skb_cb->link_id = link_id;
@@ -1046,7 +1077,6 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
if (unlikely(!ahvif->dp_vif.key_cipher))
goto skip_peer_find;
tmp_dp = ath12k_ab_to_dp(tmp_ar->ab);
spin_lock_bh(&tmp_dp->dp_lock);
peer = ath12k_dp_link_peer_find_by_addr(tmp_dp,
tmp_arvif->bssid);
@@ -1065,11 +1095,16 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
skb_cb->cipher = key->cipher;
skb_cb->flags |= ATH12K_SKB_CIPHER_SET;
if (skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP)
goto skip_fctl_protected_check;
hdr = (struct ieee80211_hdr *)msdu_copied->data;
if (!ieee80211_has_protected(hdr->frame_control))
hdr->frame_control |=
cpu_to_le16(IEEE80211_FCTL_PROTECTED);
}
skip_fctl_protected_check:
spin_unlock_bh(&tmp_dp->dp_lock);
skip_peer_find: