Commit 2dd500f1 authored by Daniel Vetter's avatar Daniel Vetter

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: default avatarDaniel Stone <daniels@collabora.com>
Reviewed-by: default avatarAlex 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.chReviewed-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@intel.com>
parent bcb877e4
...@@ -1347,44 +1347,23 @@ static struct drm_pending_vblank_event *create_vblank_event( ...@@ -1347,44 +1347,23 @@ static struct drm_pending_vblank_event *create_vblank_event(
struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data) struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data)
{ {
struct drm_pending_vblank_event *e = NULL; struct drm_pending_vblank_event *e = NULL;
unsigned long flags; int ret;
spin_lock_irqsave(&dev->event_lock, flags);
if (file_priv->event_space < sizeof e->event) {
spin_unlock_irqrestore(&dev->event_lock, flags);
goto out;
}
file_priv->event_space -= sizeof e->event;
spin_unlock_irqrestore(&dev->event_lock, flags);
e = kzalloc(sizeof *e, GFP_KERNEL); e = kzalloc(sizeof *e, GFP_KERNEL);
if (e == NULL) { if (!e)
spin_lock_irqsave(&dev->event_lock, flags); return NULL;
file_priv->event_space += sizeof e->event;
spin_unlock_irqrestore(&dev->event_lock, flags);
goto out;
}
e->event.base.type = DRM_EVENT_FLIP_COMPLETE; e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
e->event.base.length = sizeof e->event; e->event.base.length = sizeof(e->event);
e->event.user_data = user_data; e->event.user_data = user_data;
e->base.event = &e->event.base;
e->base.file_priv = file_priv;
e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
out:
return e;
}
static void destroy_vblank_event(struct drm_device *dev, ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
struct drm_file *file_priv, struct drm_pending_vblank_event *e) if (ret) {
{ kfree(e);
unsigned long flags; return NULL;
}
spin_lock_irqsave(&dev->event_lock, flags); return e;
file_priv->event_space += sizeof e->event;
spin_unlock_irqrestore(&dev->event_lock, flags);
kfree(e);
} }
static int atomic_set_prop(struct drm_atomic_state *state, static int atomic_set_prop(struct drm_atomic_state *state,
...@@ -1646,8 +1625,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev, ...@@ -1646,8 +1625,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
if (!crtc_state->event) if (!crtc_state->event)
continue; continue;
destroy_vblank_event(dev, file_priv, drm_event_cancel_free(dev, &crtc_state->event->base);
crtc_state->event);
} }
} }
......
...@@ -5265,7 +5265,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, ...@@ -5265,7 +5265,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
struct drm_crtc *crtc; struct drm_crtc *crtc;
struct drm_framebuffer *fb = NULL; struct drm_framebuffer *fb = NULL;
struct drm_pending_vblank_event *e = NULL; struct drm_pending_vblank_event *e = NULL;
unsigned long flags;
int ret = -EINVAL; int ret = -EINVAL;
if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS || if (page_flip->flags & ~DRM_MODE_PAGE_FLIP_FLAGS ||
...@@ -5316,41 +5315,26 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, ...@@ -5316,41 +5315,26 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
} }
if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
ret = -ENOMEM; e = kzalloc(sizeof *e, GFP_KERNEL);
spin_lock_irqsave(&dev->event_lock, flags); if (!e) {
if (file_priv->event_space < sizeof(e->event)) { ret = -ENOMEM;
spin_unlock_irqrestore(&dev->event_lock, flags);
goto out;
}
file_priv->event_space -= sizeof(e->event);
spin_unlock_irqrestore(&dev->event_lock, flags);
e = kzalloc(sizeof(*e), GFP_KERNEL);
if (e == NULL) {
spin_lock_irqsave(&dev->event_lock, flags);
file_priv->event_space += sizeof(e->event);
spin_unlock_irqrestore(&dev->event_lock, flags);
goto out; goto out;
} }
e->event.base.type = DRM_EVENT_FLIP_COMPLETE; e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
e->event.base.length = sizeof(e->event); e->event.base.length = sizeof(e->event);
e->event.user_data = page_flip->user_data; e->event.user_data = page_flip->user_data;
e->base.event = &e->event.base; ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
e->base.file_priv = file_priv; if (ret) {
e->base.destroy = kfree(e);
(void (*) (struct drm_pending_event *)) kfree; goto out;
}
} }
crtc->primary->old_fb = crtc->primary->fb; crtc->primary->old_fb = crtc->primary->fb;
ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
if (ret) { if (ret) {
if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT)
spin_lock_irqsave(&dev->event_lock, flags); drm_event_cancel_free(dev, &e->base);
file_priv->event_space += sizeof(e->event);
spin_unlock_irqrestore(&dev->event_lock, flags);
kfree(e);
}
/* Keep the old fb, don't unref it. */ /* Keep the old fb, don't unref it. */
crtc->primary->old_fb = NULL; crtc->primary->old_fb = NULL;
} else { } else {
......
...@@ -676,3 +676,70 @@ unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) ...@@ -676,3 +676,70 @@ unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
return mask; return mask;
} }
EXPORT_SYMBOL(drm_poll); EXPORT_SYMBOL(drm_poll);
/**
* drm_event_reserve_init - init a DRM event and reserve space for it
* @dev: DRM device
* @file_priv: DRM file private data
* @p: tracking structure for the pending event
* @e: actual event data to deliver to userspace
*
* This function prepares the passed in event for eventual delivery. If the event
* doesn't get delivered (because the IOCTL fails later on, before queuing up
* anything) then the even must be cancelled and freed using
* drm_event_cancel_free().
*
* If callers embedded @p into a larger structure it must be allocated with
* kmalloc and @p must be the first member element.
*
* RETURNS:
*
* 0 on success or a negative error code on failure.
*/
int drm_event_reserve_init(struct drm_device *dev,
struct drm_file *file_priv,
struct drm_pending_event *p,
struct drm_event *e)
{
unsigned long flags;
int ret = 0;
spin_lock_irqsave(&dev->event_lock, flags);
if (file_priv->event_space < e->length) {
ret = -ENOMEM;
goto out;
}
file_priv->event_space -= e->length;
p->event = e;
p->file_priv = file_priv;
/* we *could* pass this in as arg, but everyone uses kfree: */
p->destroy = (void (*) (struct drm_pending_event *)) kfree;
out:
spin_unlock_irqrestore(&dev->event_lock, flags);
return ret;
}
EXPORT_SYMBOL(drm_event_reserve_init);
/**
* drm_event_cancel_free - free a DRM event and release it's space
* @dev: DRM device
* @p: tracking structure for the pending event
*
* This function frees the event @p initialized with drm_event_reserve_init()
* and releases any allocated space.
*/
void drm_event_cancel_free(struct drm_device *dev,
struct drm_pending_event *p)
{
unsigned long flags;
spin_lock_irqsave(&dev->event_lock, flags);
p->file_priv->event_space += p->event->length;
spin_unlock_irqrestore(&dev->event_lock, flags);
p->destroy(p);
}
EXPORT_SYMBOL(drm_event_cancel_free);
...@@ -925,8 +925,13 @@ ssize_t drm_read(struct file *filp, char __user *buffer, ...@@ -925,8 +925,13 @@ ssize_t drm_read(struct file *filp, char __user *buffer,
size_t count, loff_t *offset); size_t count, loff_t *offset);
int drm_release(struct inode *inode, struct file *filp); int drm_release(struct inode *inode, struct file *filp);
int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv); int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv);
unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait); unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
int drm_event_reserve_init(struct drm_device *dev,
struct drm_file *file_priv,
struct drm_pending_event *p,
struct drm_event *e);
void drm_event_cancel_free(struct drm_device *dev,
struct drm_pending_event *p);
/* Misc. IOCTL support (drm_ioctl.c) */ /* Misc. IOCTL support (drm_ioctl.c) */
int drm_noop(struct drm_device *dev, void *data, int drm_noop(struct drm_device *dev, void *data,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment