linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Bernie Thompson <bernie@plugable.com>
To: linux-fbdev@vger.kernel.org
Subject: [PATCH 8/10] udlfb: Support for fbdev mmap clients (defio)
Date: Mon, 15 Feb 2010 14:46:26 +0000	[thread overview]
Message-ID: <1266245186.4353.3303.camel@bernie-aspireone> (raw)

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@plugable.com>
---
 drivers/staging/udlfb/udlfb.c |  124 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 121 insertions(+), 3 deletions(-)

Index: linux-next/drivers/staging/udlfb/udlfb.c
=================================--- linux-next.orig/drivers/staging/udlfb/udlfb.c	2010-02-14 20:26:59.000000000 -0800
+++ linux-next/drivers/staging/udlfb/udlfb.c	2010-02-14 20:27:01.000000000 -0800
@@ -63,6 +63,11 @@ static int dlfb_submit_urb(struct dlfb_d
 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, unsig
 	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 *kre
 	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
 	__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_int
 
 	/* 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);
 



                 reply	other threads:[~2010-02-15 14:46 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=1266245186.4353.3303.camel@bernie-aspireone \
    --to=bernie@plugable.com \
    --cc=linux-fbdev@vger.kernel.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).