diff options
-rw-r--r-- | hw/etraxfs_eth.c | 55 |
1 files changed, 51 insertions, 4 deletions
diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index 9ef610fd19..507937705b 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -30,6 +30,12 @@ #define D(x) +/* Advertisement control register. */ +#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ +#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ +#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ +#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ + /* * The MDIO extensions in the TDK PHY model were reversed engineered from the * linux driver (PHYID and Diagnostics reg). @@ -78,9 +84,12 @@ static unsigned int tdk_read(struct qemu_phy *phy, unsigned int req) int speed_100 = 0; /* Are we advertising 100 half or 100 duplex ? */ - speed_100 = !!(phy->regs[4] & 0x180); + speed_100 = !!(phy->regs[4] & ADVERTISE_100HALF); + speed_100 |= !!(phy->regs[4] & ADVERTISE_100FULL); + /* Are we advertising 10 duplex or 100 duplex ? */ - duplex = !!(phy->regs[4] & 0x180); + duplex = !!(phy->regs[4] & ADVERTISE_100FULL); + duplex |= !!(phy->regs[4] & ADVERTISE_10FULL); r = (speed_100 << 10) | (duplex << 11); } break; @@ -322,10 +331,40 @@ struct fs_eth /* MDIO bus. */ struct qemu_mdio mdio_bus; + unsigned int phyaddr; + int duplex_mismatch; + /* PHY. */ struct qemu_phy phy; }; +static void eth_validate_duplex(struct fs_eth *eth) +{ + struct qemu_phy *phy; + unsigned int phy_duplex; + unsigned int mac_duplex; + int new_mm = 0; + + phy = eth->mdio_bus.devs[eth->phyaddr]; + phy_duplex = !!(phy->read(phy, 18) & (1 << 11)); + mac_duplex = !!(eth->regs[RW_REC_CTRL] & 128); + + if (mac_duplex != phy_duplex) + new_mm = 1; + + if (eth->regs[RW_GEN_CTRL] & 1) { + if (new_mm != eth->duplex_mismatch) { + if (new_mm) + printf("HW: WARNING " + "ETH duplex mismatch MAC=%d PHY=%d\n", + mac_duplex, phy_duplex); + else + printf("HW: ETH duplex ok.\n"); + } + eth->duplex_mismatch = new_mm; + } +} + static uint32_t eth_rinvalid (void *opaque, target_phys_addr_t addr) { struct fs_eth *eth = opaque; @@ -418,11 +457,18 @@ eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value) /* Attach an MDIO/PHY abstraction. */ if (value & 2) eth->mdio_bus.mdio = value & 1; - if (eth->mdio_bus.mdc != (value & 4)) + if (eth->mdio_bus.mdc != (value & 4)) { mdio_cycle(ð->mdio_bus); + eth_validate_duplex(eth); + } eth->mdio_bus.mdc = !!(value & 4); break; + case RW_REC_CTRL: + eth->regs[addr] = value; + eth_validate_duplex(eth); + break; + default: eth->regs[addr] = value; D(printf ("%s %x %x\n", @@ -591,8 +637,9 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, eth->dma_in = dma + 1; /* Connect the phy. */ + eth->phyaddr = 1; tdk_init(ð->phy); - mdio_attach(ð->mdio_bus, ð->phy, 0x1); + mdio_attach(ð->mdio_bus, ð->phy, eth->phyaddr); eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth); cpu_register_physical_memory (base, 0x5c, eth->ethregs); |