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

Commit b6b401f8 authored by Gopikrishnaiah Anandan's avatar Gopikrishnaiah Anandan Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/sde: Implement work queue for crtc events



Interrupt framework of the sde driver will callback registered crtc
client when registered interrupt fires. Callback is in atomic context
and clients should do minimal processing. Due to asynchronous nature of
the events there will race conditions with crtc resources being
released. Change adds work queue for handling crtc events where sde crtc
mutex will be acquired which should prevent resource related race
conditions.

Change-Id: I911ddbc2548df550bcfcbf49973da670287fa461
Signed-off-by: default avatarGopikrishnaiah Anandan <agopik@codeaurora.org>
parent 5154c71d
Loading
Loading
Loading
Loading
+18 −4
Original line number Diff line number Diff line
@@ -70,6 +70,8 @@ static void sde_cp_update_list(struct sde_cp_node *prop_node,
static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node,
		struct sde_crtc *crtc);

static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg);

#define setup_dspp_prop_install_funcs(func) \
do { \
	func[SDE_DSPP_PCC] = dspp_pcc_install_property; \
@@ -1323,15 +1325,25 @@ static int sde_cp_ad_validate_prop(struct sde_cp_node *prop_node,
static void sde_cp_ad_interrupt_cb(void *arg, int irq_idx)
{
	struct sde_crtc *crtc = arg;
	struct drm_event event;

	sde_crtc_event_queue(&crtc->base, sde_cp_notify_ad_event, NULL);
}

static void sde_cp_notify_ad_event(struct drm_crtc *crtc_drm, void *arg)
{
	uint32_t bl = 0;
	u32 num_mixers = crtc->num_mixers;
	struct sde_hw_mixer *hw_lm = NULL;
	struct sde_hw_dspp *hw_dspp = NULL;
	u32 num_mixers;
	struct sde_crtc *crtc;
	struct drm_event event;
	int i;

	event.type = DRM_EVENT_AD_BACKLIGHT;
	event.length = sizeof(bl);
	crtc = to_sde_crtc(crtc_drm);
	num_mixers = crtc->num_mixers;
	if (!num_mixers)
		return;

	for (i = 0; i < num_mixers; i++) {
		hw_lm = crtc->mixers[i].hw_lm;
		hw_dspp = crtc->mixers[i].hw_dspp;
@@ -1343,6 +1355,8 @@ static void sde_cp_ad_interrupt_cb(void *arg, int irq_idx)
		return;

	hw_dspp->ops.ad_read_intr_resp(hw_dspp, AD4_BACKLIGHT, &bl);
	event.length = sizeof(u32);
	event.type = DRM_EVENT_AD_BACKLIGHT;
	msm_send_crtc_notification(&crtc->base, &event, (u8 *)&bl);
}

+32 −15
Original line number Diff line number Diff line
@@ -45,6 +45,16 @@ struct sde_crtc_irq_info {
	struct list_head list;
};

struct sde_crtc_custom_events {
	u32 event;
	int (*func)(struct drm_crtc *crtc, bool en,
			struct sde_irq_callback *irq);
};

static struct sde_crtc_custom_events custom_events[] = {
	{DRM_EVENT_AD_BACKLIGHT, sde_cp_ad_interrupt}
};

/* default input fence timeout, in ms */
#define SDE_CRTC_INPUT_FENCE_TIMEOUT    2000

@@ -2322,21 +2332,22 @@ static void _sde_crtc_event_cb(struct kthread_work *work)
	}

	event = container_of(work, struct sde_crtc_event, kt_work);
	if (event->cb_func)
		event->cb_func(event->usr);

	/* set sde_crtc to NULL for static work structures */
	sde_crtc = event->sde_crtc;
	if (!sde_crtc)
		return;

	if (event->cb_func)
		event->cb_func(&sde_crtc->base, event->usr);

	spin_lock_irqsave(&sde_crtc->event_lock, irq_flags);
	list_add_tail(&event->list, &sde_crtc->event_free_list);
	spin_unlock_irqrestore(&sde_crtc->event_lock, irq_flags);
}

int sde_crtc_event_queue(struct drm_crtc *crtc,
		void (*func)(void *usr), void *usr)
		void (*func)(struct drm_crtc *crtc, void *usr), void *usr)
{
	unsigned long irq_flags;
	struct sde_crtc *sde_crtc;
@@ -2346,6 +2357,8 @@ int sde_crtc_event_queue(struct drm_crtc *crtc,
		return -EINVAL;
	sde_crtc = to_sde_crtc(crtc);

	if (!sde_crtc->event_thread)
		return -EINVAL;
	/*
	 * Obtain an event struct from the private cache. This event
	 * queue may be called from ISR contexts, so use a private
@@ -2482,7 +2495,7 @@ static int _sde_crtc_event_enable(struct sde_kms *kms,
	struct msm_drm_private *priv;
	unsigned long flags;
	bool found = false;
	int ret;
	int ret, i = 0;

	crtc = to_sde_crtc(crtc_drm);
	spin_lock_irqsave(&crtc->spin_lock, flags);
@@ -2498,19 +2511,23 @@ static int _sde_crtc_event_enable(struct sde_kms *kms,
	if (found)
		return 0;

	node = NULL;
	for (i = 0; i < ARRAY_SIZE(custom_events); i++) {
		if (custom_events[i].event == event &&
			custom_events[i].func) {
			node = kzalloc(sizeof(*node), GFP_KERNEL);
			if (!node)
				return -ENOMEM;
			node->event = event;
			INIT_LIST_HEAD(&node->list);

	switch (event) {
	case DRM_EVENT_AD_BACKLIGHT:
		node->func = sde_cp_ad_interrupt;
			node->func = custom_events[i].func;
			node->event = event;
			break;
	default:
		}
	}

	if (!node) {
		SDE_ERROR("unsupported event %x\n", event);
		kfree(node);
		return -EINVAL;
	}

+2 −2
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@ struct sde_crtc_event {
	struct kthread_work kt_work;
	void *sde_crtc;

	void (*cb_func)(void *usr);
	void (*cb_func)(struct drm_crtc *crtc, void *usr);
	void *usr;
};

@@ -368,6 +368,6 @@ static inline bool sde_crtc_is_enabled(struct drm_crtc *crtc)
 * Returns: Zero on success
 */
int sde_crtc_event_queue(struct drm_crtc *crtc,
		void (*func)(void *usr), void *usr);
		void (*func)(struct drm_crtc *crtc, void *usr), void *usr);

#endif /* _SDE_CRTC_H_ */