Commit 8a1e2fd8 authored by Martin Blumenstingl's avatar Martin Blumenstingl Committed by Kalle Valo
Browse files

wifi: rtw88: Move register access from rtw_bf_assoc() outside the RCU



USB and (upcoming) SDIO support may sleep in the read/write handlers.
Shrink the RCU critical section so it only cover the call to
ieee80211_find_sta() and finding the ic_vht_cap/vht_cap based on the
found station. This moves the chip's BFEE configuration outside the
rcu_read_lock section and thus prevent "scheduling while atomic" or
"Voluntary context switch within RCU read-side critical section!"
warnings when accessing the registers using an SDIO card (which is
where this issue has been spotted in the real world - but it also
affects USB cards).

Reviewed-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Tested-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: default avatarMartin Blumenstingl <martin.blumenstingl@googlemail.com>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20230108211324.442823-2-martin.blumenstingl@googlemail.com
parent 2a86aa9a
Loading
Loading
Loading
Loading
+7 −6
Original line number Diff line number Diff line
@@ -49,19 +49,23 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,

	sta = ieee80211_find_sta(vif, bssid);
	if (!sta) {
		rcu_read_unlock();

		rtw_warn(rtwdev, "failed to find station entry for bss %pM\n",
			 bssid);
		goto out_unlock;
		return;
	}

	ic_vht_cap = &hw->wiphy->bands[NL80211_BAND_5GHZ]->vht_cap;
	vht_cap = &sta->deflink.vht_cap;

	rcu_read_unlock();

	if ((ic_vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) &&
	    (vht_cap->cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE)) {
		if (bfinfo->bfer_mu_cnt >= chip->bfer_mu_max_num) {
			rtw_dbg(rtwdev, RTW_DBG_BF, "mu bfer number over limit\n");
			goto out_unlock;
			return;
		}

		ether_addr_copy(bfee->mac_addr, bssid);
@@ -75,7 +79,7 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,
		   (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE)) {
		if (bfinfo->bfer_su_cnt >= chip->bfer_su_max_num) {
			rtw_dbg(rtwdev, RTW_DBG_BF, "su bfer number over limit\n");
			goto out_unlock;
			return;
		}

		sound_dim = vht_cap->cap &
@@ -98,9 +102,6 @@ void rtw_bf_assoc(struct rtw_dev *rtwdev, struct ieee80211_vif *vif,

		rtw_chip_config_bfee(rtwdev, rtwvif, bfee, true);
	}

out_unlock:
	rcu_read_unlock();
}

void rtw_bf_init_bfer_entry_mu(struct rtw_dev *rtwdev,