1 /***********************license start***************
2  * Author: Cavium Networks
3  *
4  * Contact: support@caviumnetworks.com
5  * This file is part of the OCTEON SDK
6  *
7  * Copyright (c) 2003-2008 Cavium Networks
8  *
9  * This file is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License, Version 2, as
11  * published by the Free Software Foundation.
12  *
13  * This file is distributed in the hope that it will be useful, but
14  * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16  * NONINFRINGEMENT.  See the GNU General Public License for more
17  * details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this file; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22  * or visit http://www.gnu.org/licenses/.
23  *
24  * This file may also be available under a different license from Cavium.
25  * Contact Cavium Networks for more information
26  ***********************license end**************************************/
27 
28 /*
29  *
30  * Helper functions for common, but complicated tasks.
31  *
32  */
33 #include <asm/octeon/octeon.h>
34 
35 #include "cvmx-config.h"
36 
37 #include "cvmx-fpa.h"
38 #include "cvmx-pip.h"
39 #include "cvmx-pko.h"
40 #include "cvmx-ipd.h"
41 #include "cvmx-spi.h"
42 #include "cvmx-helper.h"
43 #include "cvmx-helper-board.h"
44 
45 #include "cvmx-pip-defs.h"
46 #include "cvmx-smix-defs.h"
47 #include "cvmx-asxx-defs.h"
48 
49 /**
50  * cvmx_override_pko_queue_priority(int ipd_port, uint64_t
51  * priorities[16]) is a function pointer. It is meant to allow
52  * customization of the PKO queue priorities based on the port
53  * number. Users should set this pointer to a function before
54  * calling any cvmx-helper operations.
55  */
56 void (*cvmx_override_pko_queue_priority) (int pko_port,
57 					  uint64_t priorities[16]);
58 
59 /**
60  * cvmx_override_ipd_port_setup(int ipd_port) is a function
61  * pointer. It is meant to allow customization of the IPD port
62  * setup before packet input/output comes online. It is called
63  * after cvmx-helper does the default IPD configuration, but
64  * before IPD is enabled. Users should set this pointer to a
65  * function before calling any cvmx-helper operations.
66  */
67 void (*cvmx_override_ipd_port_setup) (int ipd_port);
68 
69 /* Port count per interface */
70 static int interface_port_count[4] = { 0, 0, 0, 0 };
71 
72 /* Port last configured link info index by IPD/PKO port */
73 static cvmx_helper_link_info_t
74     port_link_info[CVMX_PIP_NUM_INPUT_PORTS];
75 
76 /**
77  * Return the number of interfaces the chip has. Each interface
78  * may have multiple ports. Most chips support two interfaces,
79  * but the CNX0XX and CNX1XX are exceptions. These only support
80  * one interface.
81  *
82  * Returns Number of interfaces on chip
83  */
cvmx_helper_get_number_of_interfaces(void)84 int cvmx_helper_get_number_of_interfaces(void)
85 {
86 	if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
87 		return 4;
88 	else
89 		return 3;
90 }
91 
92 /**
93  * Return the number of ports on an interface. Depending on the
94  * chip and configuration, this can be 1-16. A value of 0
95  * specifies that the interface doesn't exist or isn't usable.
96  *
97  * @interface: Interface to get the port count for
98  *
99  * Returns Number of ports on interface. Can be Zero.
100  */
cvmx_helper_ports_on_interface(int interface)101 int cvmx_helper_ports_on_interface(int interface)
102 {
103 	return interface_port_count[interface];
104 }
105 
106 /**
107  * Get the operating mode of an interface. Depending on the Octeon
108  * chip and configuration, this function returns an enumeration
109  * of the type of packet I/O supported by an interface.
110  *
111  * @interface: Interface to probe
112  *
113  * Returns Mode of the interface. Unknown or unsupported interfaces return
114  *         DISABLED.
115  */
cvmx_helper_interface_get_mode(int interface)116 cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface)
117 {
118 	union cvmx_gmxx_inf_mode mode;
119 	if (interface == 2)
120 		return CVMX_HELPER_INTERFACE_MODE_NPI;
121 
122 	if (interface == 3) {
123 		if (OCTEON_IS_MODEL(OCTEON_CN56XX)
124 		    || OCTEON_IS_MODEL(OCTEON_CN52XX))
125 			return CVMX_HELPER_INTERFACE_MODE_LOOP;
126 		else
127 			return CVMX_HELPER_INTERFACE_MODE_DISABLED;
128 	}
129 
130 	if (interface == 0
131 	    && cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5
132 	    && cvmx_sysinfo_get()->board_rev_major == 1) {
133 		/*
134 		 * Lie about interface type of CN3005 board.  This
135 		 * board has a switch on port 1 like the other
136 		 * evaluation boards, but it is connected over RGMII
137 		 * instead of GMII.  Report GMII mode so that the
138 		 * speed is forced to 1 Gbit full duplex.  Other than
139 		 * some initial configuration (which does not use the
140 		 * output of this function) there is no difference in
141 		 * setup between GMII and RGMII modes.
142 		 */
143 		return CVMX_HELPER_INTERFACE_MODE_GMII;
144 	}
145 
146 	/* Interface 1 is always disabled on CN31XX and CN30XX */
147 	if ((interface == 1)
148 	    && (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX)
149 		|| OCTEON_IS_MODEL(OCTEON_CN50XX)
150 		|| OCTEON_IS_MODEL(OCTEON_CN52XX)))
151 		return CVMX_HELPER_INTERFACE_MODE_DISABLED;
152 
153 	mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
154 
155 	if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) {
156 		switch (mode.cn56xx.mode) {
157 		case 0:
158 			return CVMX_HELPER_INTERFACE_MODE_DISABLED;
159 		case 1:
160 			return CVMX_HELPER_INTERFACE_MODE_XAUI;
161 		case 2:
162 			return CVMX_HELPER_INTERFACE_MODE_SGMII;
163 		case 3:
164 			return CVMX_HELPER_INTERFACE_MODE_PICMG;
165 		default:
166 			return CVMX_HELPER_INTERFACE_MODE_DISABLED;
167 		}
168 	} else {
169 		if (!mode.s.en)
170 			return CVMX_HELPER_INTERFACE_MODE_DISABLED;
171 
172 		if (mode.s.type) {
173 			if (OCTEON_IS_MODEL(OCTEON_CN38XX)
174 			    || OCTEON_IS_MODEL(OCTEON_CN58XX))
175 				return CVMX_HELPER_INTERFACE_MODE_SPI;
176 			else
177 				return CVMX_HELPER_INTERFACE_MODE_GMII;
178 		} else
179 			return CVMX_HELPER_INTERFACE_MODE_RGMII;
180 	}
181 }
182 
183 /**
184  * Configure the IPD/PIP tagging and QoS options for a specific
185  * port. This function determines the POW work queue entry
186  * contents for a port. The setup performed here is controlled by
187  * the defines in executive-config.h.
188  *
189  * @ipd_port: Port to configure. This follows the IPD numbering, not the
190  *                 per interface numbering
191  *
192  * Returns Zero on success, negative on failure
193  */
__cvmx_helper_port_setup_ipd(int ipd_port)194 static int __cvmx_helper_port_setup_ipd(int ipd_port)
195 {
196 	union cvmx_pip_prt_cfgx port_config;
197 	union cvmx_pip_prt_tagx tag_config;
198 
199 	port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port));
200 	tag_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(ipd_port));
201 
202 	/* Have each port go to a different POW queue */
203 	port_config.s.qos = ipd_port & 0x7;
204 
205 	/* Process the headers and place the IP header in the work queue */
206 	port_config.s.mode = CVMX_HELPER_INPUT_PORT_SKIP_MODE;
207 
208 	tag_config.s.ip6_src_flag = CVMX_HELPER_INPUT_TAG_IPV6_SRC_IP;
209 	tag_config.s.ip6_dst_flag = CVMX_HELPER_INPUT_TAG_IPV6_DST_IP;
210 	tag_config.s.ip6_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_SRC_PORT;
211 	tag_config.s.ip6_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_DST_PORT;
212 	tag_config.s.ip6_nxth_flag = CVMX_HELPER_INPUT_TAG_IPV6_NEXT_HEADER;
213 	tag_config.s.ip4_src_flag = CVMX_HELPER_INPUT_TAG_IPV4_SRC_IP;
214 	tag_config.s.ip4_dst_flag = CVMX_HELPER_INPUT_TAG_IPV4_DST_IP;
215 	tag_config.s.ip4_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_SRC_PORT;
216 	tag_config.s.ip4_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_DST_PORT;
217 	tag_config.s.ip4_pctl_flag = CVMX_HELPER_INPUT_TAG_IPV4_PROTOCOL;
218 	tag_config.s.inc_prt_flag = CVMX_HELPER_INPUT_TAG_INPUT_PORT;
219 	tag_config.s.tcp6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
220 	tag_config.s.tcp4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
221 	tag_config.s.ip6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
222 	tag_config.s.ip4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
223 	tag_config.s.non_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
224 	/* Put all packets in group 0. Other groups can be used by the app */
225 	tag_config.s.grp = 0;
226 
227 	cvmx_pip_config_port(ipd_port, port_config, tag_config);
228 
229 	/* Give the user a chance to override our setting for each port */
230 	if (cvmx_override_ipd_port_setup)
231 		cvmx_override_ipd_port_setup(ipd_port);
232 
233 	return 0;
234 }
235 
236 /**
237  * This function probes an interface to determine the actual
238  * number of hardware ports connected to it. It doesn't setup the
239  * ports or enable them. The main goal here is to set the global
240  * interface_port_count[interface] correctly. Hardware setup of the
241  * ports will be performed later.
242  *
243  * @interface: Interface to probe
244  *
245  * Returns Zero on success, negative on failure
246  */
cvmx_helper_interface_probe(int interface)247 int cvmx_helper_interface_probe(int interface)
248 {
249 	/* At this stage in the game we don't want packets to be moving yet.
250 	   The following probe calls should perform hardware setup
251 	   needed to determine port counts. Receive must still be disabled */
252 	switch (cvmx_helper_interface_get_mode(interface)) {
253 		/* These types don't support ports to IPD/PKO */
254 	case CVMX_HELPER_INTERFACE_MODE_DISABLED:
255 	case CVMX_HELPER_INTERFACE_MODE_PCIE:
256 		interface_port_count[interface] = 0;
257 		break;
258 		/* XAUI is a single high speed port */
259 	case CVMX_HELPER_INTERFACE_MODE_XAUI:
260 		interface_port_count[interface] =
261 		    __cvmx_helper_xaui_probe(interface);
262 		break;
263 		/*
264 		 * RGMII/GMII/MII are all treated about the same. Most
265 		 * functions refer to these ports as RGMII.
266 		 */
267 	case CVMX_HELPER_INTERFACE_MODE_RGMII:
268 	case CVMX_HELPER_INTERFACE_MODE_GMII:
269 		interface_port_count[interface] =
270 		    __cvmx_helper_rgmii_probe(interface);
271 		break;
272 		/*
273 		 * SPI4 can have 1-16 ports depending on the device at
274 		 * the other end.
275 		 */
276 	case CVMX_HELPER_INTERFACE_MODE_SPI:
277 		interface_port_count[interface] =
278 		    __cvmx_helper_spi_probe(interface);
279 		break;
280 		/*
281 		 * SGMII can have 1-4 ports depending on how many are
282 		 * hooked up.
283 		 */
284 	case CVMX_HELPER_INTERFACE_MODE_SGMII:
285 	case CVMX_HELPER_INTERFACE_MODE_PICMG:
286 		interface_port_count[interface] =
287 		    __cvmx_helper_sgmii_probe(interface);
288 		break;
289 		/* PCI target Network Packet Interface */
290 	case CVMX_HELPER_INTERFACE_MODE_NPI:
291 		interface_port_count[interface] =
292 		    __cvmx_helper_npi_probe(interface);
293 		break;
294 		/*
295 		 * Special loopback only ports. These are not the same
296 		 * as other ports in loopback mode.
297 		 */
298 	case CVMX_HELPER_INTERFACE_MODE_LOOP:
299 		interface_port_count[interface] =
300 		    __cvmx_helper_loop_probe(interface);
301 		break;
302 	}
303 
304 	interface_port_count[interface] =
305 	    __cvmx_helper_board_interface_probe(interface,
306 						interface_port_count
307 						[interface]);
308 
309 	/* Make sure all global variables propagate to other cores */
310 	CVMX_SYNCWS;
311 
312 	return 0;
313 }
314 
315 /**
316  * Setup the IPD/PIP for the ports on an interface. Packet
317  * classification and tagging are set for every port on the
318  * interface. The number of ports on the interface must already
319  * have been probed.
320  *
321  * @interface: Interface to setup IPD/PIP for
322  *
323  * Returns Zero on success, negative on failure
324  */
__cvmx_helper_interface_setup_ipd(int interface)325 static int __cvmx_helper_interface_setup_ipd(int interface)
326 {
327 	int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
328 	int num_ports = interface_port_count[interface];
329 
330 	while (num_ports--) {
331 		__cvmx_helper_port_setup_ipd(ipd_port);
332 		ipd_port++;
333 	}
334 	return 0;
335 }
336 
337 /**
338  * Setup global setting for IPD/PIP not related to a specific
339  * interface or port. This must be called before IPD is enabled.
340  *
341  * Returns Zero on success, negative on failure.
342  */
__cvmx_helper_global_setup_ipd(void)343 static int __cvmx_helper_global_setup_ipd(void)
344 {
345 	/* Setup the global packet input options */
346 	cvmx_ipd_config(CVMX_FPA_PACKET_POOL_SIZE / 8,
347 			CVMX_HELPER_FIRST_MBUFF_SKIP / 8,
348 			CVMX_HELPER_NOT_FIRST_MBUFF_SKIP / 8,
349 			/* The +8 is to account for the next ptr */
350 			(CVMX_HELPER_FIRST_MBUFF_SKIP + 8) / 128,
351 			/* The +8 is to account for the next ptr */
352 			(CVMX_HELPER_NOT_FIRST_MBUFF_SKIP + 8) / 128,
353 			CVMX_FPA_WQE_POOL,
354 			CVMX_IPD_OPC_MODE_STT,
355 			CVMX_HELPER_ENABLE_BACK_PRESSURE);
356 	return 0;
357 }
358 
359 /**
360  * Setup the PKO for the ports on an interface. The number of
361  * queues per port and the priority of each PKO output queue
362  * is set here. PKO must be disabled when this function is called.
363  *
364  * @interface: Interface to setup PKO for
365  *
366  * Returns Zero on success, negative on failure
367  */
__cvmx_helper_interface_setup_pko(int interface)368 static int __cvmx_helper_interface_setup_pko(int interface)
369 {
370 	/*
371 	 * Each packet output queue has an associated priority. The
372 	 * higher the priority, the more often it can send a packet. A
373 	 * priority of 8 means it can send in all 8 rounds of
374 	 * contention. We're going to make each queue one less than
375 	 * the last.  The vector of priorities has been extended to
376 	 * support CN5xxx CPUs, where up to 16 queues can be
377 	 * associated to a port.  To keep backward compatibility we
378 	 * don't change the initial 8 priorities and replicate them in
379 	 * the second half.  With per-core PKO queues (PKO lockless
380 	 * operation) all queues have the same priority.
381 	 */
382 	uint64_t priorities[16] =
383 	    { 8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1 };
384 
385 	/*
386 	 * Setup the IPD/PIP and PKO for the ports discovered
387 	 * above. Here packet classification, tagging and output
388 	 * priorities are set.
389 	 */
390 	int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
391 	int num_ports = interface_port_count[interface];
392 	while (num_ports--) {
393 		/*
394 		 * Give the user a chance to override the per queue
395 		 * priorities.
396 		 */
397 		if (cvmx_override_pko_queue_priority)
398 			cvmx_override_pko_queue_priority(ipd_port, priorities);
399 
400 		cvmx_pko_config_port(ipd_port,
401 				     cvmx_pko_get_base_queue_per_core(ipd_port,
402 								      0),
403 				     cvmx_pko_get_num_queues(ipd_port),
404 				     priorities);
405 		ipd_port++;
406 	}
407 	return 0;
408 }
409 
410 /**
411  * Setup global setting for PKO not related to a specific
412  * interface or port. This must be called before PKO is enabled.
413  *
414  * Returns Zero on success, negative on failure.
415  */
__cvmx_helper_global_setup_pko(void)416 static int __cvmx_helper_global_setup_pko(void)
417 {
418 	/*
419 	 * Disable tagwait FAU timeout. This needs to be done before
420 	 * anyone might start packet output using tags.
421 	 */
422 	union cvmx_iob_fau_timeout fau_to;
423 	fau_to.u64 = 0;
424 	fau_to.s.tout_val = 0xfff;
425 	fau_to.s.tout_enb = 0;
426 	cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64);
427 	return 0;
428 }
429 
430 /**
431  * Setup global backpressure setting.
432  *
433  * Returns Zero on success, negative on failure
434  */
__cvmx_helper_global_setup_backpressure(void)435 static int __cvmx_helper_global_setup_backpressure(void)
436 {
437 #if CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE
438 	/* Disable backpressure if configured to do so */
439 	/* Disable backpressure (pause frame) generation */
440 	int num_interfaces = cvmx_helper_get_number_of_interfaces();
441 	int interface;
442 	for (interface = 0; interface < num_interfaces; interface++) {
443 		switch (cvmx_helper_interface_get_mode(interface)) {
444 		case CVMX_HELPER_INTERFACE_MODE_DISABLED:
445 		case CVMX_HELPER_INTERFACE_MODE_PCIE:
446 		case CVMX_HELPER_INTERFACE_MODE_NPI:
447 		case CVMX_HELPER_INTERFACE_MODE_LOOP:
448 		case CVMX_HELPER_INTERFACE_MODE_XAUI:
449 			break;
450 		case CVMX_HELPER_INTERFACE_MODE_RGMII:
451 		case CVMX_HELPER_INTERFACE_MODE_GMII:
452 		case CVMX_HELPER_INTERFACE_MODE_SPI:
453 		case CVMX_HELPER_INTERFACE_MODE_SGMII:
454 		case CVMX_HELPER_INTERFACE_MODE_PICMG:
455 			cvmx_gmx_set_backpressure_override(interface, 0xf);
456 			break;
457 		}
458 	}
459 #endif
460 
461 	return 0;
462 }
463 
464 /**
465  * Enable packet input/output from the hardware. This function is
466  * called after all internal setup is complete and IPD is enabled.
467  * After this function completes, packets will be accepted from the
468  * hardware ports. PKO should still be disabled to make sure packets
469  * aren't sent out partially setup hardware.
470  *
471  * @interface: Interface to enable
472  *
473  * Returns Zero on success, negative on failure
474  */
__cvmx_helper_packet_hardware_enable(int interface)475 static int __cvmx_helper_packet_hardware_enable(int interface)
476 {
477 	int result = 0;
478 	switch (cvmx_helper_interface_get_mode(interface)) {
479 		/* These types don't support ports to IPD/PKO */
480 	case CVMX_HELPER_INTERFACE_MODE_DISABLED:
481 	case CVMX_HELPER_INTERFACE_MODE_PCIE:
482 		/* Nothing to do */
483 		break;
484 		/* XAUI is a single high speed port */
485 	case CVMX_HELPER_INTERFACE_MODE_XAUI:
486 		result = __cvmx_helper_xaui_enable(interface);
487 		break;
488 		/*
489 		 * RGMII/GMII/MII are all treated about the same. Most
490 		 * functions refer to these ports as RGMII
491 		 */
492 	case CVMX_HELPER_INTERFACE_MODE_RGMII:
493 	case CVMX_HELPER_INTERFACE_MODE_GMII:
494 		result = __cvmx_helper_rgmii_enable(interface);
495 		break;
496 		/*
497 		 * SPI4 can have 1-16 ports depending on the device at
498 		 * the other end
499 		 */
500 	case CVMX_HELPER_INTERFACE_MODE_SPI:
501 		result = __cvmx_helper_spi_enable(interface);
502 		break;
503 		/*
504 		 * SGMII can have 1-4 ports depending on how many are
505 		 * hooked up
506 		 */
507 	case CVMX_HELPER_INTERFACE_MODE_SGMII:
508 	case CVMX_HELPER_INTERFACE_MODE_PICMG:
509 		result = __cvmx_helper_sgmii_enable(interface);
510 		break;
511 		/* PCI target Network Packet Interface */
512 	case CVMX_HELPER_INTERFACE_MODE_NPI:
513 		result = __cvmx_helper_npi_enable(interface);
514 		break;
515 		/*
516 		 * Special loopback only ports. These are not the same
517 		 * as other ports in loopback mode
518 		 */
519 	case CVMX_HELPER_INTERFACE_MODE_LOOP:
520 		result = __cvmx_helper_loop_enable(interface);
521 		break;
522 	}
523 	result |= __cvmx_helper_board_hardware_enable(interface);
524 	return result;
525 }
526 
527 /**
528  * Function to adjust internal IPD pointer alignments
529  *
530  * Returns 0 on success
531  *         !0 on failure
532  */
__cvmx_helper_errata_fix_ipd_ptr_alignment(void)533 int __cvmx_helper_errata_fix_ipd_ptr_alignment(void)
534 {
535 #define FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES \
536      (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_FIRST_MBUFF_SKIP)
537 #define FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES \
538 	(CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_NOT_FIRST_MBUFF_SKIP)
539 #define FIX_IPD_OUTPORT 0
540 	/* Ports 0-15 are interface 0, 16-31 are interface 1 */
541 #define INTERFACE(port) (port >> 4)
542 #define INDEX(port) (port & 0xf)
543 	uint64_t *p64;
544 	cvmx_pko_command_word0_t pko_command;
545 	union cvmx_buf_ptr g_buffer, pkt_buffer;
546 	cvmx_wqe_t *work;
547 	int size, num_segs = 0, wqe_pcnt, pkt_pcnt;
548 	union cvmx_gmxx_prtx_cfg gmx_cfg;
549 	int retry_cnt;
550 	int retry_loop_cnt;
551 	int mtu;
552 	int i;
553 	cvmx_helper_link_info_t link_info;
554 
555 	/* Save values for restore at end */
556 	uint64_t prtx_cfg =
557 	    cvmx_read_csr(CVMX_GMXX_PRTX_CFG
558 			  (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)));
559 	uint64_t tx_ptr_en =
560 	    cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)));
561 	uint64_t rx_ptr_en =
562 	    cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)));
563 	uint64_t rxx_jabber =
564 	    cvmx_read_csr(CVMX_GMXX_RXX_JABBER
565 			  (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)));
566 	uint64_t frame_max =
567 	    cvmx_read_csr(CVMX_GMXX_RXX_FRM_MAX
568 			  (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)));
569 
570 	/* Configure port to gig FDX as required for loopback mode */
571 	cvmx_helper_rgmii_internal_loopback(FIX_IPD_OUTPORT);
572 
573 	/*
574 	 * Disable reception on all ports so if traffic is present it
575 	 * will not interfere.
576 	 */
577 	cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), 0);
578 
579 	cvmx_wait(100000000ull);
580 
581 	for (retry_loop_cnt = 0; retry_loop_cnt < 10; retry_loop_cnt++) {
582 		retry_cnt = 100000;
583 		wqe_pcnt = cvmx_read_csr(CVMX_IPD_PTR_COUNT);
584 		pkt_pcnt = (wqe_pcnt >> 7) & 0x7f;
585 		wqe_pcnt &= 0x7f;
586 
587 		num_segs = (2 + pkt_pcnt - wqe_pcnt) & 3;
588 
589 		if (num_segs == 0)
590 			goto fix_ipd_exit;
591 
592 		num_segs += 1;
593 
594 		size =
595 		    FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES +
596 		    ((num_segs - 1) * FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES) -
597 		    (FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES / 2);
598 
599 		cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)),
600 			       1 << INDEX(FIX_IPD_OUTPORT));
601 		CVMX_SYNC;
602 
603 		g_buffer.u64 = 0;
604 		g_buffer.s.addr =
605 		    cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_WQE_POOL));
606 		if (g_buffer.s.addr == 0) {
607 			cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT "
608 				     "buffer allocation failure.\n");
609 			goto fix_ipd_exit;
610 		}
611 
612 		g_buffer.s.pool = CVMX_FPA_WQE_POOL;
613 		g_buffer.s.size = num_segs;
614 
615 		pkt_buffer.u64 = 0;
616 		pkt_buffer.s.addr =
617 		    cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL));
618 		if (pkt_buffer.s.addr == 0) {
619 			cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT "
620 				     "buffer allocation failure.\n");
621 			goto fix_ipd_exit;
622 		}
623 		pkt_buffer.s.i = 1;
624 		pkt_buffer.s.pool = CVMX_FPA_PACKET_POOL;
625 		pkt_buffer.s.size = FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES;
626 
627 		p64 = (uint64_t *) cvmx_phys_to_ptr(pkt_buffer.s.addr);
628 		p64[0] = 0xffffffffffff0000ull;
629 		p64[1] = 0x08004510ull;
630 		p64[2] = ((uint64_t) (size - 14) << 48) | 0x5ae740004000ull;
631 		p64[3] = 0x3a5fc0a81073c0a8ull;
632 
633 		for (i = 0; i < num_segs; i++) {
634 			if (i > 0)
635 				pkt_buffer.s.size =
636 				    FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES;
637 
638 			if (i == (num_segs - 1))
639 				pkt_buffer.s.i = 0;
640 
641 			*(uint64_t *) cvmx_phys_to_ptr(g_buffer.s.addr +
642 						       8 * i) = pkt_buffer.u64;
643 		}
644 
645 		/* Build the PKO command */
646 		pko_command.u64 = 0;
647 		pko_command.s.segs = num_segs;
648 		pko_command.s.total_bytes = size;
649 		pko_command.s.dontfree = 0;
650 		pko_command.s.gather = 1;
651 
652 		gmx_cfg.u64 =
653 		    cvmx_read_csr(CVMX_GMXX_PRTX_CFG
654 				  (INDEX(FIX_IPD_OUTPORT),
655 				   INTERFACE(FIX_IPD_OUTPORT)));
656 		gmx_cfg.s.en = 1;
657 		cvmx_write_csr(CVMX_GMXX_PRTX_CFG
658 			       (INDEX(FIX_IPD_OUTPORT),
659 				INTERFACE(FIX_IPD_OUTPORT)), gmx_cfg.u64);
660 		cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
661 			       1 << INDEX(FIX_IPD_OUTPORT));
662 		cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
663 			       1 << INDEX(FIX_IPD_OUTPORT));
664 
665 		mtu =
666 		    cvmx_read_csr(CVMX_GMXX_RXX_JABBER
667 				  (INDEX(FIX_IPD_OUTPORT),
668 				   INTERFACE(FIX_IPD_OUTPORT)));
669 		cvmx_write_csr(CVMX_GMXX_RXX_JABBER
670 			       (INDEX(FIX_IPD_OUTPORT),
671 				INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4);
672 		cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX
673 			       (INDEX(FIX_IPD_OUTPORT),
674 				INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4);
675 
676 		cvmx_pko_send_packet_prepare(FIX_IPD_OUTPORT,
677 					     cvmx_pko_get_base_queue
678 					     (FIX_IPD_OUTPORT),
679 					     CVMX_PKO_LOCK_CMD_QUEUE);
680 		cvmx_pko_send_packet_finish(FIX_IPD_OUTPORT,
681 					    cvmx_pko_get_base_queue
682 					    (FIX_IPD_OUTPORT), pko_command,
683 					    g_buffer, CVMX_PKO_LOCK_CMD_QUEUE);
684 
685 		CVMX_SYNC;
686 
687 		do {
688 			work = cvmx_pow_work_request_sync(CVMX_POW_WAIT);
689 			retry_cnt--;
690 		} while ((work == NULL) && (retry_cnt > 0));
691 
692 		if (!retry_cnt)
693 			cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT "
694 				     "get_work() timeout occurred.\n");
695 
696 		/* Free packet */
697 		if (work)
698 			cvmx_helper_free_packet_data(work);
699 	}
700 
701 fix_ipd_exit:
702 
703 	/* Return CSR configs to saved values */
704 	cvmx_write_csr(CVMX_GMXX_PRTX_CFG
705 		       (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)),
706 		       prtx_cfg);
707 	cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
708 		       tx_ptr_en);
709 	cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
710 		       rx_ptr_en);
711 	cvmx_write_csr(CVMX_GMXX_RXX_JABBER
712 		       (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)),
713 		       rxx_jabber);
714 	cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX
715 		       (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)),
716 		       frame_max);
717 	cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), 0);
718 	/* Set link to down so autonegotiation will set it up again */
719 	link_info.u64 = 0;
720 	cvmx_helper_link_set(FIX_IPD_OUTPORT, link_info);
721 
722 	/*
723 	 * Bring the link back up as autonegotiation is not done in
724 	 * user applications.
725 	 */
726 	cvmx_helper_link_autoconf(FIX_IPD_OUTPORT);
727 
728 	CVMX_SYNC;
729 	if (num_segs)
730 		cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT failed.\n");
731 
732 	return !!num_segs;
733 
734 }
735 
736 /**
737  * Called after all internal packet IO paths are setup. This
738  * function enables IPD/PIP and begins packet input and output.
739  *
740  * Returns Zero on success, negative on failure
741  */
cvmx_helper_ipd_and_packet_input_enable(void)742 int cvmx_helper_ipd_and_packet_input_enable(void)
743 {
744 	int num_interfaces;
745 	int interface;
746 
747 	/* Enable IPD */
748 	cvmx_ipd_enable();
749 
750 	/*
751 	 * Time to enable hardware ports packet input and output. Note
752 	 * that at this point IPD/PIP must be fully functional and PKO
753 	 * must be disabled
754 	 */
755 	num_interfaces = cvmx_helper_get_number_of_interfaces();
756 	for (interface = 0; interface < num_interfaces; interface++) {
757 		if (cvmx_helper_ports_on_interface(interface) > 0)
758 			__cvmx_helper_packet_hardware_enable(interface);
759 	}
760 
761 	/* Finally enable PKO now that the entire path is up and running */
762 	cvmx_pko_enable();
763 
764 	if ((OCTEON_IS_MODEL(OCTEON_CN31XX_PASS1)
765 	     || OCTEON_IS_MODEL(OCTEON_CN30XX_PASS1))
766 	    && (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM))
767 		__cvmx_helper_errata_fix_ipd_ptr_alignment();
768 	return 0;
769 }
770 
771 /**
772  * Initialize the PIP, IPD, and PKO hardware to support
773  * simple priority based queues for the ethernet ports. Each
774  * port is configured with a number of priority queues based
775  * on CVMX_PKO_QUEUES_PER_PORT_* where each queue is lower
776  * priority than the previous.
777  *
778  * Returns Zero on success, non-zero on failure
779  */
cvmx_helper_initialize_packet_io_global(void)780 int cvmx_helper_initialize_packet_io_global(void)
781 {
782 	int result = 0;
783 	int interface;
784 	union cvmx_l2c_cfg l2c_cfg;
785 	union cvmx_smix_en smix_en;
786 	const int num_interfaces = cvmx_helper_get_number_of_interfaces();
787 
788 	/*
789 	 * CN52XX pass 1: Due to a bug in 2nd order CDR, it needs to
790 	 * be disabled.
791 	 */
792 	if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0))
793 		__cvmx_helper_errata_qlm_disable_2nd_order_cdr(1);
794 
795 	/*
796 	 * Tell L2 to give the IOB statically higher priority compared
797 	 * to the cores. This avoids conditions where IO blocks might
798 	 * be starved under very high L2 loads.
799 	 */
800 	l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG);
801 	l2c_cfg.s.lrf_arb_mode = 0;
802 	l2c_cfg.s.rfb_arb_mode = 0;
803 	cvmx_write_csr(CVMX_L2C_CFG, l2c_cfg.u64);
804 
805 	/* Make sure SMI/MDIO is enabled so we can query PHYs */
806 	smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(0));
807 	if (!smix_en.s.en) {
808 		smix_en.s.en = 1;
809 		cvmx_write_csr(CVMX_SMIX_EN(0), smix_en.u64);
810 	}
811 
812 	/* Newer chips actually have two SMI/MDIO interfaces */
813 	if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) &&
814 	    !OCTEON_IS_MODEL(OCTEON_CN58XX) &&
815 	    !OCTEON_IS_MODEL(OCTEON_CN50XX)) {
816 		smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(1));
817 		if (!smix_en.s.en) {
818 			smix_en.s.en = 1;
819 			cvmx_write_csr(CVMX_SMIX_EN(1), smix_en.u64);
820 		}
821 	}
822 
823 	cvmx_pko_initialize_global();
824 	for (interface = 0; interface < num_interfaces; interface++) {
825 		result |= cvmx_helper_interface_probe(interface);
826 		if (cvmx_helper_ports_on_interface(interface) > 0)
827 			cvmx_dprintf("Interface %d has %d ports (%s)\n",
828 				     interface,
829 				     cvmx_helper_ports_on_interface(interface),
830 				     cvmx_helper_interface_mode_to_string
831 				     (cvmx_helper_interface_get_mode
832 				      (interface)));
833 		result |= __cvmx_helper_interface_setup_ipd(interface);
834 		result |= __cvmx_helper_interface_setup_pko(interface);
835 	}
836 
837 	result |= __cvmx_helper_global_setup_ipd();
838 	result |= __cvmx_helper_global_setup_pko();
839 
840 	/* Enable any flow control and backpressure */
841 	result |= __cvmx_helper_global_setup_backpressure();
842 
843 #if CVMX_HELPER_ENABLE_IPD
844 	result |= cvmx_helper_ipd_and_packet_input_enable();
845 #endif
846 	return result;
847 }
848 
849 /**
850  * Does core local initialization for packet io
851  *
852  * Returns Zero on success, non-zero on failure
853  */
cvmx_helper_initialize_packet_io_local(void)854 int cvmx_helper_initialize_packet_io_local(void)
855 {
856 	return cvmx_pko_initialize_local();
857 }
858 
859 /**
860  * Auto configure an IPD/PKO port link state and speed. This
861  * function basically does the equivalent of:
862  * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port));
863  *
864  * @ipd_port: IPD/PKO port to auto configure
865  *
866  * Returns Link state after configure
867  */
cvmx_helper_link_autoconf(int ipd_port)868 cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port)
869 {
870 	cvmx_helper_link_info_t link_info;
871 	int interface = cvmx_helper_get_interface_num(ipd_port);
872 	int index = cvmx_helper_get_interface_index_num(ipd_port);
873 
874 	if (index >= cvmx_helper_ports_on_interface(interface)) {
875 		link_info.u64 = 0;
876 		return link_info;
877 	}
878 
879 	link_info = cvmx_helper_link_get(ipd_port);
880 	if (link_info.u64 == port_link_info[ipd_port].u64)
881 		return link_info;
882 
883 	/* If we fail to set the link speed, port_link_info will not change */
884 	cvmx_helper_link_set(ipd_port, link_info);
885 
886 	/*
887 	 * port_link_info should be the current value, which will be
888 	 * different than expect if cvmx_helper_link_set() failed.
889 	 */
890 	return port_link_info[ipd_port];
891 }
892 
893 /**
894  * Return the link state of an IPD/PKO port as returned by
895  * auto negotiation. The result of this function may not match
896  * Octeon's link config if auto negotiation has changed since
897  * the last call to cvmx_helper_link_set().
898  *
899  * @ipd_port: IPD/PKO port to query
900  *
901  * Returns Link state
902  */
cvmx_helper_link_get(int ipd_port)903 cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port)
904 {
905 	cvmx_helper_link_info_t result;
906 	int interface = cvmx_helper_get_interface_num(ipd_port);
907 	int index = cvmx_helper_get_interface_index_num(ipd_port);
908 
909 	/* The default result will be a down link unless the code below
910 	   changes it */
911 	result.u64 = 0;
912 
913 	if (index >= cvmx_helper_ports_on_interface(interface))
914 		return result;
915 
916 	switch (cvmx_helper_interface_get_mode(interface)) {
917 	case CVMX_HELPER_INTERFACE_MODE_DISABLED:
918 	case CVMX_HELPER_INTERFACE_MODE_PCIE:
919 		/* Network links are not supported */
920 		break;
921 	case CVMX_HELPER_INTERFACE_MODE_XAUI:
922 		result = __cvmx_helper_xaui_link_get(ipd_port);
923 		break;
924 	case CVMX_HELPER_INTERFACE_MODE_GMII:
925 		if (index == 0)
926 			result = __cvmx_helper_rgmii_link_get(ipd_port);
927 		else {
928 			result.s.full_duplex = 1;
929 			result.s.link_up = 1;
930 			result.s.speed = 1000;
931 		}
932 		break;
933 	case CVMX_HELPER_INTERFACE_MODE_RGMII:
934 		result = __cvmx_helper_rgmii_link_get(ipd_port);
935 		break;
936 	case CVMX_HELPER_INTERFACE_MODE_SPI:
937 		result = __cvmx_helper_spi_link_get(ipd_port);
938 		break;
939 	case CVMX_HELPER_INTERFACE_MODE_SGMII:
940 	case CVMX_HELPER_INTERFACE_MODE_PICMG:
941 		result = __cvmx_helper_sgmii_link_get(ipd_port);
942 		break;
943 	case CVMX_HELPER_INTERFACE_MODE_NPI:
944 	case CVMX_HELPER_INTERFACE_MODE_LOOP:
945 		/* Network links are not supported */
946 		break;
947 	}
948 	return result;
949 }
950 
951 /**
952  * Configure an IPD/PKO port for the specified link state. This
953  * function does not influence auto negotiation at the PHY level.
954  * The passed link state must always match the link state returned
955  * by cvmx_helper_link_get(). It is normally best to use
956  * cvmx_helper_link_autoconf() instead.
957  *
958  * @ipd_port:  IPD/PKO port to configure
959  * @link_info: The new link state
960  *
961  * Returns Zero on success, negative on failure
962  */
cvmx_helper_link_set(int ipd_port,cvmx_helper_link_info_t link_info)963 int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
964 {
965 	int result = -1;
966 	int interface = cvmx_helper_get_interface_num(ipd_port);
967 	int index = cvmx_helper_get_interface_index_num(ipd_port);
968 
969 	if (index >= cvmx_helper_ports_on_interface(interface))
970 		return -1;
971 
972 	switch (cvmx_helper_interface_get_mode(interface)) {
973 	case CVMX_HELPER_INTERFACE_MODE_DISABLED:
974 	case CVMX_HELPER_INTERFACE_MODE_PCIE:
975 		break;
976 	case CVMX_HELPER_INTERFACE_MODE_XAUI:
977 		result = __cvmx_helper_xaui_link_set(ipd_port, link_info);
978 		break;
979 		/*
980 		 * RGMII/GMII/MII are all treated about the same. Most
981 		 * functions refer to these ports as RGMII.
982 		 */
983 	case CVMX_HELPER_INTERFACE_MODE_RGMII:
984 	case CVMX_HELPER_INTERFACE_MODE_GMII:
985 		result = __cvmx_helper_rgmii_link_set(ipd_port, link_info);
986 		break;
987 	case CVMX_HELPER_INTERFACE_MODE_SPI:
988 		result = __cvmx_helper_spi_link_set(ipd_port, link_info);
989 		break;
990 	case CVMX_HELPER_INTERFACE_MODE_SGMII:
991 	case CVMX_HELPER_INTERFACE_MODE_PICMG:
992 		result = __cvmx_helper_sgmii_link_set(ipd_port, link_info);
993 		break;
994 	case CVMX_HELPER_INTERFACE_MODE_NPI:
995 	case CVMX_HELPER_INTERFACE_MODE_LOOP:
996 		break;
997 	}
998 	/* Set the port_link_info here so that the link status is updated
999 	   no matter how cvmx_helper_link_set is called. We don't change
1000 	   the value if link_set failed */
1001 	if (result == 0)
1002 		port_link_info[ipd_port].u64 = link_info.u64;
1003 	return result;
1004 }
1005 
1006 /**
1007  * Configure a port for internal and/or external loopback. Internal loopback
1008  * causes packets sent by the port to be received by Octeon. External loopback
1009  * causes packets received from the wire to sent out again.
1010  *
1011  * @ipd_port: IPD/PKO port to loopback.
1012  * @enable_internal:
1013  *                 Non zero if you want internal loopback
1014  * @enable_external:
1015  *                 Non zero if you want external loopback
1016  *
1017  * Returns Zero on success, negative on failure.
1018  */
cvmx_helper_configure_loopback(int ipd_port,int enable_internal,int enable_external)1019 int cvmx_helper_configure_loopback(int ipd_port, int enable_internal,
1020 				   int enable_external)
1021 {
1022 	int result = -1;
1023 	int interface = cvmx_helper_get_interface_num(ipd_port);
1024 	int index = cvmx_helper_get_interface_index_num(ipd_port);
1025 
1026 	if (index >= cvmx_helper_ports_on_interface(interface))
1027 		return -1;
1028 
1029 	switch (cvmx_helper_interface_get_mode(interface)) {
1030 	case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1031 	case CVMX_HELPER_INTERFACE_MODE_PCIE:
1032 	case CVMX_HELPER_INTERFACE_MODE_SPI:
1033 	case CVMX_HELPER_INTERFACE_MODE_NPI:
1034 	case CVMX_HELPER_INTERFACE_MODE_LOOP:
1035 		break;
1036 	case CVMX_HELPER_INTERFACE_MODE_XAUI:
1037 		result =
1038 		    __cvmx_helper_xaui_configure_loopback(ipd_port,
1039 							  enable_internal,
1040 							  enable_external);
1041 		break;
1042 	case CVMX_HELPER_INTERFACE_MODE_RGMII:
1043 	case CVMX_HELPER_INTERFACE_MODE_GMII:
1044 		result =
1045 		    __cvmx_helper_rgmii_configure_loopback(ipd_port,
1046 							   enable_internal,
1047 							   enable_external);
1048 		break;
1049 	case CVMX_HELPER_INTERFACE_MODE_SGMII:
1050 	case CVMX_HELPER_INTERFACE_MODE_PICMG:
1051 		result =
1052 		    __cvmx_helper_sgmii_configure_loopback(ipd_port,
1053 							   enable_internal,
1054 							   enable_external);
1055 		break;
1056 	}
1057 	return result;
1058 }
1059