[PATCH 283/368] Staging: udlfb: Support for fbdev mmap clients (defio)

Greg KH greg at kroah.com
Thu Mar 4 20:07:41 UTC 2010


From: Bernie Thompson <bernie at plugable.com>

Add support for fbdev mmap clients who don't send damage ioctls

Because DisplayLink devices are out on the other end of usb, their
"framebuffer" is just normal system memory. So memory mapped writes
don't automatically trigger anything. So up to this point, standard
fbdev clients who rely on mmap() will get an unchanging screen.

This patch makes udlfb a client of Jaya Kumar's defio framework - which sets
up page fault triggers, and those faults are accumulated and sent to udlfb
on a defferred basis, to process as damage notifications for the framebuffer.

Because this involves more overhead than a notification directly from
the application (e.g. just passing on X DAMAGE extension notifications),
a sysfs attribute is provided by udlfb to control defio support.

/sys/class/graphics/fb*/use_defio - writing a "0" to this file before
calling mmap() causes defio to not be initialized - instead udlfb
will rely on getting damage notifications directly through the damage ioctl.

There are unsolved rendering problems with defio (horizontal dead regions
on framebuffer, that accumulate over time) which still needs a fix.

Signed-off-by: Bernie Thompson <bernie at plugable.com>
Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>
---
 drivers/staging/udlfb/udlfb.c |  124 ++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 121 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/udlfb/udlfb.c b/drivers/staging/udlfb/udlfb.c
index 22f3dc3..939b8fa 100644
--- a/drivers/staging/udlfb/udlfb.c
+++ b/drivers/staging/udlfb/udlfb.c
@@ -63,6 +63,11 @@ static int dlfb_submit_urb(struct dlfb_data *dev, struct urb * urb, size_t len);
 static int dlfb_alloc_urb_list(struct dlfb_data *dev, int count, size_t size);
 static void dlfb_free_urb_list(struct dlfb_data *dev);
 
+/* other symbols with dependents */
+#ifdef CONFIG_FB_DEFERRED_IO
+static struct fb_deferred_io dlfb_defio;
+#endif
+
 /*
  * Inserts a specific DisplayLink controller command into the provided
  * buffer.
@@ -717,9 +722,59 @@ dlfb_ops_setcolreg(unsigned regno, unsigned red, unsigned green,
 	return err;
 }
 
+/*
+ * It's common for several clients to have framebuffer open simultaneously.
+ * e.g. both fbcon and X. Makes things interesting.
+ */
+static int dlfb_ops_open(struct fb_info *info, int user)
+{
+	struct dlfb_data *dev = info->par;
+
+/*	if (user == 0)
+ *		We could special case kernel mode clients (fbcon) here
+ */
+
+	mutex_lock(&dev->fb_open_lock);
+
+	dev->fb_count++;
+
+#ifdef CONFIG_FB_DEFERRED_IO
+	if ((atomic_read(&dev->use_defio)) && (info->fbdefio == NULL)) {
+		/* enable defio */
+		info->fbdefio = &dlfb_defio;
+		fb_deferred_io_init(info);
+	}
+#endif
+
+	dl_notice("open /dev/fb%d user=%d fb_info=%p count=%d\n",
+	    info->node, user, info, dev->fb_count);
+
+	mutex_unlock(&dev->fb_open_lock);
+
+	return 0;
+}
+
 static int dlfb_ops_release(struct fb_info *info, int user)
 {
-	struct dlfb_data *dev_info = info->par;
+	struct dlfb_data *dev = info->par;
+
+	mutex_lock(&dev->fb_open_lock);
+
+	dev->fb_count--;
+
+#ifdef CONFIG_FB_DEFERRED_IO
+	if ((dev->fb_count == 0) && (info->fbdefio)) {
+		fb_deferred_io_cleanup(info);
+		info->fbdefio = NULL;
+		info->fbops->fb_mmap = dlfb_ops_mmap;
+	}
+#endif
+
+	dl_notice("release /dev/fb%d user=%d count=%d\n",
+		  info->node, user, dev->fb_count);
+
+	mutex_unlock(&dev->fb_open_lock);
+
 	return 0;
 }
 
