ath.git patches for v7.2 (PR #3)

In ath12k, add driver support for WDS mode.
 
 In ath11k and ath12k, a number of cleanups and minor bug fixes.
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQ/mtSHzPUi16IfDEksFbugiYzLewUCah7oAwAKCRAsFbugiYzL
 e4FRAQDP7XeGi3lDh02TlRthSY1z1fw8dTnUoHrok3MozxwGrQEAztgSQg1wjERh
 PAKcUibVH/ebQf5MHziPl+/ZR24RCwM=
 =iZG5
 -----END PGP SIGNATURE-----

Merge tag 'ath-next-20260602' of git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath

Jeff Johnson says:
==================
ath.git patches for v7.2 (PR #3)

In ath12k, add driver support for WDS mode.

In ath11k and ath12k, a number of cleanups and minor bug fixes.
==================

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2026-06-04 13:05:04 +02:00
commit d03291b8c7
27 changed files with 643 additions and 116 deletions

View File

@ -267,7 +267,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.coldboot_cal_ftm = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
.num_vdevs = 2 + 1,
.num_vdevs = 4,
.num_peers = 512,
.supports_suspend = true,
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
@ -445,7 +445,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.coldboot_cal_ftm = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
.num_vdevs = 2 + 1,
.num_vdevs = 4,
.num_peers = 512,
.supports_suspend = true,
.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
@ -535,7 +535,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.coldboot_cal_ftm = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
.num_vdevs = 2 + 1,
.num_vdevs = 4,
.num_peers = 512,
.supports_suspend = true,
.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
@ -797,7 +797,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.coldboot_cal_ftm = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
.num_vdevs = 2 + 1,
.num_vdevs = 4,
.num_peers = 512,
.supports_suspend = true,
.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
@ -886,7 +886,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.coldboot_cal_ftm = false,
.cbcal_restart_fw = false,
.fw_mem_mode = 0,
.num_vdevs = 2 + 1,
.num_vdevs = 4,
.num_peers = 512,
.supports_suspend = true,
.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),

View File

@ -2503,6 +2503,29 @@ static void ath11k_dp_rx_deliver_msdu(struct ath11k *ar, struct napi_struct *nap
ieee80211_rx_napi(ar->hw, pubsta, msdu, napi);
}
static bool ath11k_dp_rx_check_nwifi_hdr_len_valid(struct ath11k_base *ab,
struct hal_rx_desc *rx_desc,
struct sk_buff *msdu)
{
struct ieee80211_hdr *hdr;
u8 decap_type;
u32 hdr_len;
decap_type = ath11k_dp_rx_h_msdu_start_decap_type(ab, rx_desc);
if (decap_type != DP_RX_DECAP_TYPE_NATIVE_WIFI)
return true;
hdr = (struct ieee80211_hdr *)msdu->data;
hdr_len = ieee80211_hdrlen(hdr->frame_control);
if (likely(hdr_len <= DP_MAX_NWIFI_HDR_LEN))
return true;
ab->soc_stats.invalid_rbm++;
WARN_ON_ONCE(1);
return false;
}
static int ath11k_dp_rx_process_msdu(struct ath11k *ar,
struct sk_buff *msdu,
struct sk_buff_head *msdu_list,
@ -2573,6 +2596,11 @@ static int ath11k_dp_rx_process_msdu(struct ath11k *ar,
}
}
if (unlikely(!ath11k_dp_rx_check_nwifi_hdr_len_valid(ab, rx_desc, msdu))) {
ret = -EINVAL;
goto free_out;
}
ath11k_dp_rx_h_ppdu(ar, rx_desc, rx_status);
ath11k_dp_rx_h_mpdu(ar, msdu, rx_desc, rx_status);
@ -3262,6 +3290,12 @@ static int ath11k_dp_rx_h_verify_tkip_mic(struct ath11k *ar, struct ath11k_peer
RX_FLAG_IV_STRIPPED | RX_FLAG_DECRYPTED;
skb_pull(msdu, hal_rx_desc_sz);
if (unlikely(!ath11k_dp_rx_check_nwifi_hdr_len_valid(ar->ab, rx_desc,
msdu))) {
dev_kfree_skb_any(msdu);
return -EINVAL;
}
ath11k_dp_rx_h_ppdu(ar, rx_desc, rxs);
ath11k_dp_rx_h_undecap(ar, msdu, rx_desc,
HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true);
@ -3954,6 +3988,10 @@ static int ath11k_dp_rx_h_null_q_desc(struct ath11k *ar, struct sk_buff *msdu,
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
}
if (unlikely(!ath11k_dp_rx_check_nwifi_hdr_len_valid(ar->ab, desc, msdu)))
return -EINVAL;
ath11k_dp_rx_h_ppdu(ar, desc, status);
ath11k_dp_rx_h_mpdu(ar, msdu, desc, status);
@ -3998,7 +4036,7 @@ static bool ath11k_dp_rx_h_reo_err(struct ath11k *ar, struct sk_buff *msdu,
return drop;
}
static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
static bool ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
struct ieee80211_rx_status *status)
{
u16 msdu_len;
@ -4006,15 +4044,28 @@ static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
u8 l3pad_bytes;
struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
u32 hal_rx_desc_sz = ar->ab->hw_params.hal_desc_sz;
struct ath11k_base *ab = ar->ab;
rxcb->is_first_msdu = ath11k_dp_rx_h_msdu_end_first_msdu(ar->ab, desc);
rxcb->is_last_msdu = ath11k_dp_rx_h_msdu_end_last_msdu(ar->ab, desc);
l3pad_bytes = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, desc);
msdu_len = ath11k_dp_rx_h_msdu_start_msdu_len(ar->ab, desc);
if (unlikely(hal_rx_desc_sz + l3pad_bytes + msdu_len > DP_RX_BUFFER_SIZE)) {
ath11k_dbg(ab, ATH11K_DBG_DATA,
"invalid msdu len in tkip mic err %u\n", msdu_len);
ath11k_dbg_dump(ab, ATH11K_DBG_DATA, NULL, "", desc,
sizeof(*desc));
return true;
}
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
if (unlikely(!ath11k_dp_rx_check_nwifi_hdr_len_valid(ab, desc, msdu)))
return true;
ath11k_dp_rx_h_ppdu(ar, desc, status);
status->flag |= (RX_FLAG_MMIC_STRIPPED | RX_FLAG_MMIC_ERROR |
@ -4022,19 +4073,21 @@ static void ath11k_dp_rx_h_tkip_mic_err(struct ath11k *ar, struct sk_buff *msdu,
ath11k_dp_rx_h_undecap(ar, msdu, desc,
HAL_ENCRYPT_TYPE_TKIP_MIC, status, false);
return false;
}
static bool ath11k_dp_rx_h_rxdma_err(struct ath11k *ar, struct sk_buff *msdu,
struct ieee80211_rx_status *status)
{
struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu);
bool drop = false;
bool drop;
ar->ab->soc_stats.rxdma_error[rxcb->err_code]++;
switch (rxcb->err_code) {
case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR:
ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status);
drop = ath11k_dp_rx_h_tkip_mic_err(ar, msdu, status);
break;
default:
/* TODO: Review other rxdma error code to check if anything is

View File

@ -4227,13 +4227,14 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw,
if (ret)
goto exit;
arg = kzalloc_obj(*arg);
arg = kzalloc_flex(*arg, chan_list, req->n_channels);
if (!arg) {
ret = -ENOMEM;
goto exit;
}
arg->num_chan = req->n_channels;
ath11k_wmi_start_scan_init(ar, arg);
arg->vdev_id = arvif->vdev_id;
arg->scan_id = ATH11K_SCAN_ID;
@ -4261,38 +4262,27 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw,
arg->scan_f_passive = 1;
}
if (req->n_channels) {
arg->num_chan = req->n_channels;
arg->chan_list = kcalloc(arg->num_chan, sizeof(*arg->chan_list),
GFP_KERNEL);
for (i = 0; i < arg->num_chan; i++) {
if (test_bit(WMI_TLV_SERVICE_SCAN_CONFIG_PER_CHANNEL,
ar->ab->wmi_ab.svc_map)) {
arg->chan_list[i] =
u32_encode_bits(req->channels[i]->center_freq,
WMI_SCAN_CONFIG_PER_CHANNEL_MASK);
if (!arg->chan_list) {
ret = -ENOMEM;
goto exit;
}
for (i = 0; i < arg->num_chan; i++) {
if (test_bit(WMI_TLV_SERVICE_SCAN_CONFIG_PER_CHANNEL,
ar->ab->wmi_ab.svc_map)) {
arg->chan_list[i] =
u32_encode_bits(req->channels[i]->center_freq,
WMI_SCAN_CONFIG_PER_CHANNEL_MASK);
/* If NL80211_SCAN_FLAG_COLOCATED_6GHZ is set in scan
* flags, then scan all PSC channels in 6 GHz band and
* those non-PSC channels where RNR IE is found during
* the legacy 2.4/5 GHz scan.
* If NL80211_SCAN_FLAG_COLOCATED_6GHZ is not set,
* then all channels in 6 GHz will be scanned.
*/
if (req->channels[i]->band == NL80211_BAND_6GHZ &&
req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ &&
!cfg80211_channel_is_psc(req->channels[i]))
arg->chan_list[i] |=
WMI_SCAN_CH_FLAG_SCAN_ONLY_IF_RNR_FOUND;
} else {
arg->chan_list[i] = req->channels[i]->center_freq;
}
/* If NL80211_SCAN_FLAG_COLOCATED_6GHZ is set in scan
* flags, then scan all PSC channels in 6 GHz band and
* those non-PSC channels where RNR IE is found during
* the legacy 2.4/5 GHz scan.
* If NL80211_SCAN_FLAG_COLOCATED_6GHZ is not set,
* then all channels in 6 GHz will be scanned.
*/
if (req->channels[i]->band == NL80211_BAND_6GHZ &&
req->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ &&
!cfg80211_channel_is_psc(req->channels[i]))
arg->chan_list[i] |=
WMI_SCAN_CH_FLAG_SCAN_ONLY_IF_RNR_FOUND;
} else {
arg->chan_list[i] = req->channels[i]->center_freq;
}
}
@ -4335,7 +4325,6 @@ static int ath11k_mac_op_hw_scan(struct ieee80211_hw *hw,
exit:
if (arg) {
kfree(arg->chan_list);
kfree(arg->extraie.ptr);
kfree(arg);
}
@ -9735,19 +9724,14 @@ static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
scan_time_msec = ar->hw->wiphy->max_remain_on_channel_duration * 2;
arg = kzalloc_obj(*arg);
arg = kzalloc_flex(*arg, chan_list, 1);
if (!arg) {
ret = -ENOMEM;
goto exit;
}
ath11k_wmi_start_scan_init(ar, arg);
arg->num_chan = 1;
arg->chan_list = kcalloc(arg->num_chan, sizeof(*arg->chan_list),
GFP_KERNEL);
if (!arg->chan_list) {
ret = -ENOMEM;
goto free_arg;
}
ath11k_wmi_start_scan_init(ar, arg);
arg->vdev_id = arvif->vdev_id;
arg->scan_id = ATH11K_SCAN_ID;
@ -9768,7 +9752,7 @@ static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
spin_lock_bh(&ar->data_lock);
ar->scan.state = ATH11K_SCAN_IDLE;
spin_unlock_bh(&ar->data_lock);
goto free_chan_list;
goto free_arg;
}
ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ);
@ -9778,7 +9762,7 @@ static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
if (ret)
ath11k_warn(ar->ab, "failed to stop scan: %d\n", ret);
ret = -ETIMEDOUT;
goto free_chan_list;
goto free_arg;
}
ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout,
@ -9786,8 +9770,6 @@ static int ath11k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
ret = 0;
free_chan_list:
kfree(arg->chan_list);
free_arg:
kfree(arg);
exit:

