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