aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Jones <arthur.jones@qlogic.com>2007-09-14 15:22:49 -0400
committerRoland Dreier <rolandd@cisco.com>2007-10-09 23:56:23 -0400
commit70c51da2c4f84317bb13a2b564600afdcebd686f (patch)
treed7c39e3efaf6c90482cfe9d0e85012c3c9c511a7
parent542869a17eee2edf389273f40f757aa4e662b3da (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>
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c67
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c33
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h8
3 files changed, 57 insertions, 51 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 33ab0d6b80f..016e7c4e366 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -1341,6 +1341,19 @@ bail:
1341 return ret; 1341 return ret;
1342} 1342}
1343 1343
1344static unsigned ipath_poll_hdrqfull(struct ipath_portdata *pd)
1345{
1346 unsigned pollflag = 0;
1347
1348 if ((pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) &&
1349 pd->port_hdrqfull != pd->port_hdrqfull_poll) {
1350 pollflag |= POLLIN | POLLRDNORM;
1351 pd->port_hdrqfull_poll = pd->port_hdrqfull;
1352 }
1353
1354 return pollflag;
1355}
1356
1344static unsigned int ipath_poll_urgent(struct ipath_portdata *pd, 1357static unsigned int ipath_poll_urgent(struct ipath_portdata *pd,
1345 struct file *fp, 1358 struct file *fp,
1346 struct poll_table_struct *pt) 1359 struct poll_table_struct *pt)
@@ -1350,22 +1363,20 @@ static unsigned int ipath_poll_urgent(struct ipath_portdata *pd,
1350 1363
1351 dd = pd->port_dd; 1364 dd = pd->port_dd;
1352 1365
1353 if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) { 1366 /* variable access in ipath_poll_hdrqfull() needs this */
1354 pollflag |= POLLERR; 1367 rmb();
1355 clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag); 1368 pollflag = ipath_poll_hdrqfull(pd);
1356 }
1357 1369
1358 if (test_bit(IPATH_PORT_WAITING_URG, &pd->int_flag)) { 1370 if (pd->port_urgent != pd->port_urgent_poll) {
1359 pollflag |= POLLIN | POLLRDNORM; 1371 pollflag |= POLLIN | POLLRDNORM;
1360 clear_bit(IPATH_PORT_WAITING_URG, &pd->int_flag); 1372 pd->port_urgent_poll = pd->port_urgent;
1361 } 1373 }
1362 1374
1363 if (!pollflag) { 1375 if (!pollflag) {
1376 /* this saves a spin_lock/unlock in interrupt handler... */
1364 set_bit(IPATH_PORT_WAITING_URG, &pd->port_flag); 1377 set_bit(IPATH_PORT_WAITING_URG, &pd->port_flag);
1365 if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) 1378 /* flush waiting flag so don't miss an event... */
1366 set_bit(IPATH_PORT_WAITING_OVERFLOW, 1379 wmb();
1367 &pd->port_flag);
1368
1369 poll_wait(fp, &pd->port_wait, pt); 1380 poll_wait(fp, &pd->port_wait, pt);
1370 } 1381 }
1371 1382
@@ -1376,31 +1387,27 @@ static unsigned int ipath_poll_next(struct ipath_portdata *pd,
1376 struct file *fp, 1387 struct file *fp,
1377 struct poll_table_struct *pt) 1388 struct poll_table_struct *pt)
1378{ 1389{
1379 u32 head, tail; 1390 u32 head;
1391 u32 tail;
1380 unsigned pollflag = 0; 1392 unsigned pollflag = 0;
1381 struct ipath_devdata *dd; 1393 struct ipath_devdata *dd;
1382 1394
1383 dd = pd->port_dd; 1395 dd = pd->port_dd;
1384 1396
1397 /* variable access in ipath_poll_hdrqfull() needs this */
1398 rmb();
1399 pollflag = ipath_poll_hdrqfull(pd);
1400
1385 head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port); 1401 head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port);
1386 tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr; 1402 tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr;
1387 1403
1388 if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) { 1404 if (head != tail)
1389 pollflag |= POLLERR;
1390 clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag);
1391 }
1392
1393 if (tail != head ||
1394 test_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag)) {
1395 pollflag |= POLLIN | POLLRDNORM; 1405 pollflag |= POLLIN | POLLRDNORM;
1396 clear_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag); 1406 else {
1397 } 1407 /* this saves a spin_lock/unlock in interrupt handler */
1398
1399 if (!pollflag) {
1400 set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag); 1408 set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
1401 if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) 1409 /* flush waiting flag so we don't miss an event */
1402 set_bit(IPATH_PORT_WAITING_OVERFLOW, 1410 wmb();
1403 &pd->port_flag);
1404 1411
1405 set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT, 1412 set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
1406 &dd->ipath_rcvctrl); 1413 &dd->ipath_rcvctrl);
@@ -1917,6 +1924,12 @@ static int ipath_do_user_init(struct file *fp,
1917 ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n", 1924 ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
1918 pd->port_port, head32); 1925 pd->port_port, head32);
1919 pd->port_tidcursor = 0; /* start at beginning after open */ 1926 pd->port_tidcursor = 0; /* start at beginning after open */
1927
1928 /* initialize poll variables... */
1929 pd->port_urgent = 0;
1930 pd->port_urgent_poll = 0;
1931 pd->port_hdrqfull_poll = pd->port_hdrqfull;
1932
1920 /* 1933 /*
1921 * now enable the port; the tail registers will be written to memory 1934 * now enable the port; the tail registers will be written to memory
1922 * by the chip as soon as it sees the write to 1935 * by the chip as soon as it sees the write to
@@ -2039,9 +2052,11 @@ static int ipath_close(struct inode *in, struct file *fp)
2039 2052
2040 if (dd->ipath_kregbase) { 2053 if (dd->ipath_kregbase) {
2041 int i; 2054 int i;
2042 /* atomically clear receive enable port. */ 2055 /* atomically clear receive enable port and intr avail. */
2043 clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port, 2056 clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
2044 &dd->ipath_rcvctrl); 2057 &dd->ipath_rcvctrl);
2058 clear_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT,
2059 &dd->ipath_rcvctrl);
2045 ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl, 2060 ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
2046 dd->ipath_rcvctrl); 2061 dd->ipath_rcvctrl);
2047 /* and read back from chip to be sure that nothing 2062 /* and read back from chip to be sure that nothing
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index 11b361408ae..61eac8cc0d9 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 }
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index d983f92b9bc..872fb36703d 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -139,6 +139,12 @@ struct ipath_portdata {
139 u32 port_pionowait; 139 u32 port_pionowait;
140 /* total number of rcvhdrqfull errors */ 140 /* total number of rcvhdrqfull errors */
141 u32 port_hdrqfull; 141 u32 port_hdrqfull;
142 /* saved total number of rcvhdrqfull errors for poll edge trigger */
143 u32 port_hdrqfull_poll;
144 /* total number of polled urgent packets */
145 u32 port_urgent;
146 /* saved total number of polled urgent packets for poll edge trigger */
147 u32 port_urgent_poll;
142 /* pid of process using this port */ 148 /* pid of process using this port */
143 pid_t port_pid; 149 pid_t port_pid;
144 /* same size as task_struct .comm[] */ 150 /* same size as task_struct .comm[] */
@@ -757,8 +763,6 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
757#define IPATH_PORT_MASTER_UNINIT 4 763#define IPATH_PORT_MASTER_UNINIT 4
758 /* waiting for an urgent packet to arrive */ 764 /* waiting for an urgent packet to arrive */
759#define IPATH_PORT_WAITING_URG 5 765#define IPATH_PORT_WAITING_URG 5
760 /* waiting for a header overflow */
761#define IPATH_PORT_WAITING_OVERFLOW 6
762 766
763/* free up any allocated data at closes */ 767/* free up any allocated data at closes */
764void ipath_free_data(struct ipath_portdata *dd); 768void ipath_free_data(struct ipath_portdata *dd);