Module Name: src Committed By: riastradh Date: Wed Jan 15 21:25:29 UTC 2014
Modified Files: src/sys/external/bsd/drm2/dist/drm [riastradh-drm2]: drm_irq.c src/sys/external/bsd/drm2/dist/include/drm [riastradh-drm2]: drmP.h src/sys/external/bsd/drm2/drm [riastradh-drm2]: drm_drv.c drm_fops.c Log Message: Hack up vblank events and make them work. To generate a diff of this commit: cvs rdiff -u -r1.1.1.1.2.10 -r1.1.1.1.2.11 \ src/sys/external/bsd/drm2/dist/drm/drm_irq.c cvs rdiff -u -r1.1.1.1.2.54 -r1.1.1.1.2.55 \ src/sys/external/bsd/drm2/dist/include/drm/drmP.h cvs rdiff -u -r1.1.2.24 -r1.1.2.25 src/sys/external/bsd/drm2/drm/drm_drv.c cvs rdiff -u -r1.1.2.7 -r1.1.2.8 src/sys/external/bsd/drm2/drm/drm_fops.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/external/bsd/drm2/dist/drm/drm_irq.c diff -u src/sys/external/bsd/drm2/dist/drm/drm_irq.c:1.1.1.1.2.10 src/sys/external/bsd/drm2/dist/drm/drm_irq.c:1.1.1.1.2.11 --- src/sys/external/bsd/drm2/dist/drm/drm_irq.c:1.1.1.1.2.10 Sun Sep 8 16:11:29 2013 +++ src/sys/external/bsd/drm2/dist/drm/drm_irq.c Wed Jan 15 21:25:29 2014 @@ -50,6 +50,11 @@ #include <asm/bug.h> +#ifdef __NetBSD__ /* XXX hurk -- selnotify &c. */ +#include <sys/poll.h> +#include <sys/select.h> +#endif + /* Access macro for slots in vblank timestamp ringbuffer. */ #define vblanktimestamp(dev, crtc, count) ( \ (dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \ @@ -887,6 +892,8 @@ static void send_vblank_event(struct drm &e->base.file_priv->event_list); #ifdef __NetBSD__ DRM_SPIN_WAKEUP_ONE(&e->base.file_priv->event_wait, &dev->event_lock); + selnotify(&e->base.file_priv->event_selq, (POLLIN | POLLRDNORM), + NOTE_SUBMIT); #else wake_up_interruptible(&e->base.file_priv->event_wait); #endif @@ -1342,11 +1349,22 @@ int drm_wait_vblank(struct drm_device *d vblwait->request.sequence, crtc); dev->last_vblank_wait[crtc] = vblwait->request.sequence; #ifdef __NetBSD__ + { + unsigned long irqflags; + spin_lock_irqsave(&dev->vbl_lock, irqflags); DRM_SPIN_TIMED_WAIT_UNTIL(ret, &dev->vbl_queue[crtc], &dev->vbl_lock, (3 * DRM_HZ), (((drm_vblank_count(dev, crtc) - vblwait->request.sequence) <= (1 << 23)) || !dev->irq_enabled)); + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + if (0 < ret) + /* + * ret is ticks remaining on success in this case, but + * caller just wants 0 for success. + */ + ret = 0; + } #else DRM_WAIT_ON(ret, dev->vbl_queue[crtc], 3 * DRM_HZ, (((drm_vblank_count(dev, crtc) - @@ -1416,10 +1434,17 @@ bool drm_handle_vblank(struct drm_device s64 diff_ns; struct timeval tvblank; unsigned long irqflags; +#ifdef __NetBSD__ /* XXX vblank locking */ + unsigned long irqflags_vbl_lock; +#endif if (!dev->num_crtcs) return false; +#ifdef __NetBSD__ /* XXX vblank locking */ + spin_lock_irqsave(&dev->vbl_lock, irqflags_vbl_lock); +#endif + /* Need timestamp lock to prevent concurrent execution with * vblank enable/disable, as this would cause inconsistent * or corrupted timestamps and vblank counts. @@ -1429,6 +1454,9 @@ bool drm_handle_vblank(struct drm_device /* Vblank irq handling disabled. Nothing to do. */ if (!dev->vblank_enabled[crtc]) { spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); +#ifdef __NetBSD__ /* XXX vblank locking */ + spin_unlock_irqrestore(&dev->vbl_lock, irqflags_vbl_lock); +#endif return false; } @@ -1476,6 +1504,9 @@ bool drm_handle_vblank(struct drm_device drm_handle_vblank_events(dev, crtc); spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); +#ifdef __NetBSD__ /* XXX vblank locking */ + spin_unlock_irqrestore(&dev->vbl_lock, irqflags_vbl_lock); +#endif return true; } EXPORT_SYMBOL(drm_handle_vblank); Index: src/sys/external/bsd/drm2/dist/include/drm/drmP.h diff -u src/sys/external/bsd/drm2/dist/include/drm/drmP.h:1.1.1.1.2.54 src/sys/external/bsd/drm2/dist/include/drm/drmP.h:1.1.1.1.2.55 --- src/sys/external/bsd/drm2/dist/include/drm/drmP.h:1.1.1.1.2.54 Wed Jan 15 13:53:53 2014 +++ src/sys/external/bsd/drm2/dist/include/drm/drmP.h Wed Jan 15 21:25:29 2014 @@ -490,18 +490,13 @@ struct drm_file { #ifdef __NetBSD__ drm_waitqueue_t event_wait; + struct selinfo event_selq; #else wait_queue_head_t event_wait; #endif struct list_head event_list; int event_space; -#ifdef __NetBSD__ -#if 0 /* XXX drm event poll */ - struct selinfo event_sel; -#endif -#endif - struct drm_prime_file_private prime; }; Index: src/sys/external/bsd/drm2/drm/drm_drv.c diff -u src/sys/external/bsd/drm2/drm/drm_drv.c:1.1.2.24 src/sys/external/bsd/drm2/drm/drm_drv.c:1.1.2.25 --- src/sys/external/bsd/drm2/drm/drm_drv.c:1.1.2.24 Wed Jan 15 13:52:30 2014 +++ src/sys/external/bsd/drm2/drm/drm_drv.c Wed Jan 15 21:25:29 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: drm_drv.c,v 1.1.2.24 2014/01/15 13:52:30 riastradh Exp $ */ +/* $NetBSD: drm_drv.c,v 1.1.2.25 2014/01/15 21:25:29 riastradh Exp $ */ /*- * Copyright (c) 2013 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: drm_drv.c,v 1.1.2.24 2014/01/15 13:52:30 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: drm_drv.c,v 1.1.2.25 2014/01/15 21:25:29 riastradh Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -82,7 +82,10 @@ static dev_type_open(drm_open); static int drm_close(struct file *); static int drm_read(struct file *, off_t *, struct uio *, kauth_cred_t, int); +static int drm_dequeue_event(struct drm_file *, size_t, + struct drm_pending_event **, int); static int drm_poll(struct file *, int); +static int drm_kqfilter(struct file *, struct knote *); static int drm_stat(struct file *, struct stat *); static int drm_ioctl(struct file *, unsigned long, void *); static int drm_version_string(char *, size_t *, const char *); @@ -238,7 +241,7 @@ static const struct fileops drm_fileops .fo_poll = drm_poll, .fo_stat = drm_stat, .fo_close = drm_close, - .fo_kqfilter = fnullop_kqfilter, + .fo_kqfilter = drm_kqfilter, .fo_restart = fnullop_restart, }; @@ -500,33 +503,27 @@ drm_close(struct file *fp) return error; } -/* - * XXX According to the old drm port, doing nothing but succeeding in - * drm_read and drm_poll is a kludge for compatibility with old X - * servers. However, it's not clear to me from the drm2 code that this - * is the right thing; in fact, it looks like a load of bollocks. - */ - static int -drm_read(struct file *fp __unused, off_t *off __unused, - struct uio *uio __unused, kauth_cred_t cred __unused, int flags __unused) +drm_read(struct file *fp, off_t *off, struct uio *uio, kauth_cred_t cred, + int flags) { -#if 1 /* XXX drm event poll */ - return 0; -#else - /* XXX How do flags figure into this? */ struct drm_file *const file = fp->f_data; struct drm_pending_event *event; - int error; + bool first; + int error = 0; - if (off != 0) - return EINVAL; + for (first = true; ; first = false) { + int f = 0; + + if (!first || ISSET(fp->f_flag, FNONBLOCK)) + f |= FNONBLOCK; - for (;;) { - error = drm_dequeue_event(file, uio->uio_resid, &event); + /* XXX errno Linux->NetBSD */ + error = -drm_dequeue_event(file, uio->uio_resid, &event, f); if (error) { - /* XXX errno Linux->NetBSD */ - return -error; + if ((error == EWOULDBLOCK) && !first) + error = 0; + break; } if (event == NULL) @@ -534,44 +531,137 @@ drm_read(struct file *fp __unused, off_t error = uiomove(event->event, event->event->length, uio); if (error) /* XXX Requeue the event? */ - return error; + break; } /* Success! */ - return 0; -#endif + return error; +} + +static int +drm_dequeue_event(struct drm_file *file, size_t max_length, + struct drm_pending_event **eventp, int flags) +{ + struct drm_device *const dev = file->minor->dev; + struct drm_pending_event *event = NULL; + unsigned long irqflags; + int ret = 0; + + spin_lock_irqsave(&dev->event_lock, irqflags); + + if (ISSET(flags, FNONBLOCK)) { + if (list_empty(&file->event_list)) + ret = -EWOULDBLOCK; + } else { + DRM_SPIN_WAIT_UNTIL(ret, &file->event_wait, &dev->event_lock, + !list_empty(&file->event_list)); + } + if (ret) + goto out; + + event = list_first_entry(&file->event_list, struct drm_pending_event, + link); + if (event->event->length > max_length) { + ret = 0; + goto out; + } + + file->event_space += event->event->length; + list_del(&event->link); + +out: spin_unlock_irqrestore(&dev->event_lock, irqflags); + *eventp = event; + return ret; } static int drm_poll(struct file *fp __unused, int events __unused) { -#if 1 /* XXX drm event poll */ - /* - * XXX Let's worry about this later. Notifiers need to be - * modified to call selnotify. - */ - return 0; -#else struct drm_file *const file = fp->f_data; + struct drm_device *const dev = file->minor->dev; int revents = 0; - unsigned long flags; + unsigned long irqflags; + + if (!ISSET(events, (POLLIN | POLLRDNORM))) + return 0; - spin_lock_irqsave(&file->minor->dev->event_lock, flags); + spin_lock_irqsave(&dev->event_lock, irqflags); + if (list_empty(&file->event_list)) + selrecord(curlwp, &file->event_selq); + else + revents |= (events & (POLLIN | POLLRDNORM)); + spin_unlock_irqrestore(&dev->event_lock, irqflags); - if (events & (POLLIN | POLLRDNORM)) { - if (!list_empty(&file->event_list)) - revents |= (events & (POLLIN | POLLRDNORM)); - } + return revents; +} - if (revents == 0) { - if (events & (POLLIN | POLLRDNORM)) - selrecord(curlwp, &file->event_sel); +static void filt_drm_detach(struct knote *); +static int filt_drm_event(struct knote *, long); + +static const struct filterops drm_filtops = + { 1, NULL, filt_drm_detach, filt_drm_event }; + +static int +drm_kqfilter(struct file *fp, struct knote *kn) +{ + struct drm_file *const file = fp->f_data; + struct drm_device *const dev = file->minor->dev; + unsigned long irqflags; + + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &drm_filtops; + kn->kn_hook = file; + spin_lock_irqsave(&dev->event_lock, irqflags); + SLIST_INSERT_HEAD(&file->event_selq.sel_klist, kn, kn_selnext); + spin_unlock_irqrestore(&dev->event_lock, irqflags); + return 0; + + case EVFILT_WRITE: + default: + return EINVAL; } +} - spin_unlock_irqrestore(&file->minor->dev->event_lock, flags); +static void +filt_drm_detach(struct knote *kn) +{ + struct drm_file *const file = kn->kn_hook; + struct drm_device *const dev = file->minor->dev; + unsigned long irqflags; - return revents; -#endif + spin_lock_irqsave(&dev->event_lock, irqflags); + SLIST_REMOVE(&file->event_selq.sel_klist, kn, knote, kn_selnext); + spin_unlock_irqrestore(&dev->event_lock, irqflags); +} + +static int +filt_drm_event(struct knote *kn, long hint) +{ + struct drm_file *const file = kn->kn_hook; + struct drm_device *const dev = file->minor->dev; + unsigned long irqflags; + int ret; + + if (hint == NOTE_SUBMIT) + KASSERT(spin_is_locked(&dev->event_lock)); + else + spin_lock_irqsave(&dev->event_lock, irqflags); + if (list_empty(&file->event_list)) { + ret = 0; + } else { + struct drm_pending_event *const event = + list_first_entry(&file->event_list, + struct drm_pending_event, link); + kn->kn_data = event->event->length; + ret = 1; + } + if (hint == NOTE_SUBMIT) + KASSERT(spin_is_locked(&dev->event_lock)); + else + spin_unlock_irqrestore(&dev->event_lock, irqflags); + + return ret; } static int Index: src/sys/external/bsd/drm2/drm/drm_fops.c diff -u src/sys/external/bsd/drm2/drm/drm_fops.c:1.1.2.7 src/sys/external/bsd/drm2/drm/drm_fops.c:1.1.2.8 --- src/sys/external/bsd/drm2/drm/drm_fops.c:1.1.2.7 Wed Jan 15 13:53:53 2014 +++ src/sys/external/bsd/drm2/drm/drm_fops.c Wed Jan 15 21:25:29 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: drm_fops.c,v 1.1.2.7 2014/01/15 13:53:53 riastradh Exp $ */ +/* $NetBSD: drm_fops.c,v 1.1.2.8 2014/01/15 21:25:29 riastradh Exp $ */ /*- * Copyright (c) 2013 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: drm_fops.c,v 1.1.2.7 2014/01/15 13:53:53 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: drm_fops.c,v 1.1.2.8 2014/01/15 21:25:29 riastradh Exp $"); #include <drm/drmP.h> @@ -418,37 +418,3 @@ drm_lastclose_vma(struct drm_device *dev kfree(vma); } } - -#if 0 /* XXX drm event poll */ -int -drm_dequeue_event(struct drm_file *file, size_t max_length, - struct drm_pending_event **eventp) -{ - struct drm_device *const dev = file->minor->dev; - struct drm_pending_event *event = NULL; - unsigned long flags; - int error; - - spin_lock_irqsave(&dev->event_lock, flags); - - DRM_SPIN_WAIT_UNTIL(error, &file->event_wait, &dev->event_lock, - !list_empty(&file->event_list)); - if (error) - goto out; - - event = list_first_entry(&file->event_list, struct drm_pending_event, - link); - if (event->event->length > max_length) { - error = 0; - goto out; - } - - file->event_space += event->event->length; - list_del(&event->link); - -out: - spin_unlock_irqrestore(&dev->event_lock, flags); - *eventp = event; - return error; -} -#endif