Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 29 May 2003 13:37:31 +0200
From:      Thomas Moestl <t.moestl@tu-bs.de>
To:        freebsd-sparc64@FreeBSD.org
Subject:   PLEASE TEST: interrupt assignment patch
Message-ID:  <20030529113731.GB630@crow.dom2ip.de>

next in thread | raw e-mail | index | archive | help

--HlL+5n6rz5pIUxbD
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi,

I would like to get the attached patch into 5.1; although I am quite
confident that it will not break anything, we need a good test coverage
(i.e. testing on many different models) to make sure this is the case,
since we are that close to a release.

Therefore, I would very much appreciate if people could give this a
spin on their machines and report back.

The aim of the patch is to fix the interrupt assignment on e450s; it
should not have any effect on other boxen. It has been tested so far
on two e450s, a Blade 100 and an u60.

Thanks,
	- Thomas

-- 
Thomas Moestl <t.moestl@tu-bs.de>	http://www.tu-bs.de/~y0015675/
              <tmm@FreeBSD.org>		http://people.FreeBSD.org/~tmm/
PGP fingerprint: 1C97 A604 2BD0 E492 51D0  9C0F 1FE6 4F1D 419C 776C

--HlL+5n6rz5pIUxbD
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="guess-ino.diff"

Index: ebus/ebus.c
===================================================================
RCS file: /vol/ncvs/src/sys/sparc64/ebus/ebus.c,v
retrieving revision 1.7
diff -u -r1.7 ebus.c
--- ebus/ebus.c	19 Feb 2003 05:47:44 -0000	1.7
+++ ebus/ebus.c	23 May 2003 10:53:26 -0000
@@ -112,7 +112,7 @@
     u_long, u_long, u_long, u_int);
 static struct resource_list *ebus_get_resource_list(device_t, device_t);
 
