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