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

Commit 0b779a34 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/sde: fix deadlock between IRQ lock and node state lock" into dev/msm-4.14-display

parents d6556e75 c4837308
Loading
Loading
Loading
Loading
+40 −68
Original line number Diff line number Diff line
@@ -1726,10 +1726,9 @@ int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en,
		goto exit;
	}

	node = _sde_cp_get_intr_node(DRM_EVENT_AD_BACKLIGHT, crtc);
	node = container_of(ad_irq, struct sde_crtc_irq_info, irq);

	if (!en) {
		if (node) {
		spin_lock_irqsave(&node->state_lock, flags);
		if (node->state == IRQ_ENABLED) {
			ret = sde_core_irq_disable(kms, &irq_idx, 1);
@@ -1742,9 +1741,6 @@ int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en,
			node->state = IRQ_NOINIT;
		}
		spin_unlock_irqrestore(&node->state_lock, flags);
		} else {
			DRM_ERROR("failed to get node from crtc event list\n");
		}
		sde_core_irq_unregister_callback(kms, irq_idx, ad_irq);
		ret = 0;
		goto exit;
@@ -1758,32 +1754,18 @@ int sde_cp_ad_interrupt(struct drm_crtc *crtc_drm, bool en,
		goto exit;
	}

	if (node) {
		/* device resume or resume from IPC cases */
	spin_lock_irqsave(&node->state_lock, flags);
	if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) {
		ret = sde_core_irq_enable(kms, &irq_idx, 1);
		if (ret) {
				DRM_ERROR("enable irq %d error %d\n",
					irq_idx, ret);
				sde_core_irq_unregister_callback(kms,
					irq_idx, ad_irq);
			DRM_ERROR("enable irq %d error %d\n", irq_idx, ret);
			sde_core_irq_unregister_callback(kms, irq_idx, ad_irq);
		} else {
			node->state = IRQ_ENABLED;
		}
	}
	spin_unlock_irqrestore(&node->state_lock, flags);
	} else {
		/* request from userspace to register the event
		 * in this case, node has not been added into the event list
		 */
		ret = sde_core_irq_enable(kms, &irq_idx, 1);
		if (ret) {
			DRM_ERROR("failed to enable irq ret %d\n", ret);
			sde_core_irq_unregister_callback(kms,
				irq_idx, ad_irq);
		}
	}

exit:
	return ret;
}
@@ -1864,7 +1846,7 @@ static void sde_cp_hist_interrupt_cb(void *arg, int irq_idx)
	spin_unlock_irqrestore(&crtc->spin_lock, flags);

	if (!node) {
		DRM_ERROR("cannot find histogram event node in crtc\n");
		DRM_DEBUG_DRIVER("cannot find histogram event node in crtc\n");
		return;
	}

@@ -1988,26 +1970,29 @@ int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en,
		goto exit;
	}

	node = _sde_cp_get_intr_node(DRM_EVENT_HISTOGRAM, crtc);
	node = container_of(hist_irq, struct sde_crtc_irq_info, irq);

	/* deregister histogram irq */
	if (!en) {
		if (node) {
			/* device suspend case or suspend to IPC cases */
		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;
			}
			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 {
			DRM_ERROR("failed to get node from crtc event list\n");
			spin_unlock_irqrestore(&node->state_lock, flags);
		}

		sde_core_irq_unregister_callback(kms, irq_idx, hist_irq);
@@ -2023,14 +2008,11 @@ int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en,
		goto exit;
	}

	if (node) {
		/* device resume or resume from IPC cases */
	spin_lock_irqsave(&node->state_lock, flags);
	if (node->state == IRQ_DISABLED || node->state == IRQ_NOINIT) {
		ret = sde_core_irq_enable(kms, &irq_idx, 1);
		if (ret) {
				DRM_ERROR("enable irq %d error %d\n",
					irq_idx, ret);
			DRM_ERROR("enable irq %d error %d\n", irq_idx, ret);
			sde_core_irq_unregister_callback(kms,
				irq_idx, hist_irq);
		} else {
@@ -2038,17 +2020,7 @@ int sde_cp_hist_interrupt(struct drm_crtc *crtc_drm, bool en,
		}
	}
	spin_unlock_irqrestore(&node->state_lock, flags);
	} else {
		/* request from userspace to register the event
		 * in this case, node has not been added into the event list
		 */
		ret = sde_core_irq_enable(kms, &irq_idx, 1);
		if (ret) {
			DRM_ERROR("failed to enable irq ret %d\n", ret);
			sde_core_irq_unregister_callback(kms,
				irq_idx, hist_irq);
		}
	}

exit:
	return ret;
}
+1 −3
Original line number Diff line number Diff line
@@ -6102,10 +6102,10 @@ static int _sde_crtc_event_enable(struct sde_kms *kms,
			node = kzalloc(sizeof(*node), GFP_KERNEL);
			if (!node)
				return -ENOMEM;
			node->event = event;
			INIT_LIST_HEAD(&node->list);
			node->func = custom_events[i].func;
			node->event = event;
			node->state = IRQ_NOINIT;
			spin_lock_init(&node->state_lock);
			break;
		}
@@ -6136,8 +6136,6 @@ static int _sde_crtc_event_enable(struct sde_kms *kms,

	if (!ret) {
		spin_lock_irqsave(&crtc->spin_lock, flags);
		/* irq is regiestered and enabled and set the state */
		node->state = IRQ_ENABLED;
		list_add_tail(&node->list, &crtc->user_event_list);
		spin_unlock_irqrestore(&crtc->spin_lock, flags);
	} else {
+1 −0
Original line number Diff line number Diff line
@@ -379,6 +379,7 @@ struct sde_crtc_state {
enum sde_crtc_irq_state {
	IRQ_NOINIT,
	IRQ_ENABLED,
	IRQ_DISABLING,
	IRQ_DISABLED,
};