lkml.org 
[lkml]   [2013]   [Dec]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.10 19/52] can: c_can: dont call pm_runtime_get_sync() from interrupt context
    Date
    3.10-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Marc Kleine-Budde <mkl@pengutronix.de>

    commit e35d46adc49b469fd92bdb64fea8af93640e6651 upstream.

    The c_can driver contians a callpath (c_can_poll -> c_can_state_change ->
    c_can_get_berr_counter) which may call pm_runtime_get_sync() from the IRQ
    handler, which is not allowed and results in "BUG: scheduling while atomic".

    This problem is fixed by introducing __c_can_get_berr_counter, which will not
    call pm_runtime_get_sync().

    Reported-by: Andrew Glen <AGlen@bepmarine.com>
    Tested-by: Andrew Glen <AGlen@bepmarine.com>
    Signed-off-by: Andrew Glen <AGlen@bepmarine.com>
    Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/net/can/c_can/c_can.c | 21 +++++++++++++++------
    1 file changed, 15 insertions(+), 6 deletions(-)

    --- a/drivers/net/can/c_can/c_can.c
    +++ b/drivers/net/can/c_can/c_can.c
    @@ -712,22 +712,31 @@ static int c_can_set_mode(struct net_dev
    return 0;
    }

    -static int c_can_get_berr_counter(const struct net_device *dev,
    - struct can_berr_counter *bec)
    +static int __c_can_get_berr_counter(const struct net_device *dev,
    + struct can_berr_counter *bec)
    {
    unsigned int reg_err_counter;
    struct c_can_priv *priv = netdev_priv(dev);

    - c_can_pm_runtime_get_sync(priv);
    -
    reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
    bec->rxerr = (reg_err_counter & ERR_CNT_REC_MASK) >>
    ERR_CNT_REC_SHIFT;
    bec->txerr = reg_err_counter & ERR_CNT_TEC_MASK;

    + return 0;
    +}
    +
    +static int c_can_get_berr_counter(const struct net_device *dev,
    + struct can_berr_counter *bec)
    +{
    + struct c_can_priv *priv = netdev_priv(dev);
    + int err;
    +
    + c_can_pm_runtime_get_sync(priv);
    + err = __c_can_get_berr_counter(dev, bec);
    c_can_pm_runtime_put_sync(priv);

    - return 0;
    + return err;
    }

    /*
    @@ -872,7 +881,7 @@ static int c_can_handle_state_change(str
    if (unlikely(!skb))
    return 0;

    - c_can_get_berr_counter(dev, &bec);
    + __c_can_get_berr_counter(dev, &bec);
    reg_err_counter = priv->read_reg(priv, C_CAN_ERR_CNT_REG);
    rx_err_passive = (reg_err_counter & ERR_CNT_RP_MASK) >>
    ERR_CNT_RP_SHIFT;



    \
     
     \ /
      Last update: 2013-12-10 11:41    [W:2.158 / U:0.800 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site