]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sys/contrib/octeon-sdk/cvmx-cmd-queue.h
MFC r362623:
[FreeBSD/stable/8.git] / sys / contrib / octeon-sdk / cvmx-cmd-queue.h
1 /***********************license start***************
2  *  Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
3  *  reserved.
4  *
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions are
8  *  met:
9  *
10  *      * Redistributions of source code must retain the above copyright
11  *        notice, this list of conditions and the following disclaimer.
12  *
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.
17  *
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
21  *        permission.
22  *
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.
33  *
34  *
35  *  For any questions regarding licensing please contact marketing@caviumnetworks.com
36  *
37  ***********************license end**************************************/
38
39
40
41
42
43
44 /**
45  * @file
46  *
47  * Support functions for managing command queues used for
48  * various hardware blocks.
49  *
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
60  * commands.
61  *
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.
65  *
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
78  * cache area.
79  *
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
87  * bus traffic.
88  *
89  * <hr> $Revision: 42150 $ <hr>
90  */
91
92 #ifndef __CVMX_CMD_QUEUE_H__
93 #define __CVMX_CMD_QUEUE_H__
94
95 #ifndef CVMX_DONT_INCLUDE_CONFIG
96 #include "executive-config.h"
97 #include "cvmx-config.h"
98 #endif
99 #include "cvmx-fpa.h"
100
101 #ifdef  __cplusplus
102 extern "C" {
103 #endif
104
105 /**
106  * By default we disable the max depth support. Most programs
107  * don't use it and it slows down the command queue processing
108  * significantly.
109  */
110 #ifndef CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH
111 #define CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH 0
112 #endif
113
114 /**
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
118  * units.
119  */
120 typedef enum
121 {
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;
131
132 /**
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.
137  */
138 typedef enum
139 {
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;
146
147 typedef struct
148 {
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;
158
159 /**
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.
166  */
167 typedef struct
168 {
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;
172
173 extern CVMX_SHARED __cvmx_cmd_queue_all_state_t *__cvmx_cmd_queue_state_ptr;
174
175 /**
176  * Initialize a command queue for use. The initial FPA buffer is
177  * allocated and the hardware unit is configured to point to the
178  * new command queue.
179  *
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)
184  *
185  * @return CVMX_CMD_QUEUE_SUCCESS or a failure code
186  */
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);
188
189 /**
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.
193  *
194  * @param queue_id Queue to shutdown
195  *
196  * @return CVMX_CMD_QUEUE_SUCCESS or a failure code
197  */
198 cvmx_cmd_queue_result_t cvmx_cmd_queue_shutdown(cvmx_cmd_queue_id_t queue_id);
199
200 /**
201  * Return the number of command words pending in the queue. This
202  * function may be relatively slow for some hardware units.
203  *
204  * @param queue_id Hardware command queue to query
205  *
206  * @return Number of outstanding commands
207  */
208 int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id);
209
210 /**
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
214  * function directly.
215  *
216  * @param queue_id Command queue to query
217  *
218  * @return Command buffer or NULL on failure
219  */
220 void *cvmx_cmd_queue_buffer(cvmx_cmd_queue_id_t queue_id);
221
222 /**
223  * @INTERNAL
224  * Get the index into the state arrays for the supplied queue id.
225  *
226  * @param queue_id Queue ID to get an index for
227  *
228  * @return Index into the state arrays
229  */
230 static inline int __cvmx_cmd_queue_get_index(cvmx_cmd_queue_id_t queue_id)
231 {
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;
240 }
241
242
243 /**
244  * @INTERNAL
245  * Lock the supplied queue so nobody else is updating it at the same
246  * time as us.
247  *
248  * @param queue_id Queue ID to lock
249  * @param qptr     Pointer to the queue's global state
250  */
251 static inline void __cvmx_cmd_queue_lock(cvmx_cmd_queue_id_t queue_id, __cvmx_cmd_queue_state_t *qptr)
252 {
253     int tmp;
254     int my_ticket;
255     CVMX_PREFETCH(qptr, 0);
256     asm volatile (
257         ".set push\n"
258         ".set noreorder\n"
259         "1:\n"
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"
265         " nop\n"
266         "lbu    %[ticket], %[now_serving]\n"            /* Load the current now_serving ticket */
267         "2:\n"
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 */
272         "3:\n"
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 */
277         "4:\n"
278         ".set pop\n"
279         : [ticket_ptr] "=m" (__cvmx_cmd_queue_state_ptr->ticket[__cvmx_cmd_queue_get_index(queue_id)]),
280           [now_serving] "=m" (qptr->now_serving),
281           [ticket] "=r" (tmp),
282           [my_ticket] "=r" (my_ticket)
283     );
284 }
285
286
287 /**
288  * @INTERNAL
289  * Unlock the queue, flushing all writes.
290  *
291  * @param qptr   Queue to unlock
292  */
293 static inline void __cvmx_cmd_queue_unlock(__cvmx_cmd_queue_state_t *qptr)
294 {
295     qptr->now_serving++;
296     CVMX_SYNCWS;
297 }
298
299
300 /**
301  * @INTERNAL
302  * Get the queue state structure for the given queue id
303  *
304  * @param queue_id Queue id to get
305  *
306  * @return Queue structure or NULL on failure
307  */
308 static inline __cvmx_cmd_queue_state_t *__cvmx_cmd_queue_get_state(cvmx_cmd_queue_id_t queue_id)
309 {
310     if (CVMX_ENABLE_PARAMETER_CHECKING)
311     {
312         if (cvmx_unlikely(queue_id >= CVMX_CMD_QUEUE_END))
313             return NULL;
314         if (cvmx_unlikely((queue_id & 0xffff) >= 256))
315             return NULL;
316     }
317     return &__cvmx_cmd_queue_state_ptr->state[__cvmx_cmd_queue_get_index(queue_id)];
318 }
319
320
321 /**
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.
325  *
326  * @param queue_id  Hardware command queue to write to
327  * @param use_locking
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
333  *
334  * @return CVMX_CMD_QUEUE_SUCCESS or a failure code
335  */
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)
337 {
338     __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id);
339
340     if (CVMX_ENABLE_PARAMETER_CHECKING)
341     {
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;
348     }
349
350     /* Make sure nobody else is updating the same queue */
351     if (cvmx_likely(use_locking))
352         __cvmx_cmd_queue_lock(queue_id, qptr);
353
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
356         we allow it */
357     if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH && cvmx_unlikely(qptr->max_depth))
358     {
359         if (cvmx_unlikely(cvmx_cmd_queue_length(queue_id) > (int)qptr->max_depth))
360         {
361             if (cvmx_likely(use_locking))
362                 __cvmx_cmd_queue_unlock(qptr);
363             return CVMX_CMD_QUEUE_FULL;
364         }
365     }
366
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))
369     {
370         uint64_t *ptr = (uint64_t *)cvmx_phys_to_ptr((uint64_t)qptr->base_ptr_div128<<7);
371         ptr += qptr->index;
372         qptr->index += cmd_count;
373         while (cmd_count--)
374             *ptr++ = *cmds++;
375     }
376     else
377     {
378         uint64_t *ptr;
379         int 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))
383         {
384             if (cvmx_likely(use_locking))
385                 __cvmx_cmd_queue_unlock(qptr);
386             return CVMX_CMD_QUEUE_NO_MEMORY;
387         }
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;
392         ptr += qptr->index;
393         cmd_count-=count;
394         while (count--)
395             *ptr++ = *cmds++;
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;
401         ptr = new_buffer;
402         while (cmd_count--)
403             *ptr++ = *cmds++;
404     }
405
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;
410 }
411
412
413 /**
414  * Simple function to write two command words to a command
415  * queue.
416  *
417  * @param queue_id Hardware command queue to write to
418  * @param use_locking
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
424  *
425  * @return CVMX_CMD_QUEUE_SUCCESS or a failure code
426  */
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)
428 {
429     __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id);
430
431     if (CVMX_ENABLE_PARAMETER_CHECKING)
432     {
433         if (cvmx_unlikely(qptr == NULL))
434             return CVMX_CMD_QUEUE_INVALID_PARAM;
435     }
436
437     /* Make sure nobody else is updating the same queue */
438     if (cvmx_likely(use_locking))
439         __cvmx_cmd_queue_lock(queue_id, qptr);
440
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
443         we allow it */
444     if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH && cvmx_unlikely(qptr->max_depth))
445     {
446         if (cvmx_unlikely(cvmx_cmd_queue_length(queue_id) > (int)qptr->max_depth))
447         {
448             if (cvmx_likely(use_locking))
449                 __cvmx_cmd_queue_unlock(qptr);
450             return CVMX_CMD_QUEUE_FULL;
451         }
452     }
453
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))
456     {
457         uint64_t *ptr = (uint64_t *)cvmx_phys_to_ptr((uint64_t)qptr->base_ptr_div128<<7);
458         ptr += qptr->index;
459         qptr->index += 2;
460         ptr[0] = cmd1;
461         ptr[1] = cmd2;
462     }
463     else
464     {
465         uint64_t *ptr;
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))
472         {
473             if (cvmx_likely(use_locking))
474                 __cvmx_cmd_queue_unlock(qptr);
475             return CVMX_CMD_QUEUE_NO_MEMORY;
476         }
477         count--;
478         ptr = (uint64_t *)cvmx_phys_to_ptr((uint64_t)qptr->base_ptr_div128<<7);
479         ptr += qptr->index;
480         *ptr++ = cmd1;
481         if (cvmx_likely(count))
482             *ptr++ = cmd2;
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;
487         qptr->index = 0;
488         if (cvmx_unlikely(count == 0))
489         {
490             qptr->index = 1;
491             new_buffer[0] = cmd2;
492         }
493     }
494
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;
499 }
500
501
502 /**
503  * Simple function to write three command words to a command
504  * queue.
505  *
506  * @param queue_id Hardware command queue to write to
507  * @param use_locking
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
514  *
515  * @return CVMX_CMD_QUEUE_SUCCESS or a failure code
516  */
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)
518 {
519     __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id);
520
521     if (CVMX_ENABLE_PARAMETER_CHECKING)
522     {
523         if (cvmx_unlikely(qptr == NULL))
524             return CVMX_CMD_QUEUE_INVALID_PARAM;
525     }
526
527     /* Make sure nobody else is updating the same queue */
528     if (cvmx_likely(use_locking))
529         __cvmx_cmd_queue_lock(queue_id, qptr);
530
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
533         we allow it */
534     if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH && cvmx_unlikely(qptr->max_depth))
535     {
536         if (cvmx_unlikely(cvmx_cmd_queue_length(queue_id) > (int)qptr->max_depth))
537         {
538             if (cvmx_likely(use_locking))
539                 __cvmx_cmd_queue_unlock(qptr);
540             return CVMX_CMD_QUEUE_FULL;
541         }
542     }
543
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))
546     {
547         uint64_t *ptr = (uint64_t *)cvmx_phys_to_ptr((uint64_t)qptr->base_ptr_div128<<7);
548         ptr += qptr->index;
549         qptr->index += 3;
550         ptr[0] = cmd1;
551         ptr[1] = cmd2;
552         ptr[2] = cmd3;
553     }
554     else
555     {
556         uint64_t *ptr;
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))
563         {
564             if (cvmx_likely(use_locking))
565                 __cvmx_cmd_queue_unlock(qptr);
566             return CVMX_CMD_QUEUE_NO_MEMORY;
567         }
568         count--;
569         ptr = (uint64_t *)cvmx_phys_to_ptr((uint64_t)qptr->base_ptr_div128<<7);
570         ptr += qptr->index;
571         *ptr++ = cmd1;
572         if (count)
573         {
574             *ptr++ = cmd2;
575             if (count > 1)
576                 *ptr++ = cmd3;
577         }
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;
582         qptr->index = 0;
583         ptr = new_buffer;
584         if (count == 0)
585         {
586             *ptr++ = cmd2;
587             qptr->index++;
588         }
589         if (count < 2)
590         {
591             *ptr++ = cmd3;
592             qptr->index++;
593         }
594     }
595
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;
600 }
601
602 #ifdef  __cplusplus
603 }
604 #endif
605
606 #endif /* __CVMX_CMD_QUEUE_H__ */