static void hangcheck_handler(unsigned long data) { struct etnaviv_gpu *gpu = (struct etnaviv_gpu *)data; u32 fence = gpu->completed_fence; bool progress = false; if (fence != gpu->hangcheck_fence) { gpu->hangcheck_fence = fence; progress = true; } if (!progress) { u32 dma_addr = gpu_read(gpu, VIVS_FE_DMA_ADDRESS); int change = dma_addr - gpu->hangcheck_dma_addr; if (change < 0 || change > 16) { gpu->hangcheck_dma_addr = dma_addr; progress = true; } } if (!progress && fence_after(gpu->active_fence, fence)) { dev_err(gpu->dev, "hangcheck detected gpu lockup!\n"); dev_err(gpu->dev, " completed fence: %u\n", fence); dev_err(gpu->dev, " active fence: %u\n", gpu->active_fence); etnaviv_queue_work(gpu->drm, &gpu->recover_work); } /* if still more pending work, reset the hangcheck timer: */ if (fence_after(gpu->active_fence, gpu->hangcheck_fence)) hangcheck_timer_reset(gpu); }
static void hangcheck_handler(unsigned long data) { struct msm_gpu *gpu = (struct msm_gpu *)data; struct drm_device *dev = gpu->dev; struct msm_drm_private *priv = dev->dev_private; uint32_t fence = gpu->funcs->last_fence(gpu); if (fence != gpu->hangcheck_fence) { /* some progress has been made.. ya! */ gpu->hangcheck_fence = fence; } else if (fence < gpu->submitted_fence) { /* no progress and not done.. hung! */ gpu->hangcheck_fence = fence; dev_err(dev->dev, "%s: hangcheck detected gpu lockup!\n", gpu->name); dev_err(dev->dev, "%s: completed fence: %u\n", gpu->name, fence); dev_err(dev->dev, "%s: submitted fence: %u\n", gpu->name, gpu->submitted_fence); queue_work(priv->wq, &gpu->recover_work); } /* if still more pending work, reset the hangcheck timer: */ if (gpu->submitted_fence > gpu->hangcheck_fence) hangcheck_timer_reset(gpu); /* workaround for missing irq: */ queue_work(priv->wq, &gpu->retire_work); }
/* add bo's to gpu's ring, and kick gpu: */ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_file_private *ctx) { struct drm_device *dev = gpu->dev; struct msm_drm_private *priv = dev->dev_private; int i, ret; mutex_lock(&dev->struct_mutex); submit->fence = ++priv->next_fence; gpu->submitted_fence = submit->fence; ret = gpu->funcs->submit(gpu, submit, ctx); priv->lastctx = ctx; for (i = 0; i < submit->nr_bos; i++) { struct msm_gem_object *msm_obj = submit->bos[i].obj; /* can't happen yet.. but when we add 2d support we'll have * to deal w/ cross-ring synchronization: */ WARN_ON(is_active(msm_obj) && (msm_obj->gpu != gpu)); if (!is_active(msm_obj)) { uint32_t iova; /* ring takes a reference to the bo and iova: */ drm_gem_object_reference(&msm_obj->base); msm_gem_get_iova_locked(&msm_obj->base, submit->gpu->id, &iova); } if (submit->bos[i].flags & MSM_SUBMIT_BO_READ) msm_gem_move_to_active(&msm_obj->base, gpu, false, submit->fence); if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE) msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence); } hangcheck_timer_reset(gpu); mutex_unlock(&dev->struct_mutex); return ret; }
static void hangcheck_handler(unsigned long data) { struct msm_gpu *gpu = (struct msm_gpu *)data; uint32_t fence = gpu->funcs->last_fence(gpu); if (fence != gpu->hangcheck_fence) { /* some progress has been made.. ya! */ gpu->hangcheck_fence = fence; } else if (fence < gpu->submitted_fence) { /* no progress and not done.. hung! */ struct msm_drm_private *priv = gpu->dev->dev_private; gpu->hangcheck_fence = fence; queue_work(priv->wq, &gpu->recover_work); } /* if still more pending work, reset the hangcheck timer: */ if (gpu->submitted_fence > gpu->hangcheck_fence) hangcheck_timer_reset(gpu); }