Skip to content

Commit d49437a

Browse files
committed
wifi: iwlwifi: back off on continuous errors
When errors occur repeatedly, the driver shouldn't go into a tight loop trying to reset the device. Implement the backoff I had already defined IWL_TRANS_RESET_DELAY for, but clearly forgotten the implementation of. Fixes: 9a2f13c ("wifi: iwlwifi: implement reset escalation") Signed-off-by: Johannes Berg <[email protected]> Signed-off-by: Miri Korenblit <[email protected]> Link: https://patch.msgid.link/20250420095642.8816e299efa2.I82cde34e2345a2b33b1f03dbb040f5ad3439a5aa@changeid Signed-off-by: Johannes Berg <[email protected]>
1 parent d1ee2c1 commit d49437a

File tree

3 files changed

+28
-9
lines changed

3 files changed

+28
-9
lines changed

drivers/net/wireless/intel/iwlwifi/iwl-trans.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct iwl_trans_dev_restart_data {
2121
struct list_head list;
2222
unsigned int restart_count;
2323
time64_t last_error;
24+
bool backoff;
2425
char name[];
2526
};
2627

@@ -125,13 +126,20 @@ iwl_trans_determine_restart_mode(struct iwl_trans *trans)
125126
if (!data)
126127
return at_least;
127128

128-
if (ktime_get_boottime_seconds() - data->last_error >=
129+
if (!data->backoff &&
130+
ktime_get_boottime_seconds() - data->last_error >=
129131
IWL_TRANS_RESET_OK_TIME)
130132
data->restart_count = 0;
131133

132134
index = data->restart_count;
133-
if (index >= ARRAY_SIZE(escalation_list))
135+
if (index >= ARRAY_SIZE(escalation_list)) {
134136
index = ARRAY_SIZE(escalation_list) - 1;
137+
if (!data->backoff) {
138+
data->backoff = true;
139+
return IWL_RESET_MODE_BACKOFF;
140+
}
141+
data->backoff = false;
142+
}
135143

136144
return max(at_least, escalation_list[index]);
137145
}
@@ -140,7 +148,8 @@ iwl_trans_determine_restart_mode(struct iwl_trans *trans)
140148

141149
static void iwl_trans_restart_wk(struct work_struct *wk)
142150
{
143-
struct iwl_trans *trans = container_of(wk, typeof(*trans), restart.wk);
151+
struct iwl_trans *trans = container_of(wk, typeof(*trans),
152+
restart.wk.work);
144153
struct iwl_trans_reprobe *reprobe;
145154
enum iwl_reset_mode mode;
146155

@@ -168,6 +177,12 @@ static void iwl_trans_restart_wk(struct work_struct *wk)
168177
return;
169178

170179
mode = iwl_trans_determine_restart_mode(trans);
180+
if (mode == IWL_RESET_MODE_BACKOFF) {
181+
IWL_ERR(trans, "Too many device errors - delay next reset\n");
182+
queue_delayed_work(system_unbound_wq, &trans->restart.wk,
183+
IWL_TRANS_RESET_DELAY);
184+
return;
185+
}
171186

172187
iwl_trans_inc_restart_count(trans->dev);
173188

@@ -227,7 +242,7 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size,
227242
trans->dev = dev;
228243
trans->num_rx_queues = 1;
229244

230-
INIT_WORK(&trans->restart.wk, iwl_trans_restart_wk);
245+
INIT_DELAYED_WORK(&trans->restart.wk, iwl_trans_restart_wk);
231246

232247
return trans;
233248
}
@@ -271,7 +286,7 @@ int iwl_trans_init(struct iwl_trans *trans)
271286

272287
void iwl_trans_free(struct iwl_trans *trans)
273288
{
274-
cancel_work_sync(&trans->restart.wk);
289+
cancel_delayed_work_sync(&trans->restart.wk);
275290
kmem_cache_destroy(trans->dev_cmd_pool);
276291
}
277292

@@ -403,7 +418,7 @@ void iwl_trans_op_mode_leave(struct iwl_trans *trans)
403418

404419
iwl_trans_pcie_op_mode_leave(trans);
405420

406-
cancel_work_sync(&trans->restart.wk);
421+
cancel_delayed_work_sync(&trans->restart.wk);
407422

408423
trans->op_mode = NULL;
409424

drivers/net/wireless/intel/iwlwifi/iwl-trans.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,7 @@ struct iwl_trans {
961961
struct iwl_dma_ptr invalid_tx_cmd;
962962

963963
struct {
964-
struct work_struct wk;
964+
struct delayed_work wk;
965965
struct iwl_fw_error_dump_mode mode;
966966
bool during_reset;
967967
} restart;
@@ -1162,7 +1162,7 @@ static inline void iwl_trans_schedule_reset(struct iwl_trans *trans,
11621162
*/
11631163
trans->restart.during_reset = test_bit(STATUS_IN_SW_RESET,
11641164
&trans->status);
1165-
queue_work(system_unbound_wq, &trans->restart.wk);
1165+
queue_delayed_work(system_unbound_wq, &trans->restart.wk, 0);
11661166
}
11671167

11681168
static inline void iwl_trans_fw_error(struct iwl_trans *trans,
@@ -1261,6 +1261,9 @@ enum iwl_reset_mode {
12611261
IWL_RESET_MODE_RESCAN,
12621262
IWL_RESET_MODE_FUNC_RESET,
12631263
IWL_RESET_MODE_PROD_RESET,
1264+
1265+
/* keep last - special backoff value */
1266+
IWL_RESET_MODE_BACKOFF,
12641267
};
12651268

12661269
void iwl_trans_pcie_reset(struct iwl_trans *trans, enum iwl_reset_mode mode);

drivers/net/wireless/intel/iwlwifi/pcie/trans.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2351,7 +2351,8 @@ void iwl_trans_pcie_reset(struct iwl_trans *trans, enum iwl_reset_mode mode)
23512351
struct iwl_trans_pcie_removal *removal;
23522352
char _msg = 0, *msg = &_msg;
23532353

2354-
if (WARN_ON(mode < IWL_RESET_MODE_REMOVE_ONLY))
2354+
if (WARN_ON(mode < IWL_RESET_MODE_REMOVE_ONLY ||
2355+
mode == IWL_RESET_MODE_BACKOFF))
23552356
return;
23562357

23572358
if (test_bit(STATUS_TRANS_DEAD, &trans->status))

0 commit comments

Comments
 (0)