lkml.org 
[lkml]   [2016]   [Mar]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.2.y-ckt 269/273] net: phy: Fix phy_mac_interrupt()
    Date
    4.2.8-ckt5 -stable review patch.  If anyone has any objections, please let me know.

    ---8<------------------------------------------------------------

    From: Florian Fainelli <f.fainelli@gmail.com>

    commit deccd16f91f930af8e91ffbbfc839d0ad8da999d upstream.

    Commit 5ea94e7686a3 ("phy: add phy_mac_interrupt()") to use with
    PHY_IGNORE_INTERRUPT added a cancel_work_sync() into phy_mac_interrupt()
    which is allowed to sleep, whereas phy_mac_interrupt() is expected to be
    callable from interrupt context.

    Now that we have fixed how the PHY state machine treats
    PHY_IGNORE_INTERRUPT with respect to state changes, we can just set the
    new link state, and queue the PHY state machine for execution so it is
    going to read the new link state.

    For that to work properly, we need to update phy_change() not to try to
    invoke any interrupt callbacks if we have configured the PHY device for
    PHY_IGNORE_INTERRUPT, because that PHY device and its driver are not
    required to implement those.

    Fixes: 5ea94e7686a3 ("phy: add phy_mac_interrupt() to use with PHY_IGNORE_INTERRUPT")
    Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
    Signed-off-by: David S. Miller <davem@davemloft.net>
    Signed-off-by: Kamal Mostafa <kamal@canonical.com>
    ---
    drivers/net/phy/phy.c | 31 ++++++++++++++++++-------------
    1 file changed, 18 insertions(+), 13 deletions(-)

    diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
    index 34fe339..8e7f683 100644
    --- a/drivers/net/phy/phy.c
    +++ b/drivers/net/phy/phy.c
    @@ -687,25 +687,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);
    @@ -997,9 +1001,10 @@ void phy_state_machine(struct work_struct *work)

    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);

    --
    2.7.0
    \
     
     \ /
      Last update: 2016-03-08 00:41    [W:3.611 / U:0.172 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site