/* * kgsl_iommu_disable_clk_on_ts - Sets up event to disable IOMMU clocks * @mmu - The kgsl MMU pointer * @ts - Timestamp on which the clocks should be disabled * @ts_valid - Indicates whether ts parameter is valid, if this parameter * is false then it means that the calling function wants to disable the * IOMMU clocks immediately without waiting for any timestamp * * Creates an event to disable the IOMMU clocks on timestamp and if event * already exists then updates the timestamp of disabling the IOMMU clocks * with the passed in ts if it is greater than the current value at which * the clocks will be disabled * Return - void */ static void kgsl_iommu_disable_clk_on_ts(struct kgsl_mmu *mmu, unsigned int ts, bool ts_valid) { struct kgsl_iommu *iommu = mmu->priv; if (iommu->clk_event_queued) { if (ts_valid && (0 < timestamp_cmp(ts, iommu->iommu_last_cmd_ts))) iommu->iommu_last_cmd_ts = ts; } else { if (ts_valid) { iommu->iommu_last_cmd_ts = ts; iommu->clk_event_queued = true; if (kgsl_add_event(mmu->device, KGSL_MEMSTORE_GLOBAL, ts, kgsl_iommu_clk_disable_event, mmu, mmu)) { KGSL_DRV_ERR(mmu->device, "Failed to add IOMMU disable clk event\n"); iommu->clk_event_queued = false; } } else { kgsl_iommu_disable_clk(mmu); } } }
static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data, unsigned int id, unsigned int ts) { struct kgsl_mmu *mmu = data; struct kgsl_iommu *iommu = mmu->priv; if (!iommu->clk_event_queued) { if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) KGSL_DRV_ERR(device, "IOMMU disable clock event being cancelled, " "iommu_last_cmd_ts: %x, retired ts: %x\n", iommu->iommu_last_cmd_ts, ts); return; } if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) { kgsl_iommu_disable_clk(mmu); iommu->clk_event_queued = false; } else { if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts, kgsl_iommu_clk_disable_event, mmu, mmu)) { KGSL_DRV_ERR(device, "Failed to add IOMMU disable clk event\n"); iommu->clk_event_queued = false; } } }
/* * kgsl_iommu_disable_clk_event - An event function that is executed when * the required timestamp is reached. It disables the IOMMU clocks if * the timestamp on which the clocks can be disabled has expired. * @device - The kgsl device pointer * @data - The data passed during event creation, it is the MMU pointer * @id - Context ID, should always be KGSL_MEMSTORE_GLOBAL * @ts - The current timestamp that has expired for the device * * Disables IOMMU clocks if timestamp has expired * Return - void */ static void kgsl_iommu_clk_disable_event(struct kgsl_device *device, void *data, unsigned int id, unsigned int ts) { struct kgsl_mmu *mmu = data; struct kgsl_iommu *iommu = mmu->priv; if (!iommu->clk_event_queued) { if (0 > timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) KGSL_DRV_ERR(device, "IOMMU disable clock event being cancelled, " "iommu_last_cmd_ts: %x, retired ts: %x\n", iommu->iommu_last_cmd_ts, ts); return; } if (0 <= timestamp_cmp(ts, iommu->iommu_last_cmd_ts)) { kgsl_iommu_disable_clk(mmu); iommu->clk_event_queued = false; } else { /* add new event to fire when ts is reached, this can happen * if we queued an event and someone requested the clocks to * be disbaled on a later timestamp */ if (kgsl_add_event(device, id, iommu->iommu_last_cmd_ts, kgsl_iommu_clk_disable_event, mmu, mmu)) { KGSL_DRV_ERR(device, "Failed to add IOMMU disable clk event\n"); iommu->clk_event_queued = false; } } }
static int adreno_drawctxt_wait_global(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 (!_kgsl_context_get(context)) { ret = -EINVAL; goto done; } /* * If the context is invalid then return immediately - we may end up * waiting for a timestamp that will never come */ if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) { kgsl_context_put(context); goto done; } trace_adreno_drawctxt_wait_start(KGSL_MEMSTORE_GLOBAL, timestamp); ret = kgsl_add_event(device, &device->global_events, timestamp, global_wait_callback, (void *) drawctxt); if (ret) { kgsl_context_put(context); goto done; } kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); if (timeout) { ret = (int) wait_event_timeout(drawctxt->waiting, _check_global_timestamp(device, drawctxt, timestamp), msecs_to_jiffies(timeout)); if (ret == 0) ret = -ETIMEDOUT; else if (ret > 0) ret = 0; } else { wait_event(drawctxt->waiting, _check_global_timestamp(device, drawctxt, timestamp)); } kgsl_mutex_lock(&device->mutex, &device->mutex_owner); if (ret) kgsl_cancel_events_timestamp(device, &device->global_events, timestamp); done: trace_adreno_drawctxt_wait_done(KGSL_MEMSTORE_GLOBAL, timestamp, ret); return ret; }
static int _add_fence_event(struct kgsl_device *device, struct kgsl_context *context, unsigned int timestamp) { struct kgsl_fence_event_priv *event; int ret; event = kmalloc(sizeof(*event), GFP_KERNEL); if (event == NULL) return -ENOMEM; /* * Increase the refcount for the context to keep it through the * callback */ _kgsl_context_get(context); event->context = context; event->timestamp = timestamp; event->context = context; ret = kgsl_add_event(device, context->id, timestamp, kgsl_fence_event_cb, event, context->dev_priv); if (ret) { kgsl_context_put(context); kfree(event); } return ret; }
/** * 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 = &adreno_dev->dev; struct adreno_context *drawctxt = ADRENO_CONTEXT(context); int ret; long ret_temp; if (kgsl_context_detached(context)) return -EINVAL; if (kgsl_context_invalid(context)) return -EDEADLK; /* Needs to hold the device mutex */ BUG_ON(!mutex_is_locked(&device->mutex)); 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; mutex_unlock(&device->mutex); if (timeout) { ret_temp = wait_event_interruptible_timeout( drawctxt->waiting, _check_context_timestamp(device, drawctxt, timestamp), msecs_to_jiffies(timeout)); if (ret_temp == 0) ret = -ETIMEDOUT; else if (ret_temp > 0) ret = 0; else ret = (int) ret_temp; } else { ret = wait_event_interruptible(drawctxt->waiting, _check_context_timestamp(device, drawctxt, timestamp)); } mutex_lock(&device->mutex); /* -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 = -EINVAL; done: trace_adreno_drawctxt_wait_done(-1, context->id, timestamp, ret); return ret; }
/** * 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 = &adreno_dev->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) { ret = -ETIMEDOUT; goto done; } else if (ret_temp < 0) { ret = (int) ret_temp; 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; }
int adreno_drawctxt_wait_global(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; BUG_ON(!mutex_is_locked(&device->mutex)); if (!_kgsl_context_get(context)) { ret = -EINVAL; goto done; } if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) { kgsl_context_put(context); goto done; } trace_adreno_drawctxt_wait_start(KGSL_MEMSTORE_GLOBAL, timestamp); ret = kgsl_add_event(device, KGSL_MEMSTORE_GLOBAL, timestamp, global_wait_callback, drawctxt, NULL); if (ret) { kgsl_context_put(context); goto done; } mutex_unlock(&device->mutex); if (timeout) { ret = (int) wait_event_timeout(drawctxt->waiting, _check_global_timestamp(device, drawctxt, timestamp), msecs_to_jiffies(timeout)); if (ret == 0) ret = -ETIMEDOUT; else if (ret > 0) ret = 0; } else { wait_event(drawctxt->waiting, _check_global_timestamp(device, drawctxt, timestamp)); } mutex_lock(&device->mutex); if (ret) kgsl_cancel_events_timestamp(device, NULL, timestamp); done: trace_adreno_drawctxt_wait_done(KGSL_MEMSTORE_GLOBAL, timestamp, ret); return ret; }
/** * 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) { static unsigned int io_cnt; struct kgsl_device *device = &adreno_dev->dev; struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct adreno_context *drawctxt = ADRENO_CONTEXT(context); int ret, io; if (kgsl_context_detached(context)) return -EINVAL; if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) return -EDEADLK; /* Needs to hold the device mutex */ BUG_ON(!mutex_is_locked(&device->mutex)); trace_adreno_drawctxt_wait_start(context->id, timestamp); ret = kgsl_add_event(device, &context->events, timestamp, wait_callback, (void *) drawctxt); if (ret) goto done; /* * For proper power accounting sometimes we need to call * io_wait_interruptible_timeout and sometimes we need to call * plain old wait_interruptible_timeout. We call the regular * timeout N times out of 100, where N is a number specified by * the current power level */ io_cnt = (io_cnt + 1) % 100; io = (io_cnt < pwr->pwrlevels[pwr->active_pwrlevel].io_fraction) ? 0 : 1; kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); if (timeout) { long ret_temp; ret_temp = adreno_wait_event_interruptible_timeout( drawctxt->waiting, _check_context_timestamp(device, drawctxt, timestamp), msecs_to_jiffies(timeout), io); if (ret_temp == 0) ret = -ETIMEDOUT; else if (ret_temp > 0) ret = 0; else ret = (int) ret_temp; } else { ret = (int) adreno_wait_event_interruptible(drawctxt->waiting, _check_context_timestamp(device, drawctxt, timestamp), io); } kgsl_mutex_lock(&device->mutex, &device->mutex_owner); /* -EDEADLK if the context was invalidated while we were waiting */ if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) ret = -EDEADLK; /* Return -EINVAL if the context was detached while we were waiting */ if (kgsl_context_detached(context)) ret = -EINVAL; done: trace_adreno_drawctxt_wait_done(context->id, timestamp, ret); return ret; }
int kgsl_add_fence_event(struct kgsl_device *device, u32 context_id, u32 timestamp, void __user *data, int len, struct kgsl_device_private *owner) { struct kgsl_fence_event_priv *event; struct kgsl_timestamp_event_fence priv; struct kgsl_context *context; struct sync_pt *pt; struct sync_fence *fence = NULL; int ret = -EINVAL; if (len != sizeof(priv)) return -EINVAL; context = kgsl_find_context(owner, context_id); if (context == NULL) return -EINVAL; event = kzalloc(sizeof(*event), GFP_KERNEL); if (event == NULL) return -ENOMEM; event->context = context; event->timestamp = timestamp; kgsl_context_get(context); pt = kgsl_sync_pt_create(context->timeline, timestamp); if (pt == NULL) { KGSL_DRV_ERR(device, "kgsl_sync_pt_create failed\n"); ret = -ENOMEM; goto fail_pt; } fence = sync_fence_create("kgsl-fence", pt); if (fence == NULL) { /* only destroy pt when not added to fence */ kgsl_sync_pt_destroy(pt); KGSL_DRV_ERR(device, "sync_fence_create failed\n"); ret = -ENOMEM; goto fail_fence; } priv.fence_fd = get_unused_fd_flags(0); if (priv.fence_fd < 0) { KGSL_DRV_ERR(device, "invalid fence fd\n"); ret = -EINVAL; goto fail_fd; } sync_fence_install(fence, priv.fence_fd); if (copy_to_user(data, &priv, sizeof(priv))) { ret = -EFAULT; goto fail_copy_fd; } ret = kgsl_add_event(device, context_id, timestamp, kgsl_fence_event_cb, event, owner); if (ret) goto fail_event; return 0; fail_event: fail_copy_fd: /* clean up sync_fence_install */ put_unused_fd(priv.fence_fd); fail_fd: /* clean up sync_fence_create */ sync_fence_put(fence); fail_fence: fail_pt: kgsl_context_put(context); kfree(event); return ret; }
int adreno_drawctxt_wait(struct adreno_device *adreno_dev, struct kgsl_context *context, uint32_t timestamp, unsigned int timeout) { static unsigned int io_cnt; struct kgsl_device *device = &adreno_dev->dev; struct kgsl_pwrctrl *pwr = &device->pwrctrl; struct adreno_context *drawctxt = ADRENO_CONTEXT(context); int ret, io; if (kgsl_context_detached(context)) return -EINVAL; if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) return -EDEADLK; BUG_ON(!mutex_is_locked(&device->mutex)); trace_adreno_drawctxt_wait_start(context->id, timestamp); ret = kgsl_add_event(device, context->id, timestamp, wait_callback, drawctxt, NULL); if (ret) goto done; io_cnt = (io_cnt + 1) % 100; io = (io_cnt < pwr->pwrlevels[pwr->active_pwrlevel].io_fraction) ? 0 : 1; mutex_unlock(&device->mutex); if (timeout) { ret = (int) adreno_wait_event_interruptible_timeout( drawctxt->waiting, _check_context_timestamp(device, drawctxt, timestamp), msecs_to_jiffies(timeout), io); if (ret == 0) ret = -ETIMEDOUT; else if (ret > 0) ret = 0; } else { ret = (int) adreno_wait_event_interruptible(drawctxt->waiting, _check_context_timestamp(device, drawctxt, timestamp), io); } mutex_lock(&device->mutex); if (drawctxt->state == ADRENO_CONTEXT_STATE_INVALID) ret = -EDEADLK; if (kgsl_context_detached(context)) ret = -EINVAL; done: trace_adreno_drawctxt_wait_done(context->id, timestamp, ret); return ret; }
int kgsl_add_fence_event(struct kgsl_device *device, u32 context_id, u32 timestamp, void __user *data, int len, struct kgsl_device_private *owner) { struct kgsl_fence_event_priv *event; struct kgsl_timestamp_event_fence priv; struct kgsl_context *context; struct sync_pt *pt; struct sync_fence *fence = NULL; int ret = -EINVAL; char fence_name[sizeof(fence->name)] = {}; priv.fence_fd = -1; if (len != sizeof(priv)) return -EINVAL; event = kzalloc(sizeof(*event), GFP_KERNEL); if (event == NULL) return -ENOMEM; kgsl_mutex_lock(&device->mutex, &device->mutex_owner); context = kgsl_context_get_owner(owner, context_id); if (context == NULL) goto unlock; event->context = context; event->timestamp = timestamp; pt = kgsl_sync_pt_create(context->timeline, timestamp); if (pt == NULL) { KGSL_DRV_ERR(device, "kgsl_sync_pt_create failed\n"); ret = -ENOMEM; goto unlock; } snprintf(fence_name, sizeof(fence_name), "%s-pid-%d-ctx-%d-ts-%d", device->name, current->group_leader->pid, context_id, timestamp); fence = sync_fence_create(fence_name, pt); if (fence == NULL) { /* only destroy pt when not added to fence */ kgsl_sync_pt_destroy(pt); KGSL_DRV_ERR(device, "sync_fence_create failed\n"); ret = -ENOMEM; goto unlock; } priv.fence_fd = get_unused_fd_flags(0); if (priv.fence_fd < 0) { KGSL_DRV_ERR(device, "Unable to get a file descriptor: %d\n", priv.fence_fd); ret = priv.fence_fd; goto unlock; } /* Unlock the mutex before copying to user */ kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); if (copy_to_user(data, &priv, sizeof(priv))) { ret = -EFAULT; goto out; } /* * Hold the context ref-count for the event - it will get released in * the callback */ ret = kgsl_add_event(device, &context->events, timestamp, kgsl_fence_event_cb, event); if (ret) goto out; sync_fence_install(fence, priv.fence_fd); return 0; unlock: kgsl_mutex_unlock(&device->mutex, &device->mutex_owner); out: if (priv.fence_fd >= 0) put_unused_fd(priv.fence_fd); if (fence) sync_fence_put(fence); kgsl_context_put(context); kfree(event); return ret; }