View File

@ -3423,7 +3423,6 @@ struct scan_req_params {
u32 num_bssid;
u32 num_ssids;
u32 n_probes;
u32 *chan_list;
u32 notify_scan_events;
struct wlan_ssid ssid[WLAN_SCAN_PARAMS_MAX_SSID];
struct wmi_mac_addr bssid_list[WLAN_SCAN_PARAMS_MAX_BSSID];
@ -3436,6 +3435,7 @@ struct scan_req_params {
struct hint_bssid hint_bssid[WLAN_SCAN_MAX_HINT_BSSID];
struct wmi_mac_addr mac_addr;
struct wmi_mac_addr mac_mask;
u32 chan_list[] __counted_by(num_chan);
};
struct wmi_ssid_arg {

View File

@ -353,6 +353,9 @@ struct ath12k_link_vif {
u16 num_stations;
bool is_csa_in_progress;
struct wiphy_work bcn_tx_work;
bool set_wds_vdev_param;
bool nawds_enabled;
};
struct ath12k_vif {
@ -492,6 +495,10 @@ struct ath12k_link_sta {
/* link address similar to ieee80211_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_* */
u32 bw;
@ -527,6 +534,8 @@ struct ath12k_sta {
u16 free_logical_link_idx_map;
enum ieee80211_sta_state state;
bool enable_4addr;
};
#define ATH12K_HALF_20MHZ_BW 10

View File

@ -115,13 +115,14 @@ ath12k_dp_mon_fill_rx_rate(struct ath12k_pdev_dp *dp_pdev,
bool is_cck;
pkt_type = ppdu_info->preamble_type;
rate_mcs = ppdu_info->rate;
rate_mcs = ppdu_info->mcs;
nss = ppdu_info->nss;
sgi = ppdu_info->gi;
switch (pkt_type) {
case RX_MSDU_START_PKT_TYPE_11A:
case RX_MSDU_START_PKT_TYPE_11B:
rate_mcs = ppdu_info->rate;
is_cck = (pkt_type == RX_MSDU_START_PKT_TYPE_11B);
if (rx_status->band < NUM_NL80211_BANDS) {
struct ath12k *ar = ath12k_pdev_dp_to_ar(dp_pdev);
@ -471,13 +472,10 @@ void ath12k_dp_mon_update_radiotap(struct ath12k_pdev_dp *dp_pdev,
rxs->encoding = RX_ENC_HE;
ptr = skb_push(mon_skb, sizeof(struct ieee80211_radiotap_he));
ath12k_dp_mon_rx_update_radiotap_he(ppduinfo, ptr);
rxs->rate_idx = ppduinfo->rate;
} else if (ppduinfo->vht_flags) {
rxs->encoding = RX_ENC_VHT;
rxs->rate_idx = ppduinfo->rate;
} else if (ppduinfo->ht_flags) {
rxs->encoding = RX_ENC_HT;
rxs->rate_idx = ppduinfo->rate;
} else {
struct ath12k *ar;

View File

@ -419,7 +419,7 @@ struct ath12k_dp_peer *ath12k_dp_peer_find_by_peerid(struct ath12k_pdev_dp *dp_p
RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
"ath12k dp peer find by peerid index called without rcu lock");
if (!peer_id || peer_id >= ATH12K_DP_PEER_ID_INVALID)
if (peer_id >= ATH12K_DP_PEER_ID_INVALID)
return NULL;
index = ath12k_dp_peer_get_peerid_index(dp, peer_id);

View File

@ -143,6 +143,8 @@ struct ath12k_dp_peer {
struct ath12k_dp_link_peer __rcu *link_peers[ATH12K_NUM_MAX_LINKS];
struct ath12k_reoq_buf reoq_bufs[IEEE80211_NUM_TIDS + 1];
struct ath12k_dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1];
bool use_4addr;
};
struct ath12k_dp_link_peer *

View File

@ -1142,7 +1142,8 @@ static void ath12k_dp_rx_h_undecap_eth(struct ath12k_pdev_dp *dp_pdev,
void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu,
enum hal_encrypt_type enctype,
bool decrypted,
struct hal_rx_desc_data *rx_info)
struct hal_rx_desc_data *rx_info,
struct ath12k_dp_peer *peer)
{
enum ath12k_dp_rx_decap_type decap_type = rx_info->decap_type;
struct ethhdr *ehdr;
@ -1166,6 +1167,13 @@ void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu
break;
}
if (peer && !peer->use_4addr &&
rx_info->is_from_ds && rx_info->is_to_ds) {
ath12k_dp_rx_h_undecap_eth(dp_pdev, msdu, enctype, rx_info,
decap_type);
break;
}
/* PN for mcast packets will be validated in mac80211;
* remove eth header and add 802.11 header.
*/
@ -1202,8 +1210,7 @@ ath12k_dp_rx_h_find_link_peer(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *ms
lockdep_assert_held(&dp->dp_lock);
if (rxcb->peer_id)
peer = ath12k_dp_link_peer_find_by_peerid(dp_pdev, rxcb->peer_id);
peer = ath12k_dp_link_peer_find_by_peerid(dp_pdev, rxcb->peer_id);
if (peer)
return peer;

View File

@ -190,7 +190,8 @@ void ath12k_dp_extract_rx_desc_data(struct ath12k_hal *hal,
void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu,
enum hal_encrypt_type enctype,
bool decrypted,
struct hal_rx_desc_data *rx_info);
struct hal_rx_desc_data *rx_info,
struct ath12k_dp_peer *peer);
void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struct *napi,
struct sk_buff *msdu,
struct hal_rx_desc_data *rx_info);

View File

@ -738,7 +738,9 @@ struct hal_rx_desc_data {
addr2_present:1,
is_mcbc:1,
seq_ctl_valid:1,
fc_valid:1;
fc_valid:1,
is_to_ds:1,
is_from_ds:1;
u16 msdu_len;
u16 peer_id;
u16 seq_no;

View File

@ -19,14 +19,28 @@
#define TARGET_NUM_VDEVS(ab) ((ab)->profile_param->num_vdevs)
/* Max num of stations for Single Radio mode */
#define TARGET_NUM_STATIONS_SINGLE(ab) ((ab)->profile_param->max_client_single)
#define TARGET_NUM_STATIONS_SINGLE(ab) \
({ \
typeof(ab) _ab = (ab); \
min_not_zero(_ab->hw_params->client.max_client_single, \
_ab->profile_param->max_client_single); \
})
/* Max num of stations for DBS */
#define TARGET_NUM_STATIONS_DBS(ab) ((ab)->profile_param->max_client_dbs)
#define TARGET_NUM_STATIONS_DBS(ab) \
({ \
typeof(ab) _ab = (ab); \
min_not_zero(_ab->hw_params->client.max_client_dbs, \
_ab->profile_param->max_client_dbs); \
})
/* Max num of stations for DBS_SBS */
#define TARGET_NUM_STATIONS_DBS_SBS(ab) \
((ab)->profile_param->max_client_dbs_sbs)
({ \
typeof(ab) _ab = (ab); \
min_not_zero(_ab->hw_params->client.max_client_dbs_sbs, \
_ab->profile_param->max_client_dbs_sbs); \
})
#define TARGET_NUM_STATIONS(ab, x) TARGET_NUM_STATIONS_##x(ab)
@ -213,6 +227,11 @@ struct ath12k_hw_params {
/* setup REO queue, frag etc only for primary link peer */
bool dp_primary_link_only:1;
struct {
u32 max_client_single;
u32 max_client_dbs;
u32 max_client_dbs_sbs;
} client;
};
struct ath12k_hw_ops {

View File

@ -6571,6 +6571,79 @@ static int ath12k_mac_station_disassoc(struct ath12k *ar,
return 0;
}
static int ath12k_mac_sta_set_4addr(struct wiphy *wiphy, struct ath12k_sta *ahsta)
{
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;
u8 link_id;
int ret;
links = ahsta->links_map;
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
arsta = wiphy_dereference(wiphy, ahsta->link[link_id]);
if (!arsta)
continue;
arvif = arsta->arvif;
ahvif = arvif->ahvif;
ar = arvif->ar;
if (arvif->set_wds_vdev_param)
goto skip_nawds;
ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
"setting USE_4ADDR for peer %pM\n", arsta->addr);
ret = ath12k_wmi_set_peer_param(ar, arsta->addr,
arvif->vdev_id,
WMI_PEER_USE_4ADDR,
WMI_PEER_4ADDR_ALLOW_EAPOL_DATA_FRAME);
if (ret) {
ath12k_warn(ar->ab, "failed to set peer %pM 4addr capability: %d\n",
arsta->addr, ret);
return ret;
}
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,
arsta->addr);
if (peer && peer->dp_peer) {
peer->dp_peer->ucast_ra_only = true;
peer->dp_peer->use_4addr = true;
} else {
spin_unlock_bh(&dp->dp_lock);
ath12k_warn(ar->ab, "failed to find DP peer for %pM\n",
arsta->addr);
return -ENOENT;
}
spin_unlock_bh(&dp->dp_lock);
}
return 0;
}
static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk)
{
struct ieee80211_link_sta *link_sta;
@ -7865,6 +7938,28 @@ int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ath12k_mac_op_sta_set_txpwr);
void ath12k_mac_op_sta_set_4addr(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enabled)
{
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
lockdep_assert_wiphy(hw->wiphy);
/*
* 4-address mode disabled option is available only for station
* interface from mac80211, and we have wds_vdev_param for station
* interface and target will not allow to disable the wds_vdev_param
* during run time. So, add support only for enable case, for
* disable case station interface needs to be reconnect.
*/
if (enabled && !ahsta->enable_4addr) {
if (!ath12k_mac_sta_set_4addr(hw->wiphy, ahsta))
ahsta->enable_4addr = true;
}
}
EXPORT_SYMBOL(ath12k_mac_op_sta_set_4addr);
void ath12k_mac_op_link_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta,
@ -8049,16 +8144,16 @@ int ath12k_mac_op_change_sta_links(struct ieee80211_hw *hw,
continue;
arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]);
arsta = ath12k_mac_alloc_assign_link_sta(ah, ahsta, ahvif, link_id);
if (!arvif || !arvif->is_created)
continue;
if (!arvif || !arsta) {
arsta = ath12k_mac_alloc_assign_link_sta(ah, ahsta, ahvif, link_id);
if (!arsta) {
ath12k_hw_warn(ah, "Failed to alloc/assign link sta");
continue;
}
ar = arvif->ar;
if (!ar)
continue;
ret = ath12k_mac_station_add(ar, arvif, arsta);
if (ret) {
@ -10020,12 +10115,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);
@ -10235,6 +10332,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
struct ieee80211_hw *hw = ah->hw;
struct ath12k_vif *ahvif = arvif->ahvif;
struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif);
struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif);
struct ath12k_wmi_vdev_create_arg vdev_arg = {};
struct ath12k_wmi_peer_create_arg peer_param = {};
struct ieee80211_bss_conf *link_conf = NULL;
@ -10302,7 +10400,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
if (ret) {
ath12k_warn(ab, "failed to create WMI vdev %d: %d\n",
arvif->vdev_id, ret);
return ret;
goto err;
}
ar->num_created_vdevs++;
@ -10403,6 +10501,26 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
goto err_peer_del;
}
/*
* There could be race condition in firmware for the station
* interface between enabling 4-address peer WMI param and
* sending 4-address frame (NULL or EAPOL via TCL).
* Make the station as WDS while bringup itself
* to avoid the race condition
*/
if (vif->type == NL80211_IFTYPE_STATION &&
(wdev && wdev->use_4addr)) {
ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
WMI_VDEV_PARAM_WDS,
1);
if (ret) {
ath12k_warn(ar->ab, "failed to set WDS vdev param: %d\n",
ret);
goto err_peer_del;
}
arvif->set_wds_vdev_param = true;
}
if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&
ahvif->vdev_type == WMI_VDEV_TYPE_STA &&
ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) {
@ -10449,13 +10567,13 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
if (ret) {
ath12k_warn(ar->ab, "failed to delete peer vdev_id %d addr %pM\n",
arvif->vdev_id, arvif->bssid);
goto err;
goto err_dp_peer_del;
}
ret = ath12k_wait_for_peer_delete_done(ar, arvif->vdev_id,
arvif->bssid);
if (ret)
goto err_vdev_del;
goto err_dp_peer_del;
ar->num_peers--;
}
@ -10472,8 +10590,6 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
ath12k_wmi_vdev_delete(ar, arvif->vdev_id);
ar->num_created_vdevs--;
arvif->is_created = false;
arvif->ar = NULL;
ar->allocated_vdev_map &= ~(1LL << arvif->vdev_id);
ab->free_vdev_map |= 1LL << arvif->vdev_id;
ab->free_vdev_stats_id_map &= ~(1LL << arvif->vdev_stats_id);
@ -10482,6 +10598,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif)
spin_unlock_bh(&ar->data_lock);
err:
arvif->is_created = false;
arvif->ar = NULL;
return ret;
}
@ -11480,6 +11597,9 @@ ath12k_mac_update_vif_chan(struct ath12k *ar,
continue;
}
if (WARN_ON(!arvif))
continue;
ath12k_dbg(ab, ATH12K_DBG_MAC,
"mac chanctx switch vdev_id %i freq %u->%u width %d->%d\n",
arvif->vdev_id,
@ -12271,23 +12391,85 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
int n_vifs,
enum ieee80211_chanctx_switch_mode mode)
{
struct ath12k *ar;
struct ath12k *curr_ar, *new_ar, *group_ar;
struct ieee80211_vif_chanctx_switch *v;
int i, j, count = 0;
lockdep_assert_wiphy(hw->wiphy);
ar = ath12k_get_ar_by_ctx(hw, vifs->old_ctx);
if (!ar)
return -EINVAL;
if (n_vifs == 0)
return 0;
/* Switching channels across radio is not allowed */
if (ar != ath12k_get_ar_by_ctx(hw, vifs->new_ctx))
return -EINVAL;
struct ath12k **ar_map __free(kfree) = kzalloc_objs(*ar_map, n_vifs);
ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
"mac chanctx switch n_vifs %d mode %d\n",
n_vifs, mode);
ath12k_mac_update_vif_chan(ar, vifs, n_vifs);
if (!ar_map)
return -ENOMEM;
for (i = 0; i < n_vifs; i++) {
v = &vifs[i];
if (v->old_ctx->def.chan->band != v->new_ctx->def.chan->band) {
ath12k_generic_dbg(ATH12K_DBG_MAC,
"mac chanctx switch band change not supported\n");
return -EOPNOTSUPP;
}
curr_ar = ath12k_get_ar_by_ctx(hw, v->old_ctx);
new_ar = ath12k_get_ar_by_ctx(hw, v->new_ctx);
if (!curr_ar || !new_ar) {
ath12k_generic_dbg(ATH12K_DBG_MAC,
"unable to determine device for the passed channel ctx\n");
ath12k_generic_dbg(ATH12K_DBG_MAC,
"Old freq %d MHz (device %s) to new freq %d MHz (device %s)\n",
v->old_ctx->def.chan->center_freq,
curr_ar ? "valid" : "invalid",
v->new_ctx->def.chan->center_freq,
new_ar ? "valid" : "invalid");
return -EINVAL;
}
/* Switching a vif between two radios is not allowed */
if (curr_ar != new_ar) {
ath12k_dbg(curr_ar->ab, ATH12K_DBG_MAC,
"mac chanctx switch to another radio not supported\n");
return -EOPNOTSUPP;
}
ar_map[i] = curr_ar;
}
/* Group vifs by radio (ar) and process each group independently. */
bool *processed __free(kfree) = kzalloc_objs(*processed, n_vifs);
if (!processed)
return -ENOMEM;
struct ieee80211_vif_chanctx_switch *group_vifs __free(kfree) =
kzalloc_objs(*group_vifs, n_vifs);
if (!group_vifs)
return -ENOMEM;
for (i = 0; i < n_vifs; i++) {
if (processed[i])
continue;
group_ar = ar_map[i];
count = 0;
for (j = 0; j < n_vifs; j++) {
if (!processed[j] && ar_map[j] == group_ar) {
group_vifs[count++] = vifs[j];
processed[j] = true;
}
}
ath12k_dbg(group_ar->ab, ATH12K_DBG_MAC,
"mac chanctx switch n_vifs %d mode %d\n",
count, mode);
ath12k_mac_update_vif_chan(group_ar, group_vifs, count);
}
return 0;
}
EXPORT_SYMBOL(ath12k_mac_op_switch_vif_chanctx);

