diff options
author | Robert Walsh <robert.walsh@qlogic.com> | 2007-06-18 17:24:49 -0400 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2007-07-09 23:12:26 -0400 |
commit | f2d042313e420002b06715675963cfab48ed2597 (patch) | |
tree | ae149c8d21220aff9157952e39a7632be8c7ba61 /drivers/infiniband | |
parent | b506e1dc59726a1c608f26e7294b9fe186255139 (diff) |
IB/ipath: ipath_poll fixups and enhancements
Fix ipath_poll and enhance it so we can poll for urgent packets or
regular packets and receive notifications of when a header queue
overflows.
Signed-off-by: Robert Walsh <robert.walsh@qlogic.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_common.h | 11 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_file_ops.c | 125 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_intr.c | 38 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_kernel.h | 8 |
4 files changed, 131 insertions, 51 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h index f70788c25ea6..b4b786d0dfca 100644 --- a/drivers/infiniband/hw/ipath/ipath_common.h +++ b/drivers/infiniband/hw/ipath/ipath_common.h | |||
@@ -431,8 +431,15 @@ struct ipath_user_info { | |||
431 | #define IPATH_CMD_UNUSED_1 25 | 431 | #define IPATH_CMD_UNUSED_1 25 |
432 | #define IPATH_CMD_UNUSED_2 26 | 432 | #define IPATH_CMD_UNUSED_2 26 |
433 | #define IPATH_CMD_PIOAVAILUPD 27 /* force an update of PIOAvail reg */ | 433 | #define IPATH_CMD_PIOAVAILUPD 27 /* force an update of PIOAvail reg */ |
434 | #define IPATH_CMD_POLL_TYPE 28 /* set the kind of polling we want */ | ||
434 | 435 | ||
435 | #define IPATH_CMD_MAX 27 | 436 | #define IPATH_CMD_MAX 28 |
437 | |||
438 | /* | ||
439 | * Poll types | ||
440 | */ | ||
441 | #define IPATH_POLL_TYPE_URGENT 0x01 | ||
442 | #define IPATH_POLL_TYPE_OVERFLOW 0x02 | ||
436 | 443 | ||
437 | struct ipath_port_info { | 444 | struct ipath_port_info { |
438 | __u32 num_active; /* number of active units */ | 445 | __u32 num_active; /* number of active units */ |
@@ -473,6 +480,8 @@ struct ipath_cmd { | |||
473 | __u16 part_key; | 480 | __u16 part_key; |
474 | /* user address of __u32 bitmask of active slaves */ | 481 | /* user address of __u32 bitmask of active slaves */ |
475 | __u64 slave_mask_addr; | 482 | __u64 slave_mask_addr; |
483 | /* type of polling we want */ | ||
484 | __u16 poll_type; | ||
476 | } cmd; | 485 | } cmd; |
477 | }; | 486 | }; |
478 | 487 | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c index a47479608f48..33ab0d6b80ff 100644 --- a/drivers/infiniband/hw/ipath/ipath_file_ops.c +++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c | |||
@@ -1341,65 +1341,98 @@ bail: | |||
1341 | return ret; | 1341 | return ret; |
1342 | } | 1342 | } |
1343 | 1343 | ||
1344 | static unsigned int ipath_poll(struct file *fp, | 1344 | static unsigned int ipath_poll_urgent(struct ipath_portdata *pd, |
1345 | struct poll_table_struct *pt) | 1345 | struct file *fp, |
1346 | struct poll_table_struct *pt) | ||
1346 | { | 1347 | { |
1347 | struct ipath_portdata *pd; | ||
1348 | u32 head, tail; | ||
1349 | int bit; | ||
1350 | unsigned pollflag = 0; | 1348 | unsigned pollflag = 0; |
1351 | struct ipath_devdata *dd; | 1349 | struct ipath_devdata *dd; |
1352 | 1350 | ||
1353 | pd = port_fp(fp); | ||
1354 | if (!pd) | ||
1355 | goto bail; | ||
1356 | dd = pd->port_dd; | 1351 | dd = pd->port_dd; |
1357 | 1352 | ||
1358 | bit = pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT; | 1353 | if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) { |
1359 | set_bit(bit, &dd->ipath_rcvctrl); | 1354 | pollflag |= POLLERR; |
1355 | clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag); | ||
1356 | } | ||
1360 | 1357 | ||
1361 | /* | 1358 | if (test_bit(IPATH_PORT_WAITING_URG, &pd->int_flag)) { |
1362 | * Before blocking, make sure that head is still == tail, | 1359 | pollflag |= POLLIN | POLLRDNORM; |
1363 | * reading from the chip, so we can be sure the interrupt | 1360 | clear_bit(IPATH_PORT_WAITING_URG, &pd->int_flag); |
1364 | * enable has made it to the chip. If not equal, disable | 1361 | } |
1365 | * interrupt again and return immediately. This avoids races, | ||
1366 | * and the overhead of the chip read doesn't matter much at | ||
1367 | * this point, since we are waiting for something anyway. | ||
1368 | */ | ||
1369 | 1362 | ||
1370 | ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, | 1363 | if (!pollflag) { |
1371 | dd->ipath_rcvctrl); | 1364 | set_bit(IPATH_PORT_WAITING_URG, &pd->port_flag); |
1365 | if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) | ||
1366 | set_bit(IPATH_PORT_WAITING_OVERFLOW, | ||
1367 | &pd->port_flag); | ||
1368 | |||
1369 | poll_wait(fp, &pd->port_wait, pt); | ||
1370 | } | ||
1371 | |||
1372 | return pollflag; | ||
1373 | } | ||
1374 | |||
1375 | static unsigned int ipath_poll_next(struct ipath_portdata *pd, | ||
1376 | struct file *fp, | ||
1377 | struct poll_table_struct *pt) | ||
1378 | { | ||
1379 | u32 head, tail; | ||
1380 | unsigned pollflag = 0; | ||
1381 | struct ipath_devdata *dd; | ||
1382 | |||
1383 | dd = pd->port_dd; | ||
1372 | 1384 | ||
1373 | head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port); | 1385 | head = ipath_read_ureg32(dd, ur_rcvhdrhead, pd->port_port); |
1374 | tail = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port); | 1386 | tail = *(volatile u64 *)pd->port_rcvhdrtail_kvaddr; |
1387 | |||
1388 | if (test_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag)) { | ||
1389 | pollflag |= POLLERR; | ||
1390 | clear_bit(IPATH_PORT_WAITING_OVERFLOW, &pd->int_flag); | ||
1391 | } | ||
1375 | 1392 | ||
1376 | if (tail == head) { | 1393 | if (tail != head || |
1394 | test_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag)) { | ||
1395 | pollflag |= POLLIN | POLLRDNORM; | ||
1396 | clear_bit(IPATH_PORT_WAITING_RCV, &pd->int_flag); | ||
1397 | } | ||
1398 | |||
1399 | if (!pollflag) { | ||
1377 | set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag); | 1400 | set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag); |
1401 | if (pd->poll_type & IPATH_POLL_TYPE_OVERFLOW) | ||
1402 | set_bit(IPATH_PORT_WAITING_OVERFLOW, | ||
1403 | &pd->port_flag); | ||
1404 | |||
1405 | set_bit(pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT, | ||
1406 | &dd->ipath_rcvctrl); | ||
1407 | |||
1408 | ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, | ||
1409 | dd->ipath_rcvctrl); | ||
1410 | |||
1378 | if (dd->ipath_rhdrhead_intr_off) /* arm rcv interrupt */ | 1411 | if (dd->ipath_rhdrhead_intr_off) /* arm rcv interrupt */ |
1379 | (void)ipath_write_ureg(dd, ur_rcvhdrhead, | 1412 | ipath_write_ureg(dd, ur_rcvhdrhead, |
1380 | dd->ipath_rhdrhead_intr_off | 1413 | dd->ipath_rhdrhead_intr_off | head, |
1381 | | head, pd->port_port); | 1414 | pd->port_port); |
1382 | poll_wait(fp, &pd->port_wait, pt); | ||
1383 | 1415 | ||
1384 | if (test_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) { | 1416 | poll_wait(fp, &pd->port_wait, pt); |
1385 | /* timed out, no packets received */ | ||
1386 | clear_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag); | ||
1387 | pd->port_rcvwait_to++; | ||
1388 | } | ||
1389 | else | ||
1390 | pollflag = POLLIN | POLLRDNORM; | ||
1391 | } | ||
1392 | else { | ||
1393 | /* it's already happened; don't do wait_event overhead */ | ||
1394 | pollflag = POLLIN | POLLRDNORM; | ||
1395 | pd->port_rcvnowait++; | ||
1396 | } | 1417 | } |
1397 | 1418 | ||
1398 | clear_bit(bit, &dd->ipath_rcvctrl); | 1419 | return pollflag; |
1399 | ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl, | 1420 | } |
1400 | dd->ipath_rcvctrl); | 1421 | |
1422 | static unsigned int ipath_poll(struct file *fp, | ||
1423 | struct poll_table_struct *pt) | ||
1424 | { | ||
1425 | struct ipath_portdata *pd; | ||
1426 | unsigned pollflag; | ||
1427 | |||
1428 | pd = port_fp(fp); | ||
1429 | if (!pd) | ||
1430 | pollflag = 0; | ||
1431 | else if (pd->poll_type & IPATH_POLL_TYPE_URGENT) | ||
1432 | pollflag = ipath_poll_urgent(pd, fp, pt); | ||
1433 | else | ||
1434 | pollflag = ipath_poll_next(pd, fp, pt); | ||
1401 | 1435 | ||
1402 | bail: | ||
1403 | return pollflag; | 1436 | return pollflag; |
1404 | } | 1437 | } |
1405 | 1438 | ||
@@ -2173,6 +2206,11 @@ static ssize_t ipath_write(struct file *fp, const char __user *data, | |||
2173 | src = NULL; | 2206 | src = NULL; |
2174 | dest = NULL; | 2207 | dest = NULL; |
2175 | break; | 2208 | break; |
2209 | case IPATH_CMD_POLL_TYPE: | ||
2210 | copy = sizeof(cmd.cmd.poll_type); | ||
2211 | dest = &cmd.cmd.poll_type; | ||
2212 | src = &ucmd->cmd.poll_type; | ||
2213 | break; | ||
2176 | default: | 2214 | default: |
2177 | ret = -EINVAL; | 2215 | ret = -EINVAL; |
2178 | goto bail; | 2216 | goto bail; |
@@ -2245,6 +2283,9 @@ static ssize_t ipath_write(struct file *fp, const char __user *data, | |||
2245 | case IPATH_CMD_PIOAVAILUPD: | 2283 | case IPATH_CMD_PIOAVAILUPD: |
2246 | ret = ipath_force_pio_avail_update(pd->port_dd); | 2284 | ret = ipath_force_pio_avail_update(pd->port_dd); |
2247 | break; | 2285 | break; |
2286 | case IPATH_CMD_POLL_TYPE: | ||
2287 | pd->poll_type = cmd.cmd.poll_type; | ||
2288 | break; | ||
2248 | } | 2289 | } |
2249 | 2290 | ||
2250 | if (ret >= 0) | 2291 | if (ret >= 0) |
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c index 948091f7d5ac..f8aac8e932f5 100644 --- a/drivers/infiniband/hw/ipath/ipath_intr.c +++ b/drivers/infiniband/hw/ipath/ipath_intr.c | |||
@@ -680,6 +680,17 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs) | |||
680 | chkerrpkts = 1; | 680 | chkerrpkts = 1; |
681 | dd->ipath_lastrcvhdrqtails[i] = tl; | 681 | dd->ipath_lastrcvhdrqtails[i] = tl; |
682 | pd->port_hdrqfull++; | 682 | pd->port_hdrqfull++; |
683 | if (test_bit(IPATH_PORT_WAITING_OVERFLOW, | ||
684 | &pd->port_flag)) { | ||
685 | clear_bit( | ||
686 | IPATH_PORT_WAITING_OVERFLOW, | ||
687 | &pd->port_flag); | ||
688 | set_bit( | ||
689 | IPATH_PORT_WAITING_OVERFLOW, | ||
690 | &pd->int_flag); | ||
691 | wake_up_interruptible( | ||
692 | &pd->port_wait); | ||
693 | } | ||
683 | } | 694 | } |
684 | } | 695 | } |
685 | } | 696 | } |
@@ -877,14 +888,25 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat) | |||
877 | dd->ipath_i_rcvurg_mask); | 888 | dd->ipath_i_rcvurg_mask); |
878 | for (i = 1; i < dd->ipath_cfgports; i++) { | 889 | for (i = 1; i < dd->ipath_cfgports; i++) { |
879 | struct ipath_portdata *pd = dd->ipath_pd[i]; | 890 | struct ipath_portdata *pd = dd->ipath_pd[i]; |
880 | if (portr & (1 << i) && pd && pd->port_cnt && | 891 | if (portr & (1 << i) && pd && pd->port_cnt) { |
881 | test_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag)) { | 892 | if (test_bit(IPATH_PORT_WAITING_RCV, |
882 | clear_bit(IPATH_PORT_WAITING_RCV, | 893 | &pd->port_flag)) { |
883 | &pd->port_flag); | 894 | clear_bit(IPATH_PORT_WAITING_RCV, |
884 | clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT, | 895 | &pd->port_flag); |
885 | &dd->ipath_rcvctrl); | 896 | set_bit(IPATH_PORT_WAITING_RCV, |
886 | wake_up_interruptible(&pd->port_wait); | 897 | &pd->int_flag); |
887 | rcvdint = 1; | 898 | clear_bit(i + INFINIPATH_R_INTRAVAIL_SHIFT, |
899 | &dd->ipath_rcvctrl); | ||
900 | wake_up_interruptible(&pd->port_wait); | ||
901 | rcvdint = 1; | ||
902 | } else if (test_bit(IPATH_PORT_WAITING_URG, | ||
903 | &pd->port_flag)) { | ||
904 | clear_bit(IPATH_PORT_WAITING_URG, | ||
905 | &pd->port_flag); | ||
906 | set_bit(IPATH_PORT_WAITING_URG, | ||
907 | &pd->int_flag); | ||
908 | wake_up_interruptible(&pd->port_wait); | ||
909 | } | ||
888 | } | 910 | } |
889 | } | 911 | } |
890 | if (rcvdint) { | 912 | if (rcvdint) { |
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h index 2e85aeca5eac..034c283990e8 100644 --- a/drivers/infiniband/hw/ipath/ipath_kernel.h +++ b/drivers/infiniband/hw/ipath/ipath_kernel.h | |||
@@ -127,6 +127,8 @@ struct ipath_portdata { | |||
127 | u32 port_tidcursor; | 127 | u32 port_tidcursor; |
128 | /* next expected TID to check */ | 128 | /* next expected TID to check */ |
129 | unsigned long port_flag; | 129 | unsigned long port_flag; |
130 | /* what happened */ | ||
131 | unsigned long int_flag; | ||
130 | /* WAIT_RCV that timed out, no interrupt */ | 132 | /* WAIT_RCV that timed out, no interrupt */ |
131 | u32 port_rcvwait_to; | 133 | u32 port_rcvwait_to; |
132 | /* WAIT_PIO that timed out, no interrupt */ | 134 | /* WAIT_PIO that timed out, no interrupt */ |
@@ -155,6 +157,8 @@ struct ipath_portdata { | |||
155 | u32 userversion; | 157 | u32 userversion; |
156 | /* Bitmask of active slaves */ | 158 | /* Bitmask of active slaves */ |
157 | u32 active_slaves; | 159 | u32 active_slaves; |
160 | /* Type of packets or conditions we want to poll for */ | ||
161 | u16 poll_type; | ||
158 | }; | 162 | }; |
159 | 163 | ||
160 | struct sk_buff; | 164 | struct sk_buff; |
@@ -754,6 +758,10 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv); | |||
754 | #define IPATH_PORT_WAITING_PIO 3 | 758 | #define IPATH_PORT_WAITING_PIO 3 |
755 | /* master has not finished initializing */ | 759 | /* master has not finished initializing */ |
756 | #define IPATH_PORT_MASTER_UNINIT 4 | 760 | #define IPATH_PORT_MASTER_UNINIT 4 |
761 | /* waiting for an urgent packet to arrive */ | ||
762 | #define IPATH_PORT_WAITING_URG 5 | ||
763 | /* waiting for a header overflow */ | ||
764 | #define IPATH_PORT_WAITING_OVERFLOW 6 | ||
757 | 765 | ||
758 | /* free up any allocated data at closes */ | 766 | /* free up any allocated data at closes */ |
759 | void ipath_free_data(struct ipath_portdata *dd); | 767 | void ipath_free_data(struct ipath_portdata *dd); |