123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- /*
- * Android/Easel coprocessor communication hardware access to the PCIe/EP
- * driver on the local side of the link (AP or Easel), used by the common and
- * link-partner-specific code.
- *
- * Copyright 2016 Google Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
- #ifndef _GOOGLE_EASEL_COMM_PRIVATE_H
- #define _GOOGLE_EASEL_COMM_PRIVATE_H
- #include "google-easel-comm-shared.h"
- #include <linux/completion.h>
- #include <linux/list.h>
- #include <linux/miscdevice.h>
- #include <linux/mutex.h>
- #include <linux/spinlock.h>
- #include <linux/types.h>
- /*
- * Message types used to set the general type of processing for the message
- * and in which local data structures the message exists:
- * local: message originated locally with a local message ID, stored in the
- * local message list for the associated Easel service.
- * remote non-reply: message received from remote with a remote message ID,
- * stored in the remote message list, and also appears in the receive
- * message queue until returned by a receiveMessage() call.
- * remote reply: message from remote that is processed as a reply to a local
- * message, does not go into the receiveMessage() queue.
- */
- enum easelcomm_msg_type {
- TYPE_LOCAL = 0, /* local/outgoing */
- TYPE_REMOTE_NONREPLY, /* remote/incoming general */
- TYPE_REMOTE_REPLY, /* remote/incoming reply */
- };
- /*
- * Message metadata specific to DMA transfer handling. Messages with no DMA
- * transfer have default values for these.
- */
- struct easelcomm_dma_xfer_info {
- /*
- * The local MNH driver scatter-gather list, or NULL if discarding.
- * This points to an array of mnh_sg_entry. Content of this is
- * to be used to combine with remote scatter-gather list to be a
- * DMA Linked List.
- */
- void *sg_local;
- /* Size in bytes of the local scatter-gather list, zero if discard */
- uint32_t sg_local_size;
- /*
- * Local data private to the MNH layer associated with the SG list.
- * This points to mnh_sg_list. It marks information of
- * the buffer for DMA transfer, and is used to collect local MNH
- * driver scatter-gather list (sg_local).
- */
- void *sg_local_localdata;
- /*
- * Easel/server keeps the remote scatter-gather list received from the
- * client (in a DMA_SG command) here for processing. The server is in
- * charge of building the DMA Linked List for a multi-block transfer or
- * deciding to use a single-block transfer based on the SG lists.
- */
- void *sg_remote;
- /* Size in bytes of the remote SG list */
- uint32_t sg_remote_size;
- /* Informs server remote SG received from client */
- struct completion sg_remote_ready;
- /*
- * Server determines DMA transfer type (SBLK/MBLK/ABORT) and sends to
- * client to perform (or discard) the transfer. Sent with DMA_XFER
- * command.
- */
- uint32_t xfer_type;
- /*
- * The server's address applicable to the DMA transfer command:
- * The Multi-Block Linked List physical address (in Easel memory) or
- * the Single-Block server-side physical address of the transfer
- * source or destination address).
- */
- uint64_t server_addr;
- /*
- * Informs client the DMA transfer request ready (DMA_XFER command
- * received from server), ready to proceed (or discard).
- */
- struct completion xfer_ready;
- /*
- * Informs server DMA transfer is complete, DMA_DONE command received
- * from client after transfer is complete or aborted. Server can
- * clean up message and DMA data structures and return to caller.
- */
- struct completion xfer_done;
- /*
- * DMA request is being aborted, either the remote sent an abort
- * or locally a service flush or signal was received.
- */
- bool aborting;
- /* DMA transfer error code (-errno) if non-zero */
- int32_t errcode;
- };
- /*
- * Message metadata, one for each local/outgoing and remote/incoming message
- * in progress on the local system. Concurrency protection for all fields is
- * provided through the spinlock for the Easel service for which the message
- * is created.
- */
- struct easelcomm_message_metadata {
- /*
- * Message reference count, > 0 means kernel code is currently
- * executing that holds a pointer to this message (metadata), or a
- * data structure (other than the local/remote message lists)
- * currently points to this message (namely a reply message pointed to
- * by the replied-to message). Zero reference count means the message
- * can be safely removed from the local/remote list and freed (with the
- * service lock held), which may happen outside the normal message
- * lifecycle on a service flush.
- */
- int reference_count;
- /*
- * Set to true when the message is to be freed once the reference count
- * goes to 0.
- */
- bool free_message;
- /*
- * True if message is marked to be flushed, lets DMA handling or
- * reply waiter know to bail and let the message be flushed.
- */
- bool flushing;
- /* what type of message: local, remote reply, remote non-reply */
- enum easelcomm_msg_type msg_type;
- /* local or remote message list linkage */
- struct list_head list;
- /*
- * True if message is in the receiveMessage queue (a remote non-reply
- * not yet picked up by a receiveMessage() call).
- */
- bool queued;
- /* receiveMessage queue list linkage, if message is queued */
- struct list_head rcvq_list;
- /* signals reply message received, if message needs a reply */
- struct completion reply_received;
- /* pointer to reply message metadata once received, if need reply */
- struct easelcomm_message_metadata *reply_metadata;
- /* DMA info, if message includes a DMA transfer */
- struct easelcomm_dma_xfer_info dma_xfer;
- /* points to the Easel message desc and data */
- struct easelcomm_kmsg *msg;
- };
- /* forward declare for service/user state cross-references */
- struct easelcomm_user_state;
- /* Per-Easel-service data. */
- struct easelcomm_service {
- /* service ID (same as easelcom_service array index) */
- unsigned int service_id;
- /* protects access to all mutable fields below and in messages */
- struct mutex lock;
- /* currently registered user */
- struct easelcomm_user_state *user;
- /* true if service is being closed by local */
- bool shutdown_local;
- /* true if service was closed by remote */
- bool shutdown_remote;
- /* next local/outgoing message ID */
- easelcomm_msgid_t next_id;
- /* list of in-progress local/outgoing messages */
- struct list_head local_list;
- /* remote non-reply messages not yet returned by receiveMessage */
- struct list_head receivemsg_queue;
- /* signals new entry added to receivemsg_queue */
- struct completion receivemsg_queue_new;
- /* in-progress remote messages (reply and non-reply) */
- struct list_head remote_list;
- /* flush service complete on remote, ready to resume service */
- struct completion flush_done;
- };
- /*
- * Are we running as AP/client or Easel/server? Most decisions are made
- * at runtime instead of compile time for code prettiness.
- */
- #ifdef CONFIG_GOOGLE_EASEL_AP
- #define easelcomm_is_client() (true)
- #define easelcomm_is_server() (false)
- #else
- #define easelcomm_is_client() (false)
- #define easelcomm_is_server() (true)
- #endif
- /* the easelcomm-{client,server} miscdevice for dev_*() messages */
- extern struct miscdevice easelcomm_miscdev;
- /* debug message util prefixes message ID by local or remote marker */
- static inline char *easelcomm_msgid_prefix(
- struct easelcomm_message_metadata *msg_metadata)
- {
- return msg_metadata->msg_type == TYPE_LOCAL ? "l" : "r";
- }
- /* DMA functions called by main */
- /* Handle DMA_SG command */
- extern void easelcomm_handle_cmd_dma_sg(
- struct easelcomm_service *service, char *command_args,
- size_t command_arg_len);
- /* Handle DMA_XFER command */
- extern void easelcomm_handle_cmd_dma_xfer(
- struct easelcomm_service *service, char *command_args,
- size_t command_arg_len);
- /* Handle DMA_DONE command */
- extern void easelcomm_handle_cmd_dma_done(
- struct easelcomm_service *service, char *command_args,
- size_t command_arg_len);
- /* Handle RECVDMA ioctl */
- extern int easelcomm_receive_dma(
- struct easelcomm_service *service,
- struct easelcomm_kbuf_desc *buf_desc);
- /* Handle SENDDMA ioctl */
- extern int easelcomm_send_dma(
- struct easelcomm_service *service,
- struct easelcomm_kbuf_desc *buf_desc);
- /* Main functions called by DMA functions */
- /* Drop a reference to a message, optionally mark for freeing */
- extern void easelcomm_drop_reference(
- struct easelcomm_service *service,
- struct easelcomm_message_metadata *msg_metadata, bool mark_free);
- /* Find a local/outgoing message by message ID */
- extern struct easelcomm_message_metadata *easelcomm_find_local_message(
- struct easelcomm_service *service, easelcomm_msgid_t message_id);
- /* Find a remote/incoming message by message ID */
- extern struct easelcomm_message_metadata *easelcomm_find_remote_message(
- struct easelcomm_service *service, easelcomm_msgid_t message_id);
- /* Start a new command to be sent to remote */
- extern int easelcomm_start_cmd(
- struct easelcomm_service *service, int command_code,
- size_t command_arg_len);
- /* Add command arguments to the in-progress command */
- extern int easelcomm_append_cmd_args(
- struct easelcomm_service *service, void *cmd_args,
- size_t cmd_args_len);
- /* Finish and send command to remote */
- extern int easelcomm_send_cmd(struct easelcomm_service *service);
- /* Start and send a new command with no arguments */
- extern int easelcomm_send_cmd_noargs(
- struct easelcomm_service *service, int command_code);
- /* Easel MNH coprocessor/PCIe hardware access functions */
- /* register IRQ callbacks, etc. */
- extern int easelcomm_hw_init(void);
- /* AP retrieve Easel buffer address and setup EP iATU for both directions */
- extern int easelcomm_hw_ap_setup_cmdchans(void);
- /* send command channel data ready interrupt to remote */
- extern int easelcomm_hw_send_data_interrupt(void);
- /* send command channel wraparound interrupt to remote */
- extern int easelcomm_hw_send_wrap_interrupt(void);
- /* read remote memory */
- extern int easelcomm_hw_remote_read(
- void *local_addr, size_t len, uint64_t remote_offset);
- /* write remote memory */
- extern int easelcomm_hw_remote_write(
- void *local_addr, size_t len, uint64_t remote_offset);
- /* build an MNH DMA scatter-gather list */
- extern void *easelcomm_hw_build_scatterlist(
- struct easelcomm_kbuf_desc *buf_desc,
- uint32_t *scatterlist_size,
- void **sglocaldata, enum easelcomm_dma_direction dma_dir);
- /* get block count from SG list, for determing if multi- or single-block */
- extern int easelcomm_hw_scatterlist_block_count(uint32_t scatterlist_size);
- /* get start address from SG list for single-block transfer */
- extern uint64_t easelcomm_hw_scatterlist_sblk_addr(void *sglist);
- /* destroy (and unmap pages pinned by) a scatter-gather list */
- extern void easelcomm_hw_destroy_scatterlist(void *sglocaldata);
- /* sanity check scatterlists */
- extern int easelcomm_hw_verify_scatterlist(
- struct easelcomm_dma_xfer_info *xfer);
- /*
- * Easel builds multi-block DMA Linked List from local and remote SG lists.
- *
- * ll_data returns an opaque pointer passed to other calls.
- */
- extern int easelcomm_hw_easel_build_ll(
- void *src_sg, void *dest_sg, void **ll_data);
- /* Easel returns LL DMA address needed for multi-block transfer */
- extern uint64_t easelcomm_hw_easel_ll_addr(void *ll_data);
- /* Easel destroys MBLK DMA Linked List */
- extern int easelcomm_hw_easel_destroy_ll(void *ll_data);
- /* AP performs a single-block DMA transfer */
- extern int easelcomm_hw_ap_dma_sblk_transfer(
- uint64_t ap_paddr, uint64_t easel_paddr, uint32_t xfer_len,
- bool to_easel);
- /* AP performs a multi-block DMA transfer */
- extern int easelcomm_hw_ap_dma_mblk_transfer(uint64_t ll_paddr, bool to_easel);
- /* callbacks to main code from hardware-specific functions */
- /* PCIe ready, local cmdchan buffer alloc'ed, init upper layer */
- int easelcomm_init_pcie_ready(void *local_cmdchan_buffer);
- /* Called when PCIe EP has been hotplug out */
- int easelcomm_pcie_hotplug_out(void);
- /* Handle command channel data received interrupt (MSG_SENT) */
- extern void easelcomm_cmd_channel_data_handler(void);
- /* Handle command channel wrapround interrupt (APPDEFINED_1) */
- extern void easelcomm_cmd_channel_wrap_handler(void);
- /* AP handles BOOTSTRAP_SET interrupt, Easel command channel is ready */
- extern int easelcomm_client_remote_cmdchan_ready_handler(void);
- #endif /* _GOOGLE_EASEL_COMM_PRIVATE_H */
|