mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 17:36:20 +03:00
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 <lpeltonen@nvidia.com> Reviewed-on: http://git-master/r/439846 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
This commit is contained in:
committed by
Dan Willemsen
parent
55295c6087
commit
bcf60a22c3
@@ -21,6 +21,7 @@ nvgpu-y := \
|
|||||||
pmu_gk20a.o \
|
pmu_gk20a.o \
|
||||||
priv_ring_gk20a.o \
|
priv_ring_gk20a.o \
|
||||||
semaphore_gk20a.o \
|
semaphore_gk20a.o \
|
||||||
|
fence_gk20a.o \
|
||||||
clk_gk20a.o \
|
clk_gk20a.o \
|
||||||
therm_gk20a.o \
|
therm_gk20a.o \
|
||||||
gr_ctx_gk20a_sim.o \
|
gr_ctx_gk20a_sim.o \
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
|
|
||||||
#include "gk20a.h"
|
#include "gk20a.h"
|
||||||
#include "dbg_gpu_gk20a.h"
|
#include "dbg_gpu_gk20a.h"
|
||||||
|
#include "fence_gk20a.h"
|
||||||
#include "semaphore_gk20a.h"
|
#include "semaphore_gk20a.h"
|
||||||
|
|
||||||
#include "hw_ram_gk20a.h"
|
#include "hw_ram_gk20a.h"
|
||||||
@@ -418,8 +419,8 @@ void gk20a_channel_abort(struct channel_gk20a *ch)
|
|||||||
semaphore synchronization) */
|
semaphore synchronization) */
|
||||||
mutex_lock(&ch->jobs_lock);
|
mutex_lock(&ch->jobs_lock);
|
||||||
list_for_each_entry_safe(job, n, &ch->jobs, list) {
|
list_for_each_entry_safe(job, n, &ch->jobs, list) {
|
||||||
if (job->post_fence.semaphore) {
|
if (job->post_fence->semaphore) {
|
||||||
gk20a_semaphore_release(job->post_fence.semaphore);
|
gk20a_semaphore_release(job->post_fence->semaphore);
|
||||||
released_job_semaphore = true;
|
released_job_semaphore = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -685,8 +686,12 @@ unbind:
|
|||||||
ch->vpr = false;
|
ch->vpr = false;
|
||||||
ch->vm = NULL;
|
ch->vm = NULL;
|
||||||
|
|
||||||
gk20a_channel_fence_close(&ch->last_submit.pre_fence);
|
mutex_lock(&ch->submit_lock);
|
||||||
gk20a_channel_fence_close(&ch->last_submit.post_fence);
|
gk20a_fence_put(ch->last_submit.pre_fence);
|
||||||
|
gk20a_fence_put(ch->last_submit.post_fence);
|
||||||
|
ch->last_submit.pre_fence = NULL;
|
||||||
|
ch->last_submit.post_fence = NULL;
|
||||||
|
mutex_unlock(&ch->submit_lock);
|
||||||
WARN_ON(ch->sync);
|
WARN_ON(ch->sync);
|
||||||
|
|
||||||
/* unlink all debug sessions */
|
/* unlink all debug sessions */
|
||||||
@@ -1119,8 +1124,12 @@ int gk20a_alloc_channel_gpfifo(struct channel_gk20a *c,
|
|||||||
ch_vm = c->vm;
|
ch_vm = c->vm;
|
||||||
|
|
||||||
c->cmds_pending = false;
|
c->cmds_pending = false;
|
||||||
gk20a_channel_fence_close(&c->last_submit.pre_fence);
|
mutex_lock(&c->submit_lock);
|
||||||
gk20a_channel_fence_close(&c->last_submit.post_fence);
|
gk20a_fence_put(c->last_submit.pre_fence);
|
||||||
|
gk20a_fence_put(c->last_submit.post_fence);
|
||||||
|
c->last_submit.pre_fence = NULL;
|
||||||
|
c->last_submit.post_fence = NULL;
|
||||||
|
mutex_unlock(&c->submit_lock);
|
||||||
|
|
||||||
c->ramfc.offset = 0;
|
c->ramfc.offset = 0;
|
||||||
c->ramfc.size = ram_in_ramfc_s() / 8;
|
c->ramfc.size = ram_in_ramfc_s() / 8;
|
||||||
@@ -1303,8 +1312,10 @@ static int gk20a_channel_submit_wfi(struct channel_gk20a *c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gk20a_channel_fence_close(&c->last_submit.pre_fence);
|
gk20a_fence_put(c->last_submit.pre_fence);
|
||||||
gk20a_channel_fence_close(&c->last_submit.post_fence);
|
gk20a_fence_put(c->last_submit.post_fence);
|
||||||
|
c->last_submit.pre_fence = NULL;
|
||||||
|
c->last_submit.post_fence = NULL;
|
||||||
|
|
||||||
err = c->sync->incr_wfi(c->sync, &cmd, &c->last_submit.post_fence);
|
err = c->sync->incr_wfi(c->sync, &cmd, &c->last_submit.post_fence);
|
||||||
if (unlikely(err)) {
|
if (unlikely(err)) {
|
||||||
@@ -1312,7 +1323,7 @@ static int gk20a_channel_submit_wfi(struct channel_gk20a *c)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
WARN_ON(!c->last_submit.post_fence.wfi);
|
WARN_ON(!c->last_submit.post_fence->wfi);
|
||||||
|
|
||||||
c->gpfifo.cpu_va[c->gpfifo.put].entry0 = u64_lo32(cmd->gva);
|
c->gpfifo.cpu_va[c->gpfifo.put].entry0 = u64_lo32(cmd->gva);
|
||||||
c->gpfifo.cpu_va[c->gpfifo.put].entry1 = u64_hi32(cmd->gva) |
|
c->gpfifo.cpu_va[c->gpfifo.put].entry1 = u64_hi32(cmd->gva) |
|
||||||
@@ -1378,8 +1389,8 @@ static void trace_write_pushbuffer(struct channel_gk20a *c, struct gpfifo *g)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int gk20a_channel_add_job(struct channel_gk20a *c,
|
static int gk20a_channel_add_job(struct channel_gk20a *c,
|
||||||
struct gk20a_channel_fence *pre_fence,
|
struct gk20a_fence *pre_fence,
|
||||||
struct gk20a_channel_fence *post_fence)
|
struct gk20a_fence *post_fence)
|
||||||
{
|
{
|
||||||
struct vm_gk20a *vm = c->vm;
|
struct vm_gk20a *vm = c->vm;
|
||||||
struct channel_gk20a_job *job = NULL;
|
struct channel_gk20a_job *job = NULL;
|
||||||
@@ -1404,8 +1415,8 @@ static int gk20a_channel_add_job(struct channel_gk20a *c,
|
|||||||
|
|
||||||
job->num_mapped_buffers = num_mapped_buffers;
|
job->num_mapped_buffers = num_mapped_buffers;
|
||||||
job->mapped_buffers = mapped_buffers;
|
job->mapped_buffers = mapped_buffers;
|
||||||
gk20a_channel_fence_dup(pre_fence, &job->pre_fence);
|
job->pre_fence = gk20a_fence_get(pre_fence);
|
||||||
gk20a_channel_fence_dup(post_fence, &job->post_fence);
|
job->post_fence = gk20a_fence_get(post_fence);
|
||||||
|
|
||||||
mutex_lock(&c->jobs_lock);
|
mutex_lock(&c->jobs_lock);
|
||||||
list_add_tail(&job->list, &c->jobs);
|
list_add_tail(&job->list, &c->jobs);
|
||||||
@@ -1424,18 +1435,19 @@ void gk20a_channel_update(struct channel_gk20a *c, int nr_completed)
|
|||||||
mutex_lock(&c->submit_lock);
|
mutex_lock(&c->submit_lock);
|
||||||
mutex_lock(&c->jobs_lock);
|
mutex_lock(&c->jobs_lock);
|
||||||
list_for_each_entry_safe(job, n, &c->jobs, list) {
|
list_for_each_entry_safe(job, n, &c->jobs, list) {
|
||||||
bool completed = WARN_ON(!c->sync) ||
|
bool completed = gk20a_fence_is_expired(job->post_fence);
|
||||||
c->sync->is_expired(c->sync, &job->post_fence);
|
|
||||||
if (!completed)
|
if (!completed)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
c->sync->signal_timeline(c->sync);
|
||||||
|
|
||||||
gk20a_vm_put_buffers(vm, job->mapped_buffers,
|
gk20a_vm_put_buffers(vm, job->mapped_buffers,
|
||||||
job->num_mapped_buffers);
|
job->num_mapped_buffers);
|
||||||
|
|
||||||
/* Close the fences (this will unref the semaphores and release
|
/* Close the fences (this will unref the semaphores and release
|
||||||
* them to the pool). */
|
* them to the pool). */
|
||||||
gk20a_channel_fence_close(&job->pre_fence);
|
gk20a_fence_put(job->pre_fence);
|
||||||
gk20a_channel_fence_close(&job->post_fence);
|
gk20a_fence_put(job->post_fence);
|
||||||
|
|
||||||
/* job is done. release its reference to vm */
|
/* job is done. release its reference to vm */
|
||||||
gk20a_vm_put(vm);
|
gk20a_vm_put(vm);
|
||||||
@@ -1453,7 +1465,7 @@ void gk20a_channel_update(struct channel_gk20a *c, int nr_completed)
|
|||||||
*/
|
*/
|
||||||
if (list_empty(&c->jobs)) {
|
if (list_empty(&c->jobs)) {
|
||||||
if (c->sync && c->sync->aggressive_destroy &&
|
if (c->sync && c->sync->aggressive_destroy &&
|
||||||
c->sync->is_expired(c->sync, &c->last_submit.post_fence)) {
|
gk20a_fence_is_expired(c->last_submit.post_fence)) {
|
||||||
c->sync->destroy(c->sync);
|
c->sync->destroy(c->sync);
|
||||||
c->sync = NULL;
|
c->sync = NULL;
|
||||||
}
|
}
|
||||||
@@ -1477,8 +1489,9 @@ void add_wait_cmd(u32 *ptr, u32 id, u32 thresh)
|
|||||||
int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
|
int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
|
||||||
struct nvhost_gpfifo *gpfifo,
|
struct nvhost_gpfifo *gpfifo,
|
||||||
u32 num_entries,
|
u32 num_entries,
|
||||||
|
u32 flags,
|
||||||
struct nvhost_fence *fence,
|
struct nvhost_fence *fence,
|
||||||
u32 flags)
|
struct gk20a_fence **fence_out)
|
||||||
{
|
{
|
||||||
struct gk20a *g = c->g;
|
struct gk20a *g = c->g;
|
||||||
struct device *d = dev_from_gk20a(g);
|
struct device *d = dev_from_gk20a(g);
|
||||||
@@ -1487,8 +1500,8 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
|
|||||||
int wait_fence_fd = -1;
|
int wait_fence_fd = -1;
|
||||||
struct priv_cmd_entry *wait_cmd = NULL;
|
struct priv_cmd_entry *wait_cmd = NULL;
|
||||||
struct priv_cmd_entry *incr_cmd = NULL;
|
struct priv_cmd_entry *incr_cmd = NULL;
|
||||||
struct gk20a_channel_fence pre_fence = { 0 };
|
struct gk20a_fence *pre_fence = NULL;
|
||||||
struct gk20a_channel_fence post_fence = { 0 };
|
struct gk20a_fence *post_fence = NULL;
|
||||||
/* we might need two extra gpfifo entries - one for pre fence
|
/* we might need two extra gpfifo entries - one for pre fence
|
||||||
* and one for post fence. */
|
* and one for post fence. */
|
||||||
const int extra_entries = 2;
|
const int extra_entries = 2;
|
||||||
@@ -1591,18 +1604,9 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
|
|||||||
|
|
||||||
/* always insert syncpt increment at end of gpfifo submission
|
/* always insert syncpt increment at end of gpfifo submission
|
||||||
to keep track of method completion for idle railgating */
|
to keep track of method completion for idle railgating */
|
||||||
if (flags & NVHOST_SUBMIT_GPFIFO_FLAGS_FENCE_GET &&
|
if (flags & NVHOST_SUBMIT_GPFIFO_FLAGS_FENCE_GET)
|
||||||
flags & NVHOST_SUBMIT_GPFIFO_FLAGS_SYNC_FENCE)
|
err = c->sync->incr_user(c->sync, wait_fence_fd, &incr_cmd,
|
||||||
err = c->sync->incr_user_fd(c->sync, wait_fence_fd, &incr_cmd,
|
&post_fence, need_wfi);
|
||||||
&post_fence,
|
|
||||||
need_wfi,
|
|
||||||
&fence->syncpt_id);
|
|
||||||
else if (flags & NVHOST_SUBMIT_GPFIFO_FLAGS_FENCE_GET)
|
|
||||||
err = c->sync->incr_user_syncpt(c->sync, &incr_cmd,
|
|
||||||
&post_fence,
|
|
||||||
need_wfi,
|
|
||||||
&fence->syncpt_id,
|
|
||||||
&fence->value);
|
|
||||||
else
|
else
|
||||||
err = c->sync->incr(c->sync, &incr_cmd,
|
err = c->sync->incr(c->sync, &incr_cmd,
|
||||||
&post_fence);
|
&post_fence);
|
||||||
@@ -1653,13 +1657,15 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
|
|||||||
incr_cmd->gp_put = c->gpfifo.put;
|
incr_cmd->gp_put = c->gpfifo.put;
|
||||||
}
|
}
|
||||||
|
|
||||||
gk20a_channel_fence_close(&c->last_submit.pre_fence);
|
gk20a_fence_put(c->last_submit.pre_fence);
|
||||||
gk20a_channel_fence_close(&c->last_submit.post_fence);
|
gk20a_fence_put(c->last_submit.post_fence);
|
||||||
c->last_submit.pre_fence = pre_fence;
|
c->last_submit.pre_fence = pre_fence;
|
||||||
c->last_submit.post_fence = post_fence;
|
c->last_submit.post_fence = post_fence;
|
||||||
|
if (fence_out)
|
||||||
|
*fence_out = gk20a_fence_get(post_fence);
|
||||||
|
|
||||||
/* TODO! Check for errors... */
|
/* TODO! Check for errors... */
|
||||||
gk20a_channel_add_job(c, &pre_fence, &post_fence);
|
gk20a_channel_add_job(c, pre_fence, post_fence);
|
||||||
|
|
||||||
c->cmds_pending = true;
|
c->cmds_pending = true;
|
||||||
gk20a_bar1_writel(g,
|
gk20a_bar1_writel(g,
|
||||||
@@ -1672,8 +1678,8 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
|
|||||||
c->hw_chid,
|
c->hw_chid,
|
||||||
num_entries,
|
num_entries,
|
||||||
flags,
|
flags,
|
||||||
fence ? fence->syncpt_id : 0,
|
post_fence->syncpt_id,
|
||||||
fence ? fence->value : 0);
|
post_fence->syncpt_value);
|
||||||
|
|
||||||
gk20a_dbg_info("post-submit put %d, get %d, size %d",
|
gk20a_dbg_info("post-submit put %d, get %d, size %d",
|
||||||
c->gpfifo.put, c->gpfifo.get, c->gpfifo.entry_num);
|
c->gpfifo.put, c->gpfifo.get, c->gpfifo.entry_num);
|
||||||
@@ -1685,8 +1691,8 @@ clean_up:
|
|||||||
gk20a_err(d, "fail");
|
gk20a_err(d, "fail");
|
||||||
free_priv_cmdbuf(c, wait_cmd);
|
free_priv_cmdbuf(c, wait_cmd);
|
||||||
free_priv_cmdbuf(c, incr_cmd);
|
free_priv_cmdbuf(c, incr_cmd);
|
||||||
gk20a_channel_fence_close(&pre_fence);
|
gk20a_fence_put(pre_fence);
|
||||||
gk20a_channel_fence_close(&post_fence);
|
gk20a_fence_put(post_fence);
|
||||||
gk20a_idle(g->dev);
|
gk20a_idle(g->dev);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -1719,7 +1725,7 @@ int gk20a_init_channel_support(struct gk20a *g, u32 chid)
|
|||||||
int gk20a_channel_finish(struct channel_gk20a *ch, unsigned long timeout)
|
int gk20a_channel_finish(struct channel_gk20a *ch, unsigned long timeout)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct gk20a_channel_fence *fence = &ch->last_submit.post_fence;
|
struct gk20a_fence *fence = ch->last_submit.post_fence;
|
||||||
|
|
||||||
if (!ch->cmds_pending)
|
if (!ch->cmds_pending)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1728,26 +1734,25 @@ int gk20a_channel_finish(struct channel_gk20a *ch, unsigned long timeout)
|
|||||||
if (ch->has_timedout)
|
if (ch->has_timedout)
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
if (!(fence->valid && fence->wfi) && ch->obj_class != KEPLER_C) {
|
if (!(fence && fence->wfi) && ch->obj_class != KEPLER_C) {
|
||||||
gk20a_dbg_fn("issuing wfi, incr to finish the channel");
|
gk20a_dbg_fn("issuing wfi, incr to finish the channel");
|
||||||
err = gk20a_channel_submit_wfi(ch);
|
err = gk20a_channel_submit_wfi(ch);
|
||||||
|
fence = ch->last_submit.post_fence;
|
||||||
}
|
}
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
BUG_ON(!(fence->valid && fence->wfi) && ch->obj_class != KEPLER_C);
|
BUG_ON(!(fence && fence->wfi) && ch->obj_class != KEPLER_C);
|
||||||
|
|
||||||
gk20a_dbg_fn("waiting for channel to finish thresh:%d sema:%p",
|
gk20a_dbg_fn("waiting for channel to finish thresh:%d sema:%p",
|
||||||
fence->thresh, fence->semaphore);
|
fence->syncpt_value, fence->semaphore);
|
||||||
|
|
||||||
if (ch->sync) {
|
err = gk20a_fence_wait(fence, timeout);
|
||||||
err = ch->sync->wait_cpu(ch->sync, fence, timeout);
|
if (WARN_ON(err))
|
||||||
if (WARN_ON(err))
|
dev_warn(dev_from_gk20a(ch->g),
|
||||||
dev_warn(dev_from_gk20a(ch->g),
|
"timed out waiting for gk20a channel to finish");
|
||||||
"timed out waiting for gk20a channel to finish");
|
else
|
||||||
else
|
ch->cmds_pending = false;
|
||||||
ch->cmds_pending = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -2014,6 +2019,7 @@ static int gk20a_ioctl_channel_submit_gpfifo(
|
|||||||
struct channel_gk20a *ch,
|
struct channel_gk20a *ch,
|
||||||
struct nvhost_submit_gpfifo_args *args)
|
struct nvhost_submit_gpfifo_args *args)
|
||||||
{
|
{
|
||||||
|
struct gk20a_fence *fence_out;
|
||||||
void *gpfifo;
|
void *gpfifo;
|
||||||
u32 size;
|
u32 size;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@@ -2036,7 +2042,26 @@ static int gk20a_ioctl_channel_submit_gpfifo(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = gk20a_submit_channel_gpfifo(ch, gpfifo, args->num_entries,
|
ret = gk20a_submit_channel_gpfifo(ch, gpfifo, args->num_entries,
|
||||||
&args->fence, args->flags);
|
args->flags, &args->fence,
|
||||||
|
&fence_out);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
goto clean_up;
|
||||||
|
|
||||||
|
/* Convert fence_out to something we can pass back to user space. */
|
||||||
|
if (args->flags & NVHOST_SUBMIT_GPFIFO_FLAGS_FENCE_GET) {
|
||||||
|
if (args->flags & NVHOST_SUBMIT_GPFIFO_FLAGS_SYNC_FENCE) {
|
||||||
|
int fd = gk20a_fence_install_fd(fence_out);
|
||||||
|
if (fd < 0)
|
||||||
|
ret = fd;
|
||||||
|
else
|
||||||
|
args->fence.syncpt_id = fd;
|
||||||
|
} else {
|
||||||
|
args->fence.syncpt_id = fence_out->syncpt_id;
|
||||||
|
args->fence.value = fence_out->syncpt_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gk20a_fence_put(fence_out);
|
||||||
|
|
||||||
clean_up:
|
clean_up:
|
||||||
kfree(gpfifo);
|
kfree(gpfifo);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
struct gk20a;
|
struct gk20a;
|
||||||
struct gr_gk20a;
|
struct gr_gk20a;
|
||||||
struct dbg_session_gk20a;
|
struct dbg_session_gk20a;
|
||||||
|
struct gk20a_fence;
|
||||||
|
|
||||||
#include "channel_sync_gk20a.h"
|
#include "channel_sync_gk20a.h"
|
||||||
|
|
||||||
@@ -68,8 +69,8 @@ struct channel_ctx_gk20a {
|
|||||||
struct channel_gk20a_job {
|
struct channel_gk20a_job {
|
||||||
struct mapped_buffer_node **mapped_buffers;
|
struct mapped_buffer_node **mapped_buffers;
|
||||||
int num_mapped_buffers;
|
int num_mapped_buffers;
|
||||||
struct gk20a_channel_fence pre_fence;
|
struct gk20a_fence *pre_fence;
|
||||||
struct gk20a_channel_fence post_fence;
|
struct gk20a_fence *post_fence;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -117,8 +118,9 @@ struct channel_gk20a {
|
|||||||
|
|
||||||
bool cmds_pending;
|
bool cmds_pending;
|
||||||
struct {
|
struct {
|
||||||
struct gk20a_channel_fence pre_fence;
|
/* These fences should be accessed with submit_lock held. */
|
||||||
struct gk20a_channel_fence post_fence;
|
struct gk20a_fence *pre_fence;
|
||||||
|
struct gk20a_fence *post_fence;
|
||||||
} last_submit;
|
} last_submit;
|
||||||
|
|
||||||
void (*remove_support)(struct channel_gk20a *);
|
void (*remove_support)(struct channel_gk20a *);
|
||||||
@@ -184,8 +186,9 @@ void channel_gk20a_unbind(struct channel_gk20a *ch_gk20a);
|
|||||||
int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
|
int gk20a_submit_channel_gpfifo(struct channel_gk20a *c,
|
||||||
struct nvhost_gpfifo *gpfifo,
|
struct nvhost_gpfifo *gpfifo,
|
||||||
u32 num_entries,
|
u32 num_entries,
|
||||||
|
u32 flags,
|
||||||
struct nvhost_fence *fence,
|
struct nvhost_fence *fence,
|
||||||
u32 flags);
|
struct gk20a_fence **fence_out);
|
||||||
|
|
||||||
int gk20a_alloc_channel_gpfifo(struct channel_gk20a *c,
|
int gk20a_alloc_channel_gpfifo(struct channel_gk20a *c,
|
||||||
struct nvhost_alloc_gpfifo_args *args);
|
struct nvhost_alloc_gpfifo_args *args);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "channel_sync_gk20a.h"
|
#include "channel_sync_gk20a.h"
|
||||||
#include "gk20a.h"
|
#include "gk20a.h"
|
||||||
|
#include "fence_gk20a.h"
|
||||||
#include "semaphore_gk20a.h"
|
#include "semaphore_gk20a.h"
|
||||||
#include "sync_gk20a.h"
|
#include "sync_gk20a.h"
|
||||||
#include "mm_gk20a.h"
|
#include "mm_gk20a.h"
|
||||||
@@ -52,33 +53,9 @@ static void add_wait_cmd(u32 *ptr, u32 id, u32 thresh)
|
|||||||
ptr[3] = (id << 8) | 0x10;
|
ptr[3] = (id << 8) | 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gk20a_channel_syncpt_wait_cpu(struct gk20a_channel_sync *s,
|
|
||||||
struct gk20a_channel_fence *fence,
|
|
||||||
int timeout)
|
|
||||||
{
|
|
||||||
struct gk20a_channel_syncpt *sp =
|
|
||||||
container_of(s, struct gk20a_channel_syncpt, ops);
|
|
||||||
if (!fence->valid)
|
|
||||||
return 0;
|
|
||||||
return nvhost_syncpt_wait_timeout_ext(
|
|
||||||
sp->host1x_pdev, sp->id, fence->thresh,
|
|
||||||
timeout, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool gk20a_channel_syncpt_is_expired(struct gk20a_channel_sync *s,
|
|
||||||
struct gk20a_channel_fence *fence)
|
|
||||||
{
|
|
||||||
struct gk20a_channel_syncpt *sp =
|
|
||||||
container_of(s, struct gk20a_channel_syncpt, ops);
|
|
||||||
if (!fence->valid)
|
|
||||||
return true;
|
|
||||||
return nvhost_syncpt_is_expired_ext(sp->host1x_pdev, sp->id,
|
|
||||||
fence->thresh);
|
|
||||||
}
|
|
||||||
|
|
||||||
int gk20a_channel_syncpt_wait_syncpt(struct gk20a_channel_sync *s, u32 id,
|
int gk20a_channel_syncpt_wait_syncpt(struct gk20a_channel_sync *s, u32 id,
|
||||||
u32 thresh, struct priv_cmd_entry **entry,
|
u32 thresh, struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence)
|
struct gk20a_fence **fence)
|
||||||
{
|
{
|
||||||
struct gk20a_channel_syncpt *sp =
|
struct gk20a_channel_syncpt *sp =
|
||||||
container_of(s, struct gk20a_channel_syncpt, ops);
|
container_of(s, struct gk20a_channel_syncpt, ops);
|
||||||
@@ -103,13 +80,13 @@ int gk20a_channel_syncpt_wait_syncpt(struct gk20a_channel_sync *s, u32 id,
|
|||||||
add_wait_cmd(&wait_cmd->ptr[0], id, thresh);
|
add_wait_cmd(&wait_cmd->ptr[0], id, thresh);
|
||||||
|
|
||||||
*entry = wait_cmd;
|
*entry = wait_cmd;
|
||||||
fence->valid = false;
|
*fence = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gk20a_channel_syncpt_wait_fd(struct gk20a_channel_sync *s, int fd,
|
int gk20a_channel_syncpt_wait_fd(struct gk20a_channel_sync *s, int fd,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence)
|
struct gk20a_fence **fence)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SYNC
|
#ifdef CONFIG_SYNC
|
||||||
int i;
|
int i;
|
||||||
@@ -164,7 +141,7 @@ int gk20a_channel_syncpt_wait_fd(struct gk20a_channel_sync *s, int fd,
|
|||||||
sync_fence_put(sync_fence);
|
sync_fence_put(sync_fence);
|
||||||
|
|
||||||
*entry = wait_cmd;
|
*entry = wait_cmd;
|
||||||
fence->valid = false;
|
*fence = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@@ -181,7 +158,7 @@ static int __gk20a_channel_syncpt_incr(struct gk20a_channel_sync *s,
|
|||||||
bool gfx_class, bool wfi_cmd,
|
bool gfx_class, bool wfi_cmd,
|
||||||
bool register_irq,
|
bool register_irq,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence)
|
struct gk20a_fence **fence)
|
||||||
{
|
{
|
||||||
u32 thresh;
|
u32 thresh;
|
||||||
int incr_cmd_size;
|
int incr_cmd_size;
|
||||||
@@ -253,16 +230,15 @@ static int __gk20a_channel_syncpt_incr(struct gk20a_channel_sync *s,
|
|||||||
WARN(err, "failed to set submit complete interrupt");
|
WARN(err, "failed to set submit complete interrupt");
|
||||||
}
|
}
|
||||||
|
|
||||||
fence->thresh = thresh;
|
*fence = gk20a_fence_from_syncpt(sp->host1x_pdev, sp->id, thresh,
|
||||||
fence->valid = true;
|
wfi_cmd);
|
||||||
fence->wfi = wfi_cmd;
|
|
||||||
*entry = incr_cmd;
|
*entry = incr_cmd;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gk20a_channel_syncpt_incr_wfi(struct gk20a_channel_sync *s,
|
int gk20a_channel_syncpt_incr_wfi(struct gk20a_channel_sync *s,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence)
|
struct gk20a_fence **fence)
|
||||||
{
|
{
|
||||||
return __gk20a_channel_syncpt_incr(s,
|
return __gk20a_channel_syncpt_incr(s,
|
||||||
false /* use host class */,
|
false /* use host class */,
|
||||||
@@ -273,7 +249,7 @@ int gk20a_channel_syncpt_incr_wfi(struct gk20a_channel_sync *s,
|
|||||||
|
|
||||||
int gk20a_channel_syncpt_incr(struct gk20a_channel_sync *s,
|
int gk20a_channel_syncpt_incr(struct gk20a_channel_sync *s,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence)
|
struct gk20a_fence **fence)
|
||||||
{
|
{
|
||||||
struct gk20a_channel_syncpt *sp =
|
struct gk20a_channel_syncpt *sp =
|
||||||
container_of(s, struct gk20a_channel_syncpt, ops);
|
container_of(s, struct gk20a_channel_syncpt, ops);
|
||||||
@@ -286,51 +262,23 @@ int gk20a_channel_syncpt_incr(struct gk20a_channel_sync *s,
|
|||||||
entry, fence);
|
entry, fence);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gk20a_channel_syncpt_incr_user_syncpt(struct gk20a_channel_sync *s,
|
int gk20a_channel_syncpt_incr_user(struct gk20a_channel_sync *s,
|
||||||
struct priv_cmd_entry **entry,
|
int wait_fence_fd,
|
||||||
struct gk20a_channel_fence *fence,
|
struct priv_cmd_entry **entry,
|
||||||
bool wfi,
|
struct gk20a_fence **fence,
|
||||||
u32 *id, u32 *thresh)
|
bool wfi)
|
||||||
{
|
{
|
||||||
struct gk20a_channel_syncpt *sp =
|
struct gk20a_channel_syncpt *sp =
|
||||||
container_of(s, struct gk20a_channel_syncpt, ops);
|
container_of(s, struct gk20a_channel_syncpt, ops);
|
||||||
/* Need to do 'host incr + wfi' or 'gfx incr' since we return the fence
|
/* Need to do 'host incr + wfi' or 'gfx incr' since we return the fence
|
||||||
* to user space. */
|
* to user space. */
|
||||||
int err = __gk20a_channel_syncpt_incr(s,
|
return __gk20a_channel_syncpt_incr(s,
|
||||||
wfi &&
|
wfi &&
|
||||||
sp->c->obj_class == KEPLER_C /* use gfx class? */,
|
sp->c->obj_class == KEPLER_C /* use gfx class? */,
|
||||||
wfi &&
|
wfi &&
|
||||||
sp->c->obj_class != KEPLER_C /* wfi if host class */,
|
sp->c->obj_class != KEPLER_C /* wfi if host class */,
|
||||||
true /* register irq */,
|
true /* register irq */,
|
||||||
entry, fence);
|
entry, fence);
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
*id = sp->id;
|
|
||||||
*thresh = fence->thresh;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int gk20a_channel_syncpt_incr_user_fd(struct gk20a_channel_sync *s,
|
|
||||||
int wait_fence_fd,
|
|
||||||
struct priv_cmd_entry **entry,
|
|
||||||
struct gk20a_channel_fence *fence,
|
|
||||||
bool wfi,
|
|
||||||
int *fd)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_SYNC
|
|
||||||
int err;
|
|
||||||
struct nvhost_ctrl_sync_fence_info pt;
|
|
||||||
struct gk20a_channel_syncpt *sp =
|
|
||||||
container_of(s, struct gk20a_channel_syncpt, ops);
|
|
||||||
err = gk20a_channel_syncpt_incr_user_syncpt(s, entry, fence, wfi,
|
|
||||||
&pt.id, &pt.thresh);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
return nvhost_sync_create_fence_fd(sp->host1x_pdev, &pt, 1,
|
|
||||||
"fence", fd);
|
|
||||||
#else
|
|
||||||
return -ENODEV;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gk20a_channel_syncpt_set_min_eq_max(struct gk20a_channel_sync *s)
|
void gk20a_channel_syncpt_set_min_eq_max(struct gk20a_channel_sync *s)
|
||||||
@@ -340,6 +288,12 @@ void gk20a_channel_syncpt_set_min_eq_max(struct gk20a_channel_sync *s)
|
|||||||
nvhost_syncpt_set_min_eq_max_ext(sp->host1x_pdev, sp->id);
|
nvhost_syncpt_set_min_eq_max_ext(sp->host1x_pdev, sp->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gk20a_channel_syncpt_signal_timeline(
|
||||||
|
struct gk20a_channel_sync *s)
|
||||||
|
{
|
||||||
|
/* Nothing to do. */
|
||||||
|
}
|
||||||
|
|
||||||
static void gk20a_channel_syncpt_destroy(struct gk20a_channel_sync *s)
|
static void gk20a_channel_syncpt_destroy(struct gk20a_channel_sync *s)
|
||||||
{
|
{
|
||||||
struct gk20a_channel_syncpt *sp =
|
struct gk20a_channel_syncpt *sp =
|
||||||
@@ -366,15 +320,13 @@ gk20a_channel_syncpt_create(struct channel_gk20a *c)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
sp->ops.wait_cpu = gk20a_channel_syncpt_wait_cpu;
|
|
||||||
sp->ops.is_expired = gk20a_channel_syncpt_is_expired;
|
|
||||||
sp->ops.wait_syncpt = gk20a_channel_syncpt_wait_syncpt;
|
sp->ops.wait_syncpt = gk20a_channel_syncpt_wait_syncpt;
|
||||||
sp->ops.wait_fd = gk20a_channel_syncpt_wait_fd;
|
sp->ops.wait_fd = gk20a_channel_syncpt_wait_fd;
|
||||||
sp->ops.incr = gk20a_channel_syncpt_incr;
|
sp->ops.incr = gk20a_channel_syncpt_incr;
|
||||||
sp->ops.incr_wfi = gk20a_channel_syncpt_incr_wfi;
|
sp->ops.incr_wfi = gk20a_channel_syncpt_incr_wfi;
|
||||||
sp->ops.incr_user_syncpt = gk20a_channel_syncpt_incr_user_syncpt;
|
sp->ops.incr_user = gk20a_channel_syncpt_incr_user;
|
||||||
sp->ops.incr_user_fd = gk20a_channel_syncpt_incr_user_fd;
|
|
||||||
sp->ops.set_min_eq_max = gk20a_channel_syncpt_set_min_eq_max;
|
sp->ops.set_min_eq_max = gk20a_channel_syncpt_set_min_eq_max;
|
||||||
|
sp->ops.signal_timeline = gk20a_channel_syncpt_signal_timeline;
|
||||||
sp->ops.destroy = gk20a_channel_syncpt_destroy;
|
sp->ops.destroy = gk20a_channel_syncpt_destroy;
|
||||||
|
|
||||||
sp->ops.aggressive_destroy = true;
|
sp->ops.aggressive_destroy = true;
|
||||||
@@ -460,48 +412,10 @@ static int add_sema_cmd(u32 *ptr, u64 sema, u32 payload,
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gk20a_channel_semaphore_wait_cpu(
|
|
||||||
struct gk20a_channel_sync *s,
|
|
||||||
struct gk20a_channel_fence *fence,
|
|
||||||
int timeout)
|
|
||||||
{
|
|
||||||
int remain;
|
|
||||||
struct gk20a_channel_semaphore *sp =
|
|
||||||
container_of(s, struct gk20a_channel_semaphore, ops);
|
|
||||||
if (!fence->valid || WARN_ON(!fence->semaphore))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
remain = wait_event_interruptible_timeout(
|
|
||||||
sp->c->semaphore_wq,
|
|
||||||
!gk20a_semaphore_is_acquired(fence->semaphore),
|
|
||||||
timeout);
|
|
||||||
if (remain == 0 && gk20a_semaphore_is_acquired(fence->semaphore))
|
|
||||||
return -ETIMEDOUT;
|
|
||||||
else if (remain < 0)
|
|
||||||
return remain;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool gk20a_channel_semaphore_is_expired(
|
|
||||||
struct gk20a_channel_sync *s,
|
|
||||||
struct gk20a_channel_fence *fence)
|
|
||||||
{
|
|
||||||
bool expired;
|
|
||||||
struct gk20a_channel_semaphore *sp =
|
|
||||||
container_of(s, struct gk20a_channel_semaphore, ops);
|
|
||||||
if (!fence->valid || WARN_ON(!fence->semaphore))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
expired = !gk20a_semaphore_is_acquired(fence->semaphore);
|
|
||||||
if (expired)
|
|
||||||
gk20a_sync_timeline_signal(sp->timeline);
|
|
||||||
return expired;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gk20a_channel_semaphore_wait_syncpt(
|
static int gk20a_channel_semaphore_wait_syncpt(
|
||||||
struct gk20a_channel_sync *s, u32 id,
|
struct gk20a_channel_sync *s, u32 id,
|
||||||
u32 thresh, struct priv_cmd_entry **entry,
|
u32 thresh, struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence)
|
struct gk20a_fence **fence)
|
||||||
{
|
{
|
||||||
struct gk20a_channel_semaphore *sema =
|
struct gk20a_channel_semaphore *sema =
|
||||||
container_of(s, struct gk20a_channel_semaphore, ops);
|
container_of(s, struct gk20a_channel_semaphore, ops);
|
||||||
@@ -513,7 +427,7 @@ static int gk20a_channel_semaphore_wait_syncpt(
|
|||||||
static int gk20a_channel_semaphore_wait_fd(
|
static int gk20a_channel_semaphore_wait_fd(
|
||||||
struct gk20a_channel_sync *s, int fd,
|
struct gk20a_channel_sync *s, int fd,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence)
|
struct gk20a_fence **fence)
|
||||||
{
|
{
|
||||||
struct gk20a_channel_semaphore *sema =
|
struct gk20a_channel_semaphore *sema =
|
||||||
container_of(s, struct gk20a_channel_semaphore, ops);
|
container_of(s, struct gk20a_channel_semaphore, ops);
|
||||||
@@ -558,6 +472,11 @@ static int gk20a_channel_semaphore_wait_fd(
|
|||||||
WARN_ON(written != wait_cmd->size);
|
WARN_ON(written != wait_cmd->size);
|
||||||
sync_fence_wait_async(sync_fence, &w->waiter);
|
sync_fence_wait_async(sync_fence, &w->waiter);
|
||||||
|
|
||||||
|
/* XXX - this fixes an actual bug, we need to hold a ref to this
|
||||||
|
semaphore while the job is in flight. */
|
||||||
|
*fence = gk20a_fence_from_semaphore(sema->timeline, w->sema,
|
||||||
|
&c->semaphore_wq,
|
||||||
|
NULL, false);
|
||||||
*entry = wait_cmd;
|
*entry = wait_cmd;
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
@@ -575,8 +494,9 @@ fail:
|
|||||||
|
|
||||||
static int __gk20a_channel_semaphore_incr(
|
static int __gk20a_channel_semaphore_incr(
|
||||||
struct gk20a_channel_sync *s, bool wfi_cmd,
|
struct gk20a_channel_sync *s, bool wfi_cmd,
|
||||||
|
struct sync_fence *dependency,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence)
|
struct gk20a_fence **fence)
|
||||||
{
|
{
|
||||||
u64 va;
|
u64 va;
|
||||||
int incr_cmd_size;
|
int incr_cmd_size;
|
||||||
@@ -608,9 +528,9 @@ static int __gk20a_channel_semaphore_incr(
|
|||||||
written = add_sema_cmd(incr_cmd->ptr, va, 1, false, wfi_cmd);
|
written = add_sema_cmd(incr_cmd->ptr, va, 1, false, wfi_cmd);
|
||||||
WARN_ON(written != incr_cmd_size);
|
WARN_ON(written != incr_cmd_size);
|
||||||
|
|
||||||
fence->valid = true;
|
*fence = gk20a_fence_from_semaphore(sp->timeline, semaphore,
|
||||||
fence->wfi = wfi_cmd;
|
&c->semaphore_wq,
|
||||||
fence->semaphore = semaphore;
|
dependency, wfi_cmd);
|
||||||
*entry = incr_cmd;
|
*entry = incr_cmd;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -618,72 +538,54 @@ static int __gk20a_channel_semaphore_incr(
|
|||||||
static int gk20a_channel_semaphore_incr_wfi(
|
static int gk20a_channel_semaphore_incr_wfi(
|
||||||
struct gk20a_channel_sync *s,
|
struct gk20a_channel_sync *s,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence)
|
struct gk20a_fence **fence)
|
||||||
{
|
{
|
||||||
return __gk20a_channel_semaphore_incr(s,
|
return __gk20a_channel_semaphore_incr(s,
|
||||||
true /* wfi */,
|
true /* wfi */,
|
||||||
|
NULL,
|
||||||
entry, fence);
|
entry, fence);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gk20a_channel_semaphore_incr(
|
static int gk20a_channel_semaphore_incr(
|
||||||
struct gk20a_channel_sync *s,
|
struct gk20a_channel_sync *s,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence)
|
struct gk20a_fence **fence)
|
||||||
{
|
{
|
||||||
/* Don't put wfi cmd to this one since we're not returning
|
/* Don't put wfi cmd to this one since we're not returning
|
||||||
* a fence to user space. */
|
* a fence to user space. */
|
||||||
return __gk20a_channel_semaphore_incr(s, false /* no wfi */,
|
return __gk20a_channel_semaphore_incr(s, false /* no wfi */,
|
||||||
entry, fence);
|
NULL, entry, fence);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gk20a_channel_semaphore_incr_user_syncpt(
|
static int gk20a_channel_semaphore_incr_user(
|
||||||
struct gk20a_channel_sync *s,
|
|
||||||
struct priv_cmd_entry **entry,
|
|
||||||
struct gk20a_channel_fence *fence,
|
|
||||||
bool wfi,
|
|
||||||
u32 *id, u32 *thresh)
|
|
||||||
{
|
|
||||||
struct gk20a_channel_semaphore *sema =
|
|
||||||
container_of(s, struct gk20a_channel_semaphore, ops);
|
|
||||||
struct device *dev = dev_from_gk20a(sema->c->g);
|
|
||||||
gk20a_err(dev, "trying to use syncpoint synchronization");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int gk20a_channel_semaphore_incr_user_fd(
|
|
||||||
struct gk20a_channel_sync *s,
|
struct gk20a_channel_sync *s,
|
||||||
int wait_fence_fd,
|
int wait_fence_fd,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence,
|
struct gk20a_fence **fence,
|
||||||
bool wfi,
|
bool wfi)
|
||||||
int *fd)
|
|
||||||
{
|
{
|
||||||
struct gk20a_channel_semaphore *sema =
|
|
||||||
container_of(s, struct gk20a_channel_semaphore, ops);
|
|
||||||
#ifdef CONFIG_SYNC
|
#ifdef CONFIG_SYNC
|
||||||
struct sync_fence *dependency = NULL;
|
struct sync_fence *dependency = NULL;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = __gk20a_channel_semaphore_incr(s, wfi,
|
|
||||||
entry, fence);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
|
|
||||||
if (wait_fence_fd >= 0) {
|
if (wait_fence_fd >= 0) {
|
||||||
dependency = gk20a_sync_fence_fdget(wait_fence_fd);
|
dependency = gk20a_sync_fence_fdget(wait_fence_fd);
|
||||||
if (!dependency)
|
if (!dependency)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
*fd = gk20a_sync_fence_create(sema->timeline, fence->semaphore,
|
err = __gk20a_channel_semaphore_incr(s, wfi, dependency,
|
||||||
dependency, "fence");
|
entry, fence);
|
||||||
if (*fd < 0) {
|
if (err) {
|
||||||
if (dependency)
|
if (dependency)
|
||||||
sync_fence_put(dependency);
|
sync_fence_put(dependency);
|
||||||
return *fd;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
|
struct gk20a_channel_semaphore *sema =
|
||||||
|
container_of(s, struct gk20a_channel_semaphore, ops);
|
||||||
gk20a_err(dev_from_gk20a(sema->c->g),
|
gk20a_err(dev_from_gk20a(sema->c->g),
|
||||||
"trying to use sync fds with CONFIG_SYNC disabled");
|
"trying to use sync fds with CONFIG_SYNC disabled");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@@ -695,6 +597,14 @@ static void gk20a_channel_semaphore_set_min_eq_max(struct gk20a_channel_sync *s)
|
|||||||
/* Nothing to do. */
|
/* Nothing to do. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gk20a_channel_semaphore_signal_timeline(
|
||||||
|
struct gk20a_channel_sync *s)
|
||||||
|
{
|
||||||
|
struct gk20a_channel_semaphore *sp =
|
||||||
|
container_of(s, struct gk20a_channel_semaphore, ops);
|
||||||
|
gk20a_sync_timeline_signal(sp->timeline);
|
||||||
|
}
|
||||||
|
|
||||||
static void gk20a_channel_semaphore_destroy(struct gk20a_channel_sync *s)
|
static void gk20a_channel_semaphore_destroy(struct gk20a_channel_sync *s)
|
||||||
{
|
{
|
||||||
struct gk20a_channel_semaphore *sema =
|
struct gk20a_channel_semaphore *sema =
|
||||||
@@ -746,15 +656,13 @@ gk20a_channel_semaphore_create(struct channel_gk20a *c)
|
|||||||
if (!sema->timeline)
|
if (!sema->timeline)
|
||||||
goto clean_up;
|
goto clean_up;
|
||||||
#endif
|
#endif
|
||||||
sema->ops.wait_cpu = gk20a_channel_semaphore_wait_cpu;
|
|
||||||
sema->ops.is_expired = gk20a_channel_semaphore_is_expired;
|
|
||||||
sema->ops.wait_syncpt = gk20a_channel_semaphore_wait_syncpt;
|
sema->ops.wait_syncpt = gk20a_channel_semaphore_wait_syncpt;
|
||||||
sema->ops.wait_fd = gk20a_channel_semaphore_wait_fd;
|
sema->ops.wait_fd = gk20a_channel_semaphore_wait_fd;
|
||||||
sema->ops.incr = gk20a_channel_semaphore_incr;
|
sema->ops.incr = gk20a_channel_semaphore_incr;
|
||||||
sema->ops.incr_wfi = gk20a_channel_semaphore_incr_wfi;
|
sema->ops.incr_wfi = gk20a_channel_semaphore_incr_wfi;
|
||||||
sema->ops.incr_user_syncpt = gk20a_channel_semaphore_incr_user_syncpt;
|
sema->ops.incr_user = gk20a_channel_semaphore_incr_user;
|
||||||
sema->ops.incr_user_fd = gk20a_channel_semaphore_incr_user_fd;
|
|
||||||
sema->ops.set_min_eq_max = gk20a_channel_semaphore_set_min_eq_max;
|
sema->ops.set_min_eq_max = gk20a_channel_semaphore_set_min_eq_max;
|
||||||
|
sema->ops.signal_timeline = gk20a_channel_semaphore_signal_timeline;
|
||||||
sema->ops.destroy = gk20a_channel_semaphore_destroy;
|
sema->ops.destroy = gk20a_channel_semaphore_destroy;
|
||||||
|
|
||||||
/* Aggressively destroying the semaphore sync would cause overhead
|
/* Aggressively destroying the semaphore sync would cause overhead
|
||||||
@@ -775,26 +683,3 @@ struct gk20a_channel_sync *gk20a_channel_sync_create(struct channel_gk20a *c)
|
|||||||
#endif
|
#endif
|
||||||
return gk20a_channel_semaphore_create(c);
|
return gk20a_channel_semaphore_create(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool gk20a_channel_fence_is_closed(struct gk20a_channel_fence *f)
|
|
||||||
{
|
|
||||||
if (f->valid || f->semaphore)
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gk20a_channel_fence_close(struct gk20a_channel_fence *f)
|
|
||||||
{
|
|
||||||
if (f->semaphore)
|
|
||||||
gk20a_semaphore_put(f->semaphore);
|
|
||||||
memset(f, 0, sizeof(*f));
|
|
||||||
}
|
|
||||||
|
|
||||||
void gk20a_channel_fence_dup(struct gk20a_channel_fence *from,
|
|
||||||
struct gk20a_channel_fence *to)
|
|
||||||
{
|
|
||||||
WARN_ON(!gk20a_channel_fence_is_closed(to));
|
|
||||||
*to = *from;
|
|
||||||
if (to->semaphore)
|
|
||||||
gk20a_semaphore_get(to->semaphore);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -24,34 +24,28 @@ struct gk20a_channel_sync;
|
|||||||
struct priv_cmd_entry;
|
struct priv_cmd_entry;
|
||||||
struct channel_gk20a;
|
struct channel_gk20a;
|
||||||
struct gk20a_semaphore;
|
struct gk20a_semaphore;
|
||||||
|
struct gk20a_fence;
|
||||||
struct gk20a_channel_fence {
|
|
||||||
bool valid;
|
|
||||||
bool wfi; /* was issued with preceding wfi */
|
|
||||||
u32 thresh; /* syncpoint fences only */
|
|
||||||
struct gk20a_semaphore *semaphore; /* semaphore fences only */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct gk20a_channel_sync {
|
struct gk20a_channel_sync {
|
||||||
/* CPU wait for a fence returned by incr_syncpt() or incr_fd(). */
|
/* Generate a gpu wait cmdbuf from syncpoint.
|
||||||
int (*wait_cpu)(struct gk20a_channel_sync *s,
|
* Returns
|
||||||
struct gk20a_channel_fence *fence,
|
* - a gpu cmdbuf that performs the wait when executed,
|
||||||
int timeout);
|
* - possibly a helper fence that the caller must hold until the
|
||||||
|
* cmdbuf is executed.
|
||||||
/* Test whether a fence returned by incr_syncpt() or incr_fd() is
|
*/
|
||||||
* expired. */
|
|
||||||
bool (*is_expired)(struct gk20a_channel_sync *s,
|
|
||||||
struct gk20a_channel_fence *fence);
|
|
||||||
|
|
||||||
/* Generate a gpu wait cmdbuf from syncpoint. */
|
|
||||||
int (*wait_syncpt)(struct gk20a_channel_sync *s, u32 id, u32 thresh,
|
int (*wait_syncpt)(struct gk20a_channel_sync *s, u32 id, u32 thresh,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence);
|
struct gk20a_fence **fence);
|
||||||
|
|
||||||
/* Generate a gpu wait cmdbuf from sync fd. */
|
/* Generate a gpu wait cmdbuf from sync fd.
|
||||||
|
* Returns
|
||||||
|
* - a gpu cmdbuf that performs the wait when executed,
|
||||||
|
* - possibly a helper fence that the caller must hold until the
|
||||||
|
* cmdbuf is executed.
|
||||||
|
*/
|
||||||
int (*wait_fd)(struct gk20a_channel_sync *s, int fd,
|
int (*wait_fd)(struct gk20a_channel_sync *s, int fd,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence);
|
struct gk20a_fence **fence);
|
||||||
|
|
||||||
/* Increment syncpoint/semaphore.
|
/* Increment syncpoint/semaphore.
|
||||||
* Returns
|
* Returns
|
||||||
@@ -60,7 +54,7 @@ struct gk20a_channel_sync {
|
|||||||
*/
|
*/
|
||||||
int (*incr)(struct gk20a_channel_sync *s,
|
int (*incr)(struct gk20a_channel_sync *s,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence);
|
struct gk20a_fence **fence);
|
||||||
|
|
||||||
/* Increment syncpoint/semaphore, preceded by a wfi.
|
/* Increment syncpoint/semaphore, preceded by a wfi.
|
||||||
* Returns
|
* Returns
|
||||||
@@ -69,38 +63,29 @@ struct gk20a_channel_sync {
|
|||||||
*/
|
*/
|
||||||
int (*incr_wfi)(struct gk20a_channel_sync *s,
|
int (*incr_wfi)(struct gk20a_channel_sync *s,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence);
|
struct gk20a_fence **fence);
|
||||||
|
|
||||||
/* Increment syncpoint, so that the returned fence represents
|
|
||||||
* work completion (may need wfi) and can be returned to user space.
|
|
||||||
* Returns
|
|
||||||
* - a gpu cmdbuf that performs the increment when executed,
|
|
||||||
* - a fence that can be passed to wait_cpu() and is_expired(),
|
|
||||||
* - a syncpoint id/value pair that can be returned to user space.
|
|
||||||
*/
|
|
||||||
int (*incr_user_syncpt)(struct gk20a_channel_sync *s,
|
|
||||||
struct priv_cmd_entry **entry,
|
|
||||||
struct gk20a_channel_fence *fence,
|
|
||||||
bool wfi,
|
|
||||||
u32 *id, u32 *thresh);
|
|
||||||
|
|
||||||
/* Increment syncpoint/semaphore, so that the returned fence represents
|
/* Increment syncpoint/semaphore, so that the returned fence represents
|
||||||
* work completion (may need wfi) and can be returned to user space.
|
* work completion (may need wfi) and can be returned to user space.
|
||||||
* Returns
|
* Returns
|
||||||
* - a gpu cmdbuf that performs the increment when executed,
|
* - a gpu cmdbuf that performs the increment when executed,
|
||||||
* - a fence that can be passed to wait_cpu() and is_expired(),
|
* - a fence that can be passed to wait_cpu() and is_expired(),
|
||||||
* - a sync fd that can be returned to user space.
|
* - a gk20a_fence that signals when the incr has happened.
|
||||||
*/
|
*/
|
||||||
int (*incr_user_fd)(struct gk20a_channel_sync *s,
|
int (*incr_user)(struct gk20a_channel_sync *s,
|
||||||
int wait_fence_fd,
|
int wait_fence_fd,
|
||||||
struct priv_cmd_entry **entry,
|
struct priv_cmd_entry **entry,
|
||||||
struct gk20a_channel_fence *fence,
|
struct gk20a_fence **fence,
|
||||||
bool wfi,
|
bool wfi);
|
||||||
int *fd);
|
|
||||||
|
|
||||||
/* Reset the channel syncpoint/semaphore. */
|
/* Reset the channel syncpoint/semaphore. */
|
||||||
void (*set_min_eq_max)(struct gk20a_channel_sync *s);
|
void (*set_min_eq_max)(struct gk20a_channel_sync *s);
|
||||||
|
|
||||||
|
/* Signals the sync timeline (if owned by the gk20a_channel_sync layer).
|
||||||
|
* This should be called when we notice that a gk20a_fence is
|
||||||
|
* expired. */
|
||||||
|
void (*signal_timeline)(struct gk20a_channel_sync *s);
|
||||||
|
|
||||||
/* flag to set sync destroy aggressiveness */
|
/* flag to set sync destroy aggressiveness */
|
||||||
bool aggressive_destroy;
|
bool aggressive_destroy;
|
||||||
|
|
||||||
@@ -110,7 +95,4 @@ struct gk20a_channel_sync {
|
|||||||
|
|
||||||
struct gk20a_channel_sync *gk20a_channel_sync_create(struct channel_gk20a *c);
|
struct gk20a_channel_sync *gk20a_channel_sync_create(struct channel_gk20a *c);
|
||||||
|
|
||||||
void gk20a_channel_fence_close(struct gk20a_channel_fence *f);
|
|
||||||
void gk20a_channel_fence_dup(struct gk20a_channel_fence *from,
|
|
||||||
struct gk20a_channel_fence *to);
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
229
drivers/gpu/nvgpu/gk20a/fence_gk20a.c
Normal file
229
drivers/gpu/nvgpu/gk20a/fence_gk20a.c
Normal file
@@ -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 <linux/gk20a.h>
|
||||||
|
#include <linux/file.h>
|
||||||
|
|
||||||
|
#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 <linux/nvhost.h>
|
||||||
|
#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
|
||||||
68
drivers/gpu/nvgpu/gk20a/fence_gk20a.h
Normal file
68
drivers/gpu/nvgpu/gk20a/fence_gk20a.h
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* drivers/video/tegra/host/gk20a/fence_gk20a.h
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#ifndef _GK20A_FENCE_H_
|
||||||
|
#define _GK20A_FENCE_H_
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/kref.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
|
||||||
|
struct platform_device;
|
||||||
|
struct sync_timeline;
|
||||||
|
struct sync_fence;
|
||||||
|
struct gk20a_semaphore;
|
||||||
|
struct channel_gk20a;
|
||||||
|
|
||||||
|
struct gk20a_fence_ops;
|
||||||
|
|
||||||
|
struct gk20a_fence {
|
||||||
|
/* Valid for all fence types: */
|
||||||
|
struct kref ref;
|
||||||
|
bool wfi;
|
||||||
|
struct sync_fence *sync_fence;
|
||||||
|
const struct gk20a_fence_ops *ops;
|
||||||
|
|
||||||
|
/* Valid for fences created from semaphores: */
|
||||||
|
struct gk20a_semaphore *semaphore;
|
||||||
|
wait_queue_head_t *semaphore_wq;
|
||||||
|
|
||||||
|
/* Valid for fences created from syncpoints: */
|
||||||
|
struct platform_device *host1x_pdev;
|
||||||
|
u32 syncpt_id;
|
||||||
|
u32 syncpt_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Fences can be created from semaphores or syncpoint (id, value) pairs */
|
||||||
|
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 *gk20a_fence_from_syncpt(
|
||||||
|
struct platform_device *host1x_pdev,
|
||||||
|
u32 id, u32 value, bool wfi);
|
||||||
|
|
||||||
|
/* Fence operations */
|
||||||
|
void gk20a_fence_put(struct gk20a_fence *f);
|
||||||
|
struct gk20a_fence *gk20a_fence_get(struct gk20a_fence *f);
|
||||||
|
int gk20a_fence_wait(struct gk20a_fence *f, int timeout);
|
||||||
|
bool gk20a_fence_is_expired(struct gk20a_fence *f);
|
||||||
|
int gk20a_fence_install_fd(struct gk20a_fence *f);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -371,12 +371,11 @@ struct sync_timeline *gk20a_sync_timeline_create(
|
|||||||
return &obj->obj;
|
return &obj->obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gk20a_sync_fence_create(struct sync_timeline *obj,
|
struct sync_fence *gk20a_sync_fence_create(struct sync_timeline *obj,
|
||||||
struct gk20a_semaphore *sema,
|
struct gk20a_semaphore *sema,
|
||||||
struct sync_fence *dependency,
|
struct sync_fence *dependency,
|
||||||
const char *fmt, ...)
|
const char *fmt, ...)
|
||||||
{
|
{
|
||||||
int fd;
|
|
||||||
char name[30];
|
char name[30];
|
||||||
va_list args;
|
va_list args;
|
||||||
struct sync_pt *pt;
|
struct sync_pt *pt;
|
||||||
@@ -385,7 +384,7 @@ int gk20a_sync_fence_create(struct sync_timeline *obj,
|
|||||||
|
|
||||||
pt = gk20a_sync_pt_create_inst(timeline, sema, dependency);
|
pt = gk20a_sync_pt_create_inst(timeline, sema, dependency);
|
||||||
if (pt == NULL)
|
if (pt == NULL)
|
||||||
return -ENOMEM;
|
return NULL;
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vsnprintf(name, sizeof(name), fmt, args);
|
vsnprintf(name, sizeof(name), fmt, args);
|
||||||
@@ -394,15 +393,7 @@ int gk20a_sync_fence_create(struct sync_timeline *obj,
|
|||||||
fence = sync_fence_create(name, pt);
|
fence = sync_fence_create(name, pt);
|
||||||
if (fence == NULL) {
|
if (fence == NULL) {
|
||||||
sync_pt_free(pt);
|
sync_pt_free(pt);
|
||||||
return -ENOMEM;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
return fence;
|
||||||
fd = get_unused_fd();
|
|
||||||
if (fd < 0) {
|
|
||||||
sync_fence_put(fence);
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
sync_fence_install(fence, fd);
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ struct gk20a_semaphore;
|
|||||||
struct sync_timeline *gk20a_sync_timeline_create(const char *fmt, ...);
|
struct sync_timeline *gk20a_sync_timeline_create(const char *fmt, ...);
|
||||||
void gk20a_sync_timeline_destroy(struct sync_timeline *);
|
void gk20a_sync_timeline_destroy(struct sync_timeline *);
|
||||||
void gk20a_sync_timeline_signal(struct sync_timeline *);
|
void gk20a_sync_timeline_signal(struct sync_timeline *);
|
||||||
int gk20a_sync_fence_create(struct sync_timeline *,
|
struct sync_fence *gk20a_sync_fence_create(struct sync_timeline *,
|
||||||
struct gk20a_semaphore *,
|
struct gk20a_semaphore *,
|
||||||
struct sync_fence *dependency,
|
struct sync_fence *dependency,
|
||||||
const char *fmt, ...);
|
const char *fmt, ...);
|
||||||
|
|||||||
Reference in New Issue
Block a user