aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/phy.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/phy.c')
-rw-r--r--drivers/net/phy/phy.c46
1 files changed, 28 insertions, 18 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 8763bb20988a..5590b9c182c9 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -692,25 +692,29 @@ void phy_change(struct work_struct *work)
692 struct phy_device *phydev = 692 struct phy_device *phydev =
693 container_of(work, struct phy_device, phy_queue); 693 container_of(work, struct phy_device, phy_queue);
694 694
695 if (phydev->drv->did_interrupt && 695 if (phy_interrupt_is_valid(phydev)) {
696 !phydev->drv->did_interrupt(phydev)) 696 if (phydev->drv->did_interrupt &&
697 goto ignore; 697 !phydev->drv->did_interrupt(phydev))
698 goto ignore;
698 699
699 if (phy_disable_interrupts(phydev)) 700 if (phy_disable_interrupts(phydev))
700 goto phy_err; 701 goto phy_err;
702 }
701 703
702 mutex_lock(&phydev->lock); 704 mutex_lock(&phydev->lock);
703 if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state)) 705 if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))
704 phydev->state = PHY_CHANGELINK; 706 phydev->state = PHY_CHANGELINK;
705 mutex_unlock(&phydev->lock); 707 mutex_unlock(&phydev->lock);
706 708
707 atomic_dec(&phydev->irq_disable); 709 if (phy_interrupt_is_valid(phydev)) {
708 enable_irq(phydev->irq); 710 atomic_dec(&phydev->irq_disable);
711 enable_irq(phydev->irq);
709 712
710 /* Reenable interrupts */ 713 /* Reenable interrupts */
711 if (PHY_HALTED != phydev->state && 714 if (PHY_HALTED != phydev->state &&
712 phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED)) 715 phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED))
713 goto irq_enable_err; 716 goto irq_enable_err;
717 }
714 718
715 /* reschedule state queue work to run as soon as possible */ 719 /* reschedule state queue work to run as soon as possible */
716 cancel_delayed_work_sync(&phydev->state_queue); 720 cancel_delayed_work_sync(&phydev->state_queue);
@@ -905,10 +909,10 @@ void phy_state_machine(struct work_struct *work)
905 phydev->adjust_link(phydev->attached_dev); 909 phydev->adjust_link(phydev->attached_dev);
906 break; 910 break;
907 case PHY_RUNNING: 911 case PHY_RUNNING:
908 /* Only register a CHANGE if we are polling or ignoring 912 /* Only register a CHANGE if we are polling and link changed
909 * interrupts and link changed since latest checking. 913 * since latest checking.
910 */ 914 */
911 if (!phy_interrupt_is_valid(phydev)) { 915 if (phydev->irq == PHY_POLL) {
912 old_link = phydev->link; 916 old_link = phydev->link;
913 err = phy_read_status(phydev); 917 err = phy_read_status(phydev);
914 if (err) 918 if (err)
@@ -1000,15 +1004,21 @@ void phy_state_machine(struct work_struct *work)
1000 phy_state_to_str(old_state), 1004 phy_state_to_str(old_state),
1001 phy_state_to_str(phydev->state)); 1005 phy_state_to_str(phydev->state));
1002 1006
1003 queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, 1007 /* Only re-schedule a PHY state machine change if we are polling the
1004 PHY_STATE_TIME * HZ); 1008 * PHY, if PHY_IGNORE_INTERRUPT is set, then we will be moving
1009 * between states from phy_mac_interrupt()
1010 */
1011 if (phydev->irq == PHY_POLL)
1012 queue_delayed_work(system_power_efficient_wq, &phydev->state_queue,
1013 PHY_STATE_TIME * HZ);
1005} 1014}
1006 1015
1007void phy_mac_interrupt(struct phy_device *phydev, int new_link) 1016void phy_mac_interrupt(struct phy_device *phydev, int new_link)
1008{ 1017{
1009 cancel_work_sync(&phydev->phy_queue);
1010 phydev->link = new_link; 1018 phydev->link = new_link;
1011 schedule_work(&phydev->phy_queue); 1019
1020 /* Trigger a state machine change */
1021 queue_work(system_power_efficient_wq, &phydev->phy_queue);
1012} 1022}
1013EXPORT_SYMBOL(phy_mac_interrupt); 1023EXPORT_SYMBOL(phy_mac_interrupt);
1014 1024