msm: kgsl: Add context unregister HFI

This is a special sequence because we don't want to wait for
the ack back while holding the device mutex. This means, we
have to define a new sequence of unlocking the device mutex
before we begin our wait for ack.

Change-Id: I3ea27bdccd66cdaafd8cff6cc1366848c1a4bea6
Signed-off-by: Harshdeep Dhatt <hdhatt@codeaurora.org>
This commit is contained in:
Harshdeep Dhatt 2020-07-23 12:46:05 -06:00
commit a8002ec263
8 changed files with 187 additions and 78 deletions

View file

@ -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);

View file

@ -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,

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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

View file

@ -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;

View file

@ -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);

View file

@ -40,6 +40,7 @@ enum gmu_core_flags {
GMU_ENABLED,
GMU_RSCC_SLEEP_SEQ_DONE,
GMU_DISABLE_SLUMBER,
GMU_DISPATCH,
};
/*