Skip to content

Commit 664fcf1

Browse files
lunndavem330
authored andcommitted
net: phy: Threaded interrupts allow some simplification
The PHY interrupts are now handled in a threaded interrupt handler, which can sleep. The work queue is no longer needed, phy_change() can be called directly. phy_mac_interrupt() still needs to be safe to call in interrupt context, so keep the work queue, and use a helper to call phy_change(). Signed-off-by: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c974bdb commit 664fcf1

File tree

3 files changed

+30
-22
lines changed

3 files changed

+30
-22
lines changed

drivers/net/phy/phy.c

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ static void phy_error(struct phy_device *phydev)
664664
* @phy_dat: phy_device pointer
665665
*
666666
* Description: When a PHY interrupt occurs, the handler disables
667-
* interrupts, and schedules a work task to clear the interrupt.
667+
* interrupts, and uses phy_change to handle the interrupt.
668668
*/
669669
static irqreturn_t phy_interrupt(int irq, void *phy_dat)
670670
{
@@ -673,15 +673,10 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat)
673673
if (PHY_HALTED == phydev->state)
674674
return IRQ_NONE; /* It can't be ours. */
675675

676-
/* The MDIO bus is not allowed to be written in interrupt
677-
* context, so we need to disable the irq here. A work
678-
* queue will write the PHY to disable and clear the
679-
* interrupt, and then reenable the irq line.
680-
*/
681676
disable_irq_nosync(irq);
682677
atomic_inc(&phydev->irq_disable);
683678

684-
queue_work(system_power_efficient_wq, &phydev->phy_queue);
679+
phy_change(phydev);
685680

686681
return IRQ_HANDLED;
687682
}
@@ -766,12 +761,6 @@ int phy_stop_interrupts(struct phy_device *phydev)
766761

767762
free_irq(phydev->irq, phydev);
768763

769-
/* Cannot call flush_scheduled_work() here as desired because
770-
* of rtnl_lock(), but we do not really care about what would
771-
* be done, except from enable_irq(), so cancel any work
772-
* possibly pending and take care of the matter below.
773-
*/
774-
cancel_work_sync(&phydev->phy_queue);
775764
/* If work indeed has been cancelled, disable_irq() will have
776765
* been left unbalanced from phy_interrupt() and enable_irq()
777766
* has to be called so that other devices on the line work.
@@ -784,14 +773,11 @@ int phy_stop_interrupts(struct phy_device *phydev)
784773
EXPORT_SYMBOL(phy_stop_interrupts);
785774

786775
/**
787-
* phy_change - Scheduled by the phy_interrupt/timer to handle PHY changes
788-
* @work: work_struct that describes the work to be done
776+
* phy_change - Called by the phy_interrupt to handle PHY changes
777+
* @phydev: phy_device struct that interrupted
789778
*/
790-
void phy_change(struct work_struct *work)
779+
void phy_change(struct phy_device *phydev)
791780
{
792-
struct phy_device *phydev =
793-
container_of(work, struct phy_device, phy_queue);
794-
795781
if (phy_interrupt_is_valid(phydev)) {
796782
if (phydev->drv->did_interrupt &&
797783
!phydev->drv->did_interrupt(phydev))
@@ -832,6 +818,18 @@ void phy_change(struct work_struct *work)
832818
phy_error(phydev);
833819
}
834820

821+
/**
822+
* phy_change_work - Scheduled by the phy_mac_interrupt to handle PHY changes
823+
* @work: work_struct that describes the work to be done
824+
*/
825+
void phy_change_work(struct work_struct *work)
826+
{
827+
struct phy_device *phydev =
828+
container_of(work, struct phy_device, phy_queue);
829+
830+
phy_change(phydev);
831+
}
832+
835833
/**
836834
* phy_stop - Bring down the PHY link, and stop checking the status
837835
* @phydev: target phy_device struct
@@ -1116,6 +1114,15 @@ void phy_state_machine(struct work_struct *work)
11161114
PHY_STATE_TIME * HZ);
11171115
}
11181116

1117+
/**
1118+
* phy_mac_interrupt - MAC says the link has changed
1119+
* @phydev: phy_device struct with changed link
1120+
* @new_link: Link is Up/Down.
1121+
*
1122+
* Description: The MAC layer is able indicate there has been a change
1123+
* in the PHY link status. Set the new link status, and trigger the
1124+
* state machine, work a work queue.
1125+
*/
11191126
void phy_mac_interrupt(struct phy_device *phydev, int new_link)
11201127
{
11211128
phydev->link = new_link;

drivers/net/phy/phy_device.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id,
347347

348348
mutex_init(&dev->lock);
349349
INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
350-
INIT_WORK(&dev->phy_queue, phy_change);
350+
INIT_WORK(&dev->phy_queue, phy_change_work);
351351

352352
/* Request the appropriate module unconditionally; don't
353353
* bother trying to do so only if it isn't already loaded,

include/linux/phy.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ struct phy_c45_device_ids {
343343
* giving up on the current attempt at acquiring a link
344344
* irq: IRQ number of the PHY's interrupt (-1 if none)
345345
* phy_timer: The timer for handling the state machine
346-
* phy_queue: A work_queue for the interrupt
346+
* phy_queue: A work_queue for the phy_mac_interrupt
347347
* attached_dev: The attached enet driver's device instance ptr
348348
* adjust_link: Callback for the enet controller to respond to
349349
* changes in the link state.
@@ -802,7 +802,8 @@ int phy_driver_register(struct phy_driver *new_driver, struct module *owner);
802802
int phy_drivers_register(struct phy_driver *new_driver, int n,
803803
struct module *owner);
804804
void phy_state_machine(struct work_struct *work);
805-
void phy_change(struct work_struct *work);
805+
void phy_change(struct phy_device *phydev);
806+
void phy_change_work(struct work_struct *work);
806807
void phy_mac_interrupt(struct phy_device *phydev, int new_link);
807808
void phy_start_machine(struct phy_device *phydev);
808809
void phy_stop_machine(struct phy_device *phydev);

0 commit comments

Comments
 (0)