google-easel-comm-private.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. /*
  2. * Android/Easel coprocessor communication hardware access to the PCIe/EP
  3. * driver on the local side of the link (AP or Easel), used by the common and
  4. * link-partner-specific code.
  5. *
  6. * Copyright 2016 Google Inc.
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #ifndef _GOOGLE_EASEL_COMM_PRIVATE_H
  13. #define _GOOGLE_EASEL_COMM_PRIVATE_H
  14. #include "google-easel-comm-shared.h"
  15. #include <linux/completion.h>
  16. #include <linux/list.h>
  17. #include <linux/miscdevice.h>
  18. #include <linux/mutex.h>
  19. #include <linux/spinlock.h>
  20. #include <linux/types.h>
  21. /*
  22. * Message types used to set the general type of processing for the message
  23. * and in which local data structures the message exists:
  24. * local: message originated locally with a local message ID, stored in the
  25. * local message list for the associated Easel service.
  26. * remote non-reply: message received from remote with a remote message ID,
  27. * stored in the remote message list, and also appears in the receive
  28. * message queue until returned by a receiveMessage() call.
  29. * remote reply: message from remote that is processed as a reply to a local
  30. * message, does not go into the receiveMessage() queue.
  31. */
  32. enum easelcomm_msg_type {
  33. TYPE_LOCAL = 0, /* local/outgoing */
  34. TYPE_REMOTE_NONREPLY, /* remote/incoming general */
  35. TYPE_REMOTE_REPLY, /* remote/incoming reply */
  36. };
  37. /*
  38. * Message metadata specific to DMA transfer handling. Messages with no DMA
  39. * transfer have default values for these.
  40. */
  41. struct easelcomm_dma_xfer_info {
  42. /*
  43. * The local MNH driver scatter-gather list, or NULL if discarding.
  44. * This points to an array of mnh_sg_entry. Content of this is
  45. * to be used to combine with remote scatter-gather list to be a
  46. * DMA Linked List.
  47. */
  48. void *sg_local;
  49. /* Size in bytes of the local scatter-gather list, zero if discard */
  50. uint32_t sg_local_size;
  51. /*
  52. * Local data private to the MNH layer associated with the SG list.
  53. * This points to mnh_sg_list. It marks information of
  54. * the buffer for DMA transfer, and is used to collect local MNH
  55. * driver scatter-gather list (sg_local).
  56. */
  57. void *sg_local_localdata;
  58. /*
  59. * Easel/server keeps the remote scatter-gather list received from the
  60. * client (in a DMA_SG command) here for processing. The server is in
  61. * charge of building the DMA Linked List for a multi-block transfer or
  62. * deciding to use a single-block transfer based on the SG lists.
  63. */
  64. void *sg_remote;
  65. /* Size in bytes of the remote SG list */
  66. uint32_t sg_remote_size;
  67. /* Informs server remote SG received from client */
  68. struct completion sg_remote_ready;
  69. /*
  70. * Server determines DMA transfer type (SBLK/MBLK/ABORT) and sends to
  71. * client to perform (or discard) the transfer. Sent with DMA_XFER
  72. * command.
  73. */
  74. uint32_t xfer_type;
  75. /*
  76. * The server's address applicable to the DMA transfer command:
  77. * The Multi-Block Linked List physical address (in Easel memory) or
  78. * the Single-Block server-side physical address of the transfer
  79. * source or destination address).
  80. */
  81. uint64_t server_addr;
  82. /*
  83. * Informs client the DMA transfer request ready (DMA_XFER command
  84. * received from server), ready to proceed (or discard).
  85. */
  86. struct completion xfer_ready;
  87. /*
  88. * Informs server DMA transfer is complete, DMA_DONE command received
  89. * from client after transfer is complete or aborted. Server can
  90. * clean up message and DMA data structures and return to caller.
  91. */
  92. struct completion xfer_done;
  93. /*
  94. * DMA request is being aborted, either the remote sent an abort
  95. * or locally a service flush or signal was received.
  96. */
  97. bool aborting;
  98. /* DMA transfer error code (-errno) if non-zero */
  99. int32_t errcode;
  100. };
  101. /*
  102. * Message metadata, one for each local/outgoing and remote/incoming message
  103. * in progress on the local system. Concurrency protection for all fields is
  104. * provided through the spinlock for the Easel service for which the message
  105. * is created.
  106. */
  107. struct easelcomm_message_metadata {
  108. /*
  109. * Message reference count, > 0 means kernel code is currently
  110. * executing that holds a pointer to this message (metadata), or a
  111. * data structure (other than the local/remote message lists)
  112. * currently points to this message (namely a reply message pointed to
  113. * by the replied-to message). Zero reference count means the message
  114. * can be safely removed from the local/remote list and freed (with the
  115. * service lock held), which may happen outside the normal message
  116. * lifecycle on a service flush.
  117. */
  118. int reference_count;
  119. /*
  120. * Set to true when the message is to be freed once the reference count
  121. * goes to 0.
  122. */
  123. bool free_message;
  124. /*
  125. * True if message is marked to be flushed, lets DMA handling or
  126. * reply waiter know to bail and let the message be flushed.
  127. */
  128. bool flushing;
  129. /* what type of message: local, remote reply, remote non-reply */
  130. enum easelcomm_msg_type msg_type;
  131. /* local or remote message list linkage */
  132. struct list_head list;
  133. /*
  134. * True if message is in the receiveMessage queue (a remote non-reply
  135. * not yet picked up by a receiveMessage() call).
  136. */
  137. bool queued;
  138. /* receiveMessage queue list linkage, if message is queued */
  139. struct list_head rcvq_list;
  140. /* signals reply message received, if message needs a reply */
  141. struct completion reply_received;
  142. /* pointer to reply message metadata once received, if need reply */
  143. struct easelcomm_message_metadata *reply_metadata;
  144. /* DMA info, if message includes a DMA transfer */
  145. struct easelcomm_dma_xfer_info dma_xfer;
  146. /* points to the Easel message desc and data */
  147. struct easelcomm_kmsg *msg;
  148. };
  149. /* forward declare for service/user state cross-references */
  150. struct easelcomm_user_state;
  151. /* Per-Easel-service data. */
  152. struct easelcomm_service {
  153. /* service ID (same as easelcom_service array index) */
  154. unsigned int service_id;
  155. /* protects access to all mutable fields below and in messages */
  156. struct mutex lock;
  157. /* currently registered user */
  158. struct easelcomm_user_state *user;
  159. /* true if service is being closed by local */
  160. bool shutdown_local;
  161. /* true if service was closed by remote */
  162. bool shutdown_remote;
  163. /* next local/outgoing message ID */
  164. easelcomm_msgid_t next_id;
  165. /* list of in-progress local/outgoing messages */
  166. struct list_head local_list;
  167. /* remote non-reply messages not yet returned by receiveMessage */
  168. struct list_head receivemsg_queue;
  169. /* signals new entry added to receivemsg_queue */
  170. struct completion receivemsg_queue_new;
  171. /* in-progress remote messages (reply and non-reply) */
  172. struct list_head remote_list;
  173. /* flush service complete on remote, ready to resume service */
  174. struct completion flush_done;
  175. };
  176. /*
  177. * Are we running as AP/client or Easel/server? Most decisions are made
  178. * at runtime instead of compile time for code prettiness.
  179. */
  180. #ifdef CONFIG_GOOGLE_EASEL_AP
  181. #define easelcomm_is_client() (true)
  182. #define easelcomm_is_server() (false)
  183. #else
  184. #define easelcomm_is_client() (false)
  185. #define easelcomm_is_server() (true)
  186. #endif
  187. /* the easelcomm-{client,server} miscdevice for dev_*() messages */
  188. extern struct miscdevice easelcomm_miscdev;
  189. /* debug message util prefixes message ID by local or remote marker */
  190. static inline char *easelcomm_msgid_prefix(
  191. struct easelcomm_message_metadata *msg_metadata)
  192. {
  193. return msg_metadata->msg_type == TYPE_LOCAL ? "l" : "r";
  194. }
  195. /* DMA functions called by main */
  196. /* Handle DMA_SG command */
  197. extern void easelcomm_handle_cmd_dma_sg(
  198. struct easelcomm_service *service, char *command_args,
  199. size_t command_arg_len);
  200. /* Handle DMA_XFER command */
  201. extern void easelcomm_handle_cmd_dma_xfer(
  202. struct easelcomm_service *service, char *command_args,
  203. size_t command_arg_len);
  204. /* Handle DMA_DONE command */
  205. extern void easelcomm_handle_cmd_dma_done(
  206. struct easelcomm_service *service, char *command_args,
  207. size_t command_arg_len);
  208. /* Handle RECVDMA ioctl */
  209. extern int easelcomm_receive_dma(
  210. struct easelcomm_service *service,
  211. struct easelcomm_kbuf_desc *buf_desc);
  212. /* Handle SENDDMA ioctl */
  213. extern int easelcomm_send_dma(
  214. struct easelcomm_service *service,
  215. struct easelcomm_kbuf_desc *buf_desc);
  216. /* Main functions called by DMA functions */
  217. /* Drop a reference to a message, optionally mark for freeing */
  218. extern void easelcomm_drop_reference(
  219. struct easelcomm_service *service,
  220. struct easelcomm_message_metadata *msg_metadata, bool mark_free);
  221. /* Find a local/outgoing message by message ID */
  222. extern struct easelcomm_message_metadata *easelcomm_find_local_message(
  223. struct easelcomm_service *service, easelcomm_msgid_t message_id);
  224. /* Find a remote/incoming message by message ID */
  225. extern struct easelcomm_message_metadata *easelcomm_find_remote_message(
  226. struct easelcomm_service *service, easelcomm_msgid_t message_id);
  227. /* Start a new command to be sent to remote */
  228. extern int easelcomm_start_cmd(
  229. struct easelcomm_service *service, int command_code,
  230. size_t command_arg_len);
  231. /* Add command arguments to the in-progress command */
  232. extern int easelcomm_append_cmd_args(
  233. struct easelcomm_service *service, void *cmd_args,
  234. size_t cmd_args_len);
  235. /* Finish and send command to remote */
  236. extern int easelcomm_send_cmd(struct easelcomm_service *service);
  237. /* Start and send a new command with no arguments */
  238. extern int easelcomm_send_cmd_noargs(
  239. struct easelcomm_service *service, int command_code);
  240. /* Easel MNH coprocessor/PCIe hardware access functions */
  241. /* register IRQ callbacks, etc. */
  242. extern int easelcomm_hw_init(void);
  243. /* AP retrieve Easel buffer address and setup EP iATU for both directions */
  244. extern int easelcomm_hw_ap_setup_cmdchans(void);
  245. /* send command channel data ready interrupt to remote */
  246. extern int easelcomm_hw_send_data_interrupt(void);
  247. /* send command channel wraparound interrupt to remote */
  248. extern int easelcomm_hw_send_wrap_interrupt(void);
  249. /* read remote memory */
  250. extern int easelcomm_hw_remote_read(
  251. void *local_addr, size_t len, uint64_t remote_offset);
  252. /* write remote memory */
  253. extern int easelcomm_hw_remote_write(
  254. void *local_addr, size_t len, uint64_t remote_offset);
  255. /* build an MNH DMA scatter-gather list */
  256. extern void *easelcomm_hw_build_scatterlist(
  257. struct easelcomm_kbuf_desc *buf_desc,
  258. uint32_t *scatterlist_size,
  259. void **sglocaldata, enum easelcomm_dma_direction dma_dir);
  260. /* get block count from SG list, for determing if multi- or single-block */
  261. extern int easelcomm_hw_scatterlist_block_count(uint32_t scatterlist_size);
  262. /* get start address from SG list for single-block transfer */
  263. extern uint64_t easelcomm_hw_scatterlist_sblk_addr(void *sglist);
  264. /* destroy (and unmap pages pinned by) a scatter-gather list */
  265. extern void easelcomm_hw_destroy_scatterlist(void *sglocaldata);
  266. /* sanity check scatterlists */
  267. extern int easelcomm_hw_verify_scatterlist(
  268. struct easelcomm_dma_xfer_info *xfer);
  269. /*
  270. * Easel builds multi-block DMA Linked List from local and remote SG lists.
  271. *
  272. * ll_data returns an opaque pointer passed to other calls.
  273. */
  274. extern int easelcomm_hw_easel_build_ll(
  275. void *src_sg, void *dest_sg, void **ll_data);
  276. /* Easel returns LL DMA address needed for multi-block transfer */
  277. extern uint64_t easelcomm_hw_easel_ll_addr(void *ll_data);
  278. /* Easel destroys MBLK DMA Linked List */
  279. extern int easelcomm_hw_easel_destroy_ll(void *ll_data);
  280. /* AP performs a single-block DMA transfer */
  281. extern int easelcomm_hw_ap_dma_sblk_transfer(
  282. uint64_t ap_paddr, uint64_t easel_paddr, uint32_t xfer_len,
  283. bool to_easel);
  284. /* AP performs a multi-block DMA transfer */
  285. extern int easelcomm_hw_ap_dma_mblk_transfer(uint64_t ll_paddr, bool to_easel);
  286. /* callbacks to main code from hardware-specific functions */
  287. /* PCIe ready, local cmdchan buffer alloc'ed, init upper layer */
  288. int easelcomm_init_pcie_ready(void *local_cmdchan_buffer);
  289. /* Called when PCIe EP has been hotplug out */
  290. int easelcomm_pcie_hotplug_out(void);
  291. /* Handle command channel data received interrupt (MSG_SENT) */
  292. extern void easelcomm_cmd_channel_data_handler(void);
  293. /* Handle command channel wrapround interrupt (APPDEFINED_1) */
  294. extern void easelcomm_cmd_channel_wrap_handler(void);
  295. /* AP handles BOOTSTRAP_SET interrupt, Easel command channel is ready */
  296. extern int easelcomm_client_remote_cmdchan_ready_handler(void);
  297. #endif /* _GOOGLE_EASEL_COMM_PRIVATE_H */