Commit 4020b220 authored by Daniel Vetter's avatar Daniel Vetter

drm/vblank: Use drm_event_reserve_init

Well we can't use that directly since that code must hold
dev->event_lock already. Extract an _unlocked version.

Embarrassingly I've totally forgotten about this patch and any kind of
event-based vblank wait totally blew up, killing the kernel.

v2: Pick the right base struct, someone didn't noticed that gcc was
unhappy. No bug since the addresses at least matched (Daniel Stone)

Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: Daniel Stone <daniels@collabora.com>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: default avatarDaniel Stone <daniels@collabora.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1453978864-1513-1-git-send-email-daniel.vetter@ffwll.ch
parent 15b6b804
...@@ -678,7 +678,7 @@ unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait) ...@@ -678,7 +678,7 @@ unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
EXPORT_SYMBOL(drm_poll); EXPORT_SYMBOL(drm_poll);
/** /**
* drm_event_reserve_init - init a DRM event and reserve space for it * drm_event_reserve_init_locked - init a DRM event and reserve space for it
* @dev: DRM device * @dev: DRM device
* @file_priv: DRM file private data * @file_priv: DRM file private data
* @p: tracking structure for the pending event * @p: tracking structure for the pending event
...@@ -694,24 +694,20 @@ EXPORT_SYMBOL(drm_poll); ...@@ -694,24 +694,20 @@ EXPORT_SYMBOL(drm_poll);
* If callers embedded @p into a larger structure it must be allocated with * If callers embedded @p into a larger structure it must be allocated with
* kmalloc and @p must be the first member element. * kmalloc and @p must be the first member element.
* *
* This is the locked version of drm_event_reserve_init() for callers which
* already hold dev->event_lock.
*
* RETURNS: * RETURNS:
* *
* 0 on success or a negative error code on failure. * 0 on success or a negative error code on failure.
*/ */
int drm_event_reserve_init(struct drm_device *dev, int drm_event_reserve_init_locked(struct drm_device *dev,
struct drm_file *file_priv, struct drm_file *file_priv,
struct drm_pending_event *p, struct drm_pending_event *p,
struct drm_event *e) struct drm_event *e)
{ {
unsigned long flags; if (file_priv->event_space < e->length)
int ret = 0; return -ENOMEM;
spin_lock_irqsave(&dev->event_lock, flags);
if (file_priv->event_space < e->length) {
ret = -ENOMEM;
goto out;
}
file_priv->event_space -= e->length; file_priv->event_space -= e->length;
...@@ -721,8 +717,46 @@ int drm_event_reserve_init(struct drm_device *dev, ...@@ -721,8 +717,46 @@ int drm_event_reserve_init(struct drm_device *dev,
/* we *could* pass this in as arg, but everyone uses kfree: */ /* we *could* pass this in as arg, but everyone uses kfree: */
p->destroy = (void (*) (struct drm_pending_event *)) kfree; p->destroy = (void (*) (struct drm_pending_event *)) kfree;
out: return 0;
}
EXPORT_SYMBOL(drm_event_reserve_init_locked);
/**
* 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(). Successfully initialized events should be sent out
* using drm_send_event() or drm_send_event_locked() to signal completion of the
* asynchronous event to userspace.
*
* If callers embedded @p into a larger structure it must be allocated with
* kmalloc and @p must be the first member element.
*
* Callers which already hold dev->event_lock should use
* drm_event_reserve_init() instead.
*
* 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;
spin_lock_irqsave(&dev->event_lock, flags);
ret = drm_event_reserve_init_locked(dev, file_priv, p, e);
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
return ret; return ret;
} }
EXPORT_SYMBOL(drm_event_reserve_init); EXPORT_SYMBOL(drm_event_reserve_init);
......
...@@ -1598,9 +1598,6 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, ...@@ -1598,9 +1598,6 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe,
e->event.base.type = DRM_EVENT_VBLANK; e->event.base.type = DRM_EVENT_VBLANK;
e->event.base.length = sizeof(e->event); e->event.base.length = sizeof(e->event);
e->event.user_data = vblwait->request.signal; e->event.user_data = vblwait->request.signal;
e->base.event = &e->event.base;
e->base.file_priv = file_priv;
e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
...@@ -1616,12 +1613,12 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe, ...@@ -1616,12 +1613,12 @@ static int drm_queue_vblank_event(struct drm_device *dev, unsigned int pipe,
goto err_unlock; goto err_unlock;
} }
if (file_priv->event_space < sizeof(e->event)) { ret = drm_event_reserve_init_locked(dev, file_priv, &e->base,
ret = -EBUSY; &e->event.base);
if (ret)
goto err_unlock; goto err_unlock;
}
file_priv->event_space -= sizeof(e->event);
seq = drm_vblank_count_and_time(dev, pipe, &now); seq = drm_vblank_count_and_time(dev, pipe, &now);
if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) && if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&
......
...@@ -926,6 +926,10 @@ ssize_t drm_read(struct file *filp, char __user *buffer, ...@@ -926,6 +926,10 @@ ssize_t drm_read(struct file *filp, char __user *buffer,
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_locked(struct drm_device *dev,
struct drm_file *file_priv,
struct drm_pending_event *p,
struct drm_event *e);
int drm_event_reserve_init(struct drm_device *dev, int drm_event_reserve_init(struct drm_device *dev,
struct drm_file *file_priv, struct drm_file *file_priv,
struct drm_pending_event *p, struct drm_pending_event *p,
......
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