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>
struct wiphy_work bcn_tx_work;
bool set_wds_vdev_param;
+ bool nawds_enabled;
};
struct ath12k_vif {
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_* */
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;
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);
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,
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);
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 */
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,
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;
!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
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);
}
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.
*/
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);
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 &&
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);
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 */
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,
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,
#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 {