diff options
author | Deepak Nibade <dnibade@nvidia.com> | 2018-03-20 07:51:23 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2018-03-23 11:20:35 -0400 |
commit | b5b4353ca6cc9b6457ddccc00bf87538291870fc (patch) | |
tree | 1e2334728031345a3cb042bcc934bb0d9e3b0f82 | |
parent | 2aead38194fb6f3166a9ccb501467f7b0662f6c1 (diff) |
gpu: nvgpu: set safe state for user managed syncpoints
MAX/threshold value of user managed syncpoint is not tracked by nvgpu
So if channel is reset by nvgpu there could be waiters still waiting on some
user syncpoint fence
Fix this by setting a large safe value to user managed syncpoint when aborting
the channel and when closing the channel
We right now increment the current value by 0x10000 which should be sufficient
to release any pending waiter
Bug 200326065
Jira NVGPU-179
Change-Id: Ie6432369bb4c21bd922c14b8d5a74c1477116f0b
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1678768
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
GVS: Gerrit_Virtual_Submit
Reviewed-by: Konsta Holtta <kholtta@nvidia.com>
Reviewed-by: Vijayakumar Subbu <vsubbu@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
-rw-r--r-- | drivers/gpu/nvgpu/common/linux/nvhost.c | 19 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 18 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_sync_gk20a.c | 19 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_sync_gk20a.h | 10 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/include/nvgpu/nvhost.h | 2 |
5 files changed, 62 insertions, 6 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/nvhost.c b/drivers/gpu/nvgpu/common/linux/nvhost.c index a76953e3..fa169cf0 100644 --- a/drivers/gpu/nvgpu/common/linux/nvhost.c +++ b/drivers/gpu/nvgpu/common/linux/nvhost.c | |||
@@ -166,6 +166,25 @@ u32 nvgpu_nvhost_syncpt_read_maxval( | |||
166 | return nvhost_syncpt_read_maxval(nvhost_dev->host1x_pdev, id); | 166 | return nvhost_syncpt_read_maxval(nvhost_dev->host1x_pdev, id); |
167 | } | 167 | } |
168 | 168 | ||
169 | void nvgpu_nvhost_syncpt_set_safe_state( | ||
170 | struct nvgpu_nvhost_dev *nvhost_dev, u32 id) | ||
171 | { | ||
172 | u32 val; | ||
173 | |||
174 | /* | ||
175 | * Add large number of increments to current value | ||
176 | * so that all waiters on this syncpoint are released | ||
177 | * | ||
178 | * We don't expect any case where more than 0x10000 increments | ||
179 | * are pending | ||
180 | */ | ||
181 | val = nvhost_syncpt_read_minval(nvhost_dev->host1x_pdev, id); | ||
182 | val += 0x10000; | ||
183 | |||
184 | nvhost_syncpt_set_minval(nvhost_dev->host1x_pdev, id, val); | ||
185 | nvhost_syncpt_set_maxval(nvhost_dev->host1x_pdev, id, val); | ||
186 | } | ||
187 | |||
169 | int nvgpu_nvhost_create_symlink(struct gk20a *g) | 188 | int nvgpu_nvhost_create_symlink(struct gk20a *g) |
170 | { | 189 | { |
171 | struct device *dev = dev_from_gk20a(g); | 190 | struct device *dev = dev_from_gk20a(g); |
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index 78953558..65b17304 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c | |||
@@ -196,6 +196,8 @@ void gk20a_channel_abort_clean_up(struct channel_gk20a *ch) | |||
196 | nvgpu_mutex_acquire(&ch->sync_lock); | 196 | nvgpu_mutex_acquire(&ch->sync_lock); |
197 | if (ch->sync) | 197 | if (ch->sync) |
198 | ch->sync->set_min_eq_max(ch->sync); | 198 | ch->sync->set_min_eq_max(ch->sync); |
199 | if (ch->user_sync) | ||
200 | ch->user_sync->set_safe_state(ch->user_sync); | ||
199 | nvgpu_mutex_release(&ch->sync_lock); | 201 | nvgpu_mutex_release(&ch->sync_lock); |
200 | 202 | ||
201 | /* release all job semaphores (applies only to jobs that use | 203 | /* release all job semaphores (applies only to jobs that use |
@@ -435,11 +437,18 @@ static void gk20a_free_channel(struct channel_gk20a *ch, bool force) | |||
435 | /* sync must be destroyed before releasing channel vm */ | 437 | /* sync must be destroyed before releasing channel vm */ |
436 | nvgpu_mutex_acquire(&ch->sync_lock); | 438 | nvgpu_mutex_acquire(&ch->sync_lock); |
437 | if (ch->sync) { | 439 | if (ch->sync) { |
438 | gk20a_channel_sync_destroy(ch->sync); | 440 | gk20a_channel_sync_destroy(ch->sync, false); |
439 | ch->sync = NULL; | 441 | ch->sync = NULL; |
440 | } | 442 | } |
441 | if (ch->user_sync) { | 443 | if (ch->user_sync) { |
442 | gk20a_channel_sync_destroy(ch->user_sync); | 444 | /* |
445 | * Set user managed syncpoint to safe state | ||
446 | * But it's already done if channel has timedout | ||
447 | */ | ||
448 | if (ch->has_timedout) | ||
449 | gk20a_channel_sync_destroy(ch->user_sync, false); | ||
450 | else | ||
451 | gk20a_channel_sync_destroy(ch->user_sync, true); | ||
443 | ch->user_sync = NULL; | 452 | ch->user_sync = NULL; |
444 | } | 453 | } |
445 | nvgpu_mutex_release(&ch->sync_lock); | 454 | nvgpu_mutex_release(&ch->sync_lock); |
@@ -1211,7 +1220,7 @@ clean_up_prealloc: | |||
1211 | channel_gk20a_free_prealloc_resources(c); | 1220 | channel_gk20a_free_prealloc_resources(c); |
1212 | clean_up_sync: | 1221 | clean_up_sync: |
1213 | if (c->sync) { | 1222 | if (c->sync) { |
1214 | gk20a_channel_sync_destroy(c->sync); | 1223 | gk20a_channel_sync_destroy(c->sync, false); |
1215 | c->sync = NULL; | 1224 | c->sync = NULL; |
1216 | } | 1225 | } |
1217 | clean_up_unmap: | 1226 | clean_up_unmap: |
@@ -1905,7 +1914,8 @@ void gk20a_channel_clean_up_jobs(struct channel_gk20a *c, | |||
1905 | if (nvgpu_atomic_dec_and_test( | 1914 | if (nvgpu_atomic_dec_and_test( |
1906 | &c->sync->refcount) && | 1915 | &c->sync->refcount) && |
1907 | g->aggressive_sync_destroy) { | 1916 | g->aggressive_sync_destroy) { |
1908 | gk20a_channel_sync_destroy(c->sync); | 1917 | gk20a_channel_sync_destroy(c->sync, |
1918 | false); | ||
1909 | c->sync = NULL; | 1919 | c->sync = NULL; |
1910 | } | 1920 | } |
1911 | nvgpu_mutex_release(&c->sync_lock); | 1921 | nvgpu_mutex_release(&c->sync_lock); |
diff --git a/drivers/gpu/nvgpu/gk20a/channel_sync_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_sync_gk20a.c index 3c12147f..236ddaaf 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_sync_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_sync_gk20a.c | |||
@@ -280,6 +280,13 @@ static void gk20a_channel_syncpt_set_min_eq_max(struct gk20a_channel_sync *s) | |||
280 | nvgpu_nvhost_syncpt_set_min_eq_max_ext(sp->nvhost_dev, sp->id); | 280 | nvgpu_nvhost_syncpt_set_min_eq_max_ext(sp->nvhost_dev, sp->id); |
281 | } | 281 | } |
282 | 282 | ||
283 | static void gk20a_channel_syncpt_set_safe_state(struct gk20a_channel_sync *s) | ||
284 | { | ||
285 | struct gk20a_channel_syncpt *sp = | ||
286 | container_of(s, struct gk20a_channel_syncpt, ops); | ||
287 | nvgpu_nvhost_syncpt_set_safe_state(sp->nvhost_dev, sp->id); | ||
288 | } | ||
289 | |||
283 | static void gk20a_channel_syncpt_signal_timeline( | 290 | static void gk20a_channel_syncpt_signal_timeline( |
284 | struct gk20a_channel_sync *s) | 291 | struct gk20a_channel_sync *s) |
285 | { | 292 | { |
@@ -357,6 +364,7 @@ gk20a_channel_syncpt_create(struct channel_gk20a *c, bool user_managed) | |||
357 | sp->ops.incr_wfi = gk20a_channel_syncpt_incr_wfi; | 364 | sp->ops.incr_wfi = gk20a_channel_syncpt_incr_wfi; |
358 | sp->ops.incr_user = gk20a_channel_syncpt_incr_user; | 365 | sp->ops.incr_user = gk20a_channel_syncpt_incr_user; |
359 | sp->ops.set_min_eq_max = gk20a_channel_syncpt_set_min_eq_max; | 366 | sp->ops.set_min_eq_max = gk20a_channel_syncpt_set_min_eq_max; |
367 | sp->ops.set_safe_state = gk20a_channel_syncpt_set_safe_state; | ||
360 | sp->ops.signal_timeline = gk20a_channel_syncpt_signal_timeline; | 368 | sp->ops.signal_timeline = gk20a_channel_syncpt_signal_timeline; |
361 | sp->ops.syncpt_id = gk20a_channel_syncpt_id; | 369 | sp->ops.syncpt_id = gk20a_channel_syncpt_id; |
362 | sp->ops.syncpt_address = gk20a_channel_syncpt_address; | 370 | sp->ops.syncpt_address = gk20a_channel_syncpt_address; |
@@ -634,6 +642,11 @@ static void gk20a_channel_semaphore_set_min_eq_max(struct gk20a_channel_sync *s) | |||
634 | /* Nothing to do. */ | 642 | /* Nothing to do. */ |
635 | } | 643 | } |
636 | 644 | ||
645 | static void gk20a_channel_semaphore_set_safe_state(struct gk20a_channel_sync *s) | ||
646 | { | ||
647 | /* Nothing to do. */ | ||
648 | } | ||
649 | |||
637 | static void gk20a_channel_semaphore_signal_timeline( | 650 | static void gk20a_channel_semaphore_signal_timeline( |
638 | struct gk20a_channel_sync *s) | 651 | struct gk20a_channel_sync *s) |
639 | { | 652 | { |
@@ -703,6 +716,7 @@ gk20a_channel_semaphore_create(struct channel_gk20a *c, bool user_managed) | |||
703 | sema->ops.incr_wfi = gk20a_channel_semaphore_incr_wfi; | 716 | sema->ops.incr_wfi = gk20a_channel_semaphore_incr_wfi; |
704 | sema->ops.incr_user = gk20a_channel_semaphore_incr_user; | 717 | sema->ops.incr_user = gk20a_channel_semaphore_incr_user; |
705 | sema->ops.set_min_eq_max = gk20a_channel_semaphore_set_min_eq_max; | 718 | sema->ops.set_min_eq_max = gk20a_channel_semaphore_set_min_eq_max; |
719 | sema->ops.set_safe_state = gk20a_channel_semaphore_set_safe_state; | ||
706 | sema->ops.signal_timeline = gk20a_channel_semaphore_signal_timeline; | 720 | sema->ops.signal_timeline = gk20a_channel_semaphore_signal_timeline; |
707 | sema->ops.syncpt_id = gk20a_channel_semaphore_syncpt_id; | 721 | sema->ops.syncpt_id = gk20a_channel_semaphore_syncpt_id; |
708 | sema->ops.syncpt_address = gk20a_channel_semaphore_syncpt_address; | 722 | sema->ops.syncpt_address = gk20a_channel_semaphore_syncpt_address; |
@@ -711,8 +725,11 @@ gk20a_channel_semaphore_create(struct channel_gk20a *c, bool user_managed) | |||
711 | return &sema->ops; | 725 | return &sema->ops; |
712 | } | 726 | } |
713 | 727 | ||
714 | void gk20a_channel_sync_destroy(struct gk20a_channel_sync *sync) | 728 | void gk20a_channel_sync_destroy(struct gk20a_channel_sync *sync, |
729 | bool set_safe_state) | ||
715 | { | 730 | { |
731 | if (set_safe_state) | ||
732 | sync->set_safe_state(sync); | ||
716 | sync->destroy(sync); | 733 | sync->destroy(sync); |
717 | } | 734 | } |
718 | 735 | ||
diff --git a/drivers/gpu/nvgpu/gk20a/channel_sync_gk20a.h b/drivers/gpu/nvgpu/gk20a/channel_sync_gk20a.h index 3f44b27a..da8cb251 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_sync_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/channel_sync_gk20a.h | |||
@@ -86,6 +86,13 @@ struct gk20a_channel_sync { | |||
86 | /* Reset the channel syncpoint/semaphore. */ | 86 | /* Reset the channel syncpoint/semaphore. */ |
87 | void (*set_min_eq_max)(struct gk20a_channel_sync *s); | 87 | void (*set_min_eq_max)(struct gk20a_channel_sync *s); |
88 | 88 | ||
89 | /* | ||
90 | * Set the channel syncpoint/semaphore to safe state | ||
91 | * This should be used to reset User managed syncpoint since we don't | ||
92 | * track threshold values for those syncpoints | ||
93 | */ | ||
94 | void (*set_safe_state)(struct gk20a_channel_sync *s); | ||
95 | |||
89 | /* Signals the sync timeline (if owned by the gk20a_channel_sync layer). | 96 | /* Signals the sync timeline (if owned by the gk20a_channel_sync layer). |
90 | * This should be called when we notice that a gk20a_fence is | 97 | * This should be called when we notice that a gk20a_fence is |
91 | * expired. */ | 98 | * expired. */ |
@@ -101,7 +108,8 @@ struct gk20a_channel_sync { | |||
101 | void (*destroy)(struct gk20a_channel_sync *s); | 108 | void (*destroy)(struct gk20a_channel_sync *s); |
102 | }; | 109 | }; |
103 | 110 | ||
104 | void gk20a_channel_sync_destroy(struct gk20a_channel_sync *sync); | 111 | void gk20a_channel_sync_destroy(struct gk20a_channel_sync *sync, |
112 | bool set_safe_state); | ||
105 | struct gk20a_channel_sync *gk20a_channel_sync_create(struct channel_gk20a *c, | 113 | struct gk20a_channel_sync *gk20a_channel_sync_create(struct channel_gk20a *c, |
106 | bool user_managed); | 114 | bool user_managed); |
107 | bool gk20a_channel_sync_needs_sync_framework(struct gk20a *g); | 115 | bool gk20a_channel_sync_needs_sync_framework(struct gk20a *g); |
diff --git a/drivers/gpu/nvgpu/include/nvgpu/nvhost.h b/drivers/gpu/nvgpu/include/nvgpu/nvhost.h index d5b5831a..13de012a 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/nvhost.h +++ b/drivers/gpu/nvgpu/include/nvgpu/nvhost.h | |||
@@ -52,6 +52,8 @@ int nvgpu_nvhost_syncpt_read_ext_check(struct nvgpu_nvhost_dev *nvhost_dev, | |||
52 | u32 id, u32 *val); | 52 | u32 id, u32 *val); |
53 | u32 nvgpu_nvhost_syncpt_read_maxval(struct nvgpu_nvhost_dev *nvhost_dev, | 53 | u32 nvgpu_nvhost_syncpt_read_maxval(struct nvgpu_nvhost_dev *nvhost_dev, |
54 | u32 id); | 54 | u32 id); |
55 | void nvgpu_nvhost_syncpt_set_safe_state( | ||
56 | struct nvgpu_nvhost_dev *nvhost_dev, u32 id); | ||
55 | 57 | ||
56 | int nvgpu_nvhost_intr_register_notifier(struct nvgpu_nvhost_dev *nvhost_dev, | 58 | int nvgpu_nvhost_intr_register_notifier(struct nvgpu_nvhost_dev *nvhost_dev, |
57 | u32 id, u32 thresh, void (*callback)(void *, int), void *private_data); | 59 | u32 id, u32 thresh, void (*callback)(void *, int), void *private_data); |