@@ -735,6 +790,8 @@ static void dlfb_delete(struct kref *kref)
 	if (dev->backing_buffer)
 		vfree(dev->backing_buffer);
 
+	mutex_destroy(&dev->fb_open_lock);
+
 	kfree(dev);
 }
 
@@ -853,6 +910,7 @@ static struct fb_ops dlfb_ops = {
 	.fb_imageblit = dlfb_ops_imageblit,
 	.fb_mmap = dlfb_ops_mmap,
 	.fb_ioctl = dlfb_ops_ioctl,
+	.fb_open = dlfb_ops_open,
 	.fb_release = dlfb_ops_release,
 	.fb_blank = dlfb_ops_blank,
 	.fb_check_var = dlfb_ops_check_var,
@@ -1068,6 +1126,68 @@ static struct device_attribute fb_device_attrs[] = {
 	__ATTR_RW(use_defio),
 };
 
+#ifdef CONFIG_FB_DEFERRED_IO
+static void dlfb_dpy_deferred_io(struct fb_info *info,
+				struct list_head *pagelist)
+{
+	struct page *cur;
+	struct fb_deferred_io *fbdefio = info->fbdefio;
+	struct dlfb_data *dev = info->par;
+	struct urb *urb;
+	char *cmd;
+	cycles_t start_cycles, end_cycles;
+	int bytes_sent = 0;
+	int bytes_identical = 0;
+	int bytes_rendered = 0;
+	int fault_count = 0;
+
+	if (!atomic_read(&dev->use_defio))
+		return;
+
+	if (!atomic_read(&dev->usb_active))
+		return;
+
+	start_cycles = get_cycles();
+
+	urb = dlfb_get_urb(dev);
+	if (!urb)
+		return;
+	cmd = urb->transfer_buffer;
+
+	/* walk the written page list and render each to device */
+	list_for_each_entry(cur, &fbdefio->pagelist, lru) {
+		dlfb_render_hline(dev, &urb, (char *) info->fix.smem_start,
+				  &cmd, cur->index << PAGE_SHIFT,
+				  PAGE_SIZE, &bytes_identical, &bytes_sent);
+		bytes_rendered += PAGE_SIZE;
+		fault_count++;
+	}
+
+	if (cmd > (char *) urb->transfer_buffer) {
+		/* Send partial buffer remaining before exiting */
+		int len = cmd - (char *) urb->transfer_buffer;
+		dlfb_submit_urb(dev, urb, len);
+		bytes_sent += len;
+	} else
+		dlfb_urb_completion(urb);
+
+	atomic_add(fault_count, &dev->defio_fault_count);
+	atomic_add(bytes_sent, &dev->bytes_sent);
+	atomic_add(bytes_identical, &dev->bytes_identical);
+	atomic_add(bytes_rendered, &dev->bytes_rendered);
+	end_cycles = get_cycles();
+	atomic_add(((unsigned int) ((end_cycles - start_cycles)
+		    >> 10)), /* Kcycles */
+		   &dev->cpu_kcycles_used);
+}
+
+static struct fb_deferred_io dlfb_defio = {
+	.delay          = 5,
+	.deferred_io    = dlfb_dpy_deferred_io,
+};
+
+#endif
+
 /*
  * This is necessary before we can communicate with the display controller.
  */
@@ -1193,11 +1313,9 @@ static int dlfb_usb_probe(struct usb_interface *interface,
 
 	/* ready to begin using device */
 
-/*
 #ifdef CONFIG_FB_DEFERRED_IO
 	atomic_set(&dev->use_defio, 1);
 #endif
-*/
 	atomic_set(&dev->usb_active, 1);
 	dlfb_select_std_channel(dev);
 
-- 
1.7.0.1




More information about the devel mailing list