1210284Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3215990Sjmallett * reserved.
4210284Sjmallett *
5210284Sjmallett *
6215990Sjmallett * Redistribution and use in source and binary forms, with or without
7215990Sjmallett * modification, are permitted provided that the following conditions are
8215990Sjmallett * met:
9210284Sjmallett *
10215990Sjmallett *   * Redistributions of source code must retain the above copyright
11215990Sjmallett *     notice, this list of conditions and the following disclaimer.
12210284Sjmallett *
13215990Sjmallett *   * Redistributions in binary form must reproduce the above
14215990Sjmallett *     copyright notice, this list of conditions and the following
15215990Sjmallett *     disclaimer in the documentation and/or other materials provided
16215990Sjmallett *     with the distribution.
17215990Sjmallett
18232812Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19215990Sjmallett *     its contributors may be used to endorse or promote products
20215990Sjmallett *     derived from this software without specific prior written
21215990Sjmallett *     permission.
22215990Sjmallett
23215990Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215990Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215990Sjmallett * regulations, and may be subject to export or import  regulations in other
26215990Sjmallett * countries.
27215990Sjmallett
28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38210284Sjmallett ***********************license end**************************************/
39210284Sjmallett
40210284Sjmallett/**
41210284Sjmallett * @file
42210284Sjmallett *
43210284Sjmallett * Support library for the hardware Packet Output unit.
44210284Sjmallett *
45232812Sjmallett * <hr>$Revision: 70030 $<hr>
46210284Sjmallett */
47215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
48215990Sjmallett#include <asm/octeon/cvmx.h>
49215990Sjmallett#include <asm/octeon/cvmx-config.h>
50215990Sjmallett#include <asm/octeon/cvmx-pko.h>
51215990Sjmallett#include <asm/octeon/cvmx-helper.h>
52232812Sjmallett#include <asm/octeon/cvmx-helper-cfg.h>
53215990Sjmallett#include <asm/octeon/cvmx-clock.h>
54215990Sjmallett#else
55215990Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL)
56215990Sjmallett#include "executive-config.h"
57215990Sjmallett#endif
58210284Sjmallett#include "cvmx.h"
59215990Sjmallett#include "cvmx-sysinfo.h"
60215990Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL)
61215990Sjmallett#include "cvmx-config.h"
62215990Sjmallett#endif
63210284Sjmallett#include "cvmx-pko.h"
64210284Sjmallett#include "cvmx-helper.h"
65232812Sjmallett#include "cvmx-helper-cfg.h"
66215990Sjmallett#endif
67210284Sjmallett
68232812Sjmallett/* #define PKO_DEBUG */
69232812Sjmallett
70232812Sjmallett#define CVMX_PKO_NQ_PER_PORT_MAX	32
71232812Sjmallett
72210284Sjmallett/**
73210284Sjmallett * Internal state of packet output
74210284Sjmallett */
75210284Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
76210284Sjmallett
77232812Sjmallett/*
78232812Sjmallett * PKO port iterator
79232812Sjmallett */
80232812Sjmallett#define CVMX_PKO_FOR_EACH_PORT_BEGIN	do { 					\
81232812Sjmallett	int XIT_pko_port;							\
82232812Sjmallett	for (XIT_pko_port = 0; XIT_pko_port < CVMX_HELPER_CFG_MAX_PKO_PORT;	\
83232812Sjmallett	    XIT_pko_port++)							\
84232812Sjmallett	{									\
85232812Sjmallett		if (__cvmx_helper_cfg_pko_queue_base(XIT_pko_port) !=		\
86232812Sjmallett	            CVMX_HELPER_CFG_INVALID_VALUE)
87232812Sjmallett
88232812Sjmallett#define CVMX_PKO_FOR_EACH_PORT_END	} /* for */			\
89232812Sjmallett					} while (0)
90232812Sjmallett
91232812Sjmallett/*
92232812Sjmallett * @INTERNAL
93232812Sjmallett *
94232812Sjmallett * Get INT for a port
95232812Sjmallett *
96232812Sjmallett * @param interface
97232812Sjmallett * @param index
98232812Sjmallett * @return the INT value on success and -1 on error
99232812Sjmallett */
100232812Sjmallettstatic int __cvmx_pko_int(int interface, int index)
101232812Sjmallett{
102232812Sjmallett    cvmx_helper_cfg_assert(interface < CVMX_HELPER_CFG_MAX_IFACE);
103232812Sjmallett    cvmx_helper_cfg_assert(index >= 0);
104232812Sjmallett
105232812Sjmallett    switch (interface)
106232812Sjmallett    {
107232812Sjmallett    case 0:
108232812Sjmallett        cvmx_helper_cfg_assert(index < 4);
109232812Sjmallett        return index;
110232812Sjmallett	break;
111232812Sjmallett    case 1:
112232812Sjmallett        cvmx_helper_cfg_assert(index == 0);
113232812Sjmallett        return 4;
114232812Sjmallett	break;
115232812Sjmallett    case 2:
116232812Sjmallett        cvmx_helper_cfg_assert(index < 4);
117232812Sjmallett        return index + 8;
118232812Sjmallett	break;
119232812Sjmallett    case 3:
120232812Sjmallett        cvmx_helper_cfg_assert(index < 4);
121232812Sjmallett        return index + 0xC;
122232812Sjmallett	break;
123232812Sjmallett    case 4:
124232812Sjmallett        cvmx_helper_cfg_assert(index < 4);
125232812Sjmallett        return index + 0x10;
126232812Sjmallett	break;
127232812Sjmallett    case 5:
128232812Sjmallett        cvmx_helper_cfg_assert(index < 256);
129232812Sjmallett        return 0x1C;
130232812Sjmallett	break;
131232812Sjmallett    case 6:
132232812Sjmallett        cvmx_helper_cfg_assert(index < 256);
133232812Sjmallett        return 0x1D;
134232812Sjmallett	break;
135232812Sjmallett    case 7:
136232812Sjmallett        cvmx_helper_cfg_assert(index < 32);
137232812Sjmallett        return 0x1E;
138232812Sjmallett	break;
139232812Sjmallett    case 8:
140232812Sjmallett        cvmx_helper_cfg_assert(index < 8);
141232812Sjmallett        return 0x1F;
142232812Sjmallett	break;
143232812Sjmallett    }
144232812Sjmallett
145232812Sjmallett    return -1;
146232812Sjmallett}
147232812Sjmallett
148232812Sjmallettint cvmx_pko_get_base_pko_port(int interface, int index)
149232812Sjmallett{
150232812Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_PKND))
151232812Sjmallett        return __cvmx_helper_cfg_pko_port_base(interface, index);
152232812Sjmallett    else
153232812Sjmallett        return cvmx_helper_get_ipd_port(interface, index);
154232812Sjmallett}
155232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
156232812SjmallettEXPORT_SYMBOL(cvmx_pko_get_base_pko_port);
157232812Sjmallett#endif
158232812Sjmallett
159232812Sjmallettint cvmx_pko_get_num_pko_ports(int interface, int index)
160232812Sjmallett{
161232812Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_PKND))
162232812Sjmallett        return __cvmx_helper_cfg_pko_port_num(interface, index);
163232812Sjmallett    else
164232812Sjmallett        return 1;
165232812Sjmallett}
166232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
167232812SjmallettEXPORT_SYMBOL(cvmx_pko_get_num_pko_ports);
168232812Sjmallett#endif
169232812Sjmallett
170232812Sjmallettint cvmx_pko_get_base_queue(int port)
171232812Sjmallett{
172232812Sjmallett    if (octeon_has_feature(OCTEON_FEATURE_PKND))
173232812Sjmallett    {
174232812Sjmallett        return __cvmx_helper_cfg_pko_queue_base(
175232812Sjmallett	    cvmx_helper_cfg_ipd2pko_port_base(port));
176232812Sjmallett    }
177232812Sjmallett    else
178232812Sjmallett        return cvmx_pko_get_base_queue_per_core(port, 0);
179232812Sjmallett}
180232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
181232812SjmallettEXPORT_SYMBOL(cvmx_pko_get_base_queue);
182232812Sjmallett#endif
183232812Sjmallett
184210284Sjmallett/**
185232812Sjmallett * For a given PKO port number, return the base output queue
186232812Sjmallett * for the port.
187232812Sjmallett *
188232812Sjmallett * @param pko_port   PKO port number
189232812Sjmallett * @return           Base output queue
190232812Sjmallett */
191232812Sjmallettint cvmx_pko_get_base_queue_pkoid(int pko_port)
192232812Sjmallett{
193232812Sjmallett    return __cvmx_helper_cfg_pko_queue_base(pko_port);
194232812Sjmallett}
195232812Sjmallett
196232812Sjmallett/**
197232812Sjmallett * For a given PKO port number, return the number of output queues
198232812Sjmallett * for the port.
199232812Sjmallett *
200232812Sjmallett * @param pko_port	PKO port number
201232812Sjmallett * @return		the number of output queues
202232812Sjmallett */
203232812Sjmallettint cvmx_pko_get_num_queues_pkoid(int pko_port)
204232812Sjmallett{
205232812Sjmallett    return __cvmx_helper_cfg_pko_queue_num(pko_port);
206232812Sjmallett}
207232812Sjmallett
208232812Sjmallettint cvmx_pko_get_num_queues(int port)
209232812Sjmallett{
210232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
211232812Sjmallett    {
212232812Sjmallett        return __cvmx_helper_cfg_pko_queue_num(
213232812Sjmallett	    cvmx_helper_cfg_ipd2pko_port_base(port));
214232812Sjmallett    }
215232812Sjmallett    else
216232812Sjmallett    {
217232812Sjmallett        if (port < 16)
218232812Sjmallett            return CVMX_PKO_QUEUES_PER_PORT_INTERFACE0;
219232812Sjmallett        else if (port < 32)
220232812Sjmallett            return CVMX_PKO_QUEUES_PER_PORT_INTERFACE1;
221232812Sjmallett        else if (port < 36)
222232812Sjmallett            return CVMX_PKO_QUEUES_PER_PORT_PCI;
223232812Sjmallett        else if (port < 40)
224232812Sjmallett            return CVMX_PKO_QUEUES_PER_PORT_LOOP;
225232812Sjmallett        else if (port < 42)
226232812Sjmallett            return CVMX_PKO_QUEUES_PER_PORT_SRIO0;
227232812Sjmallett        else if (port < 44)
228232812Sjmallett            return CVMX_PKO_QUEUES_PER_PORT_SRIO1;
229232812Sjmallett        else if (port < 46)
230232812Sjmallett            return CVMX_PKO_QUEUES_PER_PORT_SRIO2;
231232812Sjmallett    }
232232812Sjmallett    return 0;
233232812Sjmallett}
234232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
235232812SjmallettEXPORT_SYMBOL(cvmx_pko_get_num_queues);
236232812Sjmallett#endif
237232812Sjmallett
238232812Sjmallett#ifdef PKO_DEBUG
239232812Sjmallett/**
240232812Sjmallett * Show queues for the internal ports
241232812Sjmallett */
242232812Sjmallettvoid cvmx_pko_show_queue_map(void)
243232812Sjmallett{
244232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
245232812Sjmallett    {
246232812Sjmallett	CVMX_PKO_FOR_EACH_PORT_BEGIN {
247232812Sjmallett	    cvmx_dprintf("pko_port %d (interface%d index%d) has %d queues (queue base = %d)\n",
248232812Sjmallett	        XIT_pko_port,
249232812Sjmallett		__cvmx_helper_cfg_pko_port_interface(XIT_pko_port),
250232812Sjmallett		__cvmx_helper_cfg_pko_port_index(XIT_pko_port),
251232812Sjmallett		__cvmx_helper_cfg_pko_queue_num(XIT_pko_port),
252232812Sjmallett	        __cvmx_helper_cfg_pko_queue_base(XIT_pko_port));
253232812Sjmallett	} CVMX_PKO_FOR_EACH_PORT_END;
254232812Sjmallett    }
255232812Sjmallett    else
256232812Sjmallett    {
257232812Sjmallett        int core, port;
258232812Sjmallett        int pko_output_ports;
259232812Sjmallett
260232812Sjmallett        pko_output_ports = 36;
261232812Sjmallett        cvmx_dprintf("port");
262232812Sjmallett        for(port = 0; port < pko_output_ports; port++)
263232812Sjmallett            cvmx_dprintf("%3d ", port);
264232812Sjmallett        cvmx_dprintf("\n");
265232812Sjmallett
266232812Sjmallett        for(core = 0; core < CVMX_MAX_CORES; core++)
267232812Sjmallett        {
268232812Sjmallett            cvmx_dprintf("\n%2d: ", core);
269232812Sjmallett            for(port = 0; port < pko_output_ports; port++)
270232812Sjmallett                cvmx_dprintf("%3d ",
271232812Sjmallett		    cvmx_pko_get_base_queue_per_core(port, core));
272232812Sjmallett        }
273232812Sjmallett        cvmx_dprintf("\n");
274232812Sjmallett
275232812Sjmallett    }
276232812Sjmallett}
277232812Sjmallett#endif /* PKO_DEBUG */
278232812Sjmallett
279232812Sjmallett/*
280232812Sjmallett * Configure queues for an internal port.
281232812Sjmallett * @INTERNAL
282232812Sjmallett * @param pko_port PKO internal port number
283232812Sjmallett * Note: o68 only
284232812Sjmallett */
285232812Sjmallettstatic void __cvmx_pko_iport_config(int pko_port)
286232812Sjmallett{
287232812Sjmallett    int queue, base_queue, num_queues;
288232812Sjmallett    int static_priority_base;
289232812Sjmallett    int static_priority_end;
290232812Sjmallett    cvmx_pko_mem_iqueue_ptrs_t config;
291232812Sjmallett    uint64_t  *buf_ptr = NULL;
292232812Sjmallett    uint64_t priorities[CVMX_PKO_NQ_PER_PORT_MAX] = {
293232812Sjmallett        [0 ... CVMX_PKO_NQ_PER_PORT_MAX - 1] = 8 };
294232812Sjmallett
295232812Sjmallett    static_priority_base = -1;
296232812Sjmallett    static_priority_end = -1;
297232812Sjmallett    base_queue = __cvmx_helper_cfg_pko_queue_base(pko_port);
298232812Sjmallett    num_queues = __cvmx_helper_cfg_pko_queue_num(pko_port);
299232812Sjmallett
300232812Sjmallett    /*
301232812Sjmallett     * Give the user a chance to override the per queue priorities.
302232812Sjmallett     */
303232812Sjmallett    if (cvmx_override_pko_queue_priority)
304232812Sjmallett        cvmx_override_pko_queue_priority(pko_port, &priorities[0]);
305232812Sjmallett
306232812Sjmallett    /*
307232812Sjmallett     * static queue priority validation
308232812Sjmallett     */
309232812Sjmallett    for (queue = 0; queue < num_queues; queue++)
310232812Sjmallett    {
311232812Sjmallett        if (static_priority_base == -1 &&
312232812Sjmallett	    priorities[queue] == CVMX_PKO_QUEUE_STATIC_PRIORITY)
313232812Sjmallett	    static_priority_base = queue;
314232812Sjmallett
315232812Sjmallett        if (static_priority_base != -1 &&
316232812Sjmallett	    static_priority_end == -1 &&
317232812Sjmallett	    priorities[queue] != CVMX_PKO_QUEUE_STATIC_PRIORITY &&
318232812Sjmallett	    queue)
319232812Sjmallett	        static_priority_end = queue - 1;
320232812Sjmallett        else if (static_priority_base != -1 &&
321232812Sjmallett	    static_priority_end == -1 &&
322232812Sjmallett	    queue == num_queues - 1)
323232812Sjmallett                static_priority_end = queue;  /* all queues are static priority */
324232812Sjmallett
325232812Sjmallett        /*
326232812Sjmallett	 * Check to make sure all static priority queues are contiguous.
327232812Sjmallett	 * Also catches some cases of static priorites not starting from
328232812Sjmallett	 * queue 0.
329232812Sjmallett	 */
330232812Sjmallett        if (static_priority_end != -1 &&
331232812Sjmallett	    (int)queue > static_priority_end &&
332232812Sjmallett	    priorities[queue] == CVMX_PKO_QUEUE_STATIC_PRIORITY)
333232812Sjmallett        {
334232812Sjmallett            cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Static priority "
335232812Sjmallett	        "queues aren't contiguous or don't start at base queue. "
336232812Sjmallett		"q: %d, eq: %d\n", (int)queue, static_priority_end);
337232812Sjmallett        }
338232812Sjmallett        if (static_priority_base > 0)
339232812Sjmallett        {
340232812Sjmallett            cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Static priority "
341232812Sjmallett	        "queues don't start at base queue. sq: %d\n",
342232812Sjmallett		static_priority_base);
343232812Sjmallett        }
344232812Sjmallett    }
345232812Sjmallett
346232812Sjmallett    /*
347232812Sjmallett     * main loop to set the fields of CVMX_PKO_MEM_IQUEUE_PTRS for
348232812Sjmallett     * each queue
349232812Sjmallett     */
350232812Sjmallett    for (queue = 0; queue < num_queues; queue++)
351232812Sjmallett    {
352232812Sjmallett        config.u64 = 0;
353232812Sjmallett	config.s.index = queue;
354232812Sjmallett	config.s.qid = base_queue + queue;
355232812Sjmallett	config.s.ipid = pko_port;
356232812Sjmallett	config.s.tail = (queue == (num_queues - 1));
357232812Sjmallett        config.s.s_tail = (queue == static_priority_end);
358232812Sjmallett        config.s.static_p = (static_priority_base >= 0);
359232812Sjmallett        config.s.static_q = (queue <= static_priority_end);
360232812Sjmallett
361232812Sjmallett        /*
362232812Sjmallett         * Convert the priority into an enable bit field.
363232812Sjmallett	 * Try to space the bits out evenly so the packet
364232812Sjmallett	 * don't get grouped up.
365232812Sjmallett         */
366232812Sjmallett        switch ((int)priorities[queue])
367232812Sjmallett        {
368232812Sjmallett            case 0: config.s.qos_mask = 0x00; break;
369232812Sjmallett            case 1: config.s.qos_mask = 0x01; break;
370232812Sjmallett            case 2: config.s.qos_mask = 0x11; break;
371232812Sjmallett            case 3: config.s.qos_mask = 0x49; break;
372232812Sjmallett            case 4: config.s.qos_mask = 0x55; break;
373232812Sjmallett            case 5: config.s.qos_mask = 0x57; break;
374232812Sjmallett            case 6: config.s.qos_mask = 0x77; break;
375232812Sjmallett            case 7: config.s.qos_mask = 0x7f; break;
376232812Sjmallett            case 8: config.s.qos_mask = 0xff; break;
377232812Sjmallett            case CVMX_PKO_QUEUE_STATIC_PRIORITY:
378232812Sjmallett                config.s.qos_mask = 0xff;
379232812Sjmallett                break;
380232812Sjmallett            default:
381232812Sjmallett                cvmx_dprintf("ERROR: __cvmx_pko_iport_config: "
382232812Sjmallett		    "Invalid priority %llu\n",
383232812Sjmallett		    (unsigned long long)priorities[queue]);
384232812Sjmallett                config.s.qos_mask = 0xff;
385232812Sjmallett                break;
386232812Sjmallett        }
387232812Sjmallett
388232812Sjmallett	/*
389232812Sjmallett	 * The command queues
390232812Sjmallett	 */
391232812Sjmallett        {
392232812Sjmallett            cvmx_cmd_queue_result_t cmd_res;
393232812Sjmallett
394232812Sjmallett	    cmd_res = cvmx_cmd_queue_initialize(
395232812Sjmallett	        CVMX_CMD_QUEUE_PKO(base_queue + queue),
396232812Sjmallett                CVMX_PKO_MAX_QUEUE_DEPTH,
397232812Sjmallett                CVMX_FPA_OUTPUT_BUFFER_POOL,
398232812Sjmallett                (CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE -
399232812Sjmallett		    CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST * 8));
400232812Sjmallett
401232812Sjmallett            if (cmd_res != CVMX_CMD_QUEUE_SUCCESS)
402232812Sjmallett            {
403232812Sjmallett	        switch (cmd_res)
404232812Sjmallett		{
405232812Sjmallett		    case CVMX_CMD_QUEUE_NO_MEMORY:
406232812Sjmallett                        cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Unable to allocate output buffer.");
407232812Sjmallett                        break;
408232812Sjmallett		    case CVMX_CMD_QUEUE_ALREADY_SETUP:
409232812Sjmallett                        cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Port already setup");
410232812Sjmallett                        break;
411232812Sjmallett		    case CVMX_CMD_QUEUE_INVALID_PARAM:
412232812Sjmallett		    default:
413232812Sjmallett                        cvmx_dprintf("ERROR: __cvmx_pko_iport_config: Command queue initialization failed.");
414232812Sjmallett                        break;
415232812Sjmallett		}
416232812Sjmallett		cvmx_dprintf(" pko_port%d base_queue%d num_queues%d queue%d.\n",
417232812Sjmallett		    pko_port, base_queue, num_queues, queue);
418232812Sjmallett            }
419232812Sjmallett
420232812Sjmallett            buf_ptr = (uint64_t*)cvmx_cmd_queue_buffer(
421232812Sjmallett	        CVMX_CMD_QUEUE_PKO(base_queue + queue));
422232812Sjmallett            config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr) >> 7;
423232812Sjmallett        }
424232812Sjmallett
425232812Sjmallett        CVMX_SYNCWS;
426232812Sjmallett        cvmx_write_csr(CVMX_PKO_MEM_IQUEUE_PTRS, config.u64);
427232812Sjmallett    }
428232812Sjmallett}
429232812Sjmallett
430232812Sjmallett/*
431232812Sjmallett * Allocate queues for the PKO internal ports.
432232812Sjmallett * @INTERNAL
433232812Sjmallett *
434232812Sjmallett */
435232812Sjmallettstatic void __cvmx_pko_queue_alloc_o68(void)
436232812Sjmallett{
437232812Sjmallett    CVMX_PKO_FOR_EACH_PORT_BEGIN {
438232812Sjmallett	__cvmx_pko_iport_config(XIT_pko_port);
439232812Sjmallett    } CVMX_PKO_FOR_EACH_PORT_END;
440232812Sjmallett}
441232812Sjmallett
442232812Sjmallett/*
443232812Sjmallett * Allocate memory for PKO engines.
444232812Sjmallett *
445232812Sjmallett * @param engine is the PKO engine ID.
446232812Sjmallett * @return # of 2KB-chunks allocated to this PKO engine.
447232812Sjmallett */
448232812Sjmallettstatic int __cvmx_pko_memory_per_engine_o68(int engine)
449232812Sjmallett{
450232812Sjmallett    /* CN68XX has 40KB to devide between the engines in 2KB chunks */
451232812Sjmallett    int max_engine;
452232812Sjmallett    int size_per_engine;
453232812Sjmallett    int size;
454232812Sjmallett
455232812Sjmallett    max_engine = __cvmx_helper_cfg_pko_max_engine();
456232812Sjmallett    size_per_engine = 40 / 2 / max_engine;
457232812Sjmallett
458232812Sjmallett    if (engine >= max_engine)
459232812Sjmallett    {
460232812Sjmallett        /* Unused engines get no space */
461232812Sjmallett        size = 0;
462232812Sjmallett    }
463232812Sjmallett    else if (engine == max_engine - 1)
464232812Sjmallett    {
465232812Sjmallett        /* The last engine gets all the space lost by rounding. This means
466232812Sjmallett            the ILK gets the most space */
467232812Sjmallett        size = 40 / 2 - engine * size_per_engine;
468232812Sjmallett    }
469232812Sjmallett    else
470232812Sjmallett    {
471232812Sjmallett        /* All other engines get the same space */
472232812Sjmallett        size = size_per_engine;
473232812Sjmallett    }
474232812Sjmallett
475232812Sjmallett    return size;
476232812Sjmallett}
477232812Sjmallett
478232812Sjmallett/*
479232812Sjmallett * Setup one-to-one mapping between PKO iport and eport.
480232812Sjmallett * @INTERNAL
481232812Sjmallett */
482232812Sjmallettstatic void __cvmx_pko_port_map_o68(void)
483232812Sjmallett{
484232812Sjmallett    int i;
485232812Sjmallett    int interface, index;
486232812Sjmallett    cvmx_helper_interface_mode_t mode;
487232812Sjmallett    cvmx_pko_mem_iport_ptrs_t config;
488232812Sjmallett
489232812Sjmallett    /*
490232812Sjmallett     * Initialize every iport with the invalid eid.
491232812Sjmallett     */
492232812Sjmallett#define CVMX_O68_PKO_INVALID_EID	31
493232812Sjmallett    config.u64 = 0;
494232812Sjmallett    config.s.eid = CVMX_O68_PKO_INVALID_EID;
495232812Sjmallett    for (i = 0; i < CVMX_HELPER_CFG_MAX_PKO_PORT; i++)
496232812Sjmallett    {
497232812Sjmallett        config.s.ipid = i;
498232812Sjmallett        cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64);
499232812Sjmallett    }
500232812Sjmallett
501232812Sjmallett    /*
502232812Sjmallett     * Set up PKO_MEM_IPORT_PTRS
503232812Sjmallett     */
504232812Sjmallett    CVMX_PKO_FOR_EACH_PORT_BEGIN {
505232812Sjmallett	interface = __cvmx_helper_cfg_pko_port_interface(XIT_pko_port);
506232812Sjmallett	index = __cvmx_helper_cfg_pko_port_index(XIT_pko_port);
507232812Sjmallett	mode = cvmx_helper_interface_get_mode(interface);
508232812Sjmallett
509232812Sjmallett	if (mode == CVMX_HELPER_INTERFACE_MODE_DISABLED)
510232812Sjmallett	    continue;
511232812Sjmallett
512232812Sjmallett        config.s.ipid = XIT_pko_port;
513232812Sjmallett        config.s.qos_mask = 0xff;
514232812Sjmallett        config.s.crc = __cvmx_helper_get_has_fcs(interface);
515232812Sjmallett	config.s.min_pkt = __cvmx_helper_get_pko_padding(interface);
516232812Sjmallett        config.s.intr = __cvmx_pko_int(interface, index);
517232812Sjmallett	config.s.eid = __cvmx_helper_cfg_pko_port_eid(XIT_pko_port);
518232812Sjmallett        config.s.pipe = (mode == CVMX_HELPER_INTERFACE_MODE_LOOP) ? index :
519232812Sjmallett	    XIT_pko_port;
520232812Sjmallett        cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64);
521232812Sjmallett    } CVMX_PKO_FOR_EACH_PORT_END;
522232812Sjmallett}
523232812Sjmallett
524232812Sjmallettint __cvmx_pko_get_pipe(int interface, int index)
525232812Sjmallett{
526232812Sjmallett    /*
527232812Sjmallett     * the loopback ports do not have pipes
528232812Sjmallett     */
529232812Sjmallett    if (cvmx_helper_interface_get_mode(interface) ==
530232812Sjmallett        CVMX_HELPER_INTERFACE_MODE_LOOP)
531232812Sjmallett        return -1;
532232812Sjmallett    /*
533232812Sjmallett     * We use pko_port as the pipe. See __cvmx_pko_port_map_o68().
534232812Sjmallett     */
535232812Sjmallett    return cvmx_helper_get_pko_port(interface, index);
536232812Sjmallett}
537232812Sjmallett
538232812Sjmallett/*
539232812Sjmallett * chip-specific setup
540232812Sjmallett * @INTERNAL
541232812Sjmallett */
542232812Sjmallettstatic void __cvmx_pko_chip_init(void)
543232812Sjmallett{
544232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
545232812Sjmallett    {
546232812Sjmallett        __cvmx_pko_port_map_o68();
547232812Sjmallett        __cvmx_pko_queue_alloc_o68();
548232812Sjmallett    }
549232812Sjmallett    else
550232812Sjmallett    {
551232812Sjmallett        int i;
552232812Sjmallett        uint64_t priority = 8;
553232812Sjmallett
554232812Sjmallett        /*
555232812Sjmallett         * Initialize queues
556232812Sjmallett         */
557232812Sjmallett        for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++)
558232812Sjmallett            cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1,
559232812Sjmallett	        &priority);
560232812Sjmallett    }
561232812Sjmallett}
562232812Sjmallett
563232812Sjmallett/**
564210284Sjmallett * Call before any other calls to initialize the packet
565210284Sjmallett * output system.  This does chip global config, and should only be
566210284Sjmallett * done by one core.
567210284Sjmallett */
568210284Sjmallett
569210284Sjmallettvoid cvmx_pko_initialize_global(void)
570210284Sjmallett{
571232812Sjmallett    cvmx_pko_reg_cmd_buf_t config;
572210284Sjmallett    int i;
573210284Sjmallett
574232812Sjmallett    /*
575232812Sjmallett     * Set the size of the PKO command buffers to an odd number of 64bit
576232812Sjmallett     * words. This allows the normal two word send to stay aligned and never
577232812Sjmallett     * span a command word buffer.
578232812Sjmallett     */
579210284Sjmallett    config.u64 = 0;
580210284Sjmallett    config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL;
581210284Sjmallett    config.s.size = CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE / 8 - 1;
582210284Sjmallett    cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64);
583210284Sjmallett
584232812Sjmallett    /*
585232812Sjmallett     * chip-specific setup.
586232812Sjmallett     */
587232812Sjmallett    __cvmx_pko_chip_init();
588210284Sjmallett
589232812Sjmallett    /*
590232812Sjmallett     * If we aren't using all of the queues optimize PKO's internal memory.
591232812Sjmallett     */
592232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX) ||
593232812Sjmallett        OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX) ||
594232812Sjmallett	OCTEON_IS_MODEL(OCTEON_CN6XXX) || OCTEON_IS_MODEL(OCTEON_CNF7XXX))
595210284Sjmallett    {
596232812Sjmallett        int num_interfaces;
597232812Sjmallett        int last_port;
598232812Sjmallett        int max_queues;
599232812Sjmallett
600232812Sjmallett        if (octeon_has_feature(OCTEON_FEATURE_PKND))
601232812Sjmallett	    max_queues = __cvmx_helper_cfg_pko_max_queue();
602232812Sjmallett	else
603232812Sjmallett	{
604232812Sjmallett	    num_interfaces = cvmx_helper_get_number_of_interfaces();
605232812Sjmallett	    last_port = cvmx_helper_get_last_ipd_port(num_interfaces-1);
606232812Sjmallett            max_queues = cvmx_pko_get_base_queue(last_port) +
607232812Sjmallett	        cvmx_pko_get_num_queues(last_port);
608232812Sjmallett        }
609232812Sjmallett
610210284Sjmallett        if (OCTEON_IS_MODEL(OCTEON_CN38XX))
611210284Sjmallett        {
612210284Sjmallett            if (max_queues <= 32)
613210284Sjmallett                cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2);
614210284Sjmallett            else if (max_queues <= 64)
615210284Sjmallett                cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1);
616232812Sjmallett            else
617232812Sjmallett                cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 0);
618210284Sjmallett        }
619210284Sjmallett        else
620210284Sjmallett        {
621232812Sjmallett            if (OCTEON_IS_MODEL(OCTEON_CN68XX) && max_queues <= 32)
622232812Sjmallett                cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 3);
623232812Sjmallett            else if (max_queues <= 64)
624210284Sjmallett                cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2);
625210284Sjmallett            else if (max_queues <= 128)
626210284Sjmallett                cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1);
627232812Sjmallett            else
628232812Sjmallett                cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 0);
629232812Sjmallett            if (OCTEON_IS_MODEL(OCTEON_CN68XX))
630232812Sjmallett	    {
631232812Sjmallett                for (i = 0; i < 2; i++)
632232812Sjmallett                {
633232812Sjmallett                    cvmx_pko_reg_engine_storagex_t engine_storage;
634232812Sjmallett
635232812Sjmallett#define PKO_ASSIGN_ENGINE_STORAGE(index)                        \
636232812Sjmallett        engine_storage.s.engine##index =                        \
637232812Sjmallett            __cvmx_pko_memory_per_engine_o68(16 * i + (index))
638232812Sjmallett
639232812Sjmallett                    engine_storage.u64 = 0;
640232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(0);
641232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(1);
642232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(2);
643232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(3);
644232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(4);
645232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(5);
646232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(6);
647232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(7);
648232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(8);
649232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(9);
650232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(10);
651232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(11);
652232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(12);
653232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(13);
654232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(14);
655232812Sjmallett                    PKO_ASSIGN_ENGINE_STORAGE(15);
656232812Sjmallett                    cvmx_write_csr(CVMX_PKO_REG_ENGINE_STORAGEX(i),
657232812Sjmallett                                   engine_storage.u64);
658232812Sjmallett		}
659232812Sjmallett            }
660210284Sjmallett        }
661210284Sjmallett    }
662210284Sjmallett}
663210284Sjmallett
664210284Sjmallett/**
665210284Sjmallett * This function does per-core initialization required by the PKO routines.
666210284Sjmallett * This must be called on all cores that will do packet output, and must
667210284Sjmallett * be called after the FPA has been initialized and filled with pages.
668210284Sjmallett *
669210284Sjmallett * @return 0 on success
670210284Sjmallett *         !0 on failure
671210284Sjmallett */
672210284Sjmallettint cvmx_pko_initialize_local(void)
673210284Sjmallett{
674210284Sjmallett    /* Nothing to do */
675210284Sjmallett    return 0;
676210284Sjmallett}
677210284Sjmallett#endif
678210284Sjmallett
679210284Sjmallett/**
680210284Sjmallett * Enables the packet output hardware. It must already be
681210284Sjmallett * configured.
682210284Sjmallett */
683210284Sjmallettvoid cvmx_pko_enable(void)
684210284Sjmallett{
685210284Sjmallett    cvmx_pko_reg_flags_t flags;
686210284Sjmallett
687210284Sjmallett    flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS);
688210284Sjmallett    if (flags.s.ena_pko)
689210284Sjmallett        cvmx_dprintf("Warning: Enabling PKO when PKO already enabled.\n");
690210284Sjmallett
691232812Sjmallett    flags.s.ena_dwb = cvmx_helper_cfg_opt_get(CVMX_HELPER_CFG_OPT_USE_DWB);
692210284Sjmallett    flags.s.ena_pko = 1;
693232812Sjmallett    flags.s.store_be =1;  /*
694232812Sjmallett    			   * always enable big endian for 3-word command.
695232812Sjmallett			   * Does nothing for 2-word.
696232812Sjmallett    			   */
697210284Sjmallett    cvmx_write_csr(CVMX_PKO_REG_FLAGS, flags.u64);
698210284Sjmallett}
699210284Sjmallett
700210284Sjmallett/**
701210284Sjmallett * Disables the packet output. Does not affect any configuration.
702210284Sjmallett */
703210284Sjmallettvoid cvmx_pko_disable(void)
704210284Sjmallett{
705210284Sjmallett    cvmx_pko_reg_flags_t pko_reg_flags;
706210284Sjmallett    pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS);
707210284Sjmallett    pko_reg_flags.s.ena_pko = 0;
708210284Sjmallett    cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64);
709210284Sjmallett}
710210284Sjmallett
711210284Sjmallett#ifdef CVMX_ENABLE_PKO_FUNCTIONS
712210284Sjmallett/**
713210284Sjmallett * @INTERNAL
714210284Sjmallett * Reset the packet output.
715210284Sjmallett */
716210284Sjmallettstatic void __cvmx_pko_reset(void)
717210284Sjmallett{
718210284Sjmallett    cvmx_pko_reg_flags_t pko_reg_flags;
719210284Sjmallett    pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS);
720210284Sjmallett    pko_reg_flags.s.reset = 1;
721210284Sjmallett    cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64);
722210284Sjmallett}
723210284Sjmallett
724210284Sjmallett/**
725210284Sjmallett * Shutdown and free resources required by packet output.
726210284Sjmallett */
727210284Sjmallettvoid cvmx_pko_shutdown(void)
728210284Sjmallett{
729210284Sjmallett    int queue;
730210284Sjmallett
731210284Sjmallett    cvmx_pko_disable();
732210284Sjmallett
733232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
734210284Sjmallett    {
735232812Sjmallett	cvmx_pko_mem_iqueue_ptrs_t config;
736232812Sjmallett	config.u64 = 0;
737232812Sjmallett        for (queue = 0; queue < CVMX_PKO_MAX_OUTPUT_QUEUES; queue++)
738232812Sjmallett	{
739232812Sjmallett	    config.s.qid = queue;
740232812Sjmallett            cvmx_write_csr(CVMX_PKO_MEM_IQUEUE_PTRS, config.u64);
741232812Sjmallett            cvmx_cmd_queue_shutdown(CVMX_CMD_QUEUE_PKO(queue));
742232812Sjmallett	}
743232812Sjmallett    }
744232812Sjmallett    else
745232812Sjmallett    {
746232812Sjmallett        cvmx_pko_mem_queue_ptrs_t config;
747232812Sjmallett        for (queue=0; queue<CVMX_PKO_MAX_OUTPUT_QUEUES; queue++)
748210284Sjmallett        {
749232812Sjmallett            config.u64          = 0;
750232812Sjmallett            config.s.tail       = 1;
751232812Sjmallett            config.s.index      = 0;
752232812Sjmallett            config.s.port       = CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID;
753232812Sjmallett            config.s.queue      = queue & 0x7f;
754232812Sjmallett            config.s.qos_mask   = 0;
755232812Sjmallett            config.s.buf_ptr    = 0;
756232812Sjmallett            if (!OCTEON_IS_MODEL(OCTEON_CN3XXX))
757232812Sjmallett            {
758232812Sjmallett                cvmx_pko_reg_queue_ptrs1_t config1;
759232812Sjmallett                config1.u64 = 0;
760232812Sjmallett                config1.s.qid7 = queue >> 7;
761232812Sjmallett                cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64);
762232812Sjmallett            }
763232812Sjmallett            cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64);
764232812Sjmallett            cvmx_cmd_queue_shutdown(CVMX_CMD_QUEUE_PKO(queue));
765210284Sjmallett        }
766210284Sjmallett    }
767232812Sjmallett
768210284Sjmallett    __cvmx_pko_reset();
769210284Sjmallett}
770210284Sjmallett
771210284Sjmallett/**
772210284Sjmallett * Configure a output port and the associated queues for use.
773210284Sjmallett *
774210284Sjmallett * @param port       Port to configure.
775210284Sjmallett * @param base_queue First queue number to associate with this port.
776210284Sjmallett * @param num_queues Number of queues to associate with this port
777210284Sjmallett * @param priority   Array of priority levels for each queue. Values are
778210284Sjmallett *                   allowed to be 0-8. A value of 8 get 8 times the traffic
779210284Sjmallett *                   of a value of 1.  A value of 0 indicates that no rounds
780210284Sjmallett *                   will be participated in. These priorities can be changed
781210284Sjmallett *                   on the fly while the pko is enabled. A priority of 9
782210284Sjmallett *                   indicates that static priority should be used.  If static
783210284Sjmallett *                   priority is used all queues with static priority must be
784210284Sjmallett *                   contiguous starting at the base_queue, and lower numbered
785210284Sjmallett *                   queues have higher priority than higher numbered queues.
786210284Sjmallett *                   There must be num_queues elements in the array.
787210284Sjmallett */
788232812Sjmallettcvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue,
789232812Sjmallett    uint64_t num_queues, const uint64_t priority[])
790210284Sjmallett{
791210284Sjmallett    cvmx_pko_status_t          result_code;
792210284Sjmallett    uint64_t                   queue;
793215990Sjmallett    cvmx_pko_mem_queue_ptrs_t  config;
794210284Sjmallett    cvmx_pko_reg_queue_ptrs1_t config1;
795210284Sjmallett    int static_priority_base = -1;
796210284Sjmallett    int static_priority_end = -1;
797210284Sjmallett
798232812Sjmallett    if (OCTEON_IS_MODEL(OCTEON_CN68XX))
799232812Sjmallett        return CVMX_PKO_SUCCESS;
800210284Sjmallett
801232812Sjmallett    if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS) &&
802232812Sjmallett        (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID))
803210284Sjmallett    {
804232812Sjmallett        cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n",
805232812Sjmallett	    (unsigned long long)port);
806210284Sjmallett        return CVMX_PKO_INVALID_PORT;
807210284Sjmallett    }
808210284Sjmallett
809210284Sjmallett    if (base_queue + num_queues > CVMX_PKO_MAX_OUTPUT_QUEUES)
810210284Sjmallett    {
811232812Sjmallett        cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid queue range %llu\n",
812232812Sjmallett	    (unsigned long long)(base_queue + num_queues));
813210284Sjmallett        return CVMX_PKO_INVALID_QUEUE;
814210284Sjmallett    }
815210284Sjmallett
816210284Sjmallett    if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)
817210284Sjmallett    {
818232812Sjmallett        /*
819232812Sjmallett	 * Validate the static queue priority setup and set
820232812Sjmallett	 * static_priority_base and static_priority_end accordingly.
821232812Sjmallett	 */
822210284Sjmallett        for (queue = 0; queue < num_queues; queue++)
823210284Sjmallett        {
824210284Sjmallett            /* Find first queue of static priority */
825232812Sjmallett            if (static_priority_base == -1 && priority[queue] ==
826232812Sjmallett	        CVMX_PKO_QUEUE_STATIC_PRIORITY)
827210284Sjmallett                static_priority_base = queue;
828210284Sjmallett            /* Find last queue of static priority */
829232812Sjmallett            if (static_priority_base != -1 && static_priority_end == -1 &&
830232812Sjmallett	        priority[queue] != CVMX_PKO_QUEUE_STATIC_PRIORITY && queue)
831210284Sjmallett                static_priority_end = queue - 1;
832232812Sjmallett            else if (static_priority_base != -1 && static_priority_end == -1 &&
833232812Sjmallett	        queue == num_queues - 1)
834232812Sjmallett                static_priority_end = queue; /* all queues're static priority */
835232812Sjmallett
836232812Sjmallett            /*
837232812Sjmallett	     * Check to make sure all static priority queues are contiguous.
838232812Sjmallett	     * Also catches some cases of static priorites not starting at
839232812Sjmallett	     * queue 0.
840232812Sjmallett	     */
841232812Sjmallett            if (static_priority_end != -1 && (int)queue > static_priority_end &&
842232812Sjmallett	        priority[queue] == CVMX_PKO_QUEUE_STATIC_PRIORITY)
843210284Sjmallett            {
844232812Sjmallett                cvmx_dprintf("ERROR: cvmx_pko_config_port: Static priority "
845232812Sjmallett		    "queues aren't contiguous or don't start at base queue. "
846232812Sjmallett		    "q: %d, eq: %d\n", (int)queue, static_priority_end);
847210284Sjmallett                return CVMX_PKO_INVALID_PRIORITY;
848210284Sjmallett            }
849210284Sjmallett        }
850210284Sjmallett        if (static_priority_base > 0)
851210284Sjmallett        {
852232812Sjmallett            cvmx_dprintf("ERROR: cvmx_pko_config_port: Static priority queues "
853232812Sjmallett	        "don't start at base queue. sq: %d\n", static_priority_base);
854210284Sjmallett            return CVMX_PKO_INVALID_PRIORITY;
855210284Sjmallett        }
856210284Sjmallett    }
857210284Sjmallett
858232812Sjmallett    /*
859232812Sjmallett     * At this point, static_priority_base and static_priority_end are either
860232812Sjmallett     * both -1, or are valid start/end queue numbers
861232812Sjmallett     */
862232812Sjmallett
863210284Sjmallett    result_code = CVMX_PKO_SUCCESS;
864210284Sjmallett
865210284Sjmallett#ifdef PKO_DEBUG
866232812Sjmallett    cvmx_dprintf("num queues: %d (%lld,%lld)\n", (int)num_queues,
867232812Sjmallett        (unsigned long long)CVMX_PKO_QUEUES_PER_PORT_INTERFACE0,
868232812Sjmallett	(unsigned long long)CVMX_PKO_QUEUES_PER_PORT_INTERFACE1);
869210284Sjmallett#endif
870210284Sjmallett
871210284Sjmallett    for (queue = 0; queue < num_queues; queue++)
872210284Sjmallett    {
873210284Sjmallett        uint64_t  *buf_ptr = NULL;
874210284Sjmallett
875210284Sjmallett        config1.u64         = 0;
876210284Sjmallett        config1.s.idx3      = queue >> 3;
877210284Sjmallett        config1.s.qid7      = (base_queue + queue) >> 7;
878210284Sjmallett
879210284Sjmallett        config.u64          = 0;
880210284Sjmallett        config.s.tail       = queue == (num_queues - 1);
881210284Sjmallett        config.s.index      = queue;
882210284Sjmallett        config.s.port       = port;
883210284Sjmallett        config.s.queue      = base_queue + queue;
884210284Sjmallett
885215990Sjmallett        config.s.static_p   = static_priority_base >= 0;
886215990Sjmallett        config.s.static_q   = (int)queue <= static_priority_end;
887215990Sjmallett        config.s.s_tail     = (int)queue == static_priority_end;
888232812Sjmallett        /*
889232812Sjmallett	 * Convert the priority into an enable bit field. Try to space the bits
890232812Sjmallett	 * out evenly so the packet don't get grouped up
891232812Sjmallett	 */
892210284Sjmallett        switch ((int)priority[queue])
893210284Sjmallett        {
894210284Sjmallett            case 0: config.s.qos_mask = 0x00; break;
895210284Sjmallett            case 1: config.s.qos_mask = 0x01; break;
896210284Sjmallett            case 2: config.s.qos_mask = 0x11; break;
897210284Sjmallett            case 3: config.s.qos_mask = 0x49; break;
898210284Sjmallett            case 4: config.s.qos_mask = 0x55; break;
899210284Sjmallett            case 5: config.s.qos_mask = 0x57; break;
900210284Sjmallett            case 6: config.s.qos_mask = 0x77; break;
901210284Sjmallett            case 7: config.s.qos_mask = 0x7f; break;
902210284Sjmallett            case 8: config.s.qos_mask = 0xff; break;
903210284Sjmallett            case CVMX_PKO_QUEUE_STATIC_PRIORITY:
904215990Sjmallett                config.s.qos_mask = 0xff;
905215990Sjmallett                break;
906210284Sjmallett            default:
907232812Sjmallett                cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid priority %llu\n",
908232812Sjmallett		    (unsigned long long)priority[queue]);
909210284Sjmallett                config.s.qos_mask = 0xff;
910210284Sjmallett                result_code = CVMX_PKO_INVALID_PRIORITY;
911210284Sjmallett                break;
912210284Sjmallett        }
913210284Sjmallett
914210284Sjmallett        if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)
915210284Sjmallett        {
916232812Sjmallett            cvmx_cmd_queue_result_t cmd_res = cvmx_cmd_queue_initialize(
917232812Sjmallett	        CVMX_CMD_QUEUE_PKO(base_queue + queue),
918232812Sjmallett                CVMX_PKO_MAX_QUEUE_DEPTH,
919232812Sjmallett                CVMX_FPA_OUTPUT_BUFFER_POOL,
920232812Sjmallett                CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE -
921232812Sjmallett		    CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST*8);
922210284Sjmallett            if (cmd_res != CVMX_CMD_QUEUE_SUCCESS)
923210284Sjmallett            {
924215990Sjmallett	        switch (cmd_res)
925210284Sjmallett		{
926210284Sjmallett		    case CVMX_CMD_QUEUE_NO_MEMORY:
927232812Sjmallett                        cvmx_dprintf("ERROR: cvmx_pko_config_port: "
928232812Sjmallett			    "Unable to allocate output buffer.\n");
929210284Sjmallett                        return(CVMX_PKO_NO_MEMORY);
930210284Sjmallett		    case CVMX_CMD_QUEUE_ALREADY_SETUP:
931232812Sjmallett                        cvmx_dprintf("ERROR: cvmx_pko_config_port: "
932232812Sjmallett			    "Port already setup.\n");
933210284Sjmallett                        return(CVMX_PKO_PORT_ALREADY_SETUP);
934210284Sjmallett		    case CVMX_CMD_QUEUE_INVALID_PARAM:
935210284Sjmallett		    default:
936232812Sjmallett                        cvmx_dprintf("ERROR: cvmx_pko_config_port: "
937232812Sjmallett			    "Command queue initialization failed.\n");
938210284Sjmallett                        return(CVMX_PKO_CMD_QUEUE_INIT_ERROR);
939210284Sjmallett		}
940210284Sjmallett            }
941210284Sjmallett
942232812Sjmallett            buf_ptr = (uint64_t*)cvmx_cmd_queue_buffer(
943232812Sjmallett	        CVMX_CMD_QUEUE_PKO(base_queue + queue));
944210284Sjmallett            config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr);
945210284Sjmallett        }
946210284Sjmallett        else
947210284Sjmallett            config.s.buf_ptr = 0;
948210284Sjmallett
949210284Sjmallett        CVMX_SYNCWS;
950210284Sjmallett
951210284Sjmallett        if (!OCTEON_IS_MODEL(OCTEON_CN3XXX))
952210284Sjmallett        {
953210284Sjmallett            cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64);
954210284Sjmallett        }
955210284Sjmallett        cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64);
956210284Sjmallett    }
957210284Sjmallett
958210284Sjmallett    return result_code;
959210284Sjmallett}
960210284Sjmallett
961210284Sjmallett/**
962210284Sjmallett * Rate limit a PKO port to a max packets/sec. This function is only
963210284Sjmallett * supported on CN51XX and higher, excluding CN58XX.
964210284Sjmallett *
965210284Sjmallett * @param port      Port to rate limit
966210284Sjmallett * @param packets_s Maximum packet/sec
967210284Sjmallett * @param burst     Maximum number of packets to burst in a row before rate
968210284Sjmallett *                  limiting cuts in.
969210284Sjmallett *
970210284Sjmallett * @return Zero on success, negative on failure
971210284Sjmallett */
972210284Sjmallettint cvmx_pko_rate_limit_packets(int port, int packets_s, int burst)
973210284Sjmallett{
974210284Sjmallett    cvmx_pko_mem_port_rate0_t pko_mem_port_rate0;
975210284Sjmallett    cvmx_pko_mem_port_rate1_t pko_mem_port_rate1;
976210284Sjmallett
977210284Sjmallett    pko_mem_port_rate0.u64 = 0;
978210284Sjmallett    pko_mem_port_rate0.s.pid = port;
979232812Sjmallett    pko_mem_port_rate0.s.rate_pkt =
980232812Sjmallett        cvmx_clock_get_rate(CVMX_CLOCK_SCLK) / packets_s / 16;
981210284Sjmallett    /* No cost per word since we are limited by packets/sec, not bits/sec */
982210284Sjmallett    pko_mem_port_rate0.s.rate_word = 0;
983210284Sjmallett
984210284Sjmallett    pko_mem_port_rate1.u64 = 0;
985210284Sjmallett    pko_mem_port_rate1.s.pid = port;
986232812Sjmallett    pko_mem_port_rate1.s.rate_lim =
987232812Sjmallett        ((uint64_t)pko_mem_port_rate0.s.rate_pkt * burst) >> 8;
988210284Sjmallett
989210284Sjmallett    cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64);
990210284Sjmallett    cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64);
991210284Sjmallett    return 0;
992210284Sjmallett}
993210284Sjmallett
994210284Sjmallett/**
995210284Sjmallett * Rate limit a PKO port to a max bits/sec. This function is only
996210284Sjmallett * supported on CN51XX and higher, excluding CN58XX.
997210284Sjmallett *
998210284Sjmallett * @param port   Port to rate limit
999210284Sjmallett * @param bits_s PKO rate limit in bits/sec
1000210284Sjmallett * @param burst  Maximum number of bits to burst before rate
1001210284Sjmallett *               limiting cuts in.
1002210284Sjmallett *
1003210284Sjmallett * @return Zero on success, negative on failure
1004210284Sjmallett */
1005210284Sjmallettint cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst)
1006210284Sjmallett{
1007210284Sjmallett    cvmx_pko_mem_port_rate0_t pko_mem_port_rate0;
1008210284Sjmallett    cvmx_pko_mem_port_rate1_t pko_mem_port_rate1;
1009215990Sjmallett    uint64_t clock_rate = cvmx_clock_get_rate(CVMX_CLOCK_SCLK);
1010210284Sjmallett    uint64_t tokens_per_bit = clock_rate*16 / bits_s;
1011210284Sjmallett
1012210284Sjmallett    pko_mem_port_rate0.u64 = 0;
1013210284Sjmallett    pko_mem_port_rate0.s.pid = port;
1014210284Sjmallett    /* Each packet has a 12 bytes of interframe gap, an 8 byte preamble, and a
1015210284Sjmallett        4 byte CRC. These are not included in the per word count. Multiply
1016210284Sjmallett        by 8 to covert to bits and divide by 256 for limit granularity */
1017210284Sjmallett    pko_mem_port_rate0.s.rate_pkt = (12 + 8 + 4) * 8 * tokens_per_bit / 256;
1018210284Sjmallett    /* Each 8 byte word has 64bits */
1019210284Sjmallett    pko_mem_port_rate0.s.rate_word = 64 * tokens_per_bit;
1020210284Sjmallett
1021210284Sjmallett    pko_mem_port_rate1.u64 = 0;
1022210284Sjmallett    pko_mem_port_rate1.s.pid = port;
1023210284Sjmallett    pko_mem_port_rate1.s.rate_lim = tokens_per_bit * burst / 256;
1024210284Sjmallett
1025210284Sjmallett    cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64);
1026210284Sjmallett    cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64);
1027210284Sjmallett    return 0;
1028210284Sjmallett}
1029210284Sjmallett
1030210284Sjmallett#endif /* CVMX_ENABLE_PKO_FUNCTIONS */
1031