-static struct ebus_devinfo *ebus_setup_dinfo(struct ebus_softc *,
+static struct ebus_devinfo *ebus_setup_dinfo(device_t, struct ebus_softc *,
     phandle_t, char *);
 static void ebus_destroy_dinfo(struct ebus_devinfo *);
 static int ebus_print_res(struct ebus_devinfo *);
@@ -200,7 +200,7 @@
 		if ((OF_getprop_alloc(node, "name", 1, (void **)&cname)) == -1)
 			continue;
 
-		if ((edi = ebus_setup_dinfo(sc, node, cname)) == NULL) {
+		if ((edi = ebus_setup_dinfo(dev, sc, node, cname)) == NULL) {
 			device_printf(dev, "<%s>: incomplete\n", cname);
 			free(cname, M_OFWPROP);
 			continue;
@@ -363,7 +363,8 @@
 }
 
 static struct ebus_devinfo *
-ebus_setup_dinfo(struct ebus_softc *sc, phandle_t node, char *name)
+ebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node,
+    char *name)
 {
 	struct ebus_devinfo *edi;
 	struct isa_regs *reg;
@@ -398,7 +399,8 @@
 	nintr = OF_getprop_alloc(node, "interrupts",  sizeof(*intrs),
 	    (void **)&intrs);
 	for (i = 0; i < nintr; i++) {
-		intr = ofw_bus_route_intr(node, intrs[i], ofw_pci_orb_callback);
+		intr = ofw_bus_route_intr(node, intrs[i], ofw_pci_orb_callback,
+		    dev);
 		if (intr == ORIR_NOTFOUND) {
 			panic("ebus_setup_dinfo: could not map ebus "
 			    "interrupt %d", intrs[i]);
Index: include/ofw_bus.h
===================================================================
RCS file: /vol/ncvs/src/sys/sparc64/include/ofw_bus.h,v
retrieving revision 1.3
diff -u -r1.3 ofw_bus.h
--- include/ofw_bus.h	7 Nov 2002 16:07:46 -0000	1.3
+++ include/ofw_bus.h	23 May 2003 10:53:26 -0000
@@ -32,8 +32,8 @@
 #define	ORIR_NOTFOUND	0xffffffff
 
 typedef int obr_callback_t(phandle_t, u_int8_t *, int, u_int8_t *, int,
-    u_int8_t **, int *);
+    u_int8_t **, int *, void *);
 
-u_int32_t ofw_bus_route_intr(phandle_t, int, obr_callback_t *);
+u_int32_t ofw_bus_route_intr(phandle_t, int, obr_callback_t *, void *);
 
 #endif /* !_MACHINE_OFW_BUS_H_ */
Index: isa/isa.c
===================================================================
RCS file: /vol/ncvs/src/sys/sparc64/isa/isa.c,v
retrieving revision 1.5
diff -u -r1.5 isa.c
--- isa/isa.c	7 Nov 2002 16:07:46 -0000	1.5
+++ isa/isa.c	23 May 2003 10:53:26 -0000
@@ -134,7 +134,7 @@
 		if (ino > 7)
 			panic("isa_init: XXX: ino too large");
 		isa_ino[ino] = ofw_bus_route_intr(node, ino,
-		    ofw_pci_orb_callback);
+		    ofw_pci_orb_callback, dev);
 	}
 
 	for (nbr -= 1; nbr >= 0; nbr--) {
Index: pci/ofw_pci.c
===================================================================
RCS file: /vol/ncvs/src/sys/sparc64/pci/ofw_pci.c,v
retrieving revision 1.10
diff -u -r1.10 ofw_pci.c
--- pci/ofw_pci.c	27 Mar 2003 02:01:59 -0000	1.10
+++ pci/ofw_pci.c	27 May 2003 11:55:48 -0000
@@ -46,44 +46,90 @@
 
 #include <sparc64/pci/ofw_pci.h>
 
+#include <machine/bus.h>
 #include <machine/cache.h>
 #include <machine/iommureg.h>
 #include <machine/ofw_bus.h>
 #include <machine/ver.h>
 
 #include "pcib_if.h"
+#include "sparcbus_if.h"
 
 u_int8_t pci_bus_cnt;
 phandle_t *pci_bus_map;
 int pci_bus_map_sz;
 
-#define	OPQ_NO_SWIZZLE	1
+/* Do not swizzle on a PCI bus node with no interrupt-map propery. */
+#define	OPQ_NO_SWIZZLE		1
+/*
+ * INOs < 255 are really intpin numbers; use a driver method to figure out
+ * the real INO.
+ */
+#define	OPQ_INO_CALLBACK	2
+/*
+ * Do not map EBus interrupts at PCI buses, but assume that they are fully
+ * specified already.
+ */
+#define	OPQ_EBUS_NOMAP		4
+
 static struct ofw_pci_quirk {
 	char	*opq_model;
 	int	opq_quirks;
 } ofw_pci_quirks[] = {
-	{ "SUNW,Ultra-4", OPQ_NO_SWIZZLE },
-	{ "SUNW,Ultra-1-Engine", OPQ_NO_SWIZZLE },
+	{ "SUNW,Ultra-4",		OPQ_INO_CALLBACK | OPQ_EBUS_NOMAP },
+	{ "SUNW,Ultra-1-Engine",	OPQ_NO_SWIZZLE },
 };
 #define	OPQ_NENT	(sizeof(ofw_pci_quirks) / sizeof(ofw_pci_quirks[0]))
 
 static int pci_quirks;
 
 #define	OFW_PCI_PCIBUS	"pci"
+#define	OFW_PCI_EBUS	"ebus"
 #define	PCI_BUS_MAP_INC	10
 
 int
 ofw_pci_orb_callback(phandle_t node, u_int8_t *pintptr, int pintsz,
-    u_int8_t *pregptr, int pregsz, u_int8_t **rintr, int *terminate)
+    u_int8_t *pregptr, int pregsz, u_int8_t **rintr, int *terminate,
+    void *cookie)
 {
+	device_t dev = cookie;
 	struct ofw_pci_register preg;
 	u_int32_t pintr, intr;
+	u_int slot;
 	char type[32];
+	int found = 0;
 
-	if (pintsz != sizeof(u_int32_t))
+	if ((pci_quirks & OPQ_EBUS_NOMAP) != 0 &&
+	    OF_getprop(node, "name", type, sizeof(type)) != -1 &&
+	    strcmp(type, OFW_PCI_EBUS) == 0) {
+		*terminate = 1;
+		return (-1);
+	}
+	if (pintsz != sizeof(u_int32_t) || pregsz < sizeof(preg))
 		return (-1);
 	bcopy(pintptr, &pintr, sizeof(pintr));
-	if ((pci_quirks & OPQ_NO_SWIZZLE) == 0 && pregsz >= sizeof(preg) &&
+	bcopy(pregptr, &preg, sizeof(preg));
+	slot = OFW_PCI_PHYS_HI_DEVICE(preg.phys_hi);
+
+	if ((pci_quirks & OPQ_INO_CALLBACK) != 0 && pintr <= 255) {
+		/*
+		 * The e450 has no interrupt maps at all, and it usually has
+		 * full interrupt numbers, including IGN, in the interrupt
+		 * properties. There is one exception, however: the property
+		 * values for external PCI devices seem to always be below 255
+		 * and describe the interrupt pin to be used on the slot, while
+		 * we have to figure out the base INO by looking at the slot
+		 * number (which we do using a sparcbus method).
+		 *
+		 * Of course, there is an exception to that nice rule:
+		 * in the ebus case, the interrupt property has the correct
+		 * INO (but without IGN). This is dealt with above.
+		 */
+		intr = SPARCBUS_GUESS_INO(dev, node, slot, pintr);
+		found = intr != 255;
+		*terminate = found;
+	}
+	if (!found && (pci_quirks & OPQ_NO_SWIZZLE) == 0 &&
 	    OF_getprop(node, "device_type", type, sizeof(type)) != -1 &&
 	    strcmp(type, OFW_PCI_PCIBUS) == 0 && pintr >= 1 && pintr <= 4) {
 		/*
@@ -91,29 +137,31 @@
 		 * PCI bridges without interrupt maps, where we apparently must
 		 * do the PCI swizzle and continue to map on at the parent.
 		 */
-		bcopy(pregptr, &preg, sizeof(preg));
-		intr = (OFW_PCI_PHYS_HI_DEVICE(preg.phys_hi) + pintr + 3) %
-		    4 + 1;
+		intr = (slot + pintr + 3) % 4 + 1;
+		*terminate = 0;
+		found = 1;
+	}
+
+	if (found) {
 		*rintr = malloc(sizeof(intr), M_OFWPROP, M_WAITOK);
 		bcopy(&intr, *rintr, sizeof(intr));
-		*terminate = 0;
 		return (sizeof(intr));
-	}
-	return (-1);
+	} else
+		return (-1);
 }
 
-u_int32_t
-ofw_pci_route_intr(phandle_t node, u_int32_t ign)
+static u_int32_t
+ofw_pci_route_intr(device_t dev, phandle_t node, u_int32_t ign)
 {
 	u_int32_t rv;
 
-	rv = ofw_bus_route_intr(node, ORIP_NOINT, ofw_pci_orb_callback);
+	rv = ofw_bus_route_intr(node, ORIP_NOINT, ofw_pci_orb_callback, dev);
 	if (rv == ORIR_NOTFOUND)
 		return (255);
 	/*
-	 * Some machines (notably the SPARCengine Ultra AX) have no mappings
-	 * at all, but use complete interrupt vector number including the IGN.
-	 * Catch this case and remove the IGN.
+	 * Some machines (notably the SPARCengine Ultra AX and the e450) have
+	 * no mappings at all, but use complete interrupt vector number
+	 * including the IGN. Catch this case and remove the IGN.
 	 */
 	if (rv > ign)
 		rv -= ign;
@@ -273,7 +321,7 @@
 			}
 
 			/* Initialize the intline registers. */
-			if ((intr = ofw_pci_route_intr(node, ign)) != 255) {
+			if ((intr = ofw_pci_route_intr(dev, node, ign)) != 255) {
 #ifdef OFW_PCI_DEBUG
 				device_printf(dev, "%s: mapping intr for "
 				    "%d/%d/%d to %d (preset was %d)\n",
Index: pci/ofw_pci.h
===================================================================
RCS file: /vol/ncvs/src/sys/sparc64/pci/ofw_pci.h,v
retrieving revision 1.4
diff -u -r1.4 ofw_pci.h
--- pci/ofw_pci.h	7 Nov 2002 16:07:46 -0000	1.4
+++ pci/ofw_pci.h	23 May 2003 10:53:26 -0000
@@ -71,7 +71,6 @@
 	struct ofw_pci_bdesc	*obd_super;
 };
 
-u_int32_t ofw_pci_route_intr(phandle_t, u_int32_t);
 obr_callback_t ofw_pci_orb_callback;
 u_int8_t ofw_pci_alloc_busno(phandle_t);
 ofw_pci_binit_t ofw_pci_binit;
Index: pci/psycho.c
===================================================================
RCS file: /vol/ncvs/src/sys/sparc64/pci/psycho.c,v
retrieving revision 1.32
diff -u -r1.32 psycho.c
--- pci/psycho.c	2 May 2003 01:21:36 -0000	1.32
+++ pci/psycho.c	23 May 2003 10:53:26 -0000
@@ -144,6 +144,7 @@
     int);
 static int psycho_route_interrupt(device_t, device_t, int);
 static int psycho_intr_pending(device_t, int);
+static u_int32_t psycho_guess_ino(device_t, phandle_t, u_int, u_int);
 static bus_space_handle_t psycho_get_bus_handle(device_t dev, enum sbbt_id id,
     bus_space_handle_t childhdl, bus_space_tag_t *tag);
 
@@ -170,6 +171,7 @@
 
 	/* sparcbus interface */
 	DEVMETHOD(sparcbus_intr_pending,	psycho_intr_pending),
+	DEVMETHOD(sparcbus_guess_ino,	psycho_guess_ino),
 	DEVMETHOD(sparcbus_get_bus_handle,	psycho_get_bus_handle),
 
 	{ 0, 0 }
@@ -339,7 +341,6 @@
 	struct upa_regs *reg;
 	struct ofw_pci_bdesc obd;
 	struct psycho_desc *desc;
-	vm_paddr_t pcictl_offs;
 	phandle_t node;
 	u_int64_t csr;
 	u_long mlen;
@@ -377,13 +378,25 @@
 			panic("psycho_attach: %d not enough registers", nreg);
 		sc->sc_basepaddr = (vm_paddr_t)UPA_REG_PHYS(&reg[2]);
 		mlen = UPA_REG_SIZE(&reg[2]);
-		pcictl_offs = UPA_REG_PHYS(&reg[0]);
+		sc->sc_pcictl = UPA_REG_PHYS(&reg[0]) - sc->sc_basepaddr;
+		switch (sc->sc_pcictl) {
+		case PSR_PCICTL0:
+			sc->sc_half = 0;
+			break;
+		case PSR_PCICTL1:
+			sc->sc_half = 1;
+			break;
+		default:
+			panic("psycho_attach: bogus pci control register "
+			    "location");
+		}
 	} else {
 		if (nreg <= 0)
 			panic("psycho_attach: %d not enough registers", nreg);
 		sc->sc_basepaddr = (vm_paddr_t)UPA_REG_PHYS(&reg[0]);
 		mlen = UPA_REG_SIZE(reg);
-		pcictl_offs = sc->sc_basepaddr + PSR_PCICTL0;
+		sc->sc_pcictl = PSR_PCICTL0;
+		sc->sc_half = 0;
 	}
 
 	/*
@@ -418,17 +431,14 @@
 		sc->sc_bustag = osc->sc_bustag;
 		sc->sc_bushandle = osc->sc_bushandle;
 	}
-	if (pcictl_offs < sc->sc_basepaddr)
-		panic("psycho_attach: bogus pci control register location");
-	sc->sc_pcictl = pcictl_offs - sc->sc_basepaddr;
 	csr = PSYCHO_READ8(sc, PSR_CS);
 	sc->sc_ign = 0x7c0; /* APB IGN is always 0x7c */
 	if (sc->sc_mode == PSYCHO_MODE_PSYCHO)
 		sc->sc_ign = PSYCHO_GCSR_IGN(csr) << 6;
 
-	device_printf(dev, "%s, impl %d, version %d, ign %#x\n",
+	device_printf(dev, "%s, impl %d, version %d, ign %#x, bus %c\n",
 	    desc->pd_name, (int)PSYCHO_GCSR_IMPL(csr),
-	    (int)PSYCHO_GCSR_VERS(csr), sc->sc_ign);
+	    (int)PSYCHO_GCSR_VERS(csr), sc->sc_ign, 'A' + sc->sc_half);
 
 	/*
 	 * Setup the PCI control register
@@ -1275,6 +1285,31 @@
 		return (0);
 	}
 	return (diag != 0);
+}
+
+static u_int32_t
+psycho_guess_ino(device_t dev, phandle_t node, u_int slot, u_int pin)
+{
+	struct psycho_softc *sc = (struct psycho_softc *)device_get_softc(dev);
+	bus_addr_t intrmap;
+
+	/*
+	 * If this is not for one of our direct children (i.e. we are mapping
+	 * at our node), tell the interrupt mapper to go on - we need the
+	 * slot number of the device or it's topmost parent bridge to guess
+	 * the INO.
+	 */
+	if (node != sc->sc_node)
+		return (255);
+	/*
+	 * Actually guess the INO. We always assume that this is a non-OBIO
+	 * device, and use from the slot number to determine it.
+	 * We only need to do this on e450s, it seems; here, the slot numbers
+	 * for bus A are one-based, while those for bus B seemingly have an
+	 * offset of 2 (hence the factor of 3 below).
+	 */
+	intrmap = PSR_PCIA0_INT_MAP + 8 * (slot - 1 + 3 * sc->sc_half);
+	return (INTINO(PSYCHO_READ8(sc, intrmap)) + pin - 1);
 }
 
 static bus_space_handle_t
