]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: ath12k: Add 4-address mode support for eth offload
authorTamizh Chelvam Raja <tamizh.raja@oss.qualcomm.com>
Mon, 25 May 2026 11:09:39 +0000 (16:39 +0530)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Mon, 1 Jun 2026 16:58:05 +0000 (09:58 -0700)
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@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/20260525110942.2890212-4-tamizh.raja@oss.qualcomm.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
drivers/net/wireless/ath/ath12k/core.h
drivers/net/wireless/ath/ath12k/mac.c
drivers/net/wireless/ath/ath12k/peer.c
drivers/net/wireless/ath/ath12k/wifi7/dp_tx.c
drivers/net/wireless/ath/ath12k/wifi7/hal_tx.c
drivers/net/wireless/ath/ath12k/wifi7/hal_tx.h
drivers/net/wireless/ath/ath12k/wmi.c
drivers/net/wireless/ath/ath12k/wmi.h

index 70ad9742c21dd0cfa09620733d70faebc574e208..fc5127b5c1a37f7d3e1e9319b13638472147441a 100644 (file)
@@ -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_* */
index 616d1326130560ab37c916cdd6e7aea9b6ae99c5..2c1eadf548ac4e69956b6cb2794e60e11355b502 100644 (file)
@@ -6576,6 +6576,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;
@@ -6589,10 +6590,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);
@@ -6607,7 +6609,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,
@@ -10098,12 +10114,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);
index 42488b4655400eac8cc3776d017c0dabf07afd19..f7f0f613b393accbb7dc421b3e8e50ea295a4394 100644 (file)
@@ -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 */
index 5f298133dee94b8ca25a8b486a32500bb39ef5cd..d2749de445534ac6043d20720e463a343b7ca0a3 100644 (file)
@@ -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 @@ tcl_ring_sel:
 
        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 @@ tcl_ring_sel:
                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 @@ tcl_ring_sel:
                        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 @@ tcl_ring_sel:
        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 &&
index 02d3cadf03fea9eebebeccb22c8b1781bc3c89cf..eeabe9db776ebb5fb0f78801b62965a21a4d9ffe 100644 (file)
@@ -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);
index 9d2b1552c2f512905a2cc0b0e761dbdaae0d2f00..c548a0fbf1bba6eee8c479d0fc1a8bf0a0cb51c8 100644 (file)
@@ -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 */
index 18f91051199c4932a724005a0b23501a17267027..d9f1b46155756fd48ad2d25dc45654a2a4ab5330 100644 (file)
@@ -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,
index a827b3c99f8ff12631efd064476b317957543fd6..13d82f706d79f91560198dd321f09ef16eb973ea 100644 (file)
@@ -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 {