提交 6a2acedb 编写于 作者: G Gabriel L. Somlo 提交者: Michael S. Tsirkin

e1000: emulate auto-negotiation during external link status change

This patch emulates auto-negotiation when the network link status
is modified externally (i.e. via "set_link <id> off/on").

Also, a couple of cleanup items:
  - unset PHY status reg. AUTONEG_COMPLETE during link_down()
  - set PHY status reg. AUTONEG_COMPLETE during autoneg_timer() only
    if we actually brought the link up.
  - group all checks for "can we, and should we autonegotiate?"
    together for more clarity.
Signed-off-by: NGabriel Somlo <somlo@cmu.edu>
Reviewed-by: NAlexander Graf <agraf@suse.de>
Reviewed-by: NStefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: NMichael S. Tsirkin <mst@redhat.com>
Signed-off-by: NMichael S. Tsirkin <mst@redhat.com>
上级 f61badf3
...@@ -175,6 +175,7 @@ e1000_link_down(E1000State *s) ...@@ -175,6 +175,7 @@ e1000_link_down(E1000State *s)
{ {
s->mac_reg[STATUS] &= ~E1000_STATUS_LU; s->mac_reg[STATUS] &= ~E1000_STATUS_LU;
s->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS; s->phy_reg[PHY_STATUS] &= ~MII_SR_LINK_STATUS;
s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
} }
static void static void
...@@ -197,7 +198,6 @@ set_phy_ctrl(E1000State *s, int index, uint16_t val) ...@@ -197,7 +198,6 @@ set_phy_ctrl(E1000State *s, int index, uint16_t val)
} }
if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) { if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) {
e1000_link_down(s); e1000_link_down(s);
s->phy_reg[PHY_STATUS] &= ~MII_SR_AUTONEG_COMPLETE;
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);
} }
...@@ -209,9 +209,9 @@ e1000_autoneg_timer(void *opaque) ...@@ -209,9 +209,9 @@ e1000_autoneg_timer(void *opaque)
E1000State *s = opaque; E1000State *s = opaque;
if (!qemu_get_queue(s->nic)->link_down) { if (!qemu_get_queue(s->nic)->link_down) {
e1000_link_up(s); e1000_link_up(s);
s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
DBGOUT(PHY, "Auto negotiation is completed\n");
} }
s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
DBGOUT(PHY, "Auto negotiation is completed\n");
} }
static void (*phyreg_writeops[])(E1000State *, int, uint16_t) = { static void (*phyreg_writeops[])(E1000State *, int, uint16_t) = {
...@@ -853,7 +853,16 @@ e1000_set_link_status(NetClientState *nc) ...@@ -853,7 +853,16 @@ e1000_set_link_status(NetClientState *nc)
if (nc->link_down) { if (nc->link_down) {
e1000_link_down(s); e1000_link_down(s);
} else { } else {
e1000_link_up(s); if (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 &&
!(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
/* emulate auto-negotiation if supported */
timer_mod(s->autoneg_timer,
qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
} else {
e1000_link_up(s);
}
} }
if (s->mac_reg[STATUS] != old_status) if (s->mac_reg[STATUS] != old_status)
...@@ -1279,16 +1288,13 @@ static void e1000_pre_save(void *opaque) ...@@ -1279,16 +1288,13 @@ static void e1000_pre_save(void *opaque)
e1000_mit_timer(s); e1000_mit_timer(s);
} }
if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
return;
}
/* /*
* If link is down and auto-negotiation is ongoing, complete * If link is down and auto-negotiation is supported and ongoing,
* auto-negotiation immediately. This allows is to look at * complete auto-negotiation immediately. This allows us to look
* MII_SR_AUTONEG_COMPLETE to infer link status on load. * at MII_SR_AUTONEG_COMPLETE to infer link status on load.
*/ */
if (nc->link_down && if (nc->link_down &&
s->compat_flags & E1000_FLAG_AUTONEG &&
s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN && s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG) { s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG) {
s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE; s->phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
...@@ -1313,11 +1319,8 @@ static int e1000_post_load(void *opaque, int version_id) ...@@ -1313,11 +1319,8 @@ static int e1000_post_load(void *opaque, int version_id)
* Alternatively, restart link negotiation if it was in progress. */ * Alternatively, restart link negotiation if it was in progress. */
nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0; nc->link_down = (s->mac_reg[STATUS] & E1000_STATUS_LU) == 0;
if (!(s->compat_flags & E1000_FLAG_AUTONEG)) { if (s->compat_flags & E1000_FLAG_AUTONEG &&
return 0; s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
}
if (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN &&
s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG && s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG &&
!(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) { !(s->phy_reg[PHY_STATUS] & MII_SR_AUTONEG_COMPLETE)) {
nc->link_down = false; nc->link_down = false;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册