Message ID | 20201119070119.4174387-1-zhangqilong3@huawei.com |
---|---|
State | New |
Headers | show |
Series | Input: omap-keypad: Fix error goto and handling in omap4_keypad_probe | expand |
Hi Zhang, On Thu, Nov 19, 2020 at 03:01:19PM +0800, Zhang Qilong wrote: > In omap4_keypad_probe, the patch fix several bugs. > > 1) pm_runtime_get_sync will increment pm usage counter even it > failed. Forgetting to pm_runtime_put_noidle will result in > reference leak. > > 2) In err_unmap, forget to disable runtime of device, > pm_runtime_enable will increase power disable depth. Thus a > pairing decrement is needed on the error handling path to keep > it balanced. > > 3) In err_pm_disable, it will call pm_runtime_put_sync twice not > one time. > > And we add the pm_runtime_put_noidle when pm_runtime_get_sync failed > for 1). Move pm_runtime_disable to the err_unmap branch for 2). Move > the input_register_device ahead for 3). > > Fixes: f77621cc640a7 ("Input: omap-keypad - dynamically handle register offsets") > Fixes: 5ad567ffbaf20 ("Input: Input: omap4-keypad - wire up runtime PM handling") > Signed-off-by: Zhang Qilong <zhangqilong3@huawei.com> > --- > drivers/input/keyboard/omap4-keypad.c | 13 +++++++------ > 1 file changed, 7 insertions(+), 6 deletions(-) > > diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c > index d6c924032aaa..17abc8434af5 100644 > --- a/drivers/input/keyboard/omap4-keypad.c > +++ b/drivers/input/keyboard/omap4-keypad.c > @@ -277,6 +277,7 @@ static int omap4_keypad_probe(struct platform_device *pdev) > pm_runtime_enable(&pdev->dev); > error = pm_runtime_get_sync(&pdev->dev); > if (error) { > + pm_runtime_put_noidle(&pdev->dev); > dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); > goto err_unmap; > } > @@ -349,20 +350,19 @@ static int omap4_keypad_probe(struct platform_device *pdev) > goto err_free_keymap; > } > > - device_init_wakeup(&pdev->dev, true); > - pm_runtime_put_sync(&pdev->dev); > - > error = input_register_device(keypad_data->input); > if (error < 0) { > dev_err(&pdev->dev, "failed to register input device\n"); > - goto err_pm_disable; > + goto err_free_irq; > } > > + device_init_wakeup(&pdev->dev, true); > + pm_runtime_put_sync(&pdev->dev); > + I think your patch is technically correct, but I wonder if we should limit area of where we have device's clocks enabled to only where we need it. I.e. something like this: diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index d6c924032aaa..4ca754e95978 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -186,12 +186,8 @@ static int omap4_keypad_open(struct input_dev *input) return 0; } -static void omap4_keypad_close(struct input_dev *input) +static void omap4_keypad_stop(struct omap4_keypad *keypad_data) { - struct omap4_keypad *keypad_data = input_get_drvdata(input); - - disable_irq(keypad_data->irq); - /* Disable interrupts and wake-up events */ kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE, OMAP4_VAL_IRQDISABLE); @@ -200,7 +196,14 @@ static void omap4_keypad_close(struct input_dev *input) /* clear pending interrupts */ kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); +} +static void omap4_keypad_close(struct input_dev *input) +{ + struct omap4_keypad *keypad_data = input_get_drvdata(input); + + disable_irq(keypad_data->irq); + omap4_keypad_stop(keypad_data); enable_irq(keypad_data->irq); pm_runtime_put_sync(input->dev.parent); @@ -223,13 +226,37 @@ static int omap4_keypad_parse_dt(struct device *dev, return 0; } +static int omap4_keypad_check_revision(struct device *dev, + struct omap4_keypad *keypad_data) +{ + unsigned int rev; + + rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION); + rev &= 0x03 << 30; + rev >>= 30; + switch (rev) { + case KBD_REVISION_OMAP4: + keypad_data->reg_offset = 0x00; + keypad_data->irqreg_offset = 0x00; + break; + case KBD_REVISION_OMAP5: + keypad_data->reg_offset = 0x10; + keypad_data->irqreg_offset = 0x0c; + break; + default: + dev_err(dev, "Keypad reports unsupported revision %d", rev); + return -EINVAL; + } + + return 0; +} + static int omap4_keypad_probe(struct platform_device *pdev) { struct omap4_keypad *keypad_data; struct input_dev *input_dev; struct resource *res; unsigned int max_keys; - int rev; int irq; int error; @@ -269,41 +296,30 @@ static int omap4_keypad_probe(struct platform_device *pdev) goto err_release_mem; } + pm_runtime_enable(&pdev->dev); /* * Enable clocks for the keypad module so that we can read * revision register. */ - pm_runtime_enable(&pdev->dev); error = pm_runtime_get_sync(&pdev->dev); if (error) { dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); - goto err_unmap; - } - rev = __raw_readl(keypad_data->base + OMAP4_KBD_REVISION); - rev &= 0x03 << 30; - rev >>= 30; - switch (rev) { - case KBD_REVISION_OMAP4: - keypad_data->reg_offset = 0x00; - keypad_data->irqreg_offset = 0x00; - break; - case KBD_REVISION_OMAP5: - keypad_data->reg_offset = 0x10; - keypad_data->irqreg_offset = 0x0c; - break; - default: - dev_err(&pdev->dev, - "Keypad reports unsupported revision %d", rev); - error = -EINVAL; - goto err_pm_put_sync; + pm_runtime_put_noidle(&pdev->dev); + } else { + error = omap4_keypad_check_revision(&pdev->dev, keypad_data); + if (!error) { + /* Ensure device does not raise interrupts */ + omap4_keypad_stop(keypad_data); + } + pm_runtime_put_sync(&pdev->dev); } /* input device allocation */ keypad_data->input = input_dev = input_allocate_device(); if (!input_dev) { error = -ENOMEM; - goto err_pm_put_sync; + goto err_pm_disable; } input_dev->name = pdev->name; @@ -349,28 +365,25 @@ static int omap4_keypad_probe(struct platform_device *pdev) goto err_free_keymap; } - device_init_wakeup(&pdev->dev, true); - pm_runtime_put_sync(&pdev->dev); - error = input_register_device(keypad_data->input); if (error < 0) { dev_err(&pdev->dev, "failed to register input device\n"); - goto err_pm_disable; + goto err_free_irq; } + device_init_wakeup(&pdev->dev, true); platform_set_drvdata(pdev, keypad_data); + return 0; -err_pm_disable: - pm_runtime_disable(&pdev->dev); +err_free_irq: free_irq(keypad_data->irq, keypad_data); err_free_keymap: kfree(keypad_data->keymap); err_free_input: input_free_device(input_dev); -err_pm_put_sync: - pm_runtime_put_sync(&pdev->dev); -err_unmap: +err_pm_disable: + pm_runtime_disable(&pdev->dev); iounmap(keypad_data->base); err_release_mem: release_mem_region(res->start, resource_size(res)); > platform_set_drvdata(pdev, keypad_data); > return 0; > > -err_pm_disable: > - pm_runtime_disable(&pdev->dev); > +err_free_irq: > free_irq(keypad_data->irq, keypad_data); > err_free_keymap: > kfree(keypad_data->keymap); > @@ -371,6 +371,7 @@ static int omap4_keypad_probe(struct platform_device *pdev) > err_pm_put_sync: > pm_runtime_put_sync(&pdev->dev); > err_unmap: > + pm_runtime_disable(&pdev->dev); > iounmap(keypad_data->base); > err_release_mem: > release_mem_region(res->start, resource_size(res)); > -- > 2.25.4 > Thanks.
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index d6c924032aaa..17abc8434af5 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -277,6 +277,7 @@ static int omap4_keypad_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); error = pm_runtime_get_sync(&pdev->dev); if (error) { + pm_runtime_put_noidle(&pdev->dev); dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); goto err_unmap; } @@ -349,20 +350,19 @@ static int omap4_keypad_probe(struct platform_device *pdev) goto err_free_keymap; } - device_init_wakeup(&pdev->dev, true); - pm_runtime_put_sync(&pdev->dev); - error = input_register_device(keypad_data->input); if (error < 0) { dev_err(&pdev->dev, "failed to register input device\n"); - goto err_pm_disable; + goto err_free_irq; } + device_init_wakeup(&pdev->dev, true); + pm_runtime_put_sync(&pdev->dev); + platform_set_drvdata(pdev, keypad_data); return 0; -err_pm_disable: - pm_runtime_disable(&pdev->dev); +err_free_irq: free_irq(keypad_data->irq, keypad_data); err_free_keymap: kfree(keypad_data->keymap); @@ -371,6 +371,7 @@ static int omap4_keypad_probe(struct platform_device *pdev) err_pm_put_sync: pm_runtime_put_sync(&pdev->dev); err_unmap: + pm_runtime_disable(&pdev->dev); iounmap(keypad_data->base); err_release_mem: release_mem_region(res->start, resource_size(res));
In omap4_keypad_probe, the patch fix several bugs. 1) pm_runtime_get_sync will increment pm usage counter even it failed. Forgetting to pm_runtime_put_noidle will result in reference leak. 2) In err_unmap, forget to disable runtime of device, pm_runtime_enable will increase power disable depth. Thus a pairing decrement is needed on the error handling path to keep it balanced. 3) In err_pm_disable, it will call pm_runtime_put_sync twice not one time. And we add the pm_runtime_put_noidle when pm_runtime_get_sync failed for 1). Move pm_runtime_disable to the err_unmap branch for 2). Move the input_register_device ahead for 3). Fixes: f77621cc640a7 ("Input: omap-keypad - dynamically handle register offsets") Fixes: 5ad567ffbaf20 ("Input: Input: omap4-keypad - wire up runtime PM handling") Signed-off-by: Zhang Qilong <zhangqilong3@huawei.com> --- drivers/input/keyboard/omap4-keypad.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)