diff options
author | Rob Clark <rob@ti.com> | 2012-01-20 10:24:29 -0600 |
---|---|---|
committer | Vincent Stehlé <v-stehle@ti.com> | 2012-02-29 12:10:34 +0100 |
commit | d6313621eaad9c7bd4e467fbc40478eea23286e1 (patch) | |
tree | 654f55ebed282a70f2cd0e67062f35b52fdfa099 | |
parent | 3a8a3b0ea942d950287d97296de97e11c6baa542 (diff) |
WIP: syncobj updatesVINCENT/5432-SGX-4
-rw-r--r-- | drivers/staging/omapdrm/omap_drv.c | 16 | ||||
-rw-r--r-- | drivers/staging/omapdrm/omap_gem.c | 72 |
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, ¬ified); + } } } + spin_unlock(&sync_lock); + list_for_each_entry_safe(waiter, n, ¬ified, 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.. */ |