diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-01-11 16:40:56 -0500 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2016-01-25 02:40:09 -0500 |
commit | 2dd500f1870e3d852488c9b30c4ecec91c6e2eea (patch) | |
tree | ab58eb47a5003abad8f12d03d4a1b40a1c12292f | |
parent | bcb877e4dcf21c3ba486fd7cc563126f08c39b8a (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.c | 44 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_crtc.c | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/drm_fops.c | 67 | ||||
-rw-r--r-- | include/drm/drmP.h | 7 |
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 | |||
1375 | out: | ||
1376 | return e; | ||
1377 | } | ||
1378 | 1359 | ||
1379 | static 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 | ||
1390 | static int atomic_set_prop(struct drm_atomic_state *state, | 1369 | static 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 | } |
678 | EXPORT_SYMBOL(drm_poll); | 678 | EXPORT_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 | */ | ||
699 | int 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 | |||
722 | out: | ||
723 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
724 | return ret; | ||
725 | } | ||
726 | EXPORT_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 | */ | ||
736 | void 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 | } | ||
745 | EXPORT_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); |
926 | int drm_release(struct inode *inode, struct file *filp); | 926 | int drm_release(struct inode *inode, struct file *filp); |
927 | int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv); | 927 | int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv); |
928 | |||
929 | unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); | 928 | unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); |
929 | int 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); | ||
933 | void 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) */ |
932 | int drm_noop(struct drm_device *dev, void *data, | 937 | int drm_noop(struct drm_device *dev, void *data, |