aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2016-10-03 20:25:52 -0400
committerDavid S. Miller <davem@davemloft.net>2016-10-04 02:11:51 -0400
commit83afdc6aad9d767cae271df1ca15641b9cbe3bfe (patch)
treeadd1f527f3a3957e4f2a0c4ca5d7673ef5d8898a
parenta0509cbeef5dafbab42c42622e012bcc94c3eb9e (diff)
net/ncsi: Rework the channel monitoring
The original NCSI channel monitoring was implemented based on a backoff algorithm: the GLS response should be received in the specified interval. Otherwise, the channel is regarded as dead and failover should be taken if current channel is an active one. There are several problems in the implementation: (A) On BCM5718, we found when the IID (Instance ID) in the GLS command packet changes from 255 to 1, the response corresponding to IID#1 never comes in. It means we cannot make the unfair judgement that the channel is dead when one response is missed. (B) The code's readability should be improved. (C) We should do failover when current channel is active one and the channel monitoring should be marked as disabled before doing failover. This reworks the channel monitoring to address all above issues. The fields for channel monitoring is put into separate struct and the state of channel monitoring is predefined. The channel is regarded alive if the network controller responses to one of two GLS commands or both of them in 5 seconds. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Reviewed-by: Joel Stanley <joel@jms.id.au> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ncsi/internal.h12
-rw-r--r--net/ncsi/ncsi-manage.c44
-rw-r--r--net/ncsi/ncsi-rsp.c2
3 files changed, 35 insertions, 23 deletions
diff --git a/net/ncsi/internal.h b/net/ncsi/internal.h
index 26e929595b5e..13290a70fa71 100644
--- a/net/ncsi/internal.h
+++ b/net/ncsi/internal.h
@@ -187,9 +187,15 @@ struct ncsi_channel {
187 struct ncsi_channel_mode modes[NCSI_MODE_MAX]; 187 struct ncsi_channel_mode modes[NCSI_MODE_MAX];
188 struct ncsi_channel_filter *filters[NCSI_FILTER_MAX]; 188 struct ncsi_channel_filter *filters[NCSI_FILTER_MAX];
189 struct ncsi_channel_stats stats; 189 struct ncsi_channel_stats stats;
190 struct timer_list timer; /* Link monitor timer */ 190 struct {
191 bool enabled; /* Timer is enabled */ 191 struct timer_list timer;
192 unsigned int timeout; /* Times of timeout */ 192 bool enabled;
193 unsigned int state;
194#define NCSI_CHANNEL_MONITOR_START 0
195#define NCSI_CHANNEL_MONITOR_RETRY 1
196#define NCSI_CHANNEL_MONITOR_WAIT 2
197#define NCSI_CHANNEL_MONITOR_WAIT_MAX 5
198 } monitor;
193 struct list_head node; 199 struct list_head node;
194 struct list_head link; 200 struct list_head link;
195}; 201};
diff --git a/net/ncsi/ncsi-manage.c b/net/ncsi/ncsi-manage.c
index adf5401817c2..4742c7c6c748 100644
--- a/net/ncsi/ncsi-manage.c
+++ b/net/ncsi/ncsi-manage.c
@@ -172,15 +172,15 @@ static void ncsi_channel_monitor(unsigned long data)
172 struct ncsi_dev_priv *ndp = np->ndp; 172 struct ncsi_dev_priv *ndp = np->ndp;
173 struct ncsi_cmd_arg nca; 173 struct ncsi_cmd_arg nca;
174 bool enabled, chained; 174 bool enabled, chained;
175 unsigned int timeout; 175 unsigned int monitor_state;
176 unsigned long flags; 176 unsigned long flags;
177 int state, ret; 177 int state, ret;
178 178
179 spin_lock_irqsave(&nc->lock, flags); 179 spin_lock_irqsave(&nc->lock, flags);
180 state = nc->state; 180 state = nc->state;
181 chained = !list_empty(&nc->link); 181 chained = !list_empty(&nc->link);
182 timeout = nc->timeout; 182 enabled = nc->monitor.enabled;
183 enabled = nc->enabled; 183 monitor_state = nc->monitor.state;
184 spin_unlock_irqrestore(&nc->lock, flags); 184 spin_unlock_irqrestore(&nc->lock, flags);
185 185
186 if (!enabled || chained) 186 if (!enabled || chained)
@@ -189,7 +189,9 @@ static void ncsi_channel_monitor(unsigned long data)
189 state != NCSI_CHANNEL_ACTIVE) 189 state != NCSI_CHANNEL_ACTIVE)
190 return; 190 return;
191 191
192 if (!(timeout % 2)) { 192 switch (monitor_state) {
193 case NCSI_CHANNEL_MONITOR_START:
194 case NCSI_CHANNEL_MONITOR_RETRY:
193 nca.ndp = ndp; 195 nca.ndp = ndp;
194 nca.package = np->id; 196 nca.package = np->id;
195 nca.channel = nc->id; 197 nca.channel = nc->id;
@@ -201,12 +203,16 @@ static void ncsi_channel_monitor(unsigned long data)
201 ret); 203 ret);
202 return; 204 return;
203 } 205 }
204 }
205 206
206 if (timeout + 1 >= 3) { 207 break;
208 case NCSI_CHANNEL_MONITOR_WAIT ... NCSI_CHANNEL_MONITOR_WAIT_MAX:
209 break;
210 default:
207 if (!(ndp->flags & NCSI_DEV_HWA) && 211 if (!(ndp->flags & NCSI_DEV_HWA) &&
208 state == NCSI_CHANNEL_ACTIVE) 212 state == NCSI_CHANNEL_ACTIVE) {
209 ncsi_report_link(ndp, true); 213 ncsi_report_link(ndp, true);
214 ndp->flags |= NCSI_DEV_RESHUFFLE;
215 }
210 216
211 spin_lock_irqsave(&nc->lock, flags); 217 spin_lock_irqsave(&nc->lock, flags);
212 nc->state = NCSI_CHANNEL_INVISIBLE; 218 nc->state = NCSI_CHANNEL_INVISIBLE;
@@ -221,10 +227,9 @@ static void ncsi_channel_monitor(unsigned long data)
221 } 227 }
222 228
223 spin_lock_irqsave(&nc->lock, flags); 229 spin_lock_irqsave(&nc->lock, flags);
224 nc->timeout = timeout + 1; 230 nc->monitor.state++;
225 nc->enabled = true;
226 spin_unlock_irqrestore(&nc->lock, flags); 231 spin_unlock_irqrestore(&nc->lock, flags);
227 mod_timer(&nc->timer, jiffies + HZ * (1 << (nc->timeout / 2))); 232 mod_timer(&nc->monitor.timer, jiffies + HZ);
228} 233}
229 234
230void ncsi_start_channel_monitor(struct ncsi_channel *nc) 235void ncsi_start_channel_monitor(struct ncsi_channel *nc)
@@ -232,12 +237,12 @@ void ncsi_start_channel_monitor(struct ncsi_channel *nc)
232 unsigned long flags; 237 unsigned long flags;
233 238
234 spin_lock_irqsave(&nc->lock, flags); 239 spin_lock_irqsave(&nc->lock, flags);
235 WARN_ON_ONCE(nc->enabled); 240 WARN_ON_ONCE(nc->monitor.enabled);
236 nc->timeout = 0; 241 nc->monitor.enabled = true;
237 nc->enabled = true; 242 nc->monitor.state = NCSI_CHANNEL_MONITOR_START;
238 spin_unlock_irqrestore(&nc->lock, flags); 243 spin_unlock_irqrestore(&nc->lock, flags);
239 244
240 mod_timer(&nc->timer, jiffies + HZ * (1 << (nc->timeout / 2))); 245 mod_timer(&nc->monitor.timer, jiffies + HZ);
241} 246}
242 247
243void ncsi_stop_channel_monitor(struct ncsi_channel *nc) 248void ncsi_stop_channel_monitor(struct ncsi_channel *nc)
@@ -245,14 +250,14 @@ void ncsi_stop_channel_monitor(struct ncsi_channel *nc)
245 unsigned long flags; 250 unsigned long flags;
246 251
247 spin_lock_irqsave(&nc->lock, flags); 252 spin_lock_irqsave(&nc->lock, flags);
248 if (!nc->enabled) { 253 if (!nc->monitor.enabled) {
249 spin_unlock_irqrestore(&nc->lock, flags); 254 spin_unlock_irqrestore(&nc->lock, flags);
250 return; 255 return;
251 } 256 }
252 nc->enabled = false; 257 nc->monitor.enabled = false;
253 spin_unlock_irqrestore(&nc->lock, flags); 258 spin_unlock_irqrestore(&nc->lock, flags);
254 259
255 del_timer_sync(&nc->timer); 260 del_timer_sync(&nc->monitor.timer);
256} 261}
257 262
258struct ncsi_channel *ncsi_find_channel(struct ncsi_package *np, 263struct ncsi_channel *ncsi_find_channel(struct ncsi_package *np,
@@ -281,8 +286,9 @@ struct ncsi_channel *ncsi_add_channel(struct ncsi_package *np, unsigned char id)
281 nc->id = id; 286 nc->id = id;
282 nc->package = np; 287 nc->package = np;
283 nc->state = NCSI_CHANNEL_INACTIVE; 288 nc->state = NCSI_CHANNEL_INACTIVE;
284 nc->enabled = false; 289 nc->monitor.enabled = false;
285 setup_timer(&nc->timer, ncsi_channel_monitor, (unsigned long)nc); 290 setup_timer(&nc->monitor.timer,
291 ncsi_channel_monitor, (unsigned long)nc);
286 spin_lock_init(&nc->lock); 292 spin_lock_init(&nc->lock);
287 INIT_LIST_HEAD(&nc->link); 293 INIT_LIST_HEAD(&nc->link);
288 for (index = 0; index < NCSI_CAP_MAX; index++) 294 for (index = 0; index < NCSI_CAP_MAX; index++)
diff --git a/net/ncsi/ncsi-rsp.c b/net/ncsi/ncsi-rsp.c
index 86cdaebd8d9e..087db775b3dc 100644
--- a/net/ncsi/ncsi-rsp.c
+++ b/net/ncsi/ncsi-rsp.c
@@ -322,7 +322,7 @@ static int ncsi_rsp_handler_gls(struct ncsi_request *nr)
322 322
323 /* Reset the channel monitor if it has been enabled */ 323 /* Reset the channel monitor if it has been enabled */
324 spin_lock_irqsave(&nc->lock, flags); 324 spin_lock_irqsave(&nc->lock, flags);
325 nc->timeout = 0; 325 nc->monitor.state = NCSI_CHANNEL_MONITOR_START;
326 spin_unlock_irqrestore(&nc->lock, flags); 326 spin_unlock_irqrestore(&nc->lock, flags);
327 327
328 return 0; 328 return 0;