aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2016-01-11 16:40:56 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2016-01-25 02:40:09 -0500
commit2dd500f1870e3d852488c9b30c4ecec91c6e2eea (patch)
treeab58eb47a5003abad8f12d03d4a1b40a1c12292f
parentbcb877e4dcf21c3ba486fd7cc563126f08c39b8a (diff)
drm: Add functions to setup/tear down drm_events.
An attempt at not spreading out the file_priv->event_space stuff out quite so far and wide. And I think fixes something in ipp_get_event() that is broken (or if they are doing something more weird/subtle, then breaks it in a fun way). Based upon a patch from Rob Clark, rebased and polished. v2: Spelling fixes (Alex). Cc: Alex Deucher <alexdeucher@gmail.com> Acked-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Cc: Rob Clark <robdclark@gmail.com> Link: http://patchwork.freedesktop.org/patch/msgid/1452548477-15905-3-git-send-email-daniel.vetter@ffwll.ch Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
-rw-r--r--drivers/gpu/drm/drm_atomic.c44
-rw-r--r--drivers/gpu/drm/drm_crtc.c36
-rw-r--r--drivers/gpu/drm/drm_fops.c67
-rw-r--r--include/drm/drmP.h7
4 files changed, 94 insertions, 60 deletions
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 3f74193885f1..8fb469c4e4b8 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1347,44 +1347,23 @@ static struct drm_pending_vblank_event *create_vblank_event(
1347 struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data) 1347 struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data)
1348{ 1348{
1349 struct drm_pending_vblank_event *e = NULL; 1349 struct drm_pending_vblank_event *e = NULL;
1350 unsigned long flags; 1350 int ret;
1351
1352 spin_lock_irqsave(&dev->event_lock, flags);
1353 if (file_priv->event_space < sizeof e->event) {
1354 spin_unlock_irqrestore(&dev->event_lock, flags);
1355 goto out;
1356 }
1357 file_priv->event_space -= sizeof e->event;
1358 spin_unlock_irqrestore(&dev->event_lock, flags);
1359 1351
1360 e = kzalloc(sizeof *e, GFP_KERNEL); 1352 e = kzalloc(sizeof *e, GFP_KERNEL);
1361 if (e == NULL) { 1353 if (!e)
1362 spin_lock_irqsave(&dev->event_lock, flags); 1354 return NULL;
1363 file_priv->event_space += sizeof e->event;
1364 spin_unlock_irqrestore(&dev->event_lock, flags);
1365 goto out;
1366 }
1367 1355
1368 e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 1356 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
1369 e->event.base.length = sizeof e->event; 1357 e->event.base.length = sizeof(e->event);
1370 e->event.user_data = user_data; 1358 e->event.user_data = user_data;
1371 e->base.event = &e->event.base;
1372 e->base.file_priv = file_priv;
1373 e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
1374
1375out:
1376 return e;
1377}
1378 1359
1379static void destroy_vblank_event(struct drm_device *dev, 1360 ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
1380 struct drm_file *file_priv, struct drm_pending_vblank_event *e) 1361 if (ret) {
1381{ 1362 kfree(e);
1382 unsigned long flags; 1363 return NULL;
1364 }
1383 1365
1384 spin_lock_irqsave(&dev->event_lock, flags); 1366 return e;
1385 file_priv->event_space += sizeof e->event;
1386 spin_unlock_irqrestore(&dev->event_lock, flags);
1387 kfree(e);
1388} 1367}
1389 1368
1390static int atomic_set_prop(struct drm_atomic_state *state, 1369static int atomic_set_prop(struct drm_atomic_state *state,
@@ -1646,8 +1625,7 @@ out:
1646 if (!crtc_state->event) 1625 if (!crtc_state->event)
1647 continue; 1626 continue;
1648 1627
1649 destroy_vblank_event(dev, file_priv, 1628 drm_event_cancel_free(dev, &crtc_state->event->base);
1650 crtc_state->event);
1651 } 1629 }
1652 } 1630 }
1653 1631
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index d40bab29747e..6e6514ef9968 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -5265,7 +5265,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
5265 struct drm_crtc *crtc; 5265 struct drm_crtc *crtc;
5266 struct drm_framebuffer *fb = NULL; 5266 struct drm_framebuffer *fb = NULL;
5267 struct drm_pending_vblank_event *e = NULL; 5267 struct drm_pending_vblank_event *e = NULL;
5268 unsigned long flags;
5269 int ret = -EINVAL; 5268 int ret = -EINVAL;
5270 5269
5271 if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || 5270 if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
@@ -5316,41 +5315,26 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
5316 } 5315 }
5317 5316
5318 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 5317 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
5319 ret = -ENOMEM; 5318 e = kzalloc(sizeof *e, GFP_KERNEL);
5320 spin_lock_irqsave(&dev->event_lock, flags); 5319 if (!e) {
5321 if (file_priv->event_space < sizeof(e->event)) { 5320 ret = -ENOMEM;
5322 spin_unlock_irqrestore(&dev->event_lock, flags);
5323 goto out;
5324 }
5325 file_priv->event_space -= sizeof(e->event);
5326 spin_unlock_irqrestore(&dev->event_lock, flags);
5327
5328 e = kzalloc(sizeof(*e), GFP_KERNEL);
5329 if (e == NULL) {
5330 spin_lock_irqsave(&dev->event_lock, flags);
5331 file_priv->event_space += sizeof(e->event);
5332 spin_unlock_irqrestore(&dev->event_lock, flags);
5333 goto out; 5321 goto out;
5334 } 5322 }
5335
5336 e->event.base.type = DRM_EVENT_FLIP_COMPLETE; 5323 e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
5337 e->event.base.length = sizeof(e->event); 5324 e->event.base.length = sizeof(e->event);
5338 e->event.user_data = page_flip->user_data; 5325 e->event.user_data = page_flip->user_data;
5339 e->base.event = &e->event.base; 5326 ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
5340 e->base.file_priv = file_priv; 5327 if (ret) {
5341 e->base.destroy = 5328 kfree(e);
5342 (void (*) (struct drm_pending_event *)) kfree; 5329 goto out;
5330 }
5343 } 5331 }
5344 5332
5345 crtc->primary->old_fb = crtc->primary->fb; 5333 crtc->primary->old_fb = crtc->primary->fb;
5346 ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); 5334 ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
5347 if (ret) { 5335 if (ret) {
5348 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { 5336 if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
5349 spin_lock_irqsave(&dev->event_lock, flags); 5337 drm_event_cancel_free(dev, &e->base);
5350 file_priv->event_space += sizeof(e->event);
5351 spin_unlock_irqrestore(&dev->event_lock, flags);
5352 kfree(e);
5353 }
5354 /* Keep the old fb, don't unref it. */ 5338 /* Keep the old fb, don't unref it. */
5355 crtc->primary->old_fb = NULL; 5339 crtc->primary->old_fb = NULL;
5356 } else { 5340 } else {
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 1551d65db24e..f9eacbb2d1dd 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -676,3 +676,70 @@ unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
676 return mask; 676 return mask;
677} 677}
678EXPORT_SYMBOL(drm_poll); 678EXPORT_SYMBOL(drm_poll);
679
680/**
681 * drm_event_reserve_init - init a DRM event and reserve space for it
682 * @dev: DRM device
683 * @file_priv: DRM file private data
684 * @p: tracking structure for the pending event
685 * @e: actual event data to deliver to userspace
686 *
687 * This function prepares the passed in event for eventual delivery. If the event
688 * doesn't get delivered (because the IOCTL fails later on, before queuing up
689 * anything) then the even must be cancelled and freed using
690 * drm_event_cancel_free().
691 *
692 * If callers embedded @p into a larger structure it must be allocated with
693 * kmalloc and @p must be the first member element.
694 *
695 * RETURNS:
696 *
697 * 0 on success or a negative error code on failure.
698 */
699int drm_event_reserve_init(struct drm_device *dev,
700 struct drm_file *file_priv,
701 struct drm_pending_event *p,
702 struct drm_event *e)
703{
704 unsigned long flags;
705 int ret = 0;
706
707 spin_lock_irqsave(&dev->event_lock, flags);
708
709 if (file_priv->event_space < e->length) {
710 ret = -ENOMEM;
711 goto out;
712 }
713
714 file_priv->event_space -= e->length;
715
716 p->event = e;
717 p->file_priv = file_priv;
718
719 /* we *could* pass this in as arg, but everyone uses kfree: */
720 p->destroy = (void (*) (struct drm_pending_event *)) kfree;
721
722out:
723 spin_unlock_irqrestore(&dev->event_lock, flags);
724 return ret;
725}
726EXPORT_SYMBOL(drm_event_reserve_init);
727
728/**
729 * drm_event_cancel_free - free a DRM event and release it's space
730 * @dev: DRM device
731 * @p: tracking structure for the pending event
732 *
733 * This function frees the event @p initialized with drm_event_reserve_init()
734 * and releases any allocated space.
735 */
736void drm_event_cancel_free(struct drm_device *dev,
737 struct drm_pending_event *p)
738{
739 unsigned long flags;
740 spin_lock_irqsave(&dev->event_lock, flags);
741 p->file_priv->event_space += p->event->length;
742 spin_unlock_irqrestore(&dev->event_lock, flags);
743 p->destroy(p);
744}
745EXPORT_SYMBOL(drm_event_cancel_free);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index a46a34fc67b3..04a66468e6e0 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -925,8 +925,13 @@ ssize_t drm_read(struct file *filp, char __user *buffer,
925 size_t count, loff_t *offset); 925 size_t count, loff_t *offset);
926int drm_release(struct inode *inode, struct file *filp); 926int drm_release(struct inode *inode, struct file *filp);
927int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv); 927int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv);
928
929unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); 928unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
929int drm_event_reserve_init(struct drm_device *dev,
930 struct drm_file *file_priv,
931 struct drm_pending_event *p,
932 struct drm_event *e);
933void drm_event_cancel_free(struct drm_device *dev,
934 struct drm_pending_event *p);
930 935
931/* Misc. IOCTL support (drm_ioctl.c) */ 936/* Misc. IOCTL support (drm_ioctl.c) */
932int drm_noop(struct drm_device *dev, void *data, 937int drm_noop(struct drm_device *dev, void *data,