* [PATCH v4 0/3] drm/panfrost: Fix poweroff and sync IRQs for suspend
@ 2023-12-04 11:42 AngeloGioacchino Del Regno
2023-12-04 11:42 ` [PATCH v4 1/3] drm/panfrost: Ignore core_mask for poweroff and disable PWRTRANS irq AngeloGioacchino Del Regno
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: AngeloGioacchino Del Regno @ 2023-12-04 11:42 UTC (permalink / raw)
To: boris.brezillon
Cc: robh, steven.price, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, angelogioacchino.delregno, dri-devel,
linux-kernel, kernel, m.szyprowski, krzysztof.kozlowski
Changes in v4:
- Added checks for is_suspended bits in hardirqs
- Added GPU suspended bit (and handling of it)
- Reordered panfrost_drv_comp_bits entries
- Commit description fixes
Changes in v3:
- Removed useless GPU_INT_CLEAR write in suspend path
- Changed to clear suspend bits in job/mmu reset path
This series contains a fast fix for the basic GPU poweroff functionality
and goes further by implementing interrupt masking and synchronization
before suspend.
For more information, please look at the conversation at [1], which
explains the regression seen with the poweroff commit and the initial
approaches taken to solve that.
Cheers!
[1]: https://lore.kernel.org/all/20231123095320.41433-1-angelogioacchino.delregno@collabora.com/
AngeloGioacchino Del Regno (3):
drm/panfrost: Ignore core_mask for poweroff and disable PWRTRANS irq
drm/panfrost: Add gpu_irq, mmu_irq to struct panfrost_device
drm/panfrost: Synchronize and disable interrupts before powering off
drivers/gpu/drm/panfrost/panfrost_device.c | 3 ++
drivers/gpu/drm/panfrost/panfrost_device.h | 10 ++++++
drivers/gpu/drm/panfrost/panfrost_gpu.c | 40 ++++++++++++++++------
drivers/gpu/drm/panfrost/panfrost_gpu.h | 1 +
drivers/gpu/drm/panfrost/panfrost_job.c | 26 +++++++++++---
drivers/gpu/drm/panfrost/panfrost_job.h | 1 +
drivers/gpu/drm/panfrost/panfrost_mmu.c | 32 ++++++++++++-----
drivers/gpu/drm/panfrost/panfrost_mmu.h | 1 +
8 files changed, 91 insertions(+), 23 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 1/3] drm/panfrost: Ignore core_mask for poweroff and disable PWRTRANS irq
2023-12-04 11:42 [PATCH v4 0/3] drm/panfrost: Fix poweroff and sync IRQs for suspend AngeloGioacchino Del Regno
@ 2023-12-04 11:42 ` AngeloGioacchino Del Regno
2023-12-04 16:05 ` Marek Szyprowski
2023-12-04 11:42 ` [PATCH v4 2/3] drm/panfrost: Add gpu_irq, mmu_irq to struct panfrost_device AngeloGioacchino Del Regno
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: AngeloGioacchino Del Regno @ 2023-12-04 11:42 UTC (permalink / raw)
To: boris.brezillon
Cc: robh, steven.price, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, angelogioacchino.delregno, dri-devel,
linux-kernel, kernel, m.szyprowski, krzysztof.kozlowski
Some SoCs may be equipped with a GPU containing two core groups
and this is exactly the case of Samsung's Exynos 5422 featuring
an ARM Mali-T628 MP6 GPU: the support for this GPU in Panfrost
is partial, as this driver currently supports using only one
core group and that's reflected on all parts of it, including
the power on (and power off, previously to this patch) function.
The issue with this is that even though executing the soft reset
operation should power off all cores unconditionally, on at least
one platform we're seeing a crash that seems to be happening due
to an interrupt firing which may be because we are calling power
transition only on the first core group, leaving the second one
unchanged, or because ISR execution was pending before entering
the panfrost_gpu_power_off() function and executed after powering
off the GPU cores, or all of the above.
Finally, solve this by:
- Avoid to enable the power transition interrupt on reset; and
- Ignoring the core_mask and ask the GPU to poweroff both core groups
Fixes: 22aa1a209018 ("drm/panfrost: Really power off GPU cores in panfrost_gpu_power_off()")
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_gpu.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c
index 09f5e1563ebd..bd41617c5e4b 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c
@@ -78,7 +78,12 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev)
}
gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_MASK_ALL);
- gpu_write(pfdev, GPU_INT_MASK, GPU_IRQ_MASK_ALL);
+
+ /* Only enable the interrupts we care about */
+ gpu_write(pfdev, GPU_INT_MASK,
+ GPU_IRQ_MASK_ERROR |
+ GPU_IRQ_PERFCNT_SAMPLE_COMPLETED |
+ GPU_IRQ_CLEAN_CACHES_COMPLETED);
/*
* All in-flight jobs should have released their cycle
@@ -425,11 +430,10 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev)
void panfrost_gpu_power_off(struct panfrost_device *pfdev)
{
- u64 core_mask = panfrost_get_core_mask(pfdev);
int ret;
u32 val;
- gpu_write(pfdev, SHADER_PWROFF_LO, pfdev->features.shader_present & core_mask);
+ gpu_write(pfdev, SHADER_PWROFF_LO, pfdev->features.shader_present);
ret = readl_relaxed_poll_timeout(pfdev->iomem + SHADER_PWRTRANS_LO,
val, !val, 1, 1000);
if (ret)
@@ -441,7 +445,7 @@ void panfrost_gpu_power_off(struct panfrost_device *pfdev)
if (ret)
dev_err(pfdev->dev, "tiler power transition timeout");
- gpu_write(pfdev, L2_PWROFF_LO, pfdev->features.l2_present & core_mask);
+ gpu_write(pfdev, L2_PWROFF_LO, pfdev->features.l2_present);
ret = readl_poll_timeout(pfdev->iomem + L2_PWRTRANS_LO,
val, !val, 0, 1000);
if (ret)
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 2/3] drm/panfrost: Add gpu_irq, mmu_irq to struct panfrost_device
2023-12-04 11:42 [PATCH v4 0/3] drm/panfrost: Fix poweroff and sync IRQs for suspend AngeloGioacchino Del Regno
2023-12-04 11:42 ` [PATCH v4 1/3] drm/panfrost: Ignore core_mask for poweroff and disable PWRTRANS irq AngeloGioacchino Del Regno
@ 2023-12-04 11:42 ` AngeloGioacchino Del Regno
2023-12-04 16:05 ` Marek Szyprowski
2023-12-04 11:42 ` [PATCH v4 3/3] drm/panfrost: Synchronize and disable interrupts before powering off AngeloGioacchino Del Regno
2023-12-05 10:42 ` [PATCH v4 0/3] drm/panfrost: Fix poweroff and sync IRQs for suspend Boris Brezillon
3 siblings, 1 reply; 10+ messages in thread
From: AngeloGioacchino Del Regno @ 2023-12-04 11:42 UTC (permalink / raw)
To: boris.brezillon
Cc: robh, steven.price, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, angelogioacchino.delregno, dri-devel,
linux-kernel, kernel, m.szyprowski, krzysztof.kozlowski
In preparation for adding a IRQ synchronization mechanism for PM suspend,
add gpu_irq and mmu_irq variables to struct panfrost_device and change
functions panfrost_gpu_init() and panfrost_mmu_init() to use those.
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_device.h | 2 ++
drivers/gpu/drm/panfrost/panfrost_gpu.c | 10 +++++-----
drivers/gpu/drm/panfrost/panfrost_mmu.c | 10 +++++-----
3 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.h b/drivers/gpu/drm/panfrost/panfrost_device.h
index 0fc558db6bfd..54a8aad54259 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -94,6 +94,8 @@ struct panfrost_device {
struct device *dev;
struct drm_device *ddev;
struct platform_device *pdev;
+ int gpu_irq;
+ int mmu_irq;
void __iomem *iomem;
struct clk *clock;
diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c
index bd41617c5e4b..7adc4441fa14 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c
@@ -454,7 +454,7 @@ void panfrost_gpu_power_off(struct panfrost_device *pfdev)
int panfrost_gpu_init(struct panfrost_device *pfdev)
{
- int err, irq;
+ int err;
err = panfrost_gpu_soft_reset(pfdev);
if (err)
@@ -469,11 +469,11 @@ int panfrost_gpu_init(struct panfrost_device *pfdev)
dma_set_max_seg_size(pfdev->dev, UINT_MAX);
- irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu");
- if (irq < 0)
- return irq;
+ pfdev->gpu_irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu");
+ if (pfdev->gpu_irq < 0)
+ return pfdev->gpu_irq;
- err = devm_request_irq(pfdev->dev, irq, panfrost_gpu_irq_handler,
+ err = devm_request_irq(pfdev->dev, pfdev->gpu_irq, panfrost_gpu_irq_handler,
IRQF_SHARED, KBUILD_MODNAME "-gpu", pfdev);
if (err) {
dev_err(pfdev->dev, "failed to request gpu irq");
diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
index 846dd697c410..ac4296c1e54b 100644
--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
@@ -753,13 +753,13 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data)
int panfrost_mmu_init(struct panfrost_device *pfdev)
{
- int err, irq;
+ int err;
- irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "mmu");
- if (irq < 0)
- return irq;
+ pfdev->mmu_irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "mmu");
+ if (pfdev->mmu_irq < 0)
+ return pfdev->mmu_irq;
- err = devm_request_threaded_irq(pfdev->dev, irq,
+ err = devm_request_threaded_irq(pfdev->dev, pfdev->mmu_irq,
panfrost_mmu_irq_handler,
panfrost_mmu_irq_handler_thread,
IRQF_SHARED, KBUILD_MODNAME "-mmu",
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 3/3] drm/panfrost: Synchronize and disable interrupts before powering off
2023-12-04 11:42 [PATCH v4 0/3] drm/panfrost: Fix poweroff and sync IRQs for suspend AngeloGioacchino Del Regno
2023-12-04 11:42 ` [PATCH v4 1/3] drm/panfrost: Ignore core_mask for poweroff and disable PWRTRANS irq AngeloGioacchino Del Regno
2023-12-04 11:42 ` [PATCH v4 2/3] drm/panfrost: Add gpu_irq, mmu_irq to struct panfrost_device AngeloGioacchino Del Regno
@ 2023-12-04 11:42 ` AngeloGioacchino Del Regno
2023-12-04 13:52 ` Boris Brezillon
` (2 more replies)
2023-12-05 10:42 ` [PATCH v4 0/3] drm/panfrost: Fix poweroff and sync IRQs for suspend Boris Brezillon
3 siblings, 3 replies; 10+ messages in thread
From: AngeloGioacchino Del Regno @ 2023-12-04 11:42 UTC (permalink / raw)
To: boris.brezillon
Cc: robh, steven.price, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, angelogioacchino.delregno, dri-devel,
linux-kernel, kernel, m.szyprowski, krzysztof.kozlowski
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 requires 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 an `is_suspended` bitmap which is used to address the
possible corner case of unintentional IRQ unmasking because of ISR
execution after a call to synchronize_irq().
At resume, clear each is_suspended bit in the reset path of JOB/MMU
to allow unmasking the interrupts.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/panfrost/panfrost_device.c | 3 +++
drivers/gpu/drm/panfrost/panfrost_device.h | 8 +++++++
drivers/gpu/drm/panfrost/panfrost_gpu.c | 18 +++++++++++++--
drivers/gpu/drm/panfrost/panfrost_gpu.h | 1 +
drivers/gpu/drm/panfrost/panfrost_job.c | 26 ++++++++++++++++++----
drivers/gpu/drm/panfrost/panfrost_job.h | 1 +
drivers/gpu/drm/panfrost/panfrost_mmu.c | 22 +++++++++++++++---
drivers/gpu/drm/panfrost/panfrost_mmu.h | 1 +
8 files changed, 71 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
index c90ad5ee34e7..a45e4addcc19 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.c
+++ b/drivers/gpu/drm/panfrost/panfrost_device.c
@@ -421,6 +421,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..62f7e3527385 100644
--- a/drivers/gpu/drm/panfrost/panfrost_device.h
+++ b/drivers/gpu/drm/panfrost/panfrost_device.h
@@ -25,6 +25,13 @@ struct panfrost_perfcnt;
#define NUM_JOB_SLOTS 3
#define MAX_PM_DOMAINS 5
+enum panfrost_drv_comp_bits {
+ PANFROST_COMP_BIT_GPU,
+ PANFROST_COMP_BIT_JOB,
+ PANFROST_COMP_BIT_MMU,
+ 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 +116,7 @@ struct panfrost_device {
struct panfrost_features features;
const struct panfrost_compatible *comp;
+ DECLARE_BITMAP(is_suspended, PANFROST_COMP_BIT_MAX);
spinlock_t as_lock;
unsigned long as_in_use_mask;
diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c
index 7adc4441fa14..9063ce254642 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gpu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c
@@ -22,9 +22,13 @@
static irqreturn_t panfrost_gpu_irq_handler(int irq, void *data)
{
struct panfrost_device *pfdev = data;
- u32 state = gpu_read(pfdev, GPU_INT_STAT);
- u32 fault_status = gpu_read(pfdev, GPU_FAULT_STATUS);
+ u32 fault_status, state;
+ if (test_bit(PANFROST_COMP_BIT_GPU, pfdev->is_suspended))
+ return IRQ_NONE;
+
+ fault_status = gpu_read(pfdev, GPU_FAULT_STATUS);
+ state = gpu_read(pfdev, GPU_INT_STAT);
if (!state)
return IRQ_NONE;
@@ -61,6 +65,8 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev)
gpu_write(pfdev, GPU_INT_MASK, 0);
gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
+ clear_bit(PANFROST_COMP_BIT_GPU, pfdev->is_suspended);
+
gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET);
ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT,
val, val & GPU_IRQ_RESET_COMPLETED, 10, 10000);
@@ -452,6 +458,14 @@ void panfrost_gpu_power_off(struct panfrost_device *pfdev)
dev_err(pfdev->dev, "l2 power transition timeout");
}
+void panfrost_gpu_suspend_irq(struct panfrost_device *pfdev)
+{
+ set_bit(PANFROST_COMP_BIT_GPU, pfdev->is_suspended);
+
+ gpu_write(pfdev, GPU_INT_MASK, 0);
+ synchronize_irq(pfdev->gpu_irq);
+}
+
int panfrost_gpu_init(struct panfrost_device *pfdev)
{
int err;
diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.h b/drivers/gpu/drm/panfrost/panfrost_gpu.h
index 876fdad9f721..d841b86504ea 100644
--- a/drivers/gpu/drm/panfrost/panfrost_gpu.h
+++ b/drivers/gpu/drm/panfrost/panfrost_gpu.h
@@ -15,6 +15,7 @@ u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev);
int panfrost_gpu_soft_reset(struct panfrost_device *pfdev);
void panfrost_gpu_power_on(struct panfrost_device *pfdev);
void panfrost_gpu_power_off(struct panfrost_device *pfdev);
+void panfrost_gpu_suspend_irq(struct panfrost_device *pfdev);
void panfrost_cycle_counter_get(struct panfrost_device *pfdev);
void panfrost_cycle_counter_put(struct panfrost_device *pfdev);
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
index f9446e197428..0c2dbf6ef2a5 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.c
+++ b/drivers/gpu/drm/panfrost/panfrost_job.c
@@ -405,6 +405,8 @@ void panfrost_job_enable_interrupts(struct panfrost_device *pfdev)
int j;
u32 irq_mask = 0;
+ clear_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended);
+
for (j = 0; j < NUM_JOB_SLOTS; j++) {
irq_mask |= MK_JS_MASK(j);
}
@@ -413,6 +415,14 @@ void panfrost_job_enable_interrupts(struct panfrost_device *pfdev)
job_write(pfdev, JOB_INT_MASK, irq_mask);
}
+void panfrost_job_suspend_irq(struct panfrost_device *pfdev)
+{
+ set_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended);
+
+ job_write(pfdev, JOB_INT_MASK, 0);
+ synchronize_irq(pfdev->js->irq);
+}
+
static void panfrost_job_handle_err(struct panfrost_device *pfdev,
struct panfrost_job *job,
unsigned int js)
@@ -792,17 +802,25 @@ static irqreturn_t panfrost_job_irq_handler_thread(int irq, void *data)
struct panfrost_device *pfdev = data;
panfrost_job_handle_irqs(pfdev);
- job_write(pfdev, JOB_INT_MASK,
- GENMASK(16 + NUM_JOB_SLOTS - 1, 16) |
- GENMASK(NUM_JOB_SLOTS - 1, 0));
+
+ /* Enable interrupts only if we're not about to get suspended */
+ if (!test_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended))
+ job_write(pfdev, JOB_INT_MASK,
+ GENMASK(16 + NUM_JOB_SLOTS - 1, 16) |
+ GENMASK(NUM_JOB_SLOTS - 1, 0));
+
return IRQ_HANDLED;
}
static irqreturn_t panfrost_job_irq_handler(int irq, void *data)
{
struct panfrost_device *pfdev = data;
- u32 status = job_read(pfdev, JOB_INT_STAT);
+ u32 status;
+
+ if (test_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended))
+ return IRQ_NONE;
+ status = job_read(pfdev, JOB_INT_STAT);
if (!status)
return IRQ_NONE;
diff --git a/drivers/gpu/drm/panfrost/panfrost_job.h b/drivers/gpu/drm/panfrost/panfrost_job.h
index 17ff808dba07..ec581b97852b 100644
--- a/drivers/gpu/drm/panfrost/panfrost_job.h
+++ b/drivers/gpu/drm/panfrost/panfrost_job.h
@@ -47,6 +47,7 @@ int panfrost_job_get_slot(struct panfrost_job *job);
int panfrost_job_push(struct panfrost_job *job);
void panfrost_job_put(struct panfrost_job *job);
void panfrost_job_enable_interrupts(struct panfrost_device *pfdev);
+void panfrost_job_suspend_irq(struct panfrost_device *pfdev);
int panfrost_job_is_idle(struct panfrost_device *pfdev);
#endif
diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
index ac4296c1e54b..f38385fe76bb 100644
--- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
@@ -231,6 +231,8 @@ void panfrost_mmu_reset(struct panfrost_device *pfdev)
{
struct panfrost_mmu *mmu, *mmu_tmp;
+ clear_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended);
+
spin_lock(&pfdev->as_lock);
pfdev->as_alloc_mask = 0;
@@ -670,6 +672,9 @@ static irqreturn_t panfrost_mmu_irq_handler(int irq, void *data)
{
struct panfrost_device *pfdev = data;
+ if (test_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended))
+ return IRQ_NONE;
+
if (!mmu_read(pfdev, MMU_INT_STAT))
return IRQ_NONE;
@@ -744,9 +749,12 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data)
status = mmu_read(pfdev, MMU_INT_RAWSTAT) & ~pfdev->as_faulty_mask;
}
- spin_lock(&pfdev->as_lock);
- mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask);
- spin_unlock(&pfdev->as_lock);
+ /* Enable interrupts only if we're not about to get suspended */
+ if (!test_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended)) {
+ spin_lock(&pfdev->as_lock);
+ mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask);
+ spin_unlock(&pfdev->as_lock);
+ }
return IRQ_HANDLED;
};
@@ -777,3 +785,11 @@ void panfrost_mmu_fini(struct panfrost_device *pfdev)
{
mmu_write(pfdev, MMU_INT_MASK, 0);
}
+
+void panfrost_mmu_suspend_irq(struct panfrost_device *pfdev)
+{
+ set_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended);
+
+ mmu_write(pfdev, MMU_INT_MASK, 0);
+ synchronize_irq(pfdev->mmu_irq);
+}
diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.h b/drivers/gpu/drm/panfrost/panfrost_mmu.h
index cc2a0d307feb..022a9a74a114 100644
--- a/drivers/gpu/drm/panfrost/panfrost_mmu.h
+++ b/drivers/gpu/drm/panfrost/panfrost_mmu.h
@@ -14,6 +14,7 @@ void panfrost_mmu_unmap(struct panfrost_gem_mapping *mapping);
int panfrost_mmu_init(struct panfrost_device *pfdev);
void panfrost_mmu_fini(struct panfrost_device *pfdev);
void panfrost_mmu_reset(struct panfrost_device *pfdev);
+void panfrost_mmu_suspend_irq(struct panfrost_device *pfdev);
u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu);
void panfrost_mmu_as_put(struct panfrost_device *pfdev, struct panfrost_mmu *mmu);
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v4 3/3] drm/panfrost: Synchronize and disable interrupts before powering off
2023-12-04 11:42 ` [PATCH v4 3/3] drm/panfrost: Synchronize and disable interrupts before powering off AngeloGioacchino Del Regno
@ 2023-12-04 13:52 ` Boris Brezillon
2023-12-04 16:05 ` Marek Szyprowski
2023-12-04 16:34 ` Steven Price
2 siblings, 0 replies; 10+ messages in thread
From: Boris Brezillon @ 2023-12-04 13:52 UTC (permalink / raw)
To: AngeloGioacchino Del Regno
Cc: robh, steven.price, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, dri-devel, linux-kernel, kernel, m.szyprowski,
krzysztof.kozlowski
On Mon, 4 Dec 2023 12:42:15 +0100
AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
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 requires 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 an `is_suspended` bitmap which is used to address the
> possible corner case of unintentional IRQ unmasking because of ISR
> execution after a call to synchronize_irq().
>
> At resume, clear each is_suspended bit in the reset path of JOB/MMU
> to allow unmasking the interrupts.
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
> ---
> drivers/gpu/drm/panfrost/panfrost_device.c | 3 +++
> drivers/gpu/drm/panfrost/panfrost_device.h | 8 +++++++
> drivers/gpu/drm/panfrost/panfrost_gpu.c | 18 +++++++++++++--
> drivers/gpu/drm/panfrost/panfrost_gpu.h | 1 +
> drivers/gpu/drm/panfrost/panfrost_job.c | 26 ++++++++++++++++++----
> drivers/gpu/drm/panfrost/panfrost_job.h | 1 +
> drivers/gpu/drm/panfrost/panfrost_mmu.c | 22 +++++++++++++++---
> drivers/gpu/drm/panfrost/panfrost_mmu.h | 1 +
> 8 files changed, 71 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
> index c90ad5ee34e7..a45e4addcc19 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_device.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_device.c
> @@ -421,6 +421,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..62f7e3527385 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_device.h
> +++ b/drivers/gpu/drm/panfrost/panfrost_device.h
> @@ -25,6 +25,13 @@ struct panfrost_perfcnt;
> #define NUM_JOB_SLOTS 3
> #define MAX_PM_DOMAINS 5
>
> +enum panfrost_drv_comp_bits {
> + PANFROST_COMP_BIT_GPU,
> + PANFROST_COMP_BIT_JOB,
> + PANFROST_COMP_BIT_MMU,
> + 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 +116,7 @@ struct panfrost_device {
>
> struct panfrost_features features;
> const struct panfrost_compatible *comp;
> + DECLARE_BITMAP(is_suspended, PANFROST_COMP_BIT_MAX);
>
> spinlock_t as_lock;
> unsigned long as_in_use_mask;
> diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c
> index 7adc4441fa14..9063ce254642 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c
> @@ -22,9 +22,13 @@
> static irqreturn_t panfrost_gpu_irq_handler(int irq, void *data)
> {
> struct panfrost_device *pfdev = data;
> - u32 state = gpu_read(pfdev, GPU_INT_STAT);
> - u32 fault_status = gpu_read(pfdev, GPU_FAULT_STATUS);
> + u32 fault_status, state;
>
> + if (test_bit(PANFROST_COMP_BIT_GPU, pfdev->is_suspended))
> + return IRQ_NONE;
> +
> + fault_status = gpu_read(pfdev, GPU_FAULT_STATUS);
> + state = gpu_read(pfdev, GPU_INT_STAT);
> if (!state)
> return IRQ_NONE;
>
> @@ -61,6 +65,8 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev)
> gpu_write(pfdev, GPU_INT_MASK, 0);
> gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
>
> + clear_bit(PANFROST_COMP_BIT_GPU, pfdev->is_suspended);
> +
> gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET);
> ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT,
> val, val & GPU_IRQ_RESET_COMPLETED, 10, 10000);
> @@ -452,6 +458,14 @@ void panfrost_gpu_power_off(struct panfrost_device *pfdev)
> dev_err(pfdev->dev, "l2 power transition timeout");
> }
>
> +void panfrost_gpu_suspend_irq(struct panfrost_device *pfdev)
> +{
> + set_bit(PANFROST_COMP_BIT_GPU, pfdev->is_suspended);
> +
> + gpu_write(pfdev, GPU_INT_MASK, 0);
> + synchronize_irq(pfdev->gpu_irq);
> +}
> +
> int panfrost_gpu_init(struct panfrost_device *pfdev)
> {
> int err;
> diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.h b/drivers/gpu/drm/panfrost/panfrost_gpu.h
> index 876fdad9f721..d841b86504ea 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_gpu.h
> +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.h
> @@ -15,6 +15,7 @@ u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev);
> int panfrost_gpu_soft_reset(struct panfrost_device *pfdev);
> void panfrost_gpu_power_on(struct panfrost_device *pfdev);
> void panfrost_gpu_power_off(struct panfrost_device *pfdev);
> +void panfrost_gpu_suspend_irq(struct panfrost_device *pfdev);
>
> void panfrost_cycle_counter_get(struct panfrost_device *pfdev);
> void panfrost_cycle_counter_put(struct panfrost_device *pfdev);
> diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
> index f9446e197428..0c2dbf6ef2a5 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_job.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_job.c
> @@ -405,6 +405,8 @@ void panfrost_job_enable_interrupts(struct panfrost_device *pfdev)
> int j;
> u32 irq_mask = 0;
>
> + clear_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended);
> +
> for (j = 0; j < NUM_JOB_SLOTS; j++) {
> irq_mask |= MK_JS_MASK(j);
> }
> @@ -413,6 +415,14 @@ void panfrost_job_enable_interrupts(struct panfrost_device *pfdev)
> job_write(pfdev, JOB_INT_MASK, irq_mask);
> }
>
> +void panfrost_job_suspend_irq(struct panfrost_device *pfdev)
> +{
> + set_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended);
> +
> + job_write(pfdev, JOB_INT_MASK, 0);
> + synchronize_irq(pfdev->js->irq);
> +}
> +
> static void panfrost_job_handle_err(struct panfrost_device *pfdev,
> struct panfrost_job *job,
> unsigned int js)
> @@ -792,17 +802,25 @@ static irqreturn_t panfrost_job_irq_handler_thread(int irq, void *data)
> struct panfrost_device *pfdev = data;
>
> panfrost_job_handle_irqs(pfdev);
> - job_write(pfdev, JOB_INT_MASK,
> - GENMASK(16 + NUM_JOB_SLOTS - 1, 16) |
> - GENMASK(NUM_JOB_SLOTS - 1, 0));
> +
> + /* Enable interrupts only if we're not about to get suspended */
> + if (!test_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended))
> + job_write(pfdev, JOB_INT_MASK,
> + GENMASK(16 + NUM_JOB_SLOTS - 1, 16) |
> + GENMASK(NUM_JOB_SLOTS - 1, 0));
> +
> return IRQ_HANDLED;
> }
>
> static irqreturn_t panfrost_job_irq_handler(int irq, void *data)
> {
> struct panfrost_device *pfdev = data;
> - u32 status = job_read(pfdev, JOB_INT_STAT);
> + u32 status;
> +
> + if (test_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended))
> + return IRQ_NONE;
>
> + status = job_read(pfdev, JOB_INT_STAT);
> if (!status)
> return IRQ_NONE;
>
> diff --git a/drivers/gpu/drm/panfrost/panfrost_job.h b/drivers/gpu/drm/panfrost/panfrost_job.h
> index 17ff808dba07..ec581b97852b 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_job.h
> +++ b/drivers/gpu/drm/panfrost/panfrost_job.h
> @@ -47,6 +47,7 @@ int panfrost_job_get_slot(struct panfrost_job *job);
> int panfrost_job_push(struct panfrost_job *job);
> void panfrost_job_put(struct panfrost_job *job);
> void panfrost_job_enable_interrupts(struct panfrost_device *pfdev);
> +void panfrost_job_suspend_irq(struct panfrost_device *pfdev);
> int panfrost_job_is_idle(struct panfrost_device *pfdev);
>
> #endif
> diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
> index ac4296c1e54b..f38385fe76bb 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
> @@ -231,6 +231,8 @@ void panfrost_mmu_reset(struct panfrost_device *pfdev)
> {
> struct panfrost_mmu *mmu, *mmu_tmp;
>
> + clear_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended);
> +
> spin_lock(&pfdev->as_lock);
>
> pfdev->as_alloc_mask = 0;
> @@ -670,6 +672,9 @@ static irqreturn_t panfrost_mmu_irq_handler(int irq, void *data)
> {
> struct panfrost_device *pfdev = data;
>
> + if (test_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended))
> + return IRQ_NONE;
> +
> if (!mmu_read(pfdev, MMU_INT_STAT))
> return IRQ_NONE;
>
> @@ -744,9 +749,12 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data)
> status = mmu_read(pfdev, MMU_INT_RAWSTAT) & ~pfdev->as_faulty_mask;
> }
>
> - spin_lock(&pfdev->as_lock);
> - mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask);
> - spin_unlock(&pfdev->as_lock);
> + /* Enable interrupts only if we're not about to get suspended */
> + if (!test_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended)) {
> + spin_lock(&pfdev->as_lock);
> + mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask);
> + spin_unlock(&pfdev->as_lock);
> + }
>
> return IRQ_HANDLED;
> };
> @@ -777,3 +785,11 @@ void panfrost_mmu_fini(struct panfrost_device *pfdev)
> {
> mmu_write(pfdev, MMU_INT_MASK, 0);
> }
> +
> +void panfrost_mmu_suspend_irq(struct panfrost_device *pfdev)
> +{
> + set_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended);
> +
> + mmu_write(pfdev, MMU_INT_MASK, 0);
> + synchronize_irq(pfdev->mmu_irq);
> +}
> diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.h b/drivers/gpu/drm/panfrost/panfrost_mmu.h
> index cc2a0d307feb..022a9a74a114 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_mmu.h
> +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.h
> @@ -14,6 +14,7 @@ void panfrost_mmu_unmap(struct panfrost_gem_mapping *mapping);
> int panfrost_mmu_init(struct panfrost_device *pfdev);
> void panfrost_mmu_fini(struct panfrost_device *pfdev);
> void panfrost_mmu_reset(struct panfrost_device *pfdev);
> +void panfrost_mmu_suspend_irq(struct panfrost_device *pfdev);
>
> u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu);
> void panfrost_mmu_as_put(struct panfrost_device *pfdev, struct panfrost_mmu *mmu);
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 1/3] drm/panfrost: Ignore core_mask for poweroff and disable PWRTRANS irq
2023-12-04 11:42 ` [PATCH v4 1/3] drm/panfrost: Ignore core_mask for poweroff and disable PWRTRANS irq AngeloGioacchino Del Regno
@ 2023-12-04 16:05 ` Marek Szyprowski
0 siblings, 0 replies; 10+ messages in thread
From: Marek Szyprowski @ 2023-12-04 16:05 UTC (permalink / raw)
To: AngeloGioacchino Del Regno, boris.brezillon
Cc: robh, steven.price, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, dri-devel, linux-kernel, kernel,
krzysztof.kozlowski
On 04.12.2023 12:42, AngeloGioacchino Del Regno wrote:
> Some SoCs may be equipped with a GPU containing two core groups
> and this is exactly the case of Samsung's Exynos 5422 featuring
> an ARM Mali-T628 MP6 GPU: the support for this GPU in Panfrost
> is partial, as this driver currently supports using only one
> core group and that's reflected on all parts of it, including
> the power on (and power off, previously to this patch) function.
>
> The issue with this is that even though executing the soft reset
> operation should power off all cores unconditionally, on at least
> one platform we're seeing a crash that seems to be happening due
> to an interrupt firing which may be because we are calling power
> transition only on the first core group, leaving the second one
> unchanged, or because ISR execution was pending before entering
> the panfrost_gpu_power_off() function and executed after powering
> off the GPU cores, or all of the above.
>
> Finally, solve this by:
> - Avoid to enable the power transition interrupt on reset; and
> - Ignoring the core_mask and ask the GPU to poweroff both core groups
>
> Fixes: 22aa1a209018 ("drm/panfrost: Really power off GPU cores in panfrost_gpu_power_off()")
> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
> Reviewed-by: Steven Price <steven.price@arm.com>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
> drivers/gpu/drm/panfrost/panfrost_gpu.c | 12 ++++++++----
> 1 file changed, 8 insertions(+), 4 deletions(-)
>
> ...
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 2/3] drm/panfrost: Add gpu_irq, mmu_irq to struct panfrost_device
2023-12-04 11:42 ` [PATCH v4 2/3] drm/panfrost: Add gpu_irq, mmu_irq to struct panfrost_device AngeloGioacchino Del Regno
@ 2023-12-04 16:05 ` Marek Szyprowski
0 siblings, 0 replies; 10+ messages in thread
From: Marek Szyprowski @ 2023-12-04 16:05 UTC (permalink / raw)
To: AngeloGioacchino Del Regno, boris.brezillon
Cc: robh, steven.price, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, dri-devel, linux-kernel, kernel,
krzysztof.kozlowski
On 04.12.2023 12:42, AngeloGioacchino Del Regno wrote:
> In preparation for adding a IRQ synchronization mechanism for PM suspend,
> add gpu_irq and mmu_irq variables to struct panfrost_device and change
> functions panfrost_gpu_init() and panfrost_mmu_init() to use those.
>
> Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
> Reviewed-by: Steven Price <steven.price@arm.com>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
> drivers/gpu/drm/panfrost/panfrost_device.h | 2 ++
> drivers/gpu/drm/panfrost/panfrost_gpu.c | 10 +++++-----
> drivers/gpu/drm/panfrost/panfrost_mmu.c | 10 +++++-----
> 3 files changed, 12 insertions(+), 10 deletions(-)
>
> ...
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 3/3] drm/panfrost: Synchronize and disable interrupts before powering off
2023-12-04 11:42 ` [PATCH v4 3/3] drm/panfrost: Synchronize and disable interrupts before powering off AngeloGioacchino Del Regno
2023-12-04 13:52 ` Boris Brezillon
@ 2023-12-04 16:05 ` Marek Szyprowski
2023-12-04 16:34 ` Steven Price
2 siblings, 0 replies; 10+ messages in thread
From: Marek Szyprowski @ 2023-12-04 16:05 UTC (permalink / raw)
To: AngeloGioacchino Del Regno, boris.brezillon
Cc: robh, steven.price, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, dri-devel, linux-kernel, kernel,
krzysztof.kozlowski
On 04.12.2023 12:42, AngeloGioacchino Del Regno 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 requires 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 an `is_suspended` bitmap which is used to address the
> possible corner case of unintentional IRQ unmasking because of ISR
> execution after a call to synchronize_irq().
>
> At resume, clear each is_suspended bit in the reset path of JOB/MMU
> to allow unmasking the interrupts.
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
> ---
> drivers/gpu/drm/panfrost/panfrost_device.c | 3 +++
> drivers/gpu/drm/panfrost/panfrost_device.h | 8 +++++++
> drivers/gpu/drm/panfrost/panfrost_gpu.c | 18 +++++++++++++--
> drivers/gpu/drm/panfrost/panfrost_gpu.h | 1 +
> drivers/gpu/drm/panfrost/panfrost_job.c | 26 ++++++++++++++++++----
> drivers/gpu/drm/panfrost/panfrost_job.h | 1 +
> drivers/gpu/drm/panfrost/panfrost_mmu.c | 22 +++++++++++++++---
> drivers/gpu/drm/panfrost/panfrost_mmu.h | 1 +
> 8 files changed, 71 insertions(+), 9 deletions(-)
>
> ...
Best regards
--
Marek Szyprowski, PhD
Samsung R&D Institute Poland
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 3/3] drm/panfrost: Synchronize and disable interrupts before powering off
2023-12-04 11:42 ` [PATCH v4 3/3] drm/panfrost: Synchronize and disable interrupts before powering off AngeloGioacchino Del Regno
2023-12-04 13:52 ` Boris Brezillon
2023-12-04 16:05 ` Marek Szyprowski
@ 2023-12-04 16:34 ` Steven Price
2 siblings, 0 replies; 10+ messages in thread
From: Steven Price @ 2023-12-04 16:34 UTC (permalink / raw)
To: AngeloGioacchino Del Regno, boris.brezillon
Cc: robh, maarten.lankhorst, mripard, tzimmermann, airlied, daniel,
dri-devel, linux-kernel, kernel, m.szyprowski,
krzysztof.kozlowski
On 04/12/2023 11:42, AngeloGioacchino Del Regno 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 requires 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 an `is_suspended` bitmap which is used to address the
> possible corner case of unintentional IRQ unmasking because of ISR
> execution after a call to synchronize_irq().
>
> At resume, clear each is_suspended bit in the reset path of JOB/MMU
> to allow unmasking the interrupts.
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: Steven Price <steven.price@arm.com>
Thanks,
Steve
> ---
> drivers/gpu/drm/panfrost/panfrost_device.c | 3 +++
> drivers/gpu/drm/panfrost/panfrost_device.h | 8 +++++++
> drivers/gpu/drm/panfrost/panfrost_gpu.c | 18 +++++++++++++--
> drivers/gpu/drm/panfrost/panfrost_gpu.h | 1 +
> drivers/gpu/drm/panfrost/panfrost_job.c | 26 ++++++++++++++++++----
> drivers/gpu/drm/panfrost/panfrost_job.h | 1 +
> drivers/gpu/drm/panfrost/panfrost_mmu.c | 22 +++++++++++++++---
> drivers/gpu/drm/panfrost/panfrost_mmu.h | 1 +
> 8 files changed, 71 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/panfrost/panfrost_device.c b/drivers/gpu/drm/panfrost/panfrost_device.c
> index c90ad5ee34e7..a45e4addcc19 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_device.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_device.c
> @@ -421,6 +421,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..62f7e3527385 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_device.h
> +++ b/drivers/gpu/drm/panfrost/panfrost_device.h
> @@ -25,6 +25,13 @@ struct panfrost_perfcnt;
> #define NUM_JOB_SLOTS 3
> #define MAX_PM_DOMAINS 5
>
> +enum panfrost_drv_comp_bits {
> + PANFROST_COMP_BIT_GPU,
> + PANFROST_COMP_BIT_JOB,
> + PANFROST_COMP_BIT_MMU,
> + 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 +116,7 @@ struct panfrost_device {
>
> struct panfrost_features features;
> const struct panfrost_compatible *comp;
> + DECLARE_BITMAP(is_suspended, PANFROST_COMP_BIT_MAX);
>
> spinlock_t as_lock;
> unsigned long as_in_use_mask;
> diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.c b/drivers/gpu/drm/panfrost/panfrost_gpu.c
> index 7adc4441fa14..9063ce254642 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_gpu.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.c
> @@ -22,9 +22,13 @@
> static irqreturn_t panfrost_gpu_irq_handler(int irq, void *data)
> {
> struct panfrost_device *pfdev = data;
> - u32 state = gpu_read(pfdev, GPU_INT_STAT);
> - u32 fault_status = gpu_read(pfdev, GPU_FAULT_STATUS);
> + u32 fault_status, state;
>
> + if (test_bit(PANFROST_COMP_BIT_GPU, pfdev->is_suspended))
> + return IRQ_NONE;
> +
> + fault_status = gpu_read(pfdev, GPU_FAULT_STATUS);
> + state = gpu_read(pfdev, GPU_INT_STAT);
> if (!state)
> return IRQ_NONE;
>
> @@ -61,6 +65,8 @@ int panfrost_gpu_soft_reset(struct panfrost_device *pfdev)
> gpu_write(pfdev, GPU_INT_MASK, 0);
> gpu_write(pfdev, GPU_INT_CLEAR, GPU_IRQ_RESET_COMPLETED);
>
> + clear_bit(PANFROST_COMP_BIT_GPU, pfdev->is_suspended);
> +
> gpu_write(pfdev, GPU_CMD, GPU_CMD_SOFT_RESET);
> ret = readl_relaxed_poll_timeout(pfdev->iomem + GPU_INT_RAWSTAT,
> val, val & GPU_IRQ_RESET_COMPLETED, 10, 10000);
> @@ -452,6 +458,14 @@ void panfrost_gpu_power_off(struct panfrost_device *pfdev)
> dev_err(pfdev->dev, "l2 power transition timeout");
> }
>
> +void panfrost_gpu_suspend_irq(struct panfrost_device *pfdev)
> +{
> + set_bit(PANFROST_COMP_BIT_GPU, pfdev->is_suspended);
> +
> + gpu_write(pfdev, GPU_INT_MASK, 0);
> + synchronize_irq(pfdev->gpu_irq);
> +}
> +
> int panfrost_gpu_init(struct panfrost_device *pfdev)
> {
> int err;
> diff --git a/drivers/gpu/drm/panfrost/panfrost_gpu.h b/drivers/gpu/drm/panfrost/panfrost_gpu.h
> index 876fdad9f721..d841b86504ea 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_gpu.h
> +++ b/drivers/gpu/drm/panfrost/panfrost_gpu.h
> @@ -15,6 +15,7 @@ u32 panfrost_gpu_get_latest_flush_id(struct panfrost_device *pfdev);
> int panfrost_gpu_soft_reset(struct panfrost_device *pfdev);
> void panfrost_gpu_power_on(struct panfrost_device *pfdev);
> void panfrost_gpu_power_off(struct panfrost_device *pfdev);
> +void panfrost_gpu_suspend_irq(struct panfrost_device *pfdev);
>
> void panfrost_cycle_counter_get(struct panfrost_device *pfdev);
> void panfrost_cycle_counter_put(struct panfrost_device *pfdev);
> diff --git a/drivers/gpu/drm/panfrost/panfrost_job.c b/drivers/gpu/drm/panfrost/panfrost_job.c
> index f9446e197428..0c2dbf6ef2a5 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_job.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_job.c
> @@ -405,6 +405,8 @@ void panfrost_job_enable_interrupts(struct panfrost_device *pfdev)
> int j;
> u32 irq_mask = 0;
>
> + clear_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended);
> +
> for (j = 0; j < NUM_JOB_SLOTS; j++) {
> irq_mask |= MK_JS_MASK(j);
> }
> @@ -413,6 +415,14 @@ void panfrost_job_enable_interrupts(struct panfrost_device *pfdev)
> job_write(pfdev, JOB_INT_MASK, irq_mask);
> }
>
> +void panfrost_job_suspend_irq(struct panfrost_device *pfdev)
> +{
> + set_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended);
> +
> + job_write(pfdev, JOB_INT_MASK, 0);
> + synchronize_irq(pfdev->js->irq);
> +}
> +
> static void panfrost_job_handle_err(struct panfrost_device *pfdev,
> struct panfrost_job *job,
> unsigned int js)
> @@ -792,17 +802,25 @@ static irqreturn_t panfrost_job_irq_handler_thread(int irq, void *data)
> struct panfrost_device *pfdev = data;
>
> panfrost_job_handle_irqs(pfdev);
> - job_write(pfdev, JOB_INT_MASK,
> - GENMASK(16 + NUM_JOB_SLOTS - 1, 16) |
> - GENMASK(NUM_JOB_SLOTS - 1, 0));
> +
> + /* Enable interrupts only if we're not about to get suspended */
> + if (!test_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended))
> + job_write(pfdev, JOB_INT_MASK,
> + GENMASK(16 + NUM_JOB_SLOTS - 1, 16) |
> + GENMASK(NUM_JOB_SLOTS - 1, 0));
> +
> return IRQ_HANDLED;
> }
>
> static irqreturn_t panfrost_job_irq_handler(int irq, void *data)
> {
> struct panfrost_device *pfdev = data;
> - u32 status = job_read(pfdev, JOB_INT_STAT);
> + u32 status;
> +
> + if (test_bit(PANFROST_COMP_BIT_JOB, pfdev->is_suspended))
> + return IRQ_NONE;
>
> + status = job_read(pfdev, JOB_INT_STAT);
> if (!status)
> return IRQ_NONE;
>
> diff --git a/drivers/gpu/drm/panfrost/panfrost_job.h b/drivers/gpu/drm/panfrost/panfrost_job.h
> index 17ff808dba07..ec581b97852b 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_job.h
> +++ b/drivers/gpu/drm/panfrost/panfrost_job.h
> @@ -47,6 +47,7 @@ int panfrost_job_get_slot(struct panfrost_job *job);
> int panfrost_job_push(struct panfrost_job *job);
> void panfrost_job_put(struct panfrost_job *job);
> void panfrost_job_enable_interrupts(struct panfrost_device *pfdev);
> +void panfrost_job_suspend_irq(struct panfrost_device *pfdev);
> int panfrost_job_is_idle(struct panfrost_device *pfdev);
>
> #endif
> diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.c b/drivers/gpu/drm/panfrost/panfrost_mmu.c
> index ac4296c1e54b..f38385fe76bb 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_mmu.c
> +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.c
> @@ -231,6 +231,8 @@ void panfrost_mmu_reset(struct panfrost_device *pfdev)
> {
> struct panfrost_mmu *mmu, *mmu_tmp;
>
> + clear_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended);
> +
> spin_lock(&pfdev->as_lock);
>
> pfdev->as_alloc_mask = 0;
> @@ -670,6 +672,9 @@ static irqreturn_t panfrost_mmu_irq_handler(int irq, void *data)
> {
> struct panfrost_device *pfdev = data;
>
> + if (test_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended))
> + return IRQ_NONE;
> +
> if (!mmu_read(pfdev, MMU_INT_STAT))
> return IRQ_NONE;
>
> @@ -744,9 +749,12 @@ static irqreturn_t panfrost_mmu_irq_handler_thread(int irq, void *data)
> status = mmu_read(pfdev, MMU_INT_RAWSTAT) & ~pfdev->as_faulty_mask;
> }
>
> - spin_lock(&pfdev->as_lock);
> - mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask);
> - spin_unlock(&pfdev->as_lock);
> + /* Enable interrupts only if we're not about to get suspended */
> + if (!test_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended)) {
> + spin_lock(&pfdev->as_lock);
> + mmu_write(pfdev, MMU_INT_MASK, ~pfdev->as_faulty_mask);
> + spin_unlock(&pfdev->as_lock);
> + }
>
> return IRQ_HANDLED;
> };
> @@ -777,3 +785,11 @@ void panfrost_mmu_fini(struct panfrost_device *pfdev)
> {
> mmu_write(pfdev, MMU_INT_MASK, 0);
> }
> +
> +void panfrost_mmu_suspend_irq(struct panfrost_device *pfdev)
> +{
> + set_bit(PANFROST_COMP_BIT_MMU, pfdev->is_suspended);
> +
> + mmu_write(pfdev, MMU_INT_MASK, 0);
> + synchronize_irq(pfdev->mmu_irq);
> +}
> diff --git a/drivers/gpu/drm/panfrost/panfrost_mmu.h b/drivers/gpu/drm/panfrost/panfrost_mmu.h
> index cc2a0d307feb..022a9a74a114 100644
> --- a/drivers/gpu/drm/panfrost/panfrost_mmu.h
> +++ b/drivers/gpu/drm/panfrost/panfrost_mmu.h
> @@ -14,6 +14,7 @@ void panfrost_mmu_unmap(struct panfrost_gem_mapping *mapping);
> int panfrost_mmu_init(struct panfrost_device *pfdev);
> void panfrost_mmu_fini(struct panfrost_device *pfdev);
> void panfrost_mmu_reset(struct panfrost_device *pfdev);
> +void panfrost_mmu_suspend_irq(struct panfrost_device *pfdev);
>
> u32 panfrost_mmu_as_get(struct panfrost_device *pfdev, struct panfrost_mmu *mmu);
> void panfrost_mmu_as_put(struct panfrost_device *pfdev, struct panfrost_mmu *mmu);
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 0/3] drm/panfrost: Fix poweroff and sync IRQs for suspend
2023-12-04 11:42 [PATCH v4 0/3] drm/panfrost: Fix poweroff and sync IRQs for suspend AngeloGioacchino Del Regno
` (2 preceding siblings ...)
2023-12-04 11:42 ` [PATCH v4 3/3] drm/panfrost: Synchronize and disable interrupts before powering off AngeloGioacchino Del Regno
@ 2023-12-05 10:42 ` Boris Brezillon
3 siblings, 0 replies; 10+ messages in thread
From: Boris Brezillon @ 2023-12-05 10:42 UTC (permalink / raw)
To: AngeloGioacchino Del Regno
Cc: robh, steven.price, maarten.lankhorst, mripard, tzimmermann,
airlied, daniel, dri-devel, linux-kernel, kernel, m.szyprowski,
krzysztof.kozlowski
On Mon, 4 Dec 2023 12:42:12 +0100
AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
wrote:
> Changes in v4:
> - Added checks for is_suspended bits in hardirqs
> - Added GPU suspended bit (and handling of it)
> - Reordered panfrost_drv_comp_bits entries
> - Commit description fixes
>
> Changes in v3:
> - Removed useless GPU_INT_CLEAR write in suspend path
> - Changed to clear suspend bits in job/mmu reset path
>
> This series contains a fast fix for the basic GPU poweroff functionality
> and goes further by implementing interrupt masking and synchronization
> before suspend.
>
> For more information, please look at the conversation at [1], which
> explains the regression seen with the poweroff commit and the initial
> approaches taken to solve that.
>
> Cheers!
>
> [1]: https://lore.kernel.org/all/20231123095320.41433-1-angelogioacchino.delregno@collabora.com/
>
> AngeloGioacchino Del Regno (3):
> drm/panfrost: Ignore core_mask for poweroff and disable PWRTRANS irq
> drm/panfrost: Add gpu_irq, mmu_irq to struct panfrost_device
> drm/panfrost: Synchronize and disable interrupts before powering off
Queued to drm-misc-next.
Thanks,
Boris
>
> drivers/gpu/drm/panfrost/panfrost_device.c | 3 ++
> drivers/gpu/drm/panfrost/panfrost_device.h | 10 ++++++
> drivers/gpu/drm/panfrost/panfrost_gpu.c | 40 ++++++++++++++++------
> drivers/gpu/drm/panfrost/panfrost_gpu.h | 1 +
> drivers/gpu/drm/panfrost/panfrost_job.c | 26 +++++++++++---
> drivers/gpu/drm/panfrost/panfrost_job.h | 1 +
> drivers/gpu/drm/panfrost/panfrost_mmu.c | 32 ++++++++++++-----
> drivers/gpu/drm/panfrost/panfrost_mmu.h | 1 +
> 8 files changed, 91 insertions(+), 23 deletions(-)
>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2023-12-05 10:42 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-12-04 11:42 [PATCH v4 0/3] drm/panfrost: Fix poweroff and sync IRQs for suspend AngeloGioacchino Del Regno
2023-12-04 11:42 ` [PATCH v4 1/3] drm/panfrost: Ignore core_mask for poweroff and disable PWRTRANS irq AngeloGioacchino Del Regno
2023-12-04 16:05 ` Marek Szyprowski
2023-12-04 11:42 ` [PATCH v4 2/3] drm/panfrost: Add gpu_irq, mmu_irq to struct panfrost_device AngeloGioacchino Del Regno
2023-12-04 16:05 ` Marek Szyprowski
2023-12-04 11:42 ` [PATCH v4 3/3] drm/panfrost: Synchronize and disable interrupts before powering off AngeloGioacchino Del Regno
2023-12-04 13:52 ` Boris Brezillon
2023-12-04 16:05 ` Marek Szyprowski
2023-12-04 16:34 ` Steven Price
2023-12-05 10:42 ` [PATCH v4 0/3] drm/panfrost: Fix poweroff and sync IRQs for suspend Boris Brezillon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox