diff options
Diffstat (limited to 'gxp-mailbox.h')
-rw-r--r-- | gxp-mailbox.h | 293 |
1 files changed, 173 insertions, 120 deletions
diff --git a/gxp-mailbox.h b/gxp-mailbox.h index 4bea5d7..cf72fbe 100644 --- a/gxp-mailbox.h +++ b/gxp-mailbox.h @@ -2,7 +2,7 @@ /* * GXP mailbox interface. * - * Copyright (C) 2020 Google LLC + * Copyright (C) 2020-2022 Google LLC */ #ifndef __GXP_MAILBOX_H__ #define __GXP_MAILBOX_H__ @@ -10,7 +10,45 @@ #include <linux/kthread.h> #include "gxp-client.h" +#include "gxp-config.h" /* GXP_USE_LEGACY_MAILBOX */ +#include "gxp-dma.h" #include "gxp-internal.h" +#include "gxp-mailbox-manager.h" + +#if !GXP_USE_LEGACY_MAILBOX +#include <gcip/gcip-kci.h> +#include <gcip/gcip-mailbox.h> +#endif + +/* + * Offset from the host mailbox interface to the device interface that needs to + * be mapped. + */ +#if defined(CONFIG_GXP_IP_ZEBU) || defined(CONFIG_GXP_GEM5) +#define MAILBOX_DEVICE_INTERFACE_OFFSET 0x180000 +#else +#define MAILBOX_DEVICE_INTERFACE_OFFSET 0x10000 +#endif + +#define __wait_event_lock_irq_timeout_exclusive(wq_head, condition, lock, \ + timeout, state) \ + ___wait_event(wq_head, ___wait_cond_timeout(condition), state, 1, \ + timeout, spin_unlock_irq(&lock); \ + __ret = schedule_timeout(__ret); spin_lock_irq(&lock)) + +/* + * wait_event_interruptible_lock_irq_timeout() but set the exclusive flag. + */ +#define wait_event_interruptible_lock_irq_timeout_exclusive( \ + wq_head, condition, lock, timeout) \ + ({ \ + long __ret = timeout; \ + if (!___wait_cond_timeout(condition)) \ + __ret = __wait_event_lock_irq_timeout_exclusive( \ + wq_head, condition, lock, timeout, \ + TASK_INTERRUPTIBLE); \ + __ret; \ + }) /* Command/Response Structures */ @@ -21,86 +59,19 @@ enum gxp_mailbox_command_code { GXP_MBOX_CODE_SUSPEND_REQUEST = 1, }; -/* Basic Buffer descriptor struct for message payloads. */ -struct buffer_descriptor { - /* Address in the device's virtual address space. */ - u64 address; - /* Size in bytes. */ - u32 size; - /* Flags can be used to indicate message type, etc. */ - u32 flags; -}; - -/* Format used for mailbox command queues. */ -struct gxp_command { - /* Sequence number. Should match the corresponding response. */ - u64 seq; +enum gxp_mailbox_type { /* - * Identifies the type of command. - * Should be a value from `gxp_mailbox_command_code` + * Mailbox will utilize `gcip-mailbox.h` internally. + * (Note: On `GXP_USE_LEGACY_MAILBOX`, it utilizes `gxp-mailbox-impl.h` + * instead.) + * Mostly will be used for handling user commands. */ - u16 code; + GXP_MBOX_TYPE_GENERAL = 0, /* - * Priority level from 0 to 99, with 0 being the highest. Pending - * commands with higher priorities will be executed before lower - * priority ones. + * Mailbox will utilize `gcip-kci.h` internally. + * Will be used for handling kernel commands. */ - u8 priority; - /* - * Insert spaces to make padding explicit. This does not affect - * alignment. - */ - u8 reserved[5]; - /* Struct describing the buffer containing the message payload */ - struct buffer_descriptor buffer_descriptor; -}; - -/* Format used for mailbox response queues from kernel. */ -struct gxp_response { - /* Sequence number. Should match the corresponding command. */ - u64 seq; - /* The status code. Either SUCCESS or an error. */ - u16 status; - /* Padding. */ - u16 reserved; - /* Return value, dependent on the command this responds to. */ - u32 retval; -}; - -/* - * Wrapper struct for responses consumed by a thread other than the one which - * sent the command. - */ -struct gxp_async_response { - struct list_head list_entry; - struct gxp_response resp; - struct delayed_work timeout_work; - /* - * If this response times out, this pointer to the owning mailbox is - * needed to delete this response from the list of pending responses. - */ - struct gxp_mailbox *mailbox; - /* Queue to add the response to once it is complete or timed out */ - struct list_head *dest_queue; - /* - * The lock that protects queue pointed to by `dest_queue`. - * The mailbox code also uses this lock to protect changes to the - * `dest_queue` pointer itself when processing this response. - */ - spinlock_t *dest_queue_lock; - /* Queue of clients to notify when this response is processed */ - wait_queue_head_t *dest_queue_waitq; - /* Specified power state vote during the command execution */ - uint gxp_power_state; - /* Specified memory power state vote during the command execution */ - uint memory_power_state; - /* - * Specified whether the power state vote is requested with low - * frequency CLKMUX flag. - */ - bool requested_low_clkmux; - /* gxp_eventfd to signal when the response completes. May be NULL */ - struct gxp_eventfd *eventfd; + GXP_MBOX_TYPE_KCI = 1, }; enum gxp_response_status { @@ -109,12 +80,6 @@ enum gxp_response_status { GXP_RESP_CANCELLED = 2, }; -struct gxp_mailbox_wait_list { - struct list_head list; - struct gxp_response *resp; - bool is_async; -}; - /* Mailbox Structures */ struct gxp_mailbox_descriptor { u64 cmd_queue_device_addr; @@ -123,6 +88,72 @@ struct gxp_mailbox_descriptor { u32 resp_queue_size; }; +struct gxp_mailbox; + +/* + * Defines the callback functions which are used by the mailbox. + */ +struct gxp_mailbox_ops { + /* + * Allocates resources such as cmd_queue and resp_queue which are used by the mailbox. + * This callback will be called by the `gxp_mailbox_alloc` internally. + * Following variables should be set in this callback. + * - @mailbox->cmd_queue : the pointer of the command queue. + * - @mailbox->cmd_queue_size : the size of @mailbox->cmd_queue. (the maximum number of + * command elements.) + * - @mailbox->cmd_queue_tail : the initial value of the tail of command queue. + * - @mailbox->resp_queue : the pointer of the response queue. + * - @mailbox->resp_queue_size : the size of @mailbox->resp_queue. (the maximum number of + * response elements.) + * - @mailbox->resp_queue_head : the initial value of the head of response queue. + * - @mailbox->descriptor : the pointer of the `strunct gxp_mailbox_descriptor` + * instance. + * - @mailbox + * ->descriptor_device_addr : the device address of @mailbox->descriptor. + * - @mailbox->descriptor + * ->cmd_queue_device_addr : the device address of @mailbox->cmd_queue. + * - @mailbox->descriptor + * ->resp_queue_device_addr : the device address of @mailbox->resp_queue. + * - @mailbox->descriptor + * ->cmd_queue_size : the size of @mailbox->cmd_queue. + * - @mailbox->descriptor + * ->resp_queue_size : the size of @mailbox->resp_queue. + * Context: normal. + */ + int (*allocate_resources)(struct gxp_mailbox *mailbox, + struct gxp_virtual_device *vd, + uint virt_core); + /* + * Releases resources which are allocated by `allocate_resources`. + * This callback will be called by the `gxp_mailbox_release` internally. + * Context: normal. + */ + void (*release_resources)(struct gxp_mailbox *mailbox, + struct gxp_virtual_device *vd, + uint virt_core); +#if !GXP_USE_LEGACY_MAILBOX + /* + * Operators which has dependency on the GCIP according to the type of mailbox. + * - GXP_MBOX_TYPE_GENERAL: @gcip_ops.mbx must be defined. + * - GXP_MBOX_TYPE_KCI: @gcip_ops.kci must be defined. + */ + union { + const struct gcip_mailbox_ops *mbx; + const struct gcip_kci_ops *kci; + } gcip_ops; +#endif +}; + +struct gxp_mailbox_args { + enum gxp_mailbox_type type; + struct gxp_mailbox_ops *ops; + u64 queue_wrap_bit; + u32 cmd_elem_size; + u32 resp_elem_size; + bool ignore_seq_order; + void *data; +}; + #define GXP_MAILBOX_INT_BIT_COUNT 16 struct gxp_mailbox { @@ -140,42 +171,53 @@ struct gxp_mailbox { /* Protects to_host_poll_task while it holds a sync barrier */ struct mutex polling_lock; - u64 cur_seq; + u64 queue_wrap_bit; /* warp bit for both cmd and resp queue */ + u32 cmd_elem_size; /* size of element of cmd queue */ + struct gxp_coherent_buf descriptor_buf; struct gxp_mailbox_descriptor *descriptor; - dma_addr_t descriptor_device_addr; - struct gxp_command *cmd_queue; + struct gxp_coherent_buf cmd_queue_buf; u32 cmd_queue_size; /* size of cmd queue */ u32 cmd_queue_tail; /* offset within the cmd queue */ - dma_addr_t cmd_queue_device_addr; /* device address for cmd queue */ struct mutex cmd_queue_lock; /* protects cmd_queue */ - struct gxp_response *resp_queue; + u32 resp_elem_size; /* size of element of resp queue */ + struct gxp_coherent_buf resp_queue_buf; u32 resp_queue_size; /* size of resp queue */ u32 resp_queue_head; /* offset within the resp queue */ - dma_addr_t resp_queue_device_addr; /* device address for resp queue */ struct mutex resp_queue_lock; /* protects resp_queue */ - /* add to this list if a command needs to wait for a response */ - struct list_head wait_list; + /* commands which need to wait for responses will be added to the wait_list */ struct mutex wait_list_lock; /* protects wait_list */ - /* queue for waiting for the wait_list to be consumed */ - wait_queue_head_t wait_list_waitq; /* to create our own realtime worker for handling responses */ struct kthread_worker response_worker; struct task_struct *response_thread; struct kthread_work response_work; -}; -typedef void __iomem *(*get_mailbox_base_t)(struct gxp_dev *gxp, uint index); + enum gxp_mailbox_type type; + struct gxp_mailbox_ops *ops; + void *data; /* private data */ -struct gxp_mailbox_manager { - struct gxp_dev *gxp; - u8 num_cores; - struct gxp_mailbox **mailboxes; - get_mailbox_base_t get_mailbox_csr_base; - get_mailbox_base_t get_mailbox_data_base; + bool ignore_seq_order; /* allow out-of-order responses if true (always false in KCI) */ + +#if GXP_USE_LEGACY_MAILBOX + u64 cur_seq; + /* add to this list if a command needs to wait for a response */ + struct list_head wait_list; + /* queue for waiting for the wait_list to be consumed */ + wait_queue_head_t wait_list_waitq; +#else /* !GXP_USE_LEGACY_MAILBOX */ + /* + * Implementation of the mailbox according to the type. + * - GXP_MBOX_TYPE_GENERAL: @gcip_mbx will be allocated. + * - GXP_MBOX_TYPE_KCI: @gcip_kci will be allocated. + */ + union { + struct gcip_mailbox *gcip_mbx; + struct gcip_kci *gcip_kci; + } mbx_impl; +#endif /* GXP_USE_LEGACY_MAILBOX */ }; /* Mailbox APIs */ @@ -183,40 +225,51 @@ struct gxp_mailbox_manager { extern int gxp_mbx_timeout; #define MAILBOX_TIMEOUT (gxp_mbx_timeout * GXP_TIME_DELAY_FACTOR) -struct gxp_mailbox_manager *gxp_mailbox_create_manager(struct gxp_dev *gxp, - uint num_cores); - /* - * The following functions all require their caller have locked - * gxp->vd_semaphore for reading. + * The following functions are low-level interfaces of the mailbox. The actual work of it will be + * implemented from the high-level interfaces such as DCI, UCI and KCI via the callbacks defined + * above. Therefore, you may not call these functions directly. + * (Except `gxp_mailbox_{register,unregister}_interrupt_handler` functions.) + * + * If the mailbox interacts with virtual cores according to the implementation, the caller must + * have locked gxp->vd_semaphore for reading. */ struct gxp_mailbox *gxp_mailbox_alloc(struct gxp_mailbox_manager *mgr, struct gxp_virtual_device *vd, - uint virt_core, u8 core_id); + uint virt_core, u8 core_id, + const struct gxp_mailbox_args *args); + void gxp_mailbox_release(struct gxp_mailbox_manager *mgr, struct gxp_virtual_device *vd, uint virt_core, struct gxp_mailbox *mailbox); void gxp_mailbox_reset(struct gxp_mailbox *mailbox); -int gxp_mailbox_execute_cmd(struct gxp_mailbox *mailbox, - struct gxp_command *cmd, struct gxp_response *resp); - -int gxp_mailbox_execute_cmd_async(struct gxp_mailbox *mailbox, - struct gxp_command *cmd, - struct list_head *resp_queue, - spinlock_t *queue_lock, - wait_queue_head_t *queue_waitq, - uint gxp_power_state, uint memory_power_state, - bool requested_low_clkmux, - struct gxp_eventfd *eventfd); - int gxp_mailbox_register_interrupt_handler(struct gxp_mailbox *mailbox, u32 int_bit, struct work_struct *handler); int gxp_mailbox_unregister_interrupt_handler(struct gxp_mailbox *mailbox, - u32 int_bit); + u32 int_bit); + +#if !GXP_USE_LEGACY_MAILBOX +/* + * Executes command synchronously. If @resp is not NULL, the response will be returned to it. + * See the `gcip_mailbox_send_cmd` of `gcip-mailbox.h` or `gcip_kci_send_cmd` of `gcip-kci.h` + * for detail. + */ +int gxp_mailbox_send_cmd(struct gxp_mailbox *mailbox, void *cmd, void *resp); + +/* + * Executes command asynchronously. The response will be written to @resp. + * See the `gcip_mailbox_put_cmd` function of `gcip-mailbox.h` for detail. + * + * Note: KCI doesn't support asynchronous requests. + */ +struct gcip_mailbox_resp_awaiter * +gxp_mailbox_put_cmd(struct gxp_mailbox *mailbox, void *cmd, void *resp, + void *data); +#endif /* !GXP_USE_LEGACY_MAILBOX */ #endif /* __GXP_MAILBOX_H__ */ |