1 /***********************license start***************
2 * Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * * Neither the name of Cavium Networks nor the names of
19 * its contributors may be used to endorse or promote products
20 * derived from this software without specific prior written
23 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24 * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25 * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26 * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31 * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT
32 * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
35 * For any questions regarding licensing please contact marketing@caviumnetworks.com
37 ***********************license end**************************************/
47 * Support functions for managing command queues used for
48 * various hardware blocks.
50 * The common command queue infrastructure abstracts out the
51 * software necessary for adding to Octeon's chained queue
52 * structures. These structures are used for commands to the
53 * PKO, ZIP, DFA, RAID, and DMA engine blocks. Although each
54 * hardware unit takes commands and CSRs of different types,
55 * they all use basic linked command buffers to store the
56 * pending request. In general, users of the CVMX API don't
57 * call cvmx-cmd-queue functions directly. Instead the hardware
58 * unit specific wrapper should be used. The wrappers perform
59 * unit specific validation and CSR writes to submit the
62 * Even though most software will never directly interact with
63 * cvmx-cmd-queue, knowledge of its internal working can help
64 * in diagnosing performance problems and help with debugging.
66 * Command queue pointers are stored in a global named block
67 * called "cvmx_cmd_queues". Except for the PKO queues, each
68 * hardware queue is stored in its own cache line to reduce SMP
69 * contention on spin locks. The PKO queues are stored such that
70 * every 16th queue is next to each other in memory. This scheme
71 * allows for queues being in separate cache lines when there
72 * are low number of queues per port. With 16 queues per port,
73 * the first queue for each port is in the same cache area. The
74 * second queues for each port are in another area, etc. This
75 * allows software to implement very efficient lockless PKO with
76 * 16 queues per port using a minimum of cache lines per core.
77 * All queues for a given core will be isolated in the same
80 * In addition to the memory pointer layout, cvmx-cmd-queue
81 * provides an optimized fair ll/sc locking mechanism for the
82 * queues. The lock uses a "ticket / now serving" model to
83 * maintain fair order on contended locks. In addition, it uses
84 * predicted locking time to limit cache contention. When a core
85 * know it must wait in line for a lock, it spins on the
86 * internal cycle counter to completely eliminate any causes of
89 * <hr> $Revision: 42150 $ <hr>
92 #ifndef __CVMX_CMD_QUEUE_H__
93 #define __CVMX_CMD_QUEUE_H__
95 #ifndef CVMX_DONT_INCLUDE_CONFIG
96 #include "executive-config.h"
97 #include "cvmx-config.h"
106 * By default we disable the max depth support. Most programs
107 * don't use it and it slows down the command queue processing
110 #ifndef CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH
111 #define CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH 0
115 * Enumeration representing all hardware blocks that use command
116 * queues. Each hardware block has up to 65536 sub identifiers for
117 * multiple command queues. Not all chips support all hardware
122 CVMX_CMD_QUEUE_PKO_BASE = 0x00000,
123 #define CVMX_CMD_QUEUE_PKO(queue) ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_PKO_BASE + (0xffff&(queue))))
124 CVMX_CMD_QUEUE_ZIP = 0x10000,
125 CVMX_CMD_QUEUE_DFA = 0x20000,
126 CVMX_CMD_QUEUE_RAID = 0x30000,
127 CVMX_CMD_QUEUE_DMA_BASE = 0x40000,
128 #define CVMX_CMD_QUEUE_DMA(queue) ((cvmx_cmd_queue_id_t)(CVMX_CMD_QUEUE_DMA_BASE + (0xffff&(queue))))
129 CVMX_CMD_QUEUE_END = 0x50000,
130 } cvmx_cmd_queue_id_t;
133 * Command write operations can fail if the comamnd queue needs
134 * a new buffer and the associated FPA pool is empty. It can also
135 * fail if the number of queued command words reaches the maximum
136 * set at initialization.
140 CVMX_CMD_QUEUE_SUCCESS = 0,
141 CVMX_CMD_QUEUE_NO_MEMORY = -1,
142 CVMX_CMD_QUEUE_FULL = -2,
143 CVMX_CMD_QUEUE_INVALID_PARAM = -3,
144 CVMX_CMD_QUEUE_ALREADY_SETUP = -4,
145 } cvmx_cmd_queue_result_t;
149 uint8_t now_serving; /**< You have lock when this is your ticket */
150 uint64_t unused1 : 24;
151 uint32_t max_depth; /**< Maximum outstanding command words */
152 uint64_t fpa_pool : 3; /**< FPA pool buffers come from */
153 uint64_t base_ptr_div128: 29; /**< Top of command buffer pointer shifted 7 */
154 uint64_t unused2 : 6;
155 uint64_t pool_size_m1 : 13; /**< FPA buffer size in 64bit words minus 1 */
156 uint64_t index : 13; /**< Number of comamnds already used in buffer */
157 } __cvmx_cmd_queue_state_t;
160 * This structure contains the global state of all comamnd queues.
161 * It is stored in a bootmem named block and shared by all
162 * applications running on Octeon. Tickets are stored in a differnet
163 * cahce line that queue information to reduce the contention on the
164 * ll/sc used to get a ticket. If this is not the case, the update
165 * of queue state causes the ll/sc to fail quite often.
169 uint64_t ticket[(CVMX_CMD_QUEUE_END>>16) * 256];
170 __cvmx_cmd_queue_state_t state[(CVMX_CMD_QUEUE_END>>16) * 256];
171 } __cvmx_cmd_queue_all_state_t;
173 extern CVMX_SHARED __cvmx_cmd_queue_all_state_t *__cvmx_cmd_queue_state_ptr;
176 * Initialize a command queue for use. The initial FPA buffer is
177 * allocated and the hardware unit is configured to point to the
180 * @param queue_id Hardware command queue to initialize.
181 * @param max_depth Maximum outstanding commands that can be queued.
182 * @param fpa_pool FPA pool the command queues should come from.
183 * @param pool_size Size of each buffer in the FPA pool (bytes)
185 * @return CVMX_CMD_QUEUE_SUCCESS or a failure code
187 cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id, int max_depth, int fpa_pool, int pool_size);
190 * Shutdown a queue a free it's command buffers to the FPA. The
191 * hardware connected to the queue must be stopped before this
192 * function is called.
194 * @param queue_id Queue to shutdown
196 * @return CVMX_CMD_QUEUE_SUCCESS or a failure code
198 cvmx_cmd_queue_result_t cvmx_cmd_queue_shutdown(cvmx_cmd_queue_id_t queue_id);
201 * Return the number of command words pending in the queue. This
202 * function may be relatively slow for some hardware units.
204 * @param queue_id Hardware command queue to query
206 * @return Number of outstanding commands
208 int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id);
211 * Return the command buffer to be written to. The purpose of this
212 * function is to allow CVMX routine access t othe low level buffer
213 * for initial hardware setup. User applications should not call this
216 * @param queue_id Command queue to query
218 * @return Command buffer or NULL on failure
220 void *cvmx_cmd_queue_buffer(cvmx_cmd_queue_id_t queue_id);
224 * Get the index into the state arrays for the supplied queue id.
226 * @param queue_id Queue ID to get an index for
228 * @return Index into the state arrays
230 static inline int __cvmx_cmd_queue_get_index(cvmx_cmd_queue_id_t queue_id)
232 /* Warning: This code currently only works with devices that have 256 queues
233 or less. Devices with more than 16 queues are layed out in memory to allow
234 cores quick access to every 16th queue. This reduces cache thrashing
235 when you are running 16 queues per port to support lockless operation */
236 int unit = queue_id>>16;
237 int q = (queue_id >> 4) & 0xf;
238 int core = queue_id & 0xf;
239 return unit*256 + core*16 + q;
245 * Lock the supplied queue so nobody else is updating it at the same
248 * @param queue_id Queue ID to lock
249 * @param qptr Pointer to the queue's global state
251 static inline void __cvmx_cmd_queue_lock(cvmx_cmd_queue_id_t queue_id, __cvmx_cmd_queue_state_t *qptr)
255 CVMX_PREFETCH(qptr, 0);
260 "ll %[my_ticket], %[ticket_ptr]\n" /* Atomic add one to ticket_ptr */
261 "li %[ticket], 1\n" /* and store the original value */
262 "baddu %[ticket], %[my_ticket]\n" /* in my_ticket */
263 "sc %[ticket], %[ticket_ptr]\n"
264 "beqz %[ticket], 1b\n"
266 "lbu %[ticket], %[now_serving]\n" /* Load the current now_serving ticket */
268 "beq %[ticket], %[my_ticket], 4f\n" /* Jump out if now_serving == my_ticket */
269 " subu %[ticket], %[my_ticket], %[ticket]\n" /* Find out how many tickets are in front of me */
270 "subu %[ticket], 1\n" /* Use tickets in front of me minus one to delay */
271 "cins %[ticket], %[ticket], 5, 7\n" /* Delay will be ((tickets in front)-1)*32 loops */
273 "bnez %[ticket], 3b\n" /* Loop here until our ticket might be up */
274 " subu %[ticket], 1\n"
275 "b 2b\n" /* Jump back up to check out ticket again */
276 " lbu %[ticket], %[now_serving]\n" /* Load the current now_serving ticket */
279 : [ticket_ptr] "=m" (__cvmx_cmd_queue_state_ptr->ticket[__cvmx_cmd_queue_get_index(queue_id)]),
280 [now_serving] "=m" (qptr->now_serving),
282 [my_ticket] "=r" (my_ticket)
289 * Unlock the queue, flushing all writes.
291 * @param qptr Queue to unlock
293 static inline void __cvmx_cmd_queue_unlock(__cvmx_cmd_queue_state_t *qptr)
302 * Get the queue state structure for the given queue id
304 * @param queue_id Queue id to get
306 * @return Queue structure or NULL on failure
308 static inline __cvmx_cmd_queue_state_t *__cvmx_cmd_queue_get_state(cvmx_cmd_queue_id_t queue_id)
310 if (CVMX_ENABLE_PARAMETER_CHECKING)
312 if (cvmx_unlikely(queue_id >= CVMX_CMD_QUEUE_END))
314 if (cvmx_unlikely((queue_id & 0xffff) >= 256))
317 return &__cvmx_cmd_queue_state_ptr->state[__cvmx_cmd_queue_get_index(queue_id)];
322 * Write an arbitrary number of command words to a command queue.
323 * This is a generic function; the fixed number of comamnd word
324 * functions yield higher performance.
326 * @param queue_id Hardware command queue to write to
328 * Use internal locking to ensure exclusive access for queue
329 * updates. If you don't use this locking you must ensure
330 * exclusivity some other way. Locking is strongly recommended.
331 * @param cmd_count Number of command words to write
332 * @param cmds Array of comamnds to write
334 * @return CVMX_CMD_QUEUE_SUCCESS or a failure code
336 static inline cvmx_cmd_queue_result_t cvmx_cmd_queue_write(cvmx_cmd_queue_id_t queue_id, int use_locking, int cmd_count, uint64_t *cmds)
338 __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id);
340 if (CVMX_ENABLE_PARAMETER_CHECKING)
342 if (cvmx_unlikely(qptr == NULL))
343 return CVMX_CMD_QUEUE_INVALID_PARAM;
344 if (cvmx_unlikely((cmd_count < 1) || (cmd_count > 32)))
345 return CVMX_CMD_QUEUE_INVALID_PARAM;
346 if (cvmx_unlikely(cmds == NULL))
347 return CVMX_CMD_QUEUE_INVALID_PARAM;
350 /* Make sure nobody else is updating the same queue */
351 if (cvmx_likely(use_locking))
352 __cvmx_cmd_queue_lock(queue_id, qptr);
354 /* If a max queue length was specified then make sure we don't
355 exceed it. If any part of the command would be below the limit
357 if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH && cvmx_unlikely(qptr->max_depth))
359 if (cvmx_unlikely(cvmx_cmd_queue_length(queue_id) > (int)qptr->max_depth))
361 if (cvmx_likely(use_locking))
362 __cvmx_cmd_queue_unlock(qptr);
363 return CVMX_CMD_QUEUE_FULL;
367 /* Normally there is plenty of room in the current buffer for the command */
368 if (cvmx_likely(qptr->index + cmd_count < qptr->pool_size_m1))
370 uint64_t *ptr = (uint64_t *)cvmx_phys_to_ptr((uint64_t)qptr->base_ptr_div128<<7);
372 qptr->index += cmd_count;
380 /* We need a new comamnd buffer. Fail if there isn't one available */
381 uint64_t *new_buffer = (uint64_t *)cvmx_fpa_alloc(qptr->fpa_pool);
382 if (cvmx_unlikely(new_buffer == NULL))
384 if (cvmx_likely(use_locking))
385 __cvmx_cmd_queue_unlock(qptr);
386 return CVMX_CMD_QUEUE_NO_MEMORY;
388 ptr = (uint64_t *)cvmx_phys_to_ptr((uint64_t)qptr->base_ptr_div128<<7);
389 /* Figure out how many command words will fit in this buffer. One
390 location will be needed for the next buffer pointer */
391 count = qptr->pool_size_m1 - qptr->index;
396 *ptr = cvmx_ptr_to_phys(new_buffer);
397 /* The current buffer is full and has a link to the next buffer. Time
398 to write the rest of the commands into the new buffer */
399 qptr->base_ptr_div128 = *ptr >> 7;
400 qptr->index = cmd_count;
406 /* All updates are complete. Release the lock and return */
407 if (cvmx_likely(use_locking))
408 __cvmx_cmd_queue_unlock(qptr);
409 return CVMX_CMD_QUEUE_SUCCESS;
414 * Simple function to write two command words to a command
417 * @param queue_id Hardware command queue to write to
419 * Use internal locking to ensure exclusive access for queue
420 * updates. If you don't use this locking you must ensure
421 * exclusivity some other way. Locking is strongly recommended.
422 * @param cmd1 Command
423 * @param cmd2 Command
425 * @return CVMX_CMD_QUEUE_SUCCESS or a failure code
427 static inline cvmx_cmd_queue_result_t cvmx_cmd_queue_write2(cvmx_cmd_queue_id_t queue_id, int use_locking, uint64_t cmd1, uint64_t cmd2)
429 __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id);
431 if (CVMX_ENABLE_PARAMETER_CHECKING)
433 if (cvmx_unlikely(qptr == NULL))
434 return CVMX_CMD_QUEUE_INVALID_PARAM;
437 /* Make sure nobody else is updating the same queue */
438 if (cvmx_likely(use_locking))
439 __cvmx_cmd_queue_lock(queue_id, qptr);
441 /* If a max queue length was specified then make sure we don't
442 exceed it. If any part of the command would be below the limit
444 if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH && cvmx_unlikely(qptr->max_depth))
446 if (cvmx_unlikely(cvmx_cmd_queue_length(queue_id) > (int)qptr->max_depth))
448 if (cvmx_likely(use_locking))
449 __cvmx_cmd_queue_unlock(qptr);
450 return CVMX_CMD_QUEUE_FULL;
454 /* Normally there is plenty of room in the current buffer for the command */
455 if (cvmx_likely(qptr->index + 2 < qptr->pool_size_m1))
457 uint64_t *ptr = (uint64_t *)cvmx_phys_to_ptr((uint64_t)qptr->base_ptr_div128<<7);
466 /* Figure out how many command words will fit in this buffer. One
467 location will be needed for the next buffer pointer */
468 int count = qptr->pool_size_m1 - qptr->index;
469 /* We need a new comamnd buffer. Fail if there isn't one available */
470 uint64_t *new_buffer = (uint64_t *)cvmx_fpa_alloc(qptr->fpa_pool);
471 if (cvmx_unlikely(new_buffer == NULL))
473 if (cvmx_likely(use_locking))
474 __cvmx_cmd_queue_unlock(qptr);
475 return CVMX_CMD_QUEUE_NO_MEMORY;
478 ptr = (uint64_t *)cvmx_phys_to_ptr((uint64_t)qptr->base_ptr_div128<<7);
481 if (cvmx_likely(count))
483 *ptr = cvmx_ptr_to_phys(new_buffer);
484 /* The current buffer is full and has a link to the next buffer. Time
485 to write the rest of the commands into the new buffer */
486 qptr->base_ptr_div128 = *ptr >> 7;
488 if (cvmx_unlikely(count == 0))
491 new_buffer[0] = cmd2;
495 /* All updates are complete. Release the lock and return */
496 if (cvmx_likely(use_locking))
497 __cvmx_cmd_queue_unlock(qptr);
498 return CVMX_CMD_QUEUE_SUCCESS;
503 * Simple function to write three command words to a command
506 * @param queue_id Hardware command queue to write to
508 * Use internal locking to ensure exclusive access for queue
509 * updates. If you don't use this locking you must ensure
510 * exclusivity some other way. Locking is strongly recommended.
511 * @param cmd1 Command
512 * @param cmd2 Command
513 * @param cmd3 Command
515 * @return CVMX_CMD_QUEUE_SUCCESS or a failure code
517 static inline cvmx_cmd_queue_result_t cvmx_cmd_queue_write3(cvmx_cmd_queue_id_t queue_id, int use_locking, uint64_t cmd1, uint64_t cmd2, uint64_t cmd3)
519 __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id);
521 if (CVMX_ENABLE_PARAMETER_CHECKING)
523 if (cvmx_unlikely(qptr == NULL))
524 return CVMX_CMD_QUEUE_INVALID_PARAM;
527 /* Make sure nobody else is updating the same queue */
528 if (cvmx_likely(use_locking))
529 __cvmx_cmd_queue_lock(queue_id, qptr);
531 /* If a max queue length was specified then make sure we don't
532 exceed it. If any part of the command would be below the limit
534 if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH && cvmx_unlikely(qptr->max_depth))
536 if (cvmx_unlikely(cvmx_cmd_queue_length(queue_id) > (int)qptr->max_depth))
538 if (cvmx_likely(use_locking))
539 __cvmx_cmd_queue_unlock(qptr);
540 return CVMX_CMD_QUEUE_FULL;
544 /* Normally there is plenty of room in the current buffer for the command */
545 if (cvmx_likely(qptr->index + 3 < qptr->pool_size_m1))
547 uint64_t *ptr = (uint64_t *)cvmx_phys_to_ptr((uint64_t)qptr->base_ptr_div128<<7);
557 /* Figure out how many command words will fit in this buffer. One
558 location will be needed for the next buffer pointer */
559 int count = qptr->pool_size_m1 - qptr->index;
560 /* We need a new comamnd buffer. Fail if there isn't one available */
561 uint64_t *new_buffer = (uint64_t *)cvmx_fpa_alloc(qptr->fpa_pool);
562 if (cvmx_unlikely(new_buffer == NULL))
564 if (cvmx_likely(use_locking))
565 __cvmx_cmd_queue_unlock(qptr);
566 return CVMX_CMD_QUEUE_NO_MEMORY;
569 ptr = (uint64_t *)cvmx_phys_to_ptr((uint64_t)qptr->base_ptr_div128<<7);
578 *ptr = cvmx_ptr_to_phys(new_buffer);
579 /* The current buffer is full and has a link to the next buffer. Time
580 to write the rest of the commands into the new buffer */
581 qptr->base_ptr_div128 = *ptr >> 7;
596 /* All updates are complete. Release the lock and return */
597 if (cvmx_likely(use_locking))
598 __cvmx_cmd_queue_unlock(qptr);
599 return CVMX_CMD_QUEUE_SUCCESS;
606 #endif /* __CVMX_CMD_QUEUE_H__ */