diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 6f1120de..1abcc585 100755 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved. +/* Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -55,12 +55,14 @@ static struct ion_client *kgsl_ion_client; * @ts - the timestamp to trigger the event on * @cb - callback function to call when the timestamp expires * @priv - private data for the specific event type + * @owner - driver instance that owns this event * * @returns - 0 on success or error code on failure */ static int kgsl_add_event(struct kgsl_device *device, u32 ts, - void (*cb)(struct kgsl_device *, void *, u32), void *priv) + void (*cb)(struct kgsl_device *, void *, u32), void *priv, + struct kgsl_device_private *owner) { struct kgsl_event *event; struct list_head *n; @@ -84,6 +86,7 @@ static int kgsl_add_event(struct kgsl_device *device, u32 ts, event->timestamp = ts; event->priv = priv; event->func = cb; + event->owner = owner; /* Add the event in order to the list */ @@ -105,6 +108,36 @@ static int kgsl_add_event(struct kgsl_device *device, u32 ts, } #endif +/** + * kgsl_cancel_events - Cancel all events for a process + * @device - KGSL device for the events to cancel + * @owner - driver instance that owns the events to cancel + * + */ +static void kgsl_cancel_events(struct kgsl_device *device, + struct kgsl_device_private *owner) +{ + struct kgsl_event *event, *event_tmp; + unsigned int cur = device->ftbl->readtimestamp(device, + KGSL_TIMESTAMP_RETIRED); + + list_for_each_entry_safe(event, event_tmp, &device->events, list) { + if (event->owner != owner) + continue; + /* + * "cancel" the events by calling their callback. + * Currently, events are used for lock and memory + * management, so if the process is dying the right + * thing to do is release or free. + */ + if (event->func) + event->func(device, event->priv, cur); + + list_del(&event->list); + kfree(event); + } +} + static inline struct kgsl_mem_entry * kgsl_mem_entry_create(void) { @@ -656,6 +689,7 @@ static int kgsl_release(struct inode *inodep, struct file *filep) * process and this device */ kgsl_memqueue_cleanup(device, private); + kgsl_cancel_events(device, dev_priv); mutex_unlock(&device->mutex); kfree(dev_priv); @@ -1796,6 +1830,7 @@ static void kgsl_genlock_event_cb(struct kgsl_device *device, * @timestamp - Timestamp to trigger the event * @data - User space buffer containing struct kgsl_genlock_event_priv * @len - length of the userspace buffer + * @owner - driver instance that owns this event * @returns 0 on success or error code on error * * Attack to a genlock handle and register an event to release the @@ -1803,7 +1838,8 @@ static void kgsl_genlock_event_cb(struct kgsl_device *device, */ static int kgsl_add_genlock_event(struct kgsl_device *device, - u32 timestamp, void __user *data, int len) + u32 timestamp, void __user *data, int len, + struct kgsl_device_private *owner) { struct kgsl_genlock_event_priv *event; struct kgsl_timestamp_event_genlock priv; @@ -1828,7 +1864,8 @@ static int kgsl_add_genlock_event(struct kgsl_device *device, return ret; } - ret = kgsl_add_event(device, timestamp, kgsl_genlock_event_cb, event); + ret = kgsl_add_event(device, timestamp, kgsl_genlock_event_cb, event, + owner); if (ret) kfree(event); @@ -1836,7 +1873,8 @@ static int kgsl_add_genlock_event(struct kgsl_device *device, } #else static long kgsl_add_genlock_event(struct kgsl_device *device, - u32 timestamp, void __user *data, int len) + u32 timestamp, void __user *data, int len, + struct kgsl_device_private *owner) { return -EINVAL; } @@ -1859,7 +1897,8 @@ static long kgsl_ioctl_timestamp_event(struct kgsl_device_private *dev_priv, switch (param->type) { case KGSL_TIMESTAMP_EVENT_GENLOCK: ret = kgsl_add_genlock_event(dev_priv->device, - param->timestamp, param->priv, param->len); + param->timestamp, param->priv, param->len, + dev_priv); break; default: ret = -EINVAL; diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index b7524d87..998c16f7 100755 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -124,6 +124,7 @@ struct kgsl_event { void (*func)(struct kgsl_device *, void *, u32); void *priv; struct list_head list; + struct kgsl_device_private *owner; };