Skip to content

Commit 5dadbe4

Browse files
Wen GongKalle Valo
authored andcommitted
ath10k: add atomic protection for device recovery
When it has more than one restart_work queued meanwhile, the 2nd restart_work is very easy to break the 1st restart work and lead recovery fail. Add a flag to allow only one restart work running untill device successfully recovered. It already has flag ATH10K_FLAG_CRASH_FLUSH, but it can not use this flag again, because it is clear in ath10k_core_start. The function ieee80211_reconfig(called by ieee80211_restart_work) of mac80211 do many things and drv_start(call to ath10k_core_start) is 1st thing, when drv_start complete, it does not mean restart complete. So it add new flag and clear it in ath10k_reconfig_complete, because it is the last thing called from drv_reconfig_complete of function ieee80211_reconfig, after it, the restart process finished. Tested-on: QCA6174 hw3.2 SDIO WLAN.RMH.4.4.1-00049 Signed-off-by: Wen Gong <[email protected]> Signed-off-by: Kalle Valo <[email protected]> Link: https://lore.kernel.org/r/010101746bead6a0-d5e97c66-dedd-4b92-810e-c2e4840fafc9-000000@us-west-2.amazonses.com
1 parent 2bc2b87 commit 5dadbe4

File tree

8 files changed

+25
-9
lines changed

8 files changed

+25
-9
lines changed

drivers/net/wireless/ath/ath10k/core.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,6 +2294,17 @@ static int ath10k_init_hw_params(struct ath10k *ar)
22942294
return 0;
22952295
}
22962296

2297+
void ath10k_core_start_recovery(struct ath10k *ar)
2298+
{
2299+
if (test_and_set_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags)) {
2300+
ath10k_warn(ar, "already restarting\n");
2301+
return;
2302+
}
2303+
2304+
queue_work(ar->workqueue, &ar->restart_work);
2305+
}
2306+
EXPORT_SYMBOL(ath10k_core_start_recovery);
2307+
22972308
static void ath10k_core_restart(struct work_struct *work)
22982309
{
22992310
struct ath10k *ar = container_of(work, struct ath10k, restart_work);

drivers/net/wireless/ath/ath10k/core.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,9 @@ enum ath10k_dev_flags {
865865

866866
/* Per Station statistics service */
867867
ATH10K_FLAG_PEER_STATS,
868+
869+
/* Indicates that ath10k device is during recovery process and not complete */
870+
ATH10K_FLAG_RESTARTING,
868871
};
869872

870873
enum ath10k_cal_mode {
@@ -1320,6 +1323,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
13201323
const struct ath10k_fw_components *fw_components);
13211324
int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);
13221325
void ath10k_core_stop(struct ath10k *ar);
1326+
void ath10k_core_start_recovery(struct ath10k *ar);
13231327
int ath10k_core_register(struct ath10k *ar,
13241328
const struct ath10k_bus_params *bus_params);
13251329
void ath10k_core_unregister(struct ath10k *ar);

drivers/net/wireless/ath/ath10k/debug.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file,
583583
ret = ath10k_debug_fw_assert(ar);
584584
} else if (!strcmp(buf, "hw-restart")) {
585585
ath10k_info(ar, "user requested hw restart\n");
586-
queue_work(ar->workqueue, &ar->restart_work);
586+
ath10k_core_start_recovery(ar);
587587
ret = 0;
588588
} else {
589589
ret = -EINVAL;
@@ -2005,7 +2005,7 @@ static ssize_t ath10k_write_btcoex(struct file *file,
20052005
}
20062006
} else {
20072007
ath10k_info(ar, "restarting firmware due to btcoex change");
2008-
queue_work(ar->workqueue, &ar->restart_work);
2008+
ath10k_core_start_recovery(ar);
20092009
}
20102010

20112011
if (val)
@@ -2136,7 +2136,7 @@ static ssize_t ath10k_write_peer_stats(struct file *file,
21362136

21372137
ath10k_info(ar, "restarting firmware due to Peer stats change");
21382138

2139-
queue_work(ar->workqueue, &ar->restart_work);
2139+
ath10k_core_start_recovery(ar);
21402140
ret = count;
21412141

21422142
exit:

drivers/net/wireless/ath/ath10k/mac.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7932,6 +7932,7 @@ static void ath10k_reconfig_complete(struct ieee80211_hw *hw,
79327932
ath10k_info(ar, "device successfully recovered\n");
79337933
ar->state = ATH10K_STATE_ON;
79347934
ieee80211_wake_queues(ar->hw);
7935+
clear_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags);
79357936
}
79367937

79377938
mutex_unlock(&ar->conf_mutex);

drivers/net/wireless/ath/ath10k/pci.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1774,7 +1774,7 @@ static void ath10k_pci_fw_dump_work(struct work_struct *work)
17741774

17751775
mutex_unlock(&ar->dump_mutex);
17761776

1777-
queue_work(ar->workqueue, &ar->restart_work);
1777+
ath10k_core_start_recovery(ar);
17781778
}
17791779

17801780
static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)

drivers/net/wireless/ath/ath10k/sdio.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ static int ath10k_sdio_mbox_rx_alloc(struct ath10k *ar,
561561
ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH);
562562
ret = -ENOMEM;
563563

564-
queue_work(ar->workqueue, &ar->restart_work);
564+
ath10k_core_start_recovery(ar);
565565
ath10k_warn(ar, "exceeds length, start recovery\n");
566566

567567
goto err;
@@ -960,7 +960,7 @@ static int ath10k_sdio_mbox_read_int_status(struct ath10k *ar,
960960
ret = ath10k_sdio_read(ar, MBOX_HOST_INT_STATUS_ADDRESS,
961961
irq_proc_reg, sizeof(*irq_proc_reg));
962962
if (ret) {
963-
queue_work(ar->workqueue, &ar->restart_work);
963+
ath10k_core_start_recovery(ar);
964964
ath10k_warn(ar, "read int status fail, start recovery\n");
965965
goto out;
966966
}
@@ -2501,7 +2501,7 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar)
25012501

25022502
ath10k_sdio_enable_intrs(ar);
25032503

2504-
queue_work(ar->workqueue, &ar->restart_work);
2504+
ath10k_core_start_recovery(ar);
25052505
}
25062506

25072507
static int ath10k_sdio_probe(struct sdio_func *func,

drivers/net/wireless/ath/ath10k/snoc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1305,7 +1305,7 @@ int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)
13051305
switch (type) {
13061306
case ATH10K_QMI_EVENT_FW_READY_IND:
13071307
if (test_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags)) {
1308-
queue_work(ar->workqueue, &ar->restart_work);
1308+
ath10k_core_start_recovery(ar);
13091309
break;
13101310
}
13111311

drivers/net/wireless/ath/ath10k/wmi.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1937,7 +1937,7 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
19371937
if (ret == -EAGAIN) {
19381938
ath10k_warn(ar, "wmi command %d timeout, restarting hardware\n",
19391939
cmd_id);
1940-
queue_work(ar->workqueue, &ar->restart_work);
1940+
ath10k_core_start_recovery(ar);
19411941
}
19421942

19431943
return ret;

0 commit comments

Comments
 (0)