/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note OR MIT */

/*
 * (C) COPYRIGHT 2024 Arm Limited or its affiliates. All rights reserved.
 */

/*
 * Part of the Mali reference arbiter
 */

#ifndef _MALI_ARBITER_GPU_SCHEDULER_H_
#define _MALI_ARBITER_GPU_SCHEDULER_H_

#include <linux/kernel.h>
#include <mali_arbiter/mali_arbiter.h>
#include "mali_arbiter_internal.h"

struct mali_arb_gpu_subinstance;

/**
 * struct mali_arb_gsi_sched_cb - gsi callback functions invoked from scheduler
 * @gpu_stop: Callback to gsi to send gpu_stop to VM
 *            arb_vm - Pointer to the VM's private data in arbiter
 * @gpu_lost: Callback to gsi to send gpu_lost to VM
 *            arb_vm - Pointer to the VM's private data in arbiter
 * @grant_gpu: Callback to gsi to grant GPU to VM
 *               gsi_ptr - Pointer to gpu-subinstance private data.
 *               arb_vm - Pointer to the VM's private data in arbiter
 *               Returns
 *               0		- successful.
 *               -EFAULT	- slice not assigned.
 *               -EPERM	    - expected interface not available.
 * @unassign_vm: Callback to gsi to un-assign a VM
 *               gsi_ptr - Pointer to gpu-subinstance private data.
 *               Returns
 *               0		- successful.
 *               -EINVAL	- invalid argument.
 *               -ENODEV	- expected interface not available.
 *               -EIO		- failed with hardware fault.
 * @get_assigned_vm: Callback to gsi to get the current assigned VM
 *                   gsi_ptr - Pointer to gpu-subinstance private data.
 *                   vm_id - Pointer to variable to receive the VM ID which
 *                   the GPU or Partition is assigned to or VM_UNASSIGNED
 *                   if no VM has access to it.
 *                   Returns
 *                   0		- successful.
 *                   -EINVAL	- invalid argument.
 *                   -ENODEV	- expected interface not available.
 *                   -EIO	- failed with hardware fault.
 */
struct mali_arb_gsi_sched_cb {
	void (*gpu_stop)(struct mali_arb_priv_data *arb_vm);
	void (*gpu_lost)(struct mali_arb_priv_data *arb_vm);
	int (*grant_gpu)(struct mali_arb_gpu_subinstance *gsi_ptr,
			 struct mali_arb_priv_data *arb_vm);
	int (*unassign_vm)(struct mali_arb_gpu_subinstance *gsi_ptr);
	int (*get_assigned_vm)(struct mali_arb_gpu_subinstance *gsi_ptr, int32_t *vm_id);
};

