[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>
Bu işleme şunda yer alıyor:
Bryan O'Sullivan
2006-07-01 04:36:05 -07:00
işlemeyi yapan: Linus Torvalds
ebeveyn f5f99929ac
işleme 57abad25f8
2 değiştirilmiş dosya ile 36 ekleme ve 17 silme

Dosyayı Görüntüle

@@ -870,7 +870,7 @@ void ipath_kreceive(struct ipath_devdata *dd)
const u32 maxcnt = dd->ipath_rcvhdrcnt * rsize; /* words */
u32 etail = -1, l, hdrqtail;
struct ips_message_header *hdr;
u32 eflags, i, etype, tlen, pkttot = 0, updegr=0;
u32 eflags, i, etype, tlen, pkttot = 0, updegr=0, reloop=0;
static u64 totcalls; /* stats, may eventually remove */
char emsg[128];
@@ -885,9 +885,11 @@ void ipath_kreceive(struct ipath_devdata *dd)
goto bail;
l = dd->ipath_port0head;
if (l == (u32)le64_to_cpu(*dd->ipath_hdrqtailptr))
hdrqtail = (u32) le64_to_cpu(*dd->ipath_hdrqtailptr);
if (l == hdrqtail)
goto done;
reloop:
/* read only once at start for performance */
hdrqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
@@ -1011,7 +1013,7 @@ void ipath_kreceive(struct ipath_devdata *dd)
*/
if (l == hdrqtail || (i && !(i&0xf))) {
u64 lval;
if (l == hdrqtail) /* want interrupt only on last */
if (l == hdrqtail) /* PE-800 interrupt only on last */
lval = dd->ipath_rhdrhead_intr_off | l;
else
lval = l;
@@ -1024,6 +1026,23 @@ void ipath_kreceive(struct ipath_devdata *dd)
}
}
if (!dd->ipath_rhdrhead_intr_off && !reloop) {
/* HT-400 workaround; we can have a race clearing chip
* interrupt with another interrupt about to be delivered,
* and can clear it before it is delivered on the GPIO
* workaround. By doing the extra check here for the
* in-memory tail register updating while we were doing
* earlier packets, we "almost" guarantee we have covered
* that case.
*/
u32 hqtail = (u32)le64_to_cpu(*dd->ipath_hdrqtailptr);
if (hqtail != hdrqtail) {
hdrqtail = hqtail;
reloop = 1; /* loop 1 extra time at most */
goto reloop;
}
}
pkttot += i;
dd->ipath_port0head = l;