@@ -1048,6 +1048,8 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab)
if (!ah || ah->state == ATH12K_HW_STATE_OFF)
continue;
+ mutex_lock(&ah->hw_mutex);
+
switch (ah->state) {
case ATH12K_HW_STATE_ON:
ah->state = ATH12K_HW_STATE_RESTARTING;
@@ -1078,6 +1080,8 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab)
"device is wedged, will not restart hw %d\n", i);
break;
}
+
+ mutex_unlock(&ah->hw_mutex);
}
complete(&ab->driver_recovery);
@@ -636,11 +636,17 @@ struct ath12k {
struct ath12k_hw {
struct ieee80211_hw *hw;
struct ath12k_base *ab;
+
+ /* Protect the write operation of the hardware state ath12k_hw::state
+ * between hardware start<=>reconfigure<=>stop transitions.
+ */
+ struct mutex hw_mutex;
enum ath12k_hw_state state;
bool regd_updated;
bool use_6ghz_regd;
u8 num_radio;
+ /* Keep last */
struct ath12k radio[] __aligned(sizeof(void *));
};
@@ -5615,10 +5615,13 @@ static void ath12k_mac_wait_reconfigure(struct ath12k_base *ab)
static int ath12k_mac_start(struct ath12k *ar)
{
+ struct ath12k_hw *ah = ar->ah;
struct ath12k_base *ab = ar->ab;
struct ath12k_pdev *pdev = ar->pdev;
int ret;
+ lockdep_assert_held(&ah->hw_mutex);
+
mutex_lock(&ar->conf_mutex);
ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS,
@@ -5733,6 +5736,8 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
ath12k_drain_tx(ah);
+ guard(mutex)(&ah->hw_mutex);
+
switch (ah->state) {
case ATH12K_HW_STATE_OFF:
ah->state = ATH12K_HW_STATE_ON;
@@ -5831,9 +5836,12 @@ int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable)
static void ath12k_mac_stop(struct ath12k *ar)
{
+ struct ath12k_hw *ah = ar->ah;
struct htt_ppdu_stats_info *ppdu_stats, *tmp;
int ret;
+ lockdep_assert_held(&ah->hw_mutex);
+
mutex_lock(&ar->conf_mutex);
ret = ath12k_mac_config_mon_status_default(ar, false);
if (ret && (ret != -EOPNOTSUPP))
@@ -5869,10 +5877,14 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
ath12k_drain_tx(ah);
+ mutex_lock(&ah->hw_mutex);
+
ah->state = ATH12K_HW_STATE_OFF;
for_each_ar(ah, ar, i)
ath12k_mac_stop(ar);
+
+ mutex_unlock(&ah->hw_mutex);
}
static u8
@@ -7921,6 +7933,8 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
return;
+ guard(mutex)(&ah->hw_mutex);
+
if (ah->state != ATH12K_HW_STATE_RESTARTED)
return;
@@ -8923,6 +8937,8 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab,
ah->ab = ab;
ah->num_radio = num_pdev_map;
+ mutex_init(&ah->hw_mutex);
+
for (i = 0; i < num_pdev_map; i++) {
ab = pdev_map[i].ab;
pdev_idx = pdev_map[i].pdev_idx;
Currently, hardware state is not protected across the reconfigure operations. However, in single wiphy models, multiple radio/links is exposed as a MAC hardware (ieee80211_hw) through the driver hardware abstraction (ath12k_hw) layer. In such scenario, we need to protect hardware state across the multiple radio/link at the driver hardware abstraction (ath12k_hw) layer. Therefore, introduce a new mutex in the ath12k_hw layer. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1 Signed-off-by: Karthikeyan Periyasamy <quic_periyasa@quicinc.com> --- drivers/net/wireless/ath/ath12k/core.c | 4 ++++ drivers/net/wireless/ath/ath12k/core.h | 6 ++++++ drivers/net/wireless/ath/ath12k/mac.c | 16 ++++++++++++++++ 3 files changed, 26 insertions(+)