diff options
author | Lucas Stach <l.stach@pengutronix.de> | 2013-03-14 01:12:01 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-03-15 08:46:48 -0400 |
commit | d97e74976982a35168c7f131cce0d93537337a26 (patch) | |
tree | da808857fddb6f987c1982b2348555afd247b80e /drivers/net | |
parent | cca7af3889bfa343d33d5e657a38d876abd10e58 (diff) |
net: fec: restart the FEC when PHY speed changes
Proviously we would only restart the FEC when PHY link or duplex state
changed. PHY does not always bring down the link for speed changes, in
which case we would not detect any change and keep FEC running.
Switching link speed without restarting the FEC results in the FEC being
stuck in an indefinite state, generating error conditions for every
packet.
Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/freescale/fec.c | 26 | ||||
-rw-r--r-- | drivers/net/ethernet/freescale/fec.h | 1 |
2 files changed, 16 insertions, 11 deletions
diff --git a/drivers/net/ethernet/freescale/fec.c b/drivers/net/ethernet/freescale/fec.c index 069a155d16ed..61d2e6202bf3 100644 --- a/drivers/net/ethernet/freescale/fec.c +++ b/drivers/net/ethernet/freescale/fec.c | |||
@@ -934,24 +934,28 @@ static void fec_enet_adjust_link(struct net_device *ndev) | |||
934 | goto spin_unlock; | 934 | goto spin_unlock; |
935 | } | 935 | } |
936 | 936 | ||
937 | /* Duplex link change */ | ||
938 | if (phy_dev->link) { | 937 | if (phy_dev->link) { |
939 | if (fep->full_duplex != phy_dev->duplex) { | 938 | if (!fep->link) { |
940 | fec_restart(ndev, phy_dev->duplex); | ||
941 | /* prevent unnecessary second fec_restart() below */ | ||
942 | fep->link = phy_dev->link; | 939 | fep->link = phy_dev->link; |
943 | status_change = 1; | 940 | status_change = 1; |
944 | } | 941 | } |
945 | } | ||
946 | 942 | ||
947 | /* Link on or off change */ | 943 | if (fep->full_duplex != phy_dev->duplex) |
948 | if (phy_dev->link != fep->link) { | 944 | status_change = 1; |
949 | fep->link = phy_dev->link; | 945 | |
950 | if (phy_dev->link) | 946 | if (phy_dev->speed != fep->speed) { |
947 | fep->speed = phy_dev->speed; | ||
948 | status_change = 1; | ||
949 | } | ||
950 | |||
951 | /* if any of the above changed restart the FEC */ | ||
952 | if (status_change) | ||
951 | fec_restart(ndev, phy_dev->duplex); | 953 | fec_restart(ndev, phy_dev->duplex); |
952 | else | 954 | } else { |
955 | if (fep->link) { | ||
953 | fec_stop(ndev); | 956 | fec_stop(ndev); |
954 | status_change = 1; | 957 | status_change = 1; |
958 | } | ||
955 | } | 959 | } |
956 | 960 | ||
957 | spin_unlock: | 961 | spin_unlock: |
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index f5390071efd0..eb4372962839 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h | |||
@@ -240,6 +240,7 @@ struct fec_enet_private { | |||
240 | phy_interface_t phy_interface; | 240 | phy_interface_t phy_interface; |
241 | int link; | 241 | int link; |
242 | int full_duplex; | 242 | int full_duplex; |
243 | int speed; | ||
243 | struct completion mdio_done; | 244 | struct completion mdio_done; |
244 | int irq[FEC_IRQ_NUM]; | 245 | int irq[FEC_IRQ_NUM]; |
245 | int bufdesc_ex; | 246 | int bufdesc_ex; |