View File

@ -255,6 +255,9 @@ int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void ath12k_mac_op_sta_set_4addr(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enabled);
void ath12k_mac_op_link_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta,

View File

@ -218,7 +218,13 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
ahsta = ath12k_sta_to_ahsta(sta);
arsta = wiphy_dereference(ath12k_ar_to_hw(ar)->wiphy,
ahsta->link[link_id]);
/* TODO: Split DP related field usage to DP peer structure */
arsta->tcl_metadata = u16_encode_bits(0, HTT_TCL_META_DATA_TYPE) |
u16_encode_bits(peer->peer_id,
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 */
@ -249,6 +255,9 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
ar->hw_link_id);
}
if (vif->type == NL80211_IFTYPE_AP && peer->dp_peer)
peer->dp_peer->ucast_ra_only = true;
return ret;
}

View File

@ -1779,8 +1779,7 @@ ath12k_wifi7_dp_mon_rx_parse_status_tlv(struct ath12k_pdev_dp *dp_pdev,
info[1] = __le32_to_cpu(mpdu_start->info1);
peer_id = u32_get_bits(info[1], HAL_RX_MPDU_START_INFO1_PEERID);
if (peer_id)
ppdu_info->peer_id = peer_id;
ppdu_info->peer_id = peer_id;
ppdu_info->mpdu_len += u32_get_bits(info[1],
HAL_RX_MPDU_START_INFO2_MPDU_LEN);

View File

@ -323,9 +323,9 @@ static void ath12k_wifi7_dp_rx_h_csum_offload(struct sk_buff *msdu,
CHECKSUM_NONE : CHECKSUM_UNNECESSARY;
}
static void ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev,
struct sk_buff *msdu,
struct hal_rx_desc_data *rx_info)
static int ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev,
struct sk_buff *msdu,
struct hal_rx_desc_data *rx_info)
{
struct ath12k_skb_rxcb *rxcb;
enum hal_encrypt_type enctype;
@ -347,6 +347,18 @@ static void ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev,
peer = ath12k_dp_peer_find_by_peerid(dp_pdev, rxcb->peer_id);
if (peer) {
/*
* Drop the 3-address multicast packet from 4-address
* peer To avoid receiving the duplicate multicast packet
* Specifically from AP interface in 3-address format
*/
if (rxcb->is_mcbc &&
rx_info->decap_type == DP_RX_DECAP_TYPE_ETHERNET2_DIX) {
if (peer->use_4addr &&
!(rx_info->is_from_ds && rx_info->is_to_ds))
return -EINVAL;
}
/* resetting mcbc bit because mcbc packets are unicast
* packets only for AP as STA sends unicast packets.
*/
@ -387,15 +399,18 @@ static void ath12k_wifi7_dp_rx_h_mpdu(struct ath12k_pdev_dp *dp_pdev,
}
ath12k_wifi7_dp_rx_h_csum_offload(msdu, rx_info);
ath12k_dp_rx_h_undecap(dp_pdev, msdu, enctype, is_decrypted, rx_info);
ath12k_dp_rx_h_undecap(dp_pdev, msdu, enctype, is_decrypted, rx_info,
peer);
if (!is_decrypted || rx_info->is_mcbc)
return;
return 0;
if (rx_info->decap_type != DP_RX_DECAP_TYPE_ETHERNET2_DIX) {
hdr = (void *)msdu->data;
hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
}
return 0;
}
static int ath12k_wifi7_dp_rx_msdu_coalesce(struct ath12k_hal *hal,
@ -554,7 +569,9 @@ static int ath12k_wifi7_dp_rx_process_msdu(struct ath12k_pdev_dp *dp_pdev,
}
ath12k_dp_rx_h_ppdu(dp_pdev, rx_info);
ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info);
ret = ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info);
if (ret)
goto free_out;
rx_info->rx_status->flag |= RX_FLAG_SKIP_MONITOR | RX_FLAG_DUP_VALIDATED;
@ -1028,12 +1045,14 @@ static int ath12k_wifi7_dp_rx_h_verify_tkip_mic(struct ath12k_pdev_dp *dp_pdev,
skb_pull(msdu, hal_rx_desc_sz);
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(dp, msdu,
rx_info)))
rx_info))) {
dev_kfree_skb_any(msdu);
return -EINVAL;
}
ath12k_dp_rx_h_ppdu(dp_pdev, rx_info);
ath12k_dp_rx_h_undecap(dp_pdev, msdu, HAL_ENCRYPT_TYPE_TKIP_MIC, true,
rx_info);
rx_info, NULL);
ieee80211_rx(ath12k_pdev_dp_to_hw(dp_pdev), msdu);
return -EINVAL;
}
@ -1588,6 +1607,7 @@ static int ath12k_wifi7_dp_rx_h_null_q_desc(struct ath12k_pdev_dp *dp_pdev,
u8 l3pad_bytes = rx_info->l3_pad_bytes;
struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
u32 hal_rx_desc_sz = dp->ab->hal.hal_desc_sz;
int ret;
if (!rxcb->is_frag && ((msdu_len + hal_rx_desc_sz) > DP_RX_BUFFER_SIZE)) {
/* First buffer will be freed by the caller, so deduct it's length */
@ -1632,7 +1652,9 @@ static int ath12k_wifi7_dp_rx_h_null_q_desc(struct ath12k_pdev_dp *dp_pdev,
return -EINVAL;
ath12k_dp_rx_h_ppdu(dp_pdev, rx_info);
ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info);
ret = ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info);
if (ret)
return ret;
rxcb->tid = rx_info->tid;
@ -1678,7 +1700,57 @@ static bool ath12k_wifi7_dp_rx_h_tkip_mic_err(struct ath12k_pdev_dp *dp_pdev,
RX_FLAG_DECRYPTED);
ath12k_dp_rx_h_undecap(dp_pdev, msdu, HAL_ENCRYPT_TYPE_TKIP_MIC, false,
rx_info);
rx_info, NULL);
return false;
}
static bool ath12k_wifi7_dp_rx_h_unauth_wds_err(struct ath12k_pdev_dp *dp_pdev,
struct sk_buff *msdu,
struct hal_rx_desc_data *rx_info)
{
struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu);
struct ath12k_dp *dp = dp_pdev->dp;
u32 hdr_len, hal_rx_desc_sz = dp->ab->hal.hal_desc_sz;
u8 l3pad_bytes = rx_info->l3_pad_bytes;
struct ath12k_dp_rx_rfc1042_hdr *llc;
u16 msdu_len = rx_info->msdu_len;
struct ath12k_dp_peer *peer;
struct ieee80211_hdr *hdr;
int ret;
guard(rcu)();
peer = ath12k_dp_peer_find_by_peerid(dp_pdev, rxcb->peer_id);
if (!peer) {
ath12k_dbg(dp->ab, ATH12K_DBG_DATA,
"failed to find the peer to process unauth wds err handling peer_id %d\n",
rxcb->peer_id);
return true;
}
if ((hal_rx_desc_sz + l3pad_bytes + msdu_len) > DP_RX_BUFFER_SIZE)
return true;
skb_put(msdu, hal_rx_desc_sz + l3pad_bytes + msdu_len);
skb_pull(msdu, hal_rx_desc_sz + l3pad_bytes);
if (unlikely(!ath12k_dp_rx_check_nwifi_hdr_len_valid(dp, msdu,
rx_info)))
return true;
ath12k_dp_rx_h_ppdu(dp_pdev, rx_info);
ret = ath12k_wifi7_dp_rx_h_mpdu(dp_pdev, msdu, rx_info);
if (ret)
return true;
rxcb->tid = rx_info->tid;
hdr = (struct ieee80211_hdr *)msdu->data;
hdr_len = ieee80211_hdrlen(hdr->frame_control);
llc = (struct ath12k_dp_rx_rfc1042_hdr *)(msdu->data + hdr_len);
if (llc->snap_type != cpu_to_be16(ETH_P_PAE))
return true;
return false;
}
@ -1693,6 +1765,9 @@ static bool ath12k_wifi7_dp_rx_h_rxdma_err(struct ath12k_pdev_dp *dp_pdev,
dp->device_stats.rxdma_error[rxcb->err_code]++;
switch (rxcb->err_code) {
case HAL_REO_ENTR_RING_RXDMA_ECODE_UNAUTH_WDS_ERR:
drop = ath12k_wifi7_dp_rx_h_unauth_wds_err(dp_pdev, msdu, rx_info);
break;
case HAL_REO_ENTR_RING_RXDMA_ECODE_DECRYPT_ERR:
case HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR:
if (rx_info->err_bitmap & HAL_RX_MPDU_ERR_TKIP_MIC) {

View File

@ -57,10 +57,12 @@ 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 sk_buff *skb, bool gsn_valid, int mcbc_gsn,
bool is_mcast)
struct ath12k_link_sta *arsta, struct sk_buff *skb,
bool gsn_valid, int mcbc_gsn, bool is_mcast)
{
struct ath12k_dp *dp = dp_pdev->dp;
struct ath12k_hal *hal = dp->hal;
@ -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,6 +130,19 @@ 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 (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);
}
if (dp_vif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags)) {
@ -140,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.
*/
@ -148,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);
@ -158,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)
ti.vdev_id += HTT_TX_MLO_MCAST_HOST_REINJECT_BASE_VDEV_ID;
ti.bss_ast_hash = dp_link_vif->ast_hash;
ti.bss_ast_idx = dp_link_vif->ast_idx;
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.dscp_tid_tbl_idx = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL &&

