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, 32 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/panthor/panthor_device.h b/drivers/gpu/drm/panthor/panthor_device.h index cf76a8abca76..a8c21a7eea05 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: Values to write to xxx_INT_MASK if active. */ 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; /** @mask_lock: protects modifications to _INT_MASK and @mask */ spinlock_t mask_lock; @@ -415,7 +426,7 @@ static irqreturn_t panthor_ ## __name ## _irq_raw_handler(int irq, void *data) \ guard(spinlock_irqsave)(&pirq->mask_lock); \ \ - if (atomic_read(&pirq->suspended)) \ + if (atomic_read(&pirq->state) == PANTHOR_IRQ_STATE_SUSPENDED) \ return IRQ_NONE; \ if (!gpu_read(ptdev, __reg_prefix ## _INT_STAT)) \ return IRQ_NONE; \ @@ -428,11 +439,14 @@ 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; \ u32 mask; \ \ scoped_guard(spinlock_irqsave, &pirq->mask_lock) { \ mask = pirq->mask; \ + atomic_cmpxchg(&pirq->state, PANTHOR_IRQ_STATE_ACTIVE, \ + PANTHOR_IRQ_STATE_PROCESSING); \ } \ \ while (true) { \ @@ -446,11 +460,14 @@ static irqreturn_t panthor_ ## __name ## _irq_threaded_handler(int irq, void *da } \ \ scoped_guard(spinlock_irqsave, &pirq->mask_lock) { \ - if (!atomic_read(&pirq->suspended)) { \ + 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); \ } \ } \ \ @@ -461,16 +478,17 @@ static inline void panthor_ ## __name ## _irq_suspend(struct panthor_irq *pirq) { \ scoped_guard(spinlock_irqsave, &pirq->mask_lock) { \ 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) \ { \ guard(spinlock_irqsave)(&pirq->mask_lock); \ \ - atomic_set(&pirq->suspended, false); \ + 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); \ } \ @@ -494,19 +512,25 @@ static int panthor_request_ ## __name ## _irq(struct panthor_device *ptdev, \ \ static inline void panthor_ ## __name ## _irq_enable_events(struct panthor_irq *pirq, u32 mask) \ { \ + enum panthor_irq_state state; \ + \ guard(spinlock_irqsave)(&pirq->mask_lock); \ \ pirq->mask |= mask; \ - if (!atomic_read(&pirq->suspended)) \ + state = atomic_read(&pirq->state); \ + if (state != PANTHOR_IRQ_STATE_SUSPENDED && state != PANTHOR_IRQ_STATE_SUSPENDING) \ gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \ } \ \ static inline void panthor_ ## __name ## _irq_disable_events(struct panthor_irq *pirq, u32 mask)\ { \ + enum panthor_irq_state state; \ + \ guard(spinlock_irqsave)(&pirq->mask_lock); \ \ pirq->mask &= ~mask; \ - if (!atomic_read(&pirq->suspended)) \ + state = atomic_read(&pirq->state); \ + if (state != PANTHOR_IRQ_STATE_SUSPENDED && state != PANTHOR_IRQ_STATE_SUSPENDING) \ gpu_write(pirq->ptdev, __reg_prefix ## _INT_MASK, pirq->mask); \ } -- 2.52.0
