lkml.org 
[lkml]   [2022]   [Aug]   [23]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.15 145/244] i2c: imx: Make sure to unregister adapter on remove()
    Date
    From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

    commit d98bdd3a5b50446d8e010be5b04ce81c4eabf728 upstream.

    If for whatever reasons pm_runtime_resume_and_get() fails and .remove() is
    exited early, the i2c adapter stays around and the irq still calls its
    handler, while the driver data and the register mapping go away. So if
    later the i2c adapter is accessed or the irq triggers this results in
    havoc accessing freed memory and unmapped registers.

    So unregister the software resources even if resume failed, and only skip
    the hardware access in that case.

    Fixes: 588eb93ea49f ("i2c: imx: add runtime pm support to improve the performance")
    Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
    Acked-by: Oleksij Rempel <o.rempel@pengutronix.de>
    Signed-off-by: Wolfram Sang <wsa@kernel.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    drivers/i2c/busses/i2c-imx.c | 20 +++++++++++---------
    1 file changed, 11 insertions(+), 9 deletions(-)

    --- a/drivers/i2c/busses/i2c-imx.c
    +++ b/drivers/i2c/busses/i2c-imx.c
    @@ -1487,9 +1487,7 @@ static int i2c_imx_remove(struct platfor
    struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev);
    int irq, ret;

    - ret = pm_runtime_resume_and_get(&pdev->dev);
    - if (ret < 0)
    - return ret;
    + ret = pm_runtime_get_sync(&pdev->dev);

    /* remove adapter */
    dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n");
    @@ -1498,17 +1496,21 @@ static int i2c_imx_remove(struct platfor
    if (i2c_imx->dma)
    i2c_imx_dma_free(i2c_imx);

    - /* setup chip registers to defaults */
    - imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
    - imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
    - imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
    - imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
    + if (ret == 0) {
    + /* setup chip registers to defaults */
    + imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR);
    + imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR);
    + imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR);
    + imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR);
    + clk_disable(i2c_imx->clk);
    + }

    clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb);
    irq = platform_get_irq(pdev, 0);
    if (irq >= 0)
    free_irq(irq, i2c_imx);
    - clk_disable_unprepare(i2c_imx->clk);
    +
    + clk_unprepare(i2c_imx->clk);

    pm_runtime_put_noidle(&pdev->dev);
    pm_runtime_disable(&pdev->dev);

    \
     
     \ /
      Last update: 2022-08-23 12:14    [W:4.121 / U:0.100 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site