2024-04-25 09:04:10

by Karthikeyan Periyasamy

[permalink] [raw]
Subject: [PATCH v3 0/3] wifi: ath12k: Refactor the hardware recovery procedures

Currently, hardware recovery procedure supports multi wiphy model. However,
to support single wiphy model, we need to refactor the hardware recovery
procedure. This patchset allows the logic to work both multi wiphy models
and future single wiphy models.

v3:
wifi: ath12k: Refactor the hardware recovery procedure
* Removed unnecessary conditional check
wifi: ath12k: Add lock to protect the hardware state
* Introduce auto guard mutex
v2:
- Rebased to ToT
- Renamed the lock name as per the kalle comments

Karthikeyan Periyasamy (3):
wifi: ath12k: Refactor the hardware recovery procedure
wifi: ath12k: Refactor the hardware state
wifi: ath12k: Add lock to protect the hardware state

drivers/net/wireless/ath/ath12k/core.c | 98 ++++++++++++++------------
drivers/net/wireless/ath/ath12k/core.h | 28 +++++---
drivers/net/wireless/ath/ath12k/mac.c | 88 +++++++++++++++--------
drivers/net/wireless/ath/ath12k/reg.c | 19 ++---
4 files changed, 141 insertions(+), 92 deletions(-)


base-commit: 326f8f68f28b0b831233acfabffb486a5b0f4717
--
2.34.1



2024-04-25 09:04:14

by Karthikeyan Periyasamy

[permalink] [raw]
Subject: [PATCH v3 1/3] wifi: ath12k: Refactor the hardware recovery procedure

Currently, in multi-wiphy models, the recovery handler access mac80211
HW from the radio/link structure. This will be incorrect for single wiphy
model, as they will hold multiple link/radio structures. To fix this,
access mac80211 HW based on the number of hardware in the SoC/chip. This
approach makes the recovery handler compatible with both multi wiphy and
single wiphy models.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Karthikeyan Periyasamy <[email protected]>
---
drivers/net/wireless/ath/ath12k/core.c | 119 +++++++++++++------------
drivers/net/wireless/ath/ath12k/mac.c | 23 +++--
2 files changed, 80 insertions(+), 62 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 6663f4e1792d..ae14614c3568 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -994,9 +994,8 @@ void ath12k_core_halt(struct ath12k *ar)
static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
{
struct ath12k *ar;
- struct ath12k_pdev *pdev;
struct ath12k_hw *ah;
- int i;
+ int i, j;

spin_lock_bh(&ab->base_lock);
ab->stats.fw_crash_counter++;
@@ -1006,35 +1005,34 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
set_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags);

for (i = 0; i < ab->num_hw; i++) {
- if (!ab->ah[i])
+ ah = ab->ah[i];
+ if (!ah)
continue;

- ah = ab->ah[i];
ieee80211_stop_queues(ah->hw);
- }

- for (i = 0; i < ab->num_radios; i++) {
- pdev = &ab->pdevs[i];
- ar = pdev->ar;
- if (!ar || ar->state == ATH12K_STATE_OFF)
- continue;
+ for (j = 0; j < ah->num_radio; j++) {
+ ar = &ah->radio[j];
+ if (ar->state == ATH12K_STATE_OFF)
+ continue;

- ath12k_mac_drain_tx(ar);
- complete(&ar->scan.started);
- complete(&ar->scan.completed);
- complete(&ar->scan.on_channel);
- complete(&ar->peer_assoc_done);
- complete(&ar->peer_delete_done);
- complete(&ar->install_key_done);
- complete(&ar->vdev_setup_done);
- complete(&ar->vdev_delete_done);
- complete(&ar->bss_survey_done);
-
- wake_up(&ar->dp.tx_empty_waitq);
- idr_for_each(&ar->txmgmt_idr,
- ath12k_mac_tx_mgmt_pending_free, ar);
- idr_destroy(&ar->txmgmt_idr);
- wake_up(&ar->txmgmt_empty_waitq);
+ ath12k_mac_drain_tx(ar);
+ complete(&ar->scan.started);
+ complete(&ar->scan.completed);
+ complete(&ar->scan.on_channel);
+ complete(&ar->peer_assoc_done);
+ complete(&ar->peer_delete_done);
+ complete(&ar->install_key_done);
+ complete(&ar->vdev_setup_done);
+ complete(&ar->vdev_delete_done);
+ complete(&ar->bss_survey_done);
+
+ wake_up(&ar->dp.tx_empty_waitq);
+ idr_for_each(&ar->txmgmt_idr,
+ ath12k_mac_tx_mgmt_pending_free, ar);
+ idr_destroy(&ar->txmgmt_idr);
+ wake_up(&ar->txmgmt_empty_waitq);
+ }
}

