Skip to contentSkip to conversation

drm/udl: Make page_flip asynchronous

PATCH New Dawid Kurek 1 participant 1 message Jun 21, 2017

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 drm/udl: Make page_flip asynchronous

In page_flip vblank is sent with no delay. Driver does not know when the actual update is present on the display and has no means for getting this information from a device. It is practically impossible to say exactly *when* as there is also i.e. a usb delay.

When we are unable to determine when the vblank actually happens we may assume it will behave accordingly, i.e. it will present frames with proper timing. In the worst case scenario it should take up to duration of one frame (we may get new frame in the device just after presenting current one so we would need to wait for the whole frame).

Because of the asynchronous nature of the delay we need to synchronize:
* read/write vrefresh/page_flip data when changing mode and preparing/executing vblank
* USB requests to prevent interleaved access to URBs for two different frame buffers

All those changes are backports from ChromeOS:
1. https://chromium-review.googlesource.com/250622
2. https://chromium-review.googlesource.com/249450
partially, only change in udl_modeset.c for 'udl_flip_queue'
3. https://chromium-review.googlesource.com/321378
4. https://chromium-review.googlesource.com/324119
+ fixes for checkpatch and latest drm changes

---
 drivers/gpu/drm/udl/udl_drv.h     |   4 +
 drivers/gpu/drm/udl/udl_fb.c      |  28 ++++---
 drivers/gpu/drm/udl/udl_main.c    |   3 +
 drivers/gpu/drm/udl/udl_modeset.c | 160 ++++++++++++++++++++++++++++++++++----
 4 files changed, 171 insertions(+), 24 deletions(-)
drivers/gpu/drm/udl/udl_drv.h +4 -0
index 2a75ab8..b93fb8d 100644
@@ -47,6 +47,7 @@ struct urb_list {
 };
 
 struct udl_fbdev;
+struct udl_flip_queue;
 
 struct udl_device {
 	struct device *dev;
@@ -66,6 +67,9 @@ struct udl_device {
 	atomic_t bytes_identical; /* saved effort with backbuffer comparison */
 	atomic_t bytes_sent; /* to usb, after compression including overhead */
 	atomic_t cpu_kcycles_used; /* transpired during pixel processing */
+
+	struct udl_flip_queue *flip_queue;
+	struct mutex transfer_lock; /* to serialize transfers */
 };
 
 struct udl_gem_object {
drivers/gpu/drm/udl/udl_fb.c +19 -9
index 4a65003..6dd9a49 100644
@@ -82,7 +82,7 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
 {
 	struct drm_device *dev = fb->base.dev;
 	struct udl_device *udl = dev->dev_private;
-	int i, ret;
+	int i, ret = 0;
 	char *cmd;
 	cycles_t start_cycles, end_cycles;
 	int bytes_sent = 0;
@@ -91,18 +91,22 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
 	int aligned_x;
 	int bpp = fb->base.format->cpp[0];
 
+	mutex_lock(&udl->transfer_lock);
+
 	if (!fb->active_16)
-		return 0;
+		goto out;
 
 	if (!fb->obj->vmapping) {
 		ret = udl_gem_vmap(fb->obj);
 		if (ret == -ENOMEM) {
 			DRM_ERROR("failed to vmap fb\n");
-			return 0;
+			ret = 0;
+			goto out;
 		}
 		if (!fb->obj->vmapping) {
 			DRM_ERROR("failed to vmapping\n");
-			return 0;
+			ret = 0;
+			goto out;
 		}
 	}
 
@@ -112,14 +116,18 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
 
 	if ((width <= 0) ||
 	    (x + width > fb->base.width) ||
-	    (y + height > fb->base.height))
-		return -EINVAL;
+	    (y + height > fb->base.height)) {
+		ret = -EINVAL;
+		goto out;
+	}
 
 	start_cycles = get_cycles();
 
 	urb = udl_get_urb(dev);
-	if (!urb)
-		return 0;
+	if (!urb) {
+		ret = 0;
+		goto out;
+	}
 	cmd = urb->transfer_buffer;
 
 	for (i = y; i < y + height ; i++) {
@@ -151,7 +159,9 @@ int udl_handle_damage(struct udl_framebuffer *fb, int x, int y,
 		    >> 10)), /* Kcycles */
 		   &udl->cpu_kcycles_used);
 
-	return 0;
+out:
+	mutex_unlock(&udl->transfer_lock);
+	return ret;
 }
 
 static int udl_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
drivers/gpu/drm/udl/udl_main.c +3 -0
index a9d93b8..d376233 100644
@@ -319,6 +319,8 @@ int udl_driver_load(struct drm_device *dev, unsigned long flags)
 	if (!udl)
 		return -ENOMEM;
 
+	mutex_init(&udl->transfer_lock);
+
 	udl->udev = udev;
 	udl->ddev = dev;
 	dev->dev_private = udl;
@@ -378,5 +380,6 @@ void udl_driver_unload(struct drm_device *dev)
 
 	udl_fbdev_cleanup(dev);
 	udl_modeset_cleanup(dev);
+	mutex_destroy(&udl->transfer_lock);
 	kfree(udl);
 }
drivers/gpu/drm/udl/udl_modeset.c +145 -15

245 lines not on this page · raw message

Signature · 1 line
2.7.4