18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Tegra host1x Command DMA
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2010-2013, NVIDIA Corporation.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <asm/cacheflush.h>
108c2ecf20Sopenharmony_ci#include <linux/device.h>
118c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
128c2ecf20Sopenharmony_ci#include <linux/host1x.h>
138c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/kfifo.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci#include <trace/events/host1x.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "cdma.h"
208c2ecf20Sopenharmony_ci#include "channel.h"
218c2ecf20Sopenharmony_ci#include "dev.h"
228c2ecf20Sopenharmony_ci#include "debug.h"
238c2ecf20Sopenharmony_ci#include "job.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/*
268c2ecf20Sopenharmony_ci * push_buffer
278c2ecf20Sopenharmony_ci *
288c2ecf20Sopenharmony_ci * The push buffer is a circular array of words to be fetched by command DMA.
298c2ecf20Sopenharmony_ci * Note that it works slightly differently to the sync queue; fence == pos
308c2ecf20Sopenharmony_ci * means that the push buffer is full, not empty.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/*
348c2ecf20Sopenharmony_ci * Typically the commands written into the push buffer are a pair of words. We
358c2ecf20Sopenharmony_ci * use slots to represent each of these pairs and to simplify things. Note the
368c2ecf20Sopenharmony_ci * strange number of slots allocated here. 512 slots will fit exactly within a
378c2ecf20Sopenharmony_ci * single memory page. We also need one additional word at the end of the push
388c2ecf20Sopenharmony_ci * buffer for the RESTART opcode that will instruct the CDMA to jump back to
398c2ecf20Sopenharmony_ci * the beginning of the push buffer. With 512 slots, this means that we'll use
408c2ecf20Sopenharmony_ci * 2 memory pages and waste 4092 bytes of the second page that will never be
418c2ecf20Sopenharmony_ci * used.
428c2ecf20Sopenharmony_ci */
438c2ecf20Sopenharmony_ci#define HOST1X_PUSHBUFFER_SLOTS	511
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/*
468c2ecf20Sopenharmony_ci * Clean up push buffer resources
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_cistatic void host1x_pushbuffer_destroy(struct push_buffer *pb)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	struct host1x_cdma *cdma = pb_to_cdma(pb);
518c2ecf20Sopenharmony_ci	struct host1x *host1x = cdma_to_host1x(cdma);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	if (!pb->mapped)
548c2ecf20Sopenharmony_ci		return;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	if (host1x->domain) {
578c2ecf20Sopenharmony_ci		iommu_unmap(host1x->domain, pb->dma, pb->alloc_size);
588c2ecf20Sopenharmony_ci		free_iova(&host1x->iova, iova_pfn(&host1x->iova, pb->dma));
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	dma_free_wc(host1x->dev, pb->alloc_size, pb->mapped, pb->phys);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	pb->mapped = NULL;
648c2ecf20Sopenharmony_ci	pb->phys = 0;
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci/*
688c2ecf20Sopenharmony_ci * Init push buffer resources
698c2ecf20Sopenharmony_ci */
708c2ecf20Sopenharmony_cistatic int host1x_pushbuffer_init(struct push_buffer *pb)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	struct host1x_cdma *cdma = pb_to_cdma(pb);
738c2ecf20Sopenharmony_ci	struct host1x *host1x = cdma_to_host1x(cdma);
748c2ecf20Sopenharmony_ci	struct iova *alloc;
758c2ecf20Sopenharmony_ci	u32 size;
768c2ecf20Sopenharmony_ci	int err;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	pb->mapped = NULL;
798c2ecf20Sopenharmony_ci	pb->phys = 0;
808c2ecf20Sopenharmony_ci	pb->size = HOST1X_PUSHBUFFER_SLOTS * 8;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	size = pb->size + 4;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	/* initialize buffer pointers */
858c2ecf20Sopenharmony_ci	pb->fence = pb->size - 8;
868c2ecf20Sopenharmony_ci	pb->pos = 0;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	if (host1x->domain) {
898c2ecf20Sopenharmony_ci		unsigned long shift;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		size = iova_align(&host1x->iova, size);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci		pb->mapped = dma_alloc_wc(host1x->dev, size, &pb->phys,
948c2ecf20Sopenharmony_ci					  GFP_KERNEL);
958c2ecf20Sopenharmony_ci		if (!pb->mapped)
968c2ecf20Sopenharmony_ci			return -ENOMEM;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci		shift = iova_shift(&host1x->iova);
998c2ecf20Sopenharmony_ci		alloc = alloc_iova(&host1x->iova, size >> shift,
1008c2ecf20Sopenharmony_ci				   host1x->iova_end >> shift, true);
1018c2ecf20Sopenharmony_ci		if (!alloc) {
1028c2ecf20Sopenharmony_ci			err = -ENOMEM;
1038c2ecf20Sopenharmony_ci			goto iommu_free_mem;
1048c2ecf20Sopenharmony_ci		}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci		pb->dma = iova_dma_addr(&host1x->iova, alloc);
1078c2ecf20Sopenharmony_ci		err = iommu_map(host1x->domain, pb->dma, pb->phys, size,
1088c2ecf20Sopenharmony_ci				IOMMU_READ);
1098c2ecf20Sopenharmony_ci		if (err)
1108c2ecf20Sopenharmony_ci			goto iommu_free_iova;
1118c2ecf20Sopenharmony_ci	} else {
1128c2ecf20Sopenharmony_ci		pb->mapped = dma_alloc_wc(host1x->dev, size, &pb->phys,
1138c2ecf20Sopenharmony_ci					  GFP_KERNEL);
1148c2ecf20Sopenharmony_ci		if (!pb->mapped)
1158c2ecf20Sopenharmony_ci			return -ENOMEM;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci		pb->dma = pb->phys;
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	pb->alloc_size = size;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	host1x_hw_pushbuffer_init(host1x, pb);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	return 0;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ciiommu_free_iova:
1278c2ecf20Sopenharmony_ci	__free_iova(&host1x->iova, alloc);
1288c2ecf20Sopenharmony_ciiommu_free_mem:
1298c2ecf20Sopenharmony_ci	dma_free_wc(host1x->dev, size, pb->mapped, pb->phys);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return err;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci/*
1358c2ecf20Sopenharmony_ci * Push two words to the push buffer
1368c2ecf20Sopenharmony_ci * Caller must ensure push buffer is not full
1378c2ecf20Sopenharmony_ci */
1388c2ecf20Sopenharmony_cistatic void host1x_pushbuffer_push(struct push_buffer *pb, u32 op1, u32 op2)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	u32 *p = (u32 *)((void *)pb->mapped + pb->pos);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	WARN_ON(pb->pos == pb->fence);
1438c2ecf20Sopenharmony_ci	*(p++) = op1;
1448c2ecf20Sopenharmony_ci	*(p++) = op2;
1458c2ecf20Sopenharmony_ci	pb->pos += 8;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (pb->pos >= pb->size)
1488c2ecf20Sopenharmony_ci		pb->pos -= pb->size;
1498c2ecf20Sopenharmony_ci}
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci/*
1528c2ecf20Sopenharmony_ci * Pop a number of two word slots from the push buffer
1538c2ecf20Sopenharmony_ci * Caller must ensure push buffer is not empty
1548c2ecf20Sopenharmony_ci */
1558c2ecf20Sopenharmony_cistatic void host1x_pushbuffer_pop(struct push_buffer *pb, unsigned int slots)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	/* Advance the next write position */
1588c2ecf20Sopenharmony_ci	pb->fence += slots * 8;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (pb->fence >= pb->size)
1618c2ecf20Sopenharmony_ci		pb->fence -= pb->size;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci/*
1658c2ecf20Sopenharmony_ci * Return the number of two word slots free in the push buffer
1668c2ecf20Sopenharmony_ci */
1678c2ecf20Sopenharmony_cistatic u32 host1x_pushbuffer_space(struct push_buffer *pb)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	unsigned int fence = pb->fence;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (pb->fence < pb->pos)
1728c2ecf20Sopenharmony_ci		fence += pb->size;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	return (fence - pb->pos) / 8;
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci/*
1788c2ecf20Sopenharmony_ci * Sleep (if necessary) until the requested event happens
1798c2ecf20Sopenharmony_ci *   - CDMA_EVENT_SYNC_QUEUE_EMPTY : sync queue is completely empty.
1808c2ecf20Sopenharmony_ci *     - Returns 1
1818c2ecf20Sopenharmony_ci *   - CDMA_EVENT_PUSH_BUFFER_SPACE : there is space in the push buffer
1828c2ecf20Sopenharmony_ci *     - Return the amount of space (> 0)
1838c2ecf20Sopenharmony_ci * Must be called with the cdma lock held.
1848c2ecf20Sopenharmony_ci */
1858c2ecf20Sopenharmony_ciunsigned int host1x_cdma_wait_locked(struct host1x_cdma *cdma,
1868c2ecf20Sopenharmony_ci				     enum cdma_event event)
1878c2ecf20Sopenharmony_ci{
1888c2ecf20Sopenharmony_ci	for (;;) {
1898c2ecf20Sopenharmony_ci		struct push_buffer *pb = &cdma->push_buffer;
1908c2ecf20Sopenharmony_ci		unsigned int space;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci		switch (event) {
1938c2ecf20Sopenharmony_ci		case CDMA_EVENT_SYNC_QUEUE_EMPTY:
1948c2ecf20Sopenharmony_ci			space = list_empty(&cdma->sync_queue) ? 1 : 0;
1958c2ecf20Sopenharmony_ci			break;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci		case CDMA_EVENT_PUSH_BUFFER_SPACE:
1988c2ecf20Sopenharmony_ci			space = host1x_pushbuffer_space(pb);
1998c2ecf20Sopenharmony_ci			break;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		default:
2028c2ecf20Sopenharmony_ci			WARN_ON(1);
2038c2ecf20Sopenharmony_ci			return -EINVAL;
2048c2ecf20Sopenharmony_ci		}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci		if (space)
2078c2ecf20Sopenharmony_ci			return space;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		trace_host1x_wait_cdma(dev_name(cdma_to_channel(cdma)->dev),
2108c2ecf20Sopenharmony_ci				       event);
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci		/* If somebody has managed to already start waiting, yield */
2138c2ecf20Sopenharmony_ci		if (cdma->event != CDMA_EVENT_NONE) {
2148c2ecf20Sopenharmony_ci			mutex_unlock(&cdma->lock);
2158c2ecf20Sopenharmony_ci			schedule();
2168c2ecf20Sopenharmony_ci			mutex_lock(&cdma->lock);
2178c2ecf20Sopenharmony_ci			continue;
2188c2ecf20Sopenharmony_ci		}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci		cdma->event = event;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci		mutex_unlock(&cdma->lock);
2238c2ecf20Sopenharmony_ci		wait_for_completion(&cdma->complete);
2248c2ecf20Sopenharmony_ci		mutex_lock(&cdma->lock);
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	return 0;
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci/*
2318c2ecf20Sopenharmony_ci * Sleep (if necessary) until the push buffer has enough free space.
2328c2ecf20Sopenharmony_ci *
2338c2ecf20Sopenharmony_ci * Must be called with the cdma lock held.
2348c2ecf20Sopenharmony_ci */
2358c2ecf20Sopenharmony_cistatic int host1x_cdma_wait_pushbuffer_space(struct host1x *host1x,
2368c2ecf20Sopenharmony_ci					     struct host1x_cdma *cdma,
2378c2ecf20Sopenharmony_ci					     unsigned int needed)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	while (true) {
2408c2ecf20Sopenharmony_ci		struct push_buffer *pb = &cdma->push_buffer;
2418c2ecf20Sopenharmony_ci		unsigned int space;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci		space = host1x_pushbuffer_space(pb);
2448c2ecf20Sopenharmony_ci		if (space >= needed)
2458c2ecf20Sopenharmony_ci			break;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci		trace_host1x_wait_cdma(dev_name(cdma_to_channel(cdma)->dev),
2488c2ecf20Sopenharmony_ci				       CDMA_EVENT_PUSH_BUFFER_SPACE);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci		host1x_hw_cdma_flush(host1x, cdma);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci		/* If somebody has managed to already start waiting, yield */
2538c2ecf20Sopenharmony_ci		if (cdma->event != CDMA_EVENT_NONE) {
2548c2ecf20Sopenharmony_ci			mutex_unlock(&cdma->lock);
2558c2ecf20Sopenharmony_ci			schedule();
2568c2ecf20Sopenharmony_ci			mutex_lock(&cdma->lock);
2578c2ecf20Sopenharmony_ci			continue;
2588c2ecf20Sopenharmony_ci		}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci		cdma->event = CDMA_EVENT_PUSH_BUFFER_SPACE;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci		mutex_unlock(&cdma->lock);
2638c2ecf20Sopenharmony_ci		wait_for_completion(&cdma->complete);
2648c2ecf20Sopenharmony_ci		mutex_lock(&cdma->lock);
2658c2ecf20Sopenharmony_ci	}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	return 0;
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci/*
2708c2ecf20Sopenharmony_ci * Start timer that tracks the time spent by the job.
2718c2ecf20Sopenharmony_ci * Must be called with the cdma lock held.
2728c2ecf20Sopenharmony_ci */
2738c2ecf20Sopenharmony_cistatic void cdma_start_timer_locked(struct host1x_cdma *cdma,
2748c2ecf20Sopenharmony_ci				    struct host1x_job *job)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	struct host1x *host = cdma_to_host1x(cdma);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (cdma->timeout.client) {
2798c2ecf20Sopenharmony_ci		/* timer already started */
2808c2ecf20Sopenharmony_ci		return;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	cdma->timeout.client = job->client;
2848c2ecf20Sopenharmony_ci	cdma->timeout.syncpt = host1x_syncpt_get(host, job->syncpt_id);
2858c2ecf20Sopenharmony_ci	cdma->timeout.syncpt_val = job->syncpt_end;
2868c2ecf20Sopenharmony_ci	cdma->timeout.start_ktime = ktime_get();
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	schedule_delayed_work(&cdma->timeout.wq,
2898c2ecf20Sopenharmony_ci			      msecs_to_jiffies(job->timeout));
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci/*
2938c2ecf20Sopenharmony_ci * Stop timer when a buffer submission completes.
2948c2ecf20Sopenharmony_ci * Must be called with the cdma lock held.
2958c2ecf20Sopenharmony_ci */
2968c2ecf20Sopenharmony_cistatic void stop_cdma_timer_locked(struct host1x_cdma *cdma)
2978c2ecf20Sopenharmony_ci{
2988c2ecf20Sopenharmony_ci	cancel_delayed_work(&cdma->timeout.wq);
2998c2ecf20Sopenharmony_ci	cdma->timeout.client = NULL;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci/*
3038c2ecf20Sopenharmony_ci * For all sync queue entries that have already finished according to the
3048c2ecf20Sopenharmony_ci * current sync point registers:
3058c2ecf20Sopenharmony_ci *  - unpin & unref their mems
3068c2ecf20Sopenharmony_ci *  - pop their push buffer slots
3078c2ecf20Sopenharmony_ci *  - remove them from the sync queue
3088c2ecf20Sopenharmony_ci * This is normally called from the host code's worker thread, but can be
3098c2ecf20Sopenharmony_ci * called manually if necessary.
3108c2ecf20Sopenharmony_ci * Must be called with the cdma lock held.
3118c2ecf20Sopenharmony_ci */
3128c2ecf20Sopenharmony_cistatic void update_cdma_locked(struct host1x_cdma *cdma)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	bool signal = false;
3158c2ecf20Sopenharmony_ci	struct host1x *host1x = cdma_to_host1x(cdma);
3168c2ecf20Sopenharmony_ci	struct host1x_job *job, *n;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* If CDMA is stopped, queue is cleared and we can return */
3198c2ecf20Sopenharmony_ci	if (!cdma->running)
3208c2ecf20Sopenharmony_ci		return;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	/*
3238c2ecf20Sopenharmony_ci	 * Walk the sync queue, reading the sync point registers as necessary,
3248c2ecf20Sopenharmony_ci	 * to consume as many sync queue entries as possible without blocking
3258c2ecf20Sopenharmony_ci	 */
3268c2ecf20Sopenharmony_ci	list_for_each_entry_safe(job, n, &cdma->sync_queue, list) {
3278c2ecf20Sopenharmony_ci		struct host1x_syncpt *sp =
3288c2ecf20Sopenharmony_ci			host1x_syncpt_get(host1x, job->syncpt_id);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci		/* Check whether this syncpt has completed, and bail if not */
3318c2ecf20Sopenharmony_ci		if (!host1x_syncpt_is_expired(sp, job->syncpt_end)) {
3328c2ecf20Sopenharmony_ci			/* Start timer on next pending syncpt */
3338c2ecf20Sopenharmony_ci			if (job->timeout)
3348c2ecf20Sopenharmony_ci				cdma_start_timer_locked(cdma, job);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci			break;
3378c2ecf20Sopenharmony_ci		}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci		/* Cancel timeout, when a buffer completes */
3408c2ecf20Sopenharmony_ci		if (cdma->timeout.client)
3418c2ecf20Sopenharmony_ci			stop_cdma_timer_locked(cdma);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci		/* Unpin the memory */
3448c2ecf20Sopenharmony_ci		host1x_job_unpin(job);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		/* Pop push buffer slots */
3478c2ecf20Sopenharmony_ci		if (job->num_slots) {
3488c2ecf20Sopenharmony_ci			struct push_buffer *pb = &cdma->push_buffer;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci			host1x_pushbuffer_pop(pb, job->num_slots);
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci			if (cdma->event == CDMA_EVENT_PUSH_BUFFER_SPACE)
3538c2ecf20Sopenharmony_ci				signal = true;
3548c2ecf20Sopenharmony_ci		}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci		list_del(&job->list);
3578c2ecf20Sopenharmony_ci		host1x_job_put(job);
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (cdma->event == CDMA_EVENT_SYNC_QUEUE_EMPTY &&
3618c2ecf20Sopenharmony_ci	    list_empty(&cdma->sync_queue))
3628c2ecf20Sopenharmony_ci		signal = true;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	if (signal) {
3658c2ecf20Sopenharmony_ci		cdma->event = CDMA_EVENT_NONE;
3668c2ecf20Sopenharmony_ci		complete(&cdma->complete);
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_civoid host1x_cdma_update_sync_queue(struct host1x_cdma *cdma,
3718c2ecf20Sopenharmony_ci				   struct device *dev)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct host1x *host1x = cdma_to_host1x(cdma);
3748c2ecf20Sopenharmony_ci	u32 restart_addr, syncpt_incrs, syncpt_val;
3758c2ecf20Sopenharmony_ci	struct host1x_job *job, *next_job = NULL;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	syncpt_val = host1x_syncpt_load(cdma->timeout.syncpt);
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: starting cleanup (thresh %d)\n",
3808c2ecf20Sopenharmony_ci		__func__, syncpt_val);
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	/*
3838c2ecf20Sopenharmony_ci	 * Move the sync_queue read pointer to the first entry that hasn't
3848c2ecf20Sopenharmony_ci	 * completed based on the current HW syncpt value. It's likely there
3858c2ecf20Sopenharmony_ci	 * won't be any (i.e. we're still at the head), but covers the case
3868c2ecf20Sopenharmony_ci	 * where a syncpt incr happens just prior/during the teardown.
3878c2ecf20Sopenharmony_ci	 */
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: skip completed buffers still in sync_queue\n",
3908c2ecf20Sopenharmony_ci		__func__);
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	list_for_each_entry(job, &cdma->sync_queue, list) {
3938c2ecf20Sopenharmony_ci		if (syncpt_val < job->syncpt_end) {
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci			if (!list_is_last(&job->list, &cdma->sync_queue))
3968c2ecf20Sopenharmony_ci				next_job = list_next_entry(job, list);
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci			goto syncpt_incr;
3998c2ecf20Sopenharmony_ci		}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci		host1x_job_dump(dev, job);
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	/* all jobs have been completed */
4058c2ecf20Sopenharmony_ci	job = NULL;
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cisyncpt_incr:
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/*
4108c2ecf20Sopenharmony_ci	 * Increment with CPU the remaining syncpts of a partially executed job.
4118c2ecf20Sopenharmony_ci	 *
4128c2ecf20Sopenharmony_ci	 * CDMA will continue execution starting with the next job or will get
4138c2ecf20Sopenharmony_ci	 * into idle state.
4148c2ecf20Sopenharmony_ci	 */
4158c2ecf20Sopenharmony_ci	if (next_job)
4168c2ecf20Sopenharmony_ci		restart_addr = next_job->first_get;
4178c2ecf20Sopenharmony_ci	else
4188c2ecf20Sopenharmony_ci		restart_addr = cdma->last_pos;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	/* do CPU increments for the remaining syncpts */
4218c2ecf20Sopenharmony_ci	if (job) {
4228c2ecf20Sopenharmony_ci		dev_dbg(dev, "%s: perform CPU incr on pending buffers\n",
4238c2ecf20Sopenharmony_ci			__func__);
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci		/* won't need a timeout when replayed */
4268c2ecf20Sopenharmony_ci		job->timeout = 0;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci		syncpt_incrs = job->syncpt_end - syncpt_val;
4298c2ecf20Sopenharmony_ci		dev_dbg(dev, "%s: CPU incr (%d)\n", __func__, syncpt_incrs);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci		host1x_job_dump(dev, job);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci		/* safe to use CPU to incr syncpts */
4348c2ecf20Sopenharmony_ci		host1x_hw_cdma_timeout_cpu_incr(host1x, cdma, job->first_get,
4358c2ecf20Sopenharmony_ci						syncpt_incrs, job->syncpt_end,
4368c2ecf20Sopenharmony_ci						job->num_slots);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci		dev_dbg(dev, "%s: finished sync_queue modification\n",
4398c2ecf20Sopenharmony_ci			__func__);
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	/* roll back DMAGET and start up channel again */
4438c2ecf20Sopenharmony_ci	host1x_hw_cdma_resume(host1x, cdma, restart_addr);
4448c2ecf20Sopenharmony_ci}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci/*
4478c2ecf20Sopenharmony_ci * Create a cdma
4488c2ecf20Sopenharmony_ci */
4498c2ecf20Sopenharmony_ciint host1x_cdma_init(struct host1x_cdma *cdma)
4508c2ecf20Sopenharmony_ci{
4518c2ecf20Sopenharmony_ci	int err;
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_ci	mutex_init(&cdma->lock);
4548c2ecf20Sopenharmony_ci	init_completion(&cdma->complete);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&cdma->sync_queue);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci	cdma->event = CDMA_EVENT_NONE;
4598c2ecf20Sopenharmony_ci	cdma->running = false;
4608c2ecf20Sopenharmony_ci	cdma->torndown = false;
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	err = host1x_pushbuffer_init(&cdma->push_buffer);
4638c2ecf20Sopenharmony_ci	if (err)
4648c2ecf20Sopenharmony_ci		return err;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	return 0;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci/*
4708c2ecf20Sopenharmony_ci * Destroy a cdma
4718c2ecf20Sopenharmony_ci */
4728c2ecf20Sopenharmony_ciint host1x_cdma_deinit(struct host1x_cdma *cdma)
4738c2ecf20Sopenharmony_ci{
4748c2ecf20Sopenharmony_ci	struct push_buffer *pb = &cdma->push_buffer;
4758c2ecf20Sopenharmony_ci	struct host1x *host1x = cdma_to_host1x(cdma);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	if (cdma->running) {
4788c2ecf20Sopenharmony_ci		pr_warn("%s: CDMA still running\n", __func__);
4798c2ecf20Sopenharmony_ci		return -EBUSY;
4808c2ecf20Sopenharmony_ci	}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	host1x_pushbuffer_destroy(pb);
4838c2ecf20Sopenharmony_ci	host1x_hw_cdma_timeout_destroy(host1x, cdma);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	return 0;
4868c2ecf20Sopenharmony_ci}
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci/*
4898c2ecf20Sopenharmony_ci * Begin a cdma submit
4908c2ecf20Sopenharmony_ci */
4918c2ecf20Sopenharmony_ciint host1x_cdma_begin(struct host1x_cdma *cdma, struct host1x_job *job)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	struct host1x *host1x = cdma_to_host1x(cdma);
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	mutex_lock(&cdma->lock);
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (job->timeout) {
4988c2ecf20Sopenharmony_ci		/* init state on first submit with timeout value */
4998c2ecf20Sopenharmony_ci		if (!cdma->timeout.initialized) {
5008c2ecf20Sopenharmony_ci			int err;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci			err = host1x_hw_cdma_timeout_init(host1x, cdma,
5038c2ecf20Sopenharmony_ci							  job->syncpt_id);
5048c2ecf20Sopenharmony_ci			if (err) {
5058c2ecf20Sopenharmony_ci				mutex_unlock(&cdma->lock);
5068c2ecf20Sopenharmony_ci				return err;
5078c2ecf20Sopenharmony_ci			}
5088c2ecf20Sopenharmony_ci		}
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	if (!cdma->running)
5128c2ecf20Sopenharmony_ci		host1x_hw_cdma_start(host1x, cdma);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	cdma->slots_free = 0;
5158c2ecf20Sopenharmony_ci	cdma->slots_used = 0;
5168c2ecf20Sopenharmony_ci	cdma->first_get = cdma->push_buffer.pos;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	trace_host1x_cdma_begin(dev_name(job->channel->dev));
5198c2ecf20Sopenharmony_ci	return 0;
5208c2ecf20Sopenharmony_ci}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci/*
5238c2ecf20Sopenharmony_ci * Push two words into a push buffer slot
5248c2ecf20Sopenharmony_ci * Blocks as necessary if the push buffer is full.
5258c2ecf20Sopenharmony_ci */
5268c2ecf20Sopenharmony_civoid host1x_cdma_push(struct host1x_cdma *cdma, u32 op1, u32 op2)
5278c2ecf20Sopenharmony_ci{
5288c2ecf20Sopenharmony_ci	struct host1x *host1x = cdma_to_host1x(cdma);
5298c2ecf20Sopenharmony_ci	struct push_buffer *pb = &cdma->push_buffer;
5308c2ecf20Sopenharmony_ci	u32 slots_free = cdma->slots_free;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	if (host1x_debug_trace_cmdbuf)
5338c2ecf20Sopenharmony_ci		trace_host1x_cdma_push(dev_name(cdma_to_channel(cdma)->dev),
5348c2ecf20Sopenharmony_ci				       op1, op2);
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	if (slots_free == 0) {
5378c2ecf20Sopenharmony_ci		host1x_hw_cdma_flush(host1x, cdma);
5388c2ecf20Sopenharmony_ci		slots_free = host1x_cdma_wait_locked(cdma,
5398c2ecf20Sopenharmony_ci						CDMA_EVENT_PUSH_BUFFER_SPACE);
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	cdma->slots_free = slots_free - 1;
5438c2ecf20Sopenharmony_ci	cdma->slots_used++;
5448c2ecf20Sopenharmony_ci	host1x_pushbuffer_push(pb, op1, op2);
5458c2ecf20Sopenharmony_ci}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci/*
5488c2ecf20Sopenharmony_ci * Push four words into two consecutive push buffer slots. Note that extra
5498c2ecf20Sopenharmony_ci * care needs to be taken not to split the two slots across the end of the
5508c2ecf20Sopenharmony_ci * push buffer. Otherwise the RESTART opcode at the end of the push buffer
5518c2ecf20Sopenharmony_ci * that ensures processing will restart at the beginning will break up the
5528c2ecf20Sopenharmony_ci * four words.
5538c2ecf20Sopenharmony_ci *
5548c2ecf20Sopenharmony_ci * Blocks as necessary if the push buffer is full.
5558c2ecf20Sopenharmony_ci */
5568c2ecf20Sopenharmony_civoid host1x_cdma_push_wide(struct host1x_cdma *cdma, u32 op1, u32 op2,
5578c2ecf20Sopenharmony_ci			   u32 op3, u32 op4)
5588c2ecf20Sopenharmony_ci{
5598c2ecf20Sopenharmony_ci	struct host1x_channel *channel = cdma_to_channel(cdma);
5608c2ecf20Sopenharmony_ci	struct host1x *host1x = cdma_to_host1x(cdma);
5618c2ecf20Sopenharmony_ci	struct push_buffer *pb = &cdma->push_buffer;
5628c2ecf20Sopenharmony_ci	unsigned int needed = 2, extra = 0, i;
5638c2ecf20Sopenharmony_ci	unsigned int space = cdma->slots_free;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	if (host1x_debug_trace_cmdbuf)
5668c2ecf20Sopenharmony_ci		trace_host1x_cdma_push_wide(dev_name(channel->dev), op1, op2,
5678c2ecf20Sopenharmony_ci					    op3, op4);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	/* compute number of extra slots needed for padding */
5708c2ecf20Sopenharmony_ci	if (pb->pos + 16 > pb->size) {
5718c2ecf20Sopenharmony_ci		extra = (pb->size - pb->pos) / 8;
5728c2ecf20Sopenharmony_ci		needed += extra;
5738c2ecf20Sopenharmony_ci	}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	host1x_cdma_wait_pushbuffer_space(host1x, cdma, needed);
5768c2ecf20Sopenharmony_ci	space = host1x_pushbuffer_space(pb);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	cdma->slots_free = space - needed;
5798c2ecf20Sopenharmony_ci	cdma->slots_used += needed;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	/*
5828c2ecf20Sopenharmony_ci	 * Note that we rely on the fact that this is only used to submit wide
5838c2ecf20Sopenharmony_ci	 * gather opcodes, which consist of 3 words, and they are padded with
5848c2ecf20Sopenharmony_ci	 * a NOP to avoid having to deal with fractional slots (a slot always
5858c2ecf20Sopenharmony_ci	 * represents 2 words). The fourth opcode passed to this function will
5868c2ecf20Sopenharmony_ci	 * therefore always be a NOP.
5878c2ecf20Sopenharmony_ci	 *
5888c2ecf20Sopenharmony_ci	 * This works around a slight ambiguity when it comes to opcodes. For
5898c2ecf20Sopenharmony_ci	 * all current host1x incarnations the NOP opcode uses the exact same
5908c2ecf20Sopenharmony_ci	 * encoding (0x20000000), so we could hard-code the value here, but a
5918c2ecf20Sopenharmony_ci	 * new incarnation may change it and break that assumption.
5928c2ecf20Sopenharmony_ci	 */
5938c2ecf20Sopenharmony_ci	for (i = 0; i < extra; i++)
5948c2ecf20Sopenharmony_ci		host1x_pushbuffer_push(pb, op4, op4);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	host1x_pushbuffer_push(pb, op1, op2);
5978c2ecf20Sopenharmony_ci	host1x_pushbuffer_push(pb, op3, op4);
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci/*
6018c2ecf20Sopenharmony_ci * End a cdma submit
6028c2ecf20Sopenharmony_ci * Kick off DMA, add job to the sync queue, and a number of slots to be freed
6038c2ecf20Sopenharmony_ci * from the pushbuffer. The handles for a submit must all be pinned at the same
6048c2ecf20Sopenharmony_ci * time, but they can be unpinned in smaller chunks.
6058c2ecf20Sopenharmony_ci */
6068c2ecf20Sopenharmony_civoid host1x_cdma_end(struct host1x_cdma *cdma,
6078c2ecf20Sopenharmony_ci		     struct host1x_job *job)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	struct host1x *host1x = cdma_to_host1x(cdma);
6108c2ecf20Sopenharmony_ci	bool idle = list_empty(&cdma->sync_queue);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	host1x_hw_cdma_flush(host1x, cdma);
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	job->first_get = cdma->first_get;
6158c2ecf20Sopenharmony_ci	job->num_slots = cdma->slots_used;
6168c2ecf20Sopenharmony_ci	host1x_job_get(job);
6178c2ecf20Sopenharmony_ci	list_add_tail(&job->list, &cdma->sync_queue);
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	/* start timer on idle -> active transitions */
6208c2ecf20Sopenharmony_ci	if (job->timeout && idle)
6218c2ecf20Sopenharmony_ci		cdma_start_timer_locked(cdma, job);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	trace_host1x_cdma_end(dev_name(job->channel->dev));
6248c2ecf20Sopenharmony_ci	mutex_unlock(&cdma->lock);
6258c2ecf20Sopenharmony_ci}
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci/*
6288c2ecf20Sopenharmony_ci * Update cdma state according to current sync point values
6298c2ecf20Sopenharmony_ci */
6308c2ecf20Sopenharmony_civoid host1x_cdma_update(struct host1x_cdma *cdma)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	mutex_lock(&cdma->lock);
6338c2ecf20Sopenharmony_ci	update_cdma_locked(cdma);
6348c2ecf20Sopenharmony_ci	mutex_unlock(&cdma->lock);
6358c2ecf20Sopenharmony_ci}
636