/** * adreno_drawctxt_invalidate() - Invalidate an adreno draw context * @device: Pointer to the KGSL device structure for the GPU * @context: Pointer to the KGSL context structure * * Invalidate the context and remove all queued commands and cancel any pending * waiters */ void adreno_drawctxt_invalidate(struct kgsl_device *device, struct kgsl_context *context) { struct adreno_context *drawctxt = ADRENO_CONTEXT(context); trace_adreno_drawctxt_invalidate(drawctxt); drawctxt->state = ADRENO_CONTEXT_STATE_INVALID; /* Clear the pending queue */ mutex_lock(&drawctxt->mutex); /* * set the timestamp to the last value since the context is invalidated * and we want the pending events for this context to go away */ kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, soptimestamp), drawctxt->timestamp); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp), drawctxt->timestamp); while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) { struct kgsl_cmdbatch *cmdbatch = drawctxt->cmdqueue[drawctxt->cmdqueue_head]; drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) % ADRENO_CONTEXT_CMDQUEUE_SIZE; mutex_unlock(&drawctxt->mutex); kgsl_mutex_lock(&device->mutex, &device->mutex_owner); kgsl_cancel_events_timestamp(device, &context->events, cmdbatch->timestamp); kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); kgsl_cmdbatch_destroy(cmdbatch); mutex_lock(&drawctxt->mutex); } mutex_unlock(&drawctxt->mutex); /* Give the bad news to everybody waiting around */ wake_up_all(&drawctxt->waiting); wake_up_all(&drawctxt->wq); }
/** * adreno_drawctxt_invalidate() - Invalidate an adreno draw context * @device: Pointer to the KGSL device structure for the GPU * @context: Pointer to the KGSL context structure * * Invalidate the context and remove all queued commands and cancel any pending * waiters */ void adreno_drawctxt_invalidate(struct kgsl_device *device, struct kgsl_context *context) { struct adreno_context *drawctxt = ADRENO_CONTEXT(context); trace_adreno_drawctxt_invalidate(drawctxt); spin_lock(&drawctxt->lock); set_bit(KGSL_CONTEXT_PRIV_INVALID, &context->priv); /* * set the timestamp to the last value since the context is invalidated * and we want the pending events for this context to go away */ kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, soptimestamp), drawctxt->timestamp); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp), drawctxt->timestamp); /* Get rid of commands still waiting in the queue */ while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) { struct kgsl_cmdbatch *cmdbatch = drawctxt->cmdqueue[drawctxt->cmdqueue_head]; drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) % ADRENO_CONTEXT_CMDQUEUE_SIZE; kgsl_cancel_events_timestamp(device, &context->events, cmdbatch->timestamp); kgsl_cmdbatch_destroy(cmdbatch); } spin_unlock(&drawctxt->lock); /* Make sure all "retired" events are processed */ kgsl_process_event_group(device, &context->events); /* Give the bad news to everybody waiting around */ wake_up_all(&drawctxt->waiting); wake_up_all(&drawctxt->wq); }
void adreno_drawctxt_invalidate(struct kgsl_device *device, struct kgsl_context *context) { struct adreno_context *drawctxt = ADRENO_CONTEXT(context); trace_adreno_drawctxt_invalidate(drawctxt); drawctxt->state = ADRENO_CONTEXT_STATE_INVALID; mutex_lock(&drawctxt->mutex); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, soptimestamp), drawctxt->timestamp); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp), drawctxt->timestamp); while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) { struct kgsl_cmdbatch *cmdbatch = drawctxt->cmdqueue[drawctxt->cmdqueue_head]; drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) % ADRENO_CONTEXT_CMDQUEUE_SIZE; mutex_unlock(&drawctxt->mutex); mutex_lock(&device->mutex); kgsl_cancel_events_timestamp(device, context, cmdbatch->timestamp); mutex_unlock(&device->mutex); kgsl_cmdbatch_destroy(cmdbatch); mutex_lock(&drawctxt->mutex); } mutex_unlock(&drawctxt->mutex); wake_up_all(&drawctxt->waiting); wake_up_all(&drawctxt->wq); }
/** * adreno_drawctxt_invalidate() - Invalidate an adreno draw context * @device: Pointer to the KGSL device structure for the GPU * @context: Pointer to the KGSL context structure * * Invalidate the context and remove all queued commands and cancel any pending * waiters */ void adreno_drawctxt_invalidate(struct kgsl_device *device, struct kgsl_context *context) { struct adreno_context *drawctxt = ADRENO_CONTEXT(context); struct kgsl_cmdbatch *list[ADRENO_CONTEXT_CMDQUEUE_SIZE]; int i, count; trace_adreno_drawctxt_invalidate(drawctxt); spin_lock(&drawctxt->lock); set_bit(KGSL_CONTEXT_PRIV_INVALID, &context->priv); /* * set the timestamp to the last value since the context is invalidated * and we want the pending events for this context to go away */ kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, soptimestamp), drawctxt->timestamp); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp), drawctxt->timestamp); /* Get rid of commands still waiting in the queue */ count = drawctxt_detach_cmdbatches(drawctxt, list); spin_unlock(&drawctxt->lock); for (i = 0; i < count; i++) { kgsl_cancel_events_timestamp(device, &context->events, list[i]->timestamp); kgsl_cmdbatch_destroy(list[i]); } /* Make sure all pending events are processed or cancelled */ kgsl_flush_event_group(device, &context->events); /* Give the bad news to everybody waiting around */ wake_up_all(&drawctxt->waiting); wake_up_all(&drawctxt->wq); }
/** * adreno_drawctxt_detach(): detach a context from the GPU * @context: Generic KGSL context container for the context * */ int adreno_drawctxt_detach(struct kgsl_context *context) { struct kgsl_device *device; struct adreno_device *adreno_dev; struct adreno_context *drawctxt; int ret; if (context == NULL) return 0; device = context->device; adreno_dev = ADRENO_DEVICE(device); drawctxt = ADRENO_CONTEXT(context); /* deactivate context */ if (adreno_dev->drawctxt_active == drawctxt) adreno_drawctxt_switch(adreno_dev, NULL, 0); mutex_lock(&drawctxt->mutex); while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) { struct kgsl_cmdbatch *cmdbatch = drawctxt->cmdqueue[drawctxt->cmdqueue_head]; drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) % ADRENO_CONTEXT_CMDQUEUE_SIZE; mutex_unlock(&drawctxt->mutex); /* * Don't hold the drawctxt mutex while the cmdbatch is being * destroyed because the cmdbatch destroy takes the device * mutex and the world falls in on itself */ kgsl_cmdbatch_destroy(cmdbatch); mutex_lock(&drawctxt->mutex); } mutex_unlock(&drawctxt->mutex); /* * internal_timestamp is set in adreno_ringbuffer_addcmds, * which holds the device mutex. The entire context destroy * process requires the device mutex as well. But lets * make sure we notice if the locking changes. */ BUG_ON(!mutex_is_locked(&device->mutex)); /* Wait for the last global timestamp to pass before continuing */ ret = adreno_drawctxt_wait_global(adreno_dev, context, drawctxt->internal_timestamp, 10 * 1000); /* * If the wait for global fails then nothing after this point is likely * to work very well - BUG_ON() so we can take advantage of the debug * tools to figure out what the h - e - double hockey sticks happened */ BUG_ON(ret); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, soptimestamp), drawctxt->timestamp); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp), drawctxt->timestamp); adreno_profile_process_results(device); /* wake threads waiting to submit commands from this context */ wake_up_all(&drawctxt->waiting); wake_up_all(&drawctxt->wq); return ret; }
/** * adreno_drawctxt_detach(): detach a context from the GPU * @context: Generic KGSL context container for the context * */ int adreno_drawctxt_detach(struct kgsl_context *context) { struct kgsl_device *device; struct adreno_device *adreno_dev; struct adreno_context *drawctxt; struct adreno_ringbuffer *rb; int ret; if (context == NULL) return 0; device = context->device; adreno_dev = ADRENO_DEVICE(device); drawctxt = ADRENO_CONTEXT(context); rb = drawctxt->rb; /* deactivate context */ if (rb->drawctxt_active == drawctxt) adreno_drawctxt_switch(adreno_dev, rb, NULL, 0); spin_lock(&drawctxt->lock); while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) { struct kgsl_cmdbatch *cmdbatch = drawctxt->cmdqueue[drawctxt->cmdqueue_head]; drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) % ADRENO_CONTEXT_CMDQUEUE_SIZE; spin_unlock(&drawctxt->lock); /* * 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(device, drawctxt, cmdbatch); /* * Don't hold the drawctxt mutex while the cmdbatch is being * destroyed because the cmdbatch destroy takes the device * mutex and the world falls in on itself */ kgsl_cmdbatch_destroy(cmdbatch); spin_lock(&drawctxt->lock); } spin_unlock(&drawctxt->lock); /* * internal_timestamp is set in adreno_ringbuffer_addcmds, * which holds the device mutex. The entire context destroy * process requires the device mutex as well. But lets * make sure we notice if the locking changes. */ BUG_ON(!mutex_is_locked(&device->mutex)); /* * Wait for the last global timestamp to pass before continuing. * The maxumum wait time is 30s, some large IB's can take longer * than 10s and if hang happens then the time for the context's * 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, drawctxt->internal_timestamp, 30 * 1000); /* * If the wait for global fails due to timeout then nothing after this * point is likely to work very well - BUG_ON() so we can take advantage * of the debug tools to figure out what the h - e - double hockey * sticks happened. If EAGAIN error is returned then recovery will kick * in and there will be no more commands in the RB pipe from this * context which is waht we are waiting for, so ignore -EAGAIN error */ if (-EAGAIN == ret) ret = 0; BUG_ON(ret); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, soptimestamp), drawctxt->timestamp); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp), drawctxt->timestamp); adreno_profile_process_results(adreno_dev); /* wake threads waiting to submit commands from this context */ wake_up_all(&drawctxt->waiting); wake_up_all(&drawctxt->wq); return ret; }
/** * 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) { struct kgsl_device *device; struct adreno_device *adreno_dev; struct adreno_context *drawctxt; struct adreno_ringbuffer *rb; int ret, count, i; struct kgsl_cmdbatch *list[ADRENO_CONTEXT_CMDQUEUE_SIZE]; if (context == NULL) return; device = context->device; adreno_dev = ADRENO_DEVICE(device); drawctxt = ADRENO_CONTEXT(context); rb = drawctxt->rb; /* deactivate context */ mutex_lock(&device->mutex); if (rb->drawctxt_active == drawctxt) { if (adreno_dev->cur_rb == rb) { if (!kgsl_active_count_get(device)) { adreno_drawctxt_switch(adreno_dev, rb, NULL, 0); kgsl_active_count_put(device); } else BUG(); } else adreno_drawctxt_switch(adreno_dev, rb, NULL, 0); } mutex_unlock(&device->mutex); spin_lock(&drawctxt->lock); count = drawctxt_detach_cmdbatches(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(device, drawctxt, list[i]); kgsl_cmdbatch_destroy(list[i]); } /* * internal_timestamp is set in adreno_ringbuffer_addcmds, * which holds the device mutex. */ mutex_lock(&device->mutex); /* * Wait for the last global timestamp to pass before continuing. * The maxumum wait time is 30s, some large IB's can take longer * than 10s and if hang happens then the time for the context's * 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, drawctxt->internal_timestamp, 30 * 1000); /* * If the wait for global fails due to timeout then nothing after this * point is likely to work very well - BUG_ON() so we can take advantage * of the debug tools to figure out what the h - e - double hockey * sticks happened. If EAGAIN error is returned then recovery will kick * in and there will be no more commands in the RB pipe from this * context which is waht we are waiting for, so ignore -EAGAIN error */ BUG_ON(ret && ret != -EAGAIN); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, soptimestamp), drawctxt->timestamp); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp), drawctxt->timestamp); adreno_profile_process_results(adreno_dev); mutex_unlock(&device->mutex); /* wake threads waiting to submit commands from this context */ wake_up_all(&drawctxt->waiting); wake_up_all(&drawctxt->wq); }
int adreno_drawctxt_detach(struct kgsl_context *context) { struct kgsl_device *device; struct adreno_device *adreno_dev; struct adreno_context *drawctxt; int ret; if (context == NULL) return 0; device = context->device; adreno_dev = ADRENO_DEVICE(device); drawctxt = ADRENO_CONTEXT(context); if (adreno_dev->drawctxt_active == drawctxt) adreno_drawctxt_switch(adreno_dev, NULL, 0); mutex_lock(&drawctxt->mutex); while (drawctxt->cmdqueue_head != drawctxt->cmdqueue_tail) { struct kgsl_cmdbatch *cmdbatch = drawctxt->cmdqueue[drawctxt->cmdqueue_head]; drawctxt->cmdqueue_head = (drawctxt->cmdqueue_head + 1) % ADRENO_CONTEXT_CMDQUEUE_SIZE; mutex_unlock(&drawctxt->mutex); kgsl_cmdbatch_destroy(cmdbatch); mutex_lock(&drawctxt->mutex); } mutex_unlock(&drawctxt->mutex); BUG_ON(!mutex_is_locked(&device->mutex)); ret = adreno_drawctxt_wait_global(adreno_dev, context, drawctxt->internal_timestamp, 10 * 1000); BUG_ON(ret); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, soptimestamp), drawctxt->timestamp); kgsl_sharedmem_writel(device, &device->memstore, KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp), drawctxt->timestamp); adreno_profile_process_results(device); if (drawctxt->ops && drawctxt->ops->detach) drawctxt->ops->detach(drawctxt); wake_up_all(&drawctxt->waiting); wake_up_all(&drawctxt->wq); return ret; }