svn commit: r259235 - in stable/10/sys: conf dev/tsec powerpc/aim powerpc/include powerpc/ofw

Andreas Tobler andreast at FreeBSD.org
Wed Dec 11 22:36:22 UTC 2013


Author: andreast
Date: Wed Dec 11 22:36:20 2013
New Revision: 259235
URL: http://svnweb.freebsd.org/changeset/base/259235

Log:
  MFC     r257991, r257992, 257993, 258504
  
  r257991:
    Consolidate Apple firmware hacks and improve them by switching on the
    presence of mac-io devices in the tree, which uniquely identifies Apple
    hardware.
  
  r257992:
    Allow OF_decode_addr() to also be able to map resources on big-endian
    devices. To this end, make PCI device detection rely on the device_type
    field rather than name, as per the standard.
  
  r257993:
  
    Make tsec work with the device tree present on the RB800. The previous code
    assumed that the MDIO bus was a direct child of the Ethernet interface. It
    may not be and indeed on many device trees is not. While here, add proper
    locking for MII transactions, which may be on a bus shared by several MACs.
  
  r258504:
  
    Save and restore the trap vectors when doing OF calls on pSeries machines.
  
    It turned out that on pSeries machines the call into OF modified the trap
    vectors and this made further behaviour unpredictable.
  
    With this commit I'm now able to boot multi user on a network booted
    environment on my IntelliStation 285. This is a POWER5+ machine.

Modified:
  stable/10/sys/conf/files.powerpc
  stable/10/sys/dev/tsec/if_tsec.c
  stable/10/sys/dev/tsec/if_tsec.h
  stable/10/sys/dev/tsec/if_tsec_fdt.c
  stable/10/sys/dev/tsec/if_tsecreg.h
  stable/10/sys/powerpc/aim/machdep.c
  stable/10/sys/powerpc/include/ofw_machdep.h
  stable/10/sys/powerpc/ofw/ofw_machdep.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/conf/files.powerpc
==============================================================================
--- stable/10/sys/conf/files.powerpc	Wed Dec 11 22:26:09 2013	(r259234)
+++ stable/10/sys/conf/files.powerpc	Wed Dec 11 22:36:20 2013	(r259235)
@@ -140,7 +140,7 @@ powerpc/mpc85xx/mpc85xx.c	optional	mpc85
 powerpc/mpc85xx/nexus.c		optional	mpc85xx
 powerpc/mpc85xx/pci_fdt.c	optional	pci mpc85xx
 powerpc/ofw/ofw_cpu.c		optional	aim
-powerpc/ofw/ofw_machdep.c	optional	aim
+powerpc/ofw/ofw_machdep.c	standard
 powerpc/ofw/ofw_pci.c		optional	pci aim
 powerpc/ofw/ofw_pcibus.c	optional	pci aim
 powerpc/ofw/ofw_pcib_pci.c	optional	pci aim

