diff options
Diffstat (limited to 'gxp-vd.h')
-rw-r--r-- | gxp-vd.h | 169 |
1 files changed, 136 insertions, 33 deletions
@@ -2,8 +2,9 @@ /* * GXP virtual device manager. * - * Copyright (C) 2021 Google LLC + * Copyright (C) 2021-2022 Google LLC */ + #ifndef __GXP_VD_H__ #define __GXP_VD_H__ @@ -11,6 +12,7 @@ #include <linux/list.h> #include <linux/rbtree.h> #include <linux/rwsem.h> +#include <linux/scatterlist.h> #include <linux/spinlock.h> #include <linux/types.h> #include <linux/wait.h> @@ -18,9 +20,17 @@ #include "gxp-internal.h" #include "gxp-mapping.h" +/* TODO(b/259192112): set to 8 once the runtime has added the credit limit. */ +#define GXP_COMMAND_CREDIT_PER_VD 256 + +/* A special client ID for secure workloads pre-agreed with MCU firmware. */ +#define SECURE_CLIENT_ID (3 << 10) + struct mailbox_resp_queue { - /* Queue of `struct gxp_async_response`s */ - struct list_head queue; + /* Queue of waiting async responses */ + struct list_head wait_queue; + /* Queue of arrived async responses */ + struct list_head dest_queue; /* Lock protecting access to the `queue` */ spinlock_t lock; /* Waitqueue to wait on if the queue is empty */ @@ -28,22 +38,23 @@ struct mailbox_resp_queue { }; enum gxp_virtual_device_state { - GXP_VD_OFF = 0, - GXP_VD_RUNNING = 1, - GXP_VD_SUSPENDED = 2, + GXP_VD_OFF, + GXP_VD_READY, + GXP_VD_RUNNING, + GXP_VD_SUSPENDED, /* * 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, + GXP_VD_UNAVAILABLE, }; struct gxp_virtual_device { struct gxp_dev *gxp; uint num_cores; void *fw_app; - struct iommu_domain **core_domains; + struct gxp_iommu_domain *domain; struct mailbox_resp_queue *mailbox_resp_queues; struct rb_root mappings_root; struct rw_semaphore mappings_semaphore; @@ -55,6 +66,46 @@ struct gxp_virtual_device { * process. */ u64 blk_switch_count_when_suspended; + /* + * @domain of each virtual device will map a slice of shared buffer. It stores which index + * of slice is used by this VD. + */ + int slice_index; + /* + * The SG table that holds the firmware data region. + */ + struct sg_table *fwdata_sgt; + uint core_list; + /* + * The ID of DSP client. -1 if it is not allocated. + * This is allocated by the DSP kernel driver, but will be set to this variable only when + * the client of this vd acquires the block wakelock successfully. (i.e, after the kernel + * driver allocates a virtual mailbox with the firmware side successfully by sending the + * `allocate_vmbox` KCI command.) + */ + int client_id; + /* + * The ID of TPU client. -1 if it is not allocated. + * This ID will be fetched from the TPU kernel driver. + */ + int tpu_client_id; + /* + * Protects credit. Use a spin lock because the critical section of + * using @credit is pretty small. + */ + spinlock_t credit_lock; + /* + * Credits for sending mailbox commands. It's initialized as + * GXP_COMMAND_CREDIT_PER_VD. The value is decreased on sending + * mailbox commands; increased on receiving mailbox responses. + * Mailbox command requests are rejected when this value reaches 0. + * + * Only used in MCU mode. + */ + uint credit; + /* Whether it's the first time allocating a VMBox for this VD. */ + bool first_open; + bool is_secure; }; /* @@ -66,7 +117,7 @@ struct gxp_virtual_device { * 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); +void gxp_vd_init(struct gxp_dev *gxp); /* * Tears down the device management subsystem. @@ -79,38 +130,54 @@ void gxp_vd_destroy(struct gxp_dev *gxp); * @gxp: The GXP device the virtual device will belong to * @requested_cores: The number of cores the virtual device will have * + * The state of VD is initialized to GXP_VD_OFF. + * + * The caller must have locked gxp->vd_semaphore for writing. + * * 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 + * * -EBUSY - Not enough iommu domains available or insufficient physical + * cores to be assigned to @vd + * * -ENOSPC - There is no more available shared slices */ -struct gxp_virtual_device *gxp_vd_allocate(struct gxp_dev *gxp, u16 requested_cores); +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 * + * The caller must have locked gxp->vd_semaphore for writing. + * * 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 + * gxp_vd_run() - Run a virtual device on physical cores + * @vd: The virtual device to run * - * The caller must have locked gxp->vd_semaphore for writing. + * The state of @vd should be GXP_VD_OFF or GXP_VD_READY before calling this + * function. If this function runs successfully, the state becomes + * GXP_VD_RUNNING. Otherwise, it would be GXP_VD_UNAVAILABLE. + * + * The caller must have locked gxp->vd_semaphore. * * Return: - * * 0 - Success - * * -EBUSY - Insufficient physical cores were free to start @vd + * * 0 - Success + * * -EINVAL - The VD is not in GXP_VD_READY state + * * Otherwise - Errno returned by firmware running */ -int gxp_vd_start(struct gxp_virtual_device *vd); +int gxp_vd_run(struct gxp_virtual_device *vd); /** - * gxp_vd_stop() - Stop a running virtual device and free up physical cores + * gxp_vd_stop() - Stop a running virtual device * @vd: The virtual device to stop * - * The caller must have locked gxp->vd_semaphore for writing. + * The state of @vd will be GXP_VD_OFF. + * + * The caller must have locked gxp->vd_semaphore. */ void gxp_vd_stop(struct gxp_virtual_device *vd); @@ -124,23 +191,11 @@ void gxp_vd_stop(struct gxp_virtual_device *vd); 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. + * Acquires the physical core IDs assigned to the virtual device. * * 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); +uint gxp_vd_phys_core_list(struct gxp_virtual_device *vd); /** * gxp_vd_mapping_store() - Store a mapping in a virtual device's records @@ -211,6 +266,10 @@ struct gxp_mapping *gxp_vd_mapping_search_host(struct gxp_virtual_device *vd, * gxp_vd_suspend() - Suspend a running virtual device * @vd: The virtual device to suspend * + * The state of @vd should be GXP_VD_RUNNING before calling this function. + * If the suspension runs successfully on all cores, the state becomes + * GXP_VD_SUSPENDED. Otherwise, it would be GXP_VD_UNAVAILABLE. + * * The caller must have locked gxp->vd_semaphore for writing. */ void gxp_vd_suspend(struct gxp_virtual_device *vd); @@ -219,6 +278,10 @@ void gxp_vd_suspend(struct gxp_virtual_device *vd); * gxp_vd_resume() - Resume a suspended virtual device * @vd: The virtual device to resume * + * The state of @vd should be GXP_VD_SUSPENDED before calling this function. + * If the resumption runs successfully on all cores, the state becomes + * GXP_VD_RUNNING. Otherwise, it would be GXP_VD_UNAVAILABLE. + * * The caller must have locked gxp->vd_semaphore for writing. * * Return: @@ -227,4 +290,44 @@ void gxp_vd_suspend(struct gxp_virtual_device *vd); */ int gxp_vd_resume(struct gxp_virtual_device *vd); +/** + * gxp_vd_block_ready() - This is called after the block wakelock is acquired. + * Does required setup for serving VD such as attaching its IOMMU domain. + * + * @vd: The virtual device to prepare the resources + * + * The state of @vd should be GXP_VD_OFF before calling this function. + * If this function runs successfully, the state becomes GXP_VD_READY. + * + * Return: + * * 0 - Success + * * -EINVAL - The VD is not in GXP_VD_OFF state + * * Otherwise - Errno returned by IOMMU domain attachment + */ +int gxp_vd_block_ready(struct gxp_virtual_device *vd); + +/** + * gxp_vd_block_unready() - This is called before one or both of the virtual device and block + * wakelock is going to be released. + * + * @vd: The virtual device to release the resources + * + * This function must be called only when the client holds the block wakelock and allocated a + * virtual device. It doesn't have a dependency on the state of @vd, but also doesn't change the + * state. + */ +void gxp_vd_block_unready(struct gxp_virtual_device *vd); + +/* + * Checks whether the virtual device has a positive credit, and use 1 credit when + * yes. + * + * Returns true when there is enough credit, false otherwise. + */ +bool gxp_vd_has_and_use_credit(struct gxp_virtual_device *vd); +/* + * Releases the credit. + */ +void gxp_vd_release_credit(struct gxp_virtual_device *vd); + #endif /* __GXP_VD_H__ */ |