xref: /OK3568_Linux_fs/kernel/arch/mips/cavium-octeon/executive/cvmx-pko.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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