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. Hardware donated by: Benjamin Perrault
This commit is contained in:
parent
43a581e116
commit
629aa519d6
@ -134,7 +134,7 @@ powerpc/mpc85xx/lbc.c optional mpc85xx
|
||||
powerpc/mpc85xx/mpc85xx.c optional mpc85xx
|
||||
powerpc/mpc85xx/pci_mpc85xx.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
|
||||
powerpc/ofw/ofw_pcibus.c optional pci
|
||||
powerpc/ofw/ofw_pcib_pci.c optional pci
|
||||
|
@ -112,6 +112,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)
|
||||
{
|
||||
@ -122,6 +124,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);
|
||||
|
||||
@ -407,21 +413,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);
|
||||
@ -1562,22 +1571,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
|
||||
@ -1588,13 +1602,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");
|
||||
|
@ -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); \
|
||||
|
@ -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...
|
||||
|
@ -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 */
|
||||
|
@ -63,11 +63,13 @@ __FBSDID("$FreeBSD$");
|
||||
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;
|
||||
static int apple_hacks;
|
||||
|
||||
int ofwcall(void *);
|
||||
static int openfirmware(void *args);
|
||||
@ -114,6 +116,7 @@ ofw_sprg_restore(void)
|
||||
*/
|
||||
__asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Memory region utilities: determine if two regions overlap,
|
||||
@ -436,6 +439,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 *))
|
||||
{
|
||||
@ -607,6 +611,8 @@ OF_reboot()
|
||||
for (;;); /* just in case */
|
||||
}
|
||||
|
||||
#endif /* AIM */
|
||||
|
||||
void
|
||||
OF_getetheraddr(device_t dev, u_char *addr)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user