[PATCH ath-next] wifi: ath12k: Advertise multicast Ethernet encapsulation offload support
Tamizh Chelvam Raja
tamizh.raja at oss.qualcomm.com
Tue Jun 23 03:05:01 PDT 2026
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 at oss.qualcomm.com>
---
drivers/net/wireless/ath/ath12k/mac.c | 6 ++-
drivers/net/wireless/ath/ath12k/wifi7/hw.c | 61 +++++++++++++++++-----
2 files changed, 53 insertions(+), 14 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index af354bef5c0d..26b46a404580 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -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;
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hw.c b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
index 3d59fa452ec0..e5bf9d218104 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hw.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hw.c
@@ -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:
base-commit: 972c4dd19cb92e03d75b66c426cfade07582a1ba
--
2.34.1
More information about the ath12k
mailing list