Index: pci/psychovar.h
===================================================================
RCS file: /vol/ncvs/src/sys/sparc64/pci/psychovar.h,v
retrieving revision 1.7
diff -u -r1.7 psychovar.h
--- pci/psychovar.h	8 Apr 2003 06:35:08 -0000	1.7
+++ pci/psychovar.h	23 May 2003 10:53:26 -0000
@@ -61,6 +61,9 @@
 #define	PSYCHO_MODE_SABRE	1
 #define	PSYCHO_MODE_PSYCHO	2
 
+	/* Bus A or B of a psycho pair? */
+	int				sc_half;
+
 	struct iommu_state		*sc_is;
 	u_int32_t			sc_dvmabase;
 
Index: sparc64/ofw_bus.c
===================================================================
RCS file: /vol/ncvs/src/sys/sparc64/sparc64/ofw_bus.c,v
retrieving revision 1.5
diff -u -r1.5 ofw_bus.c
--- sparc64/ofw_bus.c	19 Feb 2003 05:47:45 -0000	1.5
+++ sparc64/ofw_bus.c	23 May 2003 10:53:26 -0000
@@ -160,7 +160,7 @@
  * This should work for all bus systems.
  */
 u_int32_t
-ofw_bus_route_intr(phandle_t node, int intrp, obr_callback_t *cb)
+ofw_bus_route_intr(phandle_t node, int intrp, obr_callback_t *cb, void *cookie)
 {
 	u_int8_t *reg, *intr, *tintr, *imap, *imapmsk;
 	phandle_t parent;
@@ -201,7 +201,7 @@
 			 */
 			if (cb != NULL) {
 				tisz = cb(parent, intr, isz, reg, regsz, &tintr,
-				    &found);
+				    &found, cookie);
 				if (tisz != -1) {
 					isz = tisz;
 					free(intr, M_OFWPROP);
Index: sparc64/sparcbus_if.m
===================================================================
RCS file: /vol/ncvs/src/sys/sparc64/sparc64/sparcbus_if.m,v
retrieving revision 1.1
diff -u -r1.1 sparcbus_if.m
--- sparc64/sparcbus_if.m	9 Nov 2001 20:43:44 -0000	1.1
+++ sparc64/sparcbus_if.m	23 May 2003 10:53:26 -0000
@@ -26,6 +26,8 @@
 #include <sys/bus.h>
 #include <machine/bus.h>
 
+#include <dev/ofw/openfirm.h>
+
 INTERFACE sparcbus;
 
 HEADER {
@@ -37,10 +39,6 @@
 };
 
 CODE {
-	static int sparcbus_default_intr_pending(device_t, int);
-	static bus_space_handle_t sparcbus_default_get_bus_handle(device_t,
-	    enum sbbt_id, bus_space_handle_t childhdl, bus_space_tag_t *tag);
-
 	static int
 	sparcbus_default_intr_pending(device_t dev, int intr)
 	{
@@ -48,6 +46,15 @@
 		return (SPARCBUS_INTR_PENDING(device_get_parent(dev), intr));
 	}
 
+	static u_int32_t
+	sparcbus_default_guess_ino(device_t dev, phandle_t node, u_int slot,
+	    u_int pin)
+	{
+
+		return (SPARCBUS_GUESS_INO(device_get_parent(dev), node, slot,
+		    pin));
+	}
+
 	static bus_space_handle_t
 	sparcbus_default_get_bus_handle(device_t dev, enum sbbt_id id,
 	    bus_space_handle_t childhdl, bus_space_tag_t *tag)
@@ -63,6 +70,17 @@
 	device_t dev;
 	int intr;
 } DEFAULT sparcbus_default_intr_pending;
+
+# Let the bus driver guess the INO of the device at the given slot and intpin
+# on the bus described by the node if it could not be determined from the
+# firmware properties. Returns 255 if no INO could be found (mapping will
+# continue at the parent), or the desired INO.
+METHOD u_int32_t guess_ino {
+	device_t dev;
+	phandle_t node;
+	u_int slot;
+	u_int pin;
+} DEFAULT sparcbus_default_guess_ino;
 
 # Get the bustag for the root bus. This is needed for ISA old-stlye
 # in[bwl]()/out[bwl]() support, where no tag retrieved from a resource is

--HlL+5n6rz5pIUxbD--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030529113731.GB630>