On Tue, 28 Nov 2023 13:45:10 +0100 AngeloGioacchino Del Regno <angelogioacchino.delregno@xxxxxxxxxxxxx> wrote: > To make sure that we don't unintentionally perform any unclocked and/or > unpowered R/W operation on GPU registers, before turning off clocks and > regulators we must make sure that no GPU, JOB or MMU ISR execution is > pending: doing that required to add a mechanism to synchronize the > interrupts on suspend. > > Add functions panfrost_{gpu,job,mmu}_suspend_irq() which will perform > interrupts masking and ISR execution synchronization, and then call > those in the panfrost_device_runtime_suspend() handler in the exact > sequence of job (may require mmu!) -> mmu -> gpu. > > As a side note, JOB and MMU suspend_irq functions needed some special > treatment: as their interrupt handlers will unmask interrupts, it was > necessary to add a bitmap for "is_suspending" which is used to address > the possible corner case of unintentional IRQ unmasking because of ISR > execution after a call to synchronize_irq(). > > Of course, unmasking the interrupts is being done as part of the reset > happening during runtime_resume(): since we're anyway resuming all of > GPU, JOB, MMU, the only additional action is to zero out the newly > introduced `is_suspending` bitmap directly in the resume handler, as > to avoid adding panfrost_{job,mmu}_resume_irq() function just for > clearing own bits, especially because it currently makes way more sense > to just zero out the bitmap. > > Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@xxxxxxxxxxxxx> > --- > drivers/gpu/drm/panfrost/panfrost_device.c | 4 ++++ > drivers/gpu/drm/panfrost/panfrost_device.h | 7 +++++++ > drivers/gpu/drm/panfrost/panfrost_gpu.c | 7 +++++++ > drivers/gpu/drm/panfrost/panfrost_gpu.h | 1 + > drivers/gpu/drm/panfrost/panfrost_job.c | 18 +++++++++++++++--- > drivers/gpu/drm/panfrost/panfrost_job.h | 1 + > drivers/gpu/drm/panfrost/panfrost_mmu.c | 17 ++++++++++++++--- > drivers/gpu/drm/panfrost/panfrost_mmu.h | 1 + > 8 files changed, 50 insertions(+), 6 deletions(-) > > diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c > index c90ad5ee34e7..ed34aa55a7da 100644 > --- a/drivers/gpu/drm/panfrost/panfrost_device.c > +++ b/drivers/gpu/drm/panfrost/panfrost_device.c > @@ -407,6 +407,7 @@ static int panfrost_device_runtime_resume(struct device *dev) > { > struct panfrost_device *pfdev = dev_get_drvdata(dev); > > + bitmap_zero(pfdev->is_suspending, PANFROST_COMP_BIT_MAX); I would let each sub-block clear their bit in the reset path, since that's where the IRQs are effectively unmasked. > panfrost_device_reset(pfdev); > panfrost_devfreq_resume(pfdev); > > @@ -421,6 +422,9 @@ static int panfrost_device_runtime_suspend(struct device *dev) > return -EBUSY; > > panfrost_devfreq_suspend(pfdev); > + panfrost_job_suspend_irq(pfdev); > + panfrost_mmu_suspend_irq(pfdev); > + panfrost_gpu_suspend_irq(pfdev); > panfrost_gpu_power_off(pfdev); > > return 0; > diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h > index 54a8aad54259..29f89f2d3679 100644 > --- a/drivers/gpu/drm/panfrost/panfrost_device.h > +++ b/drivers/gpu/drm/panfrost/panfrost_device.h > @@ -25,6 +25,12 @@ struct panfrost_perfcnt; > #define NUM_JOB_SLOTS 3 > #define MAX_PM_DOMAINS 5 > > +enum panfrost_drv_comp_bits { > + PANFROST_COMP_BIT_MMU, > + PANFROST_COMP_BIT_JOB, > + PANFROST_COMP_BIT_MAX > +}; > + > /** > * enum panfrost_gpu_pm - Supported kernel power management features > * @GPU_PM_CLK_DIS: Allow disabling clocks during system suspend > @@ -109,6 +115,7 @@ struct panfrost_device { > > struct panfrost_features features; > const struct panfrost_compatible *comp; > + DECLARE_BITMAP(is_suspending, PANFROST_COMP_BIT_MAX); nit: Maybe s/is_suspending/suspended_irqs/, given the state remains until the device is resumed.