summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2009-05-06 20:08:48 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2009-05-06 20:08:48 +0000
commit737eb819e7c02bbee85545db8e0e2fb75d342052 (patch)
tree8fe79192febab46a370bc3b89f96d193653e6fc8
parentc52e153b4f274e8abfebe4cd275cacce3aee3f2f (diff)
Workaround a bridge deadlock, as advised by comments found in the linux sn1
code.
-rw-r--r--sys/arch/sgi/include/mnode.h6
-rw-r--r--sys/arch/sgi/xbow/xbridge.c30
-rw-r--r--sys/arch/sgi/xbow/xbridgereg.h5
3 files changed, 35 insertions, 6 deletions
diff --git a/sys/arch/sgi/include/mnode.h b/sys/arch/sgi/include/mnode.h
index b5bd754b161..0cf495b37a0 100644
--- a/sys/arch/sgi/include/mnode.h
+++ b/sys/arch/sgi/include/mnode.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: mnode.h,v 1.2 2009/05/02 21:26:00 miod Exp $ */
+/* $OpenBSD: mnode.h,v 1.3 2009/05/06 20:08:44 miod Exp $ */
/*
* Copyright (c) 2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
@@ -363,8 +363,8 @@ typedef struct klttydev_s {
#define IP27_LHUB_S(r, d) *(IP27_LHUB_ADDR(r)) = (d)
#define IP27_RHUB_L(n, r) *(IP27_RHUB_ADDR((n), (r))
#define IP27_RHUB_S(n, r, d) *(IP27_RHUB_ADDR((n), (r)) = (d)
-#define IP27_RHUB_PI_L(n, s, r) *(IP27_RHUB_PI_ADDR((n), (s), (r))
-#define IP27_RHUB_PI_S(n, s, r, d) *(IP27_RHUB_PI_ADDR((n), (s), (r)) = (d)
+#define IP27_RHUB_PI_L(n, s, r) *(IP27_RHUB_PI_ADDR((n), (s), (r)))
+#define IP27_RHUB_PI_S(n, s, r, d) *(IP27_RHUB_PI_ADDR((n), (s), (r))) = (d)
/* HUB I/O registers */
diff --git a/sys/arch/sgi/xbow/xbridge.c b/sys/arch/sgi/xbow/xbridge.c
index 08e115d2079..3e95eab6b1d 100644
--- a/sys/arch/sgi/xbow/xbridge.c
+++ b/sys/arch/sgi/xbow/xbridge.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: xbridge.c,v 1.14 2009/05/03 19:44:28 miod Exp $ */
+/* $OpenBSD: xbridge.c,v 1.15 2009/05/06 20:08:47 miod Exp $ */
/*
* Copyright (c) 2008, 2009 Miodrag Vallat.
@@ -33,12 +33,14 @@
#include <machine/bus.h>
#include <machine/cpu.h>
#include <machine/intr.h>
+#include <machine/mnode.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include <dev/pci/pcidevs.h>
#include <mips64/archtype.h>
+#include <sgi/xbow/hub.h>
#include <sgi/xbow/xbow.h>
#include <sgi/xbow/xbowdevs.h>
@@ -495,7 +497,8 @@ xbridge_conf_write(void *cookie, pcitag_t tag, int offset, pcireg_t data)
struct xbridge_intr {
struct xbridge_softc *xi_bridge;
- int xi_intrsrc;
+ int xi_intrsrc; /* interrupt source on interrupt widget */
+ int xi_intrbit; /* interrupt source on BRIDGE */
int (*xi_func)(void *);
void *xi_arg;
@@ -588,6 +591,7 @@ xbridge_intr_establish(void *cookie, pci_intr_handle_t ih, int level,
xi->xi_bridge = sc;
xi->xi_intrsrc = intrsrc;
+ xi->xi_intrbit = intrbit;
xi->xi_func = func;
xi->xi_arg = arg;
xi->xi_level = level;
@@ -648,6 +652,7 @@ xbridge_intr_handler(void *v)
{
struct xbridge_intr *xi = v;
struct xbridge_softc *sc = xi->xi_bridge;
+ uint16_t nasid = 0; /* XXX */
int rc;
if (xi == NULL) {
@@ -659,6 +664,27 @@ xbridge_intr_handler(void *v)
if ((rc = (*xi->xi_func)(xi->xi_arg)) != 0)
xi->xi_count.ec_count++;
+ /*
+ * There is a known BRIDGE race in which, if two interrupts
+ * on two different pins occur within 60nS of each other,
+ * further interrupts on the first pin do not cause an interrupt
+ * to be sent.
+ *
+ * The workaround against this is to check if our interrupt source
+ * is still active (i.e. another interrupt is pending), in which
+ * case we force an interrupt anyway.
+ *
+ * The XBridge even has a nice facility to do this, where we do not
+ * even have to check if our interrupt is pending.
+ */
+
+ if (ISSET(sc->sc_flags, XBRIDGE_FLAGS_XBRIDGE)) {
+ bus_space_write_4(sc->sc_iot, sc->sc_regh,
+ BRIDGE_INT_FORCE_PIN(xi->xi_intrbit), 1);
+ } else {
+ IP27_RHUB_PI_S(nasid, 0, HUB_IR_CHANGE, xi->xi_intrsrc);
+ }
+
return rc;
}
diff --git a/sys/arch/sgi/xbow/xbridgereg.h b/sys/arch/sgi/xbow/xbridgereg.h
index 8b9e2718778..e0a176cce03 100644
--- a/sys/arch/sgi/xbow/xbridgereg.h
+++ b/sys/arch/sgi/xbow/xbridgereg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: xbridgereg.h,v 1.3 2009/05/03 19:44:28 miod Exp $ */
+/* $OpenBSD: xbridgereg.h,v 1.4 2009/05/06 20:08:47 miod Exp $ */
/*
* Copyright (c) 2008 Miodrag Vallat.
@@ -66,6 +66,9 @@
#define BRIDGE_INT_DEV 0x00000124
#define BRIDGE_INT_HOST_ERR 0x0000012c
#define BRIDGE_INT_ADDR(d) (0x00000134 + 8 * (d))
+/* the following two are XBridge-only */
+#define BRIDGE_INT_FORCE_ALWAYS(d) (0x00000184 + 8 * (d))
+#define BRIDGE_INT_FORCE_PIN(d) (0x000001c4 + 8 * (d))
/*
* PCI Resource Mapping control