ETRAX-FS: Correct ethernet PHY diagnostics register reads.

* Correct ethernet PHY diagnostics register reads.
* Add friendly names for the speed/duplex fields.
* Report duplex mismatches between MAC and PHY.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5300 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
edgar_igl 2008-09-22 20:34:18 +00:00
parent 9d92659858
commit c64882682d

View File

@ -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(&eth->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(&eth->phy);
mdio_attach(&eth->mdio_bus, &eth->phy, 0x1);
mdio_attach(&eth->mdio_bus, &eth->phy, eth->phyaddr);
eth->ethregs = cpu_register_io_memory(0, eth_read, eth_write, eth);
cpu_register_physical_memory (base, 0x5c, eth->ethregs);