diff options
-rw-r--r-- | sys/conf/files.powerpc | 2 | ||||
-rw-r--r-- | sys/dev/tsec/if_tsec.c | 38 | ||||
-rw-r--r-- | sys/dev/tsec/if_tsec.h | 11 | ||||
-rw-r--r-- | sys/dev/tsec/if_tsec_fdt.c | 21 | ||||
-rw-r--r-- | sys/dev/tsec/if_tsecreg.h | 13 | ||||
-rw-r--r-- | sys/powerpc/aim/machdep.c | 5 | ||||
-rw-r--r-- | sys/powerpc/include/ofw_machdep.h | 1 | ||||
-rw-r--r-- | sys/powerpc/ofw/ofw_machdep.c | 77 |
8 files changed, 133 insertions, 35 deletions
diff --git a/sys/conf/files.powerpc b/sys/conf/files.powerpc index aa55d0a..e0f8ee8 100644 --- a/sys/conf/files.powerpc +++ b/sys/conf/files.powerpc @@ -140,7 +140,7 @@ powerpc/mpc85xx/mpc85xx.c optional mpc85xx 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 diff --git a/sys/dev/tsec/if_tsec.c b/sys/dev/tsec/if_tsec.c index 8041776..242df3e 100644 --- a/sys/dev/tsec/if_tsec.c +++ b/sys/dev/tsec/if_tsec.c @@ -111,6 +111,8 @@ DRIVER_MODULE(miibus, tsec, miibus_driver, miibus_devclass, 0, 0); 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 phy, int reg) { 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 phy, int reg, int value) 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"); diff --git a/sys/dev/tsec/if_tsec.h b/sys/dev/tsec/if_tsec.h index cfba3f6..7c6bc30 100644 --- a/sys/dev/tsec/if_tsec.h +++ b/sys/dev/tsec/if_tsec.h @@ -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); \ diff --git a/sys/dev/tsec/if_tsec_fdt.c b/sys/dev/tsec/if_tsec_fdt.c index 7f6f414..8836851 100644 --- a/sys/dev/tsec/if_tsec_fdt.c +++ b/sys/dev/tsec/if_tsec_fdt.c @@ -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, uint8_t *addr) 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... diff --git a/sys/dev/tsec/if_tsecreg.h b/sys/dev/tsec/if_tsecreg.h index 4ba1997..1994298 100644 --- a/sys/dev/tsec/if_tsecreg.h +++ b/sys/dev/tsec/if_tsecreg.h @@ -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 */ diff --git a/sys/powerpc/aim/machdep.c b/sys/powerpc/aim/machdep.c index 5ae42bd..4b211fa 100644 --- a/sys/powerpc/aim/machdep.c +++ b/sys/powerpc/aim/machdep.c @@ -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_offset_t endkernel, 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 diff --git a/sys/powerpc/include/ofw_machdep.h b/sys/powerpc/include/ofw_machdep.h index b85ebe1..023fa4c 100644 --- a/sys/powerpc/include/ofw_machdep.h +++ b/sys/powerpc/include/ofw_machdep.h @@ -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_ */ diff --git a/sys/powerpc/ofw/ofw_machdep.c b/sys/powerpc/ofw/ofw_machdep.c index 8165515..4969ec0 100644 --- a/sys/powerpc/ofw/ofw_machdep.c +++ b/sys/powerpc/ofw/ofw_machdep.c @@ -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 char *prop, struct mem_region *output) /* * 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 char *prop, struct mem_region *output) 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, int *memsz, *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 *addr) 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_t *addrp, uint32_t *sizep, int *pcip) 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, bus_space_tag_t *tag, 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, bus_space_tag_t *tag, 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, bus_space_tag_t *tag, 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)); } |