summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/msm_gem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/msm_gem.c')
-rw-r--r--drivers/gpu/drm/msm/msm_gem.c138
1 files changed, 104 insertions, 34 deletions
diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c
index 3cedb8d5c855..7daf4054dd2b 100644
--- a/drivers/gpu/drm/msm/msm_gem.c
+++ b/drivers/gpu/drm/msm/msm_gem.c
@@ -21,6 +21,7 @@
#include <linux/pfn_t.h>
#include "msm_drv.h"
+#include "msm_fence.h"
#include "msm_gem.h"
#include "msm_gpu.h"
#include "msm_mmu.h"
@@ -373,7 +374,7 @@ int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
int ret = 0;
/* GEM does all our handle to object mapping */
- obj = drm_gem_object_lookup(dev, file, handle);
+ obj = drm_gem_object_lookup(file, handle);
if (obj == NULL) {
ret = -ENOENT;
goto fail;
@@ -410,27 +411,62 @@ void *msm_gem_vaddr(struct drm_gem_object *obj)
return ret;
}
-/* setup callback for when bo is no longer busy..
- * TODO probably want to differentiate read vs write..
- */
-int msm_gem_queue_inactive_cb(struct drm_gem_object *obj,
- struct msm_fence_cb *cb)
+/* must be called before _move_to_active().. */
+int msm_gem_sync_object(struct drm_gem_object *obj,
+ struct msm_fence_context *fctx, bool exclusive)
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
- uint32_t fence = msm_gem_fence(msm_obj,
- MSM_PREP_READ | MSM_PREP_WRITE);
- return msm_queue_fence_cb(obj->dev, cb, fence);
+ struct reservation_object_list *fobj;
+ struct fence *fence;
+ int i, ret;
+
+ if (!exclusive) {
+ /* NOTE: _reserve_shared() must happen before _add_shared_fence(),
+ * which makes this a slightly strange place to call it. OTOH this
+ * is a convenient can-fail point to hook it in. (And similar to
+ * how etnaviv and nouveau handle this.)
+ */
+ ret = reservation_object_reserve_shared(msm_obj->resv);
+ if (ret)
+ return ret;
+ }
+
+ fobj = reservation_object_get_list(msm_obj->resv);
+ if (!fobj || (fobj->shared_count == 0)) {
+ fence = reservation_object_get_excl(msm_obj->resv);
+ /* don't need to wait on our own fences, since ring is fifo */
+ if (fence && (fence->context != fctx->context)) {
+ ret = fence_wait(fence, true);
+ if (ret)
+ return ret;
+ }
+ }
+
+ if (!exclusive || !fobj)
+ return 0;
+
+ for (i = 0; i < fobj->shared_count; i++) {
+ fence = rcu_dereference_protected(fobj->shared[i],
+ reservation_object_held(msm_obj->resv));
+ if (fence->context != fctx->context) {
+ ret = fence_wait(fence, true);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
}
void msm_gem_move_to_active(struct drm_gem_object *obj,
- struct msm_gpu *gpu, bool write, uint32_t fence)
+ struct msm_gpu *gpu, bool exclusive, struct fence *fence)
{
struct msm_gem_object *msm_obj = to_msm_bo(obj);
msm_obj->gpu = gpu;
- if (write)
- msm_obj->write_fence = fence;
+ if (exclusive)
+ reservation_object_add_excl_fence(msm_obj->resv, fence);
else
- msm_obj->read_fence = fence;
+ reservation_object_add_shared_fence(msm_obj->resv, fence);
list_del_init(&msm_obj->mm_list);
list_add_tail(&msm_obj->mm_list, &gpu->active_list);
}
@@ -444,30 +480,30 @@ void msm_gem_move_to_inactive(struct drm_gem_object *obj)
WARN_ON(!mutex_is_locked(&dev->struct_mutex));
msm_obj->gpu = NULL;
- msm_obj->read_fence = 0;
- msm_obj->write_fence = 0;
list_del_init(&msm_obj->mm_list);
list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
}
int msm_gem_cpu_prep(struct drm_gem_object *obj, uint32_t op, ktime_t *timeout)
{
- struct drm_device *dev = obj->dev;
struct msm_gem_object *msm_obj = to_msm_bo(obj);
- int ret = 0;
+ bool write = !!(op & MSM_PREP_WRITE);
- if (is_active(msm_obj)) {
- uint32_t fence = msm_gem_fence(msm_obj, op);
-
- if (op & MSM_PREP_NOSYNC)
- timeout = NULL;
+ if (op & MSM_PREP_NOSYNC) {
+ if (!reservation_object_test_signaled_rcu(msm_obj->resv, write))
+ return -EBUSY;
+ } else {
+ int ret;
- ret = msm_wait_fence(dev, fence, timeout, true);
+ ret = reservation_object_wait_timeout_rcu(msm_obj->resv, write,
+ true, timeout_to_jiffies(timeout));
+ if (ret <= 0)
+ return ret == 0 ? -ETIMEDOUT : ret;
}
/* TODO cache maintenance */
- return ret;
+ return 0;
}
int msm_gem_cpu_fini(struct drm_gem_object *obj)
@@ -477,18 +513,46 @@ int msm_gem_cpu_fini(struct drm_gem_object *obj)
}
#ifdef CONFIG_DEBUG_FS
+static void describe_fence(struct fence *fence, const char *type,
+ struct seq_file *m)
+{
+ if (!fence_is_signaled(fence))
+ seq_printf(m, "\t%9s: %s %s seq %u\n", type,
+ fence->ops->get_driver_name(fence),
+ fence->ops->get_timeline_name(fence),
+ fence->seqno);
+}
+
void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
{
- struct drm_device *dev = obj->dev;
struct msm_gem_object *msm_obj = to_msm_bo(obj);
+ struct reservation_object *robj = msm_obj->resv;
+ struct reservation_object_list *fobj;
+ struct fence *fence;
uint64_t off = drm_vma_node_start(&obj->vma_node);
- WARN_ON(!mutex_is_locked(&dev->struct_mutex));
- seq_printf(m, "%08x: %c(r=%u,w=%u) %2d (%2d) %08llx %p %zu\n",
+ WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
+
+ seq_printf(m, "%08x: %c %2d (%2d) %08llx %p %zu\n",
msm_obj->flags, is_active(msm_obj) ? 'A' : 'I',
- msm_obj->read_fence, msm_obj->write_fence,
obj->name, obj->refcount.refcount.counter,
off, msm_obj->vaddr, obj->size);
+
+ rcu_read_lock();
+ fobj = rcu_dereference(robj->fence);
+ if (fobj) {
+ unsigned int i, shared_count = fobj->shared_count;
+
+ for (i = 0; i < shared_count; i++) {
+ fence = rcu_dereference(fobj->shared[i]);
+ describe_fence(fence, "Shared", m);
+ }
+ }
+
+ fence = rcu_dereference(robj->fence_excl);
+ if (fence)
+ describe_fence(fence, "Exclusive", m);
+ rcu_read_unlock();
}
void msm_gem_describe_objects(struct list_head *list, struct seq_file *m)
@@ -583,6 +647,7 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
static int msm_gem_new_impl(struct drm_device *dev,
uint32_t size, uint32_t flags,
+ struct reservation_object *resv,
struct drm_gem_object **obj)
{
struct msm_drm_private *priv = dev->dev_private;
@@ -622,8 +687,12 @@ static int msm_gem_new_impl(struct drm_device *dev,
msm_obj->flags = flags;
- msm_obj->resv = &msm_obj->_resv;
- reservation_object_init(msm_obj->resv);
+ if (resv) {
+ msm_obj->resv = resv;
+ } else {
+ msm_obj->resv = &msm_obj->_resv;
+ reservation_object_init(msm_obj->resv);
+ }
INIT_LIST_HEAD(&msm_obj->submit_entry);
list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
@@ -643,7 +712,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
size = PAGE_ALIGN(size);
- ret = msm_gem_new_impl(dev, size, flags, &obj);
+ ret = msm_gem_new_impl(dev, size, flags, NULL, &obj);
if (ret)
goto fail;
@@ -665,10 +734,11 @@ fail:
}
struct drm_gem_object *msm_gem_import(struct drm_device *dev,
- uint32_t size, struct sg_table *sgt)
+ struct dma_buf *dmabuf, struct sg_table *sgt)
{
struct msm_gem_object *msm_obj;
struct drm_gem_object *obj;
+ uint32_t size;
int ret, npages;
/* if we don't have IOMMU, don't bother pretending we can import: */
@@ -677,9 +747,9 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
return ERR_PTR(-EINVAL);
}
- size = PAGE_ALIGN(size);
+ size = PAGE_ALIGN(dmabuf->size);
- ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj);
+ ret = msm_gem_new_impl(dev, size, MSM_BO_WC, dmabuf->resv, &obj);
if (ret)
goto fail;
OpenPOWER on IntegriCloud