e1000: correctly handle phy_ctrl reserved & self-clearing bits

Make phyreg_writeops responsible for actually writing their
respective phy registers, rather than rely on set_mdic() to
do it on their behalf.

The only current instance of phyreg_writeops is set_phy_ctrl();
modify it to write the register on its own, while also correctly
handling reserved and self-clearing bits.

have_autoneg() does not need to check for MII_CR_RESTART_AUTO_NEG,
since the only time the flag comes into play is during set_phy_ctrl(),
and, following this patch, never actually gets written to the phy
control register.

Signed-off-by: Gabriel Somlo <somlo@cmu.edu>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Gabriel L. Somlo 2014-08-06 14:07:10 -04:00 committed by Michael S. Tsirkin
parent 7f9efb6b80
commit 1195fed9e6
1 changed files with 17 additions and 14 deletions

View File

@ -186,21 +186,31 @@ e1000_link_up(E1000State *s)
s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
}
static bool
have_autoneg(E1000State *s)
{
return (s->compat_flags & E1000_FLAG_AUTONEG) &&
(s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN);
}
static void
set_phy_ctrl(E1000State *s, int index, uint16_t val)
{
/* bits 0-5 reserved; MII_CR_[RESTART_AUTO_NEG,RESET] are self clearing */
s->phy_reg[PHY_CTRL] = val & ~(0x3f |
MII_CR_RESET |
MII_CR_RESTART_AUTO_NEG);
/*
* QEMU 1.3 does not support link auto-negotiation emulation, so if we
* migrate during auto negotiation, after migration the link will be
* down.
*/
if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
return;
}
if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) {
if (have_autoneg(s) && (val & MII_CR_RESTART_AUTO_NEG)) {
e1000_link_down(s);
DBGOUT(PHY, "Start link auto negotiation\n");
timer_mod(s->autoneg_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
timer_mod(s->autoneg_timer,
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
}
}
@ -446,8 +456,9 @@ set_mdic(E1000State *s, int index, uint32_t val)
} else {
if (addr < NPHYWRITEOPS && phyreg_writeops[addr]) {
phyreg_writeops[addr](s, index, data);
} else {
s->phy_reg[addr] = data;
}
s->phy_reg[addr] = data;
}
}
s->mac_reg[MDIC] = val | E1000_MDIC_READY;
@ -848,14 +859,6 @@ receive_filter(E1000State *s, const uint8_t *buf, int size)
return 0;
}
static bool
have_autoneg(E1000State *s)
{
return (s->compat_flags & E1000_FLAG_AUTONEG) &&
(s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN) &&
(s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG);
}
static void
e1000_set_link_status(NetClientState *nc)
{