Modified: stable/10/sys/dev/tsec/if_tsec.c
==============================================================================
--- stable/10/sys/dev/tsec/if_tsec.c	Wed Dec 11 22:26:09 2013	(r259234)
+++ stable/10/sys/dev/tsec/if_tsec.c	Wed Dec 11 22:36:20 2013	(r259235)
@@ -111,6 +111,8 @@ DRIVER_MODULE(miibus, tsec, miibus_drive
 MODULE_DEPEND(tsec, ether, 1, 1, 1);
 MODULE_DEPEND(tsec, miibus, 1, 1, 1);
 
+struct mtx tsec_phy_mtx;
+
 int
 tsec_attach(struct tsec_softc *sc)
 {
@@ -121,6 +123,10 @@ tsec_attach(struct tsec_softc *sc)
 	int error = 0;
 	int i;
 
+	/* Initialize global (because potentially shared) MII lock */
+	if (!mtx_initialized(&tsec_phy_mtx))
+		mtx_init(&tsec_phy_mtx, "tsec mii", NULL, MTX_DEF);
+
 	/* Reset all TSEC counters */
 	TSEC_TX_RX_COUNTERS_INIT(sc);
 
@@ -406,21 +412,24 @@ tsec_init_locked(struct tsec_softc *sc)
 	 */
 	TSEC_WRITE(sc, TSEC_REG_TBIPA, 5);
 
+	TSEC_PHY_LOCK(sc);
+
 	/* Step 6: Reset the management interface */
-	TSEC_WRITE(sc->phy_sc, TSEC_REG_MIIMCFG, TSEC_MIIMCFG_RESETMGMT);
+	TSEC_PHY_WRITE(sc, TSEC_REG_MIIMCFG, TSEC_MIIMCFG_RESETMGMT);
 
 	/* Step 7: Setup the MII Mgmt clock speed */
-	TSEC_WRITE(sc->phy_sc, TSEC_REG_MIIMCFG, TSEC_MIIMCFG_CLKDIV28);
+	TSEC_PHY_WRITE(sc, TSEC_REG_MIIMCFG, TSEC_MIIMCFG_CLKDIV28);
 
 	/* Step 8: Read MII Mgmt indicator register and check for Busy = 0 */
 	timeout = TSEC_READ_RETRY;
-	while (--timeout && (TSEC_READ(sc->phy_sc, TSEC_REG_MIIMIND) &
+	while (--timeout && (TSEC_PHY_READ(sc, TSEC_REG_MIIMIND) &
 	    TSEC_MIIMIND_BUSY))
 		DELAY(TSEC_READ_DELAY);
 	if (timeout == 0) {
 		if_printf(ifp, "tsec_init_locked(): Mgmt busy timeout\n");
 		return;
 	}
+	TSEC_PHY_UNLOCK(sc);
 
 	/* Step 9: Setup the MII Mgmt */
 	mii_mediachg(sc->tsec_mii);
@@ -1561,22 +1570,27 @@ tsec_miibus_readreg(device_t dev, int ph
 {
 	struct tsec_softc *sc;
 	uint32_t timeout;
+	int rv;
 
 	sc = device_get_softc(dev);
 
-	TSEC_WRITE(sc->phy_sc, TSEC_REG_MIIMADD, (phy << 8) | reg);
-	TSEC_WRITE(sc->phy_sc, TSEC_REG_MIIMCOM, 0);
-	TSEC_WRITE(sc->phy_sc, TSEC_REG_MIIMCOM, TSEC_MIIMCOM_READCYCLE);
+	TSEC_PHY_LOCK();
+	TSEC_PHY_WRITE(sc, TSEC_REG_MIIMADD, (phy << 8) | reg);
+	TSEC_PHY_WRITE(sc, TSEC_REG_MIIMCOM, 0);
+	TSEC_PHY_WRITE(sc, TSEC_REG_MIIMCOM, TSEC_MIIMCOM_READCYCLE);
 
 	timeout = TSEC_READ_RETRY;
-	while (--timeout && TSEC_READ(sc->phy_sc, TSEC_REG_MIIMIND) &
+	while (--timeout && TSEC_PHY_READ(sc, TSEC_REG_MIIMIND) &
 	    (TSEC_MIIMIND_NOTVALID | TSEC_MIIMIND_BUSY))
 		DELAY(TSEC_READ_DELAY);
 
 	if (timeout == 0)
 		device_printf(dev, "Timeout while reading from PHY!\n");
 
-	return (TSEC_READ(sc->phy_sc, TSEC_REG_MIIMSTAT));
+	rv = TSEC_PHY_READ(sc, TSEC_REG_MIIMSTAT);
+	TSEC_PHY_UNLOCK();
+
+	return (rv);
 }
 
 int
@@ -1587,13 +1601,15 @@ tsec_miibus_writereg(device_t dev, int p
 
 	sc = device_get_softc(dev);
 
-	TSEC_WRITE(sc->phy_sc, TSEC_REG_MIIMADD, (phy << 8) | reg);
-	TSEC_WRITE(sc->phy_sc, TSEC_REG_MIIMCON, value);
+	TSEC_PHY_LOCK();
+	TSEC_PHY_WRITE(sc, TSEC_REG_MIIMADD, (phy << 8) | reg);
+	TSEC_PHY_WRITE(sc, TSEC_REG_MIIMCON, value);
 
 	timeout = TSEC_READ_RETRY;
-	while (--timeout && (TSEC_READ(sc->phy_sc, TSEC_REG_MIIMIND) &
+	while (--timeout && (TSEC_READ(sc, TSEC_REG_MIIMIND) &
 	    TSEC_MIIMIND_BUSY))
 		DELAY(TSEC_READ_DELAY);
+	TSEC_PHY_UNLOCK();
 
 	if (timeout == 0)
 		device_printf(dev, "Timeout while writing to PHY!\n");

Modified: stable/10/sys/dev/tsec/if_tsec.h
==============================================================================
--- stable/10/sys/dev/tsec/if_tsec.h	Wed Dec 11 22:26:09 2013	(r259234)
+++ stable/10/sys/dev/tsec/if_tsec.h	Wed Dec 11 22:36:20 2013	(r259235)
@@ -133,7 +133,8 @@ struct tsec_softc {
 	struct mbuf	*frame;
 
 	int		phyaddr;
-	struct tsec_softc *phy_sc;
+	bus_space_tag_t phy_bst;
+	bus_space_handle_t phy_bsh;
 };
 
 /* interface to get/put generic objects */
@@ -253,6 +254,14 @@ struct tsec_softc {
 #define TSEC_WRITE(sc, reg, val)	\
 		bus_space_write_4((sc)->sc_bas.bst, (sc)->sc_bas.bsh, (reg), (val))
 
+extern struct mtx tsec_phy_mtx;
+#define TSEC_PHY_LOCK(sc)	mtx_lock(&tsec_phy_mtx)
+#define TSEC_PHY_UNLOCK(sc)	mtx_unlock(&tsec_phy_mtx)
+#define TSEC_PHY_READ(sc, reg)		\
+		bus_space_read_4((sc)->phy_bst, (sc)->phy_bsh, (reg))
+#define TSEC_PHY_WRITE(sc, reg, val)	\
+		bus_space_write_4((sc)->phy_bst, (sc)->phy_bsh, (reg), (val))
+
 /* Lock for transmitter */
 #define TSEC_TRANSMIT_LOCK(sc) do {					\
 		mtx_assert(&(sc)->receive_lock, MA_NOTOWNED);		\

Modified: stable/10/sys/dev/tsec/if_tsec_fdt.c
==============================================================================
--- stable/10/sys/dev/tsec/if_tsec_fdt.c	Wed Dec 11 22:26:09 2013	(r259234)
+++ stable/10/sys/dev/tsec/if_tsec_fdt.c	Wed Dec 11 22:36:20 2013	(r259235)
@@ -110,6 +110,10 @@ tsec_fdt_probe(device_t dev)
 	struct tsec_softc *sc;
 	uint32_t id;
 
+	if (ofw_bus_get_type(dev) == NULL ||
+	    strcmp(ofw_bus_get_type(dev), "network") != 0)
+		return (ENXIO);
+
 	if (!ofw_bus_is_compatible(dev, "gianfar"))
 		return (ENXIO);
 
@@ -148,6 +152,7 @@ static int
 tsec_fdt_attach(device_t dev)
 {
 	struct tsec_softc *sc;
+	phandle_t phy;
 	int error = 0;
 
 	sc = device_get_softc(dev);
@@ -155,9 +160,14 @@ tsec_fdt_attach(device_t dev)
 	sc->node = ofw_bus_get_node(dev);
 
 	/* Get phy address from fdt */
-	if (fdt_get_phyaddr(sc->node, sc->dev, &sc->phyaddr,
-	    (void **)&sc->phy_sc) != 0)
+	if (OF_getencprop(sc->node, "phy-handle", &phy, sizeof(phy)) <= 0) {
+		device_printf(dev, "PHY not found in device tree");
 		return (ENXIO);
+	}
+
+	phy = OF_xref_phandle(phy);
+	OF_decode_addr(OF_parent(phy), 0, &sc->phy_bst, &sc->phy_bsh);
+	OF_getencprop(phy, "reg", &sc->phyaddr, sizeof(sc->phyaddr));
 
 	/* Init timer */
 	callout_init(&sc->tsec_callout, 1);
@@ -324,6 +334,13 @@ tsec_get_hwaddr(struct tsec_softc *sc, u
 		return;
 	}
 
+	/* Also try the mac-address property, which is second-best */
+	i = OF_getprop(sc->node, "mac-address", (void *)hw.addr, 6);
+	if (i == 6 && (hw.reg[0] != 0 || hw.reg[1] != 0)) {
+		bcopy(hw.addr, addr, 6);
+		return;
+	}
+
 	/*
 	 * Fall back -- use the currently programmed address in the hope that
 	 * it was set be firmware...

Modified: stable/10/sys/dev/tsec/if_tsecreg.h
==============================================================================
--- stable/10/sys/dev/tsec/if_tsecreg.h	Wed Dec 11 22:26:09 2013	(r259234)
+++ stable/10/sys/dev/tsec/if_tsecreg.h	Wed Dec 11 22:36:20 2013	(r259235)
@@ -77,12 +77,13 @@
 				       * register */
 #define TSEC_REG_HAFDUP		0x50c /* Half-duplex register */
 #define TSEC_REG_MAXFRM		0x510 /* Maximum frame length register */
-#define TSEC_REG_MIIMCFG	0x520 /* MII Management configuration register */
-#define TSEC_REG_MIIMCOM	0x524 /* MII Management command register */
-#define TSEC_REG_MIIMADD	0x528 /* MII Management address register */
-#define TSEC_REG_MIIMCON	0x52c /* MII Management control register */
-#define TSEC_REG_MIIMSTAT	0x530 /* MII Management status register */
-#define TSEC_REG_MIIMIND	0x534 /* MII Management indicator register */
+#define TSEC_REG_MIIBASE	0x520 /* MII Management base, rest offsets */
+#define TSEC_REG_MIIMCFG	0x0   /* MII Management configuration register */
+#define TSEC_REG_MIIMCOM	0x4   /* MII Management command register */
+#define TSEC_REG_MIIMADD	0x8   /* MII Management address register */
+#define TSEC_REG_MIIMCON	0xc   /* MII Management control register */
+#define TSEC_REG_MIIMSTAT	0x10  /* MII Management status register */
+#define TSEC_REG_MIIMIND	0x14  /* MII Management indicator register */
 #define TSEC_REG_IFSTAT		0x53c /* Interface status register */
 #define TSEC_REG_MACSTNADDR1	0x540 /* Station address register, part 1 */
 #define TSEC_REG_MACSTNADDR2	0x544 /* Station address register, part 2 */

Modified: stable/10/sys/powerpc/aim/machdep.c
==============================================================================
--- stable/10/sys/powerpc/aim/machdep.c	Wed Dec 11 22:26:09 2013	(r259234)
+++ stable/10/sys/powerpc/aim/machdep.c	Wed Dec 11 22:36:20 2013	(r259235)
@@ -123,6 +123,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/spr.h>
 #include <machine/trap.h>
 #include <machine/vmparam.h>
+#include <machine/ofw_machdep.h>
 
 #include <ddb/ddb.h>
 
@@ -249,6 +250,7 @@ extern void	*dblow, *dbsize;
 extern void	*imisstrap, *imisssize;
 extern void	*dlmisstrap, *dlmisssize;
 extern void	*dsmisstrap, *dsmisssize;
+char 		save_trap_init[0x2f00];		/* EXC_LAST */
 
 uintptr_t
 powerpc_init(vm_offset_t startkernel, vm_offset_t endkernel,
@@ -273,6 +275,9 @@ powerpc_init(vm_offset_t startkernel, vm
 	trap_offset = 0;
 	cacheline_warn = 0;
 
+	/* Save trap vectors. */
+	ofw_save_trap_vec(save_trap_init);
+
 #ifdef WII
 	/*
 	 * The Wii loader doesn't pass us any environment so, mdp

Modified: stable/10/sys/powerpc/include/ofw_machdep.h
==============================================================================
--- stable/10/sys/powerpc/include/ofw_machdep.h	Wed Dec 11 22:26:09 2013	(r259234)
+++ stable/10/sys/powerpc/include/ofw_machdep.h	Wed Dec 11 22:36:20 2013	(r259235)
@@ -47,5 +47,6 @@ void OF_reboot(void);
 
 void ofw_mem_regions(struct mem_region **, int *, struct mem_region **, int *);
 void ofw_quiesce(void); /* Must be called before VM is up! */
+void ofw_save_trap_vec(char *);
 
 #endif /* _MACHINE_OFW_MACHDEP_H_ */

Modified: stable/10/sys/powerpc/ofw/ofw_machdep.c
==============================================================================
--- stable/10/sys/powerpc/ofw/ofw_machdep.c	Wed Dec 11 22:26:09 2013	(r259234)
+++ stable/10/sys/powerpc/ofw/ofw_machdep.c	Wed Dec 11 22:36:20 2013	(r259235)
@@ -59,18 +59,43 @@ __FBSDID("$FreeBSD$");
 #include <machine/md_var.h>
 #include <machine/platform.h>
 #include <machine/ofw_machdep.h>
+#include <machine/trap.h>
 
 static struct mem_region OFmem[PHYS_AVAIL_SZ], OFavail[PHYS_AVAIL_SZ];
 static struct mem_region OFfree[PHYS_AVAIL_SZ];
 
+static int	apple_hacks;
+
+#ifdef AIM
 extern register_t ofmsr[5];
 extern void	*openfirmware_entry;
 static void	*fdt;
 int		ofw_real_mode;
+extern char     save_trap_init[0x2f00];          /* EXC_LAST */
+char            save_trap_of[0x2f00];            /* EXC_LAST */
 
 int		ofwcall(void *);
 static int	openfirmware(void *args);
 
+__inline void
+ofw_save_trap_vec(char *save_trap_vec)
+{
+	if (apple_hacks)
+                return;
+
+	bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST);
+}
+
+static __inline void
+ofw_restore_trap_vec(char *restore_trap_vec)
+{
+	if (apple_hacks)
+                return;
+
+	bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST);
+	__syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD);
+}
+
 /*
  * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
  */
@@ -79,6 +104,9 @@ register_t	ofw_sprg0_save;
 static __inline void
 ofw_sprg_prepare(void)
 {
+	if (!apple_hacks)
+		return;
+	
 	/*
 	 * Assume that interrupt are disabled at this point, or
 	 * SPRG1-3 could be trashed
@@ -98,6 +126,9 @@ ofw_sprg_prepare(void)
 static __inline void
 ofw_sprg_restore(void)
 {
+	if (!apple_hacks)
+		return;
+	
 	/*
 	 * Note that SPRG1-3 contents are irrelevant. They are scratch
 	 * registers used in the early portion of trap handling when
@@ -107,6 +138,7 @@ ofw_sprg_restore(void)
 	 */
 	__asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
 }
+#endif
 
 /*
  * Memory region utilities: determine if two regions overlap,
@@ -178,15 +210,10 @@ parse_ofw_memory(phandle_t node, const c
 
 	/*
 	 * On Apple hardware, address_cells is always 1 for "available",
-	 * even when it is explicitly set to 2. Then all memory above 4 GB
-	 * should be added by hand to the available list. Detect Apple hardware
-	 * by seeing if ofw_real_mode is set -- only Apple seems to use
-	 * virtual-mode OF.
+	 * even when it is explicitly set to 2. All memory above 4 GB
+	 * also needs to be added by hand to the available list.
 	 */
-	if (strcmp(prop, "available") == 0 && !ofw_real_mode)
-		apple_hack_mode = 1;
-	
-	if (apple_hack_mode)
+	if (strcmp(prop, "available") == 0 && apple_hacks)
 		address_cells = 1;
 
 	/*
@@ -241,7 +268,7 @@ parse_ofw_memory(phandle_t node, const c
 	sz = j*sizeof(output[0]);
 
 	#ifdef __powerpc64__
-	if (apple_hack_mode) {
+	if (strcmp(prop, "available") == 0 && apple_hacks) {
 		/* Add in regions above 4 GB to the available list */
 		struct mem_region himem[16];
 		int hisz;
@@ -435,6 +462,7 @@ ofw_mem_regions(struct mem_region **memp
 	*availsz = fsz;
 }
 
+#ifdef AIM
 void
 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
 {
@@ -481,6 +509,9 @@ OF_bootstrap()
 		OF_init(fdt);
 	} 
 
+	/* Apple firmware has some bugs. Check for a "mac-io" alias. */
+	apple_hacks = (OF_finddevice("mac-io") != -1) ? 1 : 0;
+
 	return (status);
 }
 
@@ -516,6 +547,12 @@ openfirmware_core(void *args)
 
 	ofw_sprg_prepare();
 
+	/* Save trap vectors */
+	ofw_save_trap_vec(save_trap_of);
+
+	/* Restore initially saved trap vectors */
+	ofw_restore_trap_vec(save_trap_init);
+
 #if defined(AIM) && !defined(__powerpc64__)
 	/*
 	 * Clear battable[] translations
@@ -527,6 +564,10 @@ openfirmware_core(void *args)
 #endif
 
 	result = ofwcall(args);
+
+	/* Restore trap vecotrs */
+	ofw_restore_trap_vec(save_trap_of);
+
 	ofw_sprg_restore();
 
 	intr_restore(oldmsr);
@@ -603,6 +644,8 @@ OF_reboot()
 	for (;;);	/* just in case */
 }
 
+#endif /* AIM */
+
 void
 OF_getetheraddr(device_t dev, u_char *addr)
 {
@@ -623,7 +666,7 @@ OF_getetheraddr(device_t dev, u_char *ad
 static void
 OF_get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep, int *pcip)
 {
-	char name[16];
+	char type[64];
 	uint32_t addr, size;
 	int pci, res;
 
@@ -635,10 +678,10 @@ OF_get_addr_props(phandle_t node, uint32
 		size = 1;
 	pci = 0;
 	if (addr == 3 && size == 2) {
-		res = OF_getprop(node, "name", name, sizeof(name));
+		res = OF_getprop(node, "device_type", type, sizeof(type));
 		if (res != -1) {
-			name[sizeof(name) - 1] = '\0';
-			pci = (strcmp(name, "pci") == 0) ? 1 : 0;
+			type[sizeof(type) - 1] = '\0';
+			pci = (strcmp(type, "pci") == 0) ? 1 : 0;
 		}
 	}
 	if (addrp != NULL)
@@ -672,8 +715,13 @@ OF_decode_addr(phandle_t dev, int regno,
 	if (tag == NULL || handle == NULL)
 		return (EINVAL);
 
+	/* Assume big-endian unless we find a PCI device */
+	*tag = &bs_be_tag;
+
 	/* Get the requested register. */
 	OF_get_addr_props(bridge, &naddr, &nsize, &pci);
+	if (pci)
+		*tag = &bs_le_tag;
 	res = OF_getprop(dev, (pci) ? "assigned-addresses" : "reg",
 	    cell, sizeof(cell));
 	if (res == -1)
@@ -701,6 +749,8 @@ OF_decode_addr(phandle_t dev, int regno,
 	parent = OF_parent(bridge);
 	while (parent != 0) {
 		OF_get_addr_props(parent, &nbridge, NULL, &pcib);
+		if (pcib)
+			*tag = &bs_le_tag;
 		res = OF_getprop(bridge, "ranges", cell, sizeof(cell));
 		if (res == -1)
 			goto next;
@@ -741,7 +791,6 @@ OF_decode_addr(phandle_t dev, int regno,
 		OF_get_addr_props(bridge, &naddr, &nsize, &pci);
 	}
 
-	*tag = &bs_le_tag;
 	return (bus_space_map(*tag, addr, size,
 	    prefetch ? BUS_SPACE_MAP_PREFETCHABLE : 0, handle));
 }


More information about the svn-src-stable-10 mailing list