Wait for engine idle via FIFO's engine status instead of submitting
WFI to channel. Submitting WFI and waiting is not robust, and wait
might invoke debug dump which cannot be done while powering down.
Bug
1499214
Change-Id: I4d52e8558e1a862ad4292036594d81ebfbd5f36b
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: http://git-master/r/432151
(cherry picked from commit
3719dff8287f5402eea81acb19ae21f028b1b968)
Reviewed-on: http://git-master/r/432154
Reviewed-by: Emad Mir <emir@nvidia.com>
Tested-by: Emad Mir <emir@nvidia.com>
struct fifo_gk20a *f = &g->fifo;
u32 chid;
bool channels_in_use = false;
- struct device *d = dev_from_gk20a(g);
int err;
gk20a_dbg_fn("");
- /* idle the engine by submitting WFI on non-KEPLER_C channel */
- for (chid = 0; chid < f->num_channels; chid++) {
- struct channel_gk20a *c = &f->channel[chid];
- if (c->in_use && c->obj_class != KEPLER_C && !c->has_timedout) {
- err = gk20a_channel_submit_wfi(c);
- if (err) {
- gk20a_err(d, "cannot idle channel %d\n",
- chid);
- return err;
- }
-
- c->sync->wait_cpu(c->sync, &c->last_submit_fence,
- 500000);
- break;
- }
- }
+ /* wait for engine idle */
+ err = gk20a_fifo_wait_engine_idle(g);
+ if (err)
+ return err;
for (chid = 0; chid < f->num_channels; chid++) {
if (f->channel[chid].in_use) {
break;
}
+ gk20a_dbg(gpu_dbg_fn|gpu_dbg_gpu_dbg, "%s powergate mode = %d done",
+ dev_name(dbg_s->dev), powermode);
return err;
}
return false;
}
+int gk20a_fifo_wait_engine_idle(struct gk20a *g)
+{
+ unsigned long end_jiffies = jiffies +
+ msecs_to_jiffies(gk20a_get_gr_idle_timeout(g));
+ unsigned long delay = GR_IDLE_CHECK_DEFAULT;
+ int ret = -ETIMEDOUT;
+ u32 i;
+ struct device *d = dev_from_gk20a(g);
+
+ gk20a_dbg_fn("");
+
+ for (i = 0; i < fifo_engine_status__size_1_v(); i++) {
+ do {
+ u32 status = gk20a_readl(g, fifo_engine_status_r(i));
+ if (!fifo_engine_status_engine_v(status)) {
+ ret = 0;
+ break;
+ }
+
+ usleep_range(delay, delay * 2);
+ delay = min_t(unsigned long,
+ delay << 1, GR_IDLE_CHECK_MAX);
+ } while (time_before(jiffies, end_jiffies) ||
+ !tegra_platform_is_silicon());
+ if (ret) {
+ gk20a_err(d, "cannot idle engine %u\n", i);
+ break;
+ }
+ }
+
+ gk20a_dbg_fn("done");
+
+ return ret;
+}
+
void gk20a_init_fifo(struct gpu_ops *gops)
{
gk20a_init_channel(gops);
void fifo_gk20a_finish_mmu_fault_handling(struct gk20a *g,
unsigned long fault_id);
+int gk20a_fifo_wait_engine_idle(struct gk20a *g);
#endif /*__GR_GK20A_H__*/