/**
 * struct mali_arb_gsi_sched_ops - scheduler operations to schedule the VM requests,
 *                    these are invoked from the gpu-subinstance to schedule
 *                    the GPU requests on that gpu-subinstance from the VMs.
 *
 * @sched_get_utilisation: Get gpu-subinstance utilization info
 *                         sched_ptr - Pointer to the Scheduler.
 *                         gsi_busytime - Out-param that will contain the gpu-subinstance busy time.
 *                         gsi_totaltime - Out-param that will contain the gpu-subinstance total
 *                                         time.
 *
 *                         This function provides the GPU busytime and totaltime since last request.
 * @sched_stop_idle_vm: Stop an idle VM.
 *                      sched_ptr - Pointer to the Scheduler.
 *                      arb_vm - VM to be stopped.
 *
 *                      This function sends stop to an idle VM.
 * @sched_get_active_vm: Get the active VM.
 *                       sched_ptr - Pointer to the Scheduler.
 *
 *                       This function returns the VM which is currently assigned to the GSI.
 * @sched_stop:  Stop an active AW on a gpu-subinstance.
 *               sched_ptr - Pointer to the Scheduler.
 *
 *               If the gpu-subinstance has an access window assigned, we need to get into a state
 *               where it is not using the GPU. If the gpu-subinstance state machine is
 *               - GSI_STATE_RUNNING: Then we need to tell the using KBase to stop, and wait for it
 *                                    to stop or a GPU_LOST state.
 *               - GSI_STATE_SINGLE_REQ: Same as GSI_STATE_RUNNING, but there is a only AW
 *                                       requesting GPU time.
 *               - GSI_STATE_STOPPING: The using KBase was already in the process of stopping so we
 *                                     just need to wait for it, or hit a GPU_LOST.
 *               - Anything else: There is no KBase instance using the GPU, so we can just do
 *                                the reassignment.
 *
 *               As the sysfs calls need to be synchronous (so an error code can be returned),
 *               we need to block this thread whilst the request completes.
 * @sched_start: Start the scheduler
 *               sched_ptr - Pointer to the Scheduler.
 *
 *               This function starts scheduling the VM requests on the gpu subinstance.
 * @sched_add_vm:  Add new VM to the scheduler.
 *                 sched_ptr - Pointer to the Scheduler.
 *                 add_vm - Pointer to the requested VM's private data.
 *
 *                 This function adds a new VM request to the existing requests such
 *                 that it can be scheduled by the scheduler.
 * @sched_remove_vm: Remove a VM from the scheduler.
 *                   sched_ptr - Pointer to the Scheduler.
 *                   rem_vm - Pointer to the VM's private data which should be removed.
 *                   req_again - Flag indicates VM has work pending and still wants the GPU,
 *                               if this is set the VM is not deleted from the scheduler.
 *
 *                   This function un-assigns the VM from the GSI if it is currently assigned
 *                   to the GSI and deletes it from the scheduler.
 * @sched_resync_vm: Resync VM after the arbiter restart.
 *                   sched_ptr - Pointer to the Scheduler.
 *                   rem_vm - Pointer to the VM's private data which should be removed.
 *
 *                   This function soft stops the VM when there is an arbiter restart.
 */
struct mali_arb_gsi_sched_ops {
	void (*sched_get_utilisation)(void *sched_ptr, u32 *gsi_busytime, u32 *gsi_totaltime);
	void (*sched_stop_idle_vm)(void *sched_ptr, struct mali_arb_priv_data *arb_vm);
	struct mali_arb_priv_data *(*sched_get_active_vm)(void *sched_ptr);
	void (*sched_stop)(void *sched_ptr);
	void (*sched_start)(void *sched_ptr);
	void (*sched_add_vm)(
		void *sched_ptr, struct mali_arb_priv_data *add_vm
	);
	bool (*sched_remove_vm)(void *sched_ptr, struct mali_arb_priv_data *rem_vm, bool req_again);
	void (*sched_resync_vm)(void *sched_ptr, struct mali_arb_priv_data *rem_vm);
};

/**
 * mali_arbiter_sched_create_rr() - Creates a round robin scheduler object
 * @dev: arbiter device data
 * @gsi_ptr: Pointer to gpu-subinstance private data.
 * @gsi_idx: gpu-subinstance index within resource-group
 * @gsi_cb: gpu-subinstance callbacks
 * @arb_hndl: gpu-arbiter handler for callbacks
 * @sched_ops: scheduler operations to schedule the VM requests
 * @gsi_sched_cb: gsi callback functions invoked from scheduler
 *
 * Return: A new round robin scheduler object, or NULL if the memory could not be allocated
 */
void *mali_arbiter_sched_create_rr(struct device *dev, void *gsi_ptr, u32 gsi_idx,
				   struct mali_arb_gsi_cb gsi_cb, struct mali_arb *arb_hndl,
				   struct mali_arb_gsi_sched_cb gsi_sched_cb,
				   struct mali_arb_gsi_sched_ops *sched_ops);

/**
 * mali_arbiter_sched_destroy_rr() - Destroy a round robin scheduler object
 * @sched_ptr: Round robin scheduler object to be destroyed
 *
 * This function release all the resources associated to a round robin scheduler
 */
void mali_arbiter_sched_destroy_rr(void *sched_ptr);

#endif /* _MALI_ARBITER_GPU_SCHEDULER_H_ */
