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