summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Clark <rob@ti.com>2012-05-17 07:13:46 +0800
committerAndy Green <andy.green@linaro.org>2012-11-27 11:43:52 +0800
commita0b360ea48c9f6e5ee4b1a01b04a796ac00a1df0 (patch)
tree30b63b64ccf2aab524c7dca3f061bf5421086ed3
parentc10699a7951bc415e13f378db5913d88cb7f767e (diff)
WIP: V2: syncobj updates
- v2 disable syncdbg traces
-rw-r--r--drivers/staging/omapdrm/omap_drv.c16
-rw-r--r--drivers/staging/omapdrm/omap_gem.c70
2 files changed, 60 insertions, 26 deletions
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c
index f3e8d34224e..15d2e6e624a 100644
--- a/drivers/staging/omapdrm/omap_drv.c
+++ b/drivers/staging/omapdrm/omap_drv.c
@@ -511,9 +511,11 @@ static int ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
ret = omap_gem_op_sync(obj, args->op);
- if (!ret) {
- ret = omap_gem_op_start(obj, args->op);
- }
+// TODO: need a way to kick sgx after omap_gem_op_finish() but for now
+// just disable this:
+// if (!ret) {
+// ret = omap_gem_op_start(obj, args->op);
+// }
drm_gem_object_unreference_unlocked(obj);
@@ -537,9 +539,11 @@ static int ioctl_gem_cpu_fini(struct drm_device *dev, void *data,
/* XXX flushy, flushy */
ret = 0;
- if (!ret) {
- ret = omap_gem_op_finish(obj, args->op);
- }
+// TODO: need a way to kick sgx after omap_gem_op_finish() but for now
+// just disable this:
+// if (!ret) {
+// ret = omap_gem_op_finish(obj, args->op);
+// }
drm_gem_object_unreference_unlocked(obj);
diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c
index d802f201dd1..c48ecf000e0 100644
--- a/drivers/staging/omapdrm/omap_gem.c
+++ b/drivers/staging/omapdrm/omap_gem.c
@@ -112,9 +112,9 @@ struct omap_gem_object {
*/
struct {
uint32_t write_pending;
- uint32_t write_complete;
+ volatile uint32_t write_complete;
uint32_t read_pending;
- uint32_t read_complete;
+ volatile uint32_t read_complete;
} *sync;
struct omap_gem_vm_ops *ops;
@@ -1032,6 +1032,7 @@ void omap_gem_describe_objects(struct list_head *list, struct seq_file *m)
*/
struct omap_gem_sync_waiter {
+ bool sync;
struct list_head list;
struct omap_gem_object *omap_obj;
enum omap_gem_op op;
@@ -1051,10 +1052,10 @@ static LIST_HEAD(waiters);
static inline bool is_waiting(struct omap_gem_sync_waiter *waiter)
{
struct omap_gem_object *omap_obj = waiter->omap_obj;
- if ((waiter->op & OMAP_GEM_READ) &&
+ if ((waiter->op & OMAP_GEM_WRITE) &&
(omap_obj->sync->read_complete < waiter->read_target))
return true;
- if ((waiter->op & OMAP_GEM_WRITE) &&
+ if ((waiter->op & (OMAP_GEM_READ|OMAP_GEM_WRITE)) &&
(omap_obj->sync->write_complete < waiter->write_target))
return true;
return false;
@@ -1062,23 +1063,48 @@ static inline bool is_waiting(struct omap_gem_sync_waiter *waiter)
/* macro for sync debug.. */
#define SYNCDBG 0
-#define SYNC(fmt, ...) do { if (SYNCDBG) \
- printk(KERN_ERR "%s:%d: "fmt"\n", \
- __func__, __LINE__, ##__VA_ARGS__); \
+#define SYNC(str, waiter) do { if (SYNCDBG) \
+ printk(KERN_ERR "%s:%d: "str": %p (%d/%d/%d, %d/%d/%d)\n", \
+ __func__, __LINE__, (waiter)->omap_obj, \
+ (waiter)->omap_obj->sync->read_pending, \
+ (waiter)->omap_obj->sync->read_complete, \
+ (waiter)->read_target, \
+ (waiter)->omap_obj->sync->write_pending, \
+ (waiter)->omap_obj->sync->write_complete, \
+ (waiter)->write_target); \
} while (0)
static void sync_op_update(void)
{
struct omap_gem_sync_waiter *waiter, *n;
+ LIST_HEAD(notified);
list_for_each_entry_safe(waiter, n, &waiters, list) {
if (!is_waiting(waiter)) {
list_del(&waiter->list);
- SYNC("notify: %p", waiter);
- waiter->notify(waiter->arg);
- kfree(waiter);
+ if (waiter->sync) {
+ /* ugg! we need to dispatch with lock held... otherwise
+ * in case of interrupted wait the waiter could be removed
+ * from it's current list, which happens to be now the
+ * 'notified' list, once the sync_lock is released..
+ * There *must* be a less ugly way to do this..
+ */
+ SYNC("notify", waiter);
+ waiter->notify(waiter->arg);
+ } else {
+ list_add_tail(&waiter->list, &notified);
+ }
}
}
+ spin_unlock(&sync_lock);
+ list_for_each_entry_safe(waiter, n, &notified, list) {
+ list_del(&waiter->list);
+ SYNC("notify", waiter);
+ waiter->notify(waiter->arg);
+ drm_gem_object_unreference_unlocked(&waiter->omap_obj->base);
+ kfree(waiter);
+ }
+ spin_lock(&sync_lock);
}
static inline int sync_op(struct drm_gem_object *obj,
@@ -1163,6 +1189,7 @@ int omap_gem_op_sync(struct drm_gem_object *obj, enum omap_gem_op op)
return -ENOMEM;
}
+ waiter->sync = false;
waiter->omap_obj = omap_obj;
waiter->op = op;
waiter->read_target = omap_obj->sync->read_pending;
@@ -1172,27 +1199,28 @@ int omap_gem_op_sync(struct drm_gem_object *obj, enum omap_gem_op op)
spin_lock(&sync_lock);
if (is_waiting(waiter)) {
- SYNC("waited: %p", waiter);
+ SYNC("waited", waiter);
list_add_tail(&waiter->list, &waiters);
spin_unlock(&sync_lock);
ret = wait_event_interruptible(sync_event,
(waiter_task == NULL));
spin_lock(&sync_lock);
if (waiter_task) {
- SYNC("interrupted: %p", waiter);
/* we were interrupted */
list_del(&waiter->list);
waiter_task = NULL;
- } else {
- /* freed in sync_op_update() */
- waiter = NULL;
+ /* but we might be finished anyways */
+ if (!is_waiting(waiter)) {
+ SYNC("interrupted, but finished", waiter);
+ ret = 0;
+ } else {
+ SYNC("interrupted", waiter);
+ }
}
}
spin_unlock(&sync_lock);
- if (waiter) {
- kfree(waiter);
- }
+ kfree(waiter);
}
return ret;
}
@@ -1218,6 +1246,7 @@ int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op,
return -ENOMEM;
}
+ waiter->sync = true;
waiter->omap_obj = omap_obj;
waiter->op = op;
waiter->read_target = omap_obj->sync->read_pending;
@@ -1227,13 +1256,14 @@ int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op,
spin_lock(&sync_lock);
if (is_waiting(waiter)) {
- SYNC("waited: %p", waiter);
+ drm_gem_object_reference(obj);
+ SYNC("waited", waiter);
list_add_tail(&waiter->list, &waiters);
spin_unlock(&sync_lock);
return 0;
}
-
spin_unlock(&sync_lock);
+ kfree(waiter);
}
/* no waiting.. */