aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryan O'Sullivan <bos@pathscale.com>2006-07-01 07:36:05 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-07-01 12:56:00 -0400
commit57abad25f844e760082c0b1ab2b176dad682ea16 (patch)
tree5a61c70ed4ae1ad7ccb8c246c22480d8bb045f46
parentf5f99929ac584126ef3f47d805dc619abc54768c (diff)
[PATCH] IB/ipath: fix lost interrupts on HT-400
Do an extra check to see if in-memory tail changed while processing packets, and if so, going back through the loop again (but only once per call to ipath_kreceive()). In practice, this seems to be enough to guarantee that if we crossed the clearing of an interrupt at start of ipath_intr with a scheduled tail register update, that we'll process the "extra" packet that lost the interrupt because we cleared it just as it was about to arrive. Signed-off-by: Dave Olson <dave.olson@qlogic.com> Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com> Cc: "Michael S. Tsirkin" <mst@mellanox.co.il> Cc: Roland Dreier <rolandd@cisco.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c25
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c28
2 files changed, 36 insertions, 17 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index e2b0bc8ebaf4..66b41ecf898b 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -870,7 +870,7 @@ void ipath_kreceive(struct ipath_devdata *dd)
870 const u32 maxcnt = dd->ipath_rcvhdrcnt * rsize; /* words */ 870 const u32 maxcnt = dd->ipath_rcvhdrcnt * rsize; /* words */
871 u32 etail = -1, l, hdrqtail; 871 u32 etail = -1, l, hdrqtail;
872 struct ips_message_header *hdr; 872 struct ips_message_header *hdr;
873 u32 eflags, i, etype, tlen, pkttot = 0, updegr=0; 873 u32 eflags, i, etype, tlen, pkttot = 0, updegr=0, reloop=0;
874 static u64 totcalls; /* stats, may eventually remove */ 874 static u64 totcalls; /* stats, may eventually remove */
875 char emsg[128]; 875 char emsg[128];
876 876
@@ -885,9 +885,11 @@ void ipath_kreceive(struct ipath_devdata *dd)
885 goto bail; 885 goto bail;
886 886
887 l = dd->ipath_port0head; 887 l = dd->ipath_port0head;
888 if (l == (u32)le64_to_cpu(*dd->ipath_hdrqtailptr)) 888 hdrqtail = (u32) le64_to_cpu(*dd->ipath_hdrqtailptr);
889 if (l == hdrqtail)
889 goto done; 890 goto done;
890 891
892reloop:
891 /* read only once at start for performance */ 893 /* read only once at start for performance */
892 hdrqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr); 894 hdrqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
893 895
@@ -1011,7 +1013,7 @@ void ipath_kreceive(struct ipath_devdata *dd)
1011 */ 1013 */
1012 if (l == hdrqtail || (i && !(i&0xf))) { 1014 if (l == hdrqtail || (i && !(i&0xf))) {
1013 u64 lval; 1015 u64 lval;
1014 if (l == hdrqtail) /* want interrupt only on last */ 1016 if (l == hdrqtail) /* PE-800 interrupt only on last */
1015 lval = dd->ipath_rhdrhead_intr_off | l; 1017 lval = dd->ipath_rhdrhead_intr_off | l;
1016 else 1018 else
1017 lval = l; 1019 lval = l;
@@ -1024,6 +1026,23 @@ void ipath_kreceive(struct ipath_devdata *dd)
1024 } 1026 }
1025 } 1027 }
1026 1028
1029 if (!dd->ipath_rhdrhead_intr_off && !reloop) {
1030 /* HT-400 workaround; we can have a race clearing chip
1031 * interrupt with another interrupt about to be delivered,
1032 * and can clear it before it is delivered on the GPIO
1033 * workaround. By doing the extra check here for the
1034 * in-memory tail register updating while we were doing
1035 * earlier packets, we "almost" guarantee we have covered
1036 * that case.
1037 */
1038 u32 hqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
1039 if (hqtail != hdrqtail) {
1040 hdrqtail = hqtail;
1041 reloop = 1; /* loop 1 extra time at most */
1042 goto reloop;
1043 }
1044 }
1045
1027 pkttot += i; 1046 pkttot += i;
1028 1047
1029 dd->ipath_port0head = l; 1048 dd->ipath_port0head = l;
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index bad20a395265..83b51ed89527 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -766,7 +766,7 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
766 u32 istat, chk0rcv = 0; 766 u32 istat, chk0rcv = 0;
767 ipath_err_t estat = 0; 767 ipath_err_t estat = 0;
768 irqreturn_t ret; 768 irqreturn_t ret;
769 u32 p0bits, oldhead; 769 u32 oldhead, curtail;
770 static unsigned unexpected = 0; 770 static unsigned unexpected = 0;
771 static const u32 port0rbits = (1U<<INFINIPATH_I_RCVAVAIL_SHIFT) | 771 static const u32 port0rbits = (1U<<INFINIPATH_I_RCVAVAIL_SHIFT) |
772 (1U<<INFINIPATH_I_RCVURG_SHIFT); 772 (1U<<INFINIPATH_I_RCVURG_SHIFT);
@@ -809,15 +809,16 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
809 * lose intr for later packets that arrive while we are processing. 809 * lose intr for later packets that arrive while we are processing.
810 */ 810 */
811 oldhead = dd->ipath_port0head; 811 oldhead = dd->ipath_port0head;
812 if (oldhead != (u32) le64_to_cpu(*dd->ipath_hdrqtailptr)) { 812 curtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
813 if (oldhead != curtail) {
813 if (dd->ipath_flags & IPATH_GPIO_INTR) { 814 if (dd->ipath_flags & IPATH_GPIO_INTR) {
814 ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear, 815 ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
815 (u64) (1 << 2)); 816 (u64) (1 << 2));
816 p0bits = port0rbits | INFINIPATH_I_GPIO; 817 istat = port0rbits | INFINIPATH_I_GPIO;
817 } 818 }
818 else 819 else
819 p0bits = port0rbits; 820 istat = port0rbits;
820 ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, p0bits); 821 ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, istat);
821 ipath_kreceive(dd); 822 ipath_kreceive(dd);
822 if (oldhead != dd->ipath_port0head) { 823 if (oldhead != dd->ipath_port0head) {
823 ipath_stats.sps_fastrcvint++; 824 ipath_stats.sps_fastrcvint++;
@@ -827,7 +828,6 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
827 } 828 }
828 829
829 istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus); 830 istat = ipath_read_kreg32(dd, dd->ipath_kregs->kr_intstatus);
830 p0bits = port0rbits;
831 831
832 if (unlikely(!istat)) { 832 if (unlikely(!istat)) {
833 ipath_stats.sps_nullintr++; 833 ipath_stats.sps_nullintr++;
@@ -890,19 +890,19 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
890 else { 890 else {
891 /* Clear GPIO status bit 2 */ 891 /* Clear GPIO status bit 2 */
892 ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear, 892 ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
893 (u64) (1 << 2)); 893 (u64) (1 << 2));
894 p0bits |= INFINIPATH_I_GPIO;
895 chk0rcv = 1; 894 chk0rcv = 1;
896 } 895 }
897 } 896 }
898 chk0rcv |= istat & p0bits; 897 chk0rcv |= istat & port0rbits;
899 898
900 /* 899 /*
901 * clear the ones we will deal with on this round 900 * Clear the interrupt bits we found set, unless they are receive
902 * We clear it early, mostly for receive interrupts, so we 901 * related, in which case we already cleared them above, and don't
903 * know the chip will have seen this by the time we process 902 * want to clear them again, because we might lose an interrupt.
904 * the queue, and will re-interrupt if necessary. The processor 903 * Clear it early, so we "know" know the chip will have seen this by
905 * itself won't take the interrupt again until we return. 904 * the time we process the queue, and will re-interrupt if necessary.
905 * The processor itself won't take the interrupt again until we return.
906 */ 906 */
907 ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, istat); 907 ipath_write_kreg(dd, dd->ipath_kregs->kr_intclear, istat);
908 908