| /* SPDX-License-Identifier: GPL-2.0-only */ |
| /* |
| * GXP user command interface. |
| * |
| * Copyright (C) 2022 Google LLC |
| */ |
| |
| #ifndef __GXP_UCI_H__ |
| #define __GXP_UCI_H__ |
| |
| #include <linux/kref.h> |
| #include <linux/kthread.h> |
| |
| #include <gcip/gcip-fence-array.h> |
| #include <gcip/gcip-fence.h> |
| #include <gcip/gcip-mailbox.h> |
| |
| #include "gxp-client.h" |
| #include "gxp-internal.h" |
| #include "gxp-mailbox.h" |
| #include "gxp-vd.h" |
| #include "gxp.h" |
| |
| #define UCI_RESOURCE_ID 0 |
| |
| struct gxp_mcu; |
| |
| /* Command/Response Structures */ |
| |
| /* Size of `gxp_uci_type` should be u8 to match FW */ |
| enum gxp_uci_type { |
| /* The command containing executable runtime command. */ |
| CORE_COMMAND = 0, |
| /* |
| * Empty command that FW will simply respond to this command. |
| * Its purpose is to overcome the limitation of the number of in/out sync fences. |
| * From the perspective of KD, the communication logic with FW should be the same with |
| * RUNTIME_COMMAND. |
| */ |
| NULL_COMMAND = 1, |
| } __packed; |
| |
| struct gxp_uci_wakelock_command_params { |
| /* DVFS operating point of DSP cores */ |
| uint8_t dsp_operating_point; |
| /* DVFS operating point of memory */ |
| uint8_t memory_operating_point; |
| }; |
| |
| struct gxp_uci_core_command_params { |
| /* iova address of the app command */ |
| uint64_t address; |
| /* size of the app command */ |
| uint32_t size; |
| /* number of dsp cores required for this command */ |
| uint8_t num_cores; |
| /* DVFS operating point of DSP cores */ |
| uint8_t dsp_operating_point; |
| /* DVFS operating point of memory */ |
| uint8_t memory_operating_point; |
| }; |
| |
| struct gxp_uci_command { |
| /* sequence number, should match the corresponding response */ |
| uint32_t seq; |
| /* device address of the additional info */ |
| uint32_t additional_info_address; |
| /* unique ID for each client that identifies client VM & security realm */ |
| uint32_t client_id; |
| /* type of the command */ |
| enum gxp_uci_type type; |
| /* reserved field */ |
| uint8_t reserved; |
| /* size of the additional info */ |
| uint16_t additional_info_size; |
| /* All possible command parameters */ |
| union { |
| struct gxp_uci_core_command_params core_command_params; |
| struct gxp_uci_wakelock_command_params wakelock_command_params; |
| uint8_t opaque[48]; |
| }; |
| }; |
| |
| /** |
| * struct gxp_uci_command_work - The callback and work object to carry data for a UCI command. |
| * @cb: The embedded DMA callback. |
| * @node: The list node used to add to the client. |
| * @fence: The fence that the callback is added to. |
| * @client: The client which request the UCI command. |
| * @cmd_seq: The specified sequence number used for the uci command. |
| * @flags: Same as gxp_mailbox_uci_command_ioctl. |
| * @opaque: Same as gxp_mailbox_uci_command_ioctl. |
| * @timeout_ms: Same as gxp_mailbox_uci_command_ioctl. |
| * @in_fences: Same as gxp_mailbox_uci_command_ioctl. |
| * @out_fences: Same as gxp_mailbox_uci_command_ioctl. |
| */ |
| struct gxp_uci_cmd_work { |
| struct dma_fence_cb cb; |
| struct list_head node; |
| struct dma_fence *fence; |
| struct gxp_client *client; |
| u64 cmd_seq; |
| u32 flags; |
| u8 opaque[GXP_UCI_CMD_OPAQUE_SIZE]; |
| u32 timeout_ms; |
| struct gcip_fence_array *in_fences; |
| struct gcip_fence_array *out_fences; |
| }; |
| |
| /* |
| * TODO(b/301608032): This additional_info must be generated by the litebuf once its C compiler |
| * is implemented. Before that we should statiaclly define compatible structures here. |
| * |
| * +----------------------------------------+ <- 0 |
| * | struct gxp_uci_additional_info_header | |
| * +----------------------------------------+ <- root_offset |
| * | | \ |
| * | | | |
| * | struct gxp_uci_additional_info_root | | -> object_size |
| * | | | |
| * | | / |
| * +----------------------------------------+ <- in_fences_offset |
| * | | |
| * | uint16_t in_fences[in_fences_size] | |
| * | | |
| * +----------------------------------------+ <- out_fences_offset |
| * | | |
| * | uint16_t out_fences[out_fences_size] | |
| * | | |
| * +----------------------------------------+ <- runtime_additional_info_offset |
| * | | |
| * | uint8_t runtime_additional_info[ | |
| * | runtime_additional_info_size | |
| * | ] | |
| * | | |
| * +----------------------------------------+ <- additional_info_size |
| */ |
| struct gxp_uci_additional_info_header { |
| /* Unique identifier to differentiate between multiple litebuf schemas. */ |
| uint8_t identifier; |
| /* Unique version within a single schema. */ |
| uint8_t version; |
| /* Reserved for alignment and future use. */ |
| uint8_t reserved[6]; |
| /* Pointer to the root object. */ |
| uint64_t root_offset; |
| } __packed; |
| |
| struct gxp_uci_additional_info_root { |
| /* The total size of this root object in bytes. */ |
| uint32_t object_size; |
| /* The offset of the in_fences vector. */ |
| int32_t in_fences_offset; |
| /* The number of elements in the in_fences vector. */ |
| uint32_t in_fences_size; |
| /* The offset of the out_fences vector. */ |
| int32_t out_fences_offset; |
| /* The number of elements in the out_fences vector. */ |
| uint32_t out_fences_size; |
| /* Runtime specified timeout. */ |
| uint32_t timeout_ms; |
| /* The offset of the runtime defined additional info buffer. */ |
| int32_t runtime_additional_info_offset; |
| /* The size of the runtime defined additional info buffer in bytes. */ |
| uint32_t runtime_additional_info_size; |
| } __packed; |
| |
| struct gxp_uci_additional_info { |
| /* Header. */ |
| struct gxp_uci_additional_info_header header; |
| /* Root. */ |
| struct gxp_uci_additional_info_root root; |
| /* The pointer to in_fences of UCI command ioctl. */ |
| uint16_t *in_fences; |
| /* The pointer to out_fences of UCI command ioctl. */ |
| uint16_t *out_fences; |
| /* The pointer to runtime_additional_info of UCI command ioctl. */ |
| uint8_t *runtime_additional_info; |
| }; |
| |
| struct gxp_uci_response { |
| /* sequence number, should match the corresponding command */ |
| uint64_t seq; |
| /* unique ID for each client that identifies client VM & security realm*/ |
| uint32_t client_id; |
| /* status code that tells the success or error. */ |
| uint16_t code; |
| /* reserved field */ |
| uint8_t reserved[2]; |
| uint8_t opaque[16]; |
| }; |
| |
| /* |
| * Wrapper struct for responses consumed by a thread other than the one which |
| * sent the command. |
| */ |
| struct gxp_uci_async_response { |
| /* |
| * List entry which will be inserted to the waiting queue of the vd. |
| * It will be pushed into the waiting queue when the response is sent. |
| * (i.e, the `gxp_uci_send_command` function is called) |
| * It will be poped when the response is consumed by the vd. |
| */ |
| struct list_head wait_list_entry; |
| /* |
| * List entry which will be inserted to the dest_queue of the vd. |
| * It will be pushed into the dest_queue when the response is arrived or timed out. |
| * It will be poped when the response is consumed by the vd. |
| */ |
| struct list_head dest_list_entry; |
| /* Stores the response. */ |
| struct gxp_uci_response resp; |
| struct gxp_uci *uci; |
| /* Queue where to be removed from once it is complete or timed out. */ |
| struct list_head *wait_queue; |
| /* Queue to add the response to once it is complete or timed out. */ |
| struct list_head *dest_queue; |
| /* |
| * The lock that protects queues pointed to by `dest_queue` and `wait_queue`. |
| * The mailbox code also uses this lock to protect changes to the `wait_queue` pointer |
| * itself when processing this response. |
| */ |
| spinlock_t *queue_lock; |
| /* Queue of clients to notify when this response is processed. */ |
| wait_queue_head_t *dest_queue_waitq; |
| /* gxp_eventfd to signal when the response completes. May be NULL. */ |
| struct gxp_eventfd *eventfd; |
| /* The request was sent from this virtual device. */ |
| struct gxp_virtual_device *vd; |
| /* Handles arrival, timeout of async response. */ |
| struct gcip_mailbox_resp_awaiter *awaiter; |
| /* Status of the response. */ |
| enum gxp_response_status status; |
| /* Additional info buffer. */ |
| struct gxp_mapped_resource additional_info_buf; |
| /* In-fences. */ |
| struct gcip_fence_array *in_fences; |
| /* Out-fences. */ |
| struct gcip_fence_array *out_fences; |
| }; |
| |
| struct gxp_uci_wait_list { |
| struct list_head list; |
| struct gxp_uci_response *resp; |
| bool is_async; |
| }; |
| |
| struct gxp_uci { |
| struct gxp_dev *gxp; |
| struct gxp_mcu *mcu; |
| struct gxp_mailbox *mbx; |
| struct gxp_mapped_resource cmd_queue_mem; |
| struct gxp_mapped_resource resp_queue_mem; |
| struct gxp_mapped_resource descriptor_mem; |
| }; |
| |
| /* UCI APIs */ |
| |
| /** |
| * gxp_uci_init() - API for initializing GXP UCI in MCU, should only be |
| * called while initializing MCU |
| * @mcu: The MCU that UCI communicate with |
| * |
| * Return: |
| * * 0 - Initialization finished successfully |
| * * -ENOMEM - Cannot get memory to finish init. |
| */ |
| int gxp_uci_init(struct gxp_mcu *mcu); |
| |
| /** |
| * gxp_uci_reinit() - Re-initializes the initialized UCI object. |
| * @uci: The UCI to be initialized |
| * |
| * Return: |
| * * 0 - Initialization finished successfully |
| */ |
| int gxp_uci_reinit(struct gxp_uci *uci); |
| |
| /** |
| * gxp_uci_exit() - API for releasing the UCI mailbox of MCU. |
| * @uci: The UCI to be released |
| */ |
| void gxp_uci_exit(struct gxp_uci *uci); |
| |
| /* |
| * gxp_uci_send_command() - API for sending @cmd to MCU firmware, and |
| * registering @resp_queue to put the response in after MCU firmware handle the |
| * command. |
| * |
| * Returns 0 on success, a negative errno on failure. |
| */ |
| int gxp_uci_send_command(struct gxp_uci *uci, struct gxp_virtual_device *vd, |
| struct gxp_uci_command *cmd, |
| struct gxp_uci_additional_info *additional_info, |
| struct gcip_fence_array *in_fences, struct gcip_fence_array *out_fences, |
| struct list_head *wait_queue, struct list_head *resp_queue, |
| spinlock_t *queue_lock, wait_queue_head_t *queue_waitq, |
| struct gxp_eventfd *eventfd, gcip_mailbox_cmd_flags_t flags); |
| |
| /** |
| * gxp_uci_create_and_send_cmd() - Create and put the UCI command into the queue. |
| * @client: The client which request the UCI command. |
| * @cmd_seq: The specified sequence number used for this uci command. |
| * @flags: Same as gxp_mailbox_uci_command_ioctl. |
| * @opaque: Same as gxp_mailbox_uci_command_ioctl. |
| * @timeout_ms: Same as gxp_mailbox_uci_command_ioctl. |
| * @in_fences: Same as gxp_mailbox_uci_command_ioctl. |
| * @out_fences: Same as gxp_mailbox_uci_command_ioctl. |
| * |
| * Following tasks will be done in this function: |
| * 1. Check the client and its virtual device to see if they are still available. |
| * 2. Prepare UCI command object. |
| * 3. Prepare UCI additional info. |
| * 4. Put the UCI command into the queue. |
| * |
| * Return: 0 on success or errno on failure. |
| */ |
| int gxp_uci_create_and_send_cmd(struct gxp_client *client, u64 cmd_seq, u32 flags, const u8 *opaque, |
| u32 timeout_ms, struct gcip_fence_array *in_fences, |
| struct gcip_fence_array *out_fences); |
| |
| /* |
| * gxp_uci_wait_async_response() - API for waiting and fetching a response from |
| * MCU firmware. |
| * |
| * Returns 0 on success, a negative errno on failure. |
| */ |
| int gxp_uci_wait_async_response(struct mailbox_resp_queue *uci_resp_queue, |
| u64 *resp_seq, u16 *error_code, u8 *opaque); |
| |
| /* |
| * gxp_uci_fill_additional_info() - Fills @info according to the passed additional information. |
| * It is expected that the filled @info will be passed to the `gxp_uci_send_command`. |
| */ |
| void gxp_uci_fill_additional_info(struct gxp_uci_additional_info *info, uint16_t *in_fences, |
| uint32_t in_fences_size, uint16_t *out_fences, |
| uint32_t out_fences_size, uint32_t timeout_ms, |
| uint8_t *runtime_additional_info, |
| uint32_t runtime_additional_info_size); |
| |
| /** |
| * gxp_uci_cmd_work_create_and_schedule() - Creates a UCI command work and registers it to the given |
| * DMA fence. |
| * @fence: The DMA fence to add the callback for the UCI work. |
| * @client: The attribute of gxp_uci_cmd_work. |
| * @ibuf: The gxp_mailbox_uci_command_ioctl passed from user. |
| * @cmd_seq: The attribute of gxp_uci_cmd_work. |
| * @in_fences: The fences which will signal @fence. |
| * @out_fences: The fences which will be signaled by @fence. |
| * |
| * This function creates a deferred work which will be scheduled when @fence is signaled and will |
| * call the gxp_uci_create_and_send_cmd function. |
| * |
| * If the given fence is NULL or the fence has already been signaled, skips the register process and |
| * run gxp_uci_create_and_send_cmd() directly. |
| * |
| * The work will be added to the @client->uci_cb_list for tracking if the callback is added to the |
| * fence successfully. |
| * |
| * This function should be called in the ioctl function only, where the gxp_client_destroy() is |
| * guaranteed not to be called simultaneously. |
| * |
| * Return: 0 on success or errno on failure. |
| */ |
| int gxp_uci_cmd_work_create_and_schedule(struct dma_fence *fence, struct gxp_client *client, |
| const struct gxp_mailbox_uci_command_ioctl *ibuf, |
| u64 cmd_seq, struct gcip_fence_array *in_fences, |
| struct gcip_fence_array *out_fences); |
| |
| /** |
| * gxp_uci_work_destroy() - The revert function of gxp_uci_cmd_work_create(). |
| * @uci_work: The target work to be destroyed. |
| */ |
| void gxp_uci_work_destroy(struct gxp_uci_cmd_work *uci_work); |
| |
| #endif /* __GXP_UCI_H__ */ |