mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-14 16:46:15 -04:00
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:
parent
019b8504ba
commit
a8002ec263
8 changed files with 187 additions and 78 deletions
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ enum gmu_core_flags {
|
|||
GMU_ENABLED,
|
||||
GMU_RSCC_SLEEP_SEQ_DONE,
|
||||
GMU_DISABLE_SLUMBER,
|
||||
GMU_DISPATCH,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in a new issue