diff options
author | Alex Waterman <alexw@nvidia.com> | 2016-11-08 14:40:10 -0500 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2017-01-04 18:53:55 -0500 |
commit | 91d977ced46f5db02da077df8703e958c5e2af4e (patch) | |
tree | 195b96e91f34933dd56b8aa5206295a093fbff11 /drivers/gpu | |
parent | a0242464f5f12d9f10fbf0d05614bfadde84386c (diff) |
gpu: nvgpu: Misc fixes for crashes on shutdown
Fix miscellaneous issues seen during driver shutdown.
o Make sure pointers are valid before accessing them.
o Busy the GPU during channel timeout.
o Cancel delayed work on channels.
o Avoid access to channels that may have been freed.
Bug 1816516
Bug 1807277
Change-Id: I62df40373fdfb1c4a011364e8c435176a08a7a96
Signed-off-by: Alex Waterman <alexw@nvidia.com>
Reviewed-on: http://git-master/r/1250026
(cherry picked from commit 64a95fc96c8ef7c5af9c53c4bb3402626e0d2f60)
Reviewed-on: http://git-master/r/1274474
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/channel_gk20a.c | 11 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/mm_gk20a.c | 15 |
2 files changed, 24 insertions, 2 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c index 15170820..7b5013ea 100644 --- a/drivers/gpu/nvgpu/gk20a/channel_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/channel_gk20a.c | |||
@@ -1038,6 +1038,8 @@ static void gk20a_free_channel(struct channel_gk20a *ch, bool force) | |||
1038 | ch->update_fn_data = NULL; | 1038 | ch->update_fn_data = NULL; |
1039 | spin_unlock(&ch->update_fn_lock); | 1039 | spin_unlock(&ch->update_fn_lock); |
1040 | cancel_work_sync(&ch->update_fn_work); | 1040 | cancel_work_sync(&ch->update_fn_work); |
1041 | cancel_delayed_work_sync(&ch->clean_up.wq); | ||
1042 | cancel_delayed_work_sync(&ch->timeout.wq); | ||
1041 | 1043 | ||
1042 | /* make sure we don't have deferred interrupts pending that | 1044 | /* make sure we don't have deferred interrupts pending that |
1043 | * could still touch the channel */ | 1045 | * could still touch the channel */ |
@@ -1177,8 +1179,7 @@ int gk20a_channel_release(struct inode *inode, struct file *filp) | |||
1177 | 1179 | ||
1178 | err = gk20a_busy(g->dev); | 1180 | err = gk20a_busy(g->dev); |
1179 | if (err) { | 1181 | if (err) { |
1180 | gk20a_err(dev_from_gk20a(g), "failed to release channel %d", | 1182 | gk20a_err(dev_from_gk20a(g), "failed to release a channel!"); |
1181 | ch->hw_chid); | ||
1182 | return err; | 1183 | return err; |
1183 | } | 1184 | } |
1184 | 1185 | ||
@@ -2108,6 +2109,11 @@ static void gk20a_channel_timeout_handler(struct work_struct *work) | |||
2108 | 2109 | ||
2109 | g = ch->g; | 2110 | g = ch->g; |
2110 | 2111 | ||
2112 | if (gk20a_busy(dev_from_gk20a(g))) { | ||
2113 | gk20a_channel_put(ch); | ||
2114 | return; | ||
2115 | } | ||
2116 | |||
2111 | /* Need global lock since multiple channels can timeout at a time */ | 2117 | /* Need global lock since multiple channels can timeout at a time */ |
2112 | mutex_lock(&g->ch_wdt_lock); | 2118 | mutex_lock(&g->ch_wdt_lock); |
2113 | 2119 | ||
@@ -2139,6 +2145,7 @@ static void gk20a_channel_timeout_handler(struct work_struct *work) | |||
2139 | fail_unlock: | 2145 | fail_unlock: |
2140 | mutex_unlock(&g->ch_wdt_lock); | 2146 | mutex_unlock(&g->ch_wdt_lock); |
2141 | gk20a_channel_put(ch); | 2147 | gk20a_channel_put(ch); |
2148 | gk20a_idle(dev_from_gk20a(g)); | ||
2142 | } | 2149 | } |
2143 | 2150 | ||
2144 | int gk20a_free_priv_cmdbuf(struct channel_gk20a *c, struct priv_cmd_entry *e) | 2151 | int gk20a_free_priv_cmdbuf(struct channel_gk20a *c, struct priv_cmd_entry *e) |
diff --git a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c index 792fa098..2e338fef 100644 --- a/drivers/gpu/nvgpu/gk20a/mm_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/mm_gk20a.c | |||
@@ -219,6 +219,11 @@ static inline void pramin_access_batch_rd_n(struct gk20a *g, u32 start, | |||
219 | { | 219 | { |
220 | u32 r = start, *dest_u32 = *arg; | 220 | u32 r = start, *dest_u32 = *arg; |
221 | 221 | ||
222 | if (!g->regs) { | ||
223 | __gk20a_warn_on_no_regs(); | ||
224 | return; | ||
225 | } | ||
226 | |||
222 | while (words--) { | 227 | while (words--) { |
223 | *dest_u32++ = gk20a_readl(g, r); | 228 | *dest_u32++ = gk20a_readl(g, r); |
224 | r += sizeof(u32); | 229 | r += sizeof(u32); |
@@ -232,6 +237,11 @@ static inline void pramin_access_batch_wr_n(struct gk20a *g, u32 start, | |||
232 | { | 237 | { |
233 | u32 r = start, *src_u32 = *arg; | 238 | u32 r = start, *src_u32 = *arg; |
234 | 239 | ||
240 | if (!g->regs) { | ||
241 | __gk20a_warn_on_no_regs(); | ||
242 | return; | ||
243 | } | ||
244 | |||
235 | while (words--) { | 245 | while (words--) { |
236 | writel_relaxed(*src_u32++, g->regs + r); | 246 | writel_relaxed(*src_u32++, g->regs + r); |
237 | r += sizeof(u32); | 247 | r += sizeof(u32); |
@@ -245,6 +255,11 @@ static inline void pramin_access_batch_set(struct gk20a *g, u32 start, | |||
245 | { | 255 | { |
246 | u32 r = start, repeat = **arg; | 256 | u32 r = start, repeat = **arg; |
247 | 257 | ||
258 | if (!g->regs) { | ||
259 | __gk20a_warn_on_no_regs(); | ||
260 | return; | ||
261 | } | ||
262 | |||
248 | while (words--) { | 263 | while (words--) { |
249 | writel_relaxed(repeat, g->regs + r); | 264 | writel_relaxed(repeat, g->regs + r); |
250 | r += sizeof(u32); | 265 | r += sizeof(u32); |