diff options
author | Arthur Jones <arthur.jones@qlogic.com> | 2007-09-14 15:22:49 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2007-10-09 23:56:23 -0400 |
commit | 70c51da2c4f84317bb13a2b564600afdcebd686f (patch) | |
tree | d7c39e3efaf6c90482cfe9d0e85012c3c9c511a7 /drivers/infiniband/hw/ipath/ipath_intr.c | |
parent | 542869a17eee2edf389273f40f757aa4e662b3da (diff) |
IB/ipath: Use counters in ipath_poll and cleanup interrupts in ipath_close
ipath_poll() suffered from a couple subtle bugs. Under the right
conditions we could leave recv interrupts enabled on an ipath user
context on close, thereby taking potentially unwanted interrupts on the
next open -- this is fixed by unconditionally turning off recv
interrupts on close. Also, we now use counters rather than set/clear
bits which allows us to make sure we catch all interrupts at the cost of
changing the semantics slightly (it's now give me all events since the
last time I called poll() rather than give me all events since I called
_this_ poll routine). We also added some memory barriers which may help
ensure we get all notifications in a timely manner.
Signed-off-by: Arthur Jones <arthur.jones@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_intr.c')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_intr.c | 33 |
1 files changed, 10 insertions, 23 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 11b361408ae6..61eac8cc0d9f 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c | |||
@@ -688,17 +688,9 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) | |||
688 | chkerrpkts = 1; | 688 | chkerrpkts = 1; |
689 | dd->ipath_lastrcvhdrqtails[i] = tl; | 689 | dd->ipath_lastrcvhdrqtails[i] = tl; |
690 | pd->port_hdrqfull++; | 690 | pd->port_hdrqfull++; |
691 | if (test_bit(IPATH_PORT_WAITING_OVERFLOW, | 691 | /* flush hdrqfull so that poll() sees it */ |
692 | &pd->port_flag)) { | 692 | wmb(); |
693 | clear_bit( | 693 | wake_up_interruptible(&pd->port_wait); |
694 | IPATH_PORT_WAITING_OVERFLOW, | ||
695 | &pd->port_flag); | ||
696 | set_bit( | ||
697 | IPATH_PORT_WAITING_OVERFLOW, | ||
698 | &pd->int_flag); | ||
699 | wake_up_interruptible( | ||
700 | &pd->port_wait); | ||
701 | } | ||
702 | } | 694 | } |
703 | } | 695 | } |
704 | } | 696 | } |
@@ -960,6 +952,8 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) | |||
960 | int i; | 952 | int i; |
961 | int rcvdint = 0; | 953 | int rcvdint = 0; |
962 | 954 | ||
955 | /* test_bit below needs this... */ | ||
956 | rmb(); | ||
963 | portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) & | 957 | portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) & |
964 | dd->ipath_i_rcvavail_mask) | 958 | dd->ipath_i_rcvavail_mask) |
965 | | ((istat >> INFINIPATH_I_RCVURG_SHIFT) & | 959 | | ((istat >> INFINIPATH_I_RCVURG_SHIFT) & |
@@ -967,22 +961,15 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) | |||
967 | for (i = 1; i < dd->ipath_cfgports; i++) { | 961 | for (i = 1; i < dd->ipath_cfgports; i++) { |
968 | struct ipath_portdata *pd = dd->ipath_pd[i]; | 962 | struct ipath_portdata *pd = dd->ipath_pd[i]; |
969 | if (portr & (1 << i) && pd && pd->port_cnt) { | 963 | if (portr & (1 << i) && pd && pd->port_cnt) { |
970 | if (test_bit(IPATH_PORT_WAITING_RCV, | 964 | if (test_and_clear_bit(IPATH_PORT_WAITING_RCV, |
971 | &pd->port_flag)) { | 965 | &pd->port_flag)) { |
972 | clear_bit(IPATH_PORT_WAITING_RCV, | ||
973 | &pd->port_flag); | ||
974 | set_bit(IPATH_PORT_WAITING_RCV, | ||
975 | &pd->int_flag); | ||
976 | clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT, | 966 | clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT, |
977 | &dd->ipath_rcvctrl); | 967 | &dd->ipath_rcvctrl); |
978 | wake_up_interruptible(&pd->port_wait); | 968 | wake_up_interruptible(&pd->port_wait); |
979 | rcvdint = 1; | 969 | rcvdint = 1; |
980 | } else if (test_bit(IPATH_PORT_WAITING_URG, | 970 | } else if (test_and_clear_bit(IPATH_PORT_WAITING_URG, |
981 | &pd->port_flag)) { | 971 | &pd->port_flag)) { |
982 | clear_bit(IPATH_PORT_WAITING_URG, | 972 | pd->port_urgent++; |
983 | &pd->port_flag); | ||
984 | set_bit(IPATH_PORT_WAITING_URG, | ||
985 | &pd->int_flag); | ||
986 | wake_up_interruptible(&pd->port_wait); | 973 | wake_up_interruptible(&pd->port_wait); |
987 | } | 974 | } |
988 | } | 975 | } |