From: Zhang Qilong <zhangqilo...@huawei.com> Sent: Sunday, November 8, 2020 
5:53 PM
> pm_runtime_get_sync() will increment pm usage at first and it will resume the
> device later. If runtime of the device has error or device is in inaccessible
> state(or other error state), resume operation will fail. If we do not call put
> operation to decrease the reference, it will result in reference count leak.
> Moreover, this device cannot enter the idle state and always stay busy or 
> other
> non-idle state later. So we fixed it through adding pm_runtime_put_noidle.
> 
> Fixes: 8fff755e9f8d0 ("net: fec: Ensure clocks are enabled while using mdio 
> bus")
> Signed-off-by: Zhang Qilong <zhangqilo...@huawei.com>

>From early discussion for the topic, Wolfram Sang wonder if such de-reference 
>can
be better handled by pm runtime core code.

https://lkml.org/lkml/2020/6/14/76

Regards,
Andy
> ---
>  drivers/net/ethernet/freescale/fec_main.c | 22 ++++++++++++++++------
>  1 file changed, 16 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/net/ethernet/freescale/fec_main.c
> b/drivers/net/ethernet/freescale/fec_main.c
> index d7919555250d..6c02f885c67e 100644
> --- a/drivers/net/ethernet/freescale/fec_main.c
> +++ b/drivers/net/ethernet/freescale/fec_main.c
> @@ -1809,8 +1809,10 @@ static int fec_enet_mdio_read(struct mii_bus *bus,
> int mii_id, int regnum)
>       bool is_c45 = !!(regnum & MII_ADDR_C45);
> 
>       ret = pm_runtime_get_sync(dev);
> -     if (ret < 0)
> +     if (ret < 0) {
> +             pm_runtime_put_noidle(dev);
>               return ret;
> +     }
> 
>       if (is_c45) {
>               frame_start = FEC_MMFR_ST_C45;
> @@ -1868,10 +1870,12 @@ static int fec_enet_mdio_write(struct mii_bus
> *bus, int mii_id, int regnum,
>       bool is_c45 = !!(regnum & MII_ADDR_C45);
> 
>       ret = pm_runtime_get_sync(dev);
> -     if (ret < 0)
> +     if (ret < 0) {
> +             pm_runtime_put_noidle(dev);
>               return ret;
> -     else
> +     } else {
>               ret = 0;
> +     }
> 
>       if (is_c45) {
>               frame_start = FEC_MMFR_ST_C45;
> @@ -2276,8 +2280,10 @@ static void fec_enet_get_regs(struct net_device
> *ndev,
>       int ret;
> 
>       ret = pm_runtime_get_sync(dev);
> -     if (ret < 0)
> +     if (ret < 0) {
> +             pm_runtime_put_noidle(dev);
>               return;
> +     }
> 
>       regs->version = fec_enet_register_version;
> 
> @@ -2977,8 +2983,10 @@ fec_enet_open(struct net_device *ndev)
>       bool reset_again;
> 
>       ret = pm_runtime_get_sync(&fep->pdev->dev);
> -     if (ret < 0)
> +     if (ret < 0) {
> +             pm_runtime_put_noidle(&fep->pdev->dev);
>               return ret;
> +     }
> 
>       pinctrl_pm_select_default_state(&fep->pdev->dev);
>       ret = fec_enet_clk_enable(ndev, true); @@ -3771,8 +3779,10 @@
> fec_drv_remove(struct platform_device *pdev)
>       int ret;
> 
>       ret = pm_runtime_get_sync(&pdev->dev);
> -     if (ret < 0)
> +     if (ret < 0) {
> +             pm_runtime_put_noidle(&pdev->dev);
>               return ret;
> +     }
> 
>       cancel_work_sync(&fep->tx_timeout_work);
>       fec_ptp_stop(pdev);
> --
> 2.25.4

Reply via email to