Loading drivers/gpu/msm/adreno_drawctxt.c +51 −65 Original line number Diff line number Diff line Loading @@ -118,42 +118,6 @@ done: return ret; } /** * adreno_drawctxt_wait_rb() - Wait for the last RB timestamp at which this * context submitted a command to the corresponding RB * @adreno_dev: The device on which the timestamp is active * @context: The context which subbmitted command to RB * @timestamp: The RB timestamp of last command submitted to RB by context * @timeout: Timeout value for the wait */ static int adreno_drawctxt_wait_rb(struct adreno_device *adreno_dev, struct kgsl_context *context, uint32_t timestamp, unsigned int timeout) { struct kgsl_device *device = &adreno_dev->dev; struct adreno_context *drawctxt = ADRENO_CONTEXT(context); int ret = 0; /* Needs to hold the device mutex */ BUG_ON(!mutex_is_locked(&device->mutex)); /* * If the context is invalid then return immediately - we may end up * waiting for a timestamp that will never come */ if (kgsl_context_invalid(context)) goto done; trace_adreno_drawctxt_wait_start(drawctxt->rb->id, context->id, timestamp); ret = adreno_ringbuffer_waittimestamp(drawctxt->rb, timestamp, timeout); done: trace_adreno_drawctxt_wait_done(drawctxt->rb->id, context->id, timestamp, ret); return ret; } /** * adreno_drawctxt_invalidate() - Invalidate an adreno draw context * @device: Pointer to the KGSL device structure for the GPU Loading Loading @@ -319,6 +283,8 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv, KGSL_MEMSTORE_OFFSET(drawctxt->base.id, eoptimestamp), 0); init_completion(&(drawctxt->base.detach_gate)); adreno_context_debugfs_init(ADRENO_DEVICE(device), drawctxt); /* copy back whatever flags we dediced were valid */ Loading @@ -341,6 +307,47 @@ void adreno_drawctxt_sched(struct kgsl_device *device, adreno_dispatcher_queue_context(device, ADRENO_CONTEXT(context)); } /** * adreno_drawctxt_detach_callback() - Callback function called when * the last timestamp on which a context submitted command expires * @device: Device pointer * @ctx: The event groups context. should be NULL since the event group is RB * @priv: The context this callback was registered for * @result: Indicates the result of wait * * Signal waiters that were waiting on the last command of this context */ static void adreno_drawctxt_detach_callback(struct kgsl_device *device, struct kgsl_context *ctx, void *priv, int result) { struct adreno_context *drawctxt = priv; struct kgsl_context *context = &drawctxt->base; struct adreno_device *adreno_dev = ADRENO_DEVICE(drawctxt->rb->device); 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); /* * Cancel all pending events after the device-specific context is * detached, to avoid possibly freeing memory while it is still * in use by the GPU. */ kgsl_cancel_events(device, &context->events); /* wake threads waiting to submit commands from this context */ wake_up_all(&drawctxt->waiting); wake_up_all(&drawctxt->wq); complete_all(&drawctxt->base.detach_gate); kgsl_context_put(context); adreno_profile_process_results(adreno_dev); } /** * adreno_drawctxt_detach(): detach a context from the GPU * @context: Generic KGSL context container for the context Loading Loading @@ -403,35 +410,14 @@ int adreno_drawctxt_detach(struct kgsl_context *context) */ BUG_ON(!mutex_is_locked(&device->mutex)); /* Wait for the last global timestamp to pass before continuing */ ret = adreno_drawctxt_wait_rb(adreno_dev, context, drawctxt->internal_timestamp, 10 * 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); /* add event to complete context detachment */ _kgsl_context_get(context); ret = kgsl_add_event(device, &drawctxt->rb->events, drawctxt->internal_timestamp, adreno_drawctxt_detach_callback, (void *) drawctxt); if (ret) kgsl_context_put(context); return ret; } Loading drivers/gpu/msm/kgsl.c +62 −27 Original line number Diff line number Diff line Loading @@ -64,6 +64,11 @@ #define KGSL_DMA_BIT_MASK DMA_BIT_MASK(32) #endif /* 2s timeout wait for contexts to complete */ #define CTXT_DETACH_TIMEOUT 10000 static struct workqueue_struct *release_work_queue; /* * Define an kmem cache for the memobj structures since we allocate and free * them so frequently Loading Loading @@ -586,15 +591,9 @@ int kgsl_context_detach(struct kgsl_context *context) mutex_unlock(&device->mutex); /* * Cancel all pending events after the device-specific context is * detached, to avoid possibly freeing memory while it is still * in use by the GPU. * This put corresponds to the get when user space * first created the context */ kgsl_cancel_events(device, &context->events); /* Remove the event group from the list */ kgsl_del_event_group(&context->events); kgsl_context_put(context); return ret; Loading Loading @@ -635,6 +634,7 @@ kgsl_context_destroy(struct kref *kref) write_unlock(&device->context_lock); kgsl_sync_timeline_destroy(context); kgsl_process_private_put(context->proc_priv); kgsl_del_event_group(&context->events); device->ftbl->drawctxt_destroy(context); } Loading Loading @@ -936,6 +936,7 @@ error: static int kgsl_close_device(struct kgsl_device *device) { int result = 0; int flush = 0; mutex_lock(&device->mutex); device->open_count--; Loading @@ -951,35 +952,30 @@ static int kgsl_close_device(struct kgsl_device *device) kgsl_pwrctrl_enable(device); result = device->ftbl->stop(device); kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); flush = 1; } mutex_unlock(&device->mutex); if (flush) flush_workqueue(release_work_queue); return result; } static int kgsl_release(struct inode *inodep, struct file *filep) /** * kgsl_release_deferred_proc_priv() - Free a process private structure * @work: The work structure used to schedule the release of the process private */ static void kgsl_release_deferred_proc_priv(struct work_struct *work) { int result = 0; struct kgsl_device_private *dev_priv = filep->private_data; struct kgsl_device_private *dev_priv = container_of(work, struct kgsl_device_private, release_work); struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_device *device = dev_priv->device; struct kgsl_context *context; struct kgsl_syncsource *syncsource; struct kgsl_mem_entry *entry; int next = 0; filep->private_data = NULL; next = 0; while (1) { syncsource = idr_get_next(&private->syncsource_idr, &next); if (syncsource == NULL) break; kgsl_syncsource_put(syncsource); next = next + 1; } next = 0; while (1) { read_lock(&device->context_lock); Loading @@ -996,7 +992,22 @@ static int kgsl_release(struct inode *inodep, struct file *filep) */ if (_kgsl_context_get(context)) { int ret; kgsl_context_detach(context); /* wait for the ctxt to complete detachment */ ret = wait_for_completion_timeout( &context->detach_gate, msecs_to_jiffies(CTXT_DETACH_TIMEOUT)); if (0 == ret) { KGSL_DRV_ERR(device, "Timed out while waiting for context %d to detach\n", context->id); wait_for_completion( &context->detach_gate); KGSL_DRV_ERR(device, "Wait for context %d detach complete\n", context->id); } kgsl_context_put(context); } } Loading Loading @@ -1027,14 +1038,36 @@ static int kgsl_release(struct inode *inodep, struct file *filep) next = next + 1; } result = kgsl_close_device(device); kfree(dev_priv); kgsl_process_private_put(private); } static int kgsl_release(struct inode *inodep, struct file *filep) { struct kgsl_device_private *dev_priv = filep->private_data; struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_device *device = dev_priv->device; struct kgsl_syncsource *syncsource; int next = 0; filep->private_data = NULL; next = 0; while (1) { syncsource = idr_get_next(&private->syncsource_idr, &next); if (syncsource == NULL) break; kgsl_syncsource_put(syncsource); next = next + 1; } INIT_WORK(&dev_priv->release_work, kgsl_release_deferred_proc_priv); queue_work(release_work_queue, &dev_priv->release_work); pm_runtime_put(&device->pdev->dev); return result; return kgsl_close_device(device); } static int kgsl_open_device(struct kgsl_device *device) Loading Loading @@ -4540,6 +4573,7 @@ int kgsl_device_platform_probe(struct kgsl_device *device) device->events_wq = create_workqueue("kgsl-events"); release_work_queue = create_workqueue("kgsl-release"); /* Initalize the snapshot engine */ kgsl_device_snapshot_init(device); Loading Loading @@ -4568,6 +4602,7 @@ EXPORT_SYMBOL(kgsl_device_platform_probe); void kgsl_device_platform_remove(struct kgsl_device *device) { destroy_workqueue(device->events_wq); destroy_workqueue(release_work_queue); kgsl_device_snapshot_close(device); Loading drivers/gpu/msm/kgsl_device.h +4 −1 Original line number Diff line number Diff line Loading @@ -371,7 +371,6 @@ struct kgsl_device { int reset_counter; /* Track how many GPU core resets have occured */ int cff_dump_enable; struct workqueue_struct *events_wq; struct device *busmondev; /* pseudo dev for GPU BW voting governor */ }; Loading Loading @@ -436,6 +435,8 @@ struct kgsl_process_private; * @pwr_constraint: power constraint from userspace for this context * @fault_count: number of times gpu hanged in last _context_throttle_time ms * @fault_time: time of the first gpu hang in last _context_throttle_time ms * @detach_gate: Once signalled it means the context is completely detached and * there are no pending commands in the pipe from this context */ struct kgsl_context { struct kref refcount; Loading @@ -455,6 +456,7 @@ struct kgsl_context { struct kgsl_pwr_constraint pwr_constraint; unsigned int fault_count; unsigned long fault_time; struct completion detach_gate; }; /** Loading Loading @@ -511,6 +513,7 @@ enum kgsl_process_priv_flags { struct kgsl_device_private { struct kgsl_device *device; struct kgsl_process_private *process_priv; struct work_struct release_work; }; /** Loading Loading
drivers/gpu/msm/adreno_drawctxt.c +51 −65 Original line number Diff line number Diff line Loading @@ -118,42 +118,6 @@ done: return ret; } /** * adreno_drawctxt_wait_rb() - Wait for the last RB timestamp at which this * context submitted a command to the corresponding RB * @adreno_dev: The device on which the timestamp is active * @context: The context which subbmitted command to RB * @timestamp: The RB timestamp of last command submitted to RB by context * @timeout: Timeout value for the wait */ static int adreno_drawctxt_wait_rb(struct adreno_device *adreno_dev, struct kgsl_context *context, uint32_t timestamp, unsigned int timeout) { struct kgsl_device *device = &adreno_dev->dev; struct adreno_context *drawctxt = ADRENO_CONTEXT(context); int ret = 0; /* Needs to hold the device mutex */ BUG_ON(!mutex_is_locked(&device->mutex)); /* * If the context is invalid then return immediately - we may end up * waiting for a timestamp that will never come */ if (kgsl_context_invalid(context)) goto done; trace_adreno_drawctxt_wait_start(drawctxt->rb->id, context->id, timestamp); ret = adreno_ringbuffer_waittimestamp(drawctxt->rb, timestamp, timeout); done: trace_adreno_drawctxt_wait_done(drawctxt->rb->id, context->id, timestamp, ret); return ret; } /** * adreno_drawctxt_invalidate() - Invalidate an adreno draw context * @device: Pointer to the KGSL device structure for the GPU Loading Loading @@ -319,6 +283,8 @@ adreno_drawctxt_create(struct kgsl_device_private *dev_priv, KGSL_MEMSTORE_OFFSET(drawctxt->base.id, eoptimestamp), 0); init_completion(&(drawctxt->base.detach_gate)); adreno_context_debugfs_init(ADRENO_DEVICE(device), drawctxt); /* copy back whatever flags we dediced were valid */ Loading @@ -341,6 +307,47 @@ void adreno_drawctxt_sched(struct kgsl_device *device, adreno_dispatcher_queue_context(device, ADRENO_CONTEXT(context)); } /** * adreno_drawctxt_detach_callback() - Callback function called when * the last timestamp on which a context submitted command expires * @device: Device pointer * @ctx: The event groups context. should be NULL since the event group is RB * @priv: The context this callback was registered for * @result: Indicates the result of wait * * Signal waiters that were waiting on the last command of this context */ static void adreno_drawctxt_detach_callback(struct kgsl_device *device, struct kgsl_context *ctx, void *priv, int result) { struct adreno_context *drawctxt = priv; struct kgsl_context *context = &drawctxt->base; struct adreno_device *adreno_dev = ADRENO_DEVICE(drawctxt->rb->device); 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); /* * Cancel all pending events after the device-specific context is * detached, to avoid possibly freeing memory while it is still * in use by the GPU. */ kgsl_cancel_events(device, &context->events); /* wake threads waiting to submit commands from this context */ wake_up_all(&drawctxt->waiting); wake_up_all(&drawctxt->wq); complete_all(&drawctxt->base.detach_gate); kgsl_context_put(context); adreno_profile_process_results(adreno_dev); } /** * adreno_drawctxt_detach(): detach a context from the GPU * @context: Generic KGSL context container for the context Loading Loading @@ -403,35 +410,14 @@ int adreno_drawctxt_detach(struct kgsl_context *context) */ BUG_ON(!mutex_is_locked(&device->mutex)); /* Wait for the last global timestamp to pass before continuing */ ret = adreno_drawctxt_wait_rb(adreno_dev, context, drawctxt->internal_timestamp, 10 * 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); /* add event to complete context detachment */ _kgsl_context_get(context); ret = kgsl_add_event(device, &drawctxt->rb->events, drawctxt->internal_timestamp, adreno_drawctxt_detach_callback, (void *) drawctxt); if (ret) kgsl_context_put(context); return ret; } Loading
drivers/gpu/msm/kgsl.c +62 −27 Original line number Diff line number Diff line Loading @@ -64,6 +64,11 @@ #define KGSL_DMA_BIT_MASK DMA_BIT_MASK(32) #endif /* 2s timeout wait for contexts to complete */ #define CTXT_DETACH_TIMEOUT 10000 static struct workqueue_struct *release_work_queue; /* * Define an kmem cache for the memobj structures since we allocate and free * them so frequently Loading Loading @@ -586,15 +591,9 @@ int kgsl_context_detach(struct kgsl_context *context) mutex_unlock(&device->mutex); /* * Cancel all pending events after the device-specific context is * detached, to avoid possibly freeing memory while it is still * in use by the GPU. * This put corresponds to the get when user space * first created the context */ kgsl_cancel_events(device, &context->events); /* Remove the event group from the list */ kgsl_del_event_group(&context->events); kgsl_context_put(context); return ret; Loading Loading @@ -635,6 +634,7 @@ kgsl_context_destroy(struct kref *kref) write_unlock(&device->context_lock); kgsl_sync_timeline_destroy(context); kgsl_process_private_put(context->proc_priv); kgsl_del_event_group(&context->events); device->ftbl->drawctxt_destroy(context); } Loading Loading @@ -936,6 +936,7 @@ error: static int kgsl_close_device(struct kgsl_device *device) { int result = 0; int flush = 0; mutex_lock(&device->mutex); device->open_count--; Loading @@ -951,35 +952,30 @@ static int kgsl_close_device(struct kgsl_device *device) kgsl_pwrctrl_enable(device); result = device->ftbl->stop(device); kgsl_pwrctrl_change_state(device, KGSL_STATE_INIT); flush = 1; } mutex_unlock(&device->mutex); if (flush) flush_workqueue(release_work_queue); return result; } static int kgsl_release(struct inode *inodep, struct file *filep) /** * kgsl_release_deferred_proc_priv() - Free a process private structure * @work: The work structure used to schedule the release of the process private */ static void kgsl_release_deferred_proc_priv(struct work_struct *work) { int result = 0; struct kgsl_device_private *dev_priv = filep->private_data; struct kgsl_device_private *dev_priv = container_of(work, struct kgsl_device_private, release_work); struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_device *device = dev_priv->device; struct kgsl_context *context; struct kgsl_syncsource *syncsource; struct kgsl_mem_entry *entry; int next = 0; filep->private_data = NULL; next = 0; while (1) { syncsource = idr_get_next(&private->syncsource_idr, &next); if (syncsource == NULL) break; kgsl_syncsource_put(syncsource); next = next + 1; } next = 0; while (1) { read_lock(&device->context_lock); Loading @@ -996,7 +992,22 @@ static int kgsl_release(struct inode *inodep, struct file *filep) */ if (_kgsl_context_get(context)) { int ret; kgsl_context_detach(context); /* wait for the ctxt to complete detachment */ ret = wait_for_completion_timeout( &context->detach_gate, msecs_to_jiffies(CTXT_DETACH_TIMEOUT)); if (0 == ret) { KGSL_DRV_ERR(device, "Timed out while waiting for context %d to detach\n", context->id); wait_for_completion( &context->detach_gate); KGSL_DRV_ERR(device, "Wait for context %d detach complete\n", context->id); } kgsl_context_put(context); } } Loading Loading @@ -1027,14 +1038,36 @@ static int kgsl_release(struct inode *inodep, struct file *filep) next = next + 1; } result = kgsl_close_device(device); kfree(dev_priv); kgsl_process_private_put(private); } static int kgsl_release(struct inode *inodep, struct file *filep) { struct kgsl_device_private *dev_priv = filep->private_data; struct kgsl_process_private *private = dev_priv->process_priv; struct kgsl_device *device = dev_priv->device; struct kgsl_syncsource *syncsource; int next = 0; filep->private_data = NULL; next = 0; while (1) { syncsource = idr_get_next(&private->syncsource_idr, &next); if (syncsource == NULL) break; kgsl_syncsource_put(syncsource); next = next + 1; } INIT_WORK(&dev_priv->release_work, kgsl_release_deferred_proc_priv); queue_work(release_work_queue, &dev_priv->release_work); pm_runtime_put(&device->pdev->dev); return result; return kgsl_close_device(device); } static int kgsl_open_device(struct kgsl_device *device) Loading Loading @@ -4540,6 +4573,7 @@ int kgsl_device_platform_probe(struct kgsl_device *device) device->events_wq = create_workqueue("kgsl-events"); release_work_queue = create_workqueue("kgsl-release"); /* Initalize the snapshot engine */ kgsl_device_snapshot_init(device); Loading Loading @@ -4568,6 +4602,7 @@ EXPORT_SYMBOL(kgsl_device_platform_probe); void kgsl_device_platform_remove(struct kgsl_device *device) { destroy_workqueue(device->events_wq); destroy_workqueue(release_work_queue); kgsl_device_snapshot_close(device); Loading
drivers/gpu/msm/kgsl_device.h +4 −1 Original line number Diff line number Diff line Loading @@ -371,7 +371,6 @@ struct kgsl_device { int reset_counter; /* Track how many GPU core resets have occured */ int cff_dump_enable; struct workqueue_struct *events_wq; struct device *busmondev; /* pseudo dev for GPU BW voting governor */ }; Loading Loading @@ -436,6 +435,8 @@ struct kgsl_process_private; * @pwr_constraint: power constraint from userspace for this context * @fault_count: number of times gpu hanged in last _context_throttle_time ms * @fault_time: time of the first gpu hang in last _context_throttle_time ms * @detach_gate: Once signalled it means the context is completely detached and * there are no pending commands in the pipe from this context */ struct kgsl_context { struct kref refcount; Loading @@ -455,6 +456,7 @@ struct kgsl_context { struct kgsl_pwr_constraint pwr_constraint; unsigned int fault_count; unsigned long fault_time; struct completion detach_gate; }; /** Loading Loading @@ -511,6 +513,7 @@ enum kgsl_process_priv_flags { struct kgsl_device_private { struct kgsl_device *device; struct kgsl_process_private *process_priv; struct work_struct release_work; }; /** Loading