]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/contrib/octeon-sdk/cvmx-pko.h
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / contrib / octeon-sdk / cvmx-pko.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  * Interface to the hardware Packet Output unit.
48  *
49  * Starting with SDK 1.7.0, the PKO output functions now support
50  * two types of locking. CVMX_PKO_LOCK_ATOMIC_TAG continues to
51  * function similarly to previous SDKs by using POW atomic tags
52  * to preserve ordering and exclusivity. As a new option, you
53  * can now pass CVMX_PKO_LOCK_CMD_QUEUE which uses a ll/sc
54  * memory based locking instead. This locking has the advantage
55  * of not affecting the tag state but doesn't preserve packet
56  * ordering. CVMX_PKO_LOCK_CMD_QUEUE is appropriate in most
57  * generic code while CVMX_PKO_LOCK_CMD_QUEUE should be used
58  * with hand tuned fast path code.
59  *
60  * Some of other SDK differences visible to the command command
61  * queuing:
62  * - PKO indexes are no longer stored in the FAU. A large
63  *   percentage of the FAU register block used to be tied up
64  *   maintaining PKO queue pointers. These are now stored in a
65  *   global named block.
66  * - The PKO <b>use_locking</b> parameter can now have a global
67  *   effect. Since all application use the same named block,
68  *   queue locking correctly applies across all operating
69  *   systems when using CVMX_PKO_LOCK_CMD_QUEUE.
70  * - PKO 3 word commands are now supported. Use
71  *   cvmx_pko_send_packet_finish3().
72  *
73  * <hr>$Revision: 42150 $<hr>
74  */
75
76
77 #ifndef __CVMX_PKO_H__
78 #define __CVMX_PKO_H__
79
80 #ifndef CVMX_DONT_INCLUDE_CONFIG
81 #include "executive-config.h"
82 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
83 #include "cvmx-config.h"
84 #endif
85 #endif
86
87 #include "cvmx-cvmmem.h"
88 #include "cvmx-fau.h"
89 #include "cvmx-fpa.h"
90 #include "cvmx-pow.h"
91 #include "cvmx-cmd-queue.h"
92
93 /* Adjust the command buffer size by 1 word so that in the case of using only
94 ** two word PKO commands no command words stradle buffers.  The useful values
95 ** for this are 0 and 1. */
96 #define CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST (1)
97
98 #ifdef  __cplusplus
99 extern "C" {
100 #endif
101
102 #define CVMX_PKO_MAX_OUTPUT_QUEUES_STATIC 256
103 #define CVMX_PKO_MAX_OUTPUT_QUEUES      ((OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN3010) || OCTEON_IS_MODEL(OCTEON_CN3005) || OCTEON_IS_MODEL(OCTEON_CN50XX)) ? 32 : (OCTEON_IS_MODEL(OCTEON_CN58XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) ? 256 : 128)
104 #define CVMX_PKO_NUM_OUTPUT_PORTS       40
105 #define CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID 63 // use this for queues that are not used
106 #define CVMX_PKO_QUEUE_STATIC_PRIORITY  9
107 #define CVMX_PKO_ILLEGAL_QUEUE  0xFFFF
108 #define CVMX_PKO_MAX_QUEUE_DEPTH 0
109
110 typedef enum
111 {
112     CVMX_PKO_SUCCESS,
113     CVMX_PKO_INVALID_PORT,
114     CVMX_PKO_INVALID_QUEUE,
115     CVMX_PKO_INVALID_PRIORITY,
116     CVMX_PKO_NO_MEMORY,
117     CVMX_PKO_PORT_ALREADY_SETUP,
118     CVMX_PKO_CMD_QUEUE_INIT_ERROR
119 } cvmx_pko_status_t;
120
121 /**
122  * This enumeration represents the differnet locking modes supported by PKO.
123  */
124 typedef enum
125 {
126     CVMX_PKO_LOCK_NONE = 0,         /**< PKO doesn't do any locking. It is the responsibility
127                                         of the application to make sure that no other core is
128                                         accessing the same queue at the smae time */
129     CVMX_PKO_LOCK_ATOMIC_TAG = 1,   /**< PKO performs an atomic tagswitch to insure exclusive
130                                         access to the output queue. This will maintain
131                                         packet ordering on output */
132     CVMX_PKO_LOCK_CMD_QUEUE = 2,    /**< PKO uses the common command queue locks to insure
133                                         exclusive access to the output queue. This is a memory
134                                         based ll/sc. This is the most portable locking
135                                         mechanism */
136 } cvmx_pko_lock_t;
137
138 typedef struct
139 {
140     uint32_t    packets;
141     uint64_t    octets;
142   uint64_t doorbell;
143 } cvmx_pko_port_status_t;
144
145 /**
146  * This structure defines the address to use on a packet enqueue
147  */
148 typedef union
149 {
150     uint64_t                u64;
151     struct
152     {
153         cvmx_mips_space_t   mem_space   : 2;    /**< Must CVMX_IO_SEG */
154         uint64_t            reserved    :13;    /**< Must be zero */
155         uint64_t            is_io       : 1;    /**< Must be one */
156         uint64_t            did         : 8;    /**< The ID of the device on the non-coherent bus */
157         uint64_t            reserved2   : 4;    /**< Must be zero */
158         uint64_t            reserved3   :18;    /**< Must be zero */
159         uint64_t            port        : 6;    /**< The hardware likes to have the output port in addition to the output queue */
160         uint64_t            queue       : 9;    /**< The output queue to send the packet to (0-127 are legal) */
161         uint64_t            reserved4   : 3;    /**< Must be zero */
162    } s;
163 } cvmx_pko_doorbell_address_t;
164
165 /**
166  * Structure of the first packet output command word.
167  */
168 typedef union
169 {
170     uint64_t                u64;
171     struct
172     {
173         cvmx_fau_op_size_t  size1       : 2; /**< The size of the reg1 operation - could be 8, 16, 32, or 64 bits */
174         cvmx_fau_op_size_t  size0       : 2; /**< The size of the reg0 operation - could be 8, 16, 32, or 64 bits */
175         uint64_t            subone1     : 1; /**< If set, subtract 1, if clear, subtract packet size */
176         uint64_t            reg1        :11; /**< The register, subtract will be done if reg1 is non-zero */
177         uint64_t            subone0     : 1; /**< If set, subtract 1, if clear, subtract packet size */
178         uint64_t            reg0        :11; /**< The register, subtract will be done if reg0 is non-zero */
179         uint64_t            le          : 1; /**< When set, interpret segment pointer and segment bytes in little endian order */
180         uint64_t            n2          : 1; /**< When set, packet data not allocated in L2 cache by PKO */
181         uint64_t            wqp         : 1; /**< If set and rsp is set, word3 contains a pointer to a work queue entry */
182         uint64_t            rsp         : 1; /**< If set, the hardware will send a response when done */
183         uint64_t            gather      : 1; /**< If set, the supplied pkt_ptr is really a pointer to a list of pkt_ptr's */
184         uint64_t            ipoffp1     : 7; /**< If ipoffp1 is non zero, (ipoffp1-1) is the number of bytes to IP header,
185                                                 and the hardware will calculate and insert the  UDP/TCP checksum */
186         uint64_t            ignore_i    : 1; /**< If set, ignore the I bit (force to zero) from all pointer structures */
187         uint64_t            dontfree    : 1; /**< If clear, the hardware will attempt to free the buffers containing the packet */
188         uint64_t            segs        : 6; /**< The total number of segs in the packet, if gather set, also gather list length */
189         uint64_t            total_bytes :16; /**< Including L2, but no trailing CRC */
190     } s;
191 } cvmx_pko_command_word0_t;
192
193 /* CSR typedefs have been moved to cvmx-csr-*.h */
194
195 /**
196  * Definition of internal state for Packet output processing
197  */
198 typedef struct
199 {
200     uint64_t *      start_ptr;          /**< ptr to start of buffer, offset kept in FAU reg */
201 } cvmx_pko_state_elem_t;
202
203
204 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
205 /**
206  * Call before any other calls to initialize the packet
207  * output system.
208  */
209 extern void cvmx_pko_initialize_global(void);
210 extern int cvmx_pko_initialize_local(void);
211
212 #endif
213
214
215 /**
216  * Enables the packet output hardware. It must already be
217  * configured.
218  */
219 extern void cvmx_pko_enable(void);
220
221
222 /**
223  * Disables the packet output. Does not affect any configuration.
224  */
225 extern void cvmx_pko_disable(void);
226
227
228 /**
229  * Shutdown and free resources required by packet output.
230  */
231
232 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
233 extern void cvmx_pko_shutdown(void);
234 #endif
235
236 /**
237  * Configure a output port and the associated queues for use.
238  *
239  * @param port       Port to configure.
240  * @param base_queue First queue number to associate with this port.
241  * @param num_queues Number of queues t oassociate with this port
242  * @param priority   Array of priority levels for each queue. Values are
243  *                   allowed to be 1-8. A value of 8 get 8 times the traffic
244  *                   of a value of 1. There must be num_queues elements in the
245  *                   array.
246  */
247 extern cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue, uint64_t num_queues, const uint64_t priority[]);
248
249
250 /**
251  * Ring the packet output doorbell. This tells the packet
252  * output hardware that "len" command words have been added
253  * to its pending list.  This command includes the required
254  * CVMX_SYNCWS before the doorbell ring.
255  *
256  * @param port   Port the packet is for
257  * @param queue  Queue the packet is for
258  * @param len    Length of the command in 64 bit words
259  */
260 static inline void cvmx_pko_doorbell(uint64_t port, uint64_t queue, uint64_t len)
261 {
262    cvmx_pko_doorbell_address_t ptr;
263
264    ptr.u64          = 0;
265    ptr.s.mem_space  = CVMX_IO_SEG;
266    ptr.s.did        = CVMX_OCT_DID_PKT_SEND;
267    ptr.s.is_io      = 1;
268    ptr.s.port       = port;
269    ptr.s.queue      = queue;
270    CVMX_SYNCWS;  /* Need to make sure output queue data is in DRAM before doorbell write */
271    cvmx_write_io(ptr.u64, len);
272 }
273
274
275 /**
276  * Prepare to send a packet.  This may initiate a tag switch to
277  * get exclusive access to the output queue structure, and
278  * performs other prep work for the packet send operation.
279  *
280  * cvmx_pko_send_packet_finish() MUST be called after this function is called,
281  * and must be called with the same port/queue/use_locking arguments.
282  *
283  * The use_locking parameter allows the caller to use three
284  * possible locking modes.
285  * - CVMX_PKO_LOCK_NONE
286  *      - PKO doesn't do any locking. It is the responsibility
287  *          of the application to make sure that no other core
288  *          is accessing the same queue at the smae time.
289  * - CVMX_PKO_LOCK_ATOMIC_TAG
290  *      - PKO performs an atomic tagswitch to insure exclusive
291  *          access to the output queue. This will maintain
292  *          packet ordering on output.
293  * - CVMX_PKO_LOCK_CMD_QUEUE
294  *      - PKO uses the common command queue locks to insure
295  *          exclusive access to the output queue. This is a
296  *          memory based ll/sc. This is the most portable
297  *          locking mechanism.
298  *
299  * NOTE: If atomic locking is used, the POW entry CANNOT be
300  * descheduled, as it does not contain a valid WQE pointer.
301  *
302  * @param port   Port to send it on
303  * @param queue  Queue to use
304  * @param use_locking
305  *               CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE
306  */
307 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
308 static inline void cvmx_pko_send_packet_prepare(uint64_t port, uint64_t queue, cvmx_pko_lock_t use_locking)
309 {
310     if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG)
311     {
312         /* Must do a full switch here to handle all cases.  We use a fake WQE pointer, as the POW does
313         ** not access this memory.  The WQE pointer and group are only used if this work is descheduled,
314         ** which is not supported by the cvmx_pko_send_packet_prepare/cvmx_pko_send_packet_finish combination.
315         ** Note that this is a special case in which these fake values can be used - this is not a general technique.
316         */
317         uint32_t tag = CVMX_TAG_SW_BITS_INTERNAL << CVMX_TAG_SW_SHIFT | CVMX_TAG_SUBGROUP_PKO  << CVMX_TAG_SUBGROUP_SHIFT | (CVMX_TAG_SUBGROUP_MASK & queue);
318         cvmx_pow_tag_sw_full((cvmx_wqe_t *)cvmx_phys_to_ptr(0x80), tag, CVMX_POW_TAG_TYPE_ATOMIC, 0);
319     }
320 }
321
322
323 /**
324  * Complete packet output. cvmx_pko_send_packet_prepare() must be called exactly once before this,
325  * and the same parameters must be passed to both cvmx_pko_send_packet_prepare() and
326  * cvmx_pko_send_packet_finish().
327  *
328  * @param port   Port to send it on
329  * @param queue  Queue to use
330  * @param pko_command
331  *               PKO HW command word
332  * @param packet Packet to send
333  * @param use_locking
334  *               CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE
335  *
336  * @return returns CVMX_PKO_SUCCESS on success, or error code on failure of output
337  */
338 static inline cvmx_pko_status_t cvmx_pko_send_packet_finish(uint64_t port, uint64_t queue,
339                                         cvmx_pko_command_word0_t pko_command,
340                                         cvmx_buf_ptr_t packet, cvmx_pko_lock_t use_locking)
341 {
342     cvmx_cmd_queue_result_t result;
343     if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG)
344         cvmx_pow_tag_sw_wait();
345     result = cvmx_cmd_queue_write2(CVMX_CMD_QUEUE_PKO(queue),
346                                    (use_locking == CVMX_PKO_LOCK_CMD_QUEUE),
347                                    pko_command.u64,
348                                    packet.u64);
349     if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS))
350     {
351         cvmx_pko_doorbell(port, queue, 2);
352         return CVMX_PKO_SUCCESS;
353     }
354     else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == CVMX_CMD_QUEUE_FULL))
355     {
356         return CVMX_PKO_NO_MEMORY;
357     }
358     else
359     {
360         return CVMX_PKO_INVALID_QUEUE;
361     }
362 }
363
364
365 /**
366  * Complete packet output. cvmx_pko_send_packet_prepare() must be called exactly once before this,
367  * and the same parameters must be passed to both cvmx_pko_send_packet_prepare() and
368  * cvmx_pko_send_packet_finish().
369  *
370  * @param port   Port to send it on
371  * @param queue  Queue to use
372  * @param pko_command
373  *               PKO HW command word
374  * @param packet Packet to send
375  * @param addr   Plysical address of a work queue entry or physical address to zero on complete.
376  * @param use_locking
377  *               CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE
378  *
379  * @return returns CVMX_PKO_SUCCESS on success, or error code on failure of output
380  */
381 static inline cvmx_pko_status_t cvmx_pko_send_packet_finish3(uint64_t port, uint64_t queue,
382                                         cvmx_pko_command_word0_t pko_command,
383                                         cvmx_buf_ptr_t packet, uint64_t addr, cvmx_pko_lock_t use_locking)
384 {
385     cvmx_cmd_queue_result_t result;
386     if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG)
387         cvmx_pow_tag_sw_wait();
388     result = cvmx_cmd_queue_write3(CVMX_CMD_QUEUE_PKO(queue),
389                                    (use_locking == CVMX_PKO_LOCK_CMD_QUEUE),
390                                    pko_command.u64,
391                                    packet.u64,
392                                    addr);
393     if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS))
394     {
395         cvmx_pko_doorbell(port, queue, 3);
396         return CVMX_PKO_SUCCESS;
397     }
398     else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == CVMX_CMD_QUEUE_FULL))
399     {
400         return CVMX_PKO_NO_MEMORY;
401     }
402     else
403     {
404         return CVMX_PKO_INVALID_QUEUE;
405     }
406 }
407
408 /**
409  * Return the pko output queue associated with a port and a specific core.
410  * In normal mode (PKO lockless operation is disabled), the value returned
411  * is the base queue.
412  *
413  * @param port   Port number
414  * @param core   Core to get queue for
415  *
416  * @return Core-specific output queue
417  */
418 static inline int cvmx_pko_get_base_queue_per_core(int port, int core)
419 {
420 #ifndef CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0
421     #define CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0 16
422 #endif
423 #ifndef CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1
424     #define CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1 16
425 #endif
426     if (port < CVMX_PKO_MAX_PORTS_INTERFACE0)
427         return port * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + core;
428     else if (port >=16 && port < 16 + CVMX_PKO_MAX_PORTS_INTERFACE1)
429         return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 +
430                (port-16) * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + core;
431     else if ((port >= 32) && (port < 36))
432         return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 +
433                CVMX_PKO_MAX_PORTS_INTERFACE1 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 +
434                (port-32) * CVMX_PKO_QUEUES_PER_PORT_PCI;
435     else if ((port >= 36) && (port < 40))
436         return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 +
437                CVMX_PKO_MAX_PORTS_INTERFACE1 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 +
438                4 * CVMX_PKO_QUEUES_PER_PORT_PCI +
439                (port-36) * CVMX_PKO_QUEUES_PER_PORT_LOOP;
440     else
441         /* Given the limit on the number of ports we can map to
442          * CVMX_MAX_OUTPUT_QUEUES_STATIC queues (currently 256,
443          * divided among all cores), the remaining unmapped ports
444          * are assigned an illegal queue number */
445         return CVMX_PKO_ILLEGAL_QUEUE;
446 }
447
448 /**
449  * For a given port number, return the base pko output queue
450  * for the port.
451  *
452  * @param port   Port number
453  * @return Base output queue
454  */
455 static inline int cvmx_pko_get_base_queue(int port)
456 {
457     return cvmx_pko_get_base_queue_per_core(port, 0);
458 }
459
460 /**
461  * For a given port number, return the number of pko output queues.
462  *
463  * @param port   Port number
464  * @return Number of output queues
465  */
466 static inline int cvmx_pko_get_num_queues(int port)
467 {
468     if (port < 16)
469         return CVMX_PKO_QUEUES_PER_PORT_INTERFACE0;
470     else if (port<32)
471         return CVMX_PKO_QUEUES_PER_PORT_INTERFACE1;
472     else if (port<36)
473         return CVMX_PKO_QUEUES_PER_PORT_PCI;
474     else if (port<40)
475         return CVMX_PKO_QUEUES_PER_PORT_LOOP;
476     else
477         return 0;
478 }
479
480 /**
481  * Get the status counters for a port.
482  *
483  * @param port_num Port number to get statistics for.
484  * @param clear    Set to 1 to clear the counters after they are read
485  * @param status   Where to put the results.
486  */
487 static inline void cvmx_pko_get_port_status(uint64_t port_num, uint64_t clear, cvmx_pko_port_status_t *status)
488 {
489     cvmx_pko_reg_read_idx_t pko_reg_read_idx;
490     cvmx_pko_mem_count0_t pko_mem_count0;
491     cvmx_pko_mem_count1_t pko_mem_count1;
492
493     pko_reg_read_idx.u64 = 0;
494     pko_reg_read_idx.s.index = port_num;
495     cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64);
496
497     pko_mem_count0.u64 = cvmx_read_csr(CVMX_PKO_MEM_COUNT0);
498     status->packets = pko_mem_count0.s.count;
499     if (clear)
500     {
501         pko_mem_count0.s.count = port_num;
502         cvmx_write_csr(CVMX_PKO_MEM_COUNT0, pko_mem_count0.u64);
503     }
504
505     pko_mem_count1.u64 = cvmx_read_csr(CVMX_PKO_MEM_COUNT1);
506     status->octets = pko_mem_count1.s.count;
507     if (clear)
508     {
509         pko_mem_count1.s.count = port_num;
510         cvmx_write_csr(CVMX_PKO_MEM_COUNT1, pko_mem_count1.u64);
511     }
512
513     if (OCTEON_IS_MODEL(OCTEON_CN3XXX))
514     {
515         cvmx_pko_mem_debug9_t debug9;
516         pko_reg_read_idx.s.index = cvmx_pko_get_base_queue(port_num);
517         cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64);
518         debug9.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG9);
519         status->doorbell = debug9.cn38xx.doorbell;
520     }
521     else
522     {
523         cvmx_pko_mem_debug8_t debug8;
524         pko_reg_read_idx.s.index = cvmx_pko_get_base_queue(port_num);
525         cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64);
526         debug8.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG8);
527         status->doorbell = debug8.cn58xx.doorbell;
528     }
529 }
530
531
532 /**
533  * Rate limit a PKO port to a max packets/sec. This function is only
534  * supported on CN57XX, CN56XX, CN55XX, and CN54XX.
535  *
536  * @param port      Port to rate limit
537  * @param packets_s Maximum packet/sec
538  * @param burst     Maximum number of packets to burst in a row before rate
539  *                  limiting cuts in.
540  *
541  * @return Zero on success, negative on failure
542  */
543 extern int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst);
544
545 /**
546  * Rate limit a PKO port to a max bits/sec. This function is only
547  * supported on CN57XX, CN56XX, CN55XX, and CN54XX.
548  *
549  * @param port   Port to rate limit
550  * @param bits_s PKO rate limit in bits/sec
551  * @param burst  Maximum number of bits to burst before rate
552  *               limiting cuts in.
553  *
554  * @return Zero on success, negative on failure
555  */
556 extern int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst);
557
558 #endif /* CVMX_ENABLE_PKO_FUNCTIONS */
559
560 #ifdef  __cplusplus
561 }
562 #endif
563
564 #endif   /* __CVMX_PKO_H__ */