diff options
Diffstat (limited to 'drivers/net/phy/phy.c')
| -rw-r--r-- | drivers/net/phy/phy.c | 46 | 
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)  	struct phy_device *phydev =  		container_of(work, struct phy_device, phy_queue); -	if (phydev->drv->did_interrupt && -	    !phydev->drv->did_interrupt(phydev)) -		goto ignore; +	if (phy_interrupt_is_valid(phydev)) { +		if (phydev->drv->did_interrupt && +		    !phydev->drv->did_interrupt(phydev)) +			goto ignore; -	if (phy_disable_interrupts(phydev)) -		goto phy_err; +		if (phy_disable_interrupts(phydev)) +			goto phy_err; +	}  	mutex_lock(&phydev->lock);  	if ((PHY_RUNNING == phydev->state) || (PHY_NOLINK == phydev->state))  		phydev->state = PHY_CHANGELINK;  	mutex_unlock(&phydev->lock); -	atomic_dec(&phydev->irq_disable); -	enable_irq(phydev->irq); +	if (phy_interrupt_is_valid(phydev)) { +		atomic_dec(&phydev->irq_disable); +		enable_irq(phydev->irq); -	/* Reenable interrupts */ -	if (PHY_HALTED != phydev->state && -	    phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED)) -		goto irq_enable_err; +		/* Reenable interrupts */ +		if (PHY_HALTED != phydev->state && +		    phy_config_interrupt(phydev, PHY_INTERRUPT_ENABLED)) +			goto irq_enable_err; +	}  	/* reschedule state queue work to run as soon as possible */  	cancel_delayed_work_sync(&phydev->state_queue); @@ -905,10 +909,10 @@ void phy_state_machine(struct work_struct *work)  		phydev->adjust_link(phydev->attached_dev);  		break;  	case PHY_RUNNING: -		/* Only register a CHANGE if we are polling or ignoring -		 * interrupts and link changed since latest checking. +		/* Only register a CHANGE if we are polling and link changed +		 * since latest checking.  		 */ -		if (!phy_interrupt_is_valid(phydev)) { +		if (phydev->irq == PHY_POLL) {  			old_link = phydev->link;  			err = phy_read_status(phydev);  			if (err) @@ -1000,15 +1004,21 @@ void phy_state_machine(struct work_struct *work)  		   phy_state_to_str(old_state),  		   phy_state_to_str(phydev->state)); -	queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, -			   PHY_STATE_TIME * HZ); +	/* Only re-schedule a PHY state machine change if we are polling the +	 * PHY, if PHY_IGNORE_INTERRUPT is set, then we will be moving +	 * between states from phy_mac_interrupt() +	 */ +	if (phydev->irq == PHY_POLL) +		queue_delayed_work(system_power_efficient_wq, &phydev->state_queue, +				   PHY_STATE_TIME * HZ);  }  void phy_mac_interrupt(struct phy_device *phydev, int new_link)  { -	cancel_work_sync(&phydev->phy_queue);  	phydev->link = new_link; -	schedule_work(&phydev->phy_queue); + +	/* Trigger a state machine change */ +	queue_work(system_power_efficient_wq, &phydev->phy_queue);  }  EXPORT_SYMBOL(phy_mac_interrupt); | 
