diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 6d6b2efc6d13..9a97d1627b67 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -806,7 +806,7 @@ struct adreno_gpudev { int (*preemption_init)(struct adreno_device *adreno_dev); void (*preemption_schedule)(struct adreno_device *adreno_dev); int (*preemption_context_init)(struct kgsl_context *context); - void (*preemption_context_destroy)(struct kgsl_context *context); + void (*context_detach)(struct adreno_context *drawctxt); void (*clk_set_options)(struct adreno_device *adreno_dev, const char *name, struct clk *clk, bool on); void (*pre_reset)(struct adreno_device *adreno_dev); diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index e533930aba74..fb9cda3c9713 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -2801,7 +2801,6 @@ struct adreno_gpudev adreno_a6xx_gpudev = { .preemption_schedule = a6xx_preemption_schedule, .set_marker = a6xx_set_marker, .preemption_context_init = a6xx_preemption_context_init, - .preemption_context_destroy = a6xx_preemption_context_destroy, .sptprac_is_on = a6xx_sptprac_is_on, .ccu_invalidate = a6xx_ccu_invalidate, .perfcounter_update = a6xx_perfcounter_update, @@ -2824,7 +2823,7 @@ struct adreno_gpudev adreno_a6xx_hwsched_gpudev = { .read_throttling_counters = a6xx_read_throttling_counters, .iommu_fault_block = a6xx_iommu_fault_block, .preemption_context_init = a6xx_preemption_context_init, - .preemption_context_destroy = a6xx_preemption_context_destroy, + .context_detach = a6xx_hwsched_context_detach, .perfcounter_update = a6xx_perfcounter_update, #ifdef CONFIG_QCOM_KGSL_CORESIGHT .coresight = {&a6xx_coresight, &a6xx_coresight_cx}, @@ -2856,7 +2855,6 @@ struct adreno_gpudev adreno_a6xx_gmu_gpudev = { .preemption_schedule = a6xx_preemption_schedule, .set_marker = a6xx_set_marker, .preemption_context_init = a6xx_preemption_context_init, - .preemption_context_destroy = a6xx_preemption_context_destroy, .sptprac_is_on = a6xx_sptprac_is_on, .ccu_invalidate = a6xx_ccu_invalidate, .perfcounter_update = a6xx_perfcounter_update, @@ -2890,7 +2888,6 @@ struct adreno_gpudev adreno_a6xx_rgmu_gpudev = { .preemption_schedule = a6xx_preemption_schedule, .set_marker = a6xx_set_marker, .preemption_context_init = a6xx_preemption_context_init, - .preemption_context_destroy = a6xx_preemption_context_destroy, .sptprac_is_on = a6xx_sptprac_is_on, .ccu_invalidate = a6xx_ccu_invalidate, .perfcounter_update = a6xx_perfcounter_update, @@ -2924,7 +2921,6 @@ struct adreno_gpudev adreno_a619_holi_gpudev = { .preemption_schedule = a6xx_preemption_schedule, .set_marker = a6xx_set_marker, .preemption_context_init = a6xx_preemption_context_init, - .preemption_context_destroy = a6xx_preemption_context_destroy, .sptprac_is_on = a6xx_sptprac_is_on, .ccu_invalidate = a6xx_ccu_invalidate, .perfcounter_update = a6xx_perfcounter_update, @@ -2961,7 +2957,6 @@ struct adreno_gpudev adreno_a630_gpudev = { .preemption_schedule = a6xx_preemption_schedule, .set_marker = a6xx_set_marker, .preemption_context_init = a6xx_preemption_context_init, - .preemption_context_destroy = a6xx_preemption_context_destroy, .sptprac_is_on = a6xx_sptprac_is_on, .ccu_invalidate = a6xx_ccu_invalidate, .perfcounter_update = a6xx_perfcounter_update, diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched.c b/drivers/gpu/msm/adreno_a6xx_hwsched.c index adb03fecc1ff..a6c9f5b85fbb 100644 --- a/drivers/gpu/msm/adreno_a6xx_hwsched.c +++ b/drivers/gpu/msm/adreno_a6xx_hwsched.c @@ -177,6 +177,21 @@ static void a6xx_hwsched_active_count_put(struct adreno_device *adreno_dev) wake_up(&device->active_cnt_wq); } +static int unregister_context_hwsched(int id, void *ptr, void *data) +{ + struct kgsl_context *context = ptr; + + /* + * We don't need to send the unregister hfi packet because + * we are anyway going to lose the gmu state of registered + * contexts. So just reset the flag so that the context + * registers with gmu on its first submission post slumber. + */ + context->gmu_registered = false; + + return 0; +} + static int a6xx_hwsched_notify_slumber(struct adreno_device *adreno_dev) { struct kgsl_device *device = KGSL_DEVICE(adreno_dev); @@ -477,6 +492,10 @@ no_gx_power: a6xx_hwsched_gmu_power_off(adreno_dev); + read_lock(&device->context_lock); + idr_for_each(&device->context_idr, unregister_context_hwsched, NULL); + read_unlock(&device->context_lock); + if (!IS_ERR_OR_NULL(adreno_dev->gpu_llc_slice)) llcc_slice_deactivate(adreno_dev->gpu_llc_slice); @@ -695,9 +714,13 @@ static int a6xx_hwsched_bind(struct device *dev, struct device *master, ret = a6xx_hwsched_hfi_probe(ADRENO_DEVICE(device)); + if (!ret) { + set_bit(GMU_DISPATCH, &device->gmu_core.flags); + return 0; + } + error: - if (ret) - a6xx_gmu_remove(device); + a6xx_gmu_remove(device); return ret; } diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c index 7c1da23afdd9..a56e3d9c6eb1 100644 --- a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c +++ b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.c @@ -911,3 +911,84 @@ free: return ret; } + +static int send_context_unregister_hfi(struct adreno_device *adreno_dev, + u32 ctxt_id, u32 ts) +{ + struct kgsl_device *device = KGSL_DEVICE(adreno_dev); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + struct a6xx_hwsched_hfi *hfi = to_a6xx_hwsched_hfi(adreno_dev); + struct pending_cmd pending_ack; + struct hfi_unregister_ctxt_cmd cmd; + u32 seqnum; + int rc; + + cmd.hdr = CMD_MSG_HDR(H2F_MSG_UNREGISTER_CONTEXT, sizeof(cmd)); + cmd.ctxt_id = ctxt_id, + cmd.ts = ts, + + seqnum = atomic_inc_return(&gmu->hfi.seqnum); + cmd.hdr = MSG_HDR_SET_SEQNUM(cmd.hdr, seqnum); + + add_waiter(hfi, cmd.hdr, &pending_ack); + + rc = a6xx_hfi_cmdq_write(adreno_dev, (u32 *)&cmd); + if (rc) + goto done; + + mutex_unlock(&device->mutex); + + rc = wait_for_completion_timeout(&pending_ack.complete, + msecs_to_jiffies(30 * 1000)); + if (!rc) { + dev_err(&gmu->pdev->dev, + "Ack timeout for context unregister seq: %d ctx: %d ts: %d\n", + MSG_HDR_GET_SEQNUM(pending_ack.sent_hdr), + ctxt_id, ts); + rc = -ETIMEDOUT; + mutex_lock(&device->mutex); + gmu_fault_snapshot(device); + goto done; + } + + mutex_lock(&device->mutex); + + rc = check_ack_failure(adreno_dev, &pending_ack); +done: + del_waiter(hfi, &pending_ack); + + return rc; +} + +void a6xx_hwsched_context_detach(struct adreno_context *drawctxt) +{ + struct kgsl_context *context = &drawctxt->base; + struct kgsl_device *device = context->device; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev); + int ret = 0; + + mutex_lock(&device->mutex); + + /* Only send HFI if device is not in SLUMBER */ + if (context->gmu_registered && + test_bit(GMU_PRIV_GPU_STARTED, &gmu->flags)) + ret = send_context_unregister_hfi(adreno_dev, context->id, + drawctxt->internal_timestamp); + + if (!ret) { + kgsl_sharedmem_writel(device->memstore, + KGSL_MEMSTORE_OFFSET(context->id, soptimestamp), + drawctxt->timestamp); + + kgsl_sharedmem_writel(device->memstore, + KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp), + drawctxt->timestamp); + + adreno_profile_process_results(adreno_dev); + } + + context->gmu_registered = false; + + mutex_unlock(&device->mutex); +} diff --git a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h index b679dc1af8cf..a82c0a68ad14 100644 --- a/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h +++ b/drivers/gpu/msm/adreno_a6xx_hwsched_hfi.h @@ -191,4 +191,13 @@ int a6xx_hfi_send_cmd_async(struct adreno_device *adreno_dev, void *data); */ int a6xx_hwsched_submit_cmdobj(struct adreno_device *adreno_dev, u32 flags, struct kgsl_drawobj_cmd *cmdobj); + +/** + * a6xx_hwsched_context_detach - Unregister a context with GMU + * @drawctxt: Pointer to the adreno context + * + * This function sends context unregister HFI and waits for the ack + * to ensure all submissions from this context have retired + */ +void a6xx_hwsched_context_detach(struct adreno_context *drawctxt); #endif diff --git a/drivers/gpu/msm/adreno_a6xx_preempt.c b/drivers/gpu/msm/adreno_a6xx_preempt.c index 33236c8bfa05..d6868274dbf9 100644 --- a/drivers/gpu/msm/adreno_a6xx_preempt.c +++ b/drivers/gpu/msm/adreno_a6xx_preempt.c @@ -714,20 +714,6 @@ int a6xx_preemption_init(struct adreno_device *adreno_dev) return 0; } -void a6xx_preemption_context_destroy(struct kgsl_context *context) -{ - struct kgsl_device *device = context->device; - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - - if (!adreno_is_preemption_enabled(adreno_dev)) - return; - - gpumem_free_entry(context->user_ctxt_record); - - /* Put the extra ref from gpumem_alloc_entry() */ - kgsl_mem_entry_put(context->user_ctxt_record); -} - int a6xx_preemption_context_init(struct kgsl_context *context) { struct kgsl_device *device = context->device; diff --git a/drivers/gpu/msm/adreno_drawctxt.c b/drivers/gpu/msm/adreno_drawctxt.c index b0b4cd26cb8b..622593f2c37a 100644 --- a/drivers/gpu/msm/adreno_drawctxt.c +++ b/drivers/gpu/msm/adreno_drawctxt.c @@ -381,9 +381,6 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv, (drawctxt->base.flags & KGSL_CONTEXT_PRIORITY_MASK) >> KGSL_CONTEXT_PRIORITY_SHIFT; - /* set the context ringbuffer */ - drawctxt->rb = adreno_ctx_get_rb(adreno_dev, drawctxt); - /* * Now initialize the common part of the context. This allocates the * context id, and then possibly another thread could look it up. @@ -405,8 +402,6 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv, adreno_context_debugfs_init(ADRENO_DEVICE(device), drawctxt); - INIT_LIST_HEAD(&drawctxt->active_node); - if (gpudev->preemption_context_init) { ret = gpudev->preemption_context_init(&drawctxt->base); if (ret != 0) { @@ -417,57 +412,23 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv, /* copy back whatever flags we dediced were valid */ *flags = drawctxt->base.flags; + + if (!test_bit(GMU_DISPATCH, &device->gmu_core.flags)) { + /* set the context ringbuffer */ + drawctxt->rb = adreno_ctx_get_rb(adreno_dev, drawctxt); + + INIT_LIST_HEAD(&drawctxt->active_node); + } + return &drawctxt->base; } -/** - * adreno_drawctxt_detach(): detach a context from the GPU - * @context: Generic KGSL context container for the context - * - */ -void adreno_drawctxt_detach(struct kgsl_context *context) +static void wait_for_timestamp_rb(struct kgsl_device *device, + struct adreno_context *drawctxt) { - struct kgsl_device *device; - struct adreno_device *adreno_dev; - struct adreno_gpudev *gpudev; - struct adreno_context *drawctxt; - struct adreno_ringbuffer *rb; - int ret, count, i; - struct kgsl_drawobj *list[ADRENO_CONTEXT_DRAWQUEUE_SIZE]; - - if (context == NULL) - return; - - device = context->device; - adreno_dev = ADRENO_DEVICE(device); - gpudev = ADRENO_GPU_DEVICE(adreno_dev); - drawctxt = ADRENO_CONTEXT(context); - rb = drawctxt->rb; - - spin_lock(&drawctxt->lock); - - spin_lock(&adreno_dev->active_list_lock); - list_del_init(&drawctxt->active_node); - spin_unlock(&adreno_dev->active_list_lock); - - - count = drawctxt_detach_drawobjs(drawctxt, list); - spin_unlock(&drawctxt->lock); - - for (i = 0; i < count; i++) { - /* - * If the context is deteached while we are waiting for - * the next command in GFT SKIP CMD, print the context - * detached status here. - */ - adreno_fault_skipcmd_detached(adreno_dev, drawctxt, list[i]); - kgsl_drawobj_destroy(list[i]); - } - - debugfs_remove_recursive(drawctxt->debug_root); - /* The debugfs file has a reference, release it */ - if (drawctxt->debug_root) - kgsl_context_put(context); + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); + struct kgsl_context *context = &drawctxt->base; + int ret; /* * internal_timestamp is set in adreno_ringbuffer_addcmds, @@ -482,7 +443,7 @@ void adreno_drawctxt_detach(struct kgsl_context *context) * commands to retire will be greater than 10s. 30s should be sufficient * time to wait for the commands even if a hang happens. */ - ret = adreno_drawctxt_wait_rb(adreno_dev, context, + ret = adreno_drawctxt_wait_rb(adreno_dev, &drawctxt->base, drawctxt->internal_timestamp, 30 * 1000); /* @@ -525,9 +486,62 @@ void adreno_drawctxt_detach(struct kgsl_context *context) adreno_profile_process_results(adreno_dev); mutex_unlock(&device->mutex); +} - if (gpudev->preemption_context_destroy) - gpudev->preemption_context_destroy(context); +void adreno_drawctxt_detach(struct kgsl_context *context) +{ + struct kgsl_device *device; + struct adreno_device *adreno_dev; + struct adreno_gpudev *gpudev; + struct adreno_context *drawctxt; + int count, i; + struct kgsl_drawobj *list[ADRENO_CONTEXT_DRAWQUEUE_SIZE]; + + if (context == NULL) + return; + + device = context->device; + adreno_dev = ADRENO_DEVICE(device); + gpudev = ADRENO_GPU_DEVICE(adreno_dev); + drawctxt = ADRENO_CONTEXT(context); + + spin_lock(&drawctxt->lock); + + if (!test_bit(GMU_DISPATCH, &device->gmu_core.flags)) { + spin_lock(&adreno_dev->active_list_lock); + list_del_init(&drawctxt->active_node); + spin_unlock(&adreno_dev->active_list_lock); + } + + count = drawctxt_detach_drawobjs(drawctxt, list); + spin_unlock(&drawctxt->lock); + + for (i = 0; i < count; i++) { + /* + * If the context is detached while we are waiting for + * the next command in GFT SKIP CMD, print the context + * detached status here. + */ + adreno_fault_skipcmd_detached(adreno_dev, drawctxt, list[i]); + kgsl_drawobj_destroy(list[i]); + } + + debugfs_remove_recursive(drawctxt->debug_root); + /* The debugfs file has a reference, release it */ + if (drawctxt->debug_root) + kgsl_context_put(context); + + if (gpudev->context_detach) + gpudev->context_detach(drawctxt); + else + wait_for_timestamp_rb(device, drawctxt); + + if (context->user_ctxt_record) { + gpumem_free_entry(context->user_ctxt_record); + + /* Put the extra ref from gpumem_alloc_entry() */ + kgsl_mem_entry_put(context->user_ctxt_record); + } /* wake threads waiting to submit commands from this context */ wake_up_all(&drawctxt->waiting); diff --git a/drivers/gpu/msm/kgsl_gmu_core.h b/drivers/gpu/msm/kgsl_gmu_core.h index 8ed31effca3c..37d30cc32599 100644 --- a/drivers/gpu/msm/kgsl_gmu_core.h +++ b/drivers/gpu/msm/kgsl_gmu_core.h @@ -40,6 +40,7 @@ enum gmu_core_flags { GMU_ENABLED, GMU_RSCC_SLEEP_SEQ_DONE, GMU_DISABLE_SLUMBER, + GMU_DISPATCH, }; /*