123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2002,2007-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #include <linux/debugfs.h>
- #include "adreno.h"
- #include "adreno_trace.h"
- static void wait_callback(struct kgsl_device *device,
- struct kgsl_event_group *group, void *priv, int result)
- {
- struct adreno_context *drawctxt = priv;
- wake_up_all(&drawctxt->waiting);
- }
- static int _check_context_timestamp(struct kgsl_device *device,
- struct kgsl_context *context, unsigned int timestamp)
- {
- /* Bail if the drawctxt has been invalidated or destroyed */
- if (kgsl_context_is_bad(context))
- return 1;
- return kgsl_check_timestamp(device, context, timestamp);
- }
- /**
- * adreno_drawctxt_dump() - dump information about a draw context
- * @device: KGSL device that owns the context
- * @context: KGSL context to dump information about
- *
- * Dump specific information about the context to the kernel log. Used for
- * fence timeout callbacks
- */
- void adreno_drawctxt_dump(struct kgsl_device *device,
- struct kgsl_context *context)
- {
- unsigned int queue, start, retire;
- struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
- int index, pos;
- char buf[120];
- kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_QUEUED, &queue);
- kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_CONSUMED, &start);
- kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED, &retire);
- /*
- * We may have kgsl sync obj timer running, which also uses same
- * lock, take a lock with software interrupt disabled (bh)
- * to avoid spin lock recursion.
- *
- * Use Spin trylock because dispatcher can acquire drawctxt->lock
- * if context is pending and the fence it is waiting on just got
- * signalled. Dispatcher acquires drawctxt->lock and tries to
- * delete the sync obj timer using del_timer_sync().
- * del_timer_sync() waits till timer and its pending handlers
- * are deleted. But if the timer expires at the same time,
- * timer handler could be waiting on drawctxt->lock leading to a
- * deadlock. To prevent this use spin_trylock_bh.
- */
- if (!spin_trylock_bh(&drawctxt->lock)) {
- dev_err(device->dev, " context[%u]: could not get lock\n",
- context->id);
- return;
- }
- dev_err(device->dev,
- " context[%u]: queue=%u, submit=%u, start=%u, retire=%u\n",
- context->id, queue, drawctxt->submitted_timestamp,
- start, retire);
- if (drawctxt->drawqueue_head != drawctxt->drawqueue_tail) {
- struct kgsl_drawobj *drawobj =
- drawctxt->drawqueue[drawctxt->drawqueue_head];
- if (test_bit(ADRENO_CONTEXT_FENCE_LOG, &context->priv)) {
- dev_err(device->dev,
- " possible deadlock. Context %u might be blocked for itself\n",
- context->id);
- goto stats;
- }
- if (!kref_get_unless_zero(&drawobj->refcount))
- goto stats;
- if (drawobj->type == SYNCOBJ_TYPE) {
- struct kgsl_drawobj_sync *syncobj = SYNCOBJ(drawobj);
- if (kgsl_drawobj_events_pending(syncobj)) {
- dev_err(device->dev,
- " context[%u] (ts=%u) Active sync points:\n",
- context->id, drawobj->timestamp);
- kgsl_dump_syncpoints(device, syncobj);
- }
- }
- kgsl_drawobj_put(drawobj);
- }
- stats:
- memset(buf, 0, sizeof(buf));
- pos = 0;
- for (index = 0; index < SUBMIT_RETIRE_TICKS_SIZE; index++) {
- uint64_t msecs;
- unsigned int usecs;
- if (!drawctxt->submit_retire_ticks[index])
- continue;
- msecs = drawctxt->submit_retire_ticks[index] * 10;
- usecs = do_div(msecs, 192);
- usecs = do_div(msecs, 1000);
- pos += scnprintf(buf + pos, sizeof(buf) - pos, "%u.%0u ",
- (unsigned int)msecs, usecs);
- }
- dev_err(device->dev, " context[%u]: submit times: %s\n",
- context->id, buf);
- spin_unlock_bh(&drawctxt->lock);
- }
- /**
- * adreno_drawctxt_wait() - sleep until a timestamp expires
- * @adreno_dev: pointer to the adreno_device struct
- * @drawctxt: Pointer to the draw context to sleep for
- * @timetamp: Timestamp to wait on
- * @timeout: Number of jiffies to wait (0 for infinite)
- *
- * Register an event to wait for a timestamp on a context and sleep until it
- * has past. Returns < 0 on error, -ETIMEDOUT if the timeout expires or 0
- * on success
- */
- int adreno_drawctxt_wait(struct adreno_device *adreno_dev,
- struct kgsl_context *context,
- uint32_t timestamp, unsigned int timeout)
- {
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
- int ret;
- long ret_temp;
- if (kgsl_context_detached(context))
- return -ENOENT;
- if (kgsl_context_invalid(context))
- return -EDEADLK;
- trace_adreno_drawctxt_wait_start(-1, context->id, timestamp);
- ret = kgsl_add_event(device, &context->events, timestamp,
- wait_callback, (void *) drawctxt);
- if (ret)
- goto done;
- /*
- * If timeout is 0, wait forever. msecs_to_jiffies will force
- * values larger than INT_MAX to an infinite timeout.
- */
- if (timeout == 0)
- timeout = UINT_MAX;
- ret_temp = wait_event_interruptible_timeout(drawctxt->waiting,
- _check_context_timestamp(device, context, timestamp),
- msecs_to_jiffies(timeout));
- if (ret_temp <= 0) {
- kgsl_cancel_event(device, &context->events, timestamp,
- wait_callback, (void *)drawctxt);
- ret = ret_temp ? (int)ret_temp : -ETIMEDOUT;
- goto done;
- }
- ret = 0;
- /* -EDEADLK if the context was invalidated while we were waiting */
- if (kgsl_context_invalid(context))
- ret = -EDEADLK;
- /* Return -EINVAL if the context was detached while we were waiting */
- if (kgsl_context_detached(context))
- ret = -ENOENT;
- done:
- trace_adreno_drawctxt_wait_done(-1, context->id, timestamp, ret);
- 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
- * Caller must hold the device mutex
- */
- static int adreno_drawctxt_wait_rb(struct adreno_device *adreno_dev,
- struct kgsl_context *context,
- uint32_t timestamp, unsigned int timeout)
- {
- struct adreno_context *drawctxt = ADRENO_CONTEXT(context);
- int ret = 0;
- /*
- * If the context is invalid (OR) not submitted commands to GPU
- * then return immediately - we may end up waiting for a timestamp
- * that will never come
- */
- if (kgsl_context_invalid(context) ||
- !test_bit(KGSL_CONTEXT_PRIV_SUBMITTED, &context->priv))
- 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;
- }
- static int drawctxt_detach_drawobjs(struct adreno_context *drawctxt,
- struct kgsl_drawobj **list)
- {
- int count = 0;
- while (drawctxt->drawqueue_head != drawctxt->drawqueue_tail) {
- struct kgsl_drawobj *drawobj =
- drawctxt->drawqueue[drawctxt->drawqueue_head];
- drawctxt->drawqueue_head = (drawctxt->drawqueue_head + 1) %
- ADRENO_CONTEXT_DRAWQUEUE_SIZE;
- list[count++] = drawobj;
- }
- return count;
- }
- /**
- * 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_drawobj *list[ADRENO_CONTEXT_DRAWQUEUE_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->memstore,
- KGSL_MEMSTORE_OFFSET(context->id, soptimestamp),
- drawctxt->timestamp);
- kgsl_sharedmem_writel(device->memstore,
- KGSL_MEMSTORE_OFFSET(context->id, eoptimestamp),
- drawctxt->timestamp);
- /* Get rid of commands still waiting in the queue */
- count = drawctxt_detach_drawobjs(drawctxt, list);
- spin_unlock(&drawctxt->lock);
- for (i = 0; i < count; i++) {
- kgsl_cancel_events_timestamp(device, &context->events,
- list[i]->timestamp);
- kgsl_drawobj_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);
- wake_up_all(&drawctxt->timeout);
- }
- void adreno_drawctxt_set_guilty(struct kgsl_device *device,
- struct kgsl_context *context)
- {
- if (!context)
- return;
- context->reset_status = KGSL_CTX_STAT_GUILTY_CONTEXT_RESET_EXT;
- adreno_drawctxt_invalidate(device, context);
- }
- #define KGSL_CONTEXT_PRIORITY_MED 0x8
- /**
- * adreno_drawctxt_create - create a new adreno draw context
- * @dev_priv: the owner of the context
- * @flags: flags for the context (passed from user space)
- *
- * Create and return a new draw context for the 3D core.
- */
- struct kgsl_context *
- adreno_drawctxt_create(struct kgsl_device_private *dev_priv,
- uint32_t *flags)
- {
- struct adreno_context *drawctxt;
- struct kgsl_device *device = dev_priv->device;
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- const struct adreno_gpudev *gpudev = ADRENO_GPU_DEVICE(adreno_dev);
- int ret;
- unsigned int local;
- local = *flags & (KGSL_CONTEXT_PREAMBLE |
- KGSL_CONTEXT_NO_GMEM_ALLOC |
- KGSL_CONTEXT_PER_CONTEXT_TS |
- KGSL_CONTEXT_USER_GENERATED_TS |
- KGSL_CONTEXT_NO_FAULT_TOLERANCE |
- KGSL_CONTEXT_INVALIDATE_ON_FAULT |
- KGSL_CONTEXT_CTX_SWITCH |
- KGSL_CONTEXT_PRIORITY_MASK |
- KGSL_CONTEXT_TYPE_MASK |
- KGSL_CONTEXT_PWR_CONSTRAINT |
- KGSL_CONTEXT_IFH_NOP |
- KGSL_CONTEXT_SECURE |
- KGSL_CONTEXT_PREEMPT_STYLE_MASK |
- KGSL_CONTEXT_LPAC |
- KGSL_CONTEXT_NO_SNAPSHOT |
- KGSL_CONTEXT_FAULT_INFO);
- /* Check for errors before trying to initialize */
- /* If preemption is not supported, ignore preemption request */
- if (!adreno_preemption_feature_set(adreno_dev))
- local &= ~KGSL_CONTEXT_PREEMPT_STYLE_MASK;
- /* We no longer support legacy context switching */
- if ((local & KGSL_CONTEXT_PREAMBLE) == 0 ||
- (local & KGSL_CONTEXT_NO_GMEM_ALLOC) == 0) {
- dev_err_once(device->dev,
- "legacy context switch not supported\n");
- return ERR_PTR(-EINVAL);
- }
- /* Make sure that our target can support secure contexts if requested */
- if (!kgsl_mmu_is_secured(&dev_priv->device->mmu) &&
- (local & KGSL_CONTEXT_SECURE)) {
- dev_err_once(device->dev, "Secure context not supported\n");
- return ERR_PTR(-EOPNOTSUPP);
- }
- if ((local & KGSL_CONTEXT_LPAC) &&
- (!(adreno_dev->lpac_enabled))) {
- dev_err_once(device->dev, "LPAC context not supported\n");
- return ERR_PTR(-EOPNOTSUPP);
- }
- if ((local & KGSL_CONTEXT_LPAC) && (local & KGSL_CONTEXT_SECURE)) {
- dev_err_once(device->dev, "LPAC secure context not supported\n");
- return ERR_PTR(-EOPNOTSUPP);
- }
- drawctxt = kzalloc(sizeof(struct adreno_context), GFP_KERNEL);
- if (drawctxt == NULL)
- return ERR_PTR(-ENOMEM);
- drawctxt->timestamp = 0;
- drawctxt->base.flags = local;
- /* Always enable per-context timestamps */
- drawctxt->base.flags |= KGSL_CONTEXT_PER_CONTEXT_TS;
- drawctxt->type = (drawctxt->base.flags & KGSL_CONTEXT_TYPE_MASK)
- >> KGSL_CONTEXT_TYPE_SHIFT;
- spin_lock_init(&drawctxt->lock);
- init_waitqueue_head(&drawctxt->wq);
- init_waitqueue_head(&drawctxt->waiting);
- init_waitqueue_head(&drawctxt->timeout);
- /* If the priority is not set by user, set it for them */
- if ((drawctxt->base.flags & KGSL_CONTEXT_PRIORITY_MASK) ==
- KGSL_CONTEXT_PRIORITY_UNDEF)
- drawctxt->base.flags |= (KGSL_CONTEXT_PRIORITY_MED <<
- KGSL_CONTEXT_PRIORITY_SHIFT);
- /* Store the context priority */
- drawctxt->base.priority =
- (drawctxt->base.flags & KGSL_CONTEXT_PRIORITY_MASK) >>
- KGSL_CONTEXT_PRIORITY_SHIFT;
- /*
- * Now initialize the common part of the context. This allocates the
- * context id, and then possibly another thread could look it up.
- * So we want all of our initializtion that doesn't require the context
- * id to be done before this call.
- */
- ret = kgsl_context_init(dev_priv, &drawctxt->base);
- if (ret != 0) {
- kfree(drawctxt);
- return ERR_PTR(ret);
- }
- kgsl_sharedmem_writel(device->memstore,
- KGSL_MEMSTORE_OFFSET(drawctxt->base.id, soptimestamp),
- 0);
- kgsl_sharedmem_writel(device->memstore,
- KGSL_MEMSTORE_OFFSET(drawctxt->base.id, eoptimestamp),
- 0);
- adreno_context_debugfs_init(ADRENO_DEVICE(device), drawctxt);
- INIT_LIST_HEAD(&drawctxt->active_node);
- INIT_LIST_HEAD(&drawctxt->hw_fence_list);
- INIT_LIST_HEAD(&drawctxt->hw_fence_inflight_list);
- if (adreno_dev->dispatch_ops && adreno_dev->dispatch_ops->setup_context)
- adreno_dev->dispatch_ops->setup_context(adreno_dev, drawctxt);
- if (gpudev->preemption_context_init) {
- ret = gpudev->preemption_context_init(&drawctxt->base);
- if (ret != 0) {
- kgsl_context_detach(&drawctxt->base);
- return ERR_PTR(ret);
- }
- }
- /* copy back whatever flags we dediced were valid */
- *flags = drawctxt->base.flags;
- return &drawctxt->base;
- }
- static void wait_for_timestamp_rb(struct kgsl_device *device,
- struct adreno_context *drawctxt)
- {
- struct adreno_device *adreno_dev = ADRENO_DEVICE(device);
- struct kgsl_context *context = &drawctxt->base;
- int ret;
- /*
- * 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, &drawctxt->base,
- drawctxt->internal_timestamp, 30 * 1000);
- /*
- * If the wait for global fails due to timeout then mark it as
- * context detach timeout fault and schedule dispatcher to kick
- * in GPU recovery. For a ADRENO_CTX_DETATCH_TIMEOUT_FAULT we clear
- * the policy and invalidate the context. 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 what we are waiting for, so ignore
- * -EAGAIN error.
- */
- if (ret && ret != -EAGAIN) {
- dev_err(device->dev,
- "Wait for global ctx=%u ts=%u type=%d error=%d\n",
- drawctxt->base.id, drawctxt->internal_timestamp,
- drawctxt->type, ret);
- adreno_set_gpu_fault(adreno_dev,
- ADRENO_CTX_DETATCH_TIMEOUT_FAULT);
- mutex_unlock(&device->mutex);
- /* Schedule dispatcher to kick in recovery */
- adreno_dispatcher_schedule(device);
- /* Wait for context to be invalidated and release context */
- wait_event_interruptible_timeout(drawctxt->timeout,
- kgsl_context_invalid(&drawctxt->base),
- msecs_to_jiffies(5000));
- return;
- }
- 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);
- mutex_unlock(&device->mutex);
- }
- void adreno_drawctxt_detach(struct kgsl_context *context)
- {
- struct kgsl_device *device;
- struct adreno_device *adreno_dev;
- const 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);
- 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);
- wake_up_all(&drawctxt->wq);
- }
- void adreno_drawctxt_destroy(struct kgsl_context *context)
- {
- struct adreno_context *drawctxt;
- struct adreno_device *adreno_dev;
- const struct adreno_gpudev *gpudev;
- if (context == NULL)
- return;
- drawctxt = ADRENO_CONTEXT(context);
- adreno_dev = ADRENO_DEVICE(context->device);
- gpudev = ADRENO_GPU_DEVICE(adreno_dev);
- if (gpudev->context_destroy)
- gpudev->context_destroy(adreno_dev, drawctxt);
- kfree(drawctxt);
- }
- static void _drawctxt_switch_wait_callback(struct kgsl_device *device,
- struct kgsl_event_group *group,
- void *priv, int result)
- {
- struct adreno_context *drawctxt = (struct adreno_context *) priv;
- kgsl_context_put(&drawctxt->base);
- }
- void adreno_put_drawctxt_on_timestamp(struct kgsl_device *device,
- struct adreno_context *drawctxt,
- struct adreno_ringbuffer *rb, u32 timestamp)
- {
- if (!drawctxt)
- return;
- if (kgsl_add_event(device, &rb->events, timestamp,
- _drawctxt_switch_wait_callback, drawctxt))
- kgsl_context_put(&drawctxt->base);
- }
- static void _add_context(struct adreno_device *adreno_dev,
- struct adreno_context *drawctxt)
- {
- /* Remove it from the list */
- list_del_init(&drawctxt->active_node);
- /* And push it to the front */
- drawctxt->active_time = jiffies;
- list_add(&drawctxt->active_node, &adreno_dev->active_list);
- }
- static int __count_context(struct adreno_context *drawctxt, void *data)
- {
- unsigned long expires = drawctxt->active_time + msecs_to_jiffies(100);
- return time_after(jiffies, expires) ? 0 : 1;
- }
- static int __count_drawqueue_context(struct adreno_context *drawctxt,
- void *data)
- {
- unsigned long expires = drawctxt->active_time + msecs_to_jiffies(100);
- if (time_after(jiffies, expires))
- return 0;
- return (&drawctxt->rb->dispatch_q ==
- (struct adreno_dispatcher_drawqueue *) data) ? 1 : 0;
- }
- static int _adreno_count_active_contexts(struct adreno_device *adreno_dev,
- int (*func)(struct adreno_context *, void *), void *data)
- {
- struct adreno_context *ctxt;
- int count = 0;
- list_for_each_entry(ctxt, &adreno_dev->active_list, active_node) {
- if (func(ctxt, data) == 0)
- return count;
- count++;
- }
- return count;
- }
- void adreno_track_context(struct adreno_device *adreno_dev,
- struct adreno_dispatcher_drawqueue *drawqueue,
- struct adreno_context *drawctxt)
- {
- struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
- spin_lock(&adreno_dev->active_list_lock);
- _add_context(adreno_dev, drawctxt);
- device->active_context_count =
- _adreno_count_active_contexts(adreno_dev,
- __count_context, NULL);
- if (drawqueue)
- drawqueue->active_context_count =
- _adreno_count_active_contexts(adreno_dev,
- __count_drawqueue_context, drawqueue);
- spin_unlock(&adreno_dev->active_list_lock);
- }
|