Commit dcdb05a4 authored by Maharaja Kennadyrajan's avatar Maharaja Kennadyrajan Committed by Jeff Johnson
Browse files

wifi: ath12k: Extend beacon miss handling for MLO non-AP STA



Currently, ath12k_mac_handle_beacon_miss() does not handle the beacon
miss for the MLO case.

In MLO scenarios, the host fails to process the beacon miss because the
vdev_id comparison in ath12k_mac_handle_beacon_miss_iter() does not match.
This mismatch occurs since arvif always points to ahvif->deflink, which may
not correspond to the actual vdev_id associated with the event.

Fix this by retrieving arvif from vdev_id instead of ahvif->deflink which
will work for both MLO and Non-MLO case.

Also refactor the ath12k_mac_handle_beacon_miss(), by passing arvif
directly instead of vdev_id and remove ath12k_mac_handle_beacon_miss_iter()
which is no longer needed.

ath12k_mac_handle_beacon_miss() is called from ath12k_roam_event() for WCN
chipsets and ath12k_peer_sta_kickout_event() for QCN chipsets.

So, refactor the ath12k_roam_event() to pass arvif instead vdev_id to the
ath12k_mac_handle_beacon_miss() function to align with the
ath12k_peer_sta_kickout_event() and change the rcu_read_lock() to
guard(rcu)() in the same function ath12k_roam_event().

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00284-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1

Co-developed-by: default avatarAditya Kumar Singh <aditya.kumar.singh@oss.qualcomm.com>
Signed-off-by: default avatarAditya Kumar Singh <aditya.kumar.singh@oss.qualcomm.com>
Signed-off-by: default avatarMaharaja Kennadyrajan <maharaja.kennadyrajan@oss.qualcomm.com>
Reviewed-by: default avatarBaochen Qiang <baochen.qiang@oss.qualcomm.com>
Reviewed-by: default avatarVasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Link: https://patch.msgid.link/20250812111708.3686-4-maharaja.kennadyrajan@oss.qualcomm.com


Signed-off-by: default avatarJeff Johnson <jeff.johnson@oss.qualcomm.com>
parent 9891fbd9
Loading
Loading
Loading
Loading
+5 −19
Original line number Diff line number Diff line
@@ -1822,22 +1822,16 @@ void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb)
						   skb);
}

static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
					       struct ieee80211_vif *vif)
void ath12k_mac_handle_beacon_miss(struct ath12k *ar,
				   struct ath12k_link_vif *arvif)
{
	u32 *vdev_id = data;
	struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
	struct ath12k_link_vif *arvif = &ahvif->deflink;
	struct ieee80211_hw *hw;

	if (!arvif->is_created || arvif->vdev_id != *vdev_id)
		return;
	struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
	struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);

	if (!arvif->is_up)
	if (!(arvif->is_created && arvif->is_up))
		return;

	ieee80211_beacon_loss(vif);
	hw = ath12k_ar_to_hw(arvif->ar);

	/* Firmware doesn't report beacon loss events repeatedly. If AP probe
	 * (done by mac80211) succeeds but beacons do not resume then it
@@ -1848,14 +1842,6 @@ static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac,
				     ATH12K_CONNECTION_LOSS_HZ);
}

void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id)
{
	ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar),
						   IEEE80211_IFACE_ITER_NORMAL,
						   ath12k_mac_handle_beacon_miss_iter,
						   &vdev_id);
}

static void ath12k_mac_vif_sta_connection_loss_work(struct work_struct *work)
{
	struct ath12k_link_vif *arvif = container_of(work, struct ath12k_link_vif,
+2 −1
Original line number Diff line number Diff line
@@ -168,7 +168,8 @@ int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable);
int ath12k_mac_rfkill_config(struct ath12k *ar);
int ath12k_mac_wait_tx_complete(struct ath12k *ar);
void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb);
void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id);
void ath12k_mac_handle_beacon_miss(struct ath12k *ar,
				   struct ath12k_link_vif *arvif);
int ath12k_mac_vif_set_keepalive(struct ath12k_link_vif *arvif,
				 enum wmi_sta_keepalive_method method,
				 u32 interval);
+25 −12
Original line number Diff line number Diff line
@@ -7308,6 +7308,7 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff
	struct ath12k_link_vif *arvif;
	struct ieee80211_sta *sta;
	struct ath12k_peer *peer;
	unsigned int link_id;
	struct ath12k *ar;

	if (ath12k_pull_peer_sta_kickout_ev(ab, skb, &arg) != 0) {
@@ -7336,11 +7337,23 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff

	ar = arvif->ar;

	if (peer->mlo) {
		sta = ieee80211_find_sta_by_link_addrs(ath12k_ar_to_hw(ar),
						       arg.mac_addr,
						       NULL, &link_id);
		if (peer->link_id != link_id) {
			ath12k_warn(ab,
				    "Spurious quick kickout for MLO STA %pM with invalid link_id, peer: %d, sta: %d\n",
				    arg.mac_addr, peer->link_id, link_id);
			goto exit;
		}
	} else {
		sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
						   arg.mac_addr, NULL);
	}
	if (!sta) {
		ath12k_warn(ab, "Spurious quick kickout for STA %pM\n",
			    arg.mac_addr);
		ath12k_warn(ab, "Spurious quick kickout for %sSTA %pM\n",
			    peer->mlo ? "MLO " : "", arg.mac_addr);
		goto exit;
	}

@@ -7351,7 +7364,7 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff
	switch (arg.reason) {
	case WMI_PEER_STA_KICKOUT_REASON_INACTIVITY:
		if (arvif->ahvif->vif->type == NL80211_IFTYPE_STATION) {
			ath12k_mac_handle_beacon_miss(ar, peer->vdev_id);
			ath12k_mac_handle_beacon_miss(ar, arvif);
			break;
		}
		fallthrough;
@@ -7366,6 +7379,7 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff

static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb)
{
	struct ath12k_link_vif *arvif;
	struct wmi_roam_event roam_ev = {};
	struct ath12k *ar;
	u32 vdev_id;
@@ -7384,21 +7398,22 @@ static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb)
		   "wmi roam event vdev %u reason %d rssi %d\n",
		   vdev_id, roam_reason, roam_ev.rssi);

	rcu_read_lock();
	ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id);
	if (!ar) {
	guard(rcu)();
	arvif = ath12k_mac_get_arvif_by_vdev_id(ab, vdev_id);
	if (!arvif) {
		ath12k_warn(ab, "invalid vdev id in roam ev %d", vdev_id);
		rcu_read_unlock();
		return;
	}

	ar = arvif->ar;

	if (roam_reason >= WMI_ROAM_REASON_MAX)
		ath12k_warn(ab, "ignoring unknown roam event reason %d on vdev %i\n",
			    roam_reason, vdev_id);

	switch (roam_reason) {
	case WMI_ROAM_REASON_BEACON_MISS:
		ath12k_mac_handle_beacon_miss(ar, vdev_id);
		ath12k_mac_handle_beacon_miss(ar, arvif);
		break;
	case WMI_ROAM_REASON_BETTER_AP:
	case WMI_ROAM_REASON_LOW_RSSI:
@@ -7408,8 +7423,6 @@ static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb)
			    roam_reason, vdev_id);
		break;
	}

	rcu_read_unlock();
}

static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb)