/* SPDX-License-Identifier: LicenseRef-NvidiaProprietary */
/* SPDX-FileCopyrightText: Copyright (c) 2016-2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 *
 * NVDLA queue management header
 */

#ifndef __NVHOST_NVDLA_QUEUE_H__
#define __NVHOST_NVDLA_QUEUE_H__

#include <linux/kref.h>

#include "port/nvdla_sync.h"

struct nvdla_queue_task_pool;

/**
 * @brief	Describe a allocated task mem struct
 *
 * kmem_addr	Address for the task kernel memory
 * dma_addr	Physical address of task memory
 * va		Virtual address of the task memory
 * pool_index	Index to the allocated task memory
 *
 * This is keep track of the memory details of the task
 * struct that is being shared between kernel and firmware.
 */
struct nvdla_queue_task_mem_info {
	void *kmem_addr;
	dma_addr_t dma_addr;
	void *va;
	int pool_index;
};
/**
 * @brief		Information needed in a Queue
 *
 * pool			pointer queue pool
 * kref			struct kref for reference count
 * sync_context		NvDLA synchronization context
 * id			Queue id
 * list_lock		mutex for tasks lists control
 * tasklist		Head of tasks list
 * sequence		monotonically incrementing task id per queue
 * task_pool		pointer to struct for task memory pool
 * task_dma_size	dma size used in hardware for a task
 * task_kmem_size	kernel memory size for a task
 * attr			queue attribute associated with the host module
 *
 */
struct nvdla_queue {
	struct nvdla_queue_task_pool *task_pool;
	struct nvdla_queue_pool *pool;
	struct kref kref;
	u32 id;

	/* Host1x resources */
#if IS_ENABLED(CONFIG_TEGRA_NVDLA_CHANNEL)
	struct nvhost_channel *channel;
#endif
	struct platform_device *vm_pdev;
	bool use_channel;
	struct nvdla_sync_context *sync_context;

	size_t task_dma_size;
	size_t task_kmem_size;

	u32 sequence;

	struct mutex attr_lock;
	void *attr;

	struct mutex list_lock;
	struct list_head tasklist;
};

/**
 * @brief	hardware specific queue callbacks
 *
 * dump			dump the task information
 * abort		abort all tasks from a queue
 * submit		submit the given list of tasks to hardware
 * get_task_size	get the dma size needed for the task in hw
 *			and the kernel memory size needed for task.
 * cleanup		cleans expired tasks from the tasklist.
 */
struct nvdla_queue_ops {
	void (*dump)(struct nvdla_queue *queue, struct seq_file *s);
	int (*abort)(struct nvdla_queue *queue);
	int (*submit)(struct nvdla_queue *queue, void *task_arg);
	void (*get_task_size)(size_t *dma_size, size_t *kmem_size);
	int (*set_attribute)(struct nvdla_queue *queue, void *arg);
	void (*cleanup)(struct nvdla_queue *queue);
};

/**
 * @brief	Queue pool data structure to hold queue table
 *
 * pdev			Pointer to the Queue client device
 * ops			Pointer to hardware specific queue ops
 * queues		Queues available for the client
 * queue_lock		Mutex for the bitmap of reserved queues
 * alloc_table		Bitmap of allocated queues
 * max_queue_cnt	Max number queues available for client
 * queue_task_pool	Pointer to the task memory pool for queues.
 *
 */
struct nvdla_queue_pool {
	struct platform_device *pdev;
	struct nvdla_queue_ops *ops;
	struct nvdla_queue *queues;
	struct mutex queue_lock;
	unsigned long alloc_table;
	unsigned int max_queue_cnt;
	void *queue_task_pool;
};

/**
 * @brief	Initialize queue structures
 *
 * This function allocates and initializes queue data structures.
 *
 * @param pdev		Pointer to the Queue client device
 * @param ops		Pointer to device speicific callbacks
 * @param num_queues	Max number queues available for client
 * @return		pointer to queue pool
 *
 */
struct nvdla_queue_pool *nvdla_queue_init(struct platform_device *pdev,
					struct nvdla_queue_ops *ops,
					unsigned int num_queues);

/**
 * @brief	De-initialize queue structures
 *
 * This function free's all queue data structures.
 *
 * @param pool	pointer to queue pool
 * @return	void
 *
 */
void nvdla_queue_deinit(struct nvdla_queue_pool *pool);

/**
 * @brief	Release reference of a queue
 *
 * This function releases reference for a queue.
 *
 * @param queue	Pointer to an allocated queue.
 * @return	void
 *
 */
void nvdla_queue_put(struct nvdla_queue *queue);

/**
 * @brief	Get reference on a queue.
 *
 * This function used to get a reference to an already allocated queue.
 *
 * @param queue	Pointer to an allocated queue.
 * @return	None
 *
 */
void nvdla_queue_get(struct nvdla_queue *queue);

/**
 * @brief	Allocate a queue for client.
 *
 * This function allocates a queue from the pool to client for the user.
 *
 * @param pool		Pointer to a queue pool table
 * @param num_tasks	Max number of tasks per queue
 * @param use_channel	Determines whether the routine allocates a channel for
 *			the queue.
 *
 * @return		Pointer to a queue struct on success
 *			or negative error on failure.
 *
 */
struct nvdla_queue *nvdla_queue_alloc(struct nvdla_queue_pool *pool,
					unsigned int num_tasks,
					bool use_channel);

#ifdef CONFIG_PM
/**
 * @brief		Prepare suspension of all queues.
 *
 * This function is responsible for the following,
 *  - Checks if there are no outstanding tasks.
 *  - Does not attempt to clear or flush the outstanding tasks.
 *
 * @param pool		Pointer to a queue pool table.
 *
 * @return		0,	on successul completion.
 *			-EBUSY,	if there are any outstanding tasks in queue.
 **/
int nvdla_queue_pool_prepare_suspend(struct nvdla_queue_pool *pool);
#endif /* CONFIG_PM */

/**
 * @brief		Abort all active queues
 *
 * @param pool		Pointer to a queue pool table
 */
void nvdla_queue_abort_all(struct nvdla_queue_pool *pool);

/**
 * @brief	Abort tasks within a client queue
 *
 * This function aborts all tasks from the given clinet queue. If there is no
 * active tasks, the function call is no-op.
 * It is expected to be called when an active device fd gets closed.
 *
 * @param queue	Pointer to an allocated queue
 * @return	None
 *
 */
int nvdla_queue_abort(struct nvdla_queue *queue);

/**
 * @brief	submits the given list of tasks to hardware
 *
 * This function submits the given list of tasks to hardware.
 * The submit structure is updated with the fence values as appropriate.
 *
 * @param queue		Pointer to an allocated queue
 * @param submit	Submit the given list of tasks to hardware
 * @return		0 on success or negative error code on failure.
 *
 */
int nvdla_queue_submit(struct nvdla_queue *queue, void *submit);

/**
 * @brief	Get the Task Size needed
 *
 * This function get the needed memory size for the task. This memory is
 * shared memory between kernel and firmware
 *
 * @param queue	Pointer to an allocated queue
 * @return	Size of the task
 *
 */
int nvdla_queue_get_task_size(struct nvdla_queue *queue);

/**
 * @brief	Allocate a memory from task memory pool
 *
 * This function helps to assign a task memory from
 * the preallocated task memory pool. This memory is shared memory between
 * kernel and firmware
 *
 * @queue		Pointer to an allocated queue
 * @task_mem_info	Pointer to nvdla_queue_task_mem_info struct
 *
 * @return	0 on success, otherwise a negative error code is returned
 *
 */
int nvdla_queue_alloc_task_memory(
			struct nvdla_queue *queue,
			struct nvdla_queue_task_mem_info *task_mem_info);

/**
 * @brief	Free the assigned task memory
 *
 * This function helps to unset the assigned task memory
 *
 * @param queue	Pointer to an allocated queue
 * @param index	Index of the assigned task pool memory
 * @return	void
 *
 */
void nvdla_queue_free_task_memory(struct nvdla_queue *queue, int index);

/**
 * @brief	Sets the attribute to the queue
 *
 * This function set the attribute of the queue with the arguments passed
 *
 * @param queue		Pointer to an allocated queue
 * @param arg		The structure which consists of the id and value
 * @return		0 on success or negative error code on failure.
 *
 */
int nvdla_queue_set_attr(struct nvdla_queue *queue, void *arg);

/**
 * @brief		Submit the given command buffer to the device
 *
 * This functions submits the given cmdbuf to a Host1x channel. The
 * submit must perform the given number of syncpoint increments
 * on the engine.
 *
 * @param queue				Pointer to an allocated queue
 * @param cmdbuf			Pointer to a command buffer to submit
 * @param num_cmdbuf_words		Number of words in the command buffer
 * @param num_syncpt_incrs		Number of syncpoint increments the task
 *					issues
 * @param wait_syncpt_ids		Syncpoint ids that should be waited on
 *					Host1x
 * @param wait_syncpoint_thresholds	Syncpoint thresholds for the waits
 * @param task_syncpt_threshold		Pointer to a u32. The variable is
 *					initialized to have the completion
 *					threshold.
 *
 * @return				0 on success or negative error code on
 *					failure.
 *
 */
int nvdla_queue_submit_to_host1x(struct nvdla_queue *queue,
				  u32 *cmdbuf,
				  u32 num_cmdbuf_words,
				  u32 num_syncpt_incrs,
				  u32 *wait_syncpt_ids,
				  u32 *wait_syncpt_thresholds,
				  u32 num_syncpt_waits,
				  u32 *task_syncpt_threshold);

#endif
