All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paulo Zanoni <przanoni@gmail.com>
To: dri-devel@lists.freedesktop.org
Cc: intel-gfx@lists.freedesktop.org, Paulo Zanoni <paulo.r.zanoni@intel.com>
Subject: [RFC 2/7] drm: allow drm_wait_vblank_kernel() callback from workqueues
Date: Wed, 19 Nov 2014 17:47:10 -0200	[thread overview]
Message-ID: <1416426435-2237-4-git-send-email-przanoni@gmail.com> (raw)
In-Reply-To: <1416426435-2237-1-git-send-email-przanoni@gmail.com>

From: Paulo Zanoni <paulo.r.zanoni@intel.com>

This is going to be needed by i915.ko, and I guess other drivers could
use it too.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
 drivers/gpu/drm/drm_irq.c           | 46 ++++++++++++++++++++++++++++++++-----
 drivers/gpu/drm/i915/i915_debugfs.c | 45 ++++++++++++++++++++++++++++--------
 include/drm/drmP.h                  | 11 ++++++++-
 3 files changed, 86 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index f031f77..099aef1 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -1108,6 +1108,22 @@ void drm_crtc_wait_one_vblank(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_crtc_wait_one_vblank);
 
+static void drm_wait_vblank_callback(struct drm_device *dev,
+				     struct drm_pending_vblank_event *e,
+				     unsigned long seq, struct timeval *now,
+				     bool premature)
+{
+	if (e->callback_from_work) {
+		e->callback_args.dev = dev;
+		e->callback_args.seq = seq;
+		e->callback_args.now = now;
+		e->callback_args.premature = premature;
+		schedule_work(&e->callback_work);
+	} else {
+		e->callback(dev, e, seq, now, premature);
+	}
+}
+
 /**
  * drm_vblank_off - disable vblank events on a CRTC
  * @dev: DRM device
@@ -1160,7 +1176,7 @@ void drm_vblank_off(struct drm_device *dev, int crtc)
 			  e->event.sequence, seq);
 		list_del(&e->base.link);
 		drm_vblank_put(dev, e->pipe);
-		e->callback(dev, e, seq, &now, true);
+		drm_wait_vblank_callback(dev, e, seq, &now, true);
 	}
 	spin_unlock_irqrestore(&dev->event_lock, irqflags);
 }
@@ -1372,9 +1388,20 @@ int drm_modeset_ctl(struct drm_device *dev, void *data,
 	return 0;
 }
 
+static void drm_vblank_event_work_func(struct work_struct *work)
+{
+	struct drm_pending_vblank_event *e =
+		container_of(work, struct drm_pending_vblank_event,
+			     callback_work);
+
+	e->callback(e->callback_args.dev, e, e->callback_args.seq,
+		    e->callback_args.now, e->callback_args.premature);
+}
+
 static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
 				  union drm_wait_vblank *vblwait,
 				  struct drm_file *file_priv,
+				  bool callback_from_work,
 				  drm_vblank_callback_t callback)
 {
 	struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
@@ -1399,6 +1426,9 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
 	e->base.file_priv = file_priv;
 	e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
 	e->callback = callback;
+	e->callback_from_work = callback_from_work;
+	if (callback_from_work)
+		INIT_WORK(&e->callback_work, drm_vblank_event_work_func);
 
 	spin_lock_irqsave(&dev->event_lock, flags);
 
@@ -1440,7 +1470,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
 	e->event.sequence = vblwait->request.sequence;
 	if ((seq - vblwait->request.sequence) <= (1 << 23)) {
 		drm_vblank_put(dev, pipe);
-		e->callback(dev, e, seq, &now, false);
+		drm_wait_vblank_callback(dev, e, seq, &now, false);
 		vblwait->reply.sequence = seq;
 	} else {
 		/* drm_handle_vblank_events will call drm_vblank_put */
