1*4882a593Smuzhiyun /***********************license start***************
2*4882a593Smuzhiyun * Author: Cavium Networks
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Contact: support@caviumnetworks.com
5*4882a593Smuzhiyun * This file is part of the OCTEON SDK
6*4882a593Smuzhiyun *
7*4882a593Smuzhiyun * Copyright (c) 2003-2008 Cavium Networks
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * This file is free software; you can redistribute it and/or modify
10*4882a593Smuzhiyun * it under the terms of the GNU General Public License, Version 2, as
11*4882a593Smuzhiyun * published by the Free Software Foundation.
12*4882a593Smuzhiyun *
13*4882a593Smuzhiyun * This file is distributed in the hope that it will be useful, but
14*4882a593Smuzhiyun * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15*4882a593Smuzhiyun * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16*4882a593Smuzhiyun * NONINFRINGEMENT. See the GNU General Public License for more
17*4882a593Smuzhiyun * details.
18*4882a593Smuzhiyun *
19*4882a593Smuzhiyun * You should have received a copy of the GNU General Public License
20*4882a593Smuzhiyun * along with this file; if not, write to the Free Software
21*4882a593Smuzhiyun * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22*4882a593Smuzhiyun * or visit http://www.gnu.org/licenses/.
23*4882a593Smuzhiyun *
24*4882a593Smuzhiyun * This file may also be available under a different license from Cavium.
25*4882a593Smuzhiyun * Contact Cavium Networks for more information
26*4882a593Smuzhiyun ***********************license end**************************************/
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun /*
29*4882a593Smuzhiyun * Support library for the hardware Packet Output unit.
30*4882a593Smuzhiyun */
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #include <asm/octeon/octeon.h>
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun #include <asm/octeon/cvmx-config.h>
35*4882a593Smuzhiyun #include <asm/octeon/cvmx-pko.h>
36*4882a593Smuzhiyun #include <asm/octeon/cvmx-helper.h>
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /**
39*4882a593Smuzhiyun * Internal state of packet output
40*4882a593Smuzhiyun */
41*4882a593Smuzhiyun
__cvmx_pko_int(int interface,int index)42*4882a593Smuzhiyun static int __cvmx_pko_int(int interface, int index)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun switch (interface) {
45*4882a593Smuzhiyun case 0:
46*4882a593Smuzhiyun return index;
47*4882a593Smuzhiyun case 1:
48*4882a593Smuzhiyun return 4;
49*4882a593Smuzhiyun case 2:
50*4882a593Smuzhiyun return index + 0x08;
51*4882a593Smuzhiyun case 3:
52*4882a593Smuzhiyun return index + 0x0c;
53*4882a593Smuzhiyun case 4:
54*4882a593Smuzhiyun return index + 0x10;
55*4882a593Smuzhiyun case 5:
56*4882a593Smuzhiyun return 0x1c;
57*4882a593Smuzhiyun case 6:
58*4882a593Smuzhiyun return 0x1d;
59*4882a593Smuzhiyun case 7:
60*4882a593Smuzhiyun return 0x1e;
61*4882a593Smuzhiyun case 8:
62*4882a593Smuzhiyun return 0x1f;
63*4882a593Smuzhiyun default:
64*4882a593Smuzhiyun return -1;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
__cvmx_pko_iport_config(int pko_port)68*4882a593Smuzhiyun static void __cvmx_pko_iport_config(int pko_port)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun int queue;
71*4882a593Smuzhiyun const int num_queues = 1;
72*4882a593Smuzhiyun const int base_queue = pko_port;
73*4882a593Smuzhiyun const int static_priority_end = 1;
74*4882a593Smuzhiyun const int static_priority_base = 1;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun for (queue = 0; queue < num_queues; queue++) {
77*4882a593Smuzhiyun union cvmx_pko_mem_iqueue_ptrs config;
78*4882a593Smuzhiyun cvmx_cmd_queue_result_t cmd_res;
79*4882a593Smuzhiyun uint64_t *buf_ptr;
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun config.u64 = 0;
82*4882a593Smuzhiyun config.s.index = queue;
83*4882a593Smuzhiyun config.s.qid = base_queue + queue;
84*4882a593Smuzhiyun config.s.ipid = pko_port;
85*4882a593Smuzhiyun config.s.tail = (queue == (num_queues - 1));
86*4882a593Smuzhiyun config.s.s_tail = (queue == static_priority_end);
87*4882a593Smuzhiyun config.s.static_p = (static_priority_base >= 0);
88*4882a593Smuzhiyun config.s.static_q = (queue <= static_priority_end);
89*4882a593Smuzhiyun config.s.qos_mask = 0xff;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun cmd_res = cvmx_cmd_queue_initialize(
92*4882a593Smuzhiyun CVMX_CMD_QUEUE_PKO(base_queue + queue),
93*4882a593Smuzhiyun CVMX_PKO_MAX_QUEUE_DEPTH,
94*4882a593Smuzhiyun CVMX_FPA_OUTPUT_BUFFER_POOL,
95*4882a593Smuzhiyun (CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE -
96*4882a593Smuzhiyun CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST * 8));
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun WARN(cmd_res,
99*4882a593Smuzhiyun "%s: cmd_res=%d pko_port=%d base_queue=%d num_queues=%d queue=%d\n",
100*4882a593Smuzhiyun __func__, (int)cmd_res, pko_port, base_queue,
101*4882a593Smuzhiyun num_queues, queue);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun buf_ptr = (uint64_t *)cvmx_cmd_queue_buffer(
104*4882a593Smuzhiyun CVMX_CMD_QUEUE_PKO(base_queue + queue));
105*4882a593Smuzhiyun config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr) >> 7;
106*4882a593Smuzhiyun CVMX_SYNCWS;
107*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_MEM_IQUEUE_PTRS, config.u64);
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
__cvmx_pko_queue_alloc_o68(void)111*4882a593Smuzhiyun static void __cvmx_pko_queue_alloc_o68(void)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun int port;
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun for (port = 0; port < 48; port++)
116*4882a593Smuzhiyun __cvmx_pko_iport_config(port);
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
__cvmx_pko_port_map_o68(void)119*4882a593Smuzhiyun static void __cvmx_pko_port_map_o68(void)
120*4882a593Smuzhiyun {
121*4882a593Smuzhiyun int port;
122*4882a593Smuzhiyun int interface, index;
123*4882a593Smuzhiyun cvmx_helper_interface_mode_t mode;
124*4882a593Smuzhiyun union cvmx_pko_mem_iport_ptrs config;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun /*
127*4882a593Smuzhiyun * Initialize every iport with the invalid eid.
128*4882a593Smuzhiyun */
129*4882a593Smuzhiyun config.u64 = 0;
130*4882a593Smuzhiyun config.s.eid = 31; /* Invalid */
131*4882a593Smuzhiyun for (port = 0; port < 128; port++) {
132*4882a593Smuzhiyun config.s.ipid = port;
133*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64);
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun /*
137*4882a593Smuzhiyun * Set up PKO_MEM_IPORT_PTRS
138*4882a593Smuzhiyun */
139*4882a593Smuzhiyun for (port = 0; port < 48; port++) {
140*4882a593Smuzhiyun interface = cvmx_helper_get_interface_num(port);
141*4882a593Smuzhiyun index = cvmx_helper_get_interface_index_num(port);
142*4882a593Smuzhiyun mode = cvmx_helper_interface_get_mode(interface);
143*4882a593Smuzhiyun if (mode == CVMX_HELPER_INTERFACE_MODE_DISABLED)
144*4882a593Smuzhiyun continue;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun config.s.ipid = port;
147*4882a593Smuzhiyun config.s.qos_mask = 0xff;
148*4882a593Smuzhiyun config.s.crc = 1;
149*4882a593Smuzhiyun config.s.min_pkt = 1;
150*4882a593Smuzhiyun config.s.intr = __cvmx_pko_int(interface, index);
151*4882a593Smuzhiyun config.s.eid = config.s.intr;
152*4882a593Smuzhiyun config.s.pipe = (mode == CVMX_HELPER_INTERFACE_MODE_LOOP) ?
153*4882a593Smuzhiyun index : port;
154*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64);
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun
__cvmx_pko_chip_init(void)158*4882a593Smuzhiyun static void __cvmx_pko_chip_init(void)
159*4882a593Smuzhiyun {
160*4882a593Smuzhiyun int i;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
163*4882a593Smuzhiyun __cvmx_pko_port_map_o68();
164*4882a593Smuzhiyun __cvmx_pko_queue_alloc_o68();
165*4882a593Smuzhiyun return;
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun /*
169*4882a593Smuzhiyun * Initialize queues
170*4882a593Smuzhiyun */
171*4882a593Smuzhiyun for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) {
172*4882a593Smuzhiyun const uint64_t priority = 8;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1,
175*4882a593Smuzhiyun &priority);
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun /**
180*4882a593Smuzhiyun * Call before any other calls to initialize the packet
181*4882a593Smuzhiyun * output system. This does chip global config, and should only be
182*4882a593Smuzhiyun * done by one core.
183*4882a593Smuzhiyun */
184*4882a593Smuzhiyun
cvmx_pko_initialize_global(void)185*4882a593Smuzhiyun void cvmx_pko_initialize_global(void)
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun union cvmx_pko_reg_cmd_buf config;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun /*
190*4882a593Smuzhiyun * Set the size of the PKO command buffers to an odd number of
191*4882a593Smuzhiyun * 64bit words. This allows the normal two word send to stay
192*4882a593Smuzhiyun * aligned and never span a command word buffer.
193*4882a593Smuzhiyun */
194*4882a593Smuzhiyun config.u64 = 0;
195*4882a593Smuzhiyun config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL;
196*4882a593Smuzhiyun config.s.size = CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE / 8 - 1;
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64);
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /*
201*4882a593Smuzhiyun * Chip-specific setup.
202*4882a593Smuzhiyun */
203*4882a593Smuzhiyun __cvmx_pko_chip_init();
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun /*
206*4882a593Smuzhiyun * If we aren't using all of the queues optimize PKO's
207*4882a593Smuzhiyun * internal memory.
208*4882a593Smuzhiyun */
209*4882a593Smuzhiyun if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)
210*4882a593Smuzhiyun || OCTEON_IS_MODEL(OCTEON_CN56XX)
211*4882a593Smuzhiyun || OCTEON_IS_MODEL(OCTEON_CN52XX)) {
212*4882a593Smuzhiyun int num_interfaces = cvmx_helper_get_number_of_interfaces();
213*4882a593Smuzhiyun int last_port =
214*4882a593Smuzhiyun cvmx_helper_get_last_ipd_port(num_interfaces - 1);
215*4882a593Smuzhiyun int max_queues =
216*4882a593Smuzhiyun cvmx_pko_get_base_queue(last_port) +
217*4882a593Smuzhiyun cvmx_pko_get_num_queues(last_port);
218*4882a593Smuzhiyun if (OCTEON_IS_MODEL(OCTEON_CN38XX)) {
219*4882a593Smuzhiyun if (max_queues <= 32)
220*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2);
221*4882a593Smuzhiyun else if (max_queues <= 64)
222*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1);
223*4882a593Smuzhiyun } else {
224*4882a593Smuzhiyun if (max_queues <= 64)
225*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2);
226*4882a593Smuzhiyun else if (max_queues <= 128)
227*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1);
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun /**
233*4882a593Smuzhiyun * This function does per-core initialization required by the PKO routines.
234*4882a593Smuzhiyun * This must be called on all cores that will do packet output, and must
235*4882a593Smuzhiyun * be called after the FPA has been initialized and filled with pages.
236*4882a593Smuzhiyun *
237*4882a593Smuzhiyun * Returns 0 on success
238*4882a593Smuzhiyun * !0 on failure
239*4882a593Smuzhiyun */
cvmx_pko_initialize_local(void)240*4882a593Smuzhiyun int cvmx_pko_initialize_local(void)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun /* Nothing to do */
243*4882a593Smuzhiyun return 0;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /**
247*4882a593Smuzhiyun * Enables the packet output hardware. It must already be
248*4882a593Smuzhiyun * configured.
249*4882a593Smuzhiyun */
cvmx_pko_enable(void)250*4882a593Smuzhiyun void cvmx_pko_enable(void)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun union cvmx_pko_reg_flags flags;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS);
255*4882a593Smuzhiyun if (flags.s.ena_pko)
256*4882a593Smuzhiyun cvmx_dprintf
257*4882a593Smuzhiyun ("Warning: Enabling PKO when PKO already enabled.\n");
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun flags.s.ena_dwb = 1;
260*4882a593Smuzhiyun flags.s.ena_pko = 1;
261*4882a593Smuzhiyun /*
262*4882a593Smuzhiyun * always enable big endian for 3-word command. Does nothing
263*4882a593Smuzhiyun * for 2-word.
264*4882a593Smuzhiyun */
265*4882a593Smuzhiyun flags.s.store_be = 1;
266*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_REG_FLAGS, flags.u64);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun /**
270*4882a593Smuzhiyun * Disables the packet output. Does not affect any configuration.
271*4882a593Smuzhiyun */
cvmx_pko_disable(void)272*4882a593Smuzhiyun void cvmx_pko_disable(void)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun union cvmx_pko_reg_flags pko_reg_flags;
275*4882a593Smuzhiyun pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS);
276*4882a593Smuzhiyun pko_reg_flags.s.ena_pko = 0;
277*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64);
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(cvmx_pko_disable);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun /**
282*4882a593Smuzhiyun * Reset the packet output.
283*4882a593Smuzhiyun */
__cvmx_pko_reset(void)284*4882a593Smuzhiyun static void __cvmx_pko_reset(void)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun union cvmx_pko_reg_flags pko_reg_flags;
287*4882a593Smuzhiyun pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS);
288*4882a593Smuzhiyun pko_reg_flags.s.reset = 1;
289*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64);
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun /**
293*4882a593Smuzhiyun * Shutdown and free resources required by packet output.
294*4882a593Smuzhiyun */
cvmx_pko_shutdown(void)295*4882a593Smuzhiyun void cvmx_pko_shutdown(void)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun union cvmx_pko_mem_queue_ptrs config;
298*4882a593Smuzhiyun int queue;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun cvmx_pko_disable();
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun for (queue = 0; queue < CVMX_PKO_MAX_OUTPUT_QUEUES; queue++) {
303*4882a593Smuzhiyun config.u64 = 0;
304*4882a593Smuzhiyun config.s.tail = 1;
305*4882a593Smuzhiyun config.s.index = 0;
306*4882a593Smuzhiyun config.s.port = CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID;
307*4882a593Smuzhiyun config.s.queue = queue & 0x7f;
308*4882a593Smuzhiyun config.s.qos_mask = 0;
309*4882a593Smuzhiyun config.s.buf_ptr = 0;
310*4882a593Smuzhiyun if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
311*4882a593Smuzhiyun union cvmx_pko_reg_queue_ptrs1 config1;
312*4882a593Smuzhiyun config1.u64 = 0;
313*4882a593Smuzhiyun config1.s.qid7 = queue >> 7;
314*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64);
317*4882a593Smuzhiyun cvmx_cmd_queue_shutdown(CVMX_CMD_QUEUE_PKO(queue));
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun __cvmx_pko_reset();
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(cvmx_pko_shutdown);
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun /**
324*4882a593Smuzhiyun * Configure a output port and the associated queues for use.
325*4882a593Smuzhiyun *
326*4882a593Smuzhiyun * @port: Port to configure.
327*4882a593Smuzhiyun * @base_queue: First queue number to associate with this port.
328*4882a593Smuzhiyun * @num_queues: Number of queues to associate with this port
329*4882a593Smuzhiyun * @priority: Array of priority levels for each queue. Values are
330*4882a593Smuzhiyun * allowed to be 0-8. A value of 8 get 8 times the traffic
331*4882a593Smuzhiyun * of a value of 1. A value of 0 indicates that no rounds
332*4882a593Smuzhiyun * will be participated in. These priorities can be changed
333*4882a593Smuzhiyun * on the fly while the pko is enabled. A priority of 9
334*4882a593Smuzhiyun * indicates that static priority should be used. If static
335*4882a593Smuzhiyun * priority is used all queues with static priority must be
336*4882a593Smuzhiyun * contiguous starting at the base_queue, and lower numbered
337*4882a593Smuzhiyun * queues have higher priority than higher numbered queues.
338*4882a593Smuzhiyun * There must be num_queues elements in the array.
339*4882a593Smuzhiyun */
cvmx_pko_config_port(uint64_t port,uint64_t base_queue,uint64_t num_queues,const uint64_t priority[])340*4882a593Smuzhiyun cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue,
341*4882a593Smuzhiyun uint64_t num_queues,
342*4882a593Smuzhiyun const uint64_t priority[])
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun cvmx_pko_status_t result_code;
345*4882a593Smuzhiyun uint64_t queue;
346*4882a593Smuzhiyun union cvmx_pko_mem_queue_ptrs config;
347*4882a593Smuzhiyun union cvmx_pko_reg_queue_ptrs1 config1;
348*4882a593Smuzhiyun int static_priority_base = -1;
349*4882a593Smuzhiyun int static_priority_end = -1;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun if (OCTEON_IS_MODEL(OCTEON_CN68XX))
352*4882a593Smuzhiyun return CVMX_PKO_SUCCESS;
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS)
355*4882a593Smuzhiyun && (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) {
356*4882a593Smuzhiyun cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n",
357*4882a593Smuzhiyun (unsigned long long)port);
358*4882a593Smuzhiyun return CVMX_PKO_INVALID_PORT;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun if (base_queue + num_queues > CVMX_PKO_MAX_OUTPUT_QUEUES) {
362*4882a593Smuzhiyun cvmx_dprintf
363*4882a593Smuzhiyun ("ERROR: cvmx_pko_config_port: Invalid queue range %llu\n",
364*4882a593Smuzhiyun (unsigned long long)(base_queue + num_queues));
365*4882a593Smuzhiyun return CVMX_PKO_INVALID_QUEUE;
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) {
369*4882a593Smuzhiyun /*
370*4882a593Smuzhiyun * Validate the static queue priority setup and set
371*4882a593Smuzhiyun * static_priority_base and static_priority_end
372*4882a593Smuzhiyun * accordingly.
373*4882a593Smuzhiyun */
374*4882a593Smuzhiyun for (queue = 0; queue < num_queues; queue++) {
375*4882a593Smuzhiyun /* Find first queue of static priority */
376*4882a593Smuzhiyun if (static_priority_base == -1
377*4882a593Smuzhiyun && priority[queue] ==
378*4882a593Smuzhiyun CVMX_PKO_QUEUE_STATIC_PRIORITY)
379*4882a593Smuzhiyun static_priority_base = queue;
380*4882a593Smuzhiyun /* Find last queue of static priority */
381*4882a593Smuzhiyun if (static_priority_base != -1
382*4882a593Smuzhiyun && static_priority_end == -1
383*4882a593Smuzhiyun && priority[queue] != CVMX_PKO_QUEUE_STATIC_PRIORITY
384*4882a593Smuzhiyun && queue)
385*4882a593Smuzhiyun static_priority_end = queue - 1;
386*4882a593Smuzhiyun else if (static_priority_base != -1
387*4882a593Smuzhiyun && static_priority_end == -1
388*4882a593Smuzhiyun && queue == num_queues - 1)
389*4882a593Smuzhiyun /* all queues are static priority */
390*4882a593Smuzhiyun static_priority_end = queue;
391*4882a593Smuzhiyun /*
392*4882a593Smuzhiyun * Check to make sure all static priority
393*4882a593Smuzhiyun * queues are contiguous. Also catches some
394*4882a593Smuzhiyun * cases of static priorites not starting at
395*4882a593Smuzhiyun * queue 0.
396*4882a593Smuzhiyun */
397*4882a593Smuzhiyun if (static_priority_end != -1
398*4882a593Smuzhiyun && (int)queue > static_priority_end
399*4882a593Smuzhiyun && priority[queue] ==
400*4882a593Smuzhiyun CVMX_PKO_QUEUE_STATIC_PRIORITY) {
401*4882a593Smuzhiyun cvmx_dprintf("ERROR: cvmx_pko_config_port: "
402*4882a593Smuzhiyun "Static priority queues aren't "
403*4882a593Smuzhiyun "contiguous or don't start at "
404*4882a593Smuzhiyun "base queue. q: %d, eq: %d\n",
405*4882a593Smuzhiyun (int)queue, static_priority_end);
406*4882a593Smuzhiyun return CVMX_PKO_INVALID_PRIORITY;
407*4882a593Smuzhiyun }
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun if (static_priority_base > 0) {
410*4882a593Smuzhiyun cvmx_dprintf("ERROR: cvmx_pko_config_port: Static "
411*4882a593Smuzhiyun "priority queues don't start at base "
412*4882a593Smuzhiyun "queue. sq: %d\n",
413*4882a593Smuzhiyun static_priority_base);
414*4882a593Smuzhiyun return CVMX_PKO_INVALID_PRIORITY;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun #if 0
417*4882a593Smuzhiyun cvmx_dprintf("Port %d: Static priority queue base: %d, "
418*4882a593Smuzhiyun "end: %d\n", port,
419*4882a593Smuzhiyun static_priority_base, static_priority_end);
420*4882a593Smuzhiyun #endif
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun /*
423*4882a593Smuzhiyun * At this point, static_priority_base and static_priority_end
424*4882a593Smuzhiyun * are either both -1, or are valid start/end queue
425*4882a593Smuzhiyun * numbers.
426*4882a593Smuzhiyun */
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun result_code = CVMX_PKO_SUCCESS;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun #ifdef PKO_DEBUG
431*4882a593Smuzhiyun cvmx_dprintf("num queues: %d (%lld,%lld)\n", num_queues,
432*4882a593Smuzhiyun CVMX_PKO_QUEUES_PER_PORT_INTERFACE0,
433*4882a593Smuzhiyun CVMX_PKO_QUEUES_PER_PORT_INTERFACE1);
434*4882a593Smuzhiyun #endif
435*4882a593Smuzhiyun
436*4882a593Smuzhiyun for (queue = 0; queue < num_queues; queue++) {
437*4882a593Smuzhiyun uint64_t *buf_ptr = NULL;
438*4882a593Smuzhiyun
439*4882a593Smuzhiyun config1.u64 = 0;
440*4882a593Smuzhiyun config1.s.idx3 = queue >> 3;
441*4882a593Smuzhiyun config1.s.qid7 = (base_queue + queue) >> 7;
442*4882a593Smuzhiyun
443*4882a593Smuzhiyun config.u64 = 0;
444*4882a593Smuzhiyun config.s.tail = queue == (num_queues - 1);
445*4882a593Smuzhiyun config.s.index = queue;
446*4882a593Smuzhiyun config.s.port = port;
447*4882a593Smuzhiyun config.s.queue = base_queue + queue;
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun if (!cvmx_octeon_is_pass1()) {
450*4882a593Smuzhiyun config.s.static_p = static_priority_base >= 0;
451*4882a593Smuzhiyun config.s.static_q = (int)queue <= static_priority_end;
452*4882a593Smuzhiyun config.s.s_tail = (int)queue == static_priority_end;
453*4882a593Smuzhiyun }
454*4882a593Smuzhiyun /*
455*4882a593Smuzhiyun * Convert the priority into an enable bit field. Try
456*4882a593Smuzhiyun * to space the bits out evenly so the packet don't
457*4882a593Smuzhiyun * get grouped up
458*4882a593Smuzhiyun */
459*4882a593Smuzhiyun switch ((int)priority[queue]) {
460*4882a593Smuzhiyun case 0:
461*4882a593Smuzhiyun config.s.qos_mask = 0x00;
462*4882a593Smuzhiyun break;
463*4882a593Smuzhiyun case 1:
464*4882a593Smuzhiyun config.s.qos_mask = 0x01;
465*4882a593Smuzhiyun break;
466*4882a593Smuzhiyun case 2:
467*4882a593Smuzhiyun config.s.qos_mask = 0x11;
468*4882a593Smuzhiyun break;
469*4882a593Smuzhiyun case 3:
470*4882a593Smuzhiyun config.s.qos_mask = 0x49;
471*4882a593Smuzhiyun break;
472*4882a593Smuzhiyun case 4:
473*4882a593Smuzhiyun config.s.qos_mask = 0x55;
474*4882a593Smuzhiyun break;
475*4882a593Smuzhiyun case 5:
476*4882a593Smuzhiyun config.s.qos_mask = 0x57;
477*4882a593Smuzhiyun break;
478*4882a593Smuzhiyun case 6:
479*4882a593Smuzhiyun config.s.qos_mask = 0x77;
480*4882a593Smuzhiyun break;
481*4882a593Smuzhiyun case 7:
482*4882a593Smuzhiyun config.s.qos_mask = 0x7f;
483*4882a593Smuzhiyun break;
484*4882a593Smuzhiyun case 8:
485*4882a593Smuzhiyun config.s.qos_mask = 0xff;
486*4882a593Smuzhiyun break;
487*4882a593Smuzhiyun case CVMX_PKO_QUEUE_STATIC_PRIORITY:
488*4882a593Smuzhiyun if (!cvmx_octeon_is_pass1()) {
489*4882a593Smuzhiyun config.s.qos_mask = 0xff;
490*4882a593Smuzhiyun break;
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun fallthrough; /* to the error case, when Pass 1 */
493*4882a593Smuzhiyun default:
494*4882a593Smuzhiyun cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid "
495*4882a593Smuzhiyun "priority %llu\n",
496*4882a593Smuzhiyun (unsigned long long)priority[queue]);
497*4882a593Smuzhiyun config.s.qos_mask = 0xff;
498*4882a593Smuzhiyun result_code = CVMX_PKO_INVALID_PRIORITY;
499*4882a593Smuzhiyun break;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) {
503*4882a593Smuzhiyun cvmx_cmd_queue_result_t cmd_res =
504*4882a593Smuzhiyun cvmx_cmd_queue_initialize(CVMX_CMD_QUEUE_PKO
505*4882a593Smuzhiyun (base_queue + queue),
506*4882a593Smuzhiyun CVMX_PKO_MAX_QUEUE_DEPTH,
507*4882a593Smuzhiyun CVMX_FPA_OUTPUT_BUFFER_POOL,
508*4882a593Smuzhiyun CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE
509*4882a593Smuzhiyun -
510*4882a593Smuzhiyun CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST
511*4882a593Smuzhiyun * 8);
512*4882a593Smuzhiyun if (cmd_res != CVMX_CMD_QUEUE_SUCCESS) {
513*4882a593Smuzhiyun switch (cmd_res) {
514*4882a593Smuzhiyun case CVMX_CMD_QUEUE_NO_MEMORY:
515*4882a593Smuzhiyun cvmx_dprintf("ERROR: "
516*4882a593Smuzhiyun "cvmx_pko_config_port: "
517*4882a593Smuzhiyun "Unable to allocate "
518*4882a593Smuzhiyun "output buffer.\n");
519*4882a593Smuzhiyun return CVMX_PKO_NO_MEMORY;
520*4882a593Smuzhiyun case CVMX_CMD_QUEUE_ALREADY_SETUP:
521*4882a593Smuzhiyun cvmx_dprintf
522*4882a593Smuzhiyun ("ERROR: cvmx_pko_config_port: Port already setup.\n");
523*4882a593Smuzhiyun return CVMX_PKO_PORT_ALREADY_SETUP;
524*4882a593Smuzhiyun case CVMX_CMD_QUEUE_INVALID_PARAM:
525*4882a593Smuzhiyun default:
526*4882a593Smuzhiyun cvmx_dprintf
527*4882a593Smuzhiyun ("ERROR: cvmx_pko_config_port: Command queue initialization failed.\n");
528*4882a593Smuzhiyun return CVMX_PKO_CMD_QUEUE_INIT_ERROR;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun buf_ptr =
533*4882a593Smuzhiyun (uint64_t *)
534*4882a593Smuzhiyun cvmx_cmd_queue_buffer(CVMX_CMD_QUEUE_PKO
535*4882a593Smuzhiyun (base_queue + queue));
536*4882a593Smuzhiyun config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr);
537*4882a593Smuzhiyun } else
538*4882a593Smuzhiyun config.s.buf_ptr = 0;
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun CVMX_SYNCWS;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun if (!OCTEON_IS_MODEL(OCTEON_CN3XXX))
543*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64);
544*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64);
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun return result_code;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun #ifdef PKO_DEBUG
551*4882a593Smuzhiyun /**
552*4882a593Smuzhiyun * Show map of ports -> queues for different cores.
553*4882a593Smuzhiyun */
cvmx_pko_show_queue_map()554*4882a593Smuzhiyun void cvmx_pko_show_queue_map()
555*4882a593Smuzhiyun {
556*4882a593Smuzhiyun int core, port;
557*4882a593Smuzhiyun int pko_output_ports = 36;
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun cvmx_dprintf("port");
560*4882a593Smuzhiyun for (port = 0; port < pko_output_ports; port++)
561*4882a593Smuzhiyun cvmx_dprintf("%3d ", port);
562*4882a593Smuzhiyun cvmx_dprintf("\n");
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun for (core = 0; core < CVMX_MAX_CORES; core++) {
565*4882a593Smuzhiyun cvmx_dprintf("\n%2d: ", core);
566*4882a593Smuzhiyun for (port = 0; port < pko_output_ports; port++) {
567*4882a593Smuzhiyun cvmx_dprintf("%3d ",
568*4882a593Smuzhiyun cvmx_pko_get_base_queue_per_core(port,
569*4882a593Smuzhiyun core));
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun cvmx_dprintf("\n");
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun #endif
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun /**
577*4882a593Smuzhiyun * Rate limit a PKO port to a max packets/sec. This function is only
578*4882a593Smuzhiyun * supported on CN51XX and higher, excluding CN58XX.
579*4882a593Smuzhiyun *
580*4882a593Smuzhiyun * @port: Port to rate limit
581*4882a593Smuzhiyun * @packets_s: Maximum packet/sec
582*4882a593Smuzhiyun * @burst: Maximum number of packets to burst in a row before rate
583*4882a593Smuzhiyun * limiting cuts in.
584*4882a593Smuzhiyun *
585*4882a593Smuzhiyun * Returns Zero on success, negative on failure
586*4882a593Smuzhiyun */
cvmx_pko_rate_limit_packets(int port,int packets_s,int burst)587*4882a593Smuzhiyun int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun union cvmx_pko_mem_port_rate0 pko_mem_port_rate0;
590*4882a593Smuzhiyun union cvmx_pko_mem_port_rate1 pko_mem_port_rate1;
591*4882a593Smuzhiyun
592*4882a593Smuzhiyun pko_mem_port_rate0.u64 = 0;
593*4882a593Smuzhiyun pko_mem_port_rate0.s.pid = port;
594*4882a593Smuzhiyun pko_mem_port_rate0.s.rate_pkt =
595*4882a593Smuzhiyun cvmx_sysinfo_get()->cpu_clock_hz / packets_s / 16;
596*4882a593Smuzhiyun /* No cost per word since we are limited by packets/sec, not bits/sec */
597*4882a593Smuzhiyun pko_mem_port_rate0.s.rate_word = 0;
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun pko_mem_port_rate1.u64 = 0;
600*4882a593Smuzhiyun pko_mem_port_rate1.s.pid = port;
601*4882a593Smuzhiyun pko_mem_port_rate1.s.rate_lim =
602*4882a593Smuzhiyun ((uint64_t) pko_mem_port_rate0.s.rate_pkt * burst) >> 8;
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64);
605*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64);
606*4882a593Smuzhiyun return 0;
607*4882a593Smuzhiyun }
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun /**
610*4882a593Smuzhiyun * Rate limit a PKO port to a max bits/sec. This function is only
611*4882a593Smuzhiyun * supported on CN51XX and higher, excluding CN58XX.
612*4882a593Smuzhiyun *
613*4882a593Smuzhiyun * @port: Port to rate limit
614*4882a593Smuzhiyun * @bits_s: PKO rate limit in bits/sec
615*4882a593Smuzhiyun * @burst: Maximum number of bits to burst before rate
616*4882a593Smuzhiyun * limiting cuts in.
617*4882a593Smuzhiyun *
618*4882a593Smuzhiyun * Returns Zero on success, negative on failure
619*4882a593Smuzhiyun */
cvmx_pko_rate_limit_bits(int port,uint64_t bits_s,int burst)620*4882a593Smuzhiyun int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst)
621*4882a593Smuzhiyun {
622*4882a593Smuzhiyun union cvmx_pko_mem_port_rate0 pko_mem_port_rate0;
623*4882a593Smuzhiyun union cvmx_pko_mem_port_rate1 pko_mem_port_rate1;
624*4882a593Smuzhiyun uint64_t clock_rate = cvmx_sysinfo_get()->cpu_clock_hz;
625*4882a593Smuzhiyun uint64_t tokens_per_bit = clock_rate * 16 / bits_s;
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun pko_mem_port_rate0.u64 = 0;
628*4882a593Smuzhiyun pko_mem_port_rate0.s.pid = port;
629*4882a593Smuzhiyun /*
630*4882a593Smuzhiyun * Each packet has a 12 bytes of interframe gap, an 8 byte
631*4882a593Smuzhiyun * preamble, and a 4 byte CRC. These are not included in the
632*4882a593Smuzhiyun * per word count. Multiply by 8 to covert to bits and divide
633*4882a593Smuzhiyun * by 256 for limit granularity.
634*4882a593Smuzhiyun */
635*4882a593Smuzhiyun pko_mem_port_rate0.s.rate_pkt = (12 + 8 + 4) * 8 * tokens_per_bit / 256;
636*4882a593Smuzhiyun /* Each 8 byte word has 64bits */
637*4882a593Smuzhiyun pko_mem_port_rate0.s.rate_word = 64 * tokens_per_bit;
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun pko_mem_port_rate1.u64 = 0;
640*4882a593Smuzhiyun pko_mem_port_rate1.s.pid = port;
641*4882a593Smuzhiyun pko_mem_port_rate1.s.rate_lim = tokens_per_bit * burst / 256;
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64);
644*4882a593Smuzhiyun cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64);
645*4882a593Smuzhiyun return 0;
646*4882a593Smuzhiyun }
647