1210284Sjmallett/***********************license start*************** 2215990Sjmallett * Copyright (c) 2003-2010 Cavium Networks (support@cavium.com). All rights 3215990Sjmallett * reserved. 4210284Sjmallett * 5210284Sjmallett * 6215990Sjmallett * Redistribution and use in source and binary forms, with or without 7215990Sjmallett * modification, are permitted provided that the following conditions are 8215990Sjmallett * met: 9210284Sjmallett * 10215990Sjmallett * * Redistributions of source code must retain the above copyright 11215990Sjmallett * notice, this list of conditions and the following disclaimer. 12210284Sjmallett * 13215990Sjmallett * * Redistributions in binary form must reproduce the above 14215990Sjmallett * copyright notice, this list of conditions and the following 15215990Sjmallett * disclaimer in the documentation and/or other materials provided 16215990Sjmallett * with the distribution. 17210284Sjmallett 18215990Sjmallett * * Neither the name of Cavium Networks nor the names of 19215990Sjmallett * its contributors may be used to endorse or promote products 20215990Sjmallett * derived from this software without specific prior written 21215990Sjmallett * permission. 22210284Sjmallett 23215990Sjmallett * This Software, including technical data, may be subject to U.S. export control 24215990Sjmallett * laws, including the U.S. Export Administration Act and its associated 25215990Sjmallett * regulations, and may be subject to export or import regulations in other 26215990Sjmallett * countries. 27210284Sjmallett 28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29215990Sjmallett * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR 30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38215990Sjmallett ***********************license end**************************************/ 39210284Sjmallett 40210284Sjmallett 41210284Sjmallett/** 42210284Sjmallett * @file 43210284Sjmallett * 44210284Sjmallett * Interface to the hardware Packet Output unit. 45210284Sjmallett * 46210284Sjmallett * Starting with SDK 1.7.0, the PKO output functions now support 47210284Sjmallett * two types of locking. CVMX_PKO_LOCK_ATOMIC_TAG continues to 48210284Sjmallett * function similarly to previous SDKs by using POW atomic tags 49210284Sjmallett * to preserve ordering and exclusivity. As a new option, you 50210284Sjmallett * can now pass CVMX_PKO_LOCK_CMD_QUEUE which uses a ll/sc 51210284Sjmallett * memory based locking instead. This locking has the advantage 52210284Sjmallett * of not affecting the tag state but doesn't preserve packet 53210284Sjmallett * ordering. CVMX_PKO_LOCK_CMD_QUEUE is appropriate in most 54210284Sjmallett * generic code while CVMX_PKO_LOCK_CMD_QUEUE should be used 55210284Sjmallett * with hand tuned fast path code. 56210284Sjmallett * 57210284Sjmallett * Some of other SDK differences visible to the command command 58210284Sjmallett * queuing: 59210284Sjmallett * - PKO indexes are no longer stored in the FAU. A large 60210284Sjmallett * percentage of the FAU register block used to be tied up 61210284Sjmallett * maintaining PKO queue pointers. These are now stored in a 62210284Sjmallett * global named block. 63210284Sjmallett * - The PKO <b>use_locking</b> parameter can now have a global 64210284Sjmallett * effect. Since all application use the same named block, 65210284Sjmallett * queue locking correctly applies across all operating 66210284Sjmallett * systems when using CVMX_PKO_LOCK_CMD_QUEUE. 67210284Sjmallett * - PKO 3 word commands are now supported. Use 68210284Sjmallett * cvmx_pko_send_packet_finish3(). 69210284Sjmallett * 70215990Sjmallett * <hr>$Revision: 49448 $<hr> 71210284Sjmallett */ 72210284Sjmallett 73210284Sjmallett 74210284Sjmallett#ifndef __CVMX_PKO_H__ 75210284Sjmallett#define __CVMX_PKO_H__ 76210284Sjmallett 77215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 78210284Sjmallett#include "cvmx-config.h" 79215990Sjmallett#include "cvmx-pko-defs.h" 80215990Sjmallett#else 81215990Sjmallett# ifndef CVMX_DONT_INCLUDE_CONFIG 82215990Sjmallett# include "executive-config.h" 83215990Sjmallett# ifdef CVMX_ENABLE_PKO_FUNCTIONS 84215990Sjmallett# include "cvmx-config.h" 85215990Sjmallett# endif 86215990Sjmallett# endif 87210284Sjmallett#endif 88210284Sjmallett 89215990Sjmallett 90210284Sjmallett#include "cvmx-fau.h" 91210284Sjmallett#include "cvmx-fpa.h" 92210284Sjmallett#include "cvmx-pow.h" 93210284Sjmallett#include "cvmx-cmd-queue.h" 94210284Sjmallett 95210284Sjmallett/* Adjust the command buffer size by 1 word so that in the case of using only 96210284Sjmallett** two word PKO commands no command words stradle buffers. The useful values 97210284Sjmallett** for this are 0 and 1. */ 98210284Sjmallett#define CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST (1) 99210284Sjmallett 100210284Sjmallett#ifdef __cplusplus 101210284Sjmallettextern "C" { 102210284Sjmallett#endif 103210284Sjmallett 104210284Sjmallett#define CVMX_PKO_MAX_OUTPUT_QUEUES_STATIC 256 105215990Sjmallett#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) || OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX)) ? 256 : 128) 106215990Sjmallett#define CVMX_PKO_NUM_OUTPUT_PORTS ((OCTEON_IS_MODEL(OCTEON_CN63XX)) ? 44 : 40) 107215990Sjmallett#define CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID 63 /* use this for queues that are not used */ 108210284Sjmallett#define CVMX_PKO_QUEUE_STATIC_PRIORITY 9 109210284Sjmallett#define CVMX_PKO_ILLEGAL_QUEUE 0xFFFF 110210284Sjmallett#define CVMX_PKO_MAX_QUEUE_DEPTH 0 111210284Sjmallett 112210284Sjmalletttypedef enum 113210284Sjmallett{ 114210284Sjmallett CVMX_PKO_SUCCESS, 115210284Sjmallett CVMX_PKO_INVALID_PORT, 116210284Sjmallett CVMX_PKO_INVALID_QUEUE, 117210284Sjmallett CVMX_PKO_INVALID_PRIORITY, 118210284Sjmallett CVMX_PKO_NO_MEMORY, 119210284Sjmallett CVMX_PKO_PORT_ALREADY_SETUP, 120210284Sjmallett CVMX_PKO_CMD_QUEUE_INIT_ERROR 121210284Sjmallett} cvmx_pko_status_t; 122210284Sjmallett 123210284Sjmallett/** 124210284Sjmallett * This enumeration represents the differnet locking modes supported by PKO. 125210284Sjmallett */ 126210284Sjmalletttypedef enum 127210284Sjmallett{ 128210284Sjmallett CVMX_PKO_LOCK_NONE = 0, /**< PKO doesn't do any locking. It is the responsibility 129210284Sjmallett of the application to make sure that no other core is 130210284Sjmallett accessing the same queue at the smae time */ 131210284Sjmallett CVMX_PKO_LOCK_ATOMIC_TAG = 1, /**< PKO performs an atomic tagswitch to insure exclusive 132210284Sjmallett access to the output queue. This will maintain 133210284Sjmallett packet ordering on output */ 134210284Sjmallett CVMX_PKO_LOCK_CMD_QUEUE = 2, /**< PKO uses the common command queue locks to insure 135210284Sjmallett exclusive access to the output queue. This is a memory 136210284Sjmallett based ll/sc. This is the most portable locking 137210284Sjmallett mechanism */ 138210284Sjmallett} cvmx_pko_lock_t; 139210284Sjmallett 140210284Sjmalletttypedef struct 141210284Sjmallett{ 142210284Sjmallett uint32_t packets; 143210284Sjmallett uint64_t octets; 144210284Sjmallett uint64_t doorbell; 145210284Sjmallett} cvmx_pko_port_status_t; 146210284Sjmallett 147210284Sjmallett/** 148210284Sjmallett * This structure defines the address to use on a packet enqueue 149210284Sjmallett */ 150210284Sjmalletttypedef union 151210284Sjmallett{ 152210284Sjmallett uint64_t u64; 153210284Sjmallett struct 154210284Sjmallett { 155210284Sjmallett cvmx_mips_space_t mem_space : 2; /**< Must CVMX_IO_SEG */ 156210284Sjmallett uint64_t reserved :13; /**< Must be zero */ 157210284Sjmallett uint64_t is_io : 1; /**< Must be one */ 158210284Sjmallett uint64_t did : 8; /**< The ID of the device on the non-coherent bus */ 159210284Sjmallett uint64_t reserved2 : 4; /**< Must be zero */ 160210284Sjmallett uint64_t reserved3 :18; /**< Must be zero */ 161210284Sjmallett uint64_t port : 6; /**< The hardware likes to have the output port in addition to the output queue */ 162210284Sjmallett uint64_t queue : 9; /**< The output queue to send the packet to (0-127 are legal) */ 163210284Sjmallett uint64_t reserved4 : 3; /**< Must be zero */ 164210284Sjmallett } s; 165210284Sjmallett} cvmx_pko_doorbell_address_t; 166210284Sjmallett 167210284Sjmallett/** 168210284Sjmallett * Structure of the first packet output command word. 169210284Sjmallett */ 170210284Sjmalletttypedef union 171210284Sjmallett{ 172210284Sjmallett uint64_t u64; 173210284Sjmallett struct 174210284Sjmallett { 175210284Sjmallett cvmx_fau_op_size_t size1 : 2; /**< The size of the reg1 operation - could be 8, 16, 32, or 64 bits */ 176210284Sjmallett cvmx_fau_op_size_t size0 : 2; /**< The size of the reg0 operation - could be 8, 16, 32, or 64 bits */ 177210284Sjmallett uint64_t subone1 : 1; /**< If set, subtract 1, if clear, subtract packet size */ 178210284Sjmallett uint64_t reg1 :11; /**< The register, subtract will be done if reg1 is non-zero */ 179210284Sjmallett uint64_t subone0 : 1; /**< If set, subtract 1, if clear, subtract packet size */ 180210284Sjmallett uint64_t reg0 :11; /**< The register, subtract will be done if reg0 is non-zero */ 181210284Sjmallett uint64_t le : 1; /**< When set, interpret segment pointer and segment bytes in little endian order */ 182210284Sjmallett uint64_t n2 : 1; /**< When set, packet data not allocated in L2 cache by PKO */ 183210284Sjmallett uint64_t wqp : 1; /**< If set and rsp is set, word3 contains a pointer to a work queue entry */ 184210284Sjmallett uint64_t rsp : 1; /**< If set, the hardware will send a response when done */ 185210284Sjmallett uint64_t gather : 1; /**< If set, the supplied pkt_ptr is really a pointer to a list of pkt_ptr's */ 186210284Sjmallett uint64_t ipoffp1 : 7; /**< If ipoffp1 is non zero, (ipoffp1-1) is the number of bytes to IP header, 187210284Sjmallett and the hardware will calculate and insert the UDP/TCP checksum */ 188210284Sjmallett uint64_t ignore_i : 1; /**< If set, ignore the I bit (force to zero) from all pointer structures */ 189210284Sjmallett uint64_t dontfree : 1; /**< If clear, the hardware will attempt to free the buffers containing the packet */ 190210284Sjmallett uint64_t segs : 6; /**< The total number of segs in the packet, if gather set, also gather list length */ 191210284Sjmallett uint64_t total_bytes :16; /**< Including L2, but no trailing CRC */ 192210284Sjmallett } s; 193210284Sjmallett} cvmx_pko_command_word0_t; 194210284Sjmallett 195215990Sjmallett/* CSR typedefs have been moved to cvmx-pko-defs.h */ 196210284Sjmallett 197210284Sjmallett/** 198210284Sjmallett * Definition of internal state for Packet output processing 199210284Sjmallett */ 200210284Sjmalletttypedef struct 201210284Sjmallett{ 202210284Sjmallett uint64_t * start_ptr; /**< ptr to start of buffer, offset kept in FAU reg */ 203210284Sjmallett} cvmx_pko_state_elem_t; 204210284Sjmallett 205210284Sjmallett 206210284Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 207210284Sjmallett/** 208210284Sjmallett * Call before any other calls to initialize the packet 209210284Sjmallett * output system. 210210284Sjmallett */ 211210284Sjmallettextern void cvmx_pko_initialize_global(void); 212210284Sjmallettextern int cvmx_pko_initialize_local(void); 213210284Sjmallett 214210284Sjmallett#endif 215210284Sjmallett 216210284Sjmallett 217210284Sjmallett/** 218210284Sjmallett * Enables the packet output hardware. It must already be 219210284Sjmallett * configured. 220210284Sjmallett */ 221210284Sjmallettextern void cvmx_pko_enable(void); 222210284Sjmallett 223210284Sjmallett 224210284Sjmallett/** 225210284Sjmallett * Disables the packet output. Does not affect any configuration. 226210284Sjmallett */ 227210284Sjmallettextern void cvmx_pko_disable(void); 228210284Sjmallett 229210284Sjmallett 230210284Sjmallett/** 231210284Sjmallett * Shutdown and free resources required by packet output. 232210284Sjmallett */ 233210284Sjmallett 234210284Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 235210284Sjmallettextern void cvmx_pko_shutdown(void); 236210284Sjmallett#endif 237210284Sjmallett 238210284Sjmallett/** 239210284Sjmallett * Configure a output port and the associated queues for use. 240210284Sjmallett * 241210284Sjmallett * @param port Port to configure. 242210284Sjmallett * @param base_queue First queue number to associate with this port. 243210284Sjmallett * @param num_queues Number of queues t oassociate with this port 244210284Sjmallett * @param priority Array of priority levels for each queue. Values are 245210284Sjmallett * allowed to be 1-8. A value of 8 get 8 times the traffic 246210284Sjmallett * of a value of 1. There must be num_queues elements in the 247210284Sjmallett * array. 248210284Sjmallett */ 249210284Sjmallettextern cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue, uint64_t num_queues, const uint64_t priority[]); 250210284Sjmallett 251210284Sjmallett 252210284Sjmallett/** 253210284Sjmallett * Ring the packet output doorbell. This tells the packet 254210284Sjmallett * output hardware that "len" command words have been added 255210284Sjmallett * to its pending list. This command includes the required 256210284Sjmallett * CVMX_SYNCWS before the doorbell ring. 257210284Sjmallett * 258210284Sjmallett * @param port Port the packet is for 259210284Sjmallett * @param queue Queue the packet is for 260210284Sjmallett * @param len Length of the command in 64 bit words 261210284Sjmallett */ 262210284Sjmallettstatic inline void cvmx_pko_doorbell(uint64_t port, uint64_t queue, uint64_t len) 263210284Sjmallett{ 264210284Sjmallett cvmx_pko_doorbell_address_t ptr; 265210284Sjmallett 266210284Sjmallett ptr.u64 = 0; 267210284Sjmallett ptr.s.mem_space = CVMX_IO_SEG; 268210284Sjmallett ptr.s.did = CVMX_OCT_DID_PKT_SEND; 269210284Sjmallett ptr.s.is_io = 1; 270210284Sjmallett ptr.s.port = port; 271210284Sjmallett ptr.s.queue = queue; 272210284Sjmallett CVMX_SYNCWS; /* Need to make sure output queue data is in DRAM before doorbell write */ 273210284Sjmallett cvmx_write_io(ptr.u64, len); 274210284Sjmallett} 275210284Sjmallett 276210284Sjmallett 277210284Sjmallett/** 278210284Sjmallett * Prepare to send a packet. This may initiate a tag switch to 279210284Sjmallett * get exclusive access to the output queue structure, and 280210284Sjmallett * performs other prep work for the packet send operation. 281210284Sjmallett * 282210284Sjmallett * cvmx_pko_send_packet_finish() MUST be called after this function is called, 283210284Sjmallett * and must be called with the same port/queue/use_locking arguments. 284210284Sjmallett * 285210284Sjmallett * The use_locking parameter allows the caller to use three 286210284Sjmallett * possible locking modes. 287210284Sjmallett * - CVMX_PKO_LOCK_NONE 288210284Sjmallett * - PKO doesn't do any locking. It is the responsibility 289210284Sjmallett * of the application to make sure that no other core 290210284Sjmallett * is accessing the same queue at the smae time. 291210284Sjmallett * - CVMX_PKO_LOCK_ATOMIC_TAG 292210284Sjmallett * - PKO performs an atomic tagswitch to insure exclusive 293210284Sjmallett * access to the output queue. This will maintain 294210284Sjmallett * packet ordering on output. 295210284Sjmallett * - CVMX_PKO_LOCK_CMD_QUEUE 296210284Sjmallett * - PKO uses the common command queue locks to insure 297210284Sjmallett * exclusive access to the output queue. This is a 298210284Sjmallett * memory based ll/sc. This is the most portable 299210284Sjmallett * locking mechanism. 300210284Sjmallett * 301210284Sjmallett * NOTE: If atomic locking is used, the POW entry CANNOT be 302210284Sjmallett * descheduled, as it does not contain a valid WQE pointer. 303210284Sjmallett * 304210284Sjmallett * @param port Port to send it on 305210284Sjmallett * @param queue Queue to use 306210284Sjmallett * @param use_locking 307210284Sjmallett * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE 308210284Sjmallett */ 309210284Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS 310210284Sjmallettstatic inline void cvmx_pko_send_packet_prepare(uint64_t port, uint64_t queue, cvmx_pko_lock_t use_locking) 311210284Sjmallett{ 312210284Sjmallett if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) 313210284Sjmallett { 314210284Sjmallett /* Must do a full switch here to handle all cases. We use a fake WQE pointer, as the POW does 315210284Sjmallett ** not access this memory. The WQE pointer and group are only used if this work is descheduled, 316210284Sjmallett ** which is not supported by the cvmx_pko_send_packet_prepare/cvmx_pko_send_packet_finish combination. 317210284Sjmallett ** Note that this is a special case in which these fake values can be used - this is not a general technique. 318210284Sjmallett */ 319210284Sjmallett 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); 320210284Sjmallett cvmx_pow_tag_sw_full((cvmx_wqe_t *)cvmx_phys_to_ptr(0x80), tag, CVMX_POW_TAG_TYPE_ATOMIC, 0); 321210284Sjmallett } 322210284Sjmallett} 323210284Sjmallett 324210284Sjmallett 325210284Sjmallett/** 326210284Sjmallett * Complete packet output. cvmx_pko_send_packet_prepare() must be called exactly once before this, 327210284Sjmallett * and the same parameters must be passed to both cvmx_pko_send_packet_prepare() and 328210284Sjmallett * cvmx_pko_send_packet_finish(). 329210284Sjmallett * 330210284Sjmallett * @param port Port to send it on 331210284Sjmallett * @param queue Queue to use 332210284Sjmallett * @param pko_command 333210284Sjmallett * PKO HW command word 334210284Sjmallett * @param packet Packet to send 335210284Sjmallett * @param use_locking 336210284Sjmallett * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE 337210284Sjmallett * 338210284Sjmallett * @return returns CVMX_PKO_SUCCESS on success, or error code on failure of output 339210284Sjmallett */ 340210284Sjmallettstatic inline cvmx_pko_status_t cvmx_pko_send_packet_finish(uint64_t port, uint64_t queue, 341210284Sjmallett cvmx_pko_command_word0_t pko_command, 342210284Sjmallett cvmx_buf_ptr_t packet, cvmx_pko_lock_t use_locking) 343210284Sjmallett{ 344210284Sjmallett cvmx_cmd_queue_result_t result; 345210284Sjmallett if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) 346210284Sjmallett cvmx_pow_tag_sw_wait(); 347210284Sjmallett result = cvmx_cmd_queue_write2(CVMX_CMD_QUEUE_PKO(queue), 348210284Sjmallett (use_locking == CVMX_PKO_LOCK_CMD_QUEUE), 349210284Sjmallett pko_command.u64, 350210284Sjmallett packet.u64); 351210284Sjmallett if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) 352210284Sjmallett { 353210284Sjmallett cvmx_pko_doorbell(port, queue, 2); 354210284Sjmallett return CVMX_PKO_SUCCESS; 355210284Sjmallett } 356210284Sjmallett else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == CVMX_CMD_QUEUE_FULL)) 357210284Sjmallett { 358210284Sjmallett return CVMX_PKO_NO_MEMORY; 359210284Sjmallett } 360210284Sjmallett else 361210284Sjmallett { 362210284Sjmallett return CVMX_PKO_INVALID_QUEUE; 363210284Sjmallett } 364210284Sjmallett} 365210284Sjmallett 366210284Sjmallett 367210284Sjmallett/** 368210284Sjmallett * Complete packet output. cvmx_pko_send_packet_prepare() must be called exactly once before this, 369210284Sjmallett * and the same parameters must be passed to both cvmx_pko_send_packet_prepare() and 370210284Sjmallett * cvmx_pko_send_packet_finish(). 371210284Sjmallett * 372210284Sjmallett * @param port Port to send it on 373210284Sjmallett * @param queue Queue to use 374210284Sjmallett * @param pko_command 375210284Sjmallett * PKO HW command word 376210284Sjmallett * @param packet Packet to send 377210284Sjmallett * @param addr Plysical address of a work queue entry or physical address to zero on complete. 378210284Sjmallett * @param use_locking 379210284Sjmallett * CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE 380210284Sjmallett * 381210284Sjmallett * @return returns CVMX_PKO_SUCCESS on success, or error code on failure of output 382210284Sjmallett */ 383210284Sjmallettstatic inline cvmx_pko_status_t cvmx_pko_send_packet_finish3(uint64_t port, uint64_t queue, 384210284Sjmallett cvmx_pko_command_word0_t pko_command, 385210284Sjmallett cvmx_buf_ptr_t packet, uint64_t addr, cvmx_pko_lock_t use_locking) 386210284Sjmallett{ 387210284Sjmallett cvmx_cmd_queue_result_t result; 388210284Sjmallett if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG) 389210284Sjmallett cvmx_pow_tag_sw_wait(); 390210284Sjmallett result = cvmx_cmd_queue_write3(CVMX_CMD_QUEUE_PKO(queue), 391210284Sjmallett (use_locking == CVMX_PKO_LOCK_CMD_QUEUE), 392210284Sjmallett pko_command.u64, 393210284Sjmallett packet.u64, 394210284Sjmallett addr); 395210284Sjmallett if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS)) 396210284Sjmallett { 397210284Sjmallett cvmx_pko_doorbell(port, queue, 3); 398210284Sjmallett return CVMX_PKO_SUCCESS; 399210284Sjmallett } 400210284Sjmallett else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == CVMX_CMD_QUEUE_FULL)) 401210284Sjmallett { 402210284Sjmallett return CVMX_PKO_NO_MEMORY; 403210284Sjmallett } 404210284Sjmallett else 405210284Sjmallett { 406210284Sjmallett return CVMX_PKO_INVALID_QUEUE; 407210284Sjmallett } 408210284Sjmallett} 409210284Sjmallett 410210284Sjmallett/** 411210284Sjmallett * Return the pko output queue associated with a port and a specific core. 412210284Sjmallett * In normal mode (PKO lockless operation is disabled), the value returned 413210284Sjmallett * is the base queue. 414210284Sjmallett * 415210284Sjmallett * @param port Port number 416210284Sjmallett * @param core Core to get queue for 417210284Sjmallett * 418210284Sjmallett * @return Core-specific output queue 419210284Sjmallett */ 420210284Sjmallettstatic inline int cvmx_pko_get_base_queue_per_core(int port, int core) 421210284Sjmallett{ 422210284Sjmallett#ifndef CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0 423210284Sjmallett #define CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0 16 424210284Sjmallett#endif 425210284Sjmallett#ifndef CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1 426210284Sjmallett #define CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1 16 427210284Sjmallett#endif 428215990Sjmallett#ifndef CVMX_PKO_QUEUES_PER_PORT_SRIO0 429215990Sjmallett /* We use two queues per port for SRIO0. Having two queues per 430215990Sjmallett port with two ports gives us four queues, one for each mailbox */ 431215990Sjmallett #define CVMX_PKO_QUEUES_PER_PORT_SRIO0 2 432215990Sjmallett#endif 433215990Sjmallett#ifndef CVMX_PKO_QUEUES_PER_PORT_SRIO1 434215990Sjmallett /* We use two queues per port for SRIO1. Having two queues per 435215990Sjmallett port with two ports gives us four queues, one for each mailbox */ 436215990Sjmallett #define CVMX_PKO_QUEUES_PER_PORT_SRIO1 2 437215990Sjmallett#endif 438210284Sjmallett if (port < CVMX_PKO_MAX_PORTS_INTERFACE0) 439210284Sjmallett return port * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + core; 440210284Sjmallett else if (port >=16 && port < 16 + CVMX_PKO_MAX_PORTS_INTERFACE1) 441210284Sjmallett return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + 442210284Sjmallett (port-16) * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + core; 443210284Sjmallett else if ((port >= 32) && (port < 36)) 444210284Sjmallett return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + 445210284Sjmallett CVMX_PKO_MAX_PORTS_INTERFACE1 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + 446210284Sjmallett (port-32) * CVMX_PKO_QUEUES_PER_PORT_PCI; 447210284Sjmallett else if ((port >= 36) && (port < 40)) 448210284Sjmallett return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + 449210284Sjmallett CVMX_PKO_MAX_PORTS_INTERFACE1 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + 450210284Sjmallett 4 * CVMX_PKO_QUEUES_PER_PORT_PCI + 451210284Sjmallett (port-36) * CVMX_PKO_QUEUES_PER_PORT_LOOP; 452215990Sjmallett else if ((port >= 40) && (port < 42)) 453215990Sjmallett return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + 454215990Sjmallett CVMX_PKO_MAX_PORTS_INTERFACE1 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + 455215990Sjmallett 4 * CVMX_PKO_QUEUES_PER_PORT_PCI + 456215990Sjmallett 4 * CVMX_PKO_QUEUES_PER_PORT_LOOP + 457215990Sjmallett (port-40) * CVMX_PKO_QUEUES_PER_PORT_SRIO0; 458215990Sjmallett else if ((port >= 42) && (port < 44)) 459215990Sjmallett return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + 460215990Sjmallett CVMX_PKO_MAX_PORTS_INTERFACE1 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + 461215990Sjmallett 4 * CVMX_PKO_QUEUES_PER_PORT_PCI + 462215990Sjmallett 4 * CVMX_PKO_QUEUES_PER_PORT_LOOP + 463215990Sjmallett 2 * CVMX_PKO_QUEUES_PER_PORT_SRIO0 + 464215990Sjmallett (port-42) * CVMX_PKO_QUEUES_PER_PORT_SRIO1; 465210284Sjmallett else 466210284Sjmallett /* Given the limit on the number of ports we can map to 467210284Sjmallett * CVMX_MAX_OUTPUT_QUEUES_STATIC queues (currently 256, 468210284Sjmallett * divided among all cores), the remaining unmapped ports 469210284Sjmallett * are assigned an illegal queue number */ 470210284Sjmallett return CVMX_PKO_ILLEGAL_QUEUE; 471210284Sjmallett} 472210284Sjmallett 473210284Sjmallett/** 474210284Sjmallett * For a given port number, return the base pko output queue 475210284Sjmallett * for the port. 476210284Sjmallett * 477210284Sjmallett * @param port Port number 478210284Sjmallett * @return Base output queue 479210284Sjmallett */ 480210284Sjmallettstatic inline int cvmx_pko_get_base_queue(int port) 481210284Sjmallett{ 482210284Sjmallett return cvmx_pko_get_base_queue_per_core(port, 0); 483210284Sjmallett} 484210284Sjmallett 485210284Sjmallett/** 486210284Sjmallett * For a given port number, return the number of pko output queues. 487210284Sjmallett * 488210284Sjmallett * @param port Port number 489210284Sjmallett * @return Number of output queues 490210284Sjmallett */ 491210284Sjmallettstatic inline int cvmx_pko_get_num_queues(int port) 492210284Sjmallett{ 493210284Sjmallett if (port < 16) 494210284Sjmallett return CVMX_PKO_QUEUES_PER_PORT_INTERFACE0; 495210284Sjmallett else if (port<32) 496210284Sjmallett return CVMX_PKO_QUEUES_PER_PORT_INTERFACE1; 497210284Sjmallett else if (port<36) 498210284Sjmallett return CVMX_PKO_QUEUES_PER_PORT_PCI; 499210284Sjmallett else if (port<40) 500210284Sjmallett return CVMX_PKO_QUEUES_PER_PORT_LOOP; 501215990Sjmallett else if (port<42) 502215990Sjmallett return CVMX_PKO_QUEUES_PER_PORT_SRIO0; 503215990Sjmallett else if (port<44) 504215990Sjmallett return CVMX_PKO_QUEUES_PER_PORT_SRIO1; 505210284Sjmallett else 506210284Sjmallett return 0; 507210284Sjmallett} 508210284Sjmallett 509210284Sjmallett/** 510210284Sjmallett * Get the status counters for a port. 511210284Sjmallett * 512210284Sjmallett * @param port_num Port number to get statistics for. 513210284Sjmallett * @param clear Set to 1 to clear the counters after they are read 514210284Sjmallett * @param status Where to put the results. 515210284Sjmallett */ 516210284Sjmallettstatic inline void cvmx_pko_get_port_status(uint64_t port_num, uint64_t clear, cvmx_pko_port_status_t *status) 517210284Sjmallett{ 518210284Sjmallett cvmx_pko_reg_read_idx_t pko_reg_read_idx; 519210284Sjmallett cvmx_pko_mem_count0_t pko_mem_count0; 520210284Sjmallett cvmx_pko_mem_count1_t pko_mem_count1; 521210284Sjmallett 522210284Sjmallett pko_reg_read_idx.u64 = 0; 523210284Sjmallett pko_reg_read_idx.s.index = port_num; 524210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64); 525210284Sjmallett 526210284Sjmallett pko_mem_count0.u64 = cvmx_read_csr(CVMX_PKO_MEM_COUNT0); 527210284Sjmallett status->packets = pko_mem_count0.s.count; 528210284Sjmallett if (clear) 529210284Sjmallett { 530210284Sjmallett pko_mem_count0.s.count = port_num; 531210284Sjmallett cvmx_write_csr(CVMX_PKO_MEM_COUNT0, pko_mem_count0.u64); 532210284Sjmallett } 533210284Sjmallett 534210284Sjmallett pko_mem_count1.u64 = cvmx_read_csr(CVMX_PKO_MEM_COUNT1); 535210284Sjmallett status->octets = pko_mem_count1.s.count; 536210284Sjmallett if (clear) 537210284Sjmallett { 538210284Sjmallett pko_mem_count1.s.count = port_num; 539210284Sjmallett cvmx_write_csr(CVMX_PKO_MEM_COUNT1, pko_mem_count1.u64); 540210284Sjmallett } 541210284Sjmallett 542210284Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) 543210284Sjmallett { 544210284Sjmallett cvmx_pko_mem_debug9_t debug9; 545210284Sjmallett pko_reg_read_idx.s.index = cvmx_pko_get_base_queue(port_num); 546210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64); 547210284Sjmallett debug9.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG9); 548210284Sjmallett status->doorbell = debug9.cn38xx.doorbell; 549210284Sjmallett } 550210284Sjmallett else 551210284Sjmallett { 552210284Sjmallett cvmx_pko_mem_debug8_t debug8; 553210284Sjmallett pko_reg_read_idx.s.index = cvmx_pko_get_base_queue(port_num); 554210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64); 555210284Sjmallett debug8.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG8); 556210284Sjmallett status->doorbell = debug8.cn58xx.doorbell; 557210284Sjmallett } 558210284Sjmallett} 559210284Sjmallett 560210284Sjmallett 561210284Sjmallett/** 562210284Sjmallett * Rate limit a PKO port to a max packets/sec. This function is only 563210284Sjmallett * supported on CN57XX, CN56XX, CN55XX, and CN54XX. 564210284Sjmallett * 565210284Sjmallett * @param port Port to rate limit 566210284Sjmallett * @param packets_s Maximum packet/sec 567210284Sjmallett * @param burst Maximum number of packets to burst in a row before rate 568210284Sjmallett * limiting cuts in. 569210284Sjmallett * 570210284Sjmallett * @return Zero on success, negative on failure 571210284Sjmallett */ 572210284Sjmallettextern int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst); 573210284Sjmallett 574210284Sjmallett/** 575210284Sjmallett * Rate limit a PKO port to a max bits/sec. This function is only 576210284Sjmallett * supported on CN57XX, CN56XX, CN55XX, and CN54XX. 577210284Sjmallett * 578210284Sjmallett * @param port Port to rate limit 579210284Sjmallett * @param bits_s PKO rate limit in bits/sec 580210284Sjmallett * @param burst Maximum number of bits to burst before rate 581210284Sjmallett * limiting cuts in. 582210284Sjmallett * 583210284Sjmallett * @return Zero on success, negative on failure 584210284Sjmallett */ 585210284Sjmallettextern int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst); 586210284Sjmallett 587210284Sjmallett#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ 588210284Sjmallett 589210284Sjmallett#ifdef __cplusplus 590210284Sjmallett} 591210284Sjmallett#endif 592210284Sjmallett 593210284Sjmallett#endif /* __CVMX_PKO_H__ */ 594