[PATCH ath-next 3/6] wifi: ath12k: Add 4-address mode support for eth offload
Tamizh Chelvam Raja
tamizh.raja at oss.qualcomm.com
Mon May 25 04:09:39 PDT 2026
Currently driver does not enable the hardware/firmware support for handling
4-address multicast frames in the Tx/Rx path when 8023_ENCAP_OFFLOAD is
enabled. Add the required support to ensure correct processing of multicast
traffic in 4-address mode.
Enable this functionality by setting the WMI_VDEV_PARAM_AP_ENABLE_NAWDS
vdev parameter when the 8023_ENCAP_OFFLOAD feature is active. Override
peer metadata values for 4-address multicast packet transmission by using
the station's ast_hash and ast_idx instead of vdev-level metadata,
and set HAL_TCL_DATA_CMD_INFO4_IDX_LOOKUP_OVERRIDE to indicate this
override.
Suppress firmware peer-map events for 4-address frames by setting the
WMI_RSRC_CFG_FLAGS2_FW_AST_INDICATION_DISABLE flag during WMI
initialization. This prevents inconsistencies in the host's peer list.
Add the IEEE80211_OFFLOAD_ENCAP_4ADDR VIF offload flag to notify mac80211
that 4-address Ethernet encapsulation offload is supported.
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/core.h | 3 ++
drivers/net/wireless/ath/ath12k/mac.c | 28 ++++++++++++---
drivers/net/wireless/ath/ath12k/peer.c | 2 ++
drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c | 35 +++++++++++++++----
.../net/wireless/ath/ath12k/wifi7/hal_tx.c | 4 ++-
.../net/wireless/ath/ath12k/wifi7/hal_tx.h | 1 +
drivers/net/wireless/ath/ath12k/wmi.c | 3 +-
drivers/net/wireless/ath/ath12k/wmi.h | 9 +++++
8 files changed, 72 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 70ad9742c21d..fc5127b5c1a3 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -355,6 +355,7 @@ struct ath12k_link_vif {
struct wiphy_work bcn_tx_work;
bool set_wds_vdev_param;
+ bool nawds_enabled;
};
struct ath12k_vif {
@@ -495,6 +496,8 @@ struct ath12k_link_sta {
u8 addr[ETH_ALEN];
u16 tcl_metadata;
+ u16 ast_hash;
+ u16 ast_idx;
/* the following are protected by ar->data_lock */
u32 changed; /* IEEE80211_RC_* */
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 0105a1fc7929..2f437ecae84d 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -6572,6 +6572,7 @@ static int ath12k_mac_sta_set_4addr(struct wiphy *wiphy, struct ath12k_sta *ahst
struct ath12k_dp_link_peer *peer;
struct ath12k_link_vif *arvif;
struct ath12k_link_sta *arsta;
+ struct ath12k_vif *ahvif;
struct ath12k_dp *dp;
unsigned long links;
struct ath12k *ar;
@@ -6585,10 +6586,11 @@ static int ath12k_mac_sta_set_4addr(struct wiphy *wiphy, struct ath12k_sta *ahst
continue;
arvif = arsta->arvif;
+ ahvif = arvif->ahvif;
ar = arvif->ar;
if (arvif->set_wds_vdev_param)
- goto skip_use_4addr;
+ goto skip_nawds;
ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
"setting USE_4ADDR for peer %pM\n", arsta->addr);
@@ -6603,7 +6605,21 @@ static int ath12k_mac_sta_set_4addr(struct wiphy *wiphy, struct ath12k_sta *ahst
return ret;
}
-skip_use_4addr:
+ if (ahvif->dp_vif.tx_encap_type != ATH12K_HW_TXRX_ETHERNET)
+ goto skip_nawds;
+
+ ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+ WMI_VDEV_PARAM_AP_ENABLE_NAWDS,
+ WDS_EXT_ENABLE);
+ if (ret) {
+ ath12k_warn(ar->ab, "failed to set vdev %d nawds parameter: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ arvif->nawds_enabled = true;
+
+skip_nawds:
dp = ath12k_ab_to_dp(ar->ab);
spin_lock_bh(&dp->dp_lock);
peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, arvif->vdev_id,
@@ -10094,12 +10110,14 @@ static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif)
vif->offload_flags &= ~(IEEE80211_OFFLOAD_ENCAP_ENABLED |
IEEE80211_OFFLOAD_DECAP_ENABLED);
- if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
+ if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) {
ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_ETHERNET;
- else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags))
+ vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
+ } else if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) {
ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_RAW;
- else
+ } else {
ahvif->dp_vif.tx_encap_type = ATH12K_HW_TXRX_NATIVE_WIFI;
+ }
ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
param_id, ahvif->dp_vif.tx_encap_type);
diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c
index 42488b465540..f7f0f613b393 100644
--- a/drivers/net/wireless/ath/ath12k/peer.c
+++ b/drivers/net/wireless/ath/ath12k/peer.c
@@ -224,6 +224,8 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
HTT_TCL_META_DATA_PEER_ID) |
u16_encode_bits(0,
HTT_TCL_META_DATA_VALID_HTT);
+ arsta->ast_hash = peer->ast_hash;
+ arsta->ast_idx = peer->hw_peer_id;
peer->link_id = arsta->link_id;
/* Fill ML info into created peer */
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c
index 5f298133dee9..d2749de44553 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c
@@ -57,6 +57,8 @@ static int ath12k_wifi7_dp_prepare_htt_metadata(struct sk_buff *skb)
return 0;
}
+#define ATH12K_AST_HASH_MASK 0xF
+
/* TODO: Remove the export once this file is built with wifi7 ko */
int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *arvif,
struct ath12k_link_sta *arsta, struct sk_buff *skb,
@@ -78,6 +80,7 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
struct ath12k_dp_vif *dp_vif = &ahvif->dp_vif;
struct ath12k_dp_link_vif *dp_link_vif;
struct dp_tx_ring *tx_ring;
+ struct ethhdr *eth = NULL;
u8 pool_id;
u8 hal_ring_id;
int ret;
@@ -96,6 +99,9 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
!ieee80211_is_data(hdr->frame_control))
return -EOPNOTSUPP;
+ if (skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP)
+ eth = (struct ethhdr *)skb->data;
+
pool_id = skb_get_queue_mapping(skb) & (ATH12K_HW_MAX_QUEUES - 1);
/* Let the default ring selection be based on current processor
@@ -124,9 +130,16 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
ti.bank_id = dp_link_vif->bank_id;
ti.meta_data_flags = dp_link_vif->tcl_metadata;
+ ti.bss_ast_hash = dp_link_vif->ast_hash;
+ ti.bss_ast_idx = dp_link_vif->ast_idx;
- if (ieee80211_has_a4(hdr->frame_control) &&
- is_multicast_ether_addr(hdr->addr3) && arsta) {
+ if (eth && is_multicast_ether_addr(eth->h_dest) && arsta) {
+ ti.meta_data_flags = arsta->tcl_metadata;
+ ti.bss_ast_hash = arsta->ast_hash & ATH12K_AST_HASH_MASK;
+ ti.bss_ast_idx = arsta->ast_idx;
+ ti.lookup_override = true;
+ } else if (!eth && ieee80211_has_a4(hdr->frame_control) &&
+ is_multicast_ether_addr(hdr->addr3) && arsta) {
ti.meta_data_flags = arsta->tcl_metadata;
ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW);
}
@@ -146,7 +159,7 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
msdu_ext_desc = true;
}
- if (gsn_valid) {
+ if (gsn_valid && !ti.lookup_override) {
/* Reset and Initialize meta_data_flags with Global Sequence
* Number (GSN) info.
*/
@@ -154,6 +167,14 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
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);
+
+ /*
+ * Since NAWDS enabled for this vdev firmware expects
+ * this flag to be set for sending 3-address multicast frame.
+ */
+ ti.meta_data_flags |=
+ u32_encode_bits(arvif->nawds_enabled,
+ HTT_TCL_META_DATA_GLOBAL_SEQ_HOST_INSPECTED);
}
ti.encap_type = ath12k_dp_tx_get_encap_type(ab, skb);
@@ -164,11 +185,13 @@ int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *a
ti.lmac_id = dp_link_vif->lmac_id;
ti.vdev_id = dp_link_vif->vdev_id;
- if (gsn_valid)
+
+ if (gsn_valid && !ti.lookup_override)
ti.vdev_id += HTT_TX_MLO_MCAST_HOST_REINJECT_BASE_VDEV_ID;
+ else if (arvif->nawds_enabled && is_mcast && !ti.lookup_override)
+ ti.meta_data_flags |=
+ u32_encode_bits(1, HTT_TCL_META_DATA_HOST_INSPECTED_MISSION);
- ti.bss_ast_hash = dp_link_vif->ast_hash;
- ti.bss_ast_idx = dp_link_vif->ast_idx;
ti.dscp_tid_tbl_idx = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL &&
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c b/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c
index 02d3cadf03fe..eeabe9db776e 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c
@@ -59,7 +59,9 @@ void ath12k_wifi7_hal_tx_cmd_desc_setup(struct ath12k_base *ab,
le32_encode_bits(ti->lmac_id, HAL_TCL_DATA_CMD_INFO3_PMAC_ID) |
le32_encode_bits(ti->vdev_id, HAL_TCL_DATA_CMD_INFO3_VDEV_ID);
- tcl_cmd->info4 = le32_encode_bits(ti->bss_ast_idx,
+ tcl_cmd->info4 = le32_encode_bits(ti->lookup_override,
+ HAL_TCL_DATA_CMD_INFO4_IDX_LOOKUP_OVERRIDE) |
+ le32_encode_bits(ti->bss_ast_idx,
HAL_TCL_DATA_CMD_INFO4_SEARCH_INDEX) |
le32_encode_bits(ti->bss_ast_hash,
HAL_TCL_DATA_CMD_INFO4_CACHE_SET_NUM);
diff --git a/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h b/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h
index 9d2b1552c2f5..c548a0fbf1bb 100644
--- a/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h
+++ b/drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h
@@ -34,6 +34,7 @@ struct hal_tx_info {
u8 dscp_tid_tbl_idx;
bool enable_mesh;
int bank_id;
+ bool lookup_override;
};
/* TODO: Check if the actual desc macros can be used instead */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 25e61cc7e5ac..eaed1c4ddd55 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -4192,7 +4192,8 @@ ath12k_wmi_copy_resource_config(struct ath12k_base *ab,
cpu_to_le32(1 << WMI_RSRC_CFG_HOST_SVC_FLAG_REO_QREF_SUPPORT_BIT);
wmi_cfg->ema_max_vap_cnt = cpu_to_le32(tg_cfg->ema_max_vap_cnt);
wmi_cfg->ema_max_profile_period = cpu_to_le32(tg_cfg->ema_max_profile_period);
- wmi_cfg->flags2 |= cpu_to_le32(WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET);
+ wmi_cfg->flags2 |= cpu_to_le32(WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET |
+ WMI_RSRC_CFG_FLAGS2_FW_AST_INDICATION_DISABLE);
}
static int ath12k_init_cmd_send(struct ath12k_wmi_pdev *wmi,
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index a827b3c99f8f..13d82f706d79 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -2334,6 +2334,14 @@ enum wmi_preamble {
WMI_VDEV_PREAMBLE_SHORT = 2,
};
+/*
+ * This will be used to set for WMI_VDEV_PARAM_AP_ENABLE_NAWDS
+ * whenever 4addr station connects in wds offload case.
+ * This is for enabling multicast to unicast conversion support in
+ * firmware
+ */
+#define WDS_EXT_ENABLE 1
+
enum wmi_peer_4addr_allow_frame {
WMI_PEER_4ADDR_ALLOW_DATA_FRAME = 1,
WMI_PEER_4ADDR_ALLOW_EAPOL_DATA_FRAME = 2,
@@ -2559,6 +2567,7 @@ struct wmi_init_cmd {
#define WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION GENMASK(5, 4)
#define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5)
#define WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET BIT(9)
+#define WMI_RSRC_CFG_FLAGS2_FW_AST_INDICATION_DISABLE BIT(18)
#define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18)
struct ath12k_wmi_resource_config_params {
--
2.34.1
More information about the ath12k
mailing list