summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Clark <rob@ti.com>2012-01-20 10:24:29 -0600
committerVincent Stehlé <v-stehle@ti.com>2012-02-29 12:10:34 +0100
commitd6313621eaad9c7bd4e467fbc40478eea23286e1 (patch)
tree654f55ebed282a70f2cd0e67062f35b52fdfa099
parent3a8a3b0ea942d950287d97296de97e11c6baa542 (diff)
WIP: syncobj updatesVINCENT/5432-SGX-4
-rw-r--r--drivers/staging/omapdrm/omap_drv.c16
-rw-r--r--drivers/staging/omapdrm/omap_gem.c72
2 files changed, 61 insertions, 27 deletions
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c
index 228edf65925..1cffbfe44a7 100644
--- a/drivers/staging/omapdrm/omap_drv.c
+++ b/drivers/staging/omapdrm/omap_drv.c
@@ -509,9 +509,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);
@@ -535,9 +537,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 e3c6d45824c..0ffbe0c5265 100644
--- a/drivers/staging/omapdrm/omap_gem.c
+++ b/drivers/staging/omapdrm/omap_gem.c
@@ -110,9 +110,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;
@@ -804,6 +804,7 @@ void *omap_gem_vaddr(struct drm_gem_object *obj)
*/
struct omap_gem_sync_waiter {
+ bool sync;
struct list_head list;
struct omap_gem_object *omap_obj;
enum omap_gem_op op;
@@ -823,34 +824,59 @@ 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;
}
/* 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 SYNCDBG 1
+#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,
@@ -935,6 +961,7 @@ int omap_gem_op_sync(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;
@@ -944,27 +971,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;
}
@@ -990,6 +1018,7 @@ int omap_gem_op_async(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;
@@ -999,13 +1028,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.. */