To deal with the threaded interrupt handler and a suspend action overlapping, the boolean panthor_irq::suspended is not sufficient.
Rework it into taking several different values depending on the current state, and check it and set it within the IRQ helper functions. Signed-off-by: Nicolas Frattaroli <[email protected]> --- drivers/gpu/drm/panthor/panthor_device.h | 40 +++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h index f35e52b9546a..424f6cd1a814 100644 --- a/drivers/gpu/drm/panthor/panthor_device.h +++ b/drivers/gpu/drm/panthor/panthor_device.h @@ -61,6 +61,17 @@ enum panthor_device_pm_state { PANTHOR_DEVICE_PM_STATE_SUSPENDING, }; +enum panthor_irq_state { + /** @PANTHOR_IRQ_STATE_ACTIVE: IRQ is active and ready to process events. */ + PANTHOR_IRQ_STATE_ACTIVE = 0, + /** @PANTHOR_IRQ_STATE_PROCESSING: IRQ is currently processing events. */ + PANTHOR_IRQ_STATE_PROCESSING, + /** @PANTHOR_IRQ_STATE_SUSPENDED: IRQ is suspended. */ + PANTHOR_IRQ_STATE_SUSPENDED, + /** @PANTHOR_IRQ_STATE_SUSPENDING: IRQ is being suspended. */ + PANTHOR_IRQ_STATE_SUSPENDING, +}; + /** * struct panthor_irq - IRQ data * @@ -76,8 +87,8 @@ struct panthor_irq { /** @mask: Current mask being applied to xxx_INT_MASK. */ u32 mask; - /** @suspended: Set to true when the IRQ is suspended. */ - atomic_t suspended; + /** @state: one of &enum panthor_irq_state reflecting the current state. */ + atomic_t state; }; /** @@ -409,8 +420,10 @@ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data) { \ struct panthor_irq *pirq = data; \ struct panthor_device *ptdev = pirq->ptdev; \ + enum panthor_irq_state state; \ \ - if (atomic_read(&pirq->suspended)) \ + state = atomic_read(&pirq->state); \ + if (state == PANTHOR_IRQ_STATE_SUSPENDED || state == PANTHOR_IRQ_STATE_SUSPENDING) \ return IRQ_NONE; \ if (!gpu_read(ptdev, __reg_prefix ## _INT_STAT)) \ return IRQ_NONE; \ @@ -423,8 +436,11 @@ static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *da { \ struct panthor_irq *pirq = data; \ struct panthor_device *ptdev = pirq->ptdev; \ + enum panthor_irq_state state; \ irqreturn_t ret = IRQ_NONE; \ \ + atomic_cmpxchg(&pirq->state, PANTHOR_IRQ_STATE_ACTIVE, PANTHOR_IRQ_STATE_PROCESSING); \ + \ while (true) { \ u32 status = gpu_read(ptdev, __reg_prefix ## _INT_RAWSTAT) & pirq->mask; \ \ @@ -435,8 +451,13 @@ static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *da ret = IRQ_HANDLED; \ } \ \ - if (!atomic_read(&pirq->suspended)) \ - gpu_write(ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \ + state = atomic_read(&pirq->state); \ + if (state != PANTHOR_IRQ_STATE_SUSPENDED && state != PANTHOR_IRQ_STATE_SUSPENDING) { \ + /* Only restore the bits that were used and are still enabled */ \ + gpu_write(ptdev, __reg_prefix ## _INT_MASK, \ + gpu_read(ptdev, __reg_prefix ## _INT_MASK) | (mask & pirq->mask)); \ + atomic_set(&pirq->state, PANTHOR_IRQ_STATE_ACTIVE); \ + } \ \ return ret; \ } \ @@ -445,16 +466,17 @@ static inline void panthor_ ## __name ## _irq_suspend(struct panthor_irq *pirq) { \ pirq->mask = 0; \ gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, 0); \ + atomic_set(&pirq->state, PANTHOR_IRQ_STATE_SUSPENDING); \ synchronize_irq(pirq->irq); \ - atomic_set(&pirq->suspended, true); \ + atomic_set(&pirq->state, PANTHOR_IRQ_STATE_SUSPENDED); \ } \ \ static inline void panthor_ ## __name ## _irq_resume(struct panthor_irq *pirq, u32 mask) \ { \ - atomic_set(&pirq->suspended, false); \ pirq->mask = mask; \ - gpu_write(pirq->ptdev, __reg_prefix ## _INT_CLEAR, mask); \ - gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, mask); \ + atomic_set(&pirq->state, PANTHOR_IRQ_STATE_ACTIVE); \ + gpu_write(pirq->ptdev, __reg_prefix ## _INT_CLEAR, pirq->mask); \ + gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \ } \ \ static int panthor_request_ ## __name ## _irq(struct panthor_device *ptdev, \ -- 2.52.0