View File

@ -8,8 +8,8 @@
#define ATH12K_DP_TX_WIFI7_H
int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *arvif,
struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
bool is_mcast);
struct ath12k_link_sta *arsta, struct sk_buff *skb,
bool gsn_valid, int mcbc_gsn, bool is_mcast);
void ath12k_wifi7_dp_tx_completion_handler(struct ath12k_dp *dp, int ring_id);
u32 ath12k_wifi7_dp_tx_get_vdev_bank_config(struct ath12k_base *ab,
struct ath12k_link_vif *arvif);

View File

@ -184,6 +184,20 @@ static u8 ath12k_hal_rx_desc_get_l3_pad_bytes_qcc2072(struct hal_rx_desc *desc)
RX_MSDU_END_INFO5_L3_HDR_PADDING);
}
static inline
u8 ath12k_wifi7_hal_rx_h_from_ds_qcc2072(struct hal_rx_desc *desc)
{
return le16_get_bits(desc->u.qcc2072.msdu_end.info5,
RX_MSDU_END_INFO5_FROM_DS);
}
static inline
u8 ath12k_wifi7_hal_rx_h_to_ds_qcc2072(struct hal_rx_desc *desc)
{
return le16_get_bits(desc->u.qcc2072.msdu_end.info5,
RX_MSDU_END_INFO5_TO_DS);
}
static u32 ath12k_hal_rx_desc_get_mpdu_start_tag_qcc2072(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.qcc2072.mpdu_start_tag,
@ -397,6 +411,8 @@ static void ath12k_hal_extract_rx_desc_data_qcc2072(struct hal_rx_desc_data *rx_
rx_desc_data->seq_no = ath12k_hal_rx_desc_get_mpdu_start_seq_no_qcc2072(rx_desc);
rx_desc_data->msdu_len = ath12k_hal_rx_desc_get_msdu_len_qcc2072(ldesc);
rx_desc_data->sgi = ath12k_hal_rx_desc_get_msdu_sgi_qcc2072(rx_desc);
rx_desc_data->is_from_ds = ath12k_wifi7_hal_rx_h_from_ds_qcc2072(rx_desc);
rx_desc_data->is_to_ds = ath12k_wifi7_hal_rx_h_to_ds_qcc2072(rx_desc);
rx_desc_data->rate_mcs = ath12k_hal_rx_desc_get_msdu_rate_mcs_qcc2072(rx_desc);
rx_desc_data->bw = ath12k_hal_rx_desc_get_msdu_rx_bw_qcc2072(rx_desc);
rx_desc_data->phy_meta_data = ath12k_hal_rx_desc_get_msdu_freq_qcc2072(rx_desc);

View File

@ -699,6 +699,20 @@ u8 ath12k_hal_rx_desc_get_mpdu_tid_qcn9274(struct hal_rx_desc *desc)
RX_MSDU_END_INFO5_TID);
}
static inline
u8 ath12k_wifi7_hal_rx_h_from_ds_qcn9274(struct hal_rx_desc *desc)
{
return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5,
RX_MSDU_END_INFO5_FROM_DS);
}
static inline
u8 ath12k_wifi7_hal_rx_h_to_ds_qcn9274(struct hal_rx_desc *desc)
{
return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5,
RX_MSDU_END_INFO5_TO_DS);
}
static inline
u16 ath12k_hal_rx_desc_get_mpdu_peer_id_qcn9274(struct hal_rx_desc *desc)
{
@ -914,6 +928,8 @@ void ath12k_hal_extract_rx_desc_data_qcn9274(struct hal_rx_desc_data *rx_desc_da
rx_desc_data->seq_ctl_valid =
ath12k_hal_rx_desc_get_mpdu_seq_ctl_vld_qcn9274(rx_desc);
rx_desc_data->fc_valid = ath12k_hal_rx_desc_get_mpdu_fc_valid_qcn9274(rx_desc);
rx_desc_data->is_from_ds = ath12k_wifi7_hal_rx_h_from_ds_qcn9274(rx_desc);
rx_desc_data->is_to_ds = ath12k_wifi7_hal_rx_h_to_ds_qcn9274(rx_desc);
rx_desc_data->seq_no = ath12k_hal_rx_desc_get_mpdu_start_seq_no_qcn9274(rx_desc);
rx_desc_data->msdu_len = ath12k_hal_rx_desc_get_msdu_len_qcn9274(ldesc);
rx_desc_data->sgi = ath12k_hal_rx_desc_get_msdu_sgi_qcn9274(rx_desc);

View 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);

View 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 */

View File

@ -280,6 +280,20 @@ u8 ath12k_hal_rx_desc_get_l3_pad_bytes_wcn7850(struct hal_rx_desc *desc)
RX_MSDU_END_INFO5_L3_HDR_PADDING);
}
static inline
u8 ath12k_wifi7_hal_rx_h_from_ds_wcn7850(struct hal_rx_desc *desc)
{
return le16_get_bits(desc->u.wcn7850.msdu_end.info5,
RX_MSDU_END_INFO5_FROM_DS);
}
static inline
u8 ath12k_wifi7_hal_rx_h_to_ds_wcn7850(struct hal_rx_desc *desc)
{
return le16_get_bits(desc->u.wcn7850.msdu_end.info5,
RX_MSDU_END_INFO5_TO_DS);
}
static inline
bool ath12k_hal_rx_desc_encrypt_valid_wcn7850(struct hal_rx_desc *desc)
{
@ -599,6 +613,8 @@ void ath12k_hal_extract_rx_desc_data_wcn7850(struct hal_rx_desc_data *rx_desc_da
rx_desc_data->seq_no = ath12k_hal_rx_desc_get_mpdu_start_seq_no_wcn7850(rx_desc);
rx_desc_data->msdu_len = ath12k_hal_rx_desc_get_msdu_len_wcn7850(ldesc);
rx_desc_data->sgi = ath12k_hal_rx_desc_get_msdu_sgi_wcn7850(rx_desc);
rx_desc_data->is_from_ds = ath12k_wifi7_hal_rx_h_from_ds_wcn7850(rx_desc);
rx_desc_data->is_to_ds = ath12k_wifi7_hal_rx_h_to_ds_wcn7850(rx_desc);
rx_desc_data->rate_mcs = ath12k_hal_rx_desc_get_msdu_rate_mcs_wcn7850(rx_desc);
rx_desc_data->bw = ath12k_hal_rx_desc_get_msdu_rx_bw_wcn7850(rx_desc);
rx_desc_data->phy_meta_data = ath12k_hal_rx_desc_get_msdu_freq_wcn7850(rx_desc);

View File

@ -434,6 +434,11 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.current_cc_support = false,
.dp_primary_link_only = true,
.client = {
.max_client_single = 512,
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
},
{
.name = "wcn7850 hw2.0",
@ -520,6 +525,11 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.current_cc_support = true,
.dp_primary_link_only = false,
.client = {
.max_client_single = 512,
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
},
{
.name = "qcn9274 hw2.0",
@ -602,6 +612,11 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.current_cc_support = false,
.dp_primary_link_only = true,
.client = {
.max_client_single = 512,
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
},
{
.name = "ipq5332 hw1.0",
@ -677,6 +692,11 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.bdf_addr_offset = 0xC00000,
.dp_primary_link_only = true,
.client = {
.max_client_single = 256,
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
},
{
.name = "qcc2072 hw1.0",
@ -764,6 +784,11 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.current_cc_support = true,
.dp_primary_link_only = false,
.client = {
.max_client_single = 512,
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
},
{
.name = "ipq5424 hw1.0",
@ -843,6 +868,11 @@ static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
.current_cc_support = false,
.dp_primary_link_only = true,
.client = {
.max_client_single = 512,
.max_client_dbs = 128,
.max_client_dbs_sbs = 128,
},
},
};
@ -859,7 +889,9 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_key_conf *key = info->control.hw_key;
struct ieee80211_sta *sta = control->sta;
struct ath12k_link_sta *arsta = NULL;
struct ath12k_link_vif *tmp_arvif;
struct ath12k_sta *ahsta = NULL;
u32 info_flags = info->flags;
struct sk_buff *msdu_copied;
struct ath12k *ar, *tmp_ar;
@ -941,6 +973,12 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
if (!(info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP))
is_mcast = is_multicast_ether_addr(hdr->addr1);
if (sta) {
ahsta = ath12k_sta_to_ahsta(control->sta);
if (ahsta && ahsta->enable_4addr)
arsta = rcu_dereference(ahsta->link[link_id]);
}
/* This is case only for P2P_GO */
if (vif->type == NL80211_IFTYPE_AP && vif->p2p)
ath12k_mac_add_p2p_noa_ie(ar, vif, skb, is_prb_rsp);
@ -961,7 +999,7 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
if (!vif->valid_links || !is_mcast || is_dvlan ||
(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) ||
test_bit(ATH12K_FLAG_RAW_MODE, &ar->ab->dev_flags)) {
ret = ath12k_wifi7_dp_tx(dp_pdev, arvif, skb, false, 0, is_mcast);
ret = ath12k_wifi7_dp_tx(dp_pdev, arvif, arsta, skb, false, 0, is_mcast);
if (unlikely(ret)) {
ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret);
ieee80211_free_txskb(ar->ah->hw, skb);
@ -999,6 +1037,11 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
skb_cb->vif = vif;
skb_cb->ar = tmp_ar;
if (ahsta && ahsta->enable_4addr)
arsta = rcu_dereference(ahsta->link[link_id]);
else
arsta = NULL;
/* For open mode, skip peer find logic */
if (unlikely(!ahvif->dp_vif.key_cipher))
goto skip_peer_find;
@ -1030,7 +1073,7 @@ static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
spin_unlock_bh(&tmp_dp->dp_lock);
skip_peer_find:
ret = ath12k_wifi7_dp_tx(tmp_dp_pdev, tmp_arvif,
ret = ath12k_wifi7_dp_tx(tmp_dp_pdev, tmp_arvif, arsta,
msdu_copied, true, mcbc_gsn, is_mcast);
if (unlikely(ret)) {
if (ret == -ENOMEM) {
@ -1075,6 +1118,7 @@ static const struct ieee80211_ops ath12k_ops_wifi7 = {
.sta_state = ath12k_mac_op_sta_state,
.sta_set_txpwr = ath12k_mac_op_sta_set_txpwr,
.link_sta_rc_update = ath12k_mac_op_link_sta_rc_update,
.sta_set_4addr = ath12k_mac_op_sta_set_4addr,
.conf_tx = ath12k_mac_op_conf_tx,
.set_antenna = ath12k_mac_op_set_antenna,
.get_antenna = ath12k_mac_op_get_antenna,

View File

@ -4192,7 +4192,12 @@ 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);
if (tg_cfg->is_wds_null_frame_supported)
wmi_cfg->flags2 |=
cpu_to_le32(WMI_RSRC_CFG_FLAGS2_WDS_NULL_FRAME_SUPPORT);
}
static int ath12k_init_cmd_send(struct ath12k_wmi_pdev *wmi,
@ -4402,6 +4407,9 @@ int ath12k_wmi_cmd_init(struct ath12k_base *ab)
ab->wmi_ab.svc_map))
arg.res_cfg.is_reg_cc_ext_event_supported = true;
if (test_bit(WMI_TLV_SERVICE_WDS_NULL_FRAME_SUPPORT, ab->wmi_ab.svc_map))
arg.res_cfg.is_wds_null_frame_supported = true;
ab->hw_params->wmi_init(ab, &arg.res_cfg);
ab->wow.wmi_conf_rx_decap_mode = arg.res_cfg.rx_decap_mode;
@ -7223,7 +7231,11 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb)
struct ath12k_wmi_mgmt_rx_arg rx_ev = {};
struct ath12k *ar;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_sta *pubsta = NULL;
struct ath12k_dp_link_peer *peer;
struct ieee80211_hdr *hdr;
bool is_4addr_null_pkt;
struct ath12k_dp *dp;
u16 fc;
struct ieee80211_supported_band *sband;
s32 noise_floor;
@ -7298,6 +7310,38 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb)
hdr = (struct ieee80211_hdr *)skb->data;
fc = le16_to_cpu(hdr->frame_control);
is_4addr_null_pkt = (ieee80211_is_nullfunc(hdr->frame_control) ||
ieee80211_is_qos_nullfunc(hdr->frame_control)) &&
ieee80211_has_a4(hdr->frame_control);
/*
* Add check to drop frames other than 4-address NULL frame. Since
* firmware sends all NULL frames in this path (3-address and 4-address)
*/
if (ieee80211_is_data(hdr->frame_control) && !is_4addr_null_pkt) {
dev_kfree_skb(skb);
goto exit;
}
if (is_4addr_null_pkt) {
dp = ath12k_ab_to_dp(ar->ab);
spin_lock_bh(&dp->dp_lock);
peer = ath12k_dp_link_peer_find_by_pdev_and_addr(dp, ar->pdev_idx,
hdr->addr2);
if (!peer) {
spin_unlock_bh(&dp->dp_lock);
dev_kfree_skb(skb);
goto exit;
}
pubsta = peer->sta;
if (pubsta && pubsta->valid_links) {
status->link_valid = 1;
status->link_id = peer->link_id;
}
spin_unlock_bh(&dp->dp_lock);
goto send_rx;
}
/* Firmware is guaranteed to report all essential management frames via
* WMI while it can deliver some extra via HTT. Since there can be
* duplicates split the reporting wrt monitor/sniffing.
@ -7321,6 +7365,7 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb)
if (ieee80211_is_beacon(hdr->frame_control))
ath12k_mac_handle_beacon(ar, skb);
send_rx:
ath12k_dbg(ab, ATH12K_DBG_MGMT,
"event mgmt rx skb %p len %d ftype %02x stype %02x\n",
skb, skb->len,

View File

@ -2278,6 +2278,7 @@ enum wmi_tlv_service {
WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT = 365,
WMI_TLV_SERVICE_THERM_THROT_POUT_REDUCTION = 410,
WMI_TLV_SERVICE_WDS_NULL_FRAME_SUPPORT = 421,
WMI_TLV_SERVICE_IS_TARGET_IPA = 425,
WMI_TLV_SERVICE_THERM_THROT_TX_CHAIN_MASK = 426,
WMI_TLV_SERVICE_THERM_THROT_5_LEVELS = 429,
@ -2334,6 +2335,19 @@ 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,
};
enum wmi_peer_smps_state {
WMI_PEER_SMPS_PS_NONE = 0,
WMI_PEER_SMPS_STATIC = 1,
@ -2498,6 +2512,7 @@ struct ath12k_wmi_resource_config_arg {
u32 ema_max_vap_cnt;
u32 ema_max_profile_period;
bool is_reg_cc_ext_event_supported;
bool is_wds_null_frame_supported;
};
struct ath12k_wmi_init_cmd_arg {
@ -2554,6 +2569,8 @@ 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_FLAGS2_WDS_NULL_FRAME_SUPPORT BIT(22)
#define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18)
struct ath12k_wmi_resource_config_params {