Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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.ch


Reviewed-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@intel.com>
parent bcb877e4
Loading
Loading
Loading
Loading
+11 −33
Original line number Original line Diff line number Diff line
@@ -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:
	ret = drm_event_reserve_init(dev, file_priv, &e->base, &e->event.base);
	return e;
	if (ret) {
		kfree(e);
		return NULL;
	}
	}


static void destroy_vblank_event(struct drm_device *dev,
	return e;
		struct drm_file *file_priv, struct drm_pending_vblank_event *e)
{
	unsigned long flags;

	spin_lock_irqsave(&dev->event_lock, flags);
	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,
			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);
		}
		}
	}
	}


+10 −26
Original line number Original line Diff line number Diff line
@@ -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,
	}
	}


	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
	if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
		e = kzalloc(sizeof *e, GFP_KERNEL);
		if (!e) {
			ret = -ENOMEM;
			ret = -ENOMEM;
		spin_lock_irqsave(&dev->event_lock, flags);
		if (file_priv->event_space < sizeof(e->event)) {
			spin_unlock_irqrestore(&dev->event_lock, flags);
			goto out;
			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;
		}

		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 {
+67 −0
Original line number Original line Diff line number Diff line
@@ -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);
+6 −1
Original line number Original line Diff line number Diff line
@@ -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,