cvmx-cmd-queue.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /***********************license start***************
  2. * Author: Cavium Networks
  3. *
  4. * Contact: [email protected]
  5. * This file is part of the OCTEON SDK
  6. *
  7. * Copyright (c) 2003-2008 Cavium Networks
  8. *
  9. * This file is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License, Version 2, as
  11. * published by the Free Software Foundation.
  12. *
  13. * This file is distributed in the hope that it will be useful, but
  14. * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
  15. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
  16. * NONINFRINGEMENT. See the GNU General Public License for more
  17. * details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this file; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  22. * or visit http://www.gnu.org/licenses/.
  23. *
  24. * This file may also be available under a different license from Cavium.
  25. * Contact Cavium Networks for more information
  26. ***********************license end**************************************/
  27. /*
  28. * Support functions for managing command queues used for
  29. * various hardware blocks.
  30. */
  31. #include <linux/kernel.h>
  32. #include <asm/octeon/octeon.h>
  33. #include <asm/octeon/cvmx-config.h>
  34. #include <asm/octeon/cvmx-fpa.h>
  35. #include <asm/octeon/cvmx-cmd-queue.h>
  36. #include <asm/octeon/cvmx-npei-defs.h>
  37. #include <asm/octeon/cvmx-pexp-defs.h>
  38. #include <asm/octeon/cvmx-pko-defs.h>
  39. /*
  40. * This application uses this pointer to access the global queue
  41. * state. It points to a bootmem named block.
  42. */
  43. __cvmx_cmd_queue_all_state_t *__cvmx_cmd_queue_state_ptr;
  44. EXPORT_SYMBOL_GPL(__cvmx_cmd_queue_state_ptr);
  45. /*
  46. * Initialize the Global queue state pointer.
  47. *
  48. * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code
  49. */
  50. static cvmx_cmd_queue_result_t __cvmx_cmd_queue_init_state_ptr(void)
  51. {
  52. char *alloc_name = "cvmx_cmd_queues";
  53. extern uint64_t octeon_reserve32_memory;
  54. if (likely(__cvmx_cmd_queue_state_ptr))
  55. return CVMX_CMD_QUEUE_SUCCESS;
  56. if (octeon_reserve32_memory)
  57. __cvmx_cmd_queue_state_ptr =
  58. cvmx_bootmem_alloc_named_range(sizeof(*__cvmx_cmd_queue_state_ptr),
  59. octeon_reserve32_memory,
  60. octeon_reserve32_memory +
  61. (CONFIG_CAVIUM_RESERVE32 <<
  62. 20) - 1, 128, alloc_name);
  63. else
  64. __cvmx_cmd_queue_state_ptr =
  65. cvmx_bootmem_alloc_named(sizeof(*__cvmx_cmd_queue_state_ptr),
  66. 128,
  67. alloc_name);
  68. if (__cvmx_cmd_queue_state_ptr)
  69. memset(__cvmx_cmd_queue_state_ptr, 0,
  70. sizeof(*__cvmx_cmd_queue_state_ptr));
  71. else {
  72. struct cvmx_bootmem_named_block_desc *block_desc =
  73. cvmx_bootmem_find_named_block(alloc_name);
  74. if (block_desc)
  75. __cvmx_cmd_queue_state_ptr =
  76. cvmx_phys_to_ptr(block_desc->base_addr);
  77. else {
  78. cvmx_dprintf
  79. ("ERROR: cvmx_cmd_queue_initialize: Unable to get named block %s.\n",
  80. alloc_name);
  81. return CVMX_CMD_QUEUE_NO_MEMORY;
  82. }
  83. }
  84. return CVMX_CMD_QUEUE_SUCCESS;
  85. }
  86. /*
  87. * Initialize a command queue for use. The initial FPA buffer is
  88. * allocated and the hardware unit is configured to point to the
  89. * new command queue.
  90. *
  91. * @queue_id: Hardware command queue to initialize.
  92. * @max_depth: Maximum outstanding commands that can be queued.
  93. * @fpa_pool: FPA pool the command queues should come from.
  94. * @pool_size: Size of each buffer in the FPA pool (bytes)
  95. *
  96. * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code
  97. */
  98. cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id,
  99. int max_depth, int fpa_pool,
  100. int pool_size)
  101. {
  102. __cvmx_cmd_queue_state_t *qstate;
  103. cvmx_cmd_queue_result_t result = __cvmx_cmd_queue_init_state_ptr();
  104. if (result != CVMX_CMD_QUEUE_SUCCESS)
  105. return result;
  106. qstate = __cvmx_cmd_queue_get_state(queue_id);
  107. if (qstate == NULL)
  108. return CVMX_CMD_QUEUE_INVALID_PARAM;
  109. /*
  110. * We artificially limit max_depth to 1<<20 words. It is an
  111. * arbitrary limit.
  112. */
  113. if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH) {
  114. if ((max_depth < 0) || (max_depth > 1 << 20))
  115. return CVMX_CMD_QUEUE_INVALID_PARAM;
  116. } else if (max_depth != 0)
  117. return CVMX_CMD_QUEUE_INVALID_PARAM;
  118. if ((fpa_pool < 0) || (fpa_pool > 7))
  119. return CVMX_CMD_QUEUE_INVALID_PARAM;
  120. if ((pool_size < 128) || (pool_size > 65536))
  121. return CVMX_CMD_QUEUE_INVALID_PARAM;
  122. /* See if someone else has already initialized the queue */
  123. if (qstate->base_ptr_div128) {
  124. if (max_depth != (int)qstate->max_depth) {
  125. cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "
  126. "Queue already initialized with different "
  127. "max_depth (%d).\n",
  128. (int)qstate->max_depth);
  129. return CVMX_CMD_QUEUE_INVALID_PARAM;
  130. }
  131. if (fpa_pool != qstate->fpa_pool) {
  132. cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "
  133. "Queue already initialized with different "
  134. "FPA pool (%u).\n",
  135. qstate->fpa_pool);
  136. return CVMX_CMD_QUEUE_INVALID_PARAM;
  137. }
  138. if ((pool_size >> 3) - 1 != qstate->pool_size_m1) {
  139. cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "
  140. "Queue already initialized with different "
  141. "FPA pool size (%u).\n",
  142. (qstate->pool_size_m1 + 1) << 3);
  143. return CVMX_CMD_QUEUE_INVALID_PARAM;
  144. }
  145. CVMX_SYNCWS;
  146. return CVMX_CMD_QUEUE_ALREADY_SETUP;
  147. } else {
  148. union cvmx_fpa_ctl_status status;
  149. void *buffer;
  150. status.u64 = cvmx_read_csr(CVMX_FPA_CTL_STATUS);
  151. if (!status.s.enb) {
  152. cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "
  153. "FPA is not enabled.\n");
  154. return CVMX_CMD_QUEUE_NO_MEMORY;
  155. }
  156. buffer = cvmx_fpa_alloc(fpa_pool);
  157. if (buffer == NULL) {
  158. cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "
  159. "Unable to allocate initial buffer.\n");
  160. return CVMX_CMD_QUEUE_NO_MEMORY;
  161. }
  162. memset(qstate, 0, sizeof(*qstate));
  163. qstate->max_depth = max_depth;
  164. qstate->fpa_pool = fpa_pool;
  165. qstate->pool_size_m1 = (pool_size >> 3) - 1;
  166. qstate->base_ptr_div128 = cvmx_ptr_to_phys(buffer) / 128;
  167. /*
  168. * We zeroed the now serving field so we need to also
  169. * zero the ticket.
  170. */
  171. __cvmx_cmd_queue_state_ptr->
  172. ticket[__cvmx_cmd_queue_get_index(queue_id)] = 0;
  173. CVMX_SYNCWS;
  174. return CVMX_CMD_QUEUE_SUCCESS;
  175. }
  176. }
  177. /*
  178. * Shutdown a queue a free it's command buffers to the FPA. The
  179. * hardware connected to the queue must be stopped before this
  180. * function is called.
  181. *
  182. * @queue_id: Queue to shutdown
  183. *
  184. * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code
  185. */
  186. cvmx_cmd_queue_result_t cvmx_cmd_queue_shutdown(cvmx_cmd_queue_id_t queue_id)
  187. {
  188. __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id);
  189. if (qptr == NULL) {
  190. cvmx_dprintf("ERROR: cvmx_cmd_queue_shutdown: Unable to "
  191. "get queue information.\n");
  192. return CVMX_CMD_QUEUE_INVALID_PARAM;
  193. }
  194. if (cvmx_cmd_queue_length(queue_id) > 0) {
  195. cvmx_dprintf("ERROR: cvmx_cmd_queue_shutdown: Queue still "
  196. "has data in it.\n");
  197. return CVMX_CMD_QUEUE_FULL;
  198. }
  199. __cvmx_cmd_queue_lock(queue_id, qptr);
  200. if (qptr->base_ptr_div128) {
  201. cvmx_fpa_free(cvmx_phys_to_ptr
  202. ((uint64_t) qptr->base_ptr_div128 << 7),
  203. qptr->fpa_pool, 0);
  204. qptr->base_ptr_div128 = 0;
  205. }
  206. __cvmx_cmd_queue_unlock(qptr);
  207. return CVMX_CMD_QUEUE_SUCCESS;
  208. }
  209. /*
  210. * Return the number of command words pending in the queue. This
  211. * function may be relatively slow for some hardware units.
  212. *
  213. * @queue_id: Hardware command queue to query
  214. *
  215. * Returns Number of outstanding commands
  216. */
  217. int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id)
  218. {
  219. if (CVMX_ENABLE_PARAMETER_CHECKING) {
  220. if (__cvmx_cmd_queue_get_state(queue_id) == NULL)
  221. return CVMX_CMD_QUEUE_INVALID_PARAM;
  222. }
  223. /*
  224. * The cast is here so gcc with check that all values in the
  225. * cvmx_cmd_queue_id_t enumeration are here.
  226. */
  227. switch ((cvmx_cmd_queue_id_t) (queue_id & 0xff0000)) {
  228. case CVMX_CMD_QUEUE_PKO_BASE:
  229. /*
  230. * FIXME: Need atomic lock on
  231. * CVMX_PKO_REG_READ_IDX. Right now we are normally
  232. * called with the queue lock, so that is a SLIGHT
  233. * amount of protection.
  234. */
  235. cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue_id & 0xffff);
  236. if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
  237. union cvmx_pko_mem_debug9 debug9;
  238. debug9.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG9);
  239. return debug9.cn38xx.doorbell;
  240. } else {
  241. union cvmx_pko_mem_debug8 debug8;
  242. debug8.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG8);
  243. return debug8.cn50xx.doorbell;
  244. }
  245. case CVMX_CMD_QUEUE_ZIP:
  246. case CVMX_CMD_QUEUE_DFA:
  247. case CVMX_CMD_QUEUE_RAID:
  248. /* FIXME: Implement other lengths */
  249. return 0;
  250. case CVMX_CMD_QUEUE_DMA_BASE:
  251. {
  252. union cvmx_npei_dmax_counts dmax_counts;
  253. dmax_counts.u64 =
  254. cvmx_read_csr(CVMX_PEXP_NPEI_DMAX_COUNTS
  255. (queue_id & 0x7));
  256. return dmax_counts.s.dbell;
  257. }
  258. case CVMX_CMD_QUEUE_END:
  259. return CVMX_CMD_QUEUE_INVALID_PARAM;
  260. }
  261. return CVMX_CMD_QUEUE_INVALID_PARAM;
  262. }
  263. /*
  264. * Return the command buffer to be written to. The purpose of this
  265. * function is to allow CVMX routine access t othe low level buffer
  266. * for initial hardware setup. User applications should not call this
  267. * function directly.
  268. *
  269. * @queue_id: Command queue to query
  270. *
  271. * Returns Command buffer or NULL on failure
  272. */
  273. void *cvmx_cmd_queue_buffer(cvmx_cmd_queue_id_t queue_id)
  274. {
  275. __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id);
  276. if (qptr && qptr->base_ptr_div128)
  277. return cvmx_phys_to_ptr((uint64_t) qptr->base_ptr_div128 << 7);
  278. else
  279. return NULL;
  280. }