void nvhost_job_unpin(struct nvhost_job *job)
{
	nvmap_unpin_handles(job->nvmap, job->unpins,
			job->num_unpins);
	memset(job->unpins, BAD_MAGIC,
			job->num_unpins * sizeof(struct nvmap_handle *));
}
예제 #2
0
/**
 * For all sync queue entries that have already finished according to the
 * current sync point registers:
 *  - unpin & unref their mems
 *  - pop their push buffer slots
 *  - remove them from the sync queue
 * This is normally called from the host code's worker thread, but can be
 * called manually if necessary.
 * Must be called with the cdma lock held.
 */
static void update_cdma(struct nvhost_cdma *cdma)
{
	bool signal = false;
	struct nvhost_master *dev = cdma_to_dev(cdma);

	BUG_ON(!cdma->running);

	/*
	 * Walk the sync queue, reading the sync point registers as necessary,
	 * to consume as many sync queue entries as possible without blocking
	 */
	for (;;) {
		u32 syncpt_id, syncpt_val;
		u32 timeout;
		struct nvhost_userctx_timeout *timeout_ref = NULL;
		unsigned int nr_slots, nr_handles;
		struct nvhost_syncpt *sp = &dev->syncpt;
		struct nvmap_handle **handles;
		struct nvmap_client *nvmap;
		u32 *sync;

		sync = sync_queue_head(&cdma->sync_queue);
		if (!sync) {
			if (cdma->event == CDMA_EVENT_SYNC_QUEUE_EMPTY)
				signal = true;
			break;
		}

		syncpt_id = sync[SQ_IDX_SYNCPT_ID];
		syncpt_val = sync[SQ_IDX_SYNCPT_VAL];
		timeout = sync[SQ_IDX_TIMEOUT];
		timeout_ref = (struct nvhost_userctx_timeout *)
				sync[SQ_IDX_TIMEOUT_CTX];

		BUG_ON(syncpt_id == NVSYNCPT_INVALID);

		/* Check whether this syncpt has completed, and bail if not */
		if (!nvhost_syncpt_min_cmp(sp, syncpt_id, syncpt_val)) {
			/* Start timer on next pending syncpt */
			if (timeout) {
				nvhost_cdma_start_timer(cdma, syncpt_id,
					syncpt_val, timeout_ref);
			}
			break;
		}

		/* Cancel timeout, when a buffer completes */
		if (cdma->timeout.ctx_timeout)
			stop_cdma_timer(cdma);

		nr_slots = sync[SQ_IDX_NUM_SLOTS];
		nr_handles = sync[SQ_IDX_NUM_HANDLES];
		nvmap = (struct nvmap_client *)sync[SQ_IDX_NVMAP_CTX];
		handles = (struct nvmap_handle **)&sync[SQ_IDX_HANDLES];

		BUG_ON(!nvmap);

		/* Unpin the memory */
		nvmap_unpin_handles(nvmap, handles, nr_handles);
		nvmap_client_put(nvmap);

		/* Pop push buffer slots */
		if (nr_slots) {
			struct push_buffer *pb = &cdma->push_buffer;
			BUG_ON(!cdma_pb_op(cdma).pop_from);
			cdma_pb_op(cdma).pop_from(pb, nr_slots);
			if (cdma->event == CDMA_EVENT_PUSH_BUFFER_SPACE)
				signal = true;
		}

		dequeue_sync_queue_head(&cdma->sync_queue);
		if (cdma->event == CDMA_EVENT_SYNC_QUEUE_SPACE)
			signal = true;
	}

	/* Wake up CdmaWait() if the requested event happened */
	if (signal) {
		cdma->event = CDMA_EVENT_NONE;
		up(&cdma->sem);
	}
}