From bcf60a22c3e8671468517d34aa37548272455c1f Mon Sep 17 00:00:00 2001 From: Lauri Peltonen Date: Fri, 18 Jul 2014 02:21:34 +0300 Subject: gpu: nvgpu: Add gk20a_fence type When moving compression state tracking and compbit management ops to kernel, we need to attach a fence to dma-buf metadata, along with the compbit state. To make in-kernel fence management easier, introduce a new gk20a_fence abstraction. A gk20a_fence may be backed by a semaphore or a syncpoint (id, value) pair. If the kernel is configured with CONFIG_SYNC, it will also contain a sync_fence. The gk20a_fence can easily be converted back to a syncpoint (id, value) parir or sync FD when we need to return it to user space. Change gk20a_submit_channel_gpfifo to return a gk20a_fence instead of nvhost_fence. This is to facilitate work submission initiated from kernel. Bug 1509620 Change-Id: I6154764a279dba83f5e91ba9e0cb5e227ca08e1b Signed-off-by: Lauri Peltonen Reviewed-on: http://git-master/r/439846 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Terje Bergstrom Tested-by: Terje Bergstrom --- drivers/gpu/nvgpu/gk20a/fence_gk20a.c | 229 ++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 drivers/gpu/nvgpu/gk20a/fence_gk20a.c (limited to 'drivers/gpu/nvgpu/gk20a/fence_gk20a.c') diff --git a/drivers/gpu/nvgpu/gk20a/fence_gk20a.c b/drivers/gpu/nvgpu/gk20a/fence_gk20a.c new file mode 100644 index 00000000..1a28e660 --- /dev/null +++ b/drivers/gpu/nvgpu/gk20a/fence_gk20a.c @@ -0,0 +1,229 @@ +/* + * drivers/video/tegra/host/gk20a/fence_gk20a.c + * + * GK20A Fences + * + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include "fence_gk20a.h" + +#include +#include + +#include "gk20a.h" +#include "semaphore_gk20a.h" +#include "channel_gk20a.h" +#include "sync_gk20a.h" + +#ifdef CONFIG_SYNC +#include "../../../staging/android/sync.h" +#endif + +#ifdef CONFIG_TEGRA_GK20A +#include +#endif + +struct gk20a_fence_ops { + int (*wait)(struct gk20a_fence *, int timeout); + bool (*is_expired)(struct gk20a_fence *); + void *(*free)(struct kref *); +}; + +static void gk20a_fence_free(struct kref *ref) +{ + struct gk20a_fence *f = + container_of(ref, struct gk20a_fence, ref); +#ifdef CONFIG_SYNC + if (f->sync_fence) + sync_fence_put(f->sync_fence); +#endif + if (f->semaphore) + gk20a_semaphore_put(f->semaphore); + kfree(f); +} + +void gk20a_fence_put(struct gk20a_fence *f) +{ + if (f) + kref_put(&f->ref, gk20a_fence_free); +} + +struct gk20a_fence *gk20a_fence_get(struct gk20a_fence *f) +{ + if (f) + kref_get(&f->ref); + return f; +} + +int gk20a_fence_wait(struct gk20a_fence *f, int timeout) +{ + return f->ops->wait(f, timeout); +} + +bool gk20a_fence_is_expired(struct gk20a_fence *f) +{ + return f->ops->is_expired(f); +} + +int gk20a_fence_install_fd(struct gk20a_fence *f) +{ +#ifdef CONFIG_SYNC + int fd; + + if (!f->sync_fence) + return -EINVAL; + + fd = get_unused_fd(); + if (fd < 0) + return fd; + + sync_fence_get(f->sync_fence); + sync_fence_install(f->sync_fence, fd); + return fd; +#else + return -ENODEV; +#endif +} + +static struct gk20a_fence *alloc_fence(const struct gk20a_fence_ops *ops, + struct sync_fence *sync_fence, bool wfi) +{ + struct gk20a_fence *f = kzalloc(sizeof(*f), GFP_KERNEL); + if (!f) + return NULL; + kref_init(&f->ref); + f->ops = ops; + f->sync_fence = sync_fence; + f->wfi = wfi; + f->syncpt_id = -1; + return f; +} + +/* Fences that are backed by GPU semaphores: */ + +static int gk20a_semaphore_fence_wait(struct gk20a_fence *f, int timeout) +{ + int remain; + + if (!gk20a_semaphore_is_acquired(f->semaphore)) + return 0; + + remain = wait_event_interruptible_timeout( + *f->semaphore_wq, + !gk20a_semaphore_is_acquired(f->semaphore), + timeout); + if (remain == 0 && gk20a_semaphore_is_acquired(f->semaphore)) + return -ETIMEDOUT; + else if (remain < 0) + return remain; + return 0; +} + +static bool gk20a_semaphore_fence_is_expired(struct gk20a_fence *f) +{ + return !gk20a_semaphore_is_acquired(f->semaphore); +} + +static const struct gk20a_fence_ops gk20a_semaphore_fence_ops = { + .wait = &gk20a_semaphore_fence_wait, + .is_expired = &gk20a_semaphore_fence_is_expired, +}; + +struct gk20a_fence *gk20a_fence_from_semaphore( + struct sync_timeline *timeline, + struct gk20a_semaphore *semaphore, + wait_queue_head_t *semaphore_wq, + struct sync_fence *dependency, + bool wfi) +{ + struct gk20a_fence *f; + struct sync_fence *sync_fence = NULL; + +#ifdef CONFIG_SYNC + sync_fence = gk20a_sync_fence_create(timeline, semaphore, + dependency, "fence"); + if (!sync_fence) + return NULL; +#endif + + f = alloc_fence(&gk20a_semaphore_fence_ops, sync_fence, wfi); + if (!f) { +#ifdef CONFIG_SYNC + sync_fence_put(sync_fence); +#endif + return NULL; + } + gk20a_semaphore_get(semaphore); + f->semaphore = semaphore; + f->semaphore_wq = semaphore_wq; + return f; +} + +#ifdef CONFIG_TEGRA_GK20A +/* Fences that are backed by host1x syncpoints: */ + +static int gk20a_syncpt_fence_wait(struct gk20a_fence *f, int timeout) +{ + return nvhost_syncpt_wait_timeout_ext( + f->host1x_pdev, f->syncpt_id, f->syncpt_value, + timeout, NULL, NULL); +} + +static bool gk20a_syncpt_fence_is_expired(struct gk20a_fence *f) +{ + return nvhost_syncpt_is_expired_ext(f->host1x_pdev, f->syncpt_id, + f->syncpt_value); +} + +static const struct gk20a_fence_ops gk20a_syncpt_fence_ops = { + .wait = &gk20a_syncpt_fence_wait, + .is_expired = &gk20a_syncpt_fence_is_expired, +}; + +struct gk20a_fence *gk20a_fence_from_syncpt(struct platform_device *host1x_pdev, + u32 id, u32 value, bool wfi) +{ + struct gk20a_fence *f; + struct sync_fence *sync_fence = NULL; + +#ifdef CONFIG_SYNC + struct nvhost_ctrl_sync_fence_info pt = { + .id = id, + .thresh = value + }; + + sync_fence = nvhost_sync_create_fence(host1x_pdev, &pt, 1, + "fence"); + if (!sync_fence) + return NULL; +#endif + + f = alloc_fence(&gk20a_syncpt_fence_ops, sync_fence, wfi); + if (!f) { +#ifdef CONFIG_SYNC + sync_fence_put(sync_fence); +#endif + return NULL; + } + f->host1x_pdev = host1x_pdev; + f->syncpt_id = id; + f->syncpt_value = value; + return f; +} +#else +struct gk20a_fence *gk20a_fence_from_syncpt(struct platform_device *host1x_pdev, + u32 id, u32 value, bool wfi) +{ + return NULL; +} +#endif -- cgit v1.2.2