1/***********************license start***************
2 * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3 * reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *   * Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 *
13 *   * Redistributions in binary form must reproduce the above
14 *     copyright notice, this list of conditions and the following
15 *     disclaimer in the documentation and/or other materials provided
16 *     with the distribution.
17
18 *   * Neither the name of Cavium Inc. nor the names of
19 *     its contributors may be used to endorse or promote products
20 *     derived from this software without specific prior written
21 *     permission.
22
23 * This Software, including technical data, may be subject to U.S. export  control
24 * laws, including the U.S. Export Administration Act and its  associated
25 * regulations, and may be subject to export or import  regulations in other
26 * countries.
27
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
39
40
41/**
42 * @file
43 *
44 * Interface to the hardware Packet Output unit.
45 *
46 * Starting with SDK 1.7.0, the PKO output functions now support
47 * two types of locking. CVMX_PKO_LOCK_ATOMIC_TAG continues to
48 * function similarly to previous SDKs by using POW atomic tags
49 * to preserve ordering and exclusivity. As a new option, you
50 * can now pass CVMX_PKO_LOCK_CMD_QUEUE which uses a ll/sc
51 * memory based locking instead. This locking has the advantage
52 * of not affecting the tag state but doesn't preserve packet
53 * ordering. CVMX_PKO_LOCK_CMD_QUEUE is appropriate in most
54 * generic code while CVMX_PKO_LOCK_CMD_QUEUE should be used
55 * with hand tuned fast path code.
56 *
57 * Some of other SDK differences visible to the command command
58 * queuing:
59 * - PKO indexes are no longer stored in the FAU. A large
60 *   percentage of the FAU register block used to be tied up
61 *   maintaining PKO queue pointers. These are now stored in a
62 *   global named block.
63 * - The PKO <b>use_locking</b> parameter can now have a global
64 *   effect. Since all application use the same named block,
65 *   queue locking correctly applies across all operating
66 *   systems when using CVMX_PKO_LOCK_CMD_QUEUE.
67 * - PKO 3 word commands are now supported. Use
68 *   cvmx_pko_send_packet_finish3().
69 *
70 * <hr>$Revision: 70030 $<hr>
71 */
72
73
74#ifndef __CVMX_PKO_H__
75#define __CVMX_PKO_H__
76
77#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
78#include "cvmx-config.h"
79#include "cvmx-pko-defs.h"
80#include <asm/octeon/cvmx-fau.h>
81#include <asm/octeon/cvmx-fpa.h>
82#include <asm/octeon/cvmx-pow.h>
83#include <asm/octeon/cvmx-cmd-queue.h>
84#include <asm/octeon/cvmx-helper.h>
85#include <asm/octeon/cvmx-helper-cfg.h>
86#else
87# ifndef CVMX_DONT_INCLUDE_CONFIG
88#  include "executive-config.h"
89#  ifdef CVMX_ENABLE_PKO_FUNCTIONS
90#   include "cvmx-config.h"
91#  endif
92# endif
93#include "cvmx-fau.h"
94#include "cvmx-fpa.h"
95#include "cvmx-pow.h"
96#include "cvmx-cmd-queue.h"
97#include "cvmx-helper.h"
98#include "cvmx-helper-util.h"
99#include "cvmx-helper-cfg.h"
100#endif
101
102/* Adjust the command buffer size by 1 word so that in the case of using only
103** two word PKO commands no command words stradle buffers.  The useful values
104** for this are 0 and 1. */
105#define CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST (1)
106
107#ifdef	__cplusplus
108extern "C" {
109#endif
110
111#define CVMX_PKO_MAX_OUTPUT_QUEUES_STATIC 256
112#define CVMX_PKO_MAX_OUTPUT_QUEUES      ((OCTEON_IS_MODEL(OCTEON_CN31XX) || \
113					  OCTEON_IS_MODEL(OCTEON_CN3010) || \
114					  OCTEON_IS_MODEL(OCTEON_CN3005) || \
115					  OCTEON_IS_MODEL(OCTEON_CN50XX)) ? \
116					  32 :				    \
117					 (OCTEON_IS_MODEL(OCTEON_CN58XX) || \
118					  OCTEON_IS_MODEL(OCTEON_CN56XX) || \
119					  OCTEON_IS_MODEL(OCTEON_CN52XX) || \
120					  OCTEON_IS_MODEL(OCTEON_CN6XXX) || \
121					  OCTEON_IS_MODEL(OCTEON_CNF7XXX)) ? \
122					  256 : 128)
123#define CVMX_PKO_NUM_OUTPUT_PORTS       ((OCTEON_IS_MODEL(OCTEON_CN63XX)) ? 44 : (OCTEON_IS_MODEL(OCTEON_CN66XX) ? 46 : 40))
124#define CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID 63 /* use this for queues that are not used */
125#define CVMX_PKO_QUEUE_STATIC_PRIORITY  9
126#define CVMX_PKO_ILLEGAL_QUEUE  0xFFFF
127#define CVMX_PKO_MAX_QUEUE_DEPTH 0
128
129typedef enum
130{
131    CVMX_PKO_SUCCESS,
132    CVMX_PKO_INVALID_PORT,
133    CVMX_PKO_INVALID_QUEUE,
134    CVMX_PKO_INVALID_PRIORITY,
135    CVMX_PKO_NO_MEMORY,
136    CVMX_PKO_PORT_ALREADY_SETUP,
137    CVMX_PKO_CMD_QUEUE_INIT_ERROR
138} cvmx_pko_status_t;
139
140/**
141 * This enumeration represents the differnet locking modes supported by PKO.
142 */
143typedef enum
144{
145    CVMX_PKO_LOCK_NONE = 0,         /**< PKO doesn't do any locking. It is the responsibility
146                                        of the application to make sure that no other core is
147                                        accessing the same queue at the same time */
148    CVMX_PKO_LOCK_ATOMIC_TAG = 1,   /**< PKO performs an atomic tagswitch to insure exclusive
149                                        access to the output queue. This will maintain
150                                        packet ordering on output */
151    CVMX_PKO_LOCK_CMD_QUEUE = 2,    /**< PKO uses the common command queue locks to insure
152                                        exclusive access to the output queue. This is a memory
153                                        based ll/sc. This is the most portable locking
154                                        mechanism */
155} cvmx_pko_lock_t;
156
157typedef struct
158{
159    uint32_t packets;
160    uint64_t octets;
161    uint64_t doorbell;
162} cvmx_pko_port_status_t;
163
164/**
165 * This structure defines the address to use on a packet enqueue
166 */
167typedef union
168{
169    uint64_t                u64;
170    struct
171    {
172        cvmx_mips_space_t   mem_space   : 2;    /**< Must CVMX_IO_SEG */
173        uint64_t            reserved    :13;    /**< Must be zero */
174        uint64_t            is_io       : 1;    /**< Must be one */
175        uint64_t            did         : 8;    /**< The ID of the device on the non-coherent bus */
176        uint64_t            reserved2   : 4;    /**< Must be zero */
177        uint64_t            reserved3   :15;    /**< Must be zero */
178        uint64_t            port        : 9;    /**< The hardware must have the output port in addition to the output queue */
179        uint64_t            queue       : 9;    /**< The output queue to send the packet to (0-127 are legal) */
180        uint64_t            reserved4   : 3;    /**< Must be zero */
181   } s;
182} cvmx_pko_doorbell_address_t;
183
184/**
185 * Structure of the first packet output command word.
186 */
187typedef union
188{
189    uint64_t                u64;
190    struct
191    {
192        cvmx_fau_op_size_t  size1       : 2; /**< The size of the reg1 operation - could be 8, 16, 32, or 64 bits */
193        cvmx_fau_op_size_t  size0       : 2; /**< The size of the reg0 operation - could be 8, 16, 32, or 64 bits */
194        uint64_t            subone1     : 1; /**< If set, subtract 1, if clear, subtract packet size */
195        uint64_t            reg1        :11; /**< The register, subtract will be done if reg1 is non-zero */
196        uint64_t            subone0     : 1; /**< If set, subtract 1, if clear, subtract packet size */
197        uint64_t            reg0        :11; /**< The register, subtract will be done if reg0 is non-zero */
198        uint64_t            le          : 1; /**< When set, interpret segment pointer and segment bytes in little endian order */
199        uint64_t            n2          : 1; /**< When set, packet data not allocated in L2 cache by PKO */
200        uint64_t            wqp         : 1; /**< If set and rsp is set, word3 contains a pointer to a work queue entry */
201        uint64_t            rsp         : 1; /**< If set, the hardware will send a response when done */
202        uint64_t            gather      : 1; /**< If set, the supplied pkt_ptr is really a pointer to a list of pkt_ptr's */
203        uint64_t            ipoffp1     : 7; /**< If ipoffp1 is non zero, (ipoffp1-1) is the number of bytes to IP header,
204                                                and the hardware will calculate and insert the  UDP/TCP checksum */
205        uint64_t            ignore_i    : 1; /**< If set, ignore the I bit (force to zero) from all pointer structures */
206        uint64_t            dontfree    : 1; /**< If clear, the hardware will attempt to free the buffers containing the packet */
207        uint64_t            segs        : 6; /**< The total number of segs in the packet, if gather set, also gather list length */
208        uint64_t            total_bytes :16; /**< Including L2, but no trailing CRC */
209    } s;
210} cvmx_pko_command_word0_t;
211
212/* CSR typedefs have been moved to cvmx-pko-defs.h */
213
214/**
215 * Definition of internal state for Packet output processing
216 */
217typedef struct
218{
219    uint64_t *      start_ptr;          /**< ptr to start of buffer, offset kept in FAU reg */
220} cvmx_pko_state_elem_t;
221
222
223#ifdef CVMX_ENABLE_PKO_FUNCTIONS
224/**
225 * Call before any other calls to initialize the packet
226 * output system.
227 */
228extern void cvmx_pko_initialize_global(void);
229extern int cvmx_pko_initialize_local(void);
230
231#endif
232
233
234/**
235 * Enables the packet output hardware. It must already be
236 * configured.
237 */
238extern void cvmx_pko_enable(void);
239
240
241/**
242 * Disables the packet output. Does not affect any configuration.
243 */
244extern void cvmx_pko_disable(void);
245
246
247/**
248 * Shutdown and free resources required by packet output.
249 */
250
251#ifdef CVMX_ENABLE_PKO_FUNCTIONS
252extern void cvmx_pko_shutdown(void);
253
254/**
255 * Configure a output port and the associated queues for use.
256 *
257 * @param port       Port to configure.
258 * @param base_queue First queue number to associate with this port.
259 * @param num_queues Number of queues t oassociate with this port
260 * @param priority   Array of priority levels for each queue. Values are
261 *                   allowed to be 1-8. A value of 8 get 8 times the traffic
262 *                   of a value of 1. There must be num_queues elements in the
263 *                   array.
264 */
265extern cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue, uint64_t num_queues, const uint64_t priority[]);
266
267
268/**
269 * Ring the packet output doorbell. This tells the packet
270 * output hardware that "len" command words have been added
271 * to its pending list.  This command includes the required
272 * CVMX_SYNCWS before the doorbell ring.
273 *
274 * WARNING: This function may have to look up the proper PKO port in
275 * the IPD port to PKO port map, and is thus slower than calling
276 * cvmx_pko_doorbell_pkoid() directly if the PKO port identifier is
277 * known.
278 *
279 * @param ipd_port   The IPD port corresponding the to pko port the packet is for
280 * @param queue  Queue the packet is for
281 * @param len    Length of the command in 64 bit words
282 */
283static inline void cvmx_pko_doorbell(uint64_t ipd_port, uint64_t queue, uint64_t len)
284{
285   cvmx_pko_doorbell_address_t ptr;
286   uint64_t pko_port;
287
288   pko_port = ipd_port;
289   if (octeon_has_feature(OCTEON_FEATURE_PKND))
290	pko_port = cvmx_helper_cfg_ipd2pko_port_base(ipd_port);
291
292   ptr.u64          = 0;
293   ptr.s.mem_space  = CVMX_IO_SEG;
294   ptr.s.did        = CVMX_OCT_DID_PKT_SEND;
295   ptr.s.is_io      = 1;
296   ptr.s.port       = pko_port;
297   ptr.s.queue      = queue;
298   CVMX_SYNCWS;  /* Need to make sure output queue data is in DRAM before doorbell write */
299   cvmx_write_io(ptr.u64, len);
300}
301#endif
302
303
304/**
305 * Prepare to send a packet.  This may initiate a tag switch to
306 * get exclusive access to the output queue structure, and
307 * performs other prep work for the packet send operation.
308 *
309 * cvmx_pko_send_packet_finish() MUST be called after this function is called,
310 * and must be called with the same port/queue/use_locking arguments.
311 *
312 * The use_locking parameter allows the caller to use three
313 * possible locking modes.
314 * - CVMX_PKO_LOCK_NONE
315 *      - PKO doesn't do any locking. It is the responsibility
316 *          of the application to make sure that no other core
317 *          is accessing the same queue at the same time.
318 * - CVMX_PKO_LOCK_ATOMIC_TAG
319 *      - PKO performs an atomic tagswitch to insure exclusive
320 *          access to the output queue. This will maintain
321 *          packet ordering on output.
322 * - CVMX_PKO_LOCK_CMD_QUEUE
323 *      - PKO uses the common command queue locks to insure
324 *          exclusive access to the output queue. This is a
325 *          memory based ll/sc. This is the most portable
326 *          locking mechanism.
327 *
328 * NOTE: If atomic locking is used, the POW entry CANNOT be
329 * descheduled, as it does not contain a valid WQE pointer.
330 *
331 * @param port   Port to send it on, this can be either IPD port or PKO
332 * 		 port.
333 * @param queue  Queue to use
334 * @param use_locking
335 *               CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE
336 */
337#ifdef CVMX_ENABLE_PKO_FUNCTIONS
338static inline void cvmx_pko_send_packet_prepare(uint64_t port, uint64_t queue, cvmx_pko_lock_t use_locking)
339{
340    if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG)
341    {
342        /* Must do a full switch here to handle all cases.  We use a fake WQE pointer, as the POW does
343        ** not access this memory.  The WQE pointer and group are only used if this work is descheduled,
344        ** which is not supported by the cvmx_pko_send_packet_prepare/cvmx_pko_send_packet_finish combination.
345        ** Note that this is a special case in which these fake values can be used - this is not a general technique.
346        */
347        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);
348        cvmx_pow_tag_sw_full((cvmx_wqe_t *)cvmx_phys_to_ptr(0x80), tag, CVMX_POW_TAG_TYPE_ATOMIC, 0);
349    }
350}
351
352#define cvmx_pko_send_packet_prepare_pkoid	cvmx_pko_send_packet_prepare
353
354/**
355 * Complete packet output. cvmx_pko_send_packet_prepare() must be called exactly once before this,
356 * and the same parameters must be passed to both cvmx_pko_send_packet_prepare() and
357 * cvmx_pko_send_packet_finish().
358 *
359 * WARNING: This function may have to look up the proper PKO port in
360 * the IPD port to PKO port map, and is thus slower than calling
361 * cvmx_pko_send_packet_finish_pkoid() directly if the PKO port
362 * identifier is known.
363 *
364 * @param ipd_port   The IPD port corresponding the to pko port the packet is for
365 * @param queue  Queue to use
366 * @param pko_command
367 *               PKO HW command word
368 * @param packet Packet to send
369 * @param use_locking
370 *               CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE
371 *
372 * @return returns CVMX_PKO_SUCCESS on success, or error code on failure of output
373 */
374static inline cvmx_pko_status_t cvmx_pko_send_packet_finish(uint64_t ipd_port, uint64_t queue,
375                                        cvmx_pko_command_word0_t pko_command,
376                                        cvmx_buf_ptr_t packet, cvmx_pko_lock_t use_locking)
377{
378    cvmx_cmd_queue_result_t result;
379    if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG)
380        cvmx_pow_tag_sw_wait();
381    result = cvmx_cmd_queue_write2(CVMX_CMD_QUEUE_PKO(queue),
382                                   (use_locking == CVMX_PKO_LOCK_CMD_QUEUE),
383                                   pko_command.u64,
384                                   packet.u64);
385    if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS))
386    {
387        cvmx_pko_doorbell(ipd_port, queue, 2);
388        return CVMX_PKO_SUCCESS;
389    }
390    else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == CVMX_CMD_QUEUE_FULL))
391    {
392        return CVMX_PKO_NO_MEMORY;
393    }
394    else
395    {
396        return CVMX_PKO_INVALID_QUEUE;
397    }
398}
399
400
401/**
402 * Complete packet output. cvmx_pko_send_packet_prepare() must be called exactly once before this,
403 * and the same parameters must be passed to both cvmx_pko_send_packet_prepare() and
404 * cvmx_pko_send_packet_finish().
405 *
406 * WARNING: This function may have to look up the proper PKO port in
407 * the IPD port to PKO port map, and is thus slower than calling
408 * cvmx_pko_send_packet_finish3_pkoid() directly if the PKO port
409 * identifier is known.
410 *
411 * @param ipd_port   The IPD port corresponding the to pko port the packet is for
412 * @param queue  Queue to use
413 * @param pko_command
414 *               PKO HW command word
415 * @param packet Packet to send
416 * @param addr   Plysical address of a work queue entry or physical address to zero on complete.
417 * @param use_locking
418 *               CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE
419 *
420 * @return returns CVMX_PKO_SUCCESS on success, or error code on failure of output
421 */
422static inline cvmx_pko_status_t cvmx_pko_send_packet_finish3(uint64_t ipd_port, uint64_t queue,
423                                        cvmx_pko_command_word0_t pko_command,
424                                        cvmx_buf_ptr_t packet, uint64_t addr, cvmx_pko_lock_t use_locking)
425{
426    cvmx_cmd_queue_result_t result;
427    if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG)
428        cvmx_pow_tag_sw_wait();
429    result = cvmx_cmd_queue_write3(CVMX_CMD_QUEUE_PKO(queue),
430                                   (use_locking == CVMX_PKO_LOCK_CMD_QUEUE),
431                                   pko_command.u64,
432                                   packet.u64,
433                                   addr);
434    if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS))
435    {
436        cvmx_pko_doorbell(ipd_port, queue, 3);
437        return CVMX_PKO_SUCCESS;
438    }
439    else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == CVMX_CMD_QUEUE_FULL))
440    {
441        return CVMX_PKO_NO_MEMORY;
442    }
443    else
444    {
445        return CVMX_PKO_INVALID_QUEUE;
446    }
447}
448
449/**
450 * Get the first pko_port for the (interface, index)
451 *
452 * @param interface
453 * @param index
454 */
455extern int cvmx_pko_get_base_pko_port(int interface, int index);
456
457/**
458 * Get the number of pko_ports for the (interface, index)
459 *
460 * @param interface
461 * @param index
462 */
463extern int cvmx_pko_get_num_pko_ports(int interface, int index);
464
465/**
466 * Return the pko output queue associated with a port and a specific core.
467 * In normal mode (PKO lockless operation is disabled), the value returned
468 * is the base queue.
469 *
470 * @param port   Port number
471 * @param core   Core to get queue for
472 *
473 * @return Core-specific output queue and -1 on error.
474 *
475 * Note: This function is invalid for o68.
476 */
477static inline int cvmx_pko_get_base_queue_per_core(int port, int core)
478{
479    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
480    {
481	cvmx_dprintf("cvmx_pko_get_base_queue_per_core() not"
482	    "supported starting from o68!\n");
483        return -1;
484    }
485
486#ifndef CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0
487    #define CVMX_HELPER_PKO_MAX_PORTS_INTERFACE0 16
488#endif
489#ifndef CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1
490    #define CVMX_HELPER_PKO_MAX_PORTS_INTERFACE1 16
491#endif
492#ifndef CVMX_PKO_QUEUES_PER_PORT_SRIO0
493    /* We use two queues per port for SRIO0. Having two queues per
494        port with two ports gives us four queues, one for each mailbox */
495    #define CVMX_PKO_QUEUES_PER_PORT_SRIO0 2
496#endif
497#ifndef CVMX_PKO_QUEUES_PER_PORT_SRIO1
498    /* We use two queues per port for SRIO1. Having two queues per
499        port with two ports gives us four queues, one for each mailbox */
500    #define CVMX_PKO_QUEUES_PER_PORT_SRIO1 2
501#endif
502#ifndef CVMX_PKO_QUEUES_PER_PORT_SRIO2
503    /* We use two queues per port for SRIO2. Having two queues per
504        port with two ports gives us four queues, one for each mailbox */
505    #define CVMX_PKO_QUEUES_PER_PORT_SRIO2 2
506#endif
507    if (port < CVMX_PKO_MAX_PORTS_INTERFACE0)
508        return port * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 + core;
509    else if (port >=16 && port < 16 + CVMX_PKO_MAX_PORTS_INTERFACE1)
510        return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 +
511	       (port-16) * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 + core;
512    else if ((port >= 32) && (port < 36))
513        return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 +
514               CVMX_PKO_MAX_PORTS_INTERFACE1 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 +
515               (port-32) * CVMX_PKO_QUEUES_PER_PORT_PCI;
516    else if ((port >= 36) && (port < 40))
517        return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 +
518               CVMX_PKO_MAX_PORTS_INTERFACE1 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 +
519               4 * CVMX_PKO_QUEUES_PER_PORT_PCI +
520               (port-36) * CVMX_PKO_QUEUES_PER_PORT_LOOP;
521    else if ((port >= 40) && (port < 42))
522        return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 +
523               CVMX_PKO_MAX_PORTS_INTERFACE1 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 +
524               4 * CVMX_PKO_QUEUES_PER_PORT_PCI +
525               4 * CVMX_PKO_QUEUES_PER_PORT_LOOP +
526	       (port-40) * CVMX_PKO_QUEUES_PER_PORT_SRIO0;
527    else if ((port >= 42) && (port < 44))
528        return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 +
529               CVMX_PKO_MAX_PORTS_INTERFACE1 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 +
530               4 * CVMX_PKO_QUEUES_PER_PORT_PCI +
531               4 * CVMX_PKO_QUEUES_PER_PORT_LOOP +
532	       2 * CVMX_PKO_QUEUES_PER_PORT_SRIO0 +
533	       (port-42) * CVMX_PKO_QUEUES_PER_PORT_SRIO1;
534    else if ((port >= 44) && (port < 46))
535        return CVMX_PKO_MAX_PORTS_INTERFACE0 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE0 +
536               CVMX_PKO_MAX_PORTS_INTERFACE1 * CVMX_PKO_QUEUES_PER_PORT_INTERFACE1 +
537               4 * CVMX_PKO_QUEUES_PER_PORT_PCI +
538               4 * CVMX_PKO_QUEUES_PER_PORT_LOOP +
539	       4 * CVMX_PKO_QUEUES_PER_PORT_SRIO0 +
540	       (port-44) * CVMX_PKO_QUEUES_PER_PORT_SRIO2;
541    else
542        /* Given the limit on the number of ports we can map to
543         * CVMX_MAX_OUTPUT_QUEUES_STATIC queues (currently 256,
544         * divided among all cores), the remaining unmapped ports
545         * are assigned an illegal queue number */
546        return CVMX_PKO_ILLEGAL_QUEUE;
547}
548
549/**
550 * For a given port number, return the base pko output queue
551 * for the port.
552 *
553 * @param port   IPD port number
554 * @return Base output queue
555 */
556extern int cvmx_pko_get_base_queue(int port);
557
558/**
559 * For a given port number, return the number of pko output queues.
560 *
561 * @param port   IPD port number
562 * @return Number of output queues
563 */
564extern int cvmx_pko_get_num_queues(int port);
565
566#ifdef CVMX_ENABLE_PKO_FUNCTIONS
567
568/**
569 * Get the status counters for a port.
570 *
571 * @param ipd_port Port number (ipd_port) to get statistics for.
572 * @param clear    Set to 1 to clear the counters after they are read
573 * @param status   Where to put the results.
574 *
575 * Note:
576 *     - Only the doorbell for the base queue of the ipd_port is
577 *       collected.
578 *     - Retrieving the stats involves writing the index through
579 *       CVMX_PKO_REG_READ_IDX and reading the stat CSRs, in that
580 *       order. It is not MP-safe and caller should guarantee
581 *       atomicity.
582 */
583static inline void cvmx_pko_get_port_status(uint64_t ipd_port, uint64_t clear,
584    cvmx_pko_port_status_t *status)
585{
586    cvmx_pko_reg_read_idx_t pko_reg_read_idx;
587    cvmx_pko_mem_count0_t pko_mem_count0;
588    cvmx_pko_mem_count1_t pko_mem_count1;
589    int pko_port, port_base, port_limit;
590
591    if (octeon_has_feature(OCTEON_FEATURE_PKND)) {
592        int interface = cvmx_helper_get_interface_num(ipd_port);
593        int index = cvmx_helper_get_interface_index_num(ipd_port);
594        port_base = cvmx_helper_get_pko_port(interface, index);
595        if (port_base == -1)
596            cvmx_dprintf("Warning: Invalid port_base\n");
597	port_limit = port_base + cvmx_pko_get_num_pko_ports(interface, index);
598    } else {
599        port_base = ipd_port;
600	port_limit = port_base + 1;
601    }
602
603    /*
604     * status->packets and status->octets
605     */
606    status->packets = 0;
607    status->octets = 0;
608    pko_reg_read_idx.u64 = 0;
609
610    for (pko_port = port_base; pko_port < port_limit; pko_port++)
611    {
612
613	/*
614	 * In theory, one doesn't need to write the index csr every
615	 * time as he can set pko_reg_read_idx.s.inc to increment
616	 * the index automatically. Need to find out exactly how XXX.
617	 */
618        pko_reg_read_idx.s.index = pko_port;
619        cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64);
620
621        pko_mem_count0.u64 = cvmx_read_csr(CVMX_PKO_MEM_COUNT0);
622        status->packets += pko_mem_count0.s.count;
623        if (clear)
624        {
625            pko_mem_count0.s.count = pko_port;
626            cvmx_write_csr(CVMX_PKO_MEM_COUNT0, pko_mem_count0.u64);
627        }
628
629        pko_mem_count1.u64 = cvmx_read_csr(CVMX_PKO_MEM_COUNT1);
630        status->octets += pko_mem_count1.s.count;
631        if (clear)
632        {
633            pko_mem_count1.s.count = pko_port;
634            cvmx_write_csr(CVMX_PKO_MEM_COUNT1, pko_mem_count1.u64);
635        }
636    }
637
638    /*
639     * status->doorbell
640     */
641    if (OCTEON_IS_MODEL(OCTEON_CN3XXX))
642    {
643        cvmx_pko_mem_debug9_t debug9;
644        pko_reg_read_idx.s.index = cvmx_pko_get_base_queue(ipd_port);
645        cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64);
646        debug9.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG9);
647        status->doorbell = debug9.cn38xx.doorbell;
648    }
649    else
650    {
651        cvmx_pko_mem_debug8_t debug8;
652        pko_reg_read_idx.s.index = cvmx_pko_get_base_queue(ipd_port);
653        cvmx_write_csr(CVMX_PKO_REG_READ_IDX, pko_reg_read_idx.u64);
654        debug8.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG8);
655        if (OCTEON_IS_MODEL(OCTEON_CN68XX))
656            status->doorbell = debug8.cn68xx.doorbell;
657        else
658            status->doorbell = debug8.cn58xx.doorbell;
659    }
660}
661
662#endif /* CVMX_ENABLE_PKO_FUNCTION */
663
664
665/**
666 * Rate limit a PKO port to a max packets/sec. This function is only
667 * supported on CN57XX, CN56XX, CN55XX, and CN54XX.
668 *
669 * @param port      Port to rate limit
670 * @param packets_s Maximum packet/sec
671 * @param burst     Maximum number of packets to burst in a row before rate
672 *                  limiting cuts in.
673 *
674 * @return Zero on success, negative on failure
675 */
676extern int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst);
677
678/**
679 * Rate limit a PKO port to a max bits/sec. This function is only
680 * supported on CN57XX, CN56XX, CN55XX, and CN54XX.
681 *
682 * @param port   Port to rate limit
683 * @param bits_s PKO rate limit in bits/sec
684 * @param burst  Maximum number of bits to burst before rate
685 *               limiting cuts in.
686 *
687 * @return Zero on success, negative on failure
688 */
689extern int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst);
690
691/**
692 * @INTERNAL
693 *
694 * Retrieve the PKO pipe number for a port
695 *
696 * @param interface
697 * @param index
698 *
699 * @return negative on error.
700 *
701 * This applies only to the non-loopback interfaces.
702 *
703 */
704extern int __cvmx_pko_get_pipe(int interface, int index);
705
706/**
707 * For a given PKO port number, return the base output queue
708 * for the port.
709 *
710 * @param pko_port   PKO port number
711 * @return           Base output queue
712 */
713extern int cvmx_pko_get_base_queue_pkoid(int pko_port);
714
715/**
716 * For a given PKO port number, return the number of output queues
717 * for the port.
718 *
719 * @param pko_port	PKO port number
720 * @return		the number of output queues
721 */
722extern int cvmx_pko_get_num_queues_pkoid(int pko_port);
723
724/**
725 * Ring the packet output doorbell. This tells the packet
726 * output hardware that "len" command words have been added
727 * to its pending list.  This command includes the required
728 * CVMX_SYNCWS before the doorbell ring.
729 *
730 * @param pko_port   Port the packet is for
731 * @param queue  Queue the packet is for
732 * @param len    Length of the command in 64 bit words
733 */
734static inline void cvmx_pko_doorbell_pkoid(uint64_t pko_port, uint64_t queue, uint64_t len)
735{
736   cvmx_pko_doorbell_address_t ptr;
737
738   ptr.u64          = 0;
739   ptr.s.mem_space  = CVMX_IO_SEG;
740   ptr.s.did        = CVMX_OCT_DID_PKT_SEND;
741   ptr.s.is_io      = 1;
742   ptr.s.port       = pko_port;
743   ptr.s.queue      = queue;
744   CVMX_SYNCWS;  /* Need to make sure output queue data is in DRAM before doorbell write */
745   cvmx_write_io(ptr.u64, len);
746}
747
748/**
749 * Complete packet output. cvmx_pko_send_packet_prepare() must be called exactly once before this,
750 * and the same parameters must be passed to both cvmx_pko_send_packet_prepare() and
751 * cvmx_pko_send_packet_finish_pkoid().
752 *
753 * @param pko_port   Port to send it on
754 * @param queue  Queue to use
755 * @param pko_command
756 *               PKO HW command word
757 * @param packet Packet to send
758 * @param use_locking
759 *               CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE
760 *
761 * @return returns CVMX_PKO_SUCCESS on success, or error code on failure of output
762 */
763static inline cvmx_pko_status_t cvmx_pko_send_packet_finish_pkoid(int pko_port, uint64_t queue,
764                                        cvmx_pko_command_word0_t pko_command,
765                                        cvmx_buf_ptr_t packet, cvmx_pko_lock_t use_locking)
766{
767    cvmx_cmd_queue_result_t result;
768    if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG)
769        cvmx_pow_tag_sw_wait();
770    result = cvmx_cmd_queue_write2(CVMX_CMD_QUEUE_PKO(queue),
771                                   (use_locking == CVMX_PKO_LOCK_CMD_QUEUE),
772                                   pko_command.u64,
773                                   packet.u64);
774    if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS))
775    {
776        cvmx_pko_doorbell_pkoid(pko_port, queue, 2);
777        return CVMX_PKO_SUCCESS;
778    }
779    else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == CVMX_CMD_QUEUE_FULL))
780    {
781        return CVMX_PKO_NO_MEMORY;
782    }
783    else
784    {
785        return CVMX_PKO_INVALID_QUEUE;
786    }
787}
788
789/**
790 * Complete packet output. cvmx_pko_send_packet_prepare() must be called exactly once before this,
791 * and the same parameters must be passed to both cvmx_pko_send_packet_prepare() and
792 * cvmx_pko_send_packet_finish_pkoid().
793 *
794 * @param pko_port   The PKO port the packet is for
795 * @param queue  Queue to use
796 * @param pko_command
797 *               PKO HW command word
798 * @param packet Packet to send
799 * @param addr   Plysical address of a work queue entry or physical address to zero on complete.
800 * @param use_locking
801 *               CVMX_PKO_LOCK_NONE, CVMX_PKO_LOCK_ATOMIC_TAG, or CVMX_PKO_LOCK_CMD_QUEUE
802 *
803 * @return returns CVMX_PKO_SUCCESS on success, or error code on failure of output
804 */
805static inline cvmx_pko_status_t cvmx_pko_send_packet_finish3_pkoid(uint64_t pko_port, uint64_t queue,
806                                        cvmx_pko_command_word0_t pko_command,
807                                        cvmx_buf_ptr_t packet, uint64_t addr, cvmx_pko_lock_t use_locking)
808{
809    cvmx_cmd_queue_result_t result;
810    if (use_locking == CVMX_PKO_LOCK_ATOMIC_TAG)
811        cvmx_pow_tag_sw_wait();
812    result = cvmx_cmd_queue_write3(CVMX_CMD_QUEUE_PKO(queue),
813                                   (use_locking == CVMX_PKO_LOCK_CMD_QUEUE),
814                                   pko_command.u64,
815                                   packet.u64,
816                                   addr);
817    if (cvmx_likely(result == CVMX_CMD_QUEUE_SUCCESS))
818    {
819        cvmx_pko_doorbell_pkoid(pko_port, queue, 3);
820        return CVMX_PKO_SUCCESS;
821    }
822    else if ((result == CVMX_CMD_QUEUE_NO_MEMORY) || (result == CVMX_CMD_QUEUE_FULL))
823    {
824        return CVMX_PKO_NO_MEMORY;
825    }
826    else
827    {
828        return CVMX_PKO_INVALID_QUEUE;
829    }
830}
831
832#endif /* CVMX_ENABLE_PKO_FUNCTIONS */
833
834#ifdef	__cplusplus
835}
836#endif
837
838#endif   /* __CVMX_PKO_H__ */
839