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:
parent
7f9efb6b80
commit
1195fed9e6
@ -186,21 +186,31 @@ e1000_link_up(E1000State *s)
|
|||||||
s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
|
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
|
static void
|
||||||
set_phy_ctrl(E1000State *s, int index, uint16_t val)
|
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
|
* QEMU 1.3 does not support link auto-negotiation emulation, so if we
|
||||||
* migrate during auto negotiation, after migration the link will be
|
* migrate during auto negotiation, after migration the link will be
|
||||||
* down.
|
* down.
|
||||||
*/
|
*/
|
||||||
if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
|
if (have_autoneg(s) && (val & MII_CR_RESTART_AUTO_NEG)) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) {
|
|
||||||
e1000_link_down(s);
|
e1000_link_down(s);
|
||||||
DBGOUT(PHY, "Start link auto negotiation\n");
|
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 {
|
} else {
|
||||||
if (addr < NPHYWRITEOPS && phyreg_writeops[addr]) {
|
if (addr < NPHYWRITEOPS && phyreg_writeops[addr]) {
|
||||||
phyreg_writeops[addr](s, index, data);
|
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;
|
s->mac_reg[MDIC] = val | E1000_MDIC_READY;
|
||||||
@ -848,14 +859,6 @@ receive_filter(E1000State *s, const uint8_t *buf, int size)
|
|||||||
return 0;
|
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
|
static void
|
||||||
e1000_set_link_status(NetClientState *nc)
|
e1000_set_link_status(NetClientState *nc)
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user