vmwgfx: Rework fence event action
Signed-off-by: Jakob Bornecrantz <jakob@vmware.com> Reviewed-by: Thomas Hellstrom <thellstrom@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
parent
8bf42225da
commit
8b7de6aa84
|
@ -657,6 +657,18 @@ int vmw_overlay_unref(struct vmw_private *dev_priv, uint32_t stream_id);
|
||||||
int vmw_overlay_num_overlays(struct vmw_private *dev_priv);
|
int vmw_overlay_num_overlays(struct vmw_private *dev_priv);
|
||||||
int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv);
|
int vmw_overlay_num_free_overlays(struct vmw_private *dev_priv);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fence function - vmwgfx_fence.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
int vmw_event_fence_action_queue(struct drm_file *file_priv,
|
||||||
|
struct vmw_fence_obj *fence,
|
||||||
|
struct drm_pending_event *event,
|
||||||
|
uint32_t *tv_sec,
|
||||||
|
uint32_t *tv_usec,
|
||||||
|
bool interruptible);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GMR Id manager
|
* GMR Id manager
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -69,12 +69,12 @@ struct vmw_user_fence {
|
||||||
* be assigned the current time tv_usec val when the fence signals.
|
* be assigned the current time tv_usec val when the fence signals.
|
||||||
*/
|
*/
|
||||||
struct vmw_event_fence_action {
|
struct vmw_event_fence_action {
|
||||||
struct drm_pending_event e;
|
|
||||||
struct vmw_fence_action action;
|
struct vmw_fence_action action;
|
||||||
|
|
||||||
|
struct drm_pending_event *event;
|
||||||
struct vmw_fence_obj *fence;
|
struct vmw_fence_obj *fence;
|
||||||
struct drm_device *dev;
|
struct drm_device *dev;
|
||||||
struct kref kref;
|
|
||||||
uint32_t size;
|
|
||||||
uint32_t *tv_sec;
|
uint32_t *tv_sec;
|
||||||
uint32_t *tv_usec;
|
uint32_t *tv_usec;
|
||||||
};
|
};
|
||||||
|
@ -783,49 +783,6 @@ int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data,
|
||||||
TTM_REF_USAGE);
|
TTM_REF_USAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* vmw_event_fence_action_destroy
|
|
||||||
*
|
|
||||||
* @kref: The struct kref embedded in a struct vmw_event_fence_action.
|
|
||||||
*
|
|
||||||
* The vmw_event_fence_action destructor that may be called either after
|
|
||||||
* the fence action cleanup, or when the event is delivered.
|
|
||||||
* It frees both the vmw_event_fence_action struct and the actual
|
|
||||||
* event structure copied to user-space.
|
|
||||||
*/
|
|
||||||
static void vmw_event_fence_action_destroy(struct kref *kref)
|
|
||||||
{
|
|
||||||
struct vmw_event_fence_action *eaction =
|
|
||||||
container_of(kref, struct vmw_event_fence_action, kref);
|
|
||||||
struct ttm_mem_global *mem_glob =
|
|
||||||
vmw_mem_glob(vmw_priv(eaction->dev));
|
|
||||||
uint32_t size = eaction->size;
|
|
||||||
|
|
||||||
kfree(eaction->e.event);
|
|
||||||
kfree(eaction);
|
|
||||||
ttm_mem_global_free(mem_glob, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* vmw_event_fence_action_delivered
|
|
||||||
*
|
|
||||||
* @e: The struct drm_pending_event embedded in a struct
|
|
||||||
* vmw_event_fence_action.
|
|
||||||
*
|
|
||||||
* The struct drm_pending_event destructor that is called by drm
|
|
||||||
* once the event is delivered. Since we don't know whether this function
|
|
||||||
* will be called before or after the fence action destructor, we
|
|
||||||
* free a refcount and destroy if it becomes zero.
|
|
||||||
*/
|
|
||||||
static void vmw_event_fence_action_delivered(struct drm_pending_event *e)
|
|
||||||
{
|
|
||||||
struct vmw_event_fence_action *eaction =
|
|
||||||
container_of(e, struct vmw_event_fence_action, e);
|
|
||||||
|
|
||||||
kref_put(&eaction->kref, vmw_event_fence_action_destroy);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vmw_event_fence_action_seq_passed
|
* vmw_event_fence_action_seq_passed
|
||||||
|
@ -836,18 +793,16 @@ static void vmw_event_fence_action_delivered(struct drm_pending_event *e)
|
||||||
* This function is called when the seqno of the fence where @action is
|
* This function is called when the seqno of the fence where @action is
|
||||||
* attached has passed. It queues the event on the submitter's event list.
|
* attached has passed. It queues the event on the submitter's event list.
|
||||||
* This function is always called from atomic context, and may be called
|
* This function is always called from atomic context, and may be called
|
||||||
* from irq context. It ups a refcount reflecting that we now have two
|
* from irq context.
|
||||||
* destructors.
|
|
||||||
*/
|
*/
|
||||||
static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
|
static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
|
||||||
{
|
{
|
||||||
struct vmw_event_fence_action *eaction =
|
struct vmw_event_fence_action *eaction =
|
||||||
container_of(action, struct vmw_event_fence_action, action);
|
container_of(action, struct vmw_event_fence_action, action);
|
||||||
struct drm_device *dev = eaction->dev;
|
struct drm_device *dev = eaction->dev;
|
||||||
struct drm_file *file_priv = eaction->e.file_priv;
|
struct drm_file *file_priv = eaction->event->file_priv;
|
||||||
unsigned long irq_flags;
|
unsigned long irq_flags;
|
||||||
|
|
||||||
kref_get(&eaction->kref);
|
|
||||||
spin_lock_irqsave(&dev->event_lock, irq_flags);
|
spin_lock_irqsave(&dev->event_lock, irq_flags);
|
||||||
|
|
||||||
if (likely(eaction->tv_sec != NULL)) {
|
if (likely(eaction->tv_sec != NULL)) {
|
||||||
|
@ -858,7 +813,7 @@ static void vmw_event_fence_action_seq_passed(struct vmw_fence_action *action)
|
||||||
*eaction->tv_usec = tv.tv_usec;
|
*eaction->tv_usec = tv.tv_usec;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_add_tail(&eaction->e.link, &file_priv->event_list);
|
list_add_tail(&eaction->event->link, &file_priv->event_list);
|
||||||
wake_up_all(&file_priv->event_wait);
|
wake_up_all(&file_priv->event_wait);
|
||||||
spin_unlock_irqrestore(&dev->event_lock, irq_flags);
|
spin_unlock_irqrestore(&dev->event_lock, irq_flags);
|
||||||
}
|
}
|
||||||
|
@ -878,7 +833,7 @@ static void vmw_event_fence_action_cleanup(struct vmw_fence_action *action)
|
||||||
container_of(action, struct vmw_event_fence_action, action);
|
container_of(action, struct vmw_event_fence_action, action);
|
||||||
|
|
||||||
vmw_fence_obj_unreference(&eaction->fence);
|
vmw_fence_obj_unreference(&eaction->fence);
|
||||||
kref_put(&eaction->kref, vmw_event_fence_action_destroy);
|
kfree(eaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -946,39 +901,22 @@ void vmw_fence_obj_add_action(struct vmw_fence_obj *fence,
|
||||||
* an error code, the caller needs to free that object.
|
* an error code, the caller needs to free that object.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int vmw_event_fence_action_create(struct drm_file *file_priv,
|
int vmw_event_fence_action_queue(struct drm_file *file_priv,
|
||||||
struct vmw_fence_obj *fence,
|
struct vmw_fence_obj *fence,
|
||||||
struct drm_event *event,
|
struct drm_pending_event *event,
|
||||||
uint32_t *tv_sec,
|
uint32_t *tv_sec,
|
||||||
uint32_t *tv_usec,
|
uint32_t *tv_usec,
|
||||||
bool interruptible)
|
bool interruptible)
|
||||||
{
|
{
|
||||||
struct vmw_event_fence_action *eaction;
|
struct vmw_event_fence_action *eaction;
|
||||||
struct ttm_mem_global *mem_glob =
|
|
||||||
vmw_mem_glob(fence->fman->dev_priv);
|
|
||||||
struct vmw_fence_manager *fman = fence->fman;
|
struct vmw_fence_manager *fman = fence->fman;
|
||||||
uint32_t size = fman->event_fence_action_size +
|
|
||||||
ttm_round_pot(event->length);
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Account for internal structure size as well as the
|
|
||||||
* event size itself.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ret = ttm_mem_global_alloc(mem_glob, size, false, interruptible);
|
|
||||||
if (unlikely(ret != 0))
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
eaction = kzalloc(sizeof(*eaction), GFP_KERNEL);
|
eaction = kzalloc(sizeof(*eaction), GFP_KERNEL);
|
||||||
if (unlikely(eaction == NULL)) {
|
if (unlikely(eaction == NULL))
|
||||||
ttm_mem_global_free(mem_glob, size);
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
|
|
||||||
eaction->e.event = event;
|
eaction->event = event;
|
||||||
eaction->e.file_priv = file_priv;
|
|
||||||
eaction->e.destroy = vmw_event_fence_action_delivered;
|
|
||||||
|
|
||||||
eaction->action.seq_passed = vmw_event_fence_action_seq_passed;
|
eaction->action.seq_passed = vmw_event_fence_action_seq_passed;
|
||||||
eaction->action.cleanup = vmw_event_fence_action_cleanup;
|
eaction->action.cleanup = vmw_event_fence_action_cleanup;
|
||||||
|
@ -986,16 +924,85 @@ int vmw_event_fence_action_create(struct drm_file *file_priv,
|
||||||
|
|
||||||
eaction->fence = vmw_fence_obj_reference(fence);
|
eaction->fence = vmw_fence_obj_reference(fence);
|
||||||
eaction->dev = fman->dev_priv->dev;
|
eaction->dev = fman->dev_priv->dev;
|
||||||
eaction->size = size;
|
|
||||||
eaction->tv_sec = tv_sec;
|
eaction->tv_sec = tv_sec;
|
||||||
eaction->tv_usec = tv_usec;
|
eaction->tv_usec = tv_usec;
|
||||||
|
|
||||||
kref_init(&eaction->kref);
|
|
||||||
vmw_fence_obj_add_action(fence, &eaction->action);
|
vmw_fence_obj_add_action(fence, &eaction->action);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct vmw_event_fence_pending {
|
||||||
|
struct drm_pending_event base;
|
||||||
|
struct drm_vmw_event_fence event;
|
||||||
|
};
|
||||||
|
|
||||||
|
int vmw_event_fence_action_create(struct drm_file *file_priv,
|
||||||
|
struct vmw_fence_obj *fence,
|
||||||
|
uint32_t flags,
|
||||||
|
uint64_t user_data,
|
||||||
|
bool interruptible)
|
||||||
|
{
|
||||||
|
struct vmw_event_fence_pending *event;
|
||||||
|
struct drm_device *dev = fence->fman->dev_priv->dev;
|
||||||
|
unsigned long irq_flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dev->event_lock, irq_flags);
|
||||||
|
|
||||||
|
ret = (file_priv->event_space < sizeof(event->event)) ? -EBUSY : 0;
|
||||||
|
if (likely(ret == 0))
|
||||||
|
file_priv->event_space -= sizeof(event->event);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&dev->event_lock, irq_flags);
|
||||||
|
|
||||||
|
if (unlikely(ret != 0)) {
|
||||||
|
DRM_ERROR("Failed to allocate event space for this file.\n");
|
||||||
|
goto out_no_space;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
event = kzalloc(sizeof(event->event), GFP_KERNEL);
|
||||||
|
if (unlikely(event == NULL)) {
|
||||||
|
DRM_ERROR("Failed to allocate an event.\n");
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto out_no_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
event->event.base.type = DRM_VMW_EVENT_FENCE_SIGNALED;
|
||||||
|
event->event.base.length = sizeof(*event);
|
||||||
|
event->event.user_data = user_data;
|
||||||
|
|
||||||
|
event->base.event = &event->event.base;
|
||||||
|
event->base.file_priv = file_priv;
|
||||||
|
event->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
|
||||||
|
|
||||||
|
|
||||||
|
if (flags & DRM_VMW_FE_FLAG_REQ_TIME)
|
||||||
|
ret = vmw_event_fence_action_queue(file_priv, fence,
|
||||||
|
&event->base,
|
||||||
|
&event->event.tv_sec,
|
||||||
|
&event->event.tv_usec,
|
||||||
|
interruptible);
|
||||||
|
else
|
||||||
|
ret = vmw_event_fence_action_queue(file_priv, fence,
|
||||||
|
&event->base,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
interruptible);
|
||||||
|
if (ret != 0)
|
||||||
|
goto out_no_queue;
|
||||||
|
|
||||||
|
out_no_queue:
|
||||||
|
event->base.destroy(&event->base);
|
||||||
|
out_no_event:
|
||||||
|
spin_lock_irqsave(&dev->event_lock, irq_flags);
|
||||||
|
file_priv->event_space += sizeof(*event);
|
||||||
|
spin_unlock_irqrestore(&dev->event_lock, irq_flags);
|
||||||
|
out_no_space:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
|
int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
|
||||||
struct drm_file *file_priv)
|
struct drm_file *file_priv)
|
||||||
{
|
{
|
||||||
|
@ -1008,8 +1015,6 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
|
||||||
(struct drm_vmw_fence_rep __user *)(unsigned long)
|
(struct drm_vmw_fence_rep __user *)(unsigned long)
|
||||||
arg->fence_rep;
|
arg->fence_rep;
|
||||||
uint32_t handle;
|
uint32_t handle;
|
||||||
unsigned long irq_flags;
|
|
||||||
struct drm_vmw_event_fence *event;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1062,59 +1067,28 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
|
||||||
|
|
||||||
BUG_ON(fence == NULL);
|
BUG_ON(fence == NULL);
|
||||||
|
|
||||||
spin_lock_irqsave(&dev->event_lock, irq_flags);
|
|
||||||
|
|
||||||
ret = (file_priv->event_space < sizeof(*event)) ? -EBUSY : 0;
|
|
||||||
if (likely(ret == 0))
|
|
||||||
file_priv->event_space -= sizeof(*event);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dev->event_lock, irq_flags);
|
|
||||||
|
|
||||||
if (unlikely(ret != 0)) {
|
|
||||||
DRM_ERROR("Failed to allocate event space for this file.\n");
|
|
||||||
goto out_no_event_space;
|
|
||||||
}
|
|
||||||
|
|
||||||
event = kzalloc(sizeof(*event), GFP_KERNEL);
|
|
||||||
if (unlikely(event == NULL)) {
|
|
||||||
DRM_ERROR("Failed to allocate an event.\n");
|
|
||||||
goto out_no_event;
|
|
||||||
}
|
|
||||||
|
|
||||||
event->base.type = DRM_VMW_EVENT_FENCE_SIGNALED;
|
|
||||||
event->base.length = sizeof(*event);
|
|
||||||
event->user_data = arg->user_data;
|
|
||||||
|
|
||||||
if (arg->flags & DRM_VMW_FE_FLAG_REQ_TIME)
|
if (arg->flags & DRM_VMW_FE_FLAG_REQ_TIME)
|
||||||
ret = vmw_event_fence_action_create(file_priv, fence,
|
ret = vmw_event_fence_action_create(file_priv, fence,
|
||||||
&event->base,
|
arg->flags,
|
||||||
&event->tv_sec,
|
arg->user_data,
|
||||||
&event->tv_usec,
|
|
||||||
true);
|
true);
|
||||||
else
|
else
|
||||||
ret = vmw_event_fence_action_create(file_priv, fence,
|
ret = vmw_event_fence_action_create(file_priv, fence,
|
||||||
&event->base,
|
arg->flags,
|
||||||
NULL,
|
arg->user_data,
|
||||||
NULL,
|
|
||||||
true);
|
true);
|
||||||
|
|
||||||
if (unlikely(ret != 0)) {
|
if (unlikely(ret != 0)) {
|
||||||
if (ret != -ERESTARTSYS)
|
if (ret != -ERESTARTSYS)
|
||||||
DRM_ERROR("Failed to attach event to fence.\n");
|
DRM_ERROR("Failed to attach event to fence.\n");
|
||||||
goto out_no_attach;
|
goto out_no_create;
|
||||||
}
|
}
|
||||||
|
|
||||||
vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
|
vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
|
||||||
handle);
|
handle);
|
||||||
vmw_fence_obj_unreference(&fence);
|
vmw_fence_obj_unreference(&fence);
|
||||||
return 0;
|
return 0;
|
||||||
out_no_attach:
|
out_no_create:
|
||||||
kfree(event);
|
|
||||||
out_no_event:
|
|
||||||
spin_lock_irqsave(&dev->event_lock, irq_flags);
|
|
||||||
file_priv->event_space += sizeof(*event);
|
|
||||||
spin_unlock_irqrestore(&dev->event_lock, irq_flags);
|
|
||||||
out_no_event_space:
|
|
||||||
if (user_fence_rep != NULL)
|
if (user_fence_rep != NULL)
|
||||||
ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
|
ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
|
||||||
handle, TTM_REF_USAGE);
|
handle, TTM_REF_USAGE);
|
||||||
|
|
Loading…
Reference in New Issue