From a49ed2a67303d410e00f1be2d08230b1c61c6d41 Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Thu, 30 Mar 2006 04:25:45 +0000 Subject: [PATCH] On some laptops, under very high loads, the socket event register read in the ISR doesn't read the actual socket event register, but instead reads garbage (usually 0xffffffff, but other times other things). This totally violates the PCI spec, but happens rarely enough that a workaround is in order. This adds one test when we have a real interrupt to service (which is very rare), and doesn't affect the usualy 'nothing to see here' case at all. Problem reported by many, but sam@ gave me this workaround after diagnosing the problem. --- sys/dev/pccbb/pccbb.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/sys/dev/pccbb/pccbb.c b/sys/dev/pccbb/pccbb.c index 9d51a790d3c..f3ced97d31d 100644 --- a/sys/dev/pccbb/pccbb.c +++ b/sys/dev/pccbb/pccbb.c @@ -650,8 +650,19 @@ cbb_intr(void *arg) struct cbb_softc *sc = arg; uint32_t sockevent; + /* + * Read the socket event. Sometimes, the theory goes, the PCI + * bus is so loaded that it cannot satisfy the read request, so + * we get garbage back from the following read. We have to filter + * out the garbage so that we don't spontaneously reset the card + * under high load. PCI isn't supposed to act like this. No doubt + * this is a bug in the PCI bridge chipset (or cbb brige) that's being + * used in certain amd64 laptops today. Work around the issue by + * assuming that any bits we don't know about being set means that + * we got garbage. + */ sockevent = cbb_get(sc, CBB_SOCKET_EVENT); - if (sockevent != 0) { + if (sockevent != 0 && (sockevent & CBB_SOCKET_EVENT_VALID_MASK) == 0) { /* ack the interrupt */ cbb_set(sc, CBB_SOCKET_EVENT, sockevent); @@ -697,7 +708,7 @@ cbb_intr(void *arg) * indication above. * * We have to call this unconditionally because some bridges deliver - * the even independent of the CBB_SOCKET_EVENT_CD above. + * the event independent of the CBB_SOCKET_EVENT_CD above. */ exca_getb(&sc->exca[0], EXCA_CSC); }