blob: feab79f7313eea76cc062b988dbedb27e72a88ad [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0 */
/*
* GXP virtual device manager.
*
* Copyright (C) 2021 Google LLC
*/
#ifndef __GXP_VD_H__
#define __GXP_VD_H__
#include <linux/iommu.h>
#include <linux/list.h>
#include <linux/rbtree.h>
#include <linux/rwsem.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/wait.h>
#include "gxp-internal.h"
#include "gxp-mapping.h"
struct mailbox_resp_queue {
/* Queue of `struct gxp_async_response`s */
struct list_head queue;
/* Lock protecting access to the `queue` */
spinlock_t lock;
/* Waitqueue to wait on if the queue is empty */
wait_queue_head_t waitq;
};
enum gxp_virtual_device_state {
GXP_VD_OFF = 0,
GXP_VD_RUNNING = 1,
GXP_VD_SUSPENDED = 2,
/*
* If the virtual device is in the unavailable state, it won't be changed
* back no matter what we do.
* Note: this state will only be set on suspend/resume failure.
*/
GXP_VD_UNAVAILABLE = 3,
};
struct gxp_virtual_device {
struct gxp_dev *gxp;
uint num_cores;
void *fw_app;
struct iommu_domain **core_domains;
struct mailbox_resp_queue *mailbox_resp_queues;
struct rb_root mappings_root;
struct rw_semaphore mappings_semaphore;
enum gxp_virtual_device_state state;
/*
* Record the gxp->power_mgr->blk_switch_count when the vd was
* suspended. Use this information to know whether the block has been
* restarted and therefore we need to re-program CSRs in the resume
* process.
*/
u64 blk_switch_count_when_suspended;
};
/*
* TODO(b/193180931) cleanup the relationship between the internal GXP modules.
* For example, whether or not gxp_vd owns the gxp_fw module, and if so, if
* other modules are expected to access the gxp_fw directly or only via gxp_vd.
*/
/*
* Initializes the device management subsystem and allocates resources for it.
* This is expected to be called once per driver lifecycle.
*/
int gxp_vd_init(struct gxp_dev *gxp);
/*
* Tears down the device management subsystem.
* This is expected to be called once per driver lifecycle.
*/
void gxp_vd_destroy(struct gxp_dev *gxp);
/**
* gxp_vd_allocate() - Allocate and initialize a struct gxp_virtual_device
* @gxp: The GXP device the virtual device will belong to
* @requested_cores: The number of cores the virtual device will have
*
* Return: The virtual address of the virtual device or an ERR_PTR on failure
* * -EINVAL - The number of requested cores was invalid
* * -ENOMEM - Unable to allocate the virtual device
* * -EBUSY - Not enough iommu domains available
*/
struct gxp_virtual_device *gxp_vd_allocate(struct gxp_dev *gxp, u16 requested_cores);
/**
* gxp_vd_release() - Cleanup and free a struct gxp_virtual_device
* @vd: The virtual device to be released
*
* A virtual device must be stopped before it can be released.
*/
void gxp_vd_release(struct gxp_virtual_device *vd);
/**
* gxp_vd_start() - Run a virtual device on physical cores
* @vd: The virtual device to start
*
* The caller must have locked gxp->vd_semaphore for writing.
*
* Return:
* * 0 - Success
* * -EBUSY - Insufficient physical cores were free to start @vd
*/
int gxp_vd_start(struct gxp_virtual_device *vd);
/**
* gxp_vd_stop() - Stop a running virtual device and free up physical cores
* @vd: The virtual device to stop
*
* The caller must have locked gxp->vd_semaphore for writing.
*/
void gxp_vd_stop(struct gxp_virtual_device *vd);
/*
* Returns the physical core ID for the specified virtual_core belonging to
* this virtual device or -EINVAL if this virtual core is not running on a
* physical core.
*
* The caller must have locked gxp->vd_semaphore for reading.
*/
int gxp_vd_virt_core_to_phys_core(struct gxp_virtual_device *vd, u16 virt_core);
/*
* Converts a bitfield of virtual core IDs to a bitfield of physical core IDs.
*
* If the virtual list contains any invalid IDs, the entire physical ID list
* will be considered invalid and this function will return 0.
*
* The caller must have locked gxp->vd_semaphore for reading.
*/
uint gxp_vd_virt_core_list_to_phys_core_list(struct gxp_virtual_device *vd,
u16 virt_core_list);
/*
* Returns the virtual core number assigned the phys_core, inside of this
* virtual device or -EINVAL if this core is not part of this virtual device.
*
* The caller must have locked gxp->vd_semaphore for reading.
*/
int gxp_vd_phys_core_to_virt_core(struct gxp_virtual_device *vd, u16 phys_core);
/**
* gxp_vd_mapping_store() - Store a mapping in a virtual device's records
* @vd: The virtual device @map was created for and will be stored in
* @map: The mapping to store
*
* Acquires a reference to @map if it was successfully stored
*
* Return:
* * 0: Success
* * -EINVAL: @map is already stored in @vd's records
*/
int gxp_vd_mapping_store(struct gxp_virtual_device *vd,
struct gxp_mapping *map);
/**
* gxp_vd_mapping_remove() - Remove a mapping from a virtual device's records
* @vd: The VD to remove @map from
* @map: The mapping to remove
*
* Releases a reference to @map if it was successfully removed
*/
void gxp_vd_mapping_remove(struct gxp_virtual_device *vd,
struct gxp_mapping *map);
/**
* gxp_vd_mapping_search() - Obtain a reference to the mapping starting at the
* specified device address
* @vd: The virtual device to search for the mapping
* @device_address: The starting device address of the mapping to find
*
* Obtains a reference to the returned mapping
*
* Return: A pointer to the mapping if found; NULL otherwise
*/
struct gxp_mapping *gxp_vd_mapping_search(struct gxp_virtual_device *vd,
dma_addr_t device_address);
/**
* gxp_vd_mapping_search_in_range() - Obtain a reference to the mapping which
* contains the specified device address
* @vd: The virtual device to search for the mapping
* @device_address: A device address contained in the buffer the mapping to
* find describes.
*
* Obtains a reference to the returned mapping
*
* Return: A pointer to the mapping if found; NULL otherwise
*/
struct gxp_mapping *
gxp_vd_mapping_search_in_range(struct gxp_virtual_device *vd,
dma_addr_t device_address);
/**
* gxp_vd_mapping_search_host() - Obtain a reference to the mapping starting at
* the specified user-space address
* @vd: The virtual device to search for the mapping
* @host_address: The starting user-space address of the mapping to find
*
* Obtains a reference to the returned mapping
*
* Return: A pointer to the mapping if found; NULL otherwise
*/
struct gxp_mapping *gxp_vd_mapping_search_host(struct gxp_virtual_device *vd,
u64 host_address);
/**
* gxp_vd_suspend() - Suspend a running virtual device
* @vd: The virtual device to suspend
*
* The caller must have locked gxp->vd_semaphore for writing.
*/
void gxp_vd_suspend(struct gxp_virtual_device *vd);
/**
* gxp_vd_resume() - Resume a suspended virtual device
* @vd: The virtual device to resume
*
* The caller must have locked gxp->vd_semaphore for writing.
*
* Return:
* * 0 - Success
* * -ETIMEDOUT - Fail to power on physical cores
*/
int gxp_vd_resume(struct gxp_virtual_device *vd);
#endif /* __GXP_VD_H__ */