Back to home page

OSCL-LXR

 
 

    


0001 /***********************license start***************
0002  * Author: Cavium Networks
0003  *
0004  * Contact: support@caviumnetworks.com
0005  * This file is part of the OCTEON SDK
0006  *
0007  * Copyright (c) 2003-2008 Cavium Networks
0008  *
0009  * This file is free software; you can redistribute it and/or modify
0010  * it under the terms of the GNU General Public License, Version 2, as
0011  * published by the Free Software Foundation.
0012  *
0013  * This file is distributed in the hope that it will be useful, but
0014  * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
0015  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
0016  * NONINFRINGEMENT.  See the GNU General Public License for more
0017  * details.
0018  *
0019  * You should have received a copy of the GNU General Public License
0020  * along with this file; if not, write to the Free Software
0021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
0022  * or visit http://www.gnu.org/licenses/.
0023  *
0024  * This file may also be available under a different license from Cavium.
0025  * Contact Cavium Networks for more information
0026  ***********************license end**************************************/
0027 
0028 /**
0029  *
0030  * Interface to the hardware Packet Output unit.
0031  *
0032  * Starting with SDK 1.7.0, the PKO output functions now support
0033  * two types of locking. CVMX_PKO_LOCK_ATOMIC_TAG continues to
0034  * function similarly to previous SDKs by using POW atomic tags
0035  * to preserve ordering and exclusivity. As a new option, you
0036  * can now pass CVMX_PKO_LOCK_CMD_QUEUE which uses a ll/sc
0037  * memory based locking instead. This locking has the advantage
0038  * of not affecting the tag state but doesn't preserve packet
0039  * ordering. CVMX_PKO_LOCK_CMD_QUEUE is appropriate in most
0040  * generic code while CVMX_PKO_LOCK_CMD_QUEUE should be used
0041  * with hand tuned fast path code.
0042  *
0043  * Some of other SDK differences visible to the command queuing:
0044  * - PKO indexes are no longer stored in the FAU. A large
0045  *   percentage of the FAU register block used to be tied up
0046  *   maintaining PKO queue pointers. These are now stored in a
0047  *   global named block.
0048  * - The PKO <b>use_locking</b> parameter can now have a global
0049  *   effect. Since all application use the same named block,
0050  *   queue locking correctly applies across all operating
0051  *   systems when using CVMX_PKO_LOCK_CMD_QUEUE.
0052  * - PKO 3 word commands are now supported. Use
0053  *   cvmx_pko_send_packet_finish3().
0054  *
0055  */
0056 
0057 #ifndef __CVMX_PKO_H__
0058 #define __CVMX_PKO_H__
0059 
0060 #include <asm/octeon/cvmx-fpa.h>
0061 #include <asm/octeon/cvmx-pow.h>
0062 #include <asm/octeon/cvmx-cmd-queue.h>
0063 #include <asm/octeon/cvmx-pko-defs.h>
0064 
0065 /* Adjust the command buffer size by 1 word so that in the case of using only
0066  * two word PKO commands no command words stradle buffers.  The useful values
0067  * for this are 0 and 1. */
0068 #define CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST (1)
0069 
0070 #define CVMX_PKO_MAX_OUTPUT_QUEUES_STATIC 256
0071 #define CVMX_PKO_MAX_OUTPUT_QUEUES  ((OCTEON_IS_MODEL(OCTEON_CN31XX) || \
0072     OCTEON_IS_MODEL(OCTEON_CN3010) || OCTEON_IS_MODEL(OCTEON_CN3005) || \
0073     OCTEON_IS_MODEL(OCTEON_CN50XX)) ? 32 : \
0074         (OCTEON_IS_MODEL(OCTEON_CN58XX) || \
0075         OCTEON_IS_MODEL(OCTEON_CN56XX)) ? 256 : 128)
0076 #define CVMX_PKO_NUM_OUTPUT_PORTS   40
0077 /* use this for queues that are not used */
0078 #define CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID 63
0079 #define CVMX_PKO_QUEUE_STATIC_PRIORITY  9
0080 #define CVMX_PKO_ILLEGAL_QUEUE  0xFFFF
0081 #define CVMX_PKO_MAX_QUEUE_DEPTH 0
0082 
0083 typedef enum {
0084     CVMX_PKO_SUCCESS,
0085     CVMX_PKO_INVALID_PORT,
0086     CVMX_PKO_INVALID_QUEUE,
0087     CVMX_PKO_INVALID_PRIORITY,
0088     CVMX_PKO_NO_MEMORY,
0089     CVMX_PKO_PORT_ALREADY_SETUP,
0090     CVMX_PKO_CMD_QUEUE_INIT_ERROR
0091 } cvmx_pko_status_t;
0092 
0093 /**
0094  * This enumeration represents the differnet locking modes supported by PKO.
0095  */
0096 typedef enum {
0097     /*
0098      * PKO doesn't do any locking. It is the responsibility of the
0099      * application to make sure that no other core is accessing
0100      * the same queue at the same time
0101      */
0102     CVMX_PKO_LOCK_NONE = 0,
0103     /*
0104      * PKO performs an atomic tagswitch to insure exclusive access
0105      * to the output queue. This will maintain packet ordering on
0106      * output.
0107      */
0108     CVMX_PKO_LOCK_ATOMIC_TAG = 1,
0109     /*
0110      * PKO uses the common command queue locks to insure exclusive
0111      * access to the output queue. This is a memory based
0112      * ll/sc. This is the most portable locking mechanism.
0113      */
0114     CVMX_PKO_LOCK_CMD_QUEUE = 2,
0115 } cvmx_pko_lock_t;
0116 
0117 typedef struct {
0118     uint32_t packets;
0119     uint64_t octets;
0120     uint64_t doorbell;
0121 } cvmx_pko_port_status_t;
0122 
0123 /**
0124  * This structure defines the address to use on a packet enqueue
0125  */
0126 typedef union {
0127     uint64_t u64;
0128     struct {
0129 #ifdef __BIG_ENDIAN_BITFIELD
0130         /* Must CVMX_IO_SEG */
0131         uint64_t mem_space:2;
0132         /* Must be zero */
0133         uint64_t reserved:13;
0134         /* Must be one */
0135         uint64_t is_io:1;
0136         /* The ID of the device on the non-coherent bus */
0137         uint64_t did:8;
0138         /* Must be zero */
0139         uint64_t reserved2:4;
0140         /* Must be zero */
0141         uint64_t reserved3:18;
0142         /*
0143          * The hardware likes to have the output port in
0144          * addition to the output queue,
0145          */
0146         uint64_t port:6;
0147         /*
0148          * The output queue to send the packet to (0-127 are
0149          * legal)
0150          */
0151         uint64_t queue:9;
0152         /* Must be zero */
0153         uint64_t reserved4:3;
0154 #else
0155             uint64_t reserved4:3;
0156             uint64_t queue:9;
0157             uint64_t port:9;
0158             uint64_t reserved3:15;
0159             uint64_t reserved2:4;
0160             uint64_t did:8;
0161             uint64_t is_io:1;
0162             uint64_t reserved:13;
0163             uint64_t mem_space:2;
0164 #endif
0165     } s;
0166 } cvmx_pko_doorbell_address_t;
0167 
0168 /**
0169  * Structure of the first packet output command word.
0170  */
0171 union cvmx_pko_command_word0 {
0172     uint64_t u64;
0173     struct {
0174 #ifdef __BIG_ENDIAN_BITFIELD
0175         /*
0176          * The size of the reg1 operation - could be 8, 16,
0177          * 32, or 64 bits.
0178          */
0179         uint64_t size1:2;
0180         /*
0181          * The size of the reg0 operation - could be 8, 16,
0182          * 32, or 64 bits.
0183          */
0184         uint64_t size0:2;
0185         /*
0186          * If set, subtract 1, if clear, subtract packet
0187          * size.
0188          */
0189         uint64_t subone1:1;
0190         /*
0191          * The register, subtract will be done if reg1 is
0192          * non-zero.
0193          */
0194         uint64_t reg1:11;
0195         /* If set, subtract 1, if clear, subtract packet size */
0196         uint64_t subone0:1;
0197         /* The register, subtract will be done if reg0 is non-zero */
0198         uint64_t reg0:11;
0199         /*
0200          * When set, interpret segment pointer and segment
0201          * bytes in little endian order.
0202          */
0203         uint64_t le:1;
0204         /*
0205          * When set, packet data not allocated in L2 cache by
0206          * PKO.
0207          */
0208         uint64_t n2:1;
0209         /*
0210          * If set and rsp is set, word3 contains a pointer to
0211          * a work queue entry.
0212          */
0213         uint64_t wqp:1;
0214         /* If set, the hardware will send a response when done */
0215         uint64_t rsp:1;
0216         /*
0217          * If set, the supplied pkt_ptr is really a pointer to
0218          * a list of pkt_ptr's.
0219          */
0220         uint64_t gather:1;
0221         /*
0222          * If ipoffp1 is non zero, (ipoffp1-1) is the number
0223          * of bytes to IP header, and the hardware will
0224          * calculate and insert the UDP/TCP checksum.
0225          */
0226         uint64_t ipoffp1:7;
0227         /*
0228          * If set, ignore the I bit (force to zero) from all
0229          * pointer structures.
0230          */
0231         uint64_t ignore_i:1;
0232         /*
0233          * If clear, the hardware will attempt to free the
0234          * buffers containing the packet.
0235          */
0236         uint64_t dontfree:1;
0237         /*
0238          * The total number of segs in the packet, if gather
0239          * set, also gather list length.
0240          */
0241         uint64_t segs:6;
0242         /* Including L2, but no trailing CRC */
0243         uint64_t total_bytes:16;
0244 #else
0245             uint64_t total_bytes:16;
0246             uint64_t segs:6;
0247             uint64_t dontfree:1;
0248             uint64_t ignore_i:1;
0249             uint64_t ipoffp1:7;
0250             uint64_t gather:1;
0251             uint64_t rsp:1;
0252             uint64_t wqp:1;
0253             uint64_t n2:1;
0254             uint64_t le:1;
0255             uint64_t reg0:11;
0256             uint64_t subone0:1;
0257             uint64_t reg1:11;
0258             uint64_t subone1:1;
0259             uint64_t size0:2;
0260             uint64_t size1:2;
0261 #endif
0262     } s;
0263 };
0264 
0265 /* CSR typedefs have been moved to cvmx-csr-*.h */
0266 
0267 /**
0268  * Definition of internal state for Packet output processing
0269  */
0270 typedef struct {
0271     /* ptr to start of buffer, offset kept in FAU reg */
0272     uint64_t *start_ptr;
0273 } cvmx_pko_state_elem_t;
0274 
0275 /**
0276  * Call before any other calls to initialize the packet
0277  * output system.
0278  */
0279 extern void cvmx_pko_initialize_global(void);
0280 
0281 /**
0282  * Enables the packet output hardware. It must already be
0283  * configured.
0284  */
0285 extern void cvmx_pko_enable(void);
0286 
0287 /**
0288  * Disables the packet output. Does not affect any configuration.
0289  */
0290 extern void cvmx_pko_disable(void);
0291 
0292 /**
0293  * Shutdown and free resources required by packet output.
0294  */
0295 
0296 extern void cvmx_pko_shutdown(void);
0297 
0298 /**
0299  * Configure a output port and the associated queues for use.
0300  *
0301  * @port:   Port to configure.
0302  * @base_queue: First queue number to associate with this port.
0303  * @num_queues: Number of queues t oassociate with this port
0304  * @priority:   Array of priority levels for each queue. Values are
0305  *           allowed to be 1-8. A value of 8 get 8 times the traffic
0306  *           of a value of 1. There must be num_queues elements in the
0307  *           array.
0308  */
0309 extern cvmx_pko_status_t cvmx_pko_config_port(uint64_t port,
0310                           uint64_t base_queue,
0311                           uint64_t num_queues,
0312                           const uint64_t priority[]);
0313 
0314 /**
0315  * Ring the packet output doorbell. This tells the packet
0316  * output hardware that "len" command words have been added
0317  * to its pending list.  This command includes the required
0318  * CVMX_SYNCWS before the doorbell ring.
0319  *
0320  * @port:   Port the packet is for
0321  * @queue:  Queue the packet is for
0322  * @len:    Length of the command in 64 bit words
0323  */
0324 static inline void cvmx_pko_doorbell(uint64_t port, uint64_t queue,
0325                      uint64_t len)
0326 {
0327     cvmx_pko_doorbell_address_t ptr;
0328 
0329     ptr.u64 = 0;
0330     ptr.s.mem_space = CVMX_IO_SEG;
0331     ptr.s.did = CVMX_OCT_DID_PKT_SEND;
0332     ptr.s.is_io = 1;
0333     ptr.s.port = port;
0334     ptr.s.queue = queue;
0335     /*
0336      * Need to make sure output queue data is in DRAM before
0337      * doorbell write.
0338      */
0339     CVMX_SYNCWS;
0340     cvmx_write_io(ptr.u64, len);
0341 }
0342 
0343 /**
0344  * Prepare to send a packet.  This may initiate a tag switch to
0345  * get exclusive access to the output queue structure, and
0346  * performs other prep work for the packet send operation.
0347  *
0348  * cvmx_pko_send_packet_finish() MUST be called after this function is called,
0349  * and must be called with the same port/queue/use_locking arguments.
0350  *
0351  * The use_locking parameter allows the caller to use three
0352  * possible locking modes.
0353  * - CVMX_PKO_LOCK_NONE
0354  *  - PKO doesn't do any locking. It is the responsibility
0355  *      of the application to make sure that no other core
0356  *      is accessing the same queue at the same time.
0357  * - CVMX_PKO_LOCK_ATOMIC_TAG
0358  *  - PKO performs an atomic tagswitch to insure exclusive
0359  *      access to the output queue. This will maintain
0360  *      packet ordering on output.
0361  * - CVMX_PKO_LOCK_CMD_QUEUE
0362  *  - PKO uses the common command queue locks to insure
0363  *      exclusive access to the output queue. This is a
0364  *      memory based ll/sc. This is the most portable
0365  *      locking mechanism.
0366  *
0367  * NOTE: If atomic locking is used, the POW entry CANNOT be
0368  * descheduled, as it does not contain a valid WQE pointer.
0369  *
0370  * @port:   Port to send it on
0371  * @queue:  Queue to use
0372  * @use_locking: CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or
0373  *       CVMX_PKO_LOCK_CMD_QUEUE
0374  */
0375 
0376 static inline void cvmx_pko_send_packet_prepare(uint64_t port, uint64_t queue,
0377                         cvmx_pko_lock_t use_locking)
0378 {
0379     if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) {
0380         /*
0381          * Must do a full switch here to handle all cases.  We
0382          * use a fake WQE pointer, as the POW does not access
0383          * this memory.  The WQE pointer and group are only
0384          * used if this work is descheduled, which is not
0385          * supported by the
0386          * cvmx_pko_send_packet_prepare/cvmx_pko_send_packet_finish
0387          * combination.  Note that this is a special case in
0388          * which these fake values can be used - this is not a
0389          * general technique.
0390          */
0391         uint32_t tag =
0392             CVMX_TAG_SW_BITS_INTERNAL << CVMX_TAG_SW_SHIFT |
0393             CVMX_TAG_SUBGROUP_PKO << CVMX_TAG_SUBGROUP_SHIFT |
0394             (CVMX_TAG_SUBGROUP_MASK & queue);
0395         cvmx_pow_tag_sw_full((struct cvmx_wqe *) cvmx_phys_to_ptr(0x80), tag,
0396                      CVMX_POW_TAG_TYPE_ATOMIC, 0);
0397     }
0398 }
0399 
0400 /**
0401  * Complete packet output. cvmx_pko_send_packet_prepare() must be
0402  * called exactly once before this, and the same parameters must be
0403  * passed to both cvmx_pko_send_packet_prepare() and
0404  * cvmx_pko_send_packet_finish().
0405  *
0406  * @port:   Port to send it on
0407  * @queue:  Queue to use
0408  * @pko_command:
0409  *       PKO HW command word
0410  * @packet: Packet to send
0411  * @use_locking: CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or
0412  *       CVMX_PKO_LOCK_CMD_QUEUE
0413  *
0414  * Returns: CVMX_PKO_SUCCESS on success, or error code on
0415  * failure of output
0416  */
0417 static inline cvmx_pko_status_t cvmx_pko_send_packet_finish(
0418     uint64_t port,
0419     uint64_t queue,
0420     union cvmx_pko_command_word0 pko_command,
0421     union cvmx_buf_ptr packet,
0422     cvmx_pko_lock_t use_locking)
0423 {
0424     cvmx_cmd_queue_result_t result;
0425     if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG)
0426         cvmx_pow_tag_sw_wait();
0427     result = cvmx_cmd_queue_write2(CVMX_CMD_QUEUE_PKO(queue),
0428                        (use_locking == CVMX_PKO_LOCK_CMD_QUEUE),
0429                        pko_command.u64, packet.u64);
0430     if (likely(result == CVMX_CMD_QUEUE_SUCCESS)) {
0431         cvmx_pko_doorbell(port, queue, 2);
0432         return CVMX_PKO_SUCCESS;
0433     } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY)
0434            || (result == CVMX_CMD_QUEUE_FULL)) {
0435         return CVMX_PKO_NO_MEMORY;
0436     } else {
0437         return CVMX_PKO_INVALID_QUEUE;
0438     }
0439 }
0440 
0441 /**
0442  * Complete packet output. cvmx_pko_send_packet_prepare() must be
0443  * called exactly once before this, and the same parameters must be
0444  * passed to both cvmx_pko_send_packet_prepare() and
0445  * cvmx_pko_send_packet_finish().
0446  *
0447  * @port:   Port to send it on
0448  * @queue:  Queue to use
0449  * @pko_command:
0450  *       PKO HW command word
0451  * @packet: Packet to send
0452  * @addr: Plysical address of a work queue entry or physical address
0453  *    to zero on complete.
0454  * @use_locking: CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or
0455  *       CVMX_PKO_LOCK_CMD_QUEUE
0456  *
0457  * Returns: CVMX_PKO_SUCCESS on success, or error code on
0458  * failure of output
0459  */
0460 static inline cvmx_pko_status_t cvmx_pko_send_packet_finish3(
0461     uint64_t port,
0462     uint64_t queue,
0463     union cvmx_pko_command_word0 pko_command,
0464     union cvmx_buf_ptr packet,
0465     uint64_t addr,
0466     cvmx_pko_lock_t use_locking)
0467 {
0468     cvmx_cmd_queue_result_t result;
0469     if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG)
0470         cvmx_pow_tag_sw_wait();
0471     result = cvmx_cmd_queue_write3(CVMX_CMD_QUEUE_PKO(queue),
0472                        (use_locking == CVMX_PKO_LOCK_CMD_QUEUE),
0473                        pko_command.u64, packet.u64, addr);
0474     if (likely(result == CVMX_CMD_QUEUE_SUCCESS)) {
0475         cvmx_pko_doorbell(port, queue, 3);
0476         return CVMX_PKO_SUCCESS;
0477     } else if ((result == CVMX_CMD_QUEUE_NO_MEMORY)
0478            || (result == CVMX_CMD_QUEUE_FULL)) {
0479         return CVMX_PKO_NO_MEMORY;
0480     } else {
0481         return CVMX_PKO_INVALID_QUEUE;
0482     }
0483 }
0484 
0485 /**
0486  * Return the pko output queue associated with a port and a specific core.
0487  * In normal mode (PKO lockless operation is disabled), the value returned
0488  * is the base queue.
0489  *
0490  * @port:   Port number
0491  * @core:   Core to get queue for
0492  *
0493  * Returns Core-specific output queue
0494  */
0495 static inline int cvmx_pko_get_base_queue_per_core(int port, int core)
0496 {
0497 #ifndef CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0
0498 #define CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0 16
0499 #endif
0500 #ifndef CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1
0501 #define CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1 16
0502 #endif
0503 
0504     if (port < CVMX_PKO_MAX_PORTS_INTERFACE0)
0505         return port * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + core;
0506     else if (port >= 16 && port < 16 + CVMX_PKO_MAX_PORTS_INTERFACE1)
0507         return CVMX_PKO_MAX_PORTS_INTERFACE0 *
0508             CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + (port -
0509                                16) *
0510             CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + core;
0511     else if ((port >= 32) && (port < 36))
0512         return CVMX_PKO_MAX_PORTS_INTERFACE0 *
0513             CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 +
0514             CVMX_PKO_MAX_PORTS_INTERFACE1 *
0515             CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + (port -
0516                                32) *
0517             CVMX_PKO_QUEUES_PER_PORT_PCI;
0518     else if ((port >= 36) && (port < 40))
0519         return CVMX_PKO_MAX_PORTS_INTERFACE0 *
0520             CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 +
0521             CVMX_PKO_MAX_PORTS_INTERFACE1 *
0522             CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 +
0523             4 * CVMX_PKO_QUEUES_PER_PORT_PCI + (port -
0524                             36) *
0525             CVMX_PKO_QUEUES_PER_PORT_LOOP;
0526     else
0527         /* Given the limit on the number of ports we can map to
0528          * CVMX_MAX_OUTPUT_QUEUES_STATIC queues (currently 256,
0529          * divided among all cores), the remaining unmapped ports
0530          * are assigned an illegal queue number */
0531         return CVMX_PKO_ILLEGAL_QUEUE;
0532 }
0533 
0534 /**
0535  * For a given port number, return the base pko output queue
0536  * for the port.
0537  *
0538  * @port:   Port number
0539  * Returns Base output queue
0540  */
0541 static inline int cvmx_pko_get_base_queue(int port)
0542 {
0543     if (OCTEON_IS_MODEL(OCTEON_CN68XX))
0544         return port;
0545 
0546     return cvmx_pko_get_base_queue_per_core(port, 0);
0547 }
0548 
0549 /**
0550  * For a given port number, return the number of pko output queues.
0551  *
0552  * @port:   Port number
0553  * Returns Number of output queues
0554  */
0555 static inline int cvmx_pko_get_num_queues(int port)
0556 {
0557     if (port < 16)
0558         return CVMX_PKO_QUEUES_PER_PORT_INTERFACE0;
0559     else if (port < 32)
0560         return CVMX_PKO_QUEUES_PER_PORT_INTERFACE1;
0561     else if (port < 36)
0562         return CVMX_PKO_QUEUES_PER_PORT_PCI;
0563     else if (port < 40)
0564         return CVMX_PKO_QUEUES_PER_PORT_LOOP;
0565     else
0566         return 0;
0567 }
0568 
0569 /**
0570  * Get the status counters for a port.
0571  *
0572  * @port_num: Port number to get statistics for.
0573  * @clear:    Set to 1 to clear the counters after they are read
0574  * @status:   Where to put the results.
0575  */
0576 static inline void cvmx_pko_get_port_status(uint64_t port_num, uint64_t clear,
0577                         cvmx_pko_port_status_t *status)
0578 {
0579     union cvmx_pko_reg_read_idx pko_reg_read_idx;
0580     union cvmx_pko_mem_count0 pko_mem_count0;
0581     union cvmx_pko_mem_count1 pko_mem_count1;
0582 
0583     pko_reg_read_idx.u64 = 0;
0584     pko_reg_read_idx.s.index = port_num;
0585     cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64);
0586 
0587     pko_mem_count0.u64 = cvmx_read_csr(CVMX_PKO_MEM_COUNT0);
0588     status->packets = pko_mem_count0.s.count;
0589     if (clear) {
0590         pko_mem_count0.s.count = port_num;
0591         cvmx_write_csr(CVMX_PKO_MEM_COUNT0, pko_mem_count0.u64);
0592     }
0593 
0594     pko_mem_count1.u64 = cvmx_read_csr(CVMX_PKO_MEM_COUNT1);
0595     status->octets = pko_mem_count1.s.count;
0596     if (clear) {
0597         pko_mem_count1.s.count = port_num;
0598         cvmx_write_csr(CVMX_PKO_MEM_COUNT1, pko_mem_count1.u64);
0599     }
0600 
0601     if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
0602         union cvmx_pko_mem_debug9 debug9;
0603         pko_reg_read_idx.s.index = cvmx_pko_get_base_queue(port_num);
0604         cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64);
0605         debug9.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG9);
0606         status->doorbell = debug9.cn38xx.doorbell;
0607     } else {
0608         union cvmx_pko_mem_debug8 debug8;
0609         pko_reg_read_idx.s.index = cvmx_pko_get_base_queue(port_num);
0610         cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64);
0611         debug8.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG8);
0612         status->doorbell = debug8.cn50xx.doorbell;
0613     }
0614 }
0615 
0616 /**
0617  * Rate limit a PKO port to a max packets/sec. This function is only
0618  * supported on CN57XX, CN56XX, CN55XX, and CN54XX.
0619  *
0620  * @port:      Port to rate limit
0621  * @packets_s: Maximum packet/sec
0622  * @burst:     Maximum number of packets to burst in a row before rate
0623  *          limiting cuts in.
0624  *
0625  * Returns Zero on success, negative on failure
0626  */
0627 extern int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst);
0628 
0629 /**
0630  * Rate limit a PKO port to a max bits/sec. This function is only
0631  * supported on CN57XX, CN56XX, CN55XX, and CN54XX.
0632  *
0633  * @port:   Port to rate limit
0634  * @bits_s: PKO rate limit in bits/sec
0635  * @burst:  Maximum number of bits to burst before rate
0636  *       limiting cuts in.
0637  *
0638  * Returns Zero on success, negative on failure
0639  */
0640 extern int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst);
0641 
0642 #endif /* __CVMX_PKO_H__ */