diff options
author | Deepak Nibade <dnibade@nvidia.com> | 2016-04-18 06:16:10 -0400 |
---|---|---|
committer | Terje Bergstrom <tbergstrom@nvidia.com> | 2016-04-19 11:16:13 -0400 |
commit | e0c9da1fe9d8862fc89773208aa170b7c73d093b (patch) | |
tree | f9f0f9edbe7ae1c2f44285b0ce89385d18dc826a /drivers/gpu/nvgpu/gk20a/channel_gk20a.c | |
parent | 1c96bc6942cdae7f4e90563687da7d068aea90bc (diff) |
gpu: nvgpu: implement sync refcounting
We currently free sync when we find job list empty
If aggressive_sync is set to true, we try to free
sync during channel unbind() call
But we rarely free sync from channel_unbind() call
since freeing it when job list is empty is
aggressive enough
Hence remove sync free code from channel_unbind()
Implement refcounting for sync:
- get a refcount while submitting a job (and
allocate sync if it is not allocated already)
- put a refcount while freeing the job
- if refcount==0 and if aggressive_sync_destroy is
set, free the sync
- if aggressive_sync_destroy is not set, we will
free the sync during channel close time
Bug 200187553
Change-Id: I74e24adb15dc26a375ebca1fdd017b3ad6d57b61
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: http://git-master/r/1120410
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/gk20a/channel_gk20a.c')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 45 |
1 files changed, 13 insertions, 32 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index aeb115ef..b282db89 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c | |||
@@ -370,7 +370,6 @@ static void channel_gk20a_bind(struct channel_gk20a *c) | |||
370 | void channel_gk20a_unbind(struct channel_gk20a *ch_gk20a) | 370 | void channel_gk20a_unbind(struct channel_gk20a *ch_gk20a) |
371 | { | 371 | { |
372 | struct gk20a *g = ch_gk20a->g; | 372 | struct gk20a *g = ch_gk20a->g; |
373 | struct gk20a_platform *platform = gk20a_get_platform(g->dev); | ||
374 | 373 | ||
375 | gk20a_dbg_fn(""); | 374 | gk20a_dbg_fn(""); |
376 | 375 | ||
@@ -380,18 +379,6 @@ void channel_gk20a_unbind(struct channel_gk20a *ch_gk20a) | |||
380 | ccsr_channel_inst_bind_false_f()); | 379 | ccsr_channel_inst_bind_false_f()); |
381 | 380 | ||
382 | ch_gk20a->bound = false; | 381 | ch_gk20a->bound = false; |
383 | |||
384 | /* | ||
385 | * if we are agrressive then we can destroy the syncpt | ||
386 | * resource at this point | ||
387 | * if not, then it will be destroyed at channel_free() | ||
388 | */ | ||
389 | mutex_lock(&ch_gk20a->sync_lock); | ||
390 | if (ch_gk20a->sync && platform->aggressive_sync_destroy) { | ||
391 | ch_gk20a->sync->destroy(ch_gk20a->sync); | ||
392 | ch_gk20a->sync = NULL; | ||
393 | } | ||
394 | mutex_unlock(&ch_gk20a->sync_lock); | ||
395 | } | 382 | } |
396 | 383 | ||
397 | int channel_gk20a_alloc_inst(struct gk20a *g, struct channel_gk20a *ch) | 384 | int channel_gk20a_alloc_inst(struct gk20a *g, struct channel_gk20a *ch) |
@@ -954,7 +941,7 @@ static void gk20a_free_channel(struct channel_gk20a *ch) | |||
954 | /* sync must be destroyed before releasing channel vm */ | 941 | /* sync must be destroyed before releasing channel vm */ |
955 | mutex_lock(&ch->sync_lock); | 942 | mutex_lock(&ch->sync_lock); |
956 | if (ch->sync) { | 943 | if (ch->sync) { |
957 | ch->sync->destroy(ch->sync); | 944 | gk20a_channel_sync_destroy(ch->sync); |
958 | ch->sync = NULL; | 945 | ch->sync = NULL; |
959 | } | 946 | } |
960 | mutex_unlock(&ch->sync_lock); | 947 | mutex_unlock(&ch->sync_lock); |
@@ -1922,8 +1909,18 @@ static void gk20a_channel_clean_up_jobs(struct work_struct *work) | |||
1922 | 1909 | ||
1923 | gk20a_channel_timeout_stop(c); | 1910 | gk20a_channel_timeout_stop(c); |
1924 | 1911 | ||
1925 | if (c->sync) | 1912 | mutex_lock(&c->sync_lock); |
1913 | if (c->sync) { | ||
1926 | c->sync->signal_timeline(c->sync); | 1914 | c->sync->signal_timeline(c->sync); |
1915 | if (atomic_dec_and_test(&c->sync->refcount) && | ||
1916 | platform->aggressive_sync_destroy) { | ||
1917 | gk20a_channel_sync_destroy(c->sync); | ||
1918 | c->sync = NULL; | ||
1919 | } | ||
1920 | } else { | ||
1921 | WARN_ON(1); | ||
1922 | } | ||
1923 | mutex_unlock(&c->sync_lock); | ||
1927 | 1924 | ||
1928 | if (job->num_mapped_buffers) | 1925 | if (job->num_mapped_buffers) |
1929 | gk20a_vm_put_buffers(vm, job->mapped_buffers, | 1926 | gk20a_vm_put_buffers(vm, job->mapped_buffers, |
@@ -1950,23 +1947,6 @@ static void gk20a_channel_clean_up_jobs(struct work_struct *work) | |||
1950 | gk20a_idle(g->dev); | 1947 | gk20a_idle(g->dev); |
1951 | } | 1948 | } |
1952 | 1949 | ||
1953 | /* | ||
1954 | * If job list is empty then channel is idle and we can free | ||
1955 | * the syncpt here (given aggressive_destroy flag is set) | ||
1956 | * Note: check if last submit is complete before destroying | ||
1957 | * the sync resource | ||
1958 | */ | ||
1959 | if (list_empty(&c->jobs)) { | ||
1960 | mutex_lock(&c->sync_lock); | ||
1961 | mutex_lock(&c->last_submit.fence_lock); | ||
1962 | if (c->sync && platform->aggressive_sync_destroy && | ||
1963 | gk20a_fence_is_expired(c->last_submit.post_fence)) { | ||
1964 | c->sync->destroy(c->sync); | ||
1965 | c->sync = NULL; | ||
1966 | } | ||
1967 | mutex_unlock(&c->last_submit.fence_lock); | ||
1968 | mutex_unlock(&c->sync_lock); | ||
1969 | } | ||
1970 | mutex_unlock(&c->jobs_lock); | 1950 | mutex_unlock(&c->jobs_lock); |
1971 | mutex_unlock(&c->submit_lock); | 1951 | mutex_unlock(&c->submit_lock); |
1972 | 1952 | ||
@@ -2121,6 +2101,7 @@ int gk20a_submit_channel_gpfifo(struct channel_gk20a *c, | |||
2121 | } | 2101 | } |
2122 | new_sync_created = true; | 2102 | new_sync_created = true; |
2123 | } | 2103 | } |
2104 | atomic_inc(&c->sync->refcount); | ||
2124 | mutex_unlock(&c->sync_lock); | 2105 | mutex_unlock(&c->sync_lock); |
2125 | 2106 | ||
2126 | if (g->ops.fifo.resetup_ramfc && new_sync_created) { | 2107 | if (g->ops.fifo.resetup_ramfc && new_sync_created) { |