wake_up(&ab->wmi_ab.tx_credits_wq);
@@ -1043,41 +1041,52 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)

static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab)
{
+ struct ath12k_hw *ah;
struct ath12k *ar;
- struct ath12k_pdev *pdev;
- int i;
+ int i, j;
+ u8 restart_count;

- for (i = 0; i < ab->num_radios; i++) {
- pdev = &ab->pdevs[i];
- ar = pdev->ar;
- if (!ar || ar->state == ATH12K_STATE_OFF)
+ for (i = 0; i < ab->num_hw; i++) {
+ ah = ab->ah[i];
+ if (!ah)
continue;

- mutex_lock(&ar->conf_mutex);
-
- switch (ar->state) {
- case ATH12K_STATE_ON:
- ar->state = ATH12K_STATE_RESTARTING;
- ath12k_core_halt(ar);
- ieee80211_restart_hw(ath12k_ar_to_hw(ar));
- break;
- case ATH12K_STATE_OFF:
- ath12k_warn(ab,
- "cannot restart radio %d that hasn't been started\n",
- i);
- break;
- case ATH12K_STATE_RESTARTING:
- break;
- case ATH12K_STATE_RESTARTED:
- ar->state = ATH12K_STATE_WEDGED;
- fallthrough;
- case ATH12K_STATE_WEDGED:
- ath12k_warn(ab,
- "device is wedged, will not restart radio %d\n", i);
- break;
+ for (j = 0, restart_count = 0; j < ah->num_radio; j++) {
+ ar = &ah->radio[j];
+ if (ar->state == ATH12K_STATE_OFF)
+ continue;
+
+ mutex_lock(&ar->conf_mutex);
+
+ switch (ar->state) {
+ case ATH12K_STATE_ON:
+ ar->state = ATH12K_STATE_RESTARTING;
+ ath12k_core_halt(ar);
+ restart_count++;
+ break;
+ case ATH12K_STATE_OFF:
+ ath12k_warn(ab,
+ "cannot restart radio %d that hasn't been started\n",
+ j);
+ break;
+ case ATH12K_STATE_RESTARTING:
+ break;
+ case ATH12K_STATE_RESTARTED:
+ ar->state = ATH12K_STATE_WEDGED;
+ fallthrough;
+ case ATH12K_STATE_WEDGED:
+ ath12k_warn(ab,
+ "device is wedged, will not restart radio %d\n", j);
+ break;
+ }
+ mutex_unlock(&ar->conf_mutex);
}
- mutex_unlock(&ar->conf_mutex);
+
+ /* Restart after all the link/radio got restart */
+ if (restart_count == ah->num_radio)
+ ieee80211_restart_hw(ah->hw);
}
+
complete(&ab->driver_recovery);
}

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 56b1f8b6844e..27664845e990 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -7910,26 +7910,33 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
struct ath12k *ar;
struct ath12k_base *ab;
struct ath12k_vif *arvif;
- int recovery_count;
+ int recovery_count, i;

if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
return;

- ar = ath12k_ah_to_ar(ah, 0);
- ab = ar->ab;
+ for_each_ar(ah, ar, i) {
+ mutex_lock(&ar->conf_mutex);

- mutex_lock(&ar->conf_mutex);
+ if (ar->state != ATH12K_STATE_RESTARTED) {
+ mutex_unlock(&ar->conf_mutex);
+ continue;
+ }
+
+ ab = ar->ab;

- if (ar->state == ATH12K_STATE_RESTARTED) {
ath12k_warn(ar->ab, "pdev %d successfully recovered\n",
ar->pdev->pdev_id);
+
ar->state = ATH12K_STATE_ON;
ieee80211_wake_queues(hw);

if (ab->is_reset) {
recovery_count = atomic_inc_return(&ab->recovery_count);
+
ath12k_dbg(ab, ATH12K_DBG_BOOT, "recovery count %d\n",
recovery_count);
+
/* When there are multiple radios in an SOC,
* the recovery has to be done for each radio
*/
@@ -7948,6 +7955,7 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
arvif->key_cipher,
arvif->is_up,
arvif->vdev_type);
+
/* After trigger disconnect, then upper layer will
* trigger connect again, then the PN number of
* upper layer will be reset to keep up with AP
@@ -7957,13 +7965,14 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
arvif->vdev_type == WMI_VDEV_TYPE_STA &&
arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) {
ieee80211_hw_restart_disconnect(arvif->vif);
+
ath12k_dbg(ab, ATH12K_DBG_BOOT,
"restart disconnect\n");
}
}
- }

- mutex_unlock(&ar->conf_mutex);
+ mutex_unlock(&ar->conf_mutex);
+ }
}

static void
--
2.34.1


2024-04-25 09:04:20

by Karthikeyan Periyasamy

[permalink] [raw]
Subject: [PATCH v3 3/3] wifi: ath12k: Add lock to protect the hardware state

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 <[email protected]>
---
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(+)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index a685cfd6fd92..e9aabdb9341c 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -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);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index c4eb8b25398c..d833361948b7 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -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 *));
};

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 710ed8fa79fd..2626328056dd 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -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;
--
2.34.1


2024-04-25 09:04:27

by Karthikeyan Periyasamy

[permalink] [raw]
Subject: [PATCH v3 2/3] wifi: ath12k: Refactor the hardware state

Currently, in multi wiphy models, the mac80211 hardware state is maintained
within the radio/link structure. However, in single wiphy models, the
mac80211 hardware state is needed at the hardware abstraction layer
(ath12k_hw). Therefore, move the hardware state from the radio/link
structure to the hardware abstraction layer (ath12k_hw). Additionally,
update the naming convention of the state enums to enhance clarity and
consistency.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Karthikeyan Periyasamy <[email protected]>
---
drivers/net/wireless/ath/ath12k/core.c | 59 +++++++++++--------------
drivers/net/wireless/ath/ath12k/core.h | 22 ++++++----
drivers/net/wireless/ath/ath12k/mac.c | 61 ++++++++++++++------------
drivers/net/wireless/ath/ath12k/reg.c | 19 ++++----
4 files changed, 83 insertions(+), 78 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index ae14614c3568..a685cfd6fd92 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -1006,15 +1006,13 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)

for (i = 0; i < ab->num_hw; i++) {
ah = ab->ah[i];
- if (!ah)
+ if (!ah || ah->state == ATH12K_HW_STATE_OFF)
continue;

ieee80211_stop_queues(ah->hw);

for (j = 0; j < ah->num_radio; j++) {
ar = &ah->radio[j];
- if (ar->state == ATH12K_STATE_OFF)
- continue;

ath12k_mac_drain_tx(ar);
complete(&ar->scan.started);
@@ -1044,47 +1042,42 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab)
struct ath12k_hw *ah;
struct ath12k *ar;
int i, j;
- u8 restart_count;

for (i = 0; i < ab->num_hw; i++) {
ah = ab->ah[i];
- if (!ah)
+ if (!ah || ah->state == ATH12K_HW_STATE_OFF)
continue;

- for (j = 0, restart_count = 0; j < ah->num_radio; j++) {
- ar = &ah->radio[j];
- if (ar->state == ATH12K_STATE_OFF)
- continue;
+ switch (ah->state) {
+ case ATH12K_HW_STATE_ON:
+ ah->state = ATH12K_HW_STATE_RESTARTING;

- mutex_lock(&ar->conf_mutex);
+ for (j = 0; j < ah->num_radio; j++) {
+ ar = &ah->radio[j];

- switch (ar->state) {
- case ATH12K_STATE_ON:
- ar->state = ATH12K_STATE_RESTARTING;
+ mutex_lock(&ar->conf_mutex);
ath12k_core_halt(ar);
- restart_count++;
- break;
- case ATH12K_STATE_OFF:
- ath12k_warn(ab,
- "cannot restart radio %d that hasn't been started\n",
- j);
- break;
- case ATH12K_STATE_RESTARTING:
- break;
- case ATH12K_STATE_RESTARTED:
- ar->state = ATH12K_STATE_WEDGED;
- fallthrough;
- case ATH12K_STATE_WEDGED:
- ath12k_warn(ab,
- "device is wedged, will not restart radio %d\n", j);
- break;
+ mutex_unlock(&ar->conf_mutex);
}
- mutex_unlock(&ar->conf_mutex);
- }

- /* Restart after all the link/radio got restart */
- if (restart_count == ah->num_radio)
+ /* Restart after all the link/radio halt */
ieee80211_restart_hw(ah->hw);
+ break;
+ case ATH12K_HW_STATE_OFF:
+ ath12k_warn(ab,
+ "cannot restart hw %d that hasn't been started\n",
+ i);
+ break;
+ case ATH12K_HW_STATE_RESTARTING:
+ break;
+ case ATH12K_HW_STATE_RESTARTED:
+ ah->state = ATH12K_HW_STATE_WEDGED;
+ fallthrough;
+ case ATH12K_HW_STATE_WEDGED:
+ ath12k_warn(ab,
+ "device is wedged, will not restart hw %d\n", i);
+ break;
+ }
}

complete(&ab->driver_recovery);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 47dde4401210..c4eb8b25398c 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -457,12 +457,12 @@ struct ath12k_sta {
#define ATH12K_NUM_CHANS 100
#define ATH12K_MAX_5G_CHAN 173

-enum ath12k_state {
- ATH12K_STATE_OFF,
- ATH12K_STATE_ON,
- ATH12K_STATE_RESTARTING,
- ATH12K_STATE_RESTARTED,
- ATH12K_STATE_WEDGED,
+enum ath12k_hw_state {
+ ATH12K_HW_STATE_OFF,
+ ATH12K_HW_STATE_ON,
+ ATH12K_HW_STATE_RESTARTING,
+ ATH12K_HW_STATE_RESTARTED,
+ ATH12K_HW_STATE_WEDGED,
/* Add other states as required */
};

@@ -511,7 +511,6 @@ struct ath12k {
u32 ht_cap_info;
u32 vht_cap_info;
struct ath12k_he ar_he;
- enum ath12k_state state;
bool supports_6ghz;
struct {
struct completion started;
@@ -636,10 +635,12 @@ struct ath12k {

struct ath12k_hw {
struct ieee80211_hw *hw;
+ struct ath12k_base *ab;
+ enum ath12k_hw_state state;
bool regd_updated;
bool use_6ghz_regd;
-
u8 num_radio;
+
struct ath12k radio[] __aligned(sizeof(void *));
};

@@ -1037,6 +1038,11 @@ static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah, u8 hw_link_id
return &ah->radio[hw_link_id];
}

+static inline struct ath12k_hw *ath12k_ar_to_ah(struct ath12k *ar)
+{
+ return ar->ah;
+}
+
static inline struct ieee80211_hw *ath12k_ar_to_hw(struct ath12k *ar)
{
return ar->ah->hw;
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 27664845e990..710ed8fa79fd 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5269,6 +5269,7 @@ static void ath12k_mac_setup_sband_iftype_data(struct ath12k *ar,

static int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant)
{
+ struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
int ret;

lockdep_assert_held(&ar->conf_mutex);
@@ -5289,8 +5290,8 @@ static int __ath12k_set_antenna(struct ath12k *ar, u32 tx_ant, u32 rx_ant)
ar->cfg_tx_chainmask = tx_ant;
ar->cfg_rx_chainmask = rx_ant;

- if (ar->state != ATH12K_STATE_ON &&
- ar->state != ATH12K_STATE_RESTARTED)
+ if (ah->state != ATH12K_HW_STATE_ON &&
+ ah->state != ATH12K_HW_STATE_RESTARTED)
return 0;

ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_TX_CHAIN_MASK,
@@ -5620,22 +5621,6 @@ static int ath12k_mac_start(struct ath12k *ar)

mutex_lock(&ar->conf_mutex);

- switch (ar->state) {
- case ATH12K_STATE_OFF:
- ar->state = ATH12K_STATE_ON;
- break;
- case ATH12K_STATE_RESTARTING:
- ar->state = ATH12K_STATE_RESTARTED;
- ath12k_mac_wait_reconfigure(ab);
- break;
- case ATH12K_STATE_RESTARTED:
- case ATH12K_STATE_WEDGED:
- case ATH12K_STATE_ON:
- WARN_ON(1);
- ret = -EINVAL;
- goto err;
- }
-
ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_PMF_QOS,
1, pdev->pdev_id);

@@ -5726,7 +5711,6 @@ static int ath12k_mac_start(struct ath12k *ar)

return 0;
err:
- ar->state = ATH12K_STATE_OFF;
mutex_unlock(&ar->conf_mutex);

return ret;
@@ -5749,9 +5733,28 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)

ath12k_drain_tx(ah);

+ switch (ah->state) {
+ case ATH12K_HW_STATE_OFF:
+ ah->state = ATH12K_HW_STATE_ON;
+ break;
+ case ATH12K_HW_STATE_RESTARTING:
+ ah->state = ATH12K_HW_STATE_RESTARTED;
+ ath12k_mac_wait_reconfigure(ah->ab);
+ break;
+ case ATH12K_HW_STATE_RESTARTED:
+ case ATH12K_HW_STATE_WEDGED:
+ case ATH12K_HW_STATE_ON:
+ ah->state = ATH12K_HW_STATE_OFF;
+
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
for_each_ar(ah, ar, i) {
ret = ath12k_mac_start(ar);
if (ret) {
+ ah->state = ATH12K_HW_STATE_OFF;
+
ath12k_err(ar->ab, "fail to start mac operations in pdev idx %d ret %d\n",
ar->pdev_idx, ret);
goto fail_start;
@@ -5759,11 +5762,13 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
}

return 0;
+
fail_start:
for (; i > 0; i--) {
ar = ath12k_ah_to_ar(ah, i - 1);
ath12k_mac_stop(ar);
}
+
return ret;
}

@@ -5836,7 +5841,6 @@ static void ath12k_mac_stop(struct ath12k *ar)
ret);

clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags);
- ar->state = ATH12K_STATE_OFF;
mutex_unlock(&ar->conf_mutex);

cancel_delayed_work_sync(&ar->scan.timeout);
@@ -5865,6 +5869,8 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw)

ath12k_drain_tx(ah);

+ ah->state = ATH12K_HW_STATE_OFF;
+
for_each_ar(ah, ar, i)
ath12k_mac_stop(ar);
}
@@ -7915,22 +7921,20 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
return;

+ if (ah->state != ATH12K_HW_STATE_RESTARTED)
+ return;
+
+ ah->state = ATH12K_HW_STATE_ON;
+ ieee80211_wake_queues(hw);
+
for_each_ar(ah, ar, i) {
mutex_lock(&ar->conf_mutex);

- if (ar->state != ATH12K_STATE_RESTARTED) {
- mutex_unlock(&ar->conf_mutex);
- continue;
- }
-
ab = ar->ab;

ath12k_warn(ar->ab, "pdev %d successfully recovered\n",
ar->pdev->pdev_id);

- ar->state = ATH12K_STATE_ON;
- ieee80211_wake_queues(hw);
-
if (ab->is_reset) {
recovery_count = atomic_inc_return(&ab->recovery_count);

@@ -8916,6 +8920,7 @@ static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab,

ah = ath12k_hw_to_ah(hw);
ah->hw = hw;
+ ah->ab = ab;
ah->num_radio = num_pdev_map;

for (i = 0; i < num_pdev_map; i++) {
diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index fbf38044938c..439d61f284d8 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -206,9 +206,9 @@ static void ath12k_copy_regd(struct ieee80211_regdomain *regd_orig,

int ath12k_regd_update(struct ath12k *ar, bool init)
{
- struct ieee80211_hw *hw = ath12k_ar_to_hw(ar);
+ struct ath12k_hw *ah = ath12k_ar_to_ah(ar);
+ struct ieee80211_hw *hw = ah->hw;
struct ieee80211_regdomain *regd, *regd_copy = NULL;
- struct ath12k_hw *ah = ar->ah;
int ret, regd_len, pdev_id;
struct ath12k_base *ab;
int i;
@@ -286,19 +286,20 @@ int ath12k_regd_update(struct ath12k *ar, bool init)
if (ret)
goto err;

+ if (ah->state != ATH12K_HW_STATE_ON)
+ goto skip;
+
ah->regd_updated = true;
/* Apply the new regd to all the radios, this is expected to be received only once
* since we check for ah->regd_updated and allow here only once.
*/
for_each_ar(ah, ar, i) {
- if (ar->state == ATH12K_STATE_ON) {
- ab = ar->ab;
- ret = ath12k_reg_update_chan_list(ar);
- if (ret)
- goto err;
- }
+ ab = ar->ab;
+ ret = ath12k_reg_update_chan_list(ar);
+ if (ret)
+ goto err;
}
-
+skip:
return 0;
err:
ath12k_warn(ab, "failed to perform regd update : %d\n", ret);
--
2.34.1


2024-04-25 21:09:52

by Jeff Johnson

[permalink] [raw]
Subject: Re: [PATCH v3 1/3] wifi: ath12k: Refactor the hardware recovery procedure

On 4/25/2024 2:03 AM, Karthikeyan Periyasamy wrote:
> Currently, in multi-wiphy models, the recovery handler access mac80211
> HW from the radio/link structure. This will be incorrect for single wiphy
> model, as they will hold multiple link/radio structures. To fix this,
> access mac80211 HW based on the number of hardware in the SoC/chip. This
> approach makes the recovery handler compatible with both multi wiphy and
> single wiphy models.
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>
> Signed-off-by: Karthikeyan Periyasamy <[email protected]>

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

Acked-by: Jeff Johnson <[email protected]>


2024-04-25 21:11:25

by Jeff Johnson

[permalink] [raw]
Subject: Re: [PATCH v3 2/3] wifi: ath12k: Refactor the hardware state

On 4/25/2024 2:03 AM, Karthikeyan Periyasamy wrote:
> Currently, in multi wiphy models, the mac80211 hardware state is maintained
> within the radio/link structure. However, in single wiphy models, the
> mac80211 hardware state is needed at the hardware abstraction layer
> (ath12k_hw). Therefore, move the hardware state from the radio/link
> structure to the hardware abstraction layer (ath12k_hw). Additionally,
> update the naming convention of the state enums to enhance clarity and
> consistency.
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>
> Signed-off-by: Karthikeyan Periyasamy <[email protected]>

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

Acked-by: Jeff Johnson <[email protected]>


2024-04-25 21:16:36

by Jeff Johnson

[permalink] [raw]
Subject: Re: [PATCH v3 3/3] wifi: ath12k: Add lock to protect the hardware state

On 4/25/2024 2:03 AM, Karthikeyan Periyasamy wrote:
> 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 <[email protected]>

I know there are concerns with adding a new lock, however this design has
already been productized with QSDK/OpenWrt, so the current goal is to get
upstream on par with QSDK/OpenWrt, and after that we can revisit the locking
model.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3

Acked-by: Jeff Johnson <[email protected]>


2024-05-03 13:12:36

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v3 1/3] wifi: ath12k: Refactor the hardware recovery procedure

Karthikeyan Periyasamy <[email protected]> wrote:

> Currently, in multi-wiphy models, the recovery handler access mac80211
> HW from the radio/link structure. This will be incorrect for single wiphy
> model, as they will hold multiple link/radio structures. To fix this,
> access mac80211 HW based on the number of hardware in the SoC/chip. This
> approach makes the recovery handler compatible with both multi wiphy and
> single wiphy models.
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>
> Signed-off-by: Karthikeyan Periyasamy <[email protected]>
> Acked-by: Jeff Johnson <[email protected]>
> Signed-off-by: Kalle Valo <[email protected]>

3 patches applied to ath-next branch of ath.git, thanks.

ecd509b6f263 wifi: ath12k: Refactor the hardware recovery procedure
9b4e5caaf590 wifi: ath12k: Refactor the hardware state
acaa84009fad wifi: ath12k: Add lock to protect the hardware state

--
https://patchwork.kernel.org/project/linux-wireless/patch/[email protected]/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches