Index: psycho.c
===================================================================
RCS file: /space/ncvs/src/sys/sparc64/pci/psycho.c,v
retrieving revision 1.20
diff -u -p -r1.20 psycho.c
--- psycho.c	1 Dec 2002 23:30:26 -0000	1.20
+++ psycho.c	3 Dec 2002 18:49:18 -0000
@@ -353,6 +353,7 @@ psycho_attach(device_t dev)
 	sc->sc_dev = dev;
 	sc->sc_dmatag = nexus_get_dmatag(dev);
 	sc->sc_mode = desc->pd_mode;
+	sc->sc_running = 0;
 
 	/*
 	 * The psycho gets three register banks:
@@ -639,6 +640,8 @@ psycho_attach(device_t dev)
 	 */
 	ofw_pci_init(dev, sc->sc_node, sc->sc_ign, &obd);
 
+	sc->sc_running = 1;
+
 	device_add_child(dev, "pci", device_get_unit(dev));
 	return (bus_generic_attach(dev));
 }
@@ -920,16 +923,51 @@ static struct psycho_dquirk dquirks[] = 
 
 #define	NDQUIRKS	(sizeof(dquirks) / sizeof(dquirks[0]))
 
+struct psycho_func_xlat {
+	u_int	pfx_bus;
+	u_int	pfx_slot;
+	u_int	pfx_func;
+	u_int	pfx_offset;
+	SLIST_ENTRY(psycho_func_xlat)	pfx_link;
+};
+
+static SLIST_HEAD(, psycho_func_xlat) func_xlat =
+    SLIST_HEAD_INITIALIZER(func_xlat);
+
+static struct psycho_dquirk *
+psycho_find_quirk(u_int32_t devid)
+{
+	int i;
+
+	for (i = 0; i < NDQUIRKS; i++) {
+		if (dquirks[i].dq_devid == devid)
+			return (&dquirks[i]);
+	}
+	return (NULL);
+}
+
 static u_int32_t
 psycho_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg,
 	int width)
 {
 	struct psycho_softc *sc;
+	struct psycho_dquirk *q = NULL;
+	struct psycho_func_xlat *fx;
 	bus_space_handle_t bh;
 	u_long offset = 0;
 	u_int32_t r, devid;
-	int i;
 
+	sc = (struct psycho_softc *)device_get_softc(dev);
+	/* Do not attempt to translate functions during early initialization. */
+	if (sc->sc_running) {
+		SLIST_FOREACH(fx, &func_xlat, pfx_link) {
+			if (fx->pfx_bus == bus && fx->pfx_slot == slot &&
+			    fx->pfx_func <= func) {
+				func += fx->pfx_offset;
+				break;
+			}
+		}
+	}
 	/*
 	 * The psycho bridge does not tolerate accesses to unconfigured PCI
 	 * devices' or function's config space, so look up the device in the
@@ -937,9 +975,30 @@ psycho_read_config(device_t dev, u_int b
 	 * that will make the detection code think that there is no device here.
 	 * This is ugly...
 	 */
-	if (reg == 0 && ofw_pci_find_node(bus, slot, func) == 0)
-		return (0xffffffff);
-	sc = (struct psycho_softc *)device_get_softc(dev);
+	if (reg == 0 && ofw_pci_find_node(bus, slot, func) == 0) {
+		/*
+		 * Yet another ugly hack around quirky hardware:
+		 * Handle quirky devices (PCIO and PCIO2) which occur in
+		 * variants with the EBus module (function 0) turned off,
+		 * but function 1 (hme or gem) present. This violates the
+		 * PCI spec, and the MI code cannot cope with it (although
+		 * this hack should maybe be MI, see above). Just move these
+		 * devices to function 0 for now, by redirecting all config
+		 * space accesses.
+		 */
+		if (sc->sc_running && func == 0 &&
+		    ofw_pci_find_node(bus, slot, 1) != 0) {
+			/* XXX: M_WAITOK is questionable. */
+			fx = malloc(sizeof(*fx), M_DEVBUF, M_WAITOK);
+			fx->pfx_bus = bus;
+			fx->pfx_slot = slot;
+			fx->pfx_func = func;
+			fx->pfx_offset = 1;
+			SLIST_INSERT_HEAD(&func_xlat, fx, pfx_link);
+			func = 1;
+		} else
+			return (0xffffffff);
+	}
 	offset = PSYCHO_CONF_OFF(bus, slot, func, reg);
 	bh = sc->sc_bh[PCI_CS_CONFIG];
 	switch (width) {
@@ -955,25 +1014,22 @@ psycho_read_config(device_t dev, u_int b
 	default:
 		panic("psycho_read_config: bad width");
 	}
-	if (reg == PCIR_INTPIN && r == 0) {
+	if (sc->sc_running && reg == PCIR_INTPIN && r == 0) {
 		/* Check for DQT_BAD_INTPIN quirk. */
 		devid = psycho_read_config(dev, bus, slot, func,
 		    PCIR_DEVVENDOR, 4);
-		for (i = 0; i < NDQUIRKS; i++) {
-			if (dquirks[i].dq_devid == devid) {
-				/*
-				 * Need to set the intpin to a value != 0 so
-				 * that the MI code will think that this device
-				 * has an interrupt.
-				 * Just use 1 (intpin a) for now. This is, of
-				 * course, bogus, but since interrupts are
-				 * routed in advance, this does not really
-				 * matter.
-				 */
-				if ((dquirks[i].dq_quirk & DQT_BAD_INTPIN) != 0)
-					r = 1;
-				break;
-			}
+		if ((q != NULL || (q = psycho_find_quirk(devid)) != NULL) &&
+		    (q->dq_quirk & DQT_BAD_INTPIN) != 0) {
+			/*
+			 * Need to set the intpin to a value != 0 so
+			 * that the MI code will think that this device
+			 * has an interrupt.
+			 * Just use 1 (intpin a) for now. This is, of
+			 * course, bogus, but since interrupts are
+			 * routed in advance, this does not really
+			 * matter.
+			 */
+			r = 1;
 		}
 	}
 	return (r);
@@ -984,10 +1040,21 @@ psycho_write_config(device_t dev, u_int 
 	u_int reg, u_int32_t val, int width)
 {
 	struct psycho_softc *sc;
+	struct psycho_func_xlat *fx;
 	bus_space_handle_t bh;
 	u_long offset = 0;
 
 	sc = (struct psycho_softc *)device_get_softc(dev);
+	/* Do not attempt to translate functions during early initialization. */
+	if (sc->sc_running) {
+		SLIST_FOREACH(fx, &func_xlat, pfx_link) {
+			if (fx->pfx_bus == bus && fx->pfx_slot == slot &&
+			    fx->pfx_func <= func) {
+				func += fx->pfx_offset;
+				break;
+			}
+		}
+	}
 	offset = PSYCHO_CONF_OFF(bus, slot, func, reg);
 	bh = sc->sc_bh[PCI_CS_CONFIG];
 	switch (width) {
Index: psychovar.h
===================================================================
RCS file: /space/ncvs/src/sys/sparc64/pci/psychovar.h,v
retrieving revision 1.5
diff -u -p -r1.5 psychovar.h
--- psychovar.h	16 Oct 2002 17:03:36 -0000	1.5
+++ psychovar.h	7 Nov 2002 18:04:18 -0000
@@ -61,6 +61,9 @@ struct psycho_softc {
 #define	PSYCHO_MODE_SABRE	1
 #define	PSYCHO_MODE_PSYCHO	2
 
+	/* Initialization complete. */
+	int				sc_running;
+
 	struct iommu_state		*sc_is;
 
 	struct resource			*sc_mem_res;
