aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
diff options
context:
space:
mode:
authorBjorn Andersson <bjorn.andersson@linaro.org>2021-06-11 10:00:03 -0700
committerRob Clark <robdclark@chromium.org>2021-06-23 07:33:55 -0700
commitc96348a8fbff90ef610b0323218e9d585683bdd2 (patch)
treed4d604dc8d3a0d9c1af7b19a3a894448b30af250 /drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
parentdrm/msm: devcoredump iommu fault support (diff)
downloadlinux-dev-c96348a8fbff90ef610b0323218e9d585683bdd2.tar.xz
linux-dev-c96348a8fbff90ef610b0323218e9d585683bdd2.zip
drm/msm/dpu: Avoid ABBA deadlock between IRQ modules
Handling of the interrupt callback lists is done in dpu_core_irq.c, under the "cb_lock" spinlock. When these operations results in the need for enableing or disabling the IRQ in the hardware the code jumps to dpu_hw_interrupts.c, which protects its operations with "irq_lock" spinlock. When an interrupt fires, dpu_hw_intr_dispatch_irq() inspects the hardware state while holding the "irq_lock" spinlock and jumps to dpu_core_irq_callback_handler() to invoke the registered handlers, which traverses the callback list under the "cb_lock" spinlock. As such, in the event that these happens concurrently we'll end up with a deadlock. Prior to '1c1e7763a6d4 ("drm/msm/dpu: simplify IRQ enabling/disabling")' the enable/disable of the hardware interrupt was done outside the "cb_lock" region, optimitically by using an atomic enable-counter for each interrupt and an warning print if someone changed the list between the atomic_read and the time the operation concluded. Rather than re-introducing the large array of atomics, this change embraces the fact that dpu_core_irq and dpu_hw_interrupts are deeply entangled and make them share the single "irq_lock". Following this step it's suggested that we squash the two parts into a single irq handling thing. Fixes: 1c1e7763a6d4 ("drm/msm/dpu: simplify IRQ enabling/disabling") Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Link: https://lore.kernel.org/r/20210611170003.3539059-1-bjorn.andersson@linaro.org Signed-off-by: Rob Clark <robdclark@chromium.org>
Diffstat (limited to 'drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h')
-rw-r--r--drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h20
1 files changed, 18 insertions, 2 deletions
diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
index 3c8b788d78e6..ac83c1159815 100644
--- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
+++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_interrupts.h
@@ -45,7 +45,7 @@ struct dpu_hw_intr_ops {
* @irq_idx: Lookup irq index return from irq_idx_lookup
* @return: 0 for success, otherwise failure
*/
- int (*enable_irq)(
+ int (*enable_irq_locked)(
struct dpu_hw_intr *intr,
int irq_idx);
@@ -55,7 +55,7 @@ struct dpu_hw_intr_ops {
* @irq_idx: Lookup irq index return from irq_idx_lookup
* @return: 0 for success, otherwise failure
*/
- int (*disable_irq)(
+ int (*disable_irq_locked)(
struct dpu_hw_intr *intr,
int irq_idx);
@@ -100,6 +100,22 @@ struct dpu_hw_intr_ops {
struct dpu_hw_intr *intr,
int irq_idx,
bool clear);
+
+ /**
+ * lock - take the IRQ lock
+ * @intr: HW interrupt handle
+ * @return: irq_flags for the taken spinlock
+ */
+ unsigned long (*lock)(
+ struct dpu_hw_intr *intr);
+
+ /**
+ * unlock - take the IRQ lock
+ * @intr: HW interrupt handle
+ * @irq_flags: the irq_flags returned from lock
+ */
+ void (*unlock)(
+ struct dpu_hw_intr *intr, unsigned long irq_flags);
};
/**