aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/ipath/ipath_driver.c
diff options
context:
space:
mode:
authorJohn Gregor <john.gregor@qlogic.com>2008-04-17 00:09:24 -0400
committerRoland Dreier <rolandd@cisco.com>2008-04-17 00:09:24 -0400
commit58411d1c012dca53ec9107bd98acb63f648e2435 (patch)
treed48edc5c3c64d91311bb4134b83bfe7b62b10ec4 /drivers/infiniband/hw/ipath/ipath_driver.c
parent6be979d71a5e8720c8560cc58713407947e5f691 (diff)
IB/ipath: Head of Line blocking vs forward progress of user apps
There's a conflict between our need to quiesce PSM-based applications to avoid HoL blocking when the IB link goes down and the apps' desire to remain running so that their quiescence timout mechanism can keep running. The compromise is to STOP the processes for a fixed period of time and then alternate between CONT and STOP until the link is again active. If there are poor interactions with subnet manager configuration at a given site, the interval can be adjusted via a module paramter. Signed-off-by: John Gregor <john.gregor@qlogic.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_driver.c')
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c129
1 files changed, 121 insertions, 8 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index 7121fe84ff8b..5605f4f27521 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -77,6 +77,11 @@ unsigned ipath_mtu4096 = 1; /* max 4KB IB mtu by default, if supported */
77module_param_named(mtu4096, ipath_mtu4096, uint, S_IRUGO); 77module_param_named(mtu4096, ipath_mtu4096, uint, S_IRUGO);
78MODULE_PARM_DESC(mtu4096, "enable MTU of 4096 bytes, if supported"); 78MODULE_PARM_DESC(mtu4096, "enable MTU of 4096 bytes, if supported");
79 79
80static unsigned ipath_hol_timeout_ms = 13000;
81module_param_named(hol_timeout_ms, ipath_hol_timeout_ms, uint, S_IRUGO);
82MODULE_PARM_DESC(hol_timeout_ms,
83 "duration of user app suspension after link failure");
84
80MODULE_LICENSE("GPL"); 85MODULE_LICENSE("GPL");
81MODULE_AUTHOR("QLogic <support@pathscale.com>"); 86MODULE_AUTHOR("QLogic <support@pathscale.com>");
82MODULE_DESCRIPTION("QLogic InfiniPath driver"); 87MODULE_DESCRIPTION("QLogic InfiniPath driver");
@@ -1670,11 +1675,8 @@ static void ipath_set_ib_lstate(struct ipath_devdata *dd, int which)
1670 ipath_cdbg(VERBOSE, "Trying to move unit %u to %s, current ltstate " 1675 ipath_cdbg(VERBOSE, "Trying to move unit %u to %s, current ltstate "
1671 "is %s\n", dd->ipath_unit, 1676 "is %s\n", dd->ipath_unit,
1672 what[linkcmd], 1677 what[linkcmd],
1673 ipath_ibcstatus_str[ 1678 ipath_ibcstatus_str[ipath_ib_linktrstate(dd,
1674 (ipath_read_kreg64 1679 ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus))]);
1675 (dd, dd->ipath_kregs->kr_ibcstatus) >>
1676 INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
1677 INFINIPATH_IBCS_LINKTRAININGSTATE_MASK]);
1678 /* flush all queued sends when going to DOWN to be sure that 1680 /* flush all queued sends when going to DOWN to be sure that
1679 * they don't block MAD packets */ 1681 * they don't block MAD packets */
1680 if (linkcmd == INFINIPATH_IBCC_LINKCMD_DOWN) 1682 if (linkcmd == INFINIPATH_IBCC_LINKCMD_DOWN)
@@ -1925,9 +1927,8 @@ static void ipath_run_led_override(unsigned long opaque)
1925 */ 1927 */
1926 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus); 1928 val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
1927 ltstate = (val >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) & 1929 ltstate = (val >> INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) &
1928 INFINIPATH_IBCS_LINKTRAININGSTATE_MASK; 1930 dd->ibcs_lts_mask;
1929 lstate = (val >> INFINIPATH_IBCS_LINKSTATE_SHIFT) & 1931 lstate = (val >> dd->ibcs_ls_shift) & INFINIPATH_IBCS_LINKSTATE_MASK;
1930 INFINIPATH_IBCS_LINKSTATE_MASK;
1931 1932
1932 dd->ipath_f_setextled(dd, lstate, ltstate); 1933 dd->ipath_f_setextled(dd, lstate, ltstate);
1933 mod_timer(&dd->ipath_led_override_timer, jiffies + timeoff); 1934 mod_timer(&dd->ipath_led_override_timer, jiffies + timeoff);
@@ -1988,6 +1989,8 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
1988 1989
1989 ipath_dbg("Shutting down the device\n"); 1990 ipath_dbg("Shutting down the device\n");
1990 1991
1992 ipath_hol_up(dd); /* make sure user processes aren't suspended */
1993
1991 dd->ipath_flags |= IPATH_LINKUNK; 1994 dd->ipath_flags |= IPATH_LINKUNK;
1992 dd->ipath_flags &= ~(IPATH_INITTED | IPATH_LINKDOWN | 1995 dd->ipath_flags &= ~(IPATH_INITTED | IPATH_LINKDOWN |
1993 IPATH_LINKINIT | IPATH_LINKARMED | 1996 IPATH_LINKINIT | IPATH_LINKARMED |
@@ -2037,6 +2040,8 @@ void ipath_shutdown_device(struct ipath_devdata *dd)
2037 */ 2040 */
2038 dd->ipath_f_quiet_serdes(dd); 2041 dd->ipath_f_quiet_serdes(dd);
2039 2042
2043 /* stop all the timers that might still be running */
2044 del_timer_sync(&dd->ipath_hol_timer);
2040 if (dd->ipath_stats_timer_active) { 2045 if (dd->ipath_stats_timer_active) {
2041 del_timer_sync(&dd->ipath_stats_timer); 2046 del_timer_sync(&dd->ipath_stats_timer);
2042 dd->ipath_stats_timer_active = 0; 2047 dd->ipath_stats_timer_active = 0;
@@ -2252,6 +2257,114 @@ bail:
2252 return ret; 2257 return ret;
2253} 2258}
2254 2259
2260/*
2261 * send a signal to all the processes that have the driver open
2262 * through the normal interfaces (i.e., everything other than diags
2263 * interface). Returns number of signalled processes.
2264 */
2265static int ipath_signal_procs(struct ipath_devdata *dd, int sig)
2266{
2267 int i, sub, any = 0;
2268 pid_t pid;
2269
2270 if (!dd->ipath_pd)
2271 return 0;
2272 for (i = 1; i < dd->ipath_cfgports; i++) {
2273 if (!dd->ipath_pd[i] || !dd->ipath_pd[i]->port_cnt ||
2274 !dd->ipath_pd[i]->port_pid)
2275 continue;
2276 pid = dd->ipath_pd[i]->port_pid;
2277 dev_info(&dd->pcidev->dev, "context %d in use "
2278 "(PID %u), sending signal %d\n",
2279 i, pid, sig);
2280 kill_proc(pid, sig, 1);
2281 any++;
2282 for (sub = 0; sub < INFINIPATH_MAX_SUBPORT; sub++) {
2283 pid = dd->ipath_pd[i]->port_subpid[sub];
2284 if (!pid)
2285 continue;
2286 dev_info(&dd->pcidev->dev, "sub-context "
2287 "%d:%d in use (PID %u), sending "
2288 "signal %d\n", i, sub, pid, sig);
2289 kill_proc(pid, sig, 1);
2290 any++;
2291 }
2292 }
2293 return any;
2294}
2295
2296static void ipath_hol_signal_down(struct ipath_devdata *dd)
2297{
2298 if (ipath_signal_procs(dd, SIGSTOP))
2299 ipath_dbg("Stopped some processes\n");
2300 ipath_cancel_sends(dd, 1);
2301}
2302
2303
2304static void ipath_hol_signal_up(struct ipath_devdata *dd)
2305{
2306 if (ipath_signal_procs(dd, SIGCONT))
2307 ipath_dbg("Continued some processes\n");
2308}
2309
2310/*
2311 * link is down, stop any users processes, and flush pending sends
2312 * to prevent HoL blocking, then start the HoL timer that
2313 * periodically continues, then stop procs, so they can detect
2314 * link down if they want, and do something about it.
2315 * Timer may already be running, so use __mod_timer, not add_timer.
2316 */
2317void ipath_hol_down(struct ipath_devdata *dd)
2318{
2319 dd->ipath_hol_state = IPATH_HOL_DOWN;
2320 ipath_hol_signal_down(dd);
2321 dd->ipath_hol_next = IPATH_HOL_DOWNCONT;
2322 dd->ipath_hol_timer.expires = jiffies +
2323 msecs_to_jiffies(ipath_hol_timeout_ms);
2324 __mod_timer(&dd->ipath_hol_timer, dd->ipath_hol_timer.expires);
2325}
2326
2327/*
2328 * link is up, continue any user processes, and ensure timer
2329 * is a nop, if running. Let timer keep running, if set; it
2330 * will nop when it sees the link is up
2331 */
2332void ipath_hol_up(struct ipath_devdata *dd)
2333{
2334 ipath_hol_signal_up(dd);
2335 dd->ipath_hol_state = IPATH_HOL_UP;
2336}
2337
2338/*
2339 * toggle the running/not running state of user proceses
2340 * to prevent HoL blocking on chip resources, but still allow
2341 * user processes to do link down special case handling.
2342 * Should only be called via the timer
2343 */
2344void ipath_hol_event(unsigned long opaque)
2345{
2346 struct ipath_devdata *dd = (struct ipath_devdata *)opaque;
2347
2348 if (dd->ipath_hol_next == IPATH_HOL_DOWNSTOP
2349 && dd->ipath_hol_state != IPATH_HOL_UP) {
2350 dd->ipath_hol_next = IPATH_HOL_DOWNCONT;
2351 ipath_dbg("Stopping processes\n");
2352 ipath_hol_signal_down(dd);
2353 } else { /* may do "extra" if also in ipath_hol_up() */
2354 dd->ipath_hol_next = IPATH_HOL_DOWNSTOP;
2355 ipath_dbg("Continuing processes\n");
2356 ipath_hol_signal_up(dd);
2357 }
2358 if (dd->ipath_hol_state == IPATH_HOL_UP)
2359 ipath_dbg("link's up, don't resched timer\n");
2360 else {
2361 dd->ipath_hol_timer.expires = jiffies +
2362 msecs_to_jiffies(ipath_hol_timeout_ms);
2363 __mod_timer(&dd->ipath_hol_timer,
2364 dd->ipath_hol_timer.expires);
2365 }
2366}
2367
2255int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv) 2368int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv)
2256{ 2369{
2257 u64 val; 2370 u64 val;