| From 18898df13e0c27d3505828c89754f07f0e1fc469 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 19 Jan 2021 11:12:08 -0500 |
| Subject: pwm: rockchip: Eliminate potential race condition when probing |
| |
| From: Simon South <simon@simonsouth.net> |
| |
| [ Upstream commit d21ba5d6217bd5a6a696678385906ed1994b380b ] |
| |
| Commit 48cf973cae33 ("pwm: rockchip: Avoid glitches on already running |
| PWMs") introduced a potential race condition in rockchip_pwm_probe(): A |
| consumer could enable an inactive PWM, or disable a running one, between |
| rockchip_pwm_probe() registering the device via pwmchip_add() and checking |
| whether it is enabled (to determine whether it was started by a |
| bootloader). This could result in a device's PWM clock being either enabled |
| once more than necessary, potentially causing it to continue running when |
| no longer needed, or disabled once more than necessary, producing a warning |
| from the kernel. |
| |
| Eliminate these possibilities by modifying rockchip_pwm_probe() so it |
| checks whether a device is enabled before registering it rather than after. |
| |
| Fixes: 48cf973cae33 ("pwm: rockchip: Avoid glitches on already running PWMs") |
| Reported-by: Trent Piepho <tpiepho@gmail.com> |
| Signed-off-by: Simon South <simon@simonsouth.net> |
| Signed-off-by: Thierry Reding <thierry.reding@gmail.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/pwm/pwm-rockchip.c | 9 ++++++--- |
| 1 file changed, 6 insertions(+), 3 deletions(-) |
| |
| diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c |
| index ede027fbf2bb4..3b8da7b0091b1 100644 |
| --- a/drivers/pwm/pwm-rockchip.c |
| +++ b/drivers/pwm/pwm-rockchip.c |
| @@ -289,6 +289,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev) |
| struct rockchip_pwm_chip *pc; |
| struct resource *r; |
| u32 enable_conf, ctrl; |
| + bool enabled; |
| int ret, count; |
| |
| id = of_match_device(rockchip_pwm_dt_ids, &pdev->dev); |
| @@ -351,6 +352,10 @@ static int rockchip_pwm_probe(struct platform_device *pdev) |
| pc->chip.of_pwm_n_cells = 3; |
| } |
| |
| + enable_conf = pc->data->enable_conf; |
| + ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl); |
| + enabled = (ctrl & enable_conf) == enable_conf; |
| + |
| ret = pwmchip_add(&pc->chip); |
| if (ret < 0) { |
| dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret); |
| @@ -358,9 +363,7 @@ static int rockchip_pwm_probe(struct platform_device *pdev) |
| } |
| |
| /* Keep the PWM clk enabled if the PWM appears to be up and running. */ |
| - enable_conf = pc->data->enable_conf; |
| - ctrl = readl_relaxed(pc->base + pc->data->regs.ctrl); |
| - if ((ctrl & enable_conf) != enable_conf) |
| + if (!enabled) |
| clk_disable(pc->clk); |
| |
| clk_disable(pc->pclk); |
| -- |
| 2.27.0 |
| |