@@ -1477,6 +1507,7 @@ err_put:
 static int __drm_wait_vblank(struct drm_device *dev,
 			     union drm_wait_vblank *vblwait,
 			     struct drm_file *file_priv,
+			     bool callback_from_work,
 			     drm_vblank_callback_t callback)
 {
 	struct drm_vblank_crtc *vblank;
@@ -1533,7 +1564,7 @@ static int __drm_wait_vblank(struct drm_device *dev,
 		 * drm_vblank_put will be called asynchronously
 		 */
 		return drm_queue_vblank_event(dev, crtc, vblwait, file_priv,
-					      callback);
+					      callback_from_work, callback);
 	}
 
 	if ((flags & _DRM_VBLANK_NEXTONMISS) &&
@@ -1573,10 +1604,12 @@ int drm_wait_vblank_ioctl(struct drm_device *dev, void *data,
 {
 	union drm_wait_vblank *vblwait = data;
 
-	return __drm_wait_vblank(dev, vblwait, file_priv, send_vblank_event);
+	return __drm_wait_vblank(dev, vblwait, file_priv, false,
+				 send_vblank_event);
 }
 
 int drm_wait_vblank_kernel(struct drm_crtc *crtc, int count, bool absolute,
+			   bool callback_from_work,
 			   drm_vblank_callback_t callback,
 			   unsigned long user_data)
 {
@@ -1593,7 +1626,8 @@ int drm_wait_vblank_kernel(struct drm_crtc *crtc, int count, bool absolute,
 	vblwait.request.sequence = count;
 	vblwait.request.signal = user_data;
 
-	return __drm_wait_vblank(dev, &vblwait, NULL, callback);
+	return __drm_wait_vblank(dev, &vblwait, NULL, callback_from_work,
+				 callback);
 }
 EXPORT_SYMBOL(drm_wait_vblank_kernel);
 
@@ -1618,7 +1652,7 @@ static void drm_handle_vblank_events(struct drm_device *dev, int crtc)
 
 		list_del(&e->base.link);
 		drm_vblank_put(dev, e->pipe);
-		e->callback(dev, e, seq, &now, false);
+		drm_wait_vblank_callback(dev, e, seq, &now, false);
 	}
 
 	trace_drm_vblank_event(crtc, seq);
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index f989587..95cf6d3 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2718,6 +2718,7 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
 struct vblank_data {
 	int eight;
 	const char *message;
+	bool can_sleep;
 };
 
 static void vblank_callback(struct drm_device *dev,
@@ -2727,6 +2728,7 @@ static void vblank_callback(struct drm_device *dev,
 {
 	struct vblank_data *data = (struct vblank_data *)e->event.user_data;
 
+	WARN_ON(data->can_sleep != drm_can_sleep());
 	WARN_ON(data->eight != 8);
 	DRM_DEBUG_KMS("vblank callback, seq: %lu, premature: %s message:%s\n",
 		      seq, yesno(premature), data->message);
@@ -2741,7 +2743,7 @@ static int i915_vblank_queue_test_new(struct seq_file *m, void *unused)
 	struct drm_device *dev = node->minor->dev;
 	struct intel_crtc *crtc = NULL;
 	int ret = 0;
-	struct vblank_data *data;
+	struct vblank_data *data1, *data2;
 
 	for_each_intel_crtc(dev, crtc)
 		if (crtc->pipe == PIPE_A)
@@ -2749,26 +2751,51 @@ static int i915_vblank_queue_test_new(struct seq_file *m, void *unused)
 	if (WARN_ON(!crtc))
 		return -EINVAL;
 
-	data = kzalloc(sizeof *data, GFP_KERNEL);
-	if (!data)
+	data1 = kzalloc(sizeof *data1, GFP_KERNEL);
+	if (!data1)
 		return -ENOMEM;
 
-	data->message = "hello world";
-	data->eight = 8;
+	data1->message = "hello world (atomic)";
+	data1->eight = 8;
+	data1->can_sleep = false;
+
+	data2 = kzalloc(sizeof *data2, GFP_KERNEL);
+	if (!data2) {
+		kfree(data1);
+		return -ENOMEM;
+	}
+
+	data2->message = "hello world (from work)";
+	data2->eight = 8;
+	data2->can_sleep = true;
 
 	DRM_DEBUG_KMS("waiting 60 vblanks (no callback)\n");
-	ret = drm_wait_vblank_kernel(&crtc->base, 60, false, NULL, 0);
+	ret = drm_wait_vblank_kernel(&crtc->base, 60, false, false, NULL, 0);
 	if (ret) {
 		DRM_DEBUG_KMS("vblank wait error: %d\n", ret);
+		kfree(data1);
+		kfree(data2);
 		return ret;
 	}
 	DRM_DEBUG_KMS("vblank wait done\n");
 
-	DRM_DEBUG_KMS("scheduling 60 vblanks (with callback)\n");
-	ret = drm_wait_vblank_kernel(&crtc->base, 60, false, vblank_callback,
-				     (unsigned long) data);
+	DRM_DEBUG_KMS("scheduling 60 vblanks (with callback, can't sleep)\n");
+	ret = drm_wait_vblank_kernel(&crtc->base, 60, false, false,
+				     vblank_callback, (unsigned long) data1);
+	if (ret) {
+		DRM_DEBUG_KMS("vblank schedule error: %d\n", ret);
+		kfree(data1);
+		kfree(data2);
+		return ret;
+	}
+	DRM_DEBUG_KMS("vblanks scheduled\n");
+
+	DRM_DEBUG_KMS("scheduling 60 vblanks (with callback, can sleep)\n");
+	ret = drm_wait_vblank_kernel(&crtc->base, 60, false, true,
+				     vblank_callback, (unsigned long) data2);
 	if (ret) {
 		DRM_DEBUG_KMS("vblank schedule error: %d\n", ret);
+		kfree(data2);
 		return ret;
 	}
 	DRM_DEBUG_KMS("vblanks scheduled\n");
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 39d0d87..bc114f0 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -669,7 +669,16 @@ struct drm_pending_vblank_event {
 	struct drm_pending_event base;
 	int pipe;
 	struct drm_event_vblank event;
+
 	drm_vblank_callback_t callback;
+	bool callback_from_work;
+	struct work_struct callback_work;
+	struct {
+		struct drm_device *dev;
+		unsigned long seq;
+		struct timeval *now;
+		bool premature;
+	} callback_args;
 };
 
 struct drm_vblank_crtc {
@@ -906,7 +915,7 @@ extern int drm_vblank_init(struct drm_device *dev, int num_crtcs);
 extern int drm_wait_vblank_ioctl(struct drm_device *dev, void *data,
 				 struct drm_file *filp);
 extern int drm_wait_vblank_kernel(struct drm_crtc *crtc, int count,
-				  bool absolute,
+				  bool absolute, bool callback_from_work,
 				  drm_vblank_callback_t callback,
 				  unsigned long user_data);
 extern u32 drm_vblank_count(struct drm_device *dev, int crtc);
-- 
2.1.1

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

  parent reply	other threads:[~2014-11-19 19:47 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-19 19:47 [RFC 0/7+1] Add in-kernel vblank delaying mechanism Paulo Zanoni
2014-11-19 19:47 ` [RFC] drm: add a mechanism for drivers to schedule vblank callbacks Paulo Zanoni
2014-12-03  2:13   ` [Intel-gfx] " Matt Roper
2014-11-19 19:47 ` [RFC 1/7] drm: allow the drivers to call the vblank IOCTL internally Paulo Zanoni
2014-12-03  2:14   ` Matt Roper
2014-11-19 19:47 ` Paulo Zanoni [this message]
2014-12-05  0:34   ` [Intel-gfx] [RFC 2/7] drm: allow drm_wait_vblank_kernel() callback from workqueues Matt Roper
2014-11-19 19:47 ` [RFC 3/7] drm: introduce struct drm_vblank_wait_item Paulo Zanoni
2014-12-05  2:27   ` Matt Roper
2014-11-19 19:47 ` [RFC 4/7] drm: add wanted_seq to drm_vblank_wait_item Paulo Zanoni
2014-11-19 19:47 ` [RFC 5/7] drm: change the drm vblank callback item type Paulo Zanoni
2014-11-19 19:47 ` [RFC 6/7] drm: make vblank_event_list handle drm_vblank_wait_item types Paulo Zanoni
2014-12-05  2:27   ` [Intel-gfx] " Matt Roper
2014-11-19 19:47 ` [RFC 7/7] drm: make the callers of drm_wait_vblank() allocate the memory Paulo Zanoni
2014-11-26 17:19 ` [RFC 0/7+1] Add in-kernel vblank delaying mechanism Daniel Vetter
2014-11-26 23:25   ` Dave Airlie
2014-11-27 10:06     ` Daniel Vetter
2014-12-04 17:09 ` Daniel Vetter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1416426435-2237-4-git-send-email-przanoni@gmail.com \
    --to=przanoni@gmail.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=paulo.r.zanoni@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.