Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4abbc98 authored by Xu Yang's avatar Xu Yang Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/sde: add interrupt enabling state to fix deadlock



Add one more state of interrupt enabling as transition state
when enable the interrupt. Change fixes the deadlock issue
when client tries to enable the interrupt and meanwhile there
is interrupt callback function happenes.

CRs-Fixed: 2316684
Change-Id: I2954db910df1e63d5882e7980f01b9219647e731
Signed-off-by: default avatarXu Yang <yangxu@codeaurora.org>
parent 38ec7e0c
Loading
Loading
Loading
Loading
+23 −15
Original line number Diff line number Diff line
@@ -1862,24 +1862,29 @@ int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en,

	node = container_of(ad_irq, struct sde_crtc_irq_info, irq);

	/* deregister AD irq */
	if (!en) {
		spin_lock_irqsave(&node->state_lock, flags);
		if (node->state == IRQ_ENABLED) {
			node->state = IRQ_DISABLING;
			spin_unlock_irqrestore(&node->state_lock, flags);
			ret = sde_core_irq_disable(kms, &irq_idx, 1);
			if (ret)
			spin_lock_irqsave(&node->state_lock, flags);
			if (ret) {
				DRM_ERROR("disable irq %d error %d\n",
					irq_idx, ret);
			else
				node->state = IRQ_NOINIT;
				node->state = IRQ_ENABLED;
			} else {
			node->state = IRQ_NOINIT;
				node->state = IRQ_DISABLED;
			}
		}
		spin_unlock_irqrestore(&node->state_lock, flags);

		sde_core_irq_unregister_callback(kms, irq_idx, ad_irq);
		ret = 0;
		goto exit;
	}

	/* register AD irq */
	ad_irq->arg = crtc;
	ad_irq->func = sde_cp_ad_interrupt_cb;
	ret = sde_core_irq_register_callback(kms, irq_idx, ad_irq);
@@ -1889,11 +1894,15 @@ int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en,
	}

	spin_lock_irqsave(&node->state_lock, flags);
	if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) {
	if (node->state == IRQ_DISABLED) {
		node->state = IRQ_ENABLING;
		spin_unlock_irqrestore(&node->state_lock, flags);
		ret = sde_core_irq_enable(kms, &irq_idx, 1);
		spin_lock_irqsave(&node->state_lock, flags);
		if (ret) {
			DRM_ERROR("enable irq %d error %d\n", irq_idx, ret);
			sde_core_irq_unregister_callback(kms, irq_idx, ad_irq);
			node->state = IRQ_DISABLED;
		} else {
			node->state = IRQ_ENABLED;
		}
@@ -2138,15 +2147,10 @@ int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en,
					irq_idx, ret);
				node->state = IRQ_ENABLED;
			} else {
				node->state = IRQ_NOINIT;
				node->state = IRQ_DISABLED;
			}
			spin_unlock_irqrestore(&node->state_lock, flags);
		} else if (node->state == IRQ_DISABLED) {
			node->state = IRQ_NOINIT;
			spin_unlock_irqrestore(&node->state_lock, flags);
		} else {
			spin_unlock_irqrestore(&node->state_lock, flags);
		}
		spin_unlock_irqrestore(&node->state_lock, flags);

		sde_core_irq_unregister_callback(kms, irq_idx, hist_irq);
		goto exit;
@@ -2162,12 +2166,16 @@ int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en,
	}

	spin_lock_irqsave(&node->state_lock, flags);
	if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) {
	if (node->state == IRQ_DISABLED) {
		node->state = IRQ_ENABLING;
		spin_unlock_irqrestore(&node->state_lock, flags);
		ret = sde_core_irq_enable(kms, &irq_idx, 1);
		spin_lock_irqsave(&node->state_lock, flags);
		if (ret) {
			DRM_ERROR("enable irq %d error %d\n", irq_idx, ret);
			sde_core_irq_unregister_callback(kms,
				irq_idx, hist_irq);
			node->state = IRQ_DISABLED;
		} else {
			node->state = IRQ_ENABLED;
		}
+1 −1
Original line number Diff line number Diff line
@@ -6216,7 +6216,7 @@ static int _sde_crtc_event_enable(struct sde_kms *kms,
			INIT_LIST_HEAD(&node->list);
			node->func = custom_events[i].func;
			node->event = event;
			node->state = IRQ_NOINIT;
			node->state = IRQ_DISABLED;
			spin_lock_init(&node->state_lock);
			break;
		}
+1 −1
Original line number Diff line number Diff line
@@ -430,7 +430,7 @@ struct sde_crtc_state {
};

enum sde_crtc_irq_state {
	IRQ_NOINIT,
	IRQ_ENABLING,
	IRQ_ENABLED,
	IRQ_DISABLING,
	IRQ_DISABLED,