Commit ecd509b6 authored by Karthikeyan Periyasamy's avatar Karthikeyan Periyasamy Committed by Kalle Valo

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: default avatarKarthikeyan Periyasamy <quic_periyasa@quicinc.com>
Acked-by: default avatarJeff Johnson <quic_jjohnson@quicinc.com>
Signed-off-by: default avatarKalle Valo <quic_kvalo@quicinc.com>
Link: https://msgid.link/20240425090307.3233434-2-quic_periyasa@quicinc.com
parent f41c7cab
...@@ -994,9 +994,8 @@ void ath12k_core_halt(struct ath12k *ar) ...@@ -994,9 +994,8 @@ void ath12k_core_halt(struct ath12k *ar)
static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
{ {
struct ath12k *ar; struct ath12k *ar;
struct ath12k_pdev *pdev;
struct ath12k_hw *ah; struct ath12k_hw *ah;
int i; int i, j;
spin_lock_bh(&ab->base_lock); spin_lock_bh(&ab->base_lock);
ab->stats.fw_crash_counter++; ab->stats.fw_crash_counter++;
...@@ -1006,35 +1005,34 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) ...@@ -1006,35 +1005,34 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
set_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags); set_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags);
for (i = 0; i < ab->num_hw; i++) { for (i = 0; i < ab->num_hw; i++) {
if (!ab->ah[i]) ah = ab->ah[i];
if (!ah)
continue; continue;
ah = ab->ah[i];
ieee80211_stop_queues(ah->hw); ieee80211_stop_queues(ah->hw);
}
for (i = 0; i < ab->num_radios; i++) { for (j = 0; j < ah->num_radio; j++) {
pdev = &ab->pdevs[i]; ar = &ah->radio[j];
ar = pdev->ar; if (ar->state == ATH12K_STATE_OFF)
if (!ar || ar->state == ATH12K_STATE_OFF) continue;
continue;
ath12k_mac_drain_tx(ar); ath12k_mac_drain_tx(ar);
complete(&ar->scan.started); complete(&ar->scan.started);
complete(&ar->scan.completed); complete(&ar->scan.completed);
complete(&ar->scan.on_channel); complete(&ar->scan.on_channel);
complete(&ar->peer_assoc_done); complete(&ar->peer_assoc_done);
complete(&ar->peer_delete_done); complete(&ar->peer_delete_done);
complete(&ar->install_key_done); complete(&ar->install_key_done);
complete(&ar->vdev_setup_done); complete(&ar->vdev_setup_done);
complete(&ar->vdev_delete_done); complete(&ar->vdev_delete_done);
complete(&ar->bss_survey_done); complete(&ar->bss_survey_done);
wake_up(&ar->dp.tx_empty_waitq); wake_up(&ar->dp.tx_empty_waitq);
idr_for_each(&ar->txmgmt_idr, idr_for_each(&ar->txmgmt_idr,
ath12k_mac_tx_mgmt_pending_free, ar); ath12k_mac_tx_mgmt_pending_free, ar);
idr_destroy(&ar->txmgmt_idr); idr_destroy(&ar->txmgmt_idr);
wake_up(&ar->txmgmt_empty_waitq); wake_up(&ar->txmgmt_empty_waitq);
}
} }
wake_up(&ab->wmi_ab.tx_credits_wq); wake_up(&ab->wmi_ab.tx_credits_wq);
...@@ -1043,41 +1041,52 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) ...@@ -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) static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab)
{ {
struct ath12k_hw *ah;
struct ath12k *ar; struct ath12k *ar;
struct ath12k_pdev *pdev; int i, j;
int i; u8 restart_count;
for (i = 0; i < ab->num_radios; i++) { for (i = 0; i < ab->num_hw; i++) {
pdev = &ab->pdevs[i]; ah = ab->ah[i];
ar = pdev->ar; if (!ah)
if (!ar || ar->state == ATH12K_STATE_OFF)
continue; continue;
mutex_lock(&ar->conf_mutex); for (j = 0, restart_count = 0; j < ah->num_radio; j++) {
ar = &ah->radio[j];
switch (ar->state) { if (ar->state == ATH12K_STATE_OFF)
case ATH12K_STATE_ON: continue;
ar->state = ATH12K_STATE_RESTARTING;
ath12k_core_halt(ar); mutex_lock(&ar->conf_mutex);
ieee80211_restart_hw(ath12k_ar_to_hw(ar));
break; switch (ar->state) {
case ATH12K_STATE_OFF: case ATH12K_STATE_ON:
ath12k_warn(ab, ar->state = ATH12K_STATE_RESTARTING;
"cannot restart radio %d that hasn't been started\n", ath12k_core_halt(ar);
i); restart_count++;
break; break;
case ATH12K_STATE_RESTARTING: case ATH12K_STATE_OFF:
break; ath12k_warn(ab,
case ATH12K_STATE_RESTARTED: "cannot restart radio %d that hasn't been started\n",
ar->state = ATH12K_STATE_WEDGED; j);
fallthrough; break;
case ATH12K_STATE_WEDGED: case ATH12K_STATE_RESTARTING:
ath12k_warn(ab, break;
"device is wedged, will not restart radio %d\n", i); case ATH12K_STATE_RESTARTED:
break; 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); complete(&ab->driver_recovery);
} }
......
...@@ -7920,26 +7920,33 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, ...@@ -7920,26 +7920,33 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
struct ath12k *ar; struct ath12k *ar;
struct ath12k_base *ab; struct ath12k_base *ab;
struct ath12k_vif *arvif; struct ath12k_vif *arvif;
int recovery_count; int recovery_count, i;
if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
return; return;
ar = ath12k_ah_to_ar(ah, 0); for_each_ar(ah, ar, i) {
ab = ar->ab; 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", ath12k_warn(ar->ab, "pdev %d successfully recovered\n",
ar->pdev->pdev_id); ar->pdev->pdev_id);
ar->state = ATH12K_STATE_ON; ar->state = ATH12K_STATE_ON;
ieee80211_wake_queues(hw); ieee80211_wake_queues(hw);
if (ab->is_reset) { if (ab->is_reset) {
recovery_count = atomic_inc_return(&ab->recovery_count); recovery_count = atomic_inc_return(&ab->recovery_count);
ath12k_dbg(ab, ATH12K_DBG_BOOT, "recovery count %d\n", ath12k_dbg(ab, ATH12K_DBG_BOOT, "recovery count %d\n",
recovery_count); recovery_count);
/* When there are multiple radios in an SOC, /* When there are multiple radios in an SOC,
* the recovery has to be done for each radio * the recovery has to be done for each radio
*/ */
...@@ -7958,6 +7965,7 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, ...@@ -7958,6 +7965,7 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
arvif->key_cipher, arvif->key_cipher,
arvif->is_up, arvif->is_up,
arvif->vdev_type); arvif->vdev_type);
/* After trigger disconnect, then upper layer will /* After trigger disconnect, then upper layer will
* trigger connect again, then the PN number of * trigger connect again, then the PN number of
* upper layer will be reset to keep up with AP * upper layer will be reset to keep up with AP
...@@ -7967,13 +7975,14 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, ...@@ -7967,13 +7975,14 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
arvif->vdev_type == WMI_VDEV_TYPE_STA && arvif->vdev_type == WMI_VDEV_TYPE_STA &&
arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) { arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) {
ieee80211_hw_restart_disconnect(arvif->vif); ieee80211_hw_restart_disconnect(arvif->vif);
ath12k_dbg(ab, ATH12K_DBG_BOOT, ath12k_dbg(ab, ATH12K_DBG_BOOT,
"restart disconnect\n"); "restart disconnect\n");
} }
} }
}
mutex_unlock(&ar->conf_mutex); mutex_unlock(&ar->conf_mutex);
}
} }
static void static void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment