Thank you for your contribution! Sashiko AI review found 3 potential issue(s) 
to consider:

New issues:
- [Low] Final Result: The clock framework logs '(null)' during enablement 
failures because the .id fields in the clk_bulk_data array are not initialized.

Pre-existing issues:
- [High] Final Result: Hardware accesses on explicitly disabled clocks trigger 
synchronous external aborts. Ignored return values from pm_runtime_get_sync() 
and malidp_runtime_pm_resume() combine with the new clock rollback to guarantee 
an APB bus hang.
- [High] Final Result: Missing synchronize_irq() in the runtime suspend path 
allows active shared IRQ handlers to crash the system by accessing powered-down 
hardware.
--

commit 049d634e1eb44e14ba4f4fc2612f50ff9b67236e
Author: Gustavo Kenji Mendonça Kaneko <[email protected]>

drm/arm/malidp: use clk_bulk API in runtime PM resume and suspend

This commit converts the Mali DP driver's runtime PM resume and suspend
paths to use the clk_bulk API. It ensures that clk_bulk_prepare_enable()
return values are checked during resume, rolling back any successfully
enabled clocks if a failure occurs.

Link: https://patch.msgid.link/[email protected]

> diff --git a/drivers/gpu/drm/arm/malidp_drv.c 
> b/drivers/gpu/drm/arm/malidp_drv.c
> index bc5f5e9798c32..2bf4a647e4b28 100644
> --- a/drivers/gpu/drm/arm/malidp_drv.c
> +++ b/drivers/gpu/drm/arm/malidp_drv.c
> @@ -669,6 +669,11 @@ static int malidp_runtime_pm_suspend(struct device *dev)
>       struct drm_device *drm = dev_get_drvdata(dev);
>       struct malidp_drm *malidp = drm_to_malidp(drm);
>       struct malidp_hw_device *hwdev = malidp->dev;
> +     struct clk_bulk_data clks[] = {
> +             { .clk = hwdev->pclk },
> +             { .clk = hwdev->aclk },
> +             { .clk = hwdev->mclk },
> +     };
>  
>       /* we can only suspend if the hardware is in config mode */
>       WARN_ON(!hwdev->hw->in_config_mode(hwdev));
> @@ -676,9 +681,7 @@ static int malidp_runtime_pm_suspend(struct device *dev)
>       malidp_se_irq_fini(hwdev);
>       malidp_de_irq_fini(hwdev);
>       hwdev->pm_suspended = true;
> -     clk_disable_unprepare(hwdev->mclk);
> -     clk_disable_unprepare(hwdev->aclk);
> -     clk_disable_unprepare(hwdev->pclk);
> +     clk_bulk_disable_unprepare(ARRAY_SIZE(clks), clks);

[Severity: High]
This is a pre-existing issue, but is there a risk of a shared interrupt
firing exactly as the device enters runtime suspend?

The omission of synchronize_irq() before clk_bulk_disable_unprepare() allows
concurrently executing handlers to read unclocked registers. For example, in
drivers/gpu/drm/arm/malidp_hw.c:

malidp_de_irq() {
    if (hwdev->pm_suspended)
        return IRQ_NONE;
    ...
}

Could we add a call to synchronize_irq() before disabling the clocks so
active shared IRQ handlers do not crash the system by accessing powered-down
hardware?

>  
>       return 0;
>  }
> @@ -688,10 +691,17 @@ static int malidp_runtime_pm_resume(struct device *dev)
>       struct drm_device *drm = dev_get_drvdata(dev);
>       struct malidp_drm *malidp = drm_to_malidp(drm);
>       struct malidp_hw_device *hwdev = malidp->dev;
> +     struct clk_bulk_data clks[] = {
> +             { .clk = hwdev->pclk },
> +             { .clk = hwdev->aclk },
> +             { .clk = hwdev->mclk },
> +     };

[Severity: Low]
Does this array initialization cause the clock framework to log (null)
during enablement failures?

If a clock fails to enable during PM resume, the uninitialized .id fields
in the local clk_bulk_data array are used by pr_err(), which results in
useless error logging instead of the clock name.

Should we add the corresponding .id string values to this array?

> +     int err;
> +
> +     err = clk_bulk_prepare_enable(ARRAY_SIZE(clks), clks);
> +     if (err)
> +             return err;

[Severity: High]
This is a pre-existing issue, but can the new clock rollback here cause an
APB bus hang on failure?

If a clock enablement fails during malidp_runtime_pm_resume(), the newly
introduced clk_bulk_prepare_enable() rolls back and disables all clocks on
partial failure.

However, callers blindly proceed and ignore the return values from
pm_runtime_get_sync() and malidp_runtime_pm_resume(), meaning they will
read and write unclocked MMIO registers. For example, in
drivers/gpu/drm/arm/malidp_drv.c:

malidp_atomic_commit_tail() {
    pm_runtime_get_sync(drm->dev);
    ...
    atomic_set(&malidp->config_valid, MALIDP_CONFIG_START);
    malidp->dev->hw->set_config_valid(malidp->dev, 0);
}

Are we able to check the return value of pm_runtime_get_sync() in these
callers to prevent a synchronous external abort when the resume path fails?

>  
> -     clk_prepare_enable(hwdev->pclk);
> -     clk_prepare_enable(hwdev->aclk);
> -     clk_prepare_enable(hwdev->mclk);
>       hwdev->pm_suspended = false;
>       malidp_de_irq_hw_init(hwdev);
>       malidp_se_irq_hw_init(hwdev);

-- 
Sashiko AI review · 
https://sashiko.dev/#/patchset/[email protected]?part=1

Reply via email to