66 */
77#include <linux/kernel.h>
88#include <linux/bsearch.h>
9+ #include <linux/list.h>
910
1011#include "fw/api/tx.h"
1112#include "iwl-trans.h"
1617#include "pcie/internal.h"
1718#include "iwl-context-info-gen3.h"
1819
20+ struct iwl_trans_dev_restart_data {
21+ struct list_head list ;
22+ unsigned int restart_count ;
23+ time64_t last_error ;
24+ char name [];
25+ };
26+
27+ static LIST_HEAD (restart_data_list );
28+ static DEFINE_SPINLOCK (restart_data_lock );
29+
30+ static struct iwl_trans_dev_restart_data *
31+ iwl_trans_get_restart_data (struct device * dev )
32+ {
33+ struct iwl_trans_dev_restart_data * tmp , * data = NULL ;
34+ const char * name = dev_name (dev );
35+
36+ spin_lock (& restart_data_lock );
37+ list_for_each_entry (tmp , & restart_data_list , list ) {
38+ if (strcmp (tmp -> name , name ))
39+ continue ;
40+ data = tmp ;
41+ break ;
42+ }
43+ spin_unlock (& restart_data_lock );
44+
45+ if (data )
46+ return data ;
47+
48+ data = kzalloc (struct_size (data , name , strlen (name ) + 1 ), GFP_ATOMIC );
49+ if (!data )
50+ return NULL ;
51+
52+ strcpy (data -> name , name );
53+ spin_lock (& restart_data_lock );
54+ list_add_tail (& data -> list , & restart_data_list );
55+ spin_unlock (& restart_data_lock );
56+
57+ return data ;
58+ }
59+
60+ static void iwl_trans_inc_restart_count (struct device * dev )
61+ {
62+ struct iwl_trans_dev_restart_data * data ;
63+
64+ data = iwl_trans_get_restart_data (dev );
65+ if (data ) {
66+ data -> last_error = ktime_get_boottime_seconds ();
67+ data -> restart_count ++ ;
68+ }
69+ }
70+
71+ void iwl_trans_free_restart_list (void )
72+ {
73+ struct iwl_trans_dev_restart_data * tmp ;
74+
75+ while ((tmp = list_first_entry_or_null (& restart_data_list ,
76+ typeof (* tmp ), list ))) {
77+ list_del (& tmp -> list );
78+ kfree (tmp );
79+ }
80+ }
81+
1982struct iwl_trans_reprobe {
2083 struct device * dev ;
2184 struct work_struct work ;
@@ -34,10 +97,52 @@ static void iwl_trans_reprobe_wk(struct work_struct *wk)
3497 module_put (THIS_MODULE );
3598}
3699
100+ #define IWL_TRANS_RESET_OK_TIME 180 /* seconds */
101+
102+ static enum iwl_reset_mode
103+ iwl_trans_determine_restart_mode (struct iwl_trans * trans )
104+ {
105+ struct iwl_trans_dev_restart_data * data ;
106+ enum iwl_reset_mode at_least = 0 ;
107+ unsigned int index ;
108+ static const enum iwl_reset_mode escalation_list [] = {
109+ IWL_RESET_MODE_SW_RESET ,
110+ IWL_RESET_MODE_REPROBE ,
111+ IWL_RESET_MODE_REPROBE ,
112+ IWL_RESET_MODE_FUNC_RESET ,
113+ /* FIXME: add TOP reset */
114+ IWL_RESET_MODE_PROD_RESET ,
115+ /* FIXME: add TOP reset */
116+ IWL_RESET_MODE_PROD_RESET ,
117+ /* FIXME: add TOP reset */
118+ IWL_RESET_MODE_PROD_RESET ,
119+ };
120+
121+ if (trans -> restart .during_reset )
122+ at_least = IWL_RESET_MODE_REPROBE ;
123+
124+ data = iwl_trans_get_restart_data (trans -> dev );
125+ if (!data )
126+ return at_least ;
127+
128+ if (ktime_get_boottime_seconds () - data -> last_error >=
129+ IWL_TRANS_RESET_OK_TIME )
130+ data -> restart_count = 0 ;
131+
132+ index = data -> restart_count ;
133+ if (index >= ARRAY_SIZE (escalation_list ))
134+ index = ARRAY_SIZE (escalation_list ) - 1 ;
135+
136+ return max (at_least , escalation_list [index ]);
137+ }
138+
139+ #define IWL_TRANS_RESET_DELAY (HZ * 60)
140+
37141static void iwl_trans_restart_wk (struct work_struct * wk )
38142{
39143 struct iwl_trans * trans = container_of (wk , typeof (* trans ), restart .wk );
40144 struct iwl_trans_reprobe * reprobe ;
145+ enum iwl_reset_mode mode ;
41146
42147 if (!trans -> op_mode )
43148 return ;
@@ -62,32 +167,41 @@ static void iwl_trans_restart_wk(struct work_struct *wk)
62167 if (!iwlwifi_mod_params .fw_restart )
63168 return ;
64169
65- if (!trans -> restart .during_reset ) {
66- iwl_trans_opmode_sw_reset (trans , trans -> restart .mode .type );
67- return ;
68- }
170+ mode = iwl_trans_determine_restart_mode (trans );
69171
70- IWL_ERR (trans ,
71- "Device error during reconfiguration - reprobe!\n" );
172+ iwl_trans_inc_restart_count (trans -> dev );
72173
73- /*
74- * get a module reference to avoid doing this while unloading
75- * anyway and to avoid scheduling a work with code that's
76- * being removed.
77- */
78- if (!try_module_get (THIS_MODULE )) {
79- IWL_ERR (trans , "Module is being unloaded - abort\n" );
80- return ;
81- }
82-
83- reprobe = kzalloc (sizeof (* reprobe ), GFP_KERNEL );
84- if (!reprobe ) {
85- module_put (THIS_MODULE );
86- return ;
174+ switch (mode ) {
175+ case IWL_RESET_MODE_SW_RESET :
176+ IWL_ERR (trans , "Device error - SW reset\n" );
177+ iwl_trans_opmode_sw_reset (trans , trans -> restart .mode .type );
178+ break ;
179+ case IWL_RESET_MODE_REPROBE :
180+ IWL_ERR (trans , "Device error - reprobe!\n" );
181+
182+ /*
183+ * get a module reference to avoid doing this while unloading
184+ * anyway and to avoid scheduling a work with code that's
185+ * being removed.
186+ */
187+ if (!try_module_get (THIS_MODULE )) {
188+ IWL_ERR (trans , "Module is being unloaded - abort\n" );
189+ return ;
190+ }
191+
192+ reprobe = kzalloc (sizeof (* reprobe ), GFP_KERNEL );
193+ if (!reprobe ) {
194+ module_put (THIS_MODULE );
195+ return ;
196+ }
197+ reprobe -> dev = get_device (trans -> dev );
198+ INIT_WORK (& reprobe -> work , iwl_trans_reprobe_wk );
199+ schedule_work (& reprobe -> work );
200+ break ;
201+ default :
202+ iwl_trans_pcie_reset (trans , mode );
203+ break ;
87204 }
88- reprobe -> dev = get_device (trans -> dev );
89- INIT_WORK (& reprobe -> work , iwl_trans_reprobe_wk );
90- schedule_work (& reprobe -> work );
91205}
92206
93207struct iwl_trans * iwl_trans_alloc (unsigned int priv_size ,
0 commit comments