aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Beale <tim.beale@alliedtelesis.co.nz>2015-05-17 23:38:38 -0400
committerDavid S. Miller <davem@davemloft.net>2015-05-20 12:22:08 -0400
commitc15e10e71ce3b4ee78d85d80102a9621cde1edbd (patch)
tree51f55dc4cd4bd6e6f082f36ec6b9d081deb4ecad
parent7764b9dd38f31ce58e6f764e2d7d8399d9b62486 (diff)
net: phy: Make sure phy_start() always re-enables the phy interrupts
This is an alternative way of fixing: commit db9683fb412d ("net: phy: Make sure PHY_RESUMING state change is always processed") When the PHY state transitions from PHY_HALTED to PHY_RESUMING, there are two things we need to do: 1). Re-enable interrupts (and power up the physical link, if powered down) 2). Update the PHY state and net-device based on the link status. There's no strict reason why #1 has to be done from within the main phy_state_machine() function. There is a risk that other changes to the PHY (e.g. setting speed/duplex, which calls phy_start_aneg()) could cause a subsequent state transition before phy_state_machine() has processed the PHY_RESUMING state change. This would leave the PHY with interrupts disabled and/or still in the BMCR_PDOWN/low-power mode. Moving enabling the interrupts and phy_resume() into phy_start() will guarantee this work always gets done. As the PHY is already in the HALTED state and interrupts are disabled, it shouldn't conflict with any work being done in phy_state_machine(). The downside of this change is that if the PHY_RESUMING state is ever entered from anywhere else, it'll also have to repeat this work. Signed-off-by: Tim Beale <tim.beale@alliedtelesis.co.nz> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/phy/phy.c29
1 files changed, 16 insertions, 13 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 710696d1af97..47cd578052fc 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -465,7 +465,7 @@ int phy_start_aneg(struct phy_device *phydev)
465 if (err < 0) 465 if (err < 0)
466 goto out_unlock; 466 goto out_unlock;
467 467
468 if (phydev->state != PHY_HALTED && phydev->state != PHY_RESUMING) { 468 if (phydev->state != PHY_HALTED) {
469 if (AUTONEG_ENABLE == phydev->autoneg) { 469 if (AUTONEG_ENABLE == phydev->autoneg) {
470 phydev->state = PHY_AN; 470 phydev->state = PHY_AN;
471 phydev->link_timeout = PHY_AN_TIMEOUT; 471 phydev->link_timeout = PHY_AN_TIMEOUT;
@@ -742,6 +742,9 @@ EXPORT_SYMBOL(phy_stop);
742 */ 742 */
743void phy_start(struct phy_device *phydev) 743void phy_start(struct phy_device *phydev)
744{ 744{
745 bool do_resume = false;
746 int err = 0;
747
745 mutex_lock(&phydev->lock); 748 mutex_lock(&phydev->lock);
746 749
747 switch (phydev->state) { 750 switch (phydev->state) {
@@ -752,11 +755,22 @@ void phy_start(struct phy_device *phydev)
752 phydev->state = PHY_UP; 755 phydev->state = PHY_UP;
753 break; 756 break;
754 case PHY_HALTED: 757 case PHY_HALTED:
758 /* make sure interrupts are re-enabled for the PHY */
759 err = phy_enable_interrupts(phydev);
760 if (err < 0)
761 break;
762
755 phydev->state = PHY_RESUMING; 763 phydev->state = PHY_RESUMING;
764 do_resume = true;
765 break;
756 default: 766 default:
757 break; 767 break;
758 } 768 }
759 mutex_unlock(&phydev->lock); 769 mutex_unlock(&phydev->lock);
770
771 /* if phy was suspended, bring the physical link up again */
772 if (do_resume)
773 phy_resume(phydev);
760} 774}
761EXPORT_SYMBOL(phy_start); 775EXPORT_SYMBOL(phy_start);
762 776
@@ -769,7 +783,7 @@ void phy_state_machine(struct work_struct *work)
769 struct delayed_work *dwork = to_delayed_work(work); 783 struct delayed_work *dwork = to_delayed_work(work);
770 struct phy_device *phydev = 784 struct phy_device *phydev =
771 container_of(dwork, struct phy_device, state_queue); 785 container_of(dwork, struct phy_device, state_queue);
772 bool needs_aneg = false, do_suspend = false, do_resume = false; 786 bool needs_aneg = false, do_suspend = false;
773 int err = 0; 787 int err = 0;
774 788
775 mutex_lock(&phydev->lock); 789 mutex_lock(&phydev->lock);
@@ -888,14 +902,6 @@ void phy_state_machine(struct work_struct *work)
888 } 902 }
889 break; 903 break;
890 case PHY_RESUMING: 904 case PHY_RESUMING:
891 err = phy_clear_interrupt(phydev);
892 if (err)
893 break;
894
895 err = phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED);
896 if (err)
897 break;
898
899 if (AUTONEG_ENABLE == phydev->autoneg) { 905 if (AUTONEG_ENABLE == phydev->autoneg) {
900 err = phy_aneg_done(phydev); 906 err = phy_aneg_done(phydev);
901 if (err < 0) 907 if (err < 0)
@@ -933,7 +939,6 @@ void phy_state_machine(struct work_struct *work)
933 } 939 }
934 phydev->adjust_link(phydev->attached_dev); 940 phydev->adjust_link(phydev->attached_dev);
935 } 941 }
936 do_resume = true;
937 break; 942 break;
938 } 943 }
939 944
@@ -943,8 +948,6 @@ void phy_state_machine(struct work_struct *work)
943 err = phy_start_aneg(phydev); 948 err = phy_start_aneg(phydev);
944 else if (do_suspend) 949 else if (do_suspend)
945 phy_suspend(phydev); 950 phy_suspend(phydev);
946 else if (do_resume)
947 phy_resume(phydev);
948 951
949 if (err < 0) 952 if (err < 0)
950 phy_error(phydev); 953 phy_error(phydev);