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 <asm/octeon/cvmx-config.h>
36
37#include <asm/octeon/cvmx-fpa.h>
38#include <asm/octeon/cvmx-pip.h>
39#include <asm/octeon/cvmx-pko.h>
40#include <asm/octeon/cvmx-ipd.h>
41#include <asm/octeon/cvmx-spi.h>
42#include <asm/octeon/cvmx-helper.h>
43#include <asm/octeon/cvmx-helper-board.h>
44
45#include <asm/octeon/cvmx-pip-defs.h>
46#include <asm/octeon/cvmx-smix-defs.h>
47#include <asm/octeon/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 */
56void (*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 */
67void (*cvmx_override_ipd_port_setup) (int ipd_port);
68
69/* Port count per interface */
70static int interface_port_count[4] = { 0, 0, 0, 0 };
71
72/* Port last configured link info index by IPD/PKO port */
73static 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 */
84int 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 */
101int 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 */
116cvmx_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 */
194static 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 sets the interface_port_count[interface] correctly,
238 * without modifying any hardware configuration.  Hardware setup of
239 * the ports will be performed later.
240 *
241 * @interface: Interface to probe
242 *
243 * Returns Zero on success, negative on failure
244 */
245int cvmx_helper_interface_enumerate(int interface)
246{
247	switch (cvmx_helper_interface_get_mode(interface)) {
248		/* These types don't support ports to IPD/PKO */
249	case CVMX_HELPER_INTERFACE_MODE_DISABLED:
250	case CVMX_HELPER_INTERFACE_MODE_PCIE:
251		interface_port_count[interface] = 0;
252		break;
253		/* XAUI is a single high speed port */
254	case CVMX_HELPER_INTERFACE_MODE_XAUI:
255		interface_port_count[interface] =
256		    __cvmx_helper_xaui_enumerate(interface);
257		break;
258		/*
259		 * RGMII/GMII/MII are all treated about the same. Most
260		 * functions refer to these ports as RGMII.
261		 */
262	case CVMX_HELPER_INTERFACE_MODE_RGMII:
263	case CVMX_HELPER_INTERFACE_MODE_GMII:
264		interface_port_count[interface] =
265		    __cvmx_helper_rgmii_enumerate(interface);
266		break;
267		/*
268		 * SPI4 can have 1-16 ports depending on the device at
269		 * the other end.
270		 */
271	case CVMX_HELPER_INTERFACE_MODE_SPI:
272		interface_port_count[interface] =
273		    __cvmx_helper_spi_enumerate(interface);
274		break;
275		/*
276		 * SGMII can have 1-4 ports depending on how many are
277		 * hooked up.
278		 */
279	case CVMX_HELPER_INTERFACE_MODE_SGMII:
280	case CVMX_HELPER_INTERFACE_MODE_PICMG:
281		interface_port_count[interface] =
282		    __cvmx_helper_sgmii_enumerate(interface);
283		break;
284		/* PCI target Network Packet Interface */
285	case CVMX_HELPER_INTERFACE_MODE_NPI:
286		interface_port_count[interface] =
287		    __cvmx_helper_npi_enumerate(interface);
288		break;
289		/*
290		 * Special loopback only ports. These are not the same
291		 * as other ports in loopback mode.
292		 */
293	case CVMX_HELPER_INTERFACE_MODE_LOOP:
294		interface_port_count[interface] =
295		    __cvmx_helper_loop_enumerate(interface);
296		break;
297	}
298
299	interface_port_count[interface] =
300	    __cvmx_helper_board_interface_probe(interface,
301						interface_port_count
302						[interface]);
303
304	/* Make sure all global variables propagate to other cores */
305	CVMX_SYNCWS;
306
307	return 0;
308}
309
310/**
311 * This function probes an interface to determine the actual
312 * number of hardware ports connected to it. It doesn't setup the
313 * ports or enable them. The main goal here is to set the global
314 * interface_port_count[interface] correctly. Hardware setup of the
315 * ports will be performed later.
316 *
317 * @interface: Interface to probe
318 *
319 * Returns Zero on success, negative on failure
320 */
321int cvmx_helper_interface_probe(int interface)
322{
323	cvmx_helper_interface_enumerate(interface);
324	/* At this stage in the game we don't want packets to be moving yet.
325	   The following probe calls should perform hardware setup
326	   needed to determine port counts. Receive must still be disabled */
327	switch (cvmx_helper_interface_get_mode(interface)) {
328		/* These types don't support ports to IPD/PKO */
329	case CVMX_HELPER_INTERFACE_MODE_DISABLED:
330	case CVMX_HELPER_INTERFACE_MODE_PCIE:
331		break;
332		/* XAUI is a single high speed port */
333	case CVMX_HELPER_INTERFACE_MODE_XAUI:
334		__cvmx_helper_xaui_probe(interface);
335		break;
336		/*
337		 * RGMII/GMII/MII are all treated about the same. Most
338		 * functions refer to these ports as RGMII.
339		 */
340	case CVMX_HELPER_INTERFACE_MODE_RGMII:
341	case CVMX_HELPER_INTERFACE_MODE_GMII:
342		__cvmx_helper_rgmii_probe(interface);
343		break;
344		/*
345		 * SPI4 can have 1-16 ports depending on the device at
346		 * the other end.
347		 */
348	case CVMX_HELPER_INTERFACE_MODE_SPI:
349		__cvmx_helper_spi_probe(interface);
350		break;
351		/*
352		 * SGMII can have 1-4 ports depending on how many are
353		 * hooked up.
354		 */
355	case CVMX_HELPER_INTERFACE_MODE_SGMII:
356	case CVMX_HELPER_INTERFACE_MODE_PICMG:
357		__cvmx_helper_sgmii_probe(interface);
358		break;
359		/* PCI target Network Packet Interface */
360	case CVMX_HELPER_INTERFACE_MODE_NPI:
361		__cvmx_helper_npi_probe(interface);
362		break;
363		/*
364		 * Special loopback only ports. These are not the same
365		 * as other ports in loopback mode.
366		 */
367	case CVMX_HELPER_INTERFACE_MODE_LOOP:
368		__cvmx_helper_loop_probe(interface);
369		break;
370	}
371
372	/* Make sure all global variables propagate to other cores */
373	CVMX_SYNCWS;
374
375	return 0;
376}
377
378/**
379 * Setup the IPD/PIP for the ports on an interface. Packet
380 * classification and tagging are set for every port on the
381 * interface. The number of ports on the interface must already
382 * have been probed.
383 *
384 * @interface: Interface to setup IPD/PIP for
385 *
386 * Returns Zero on success, negative on failure
387 */
388static int __cvmx_helper_interface_setup_ipd(int interface)
389{
390	int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
391	int num_ports = interface_port_count[interface];
392
393	while (num_ports--) {
394		__cvmx_helper_port_setup_ipd(ipd_port);
395		ipd_port++;
396	}
397	return 0;
398}
399
400/**
401 * Setup global setting for IPD/PIP not related to a specific
402 * interface or port. This must be called before IPD is enabled.
403 *
404 * Returns Zero on success, negative on failure.
405 */
406static int __cvmx_helper_global_setup_ipd(void)
407{
408	/* Setup the global packet input options */
409	cvmx_ipd_config(CVMX_FPA_PACKET_POOL_SIZE / 8,
410			CVMX_HELPER_FIRST_MBUFF_SKIP / 8,
411			CVMX_HELPER_NOT_FIRST_MBUFF_SKIP / 8,
412			/* The +8 is to account for the next ptr */
413			(CVMX_HELPER_FIRST_MBUFF_SKIP + 8) / 128,
414			/* The +8 is to account for the next ptr */
415			(CVMX_HELPER_NOT_FIRST_MBUFF_SKIP + 8) / 128,
416			CVMX_FPA_WQE_POOL,
417			CVMX_IPD_OPC_MODE_STT,
418			CVMX_HELPER_ENABLE_BACK_PRESSURE);
419	return 0;
420}
421
422/**
423 * Setup the PKO for the ports on an interface. The number of
424 * queues per port and the priority of each PKO output queue
425 * is set here. PKO must be disabled when this function is called.
426 *
427 * @interface: Interface to setup PKO for
428 *
429 * Returns Zero on success, negative on failure
430 */
431static int __cvmx_helper_interface_setup_pko(int interface)
432{
433	/*
434	 * Each packet output queue has an associated priority. The
435	 * higher the priority, the more often it can send a packet. A
436	 * priority of 8 means it can send in all 8 rounds of
437	 * contention. We're going to make each queue one less than
438	 * the last.  The vector of priorities has been extended to
439	 * support CN5xxx CPUs, where up to 16 queues can be
440	 * associated to a port.  To keep backward compatibility we
441	 * don't change the initial 8 priorities and replicate them in
442	 * the second half.  With per-core PKO queues (PKO lockless
443	 * operation) all queues have the same priority.
444	 */
445	uint64_t priorities[16] =
446	    { 8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1 };
447
448	/*
449	 * Setup the IPD/PIP and PKO for the ports discovered
450	 * above. Here packet classification, tagging and output
451	 * priorities are set.
452	 */
453	int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
454	int num_ports = interface_port_count[interface];
455	while (num_ports--) {
456		/*
457		 * Give the user a chance to override the per queue
458		 * priorities.
459		 */
460		if (cvmx_override_pko_queue_priority)
461			cvmx_override_pko_queue_priority(ipd_port, priorities);
462
463		cvmx_pko_config_port(ipd_port,
464				     cvmx_pko_get_base_queue_per_core(ipd_port,
465								      0),
466				     cvmx_pko_get_num_queues(ipd_port),
467				     priorities);
468		ipd_port++;
469	}
470	return 0;
471}
472
473/**
474 * Setup global setting for PKO not related to a specific
475 * interface or port. This must be called before PKO is enabled.
476 *
477 * Returns Zero on success, negative on failure.
478 */
479static int __cvmx_helper_global_setup_pko(void)
480{
481	/*
482	 * Disable tagwait FAU timeout. This needs to be done before
483	 * anyone might start packet output using tags.
484	 */
485	union cvmx_iob_fau_timeout fau_to;
486	fau_to.u64 = 0;
487	fau_to.s.tout_val = 0xfff;
488	fau_to.s.tout_enb = 0;
489	cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64);
490	return 0;
491}
492
493/**
494 * Setup global backpressure setting.
495 *
496 * Returns Zero on success, negative on failure
497 */
498static int __cvmx_helper_global_setup_backpressure(void)
499{
500#if CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE
501	/* Disable backpressure if configured to do so */
502	/* Disable backpressure (pause frame) generation */
503	int num_interfaces = cvmx_helper_get_number_of_interfaces();
504	int interface;
505	for (interface = 0; interface < num_interfaces; interface++) {
506		switch (cvmx_helper_interface_get_mode(interface)) {
507		case CVMX_HELPER_INTERFACE_MODE_DISABLED:
508		case CVMX_HELPER_INTERFACE_MODE_PCIE:
509		case CVMX_HELPER_INTERFACE_MODE_NPI:
510		case CVMX_HELPER_INTERFACE_MODE_LOOP:
511		case CVMX_HELPER_INTERFACE_MODE_XAUI:
512			break;
513		case CVMX_HELPER_INTERFACE_MODE_RGMII:
514		case CVMX_HELPER_INTERFACE_MODE_GMII:
515		case CVMX_HELPER_INTERFACE_MODE_SPI:
516		case CVMX_HELPER_INTERFACE_MODE_SGMII:
517		case CVMX_HELPER_INTERFACE_MODE_PICMG:
518			cvmx_gmx_set_backpressure_override(interface, 0xf);
519			break;
520		}
521	}
522#endif
523
524	return 0;
525}
526
527/**
528 * Enable packet input/output from the hardware. This function is
529 * called after all internal setup is complete and IPD is enabled.
530 * After this function completes, packets will be accepted from the
531 * hardware ports. PKO should still be disabled to make sure packets
532 * aren't sent out partially setup hardware.
533 *
534 * @interface: Interface to enable
535 *
536 * Returns Zero on success, negative on failure
537 */
538static int __cvmx_helper_packet_hardware_enable(int interface)
539{
540	int result = 0;
541	switch (cvmx_helper_interface_get_mode(interface)) {
542		/* These types don't support ports to IPD/PKO */
543	case CVMX_HELPER_INTERFACE_MODE_DISABLED:
544	case CVMX_HELPER_INTERFACE_MODE_PCIE:
545		/* Nothing to do */
546		break;
547		/* XAUI is a single high speed port */
548	case CVMX_HELPER_INTERFACE_MODE_XAUI:
549		result = __cvmx_helper_xaui_enable(interface);
550		break;
551		/*
552		 * RGMII/GMII/MII are all treated about the same. Most
553		 * functions refer to these ports as RGMII
554		 */
555	case CVMX_HELPER_INTERFACE_MODE_RGMII:
556	case CVMX_HELPER_INTERFACE_MODE_GMII:
557		result = __cvmx_helper_rgmii_enable(interface);
558		break;
559		/*
560		 * SPI4 can have 1-16 ports depending on the device at
561		 * the other end
562		 */
563	case CVMX_HELPER_INTERFACE_MODE_SPI:
564		result = __cvmx_helper_spi_enable(interface);
565		break;
566		/*
567		 * SGMII can have 1-4 ports depending on how many are
568		 * hooked up
569		 */
570	case CVMX_HELPER_INTERFACE_MODE_SGMII:
571	case CVMX_HELPER_INTERFACE_MODE_PICMG:
572		result = __cvmx_helper_sgmii_enable(interface);
573		break;
574		/* PCI target Network Packet Interface */
575	case CVMX_HELPER_INTERFACE_MODE_NPI:
576		result = __cvmx_helper_npi_enable(interface);
577		break;
578		/*
579		 * Special loopback only ports. These are not the same
580		 * as other ports in loopback mode
581		 */
582	case CVMX_HELPER_INTERFACE_MODE_LOOP:
583		result = __cvmx_helper_loop_enable(interface);
584		break;
585	}
586	result |= __cvmx_helper_board_hardware_enable(interface);
587	return result;
588}
589
590/**
591 * Function to adjust internal IPD pointer alignments
592 *
593 * Returns 0 on success
594 *         !0 on failure
595 */
596int __cvmx_helper_errata_fix_ipd_ptr_alignment(void)
597{
598#define FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES \
599     (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_FIRST_MBUFF_SKIP)
600#define FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES \
601	(CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_NOT_FIRST_MBUFF_SKIP)
602#define FIX_IPD_OUTPORT 0
603	/* Ports 0-15 are interface 0, 16-31 are interface 1 */
604#define INTERFACE(port) (port >> 4)
605#define INDEX(port) (port & 0xf)
606	uint64_t *p64;
607	cvmx_pko_command_word0_t pko_command;
608	union cvmx_buf_ptr g_buffer, pkt_buffer;
609	cvmx_wqe_t *work;
610	int size, num_segs = 0, wqe_pcnt, pkt_pcnt;
611	union cvmx_gmxx_prtx_cfg gmx_cfg;
612	int retry_cnt;
613	int retry_loop_cnt;
614	int i;
615	cvmx_helper_link_info_t link_info;
616
617	/* Save values for restore at end */
618	uint64_t prtx_cfg =
619	    cvmx_read_csr(CVMX_GMXX_PRTX_CFG
620			  (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)));
621	uint64_t tx_ptr_en =
622	    cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)));
623	uint64_t rx_ptr_en =
624	    cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)));
625	uint64_t rxx_jabber =
626	    cvmx_read_csr(CVMX_GMXX_RXX_JABBER
627			  (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)));
628	uint64_t frame_max =
629	    cvmx_read_csr(CVMX_GMXX_RXX_FRM_MAX
630			  (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)));
631
632	/* Configure port to gig FDX as required for loopback mode */
633	cvmx_helper_rgmii_internal_loopback(FIX_IPD_OUTPORT);
634
635	/*
636	 * Disable reception on all ports so if traffic is present it
637	 * will not interfere.
638	 */
639	cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), 0);
640
641	cvmx_wait(100000000ull);
642
643	for (retry_loop_cnt = 0; retry_loop_cnt < 10; retry_loop_cnt++) {
644		retry_cnt = 100000;
645		wqe_pcnt = cvmx_read_csr(CVMX_IPD_PTR_COUNT);
646		pkt_pcnt = (wqe_pcnt >> 7) & 0x7f;
647		wqe_pcnt &= 0x7f;
648
649		num_segs = (2 + pkt_pcnt - wqe_pcnt) & 3;
650
651		if (num_segs == 0)
652			goto fix_ipd_exit;
653
654		num_segs += 1;
655
656		size =
657		    FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES +
658		    ((num_segs - 1) * FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES) -
659		    (FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES / 2);
660
661		cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)),
662			       1 << INDEX(FIX_IPD_OUTPORT));
663		CVMX_SYNC;
664
665		g_buffer.u64 = 0;
666		g_buffer.s.addr =
667		    cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_WQE_POOL));
668		if (g_buffer.s.addr == 0) {
669			cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT "
670				     "buffer allocation failure.\n");
671			goto fix_ipd_exit;
672		}
673
674		g_buffer.s.pool = CVMX_FPA_WQE_POOL;
675		g_buffer.s.size = num_segs;
676
677		pkt_buffer.u64 = 0;
678		pkt_buffer.s.addr =
679		    cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL));
680		if (pkt_buffer.s.addr == 0) {
681			cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT "
682				     "buffer allocation failure.\n");
683			goto fix_ipd_exit;
684		}
685		pkt_buffer.s.i = 1;
686		pkt_buffer.s.pool = CVMX_FPA_PACKET_POOL;
687		pkt_buffer.s.size = FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES;
688
689		p64 = (uint64_t *) cvmx_phys_to_ptr(pkt_buffer.s.addr);
690		p64[0] = 0xffffffffffff0000ull;
691		p64[1] = 0x08004510ull;
692		p64[2] = ((uint64_t) (size - 14) << 48) | 0x5ae740004000ull;
693		p64[3] = 0x3a5fc0a81073c0a8ull;
694
695		for (i = 0; i < num_segs; i++) {
696			if (i > 0)
697				pkt_buffer.s.size =
698				    FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES;
699
700			if (i == (num_segs - 1))
701				pkt_buffer.s.i = 0;
702
703			*(uint64_t *) cvmx_phys_to_ptr(g_buffer.s.addr +
704						       8 * i) = pkt_buffer.u64;
705		}
706
707		/* Build the PKO command */
708		pko_command.u64 = 0;
709		pko_command.s.segs = num_segs;
710		pko_command.s.total_bytes = size;
711		pko_command.s.dontfree = 0;
712		pko_command.s.gather = 1;
713
714		gmx_cfg.u64 =
715		    cvmx_read_csr(CVMX_GMXX_PRTX_CFG
716				  (INDEX(FIX_IPD_OUTPORT),
717				   INTERFACE(FIX_IPD_OUTPORT)));
718		gmx_cfg.s.en = 1;
719		cvmx_write_csr(CVMX_GMXX_PRTX_CFG
720			       (INDEX(FIX_IPD_OUTPORT),
721				INTERFACE(FIX_IPD_OUTPORT)), gmx_cfg.u64);
722		cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
723			       1 << INDEX(FIX_IPD_OUTPORT));
724		cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
725			       1 << INDEX(FIX_IPD_OUTPORT));
726
727		cvmx_write_csr(CVMX_GMXX_RXX_JABBER
728			       (INDEX(FIX_IPD_OUTPORT),
729				INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4);
730		cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX
731			       (INDEX(FIX_IPD_OUTPORT),
732				INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4);
733
734		cvmx_pko_send_packet_prepare(FIX_IPD_OUTPORT,
735					     cvmx_pko_get_base_queue
736					     (FIX_IPD_OUTPORT),
737					     CVMX_PKO_LOCK_CMD_QUEUE);
738		cvmx_pko_send_packet_finish(FIX_IPD_OUTPORT,
739					    cvmx_pko_get_base_queue
740					    (FIX_IPD_OUTPORT), pko_command,
741					    g_buffer, CVMX_PKO_LOCK_CMD_QUEUE);
742
743		CVMX_SYNC;
744
745		do {
746			work = cvmx_pow_work_request_sync(CVMX_POW_WAIT);
747			retry_cnt--;
748		} while ((work == NULL) && (retry_cnt > 0));
749
750		if (!retry_cnt)
751			cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT "
752				     "get_work() timeout occurred.\n");
753
754		/* Free packet */
755		if (work)
756			cvmx_helper_free_packet_data(work);
757	}
758
759fix_ipd_exit:
760
761	/* Return CSR configs to saved values */
762	cvmx_write_csr(CVMX_GMXX_PRTX_CFG
763		       (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)),
764		       prtx_cfg);
765	cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
766		       tx_ptr_en);
767	cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
768		       rx_ptr_en);
769	cvmx_write_csr(CVMX_GMXX_RXX_JABBER
770		       (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)),
771		       rxx_jabber);
772	cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX
773		       (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)),
774		       frame_max);
775	cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), 0);
776	/* Set link to down so autonegotiation will set it up again */
777	link_info.u64 = 0;
778	cvmx_helper_link_set(FIX_IPD_OUTPORT, link_info);
779
780	/*
781	 * Bring the link back up as autonegotiation is not done in
782	 * user applications.
783	 */
784	cvmx_helper_link_autoconf(FIX_IPD_OUTPORT);
785
786	CVMX_SYNC;
787	if (num_segs)
788		cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT failed.\n");
789
790	return !!num_segs;
791
792}
793
794/**
795 * Called after all internal packet IO paths are setup. This
796 * function enables IPD/PIP and begins packet input and output.
797 *
798 * Returns Zero on success, negative on failure
799 */
800int cvmx_helper_ipd_and_packet_input_enable(void)
801{
802	int num_interfaces;
803	int interface;
804
805	/* Enable IPD */
806	cvmx_ipd_enable();
807
808	/*
809	 * Time to enable hardware ports packet input and output. Note
810	 * that at this point IPD/PIP must be fully functional and PKO
811	 * must be disabled
812	 */
813	num_interfaces = cvmx_helper_get_number_of_interfaces();
814	for (interface = 0; interface < num_interfaces; interface++) {
815		if (cvmx_helper_ports_on_interface(interface) > 0)
816			__cvmx_helper_packet_hardware_enable(interface);
817	}
818
819	/* Finally enable PKO now that the entire path is up and running */
820	cvmx_pko_enable();
821
822	if ((OCTEON_IS_MODEL(OCTEON_CN31XX_PASS1)
823	     || OCTEON_IS_MODEL(OCTEON_CN30XX_PASS1))
824	    && (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM))
825		__cvmx_helper_errata_fix_ipd_ptr_alignment();
826	return 0;
827}
828
829/**
830 * Initialize the PIP, IPD, and PKO hardware to support
831 * simple priority based queues for the ethernet ports. Each
832 * port is configured with a number of priority queues based
833 * on CVMX_PKO_QUEUES_PER_PORT_* where each queue is lower
834 * priority than the previous.
835 *
836 * Returns Zero on success, non-zero on failure
837 */
838int cvmx_helper_initialize_packet_io_global(void)
839{
840	int result = 0;
841	int interface;
842	union cvmx_l2c_cfg l2c_cfg;
843	union cvmx_smix_en smix_en;
844	const int num_interfaces = cvmx_helper_get_number_of_interfaces();
845
846	/*
847	 * CN52XX pass 1: Due to a bug in 2nd order CDR, it needs to
848	 * be disabled.
849	 */
850	if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0))
851		__cvmx_helper_errata_qlm_disable_2nd_order_cdr(1);
852
853	/*
854	 * Tell L2 to give the IOB statically higher priority compared
855	 * to the cores. This avoids conditions where IO blocks might
856	 * be starved under very high L2 loads.
857	 */
858	l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG);
859	l2c_cfg.s.lrf_arb_mode = 0;
860	l2c_cfg.s.rfb_arb_mode = 0;
861	cvmx_write_csr(CVMX_L2C_CFG, l2c_cfg.u64);
862
863	/* Make sure SMI/MDIO is enabled so we can query PHYs */
864	smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(0));
865	if (!smix_en.s.en) {
866		smix_en.s.en = 1;
867		cvmx_write_csr(CVMX_SMIX_EN(0), smix_en.u64);
868	}
869
870	/* Newer chips actually have two SMI/MDIO interfaces */
871	if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) &&
872	    !OCTEON_IS_MODEL(OCTEON_CN58XX) &&
873	    !OCTEON_IS_MODEL(OCTEON_CN50XX)) {
874		smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(1));
875		if (!smix_en.s.en) {
876			smix_en.s.en = 1;
877			cvmx_write_csr(CVMX_SMIX_EN(1), smix_en.u64);
878		}
879	}
880
881	cvmx_pko_initialize_global();
882	for (interface = 0; interface < num_interfaces; interface++) {
883		result |= cvmx_helper_interface_probe(interface);
884		if (cvmx_helper_ports_on_interface(interface) > 0)
885			cvmx_dprintf("Interface %d has %d ports (%s)\n",
886				     interface,
887				     cvmx_helper_ports_on_interface(interface),
888				     cvmx_helper_interface_mode_to_string
889				     (cvmx_helper_interface_get_mode
890				      (interface)));
891		result |= __cvmx_helper_interface_setup_ipd(interface);
892		result |= __cvmx_helper_interface_setup_pko(interface);
893	}
894
895	result |= __cvmx_helper_global_setup_ipd();
896	result |= __cvmx_helper_global_setup_pko();
897
898	/* Enable any flow control and backpressure */
899	result |= __cvmx_helper_global_setup_backpressure();
900
901#if CVMX_HELPER_ENABLE_IPD
902	result |= cvmx_helper_ipd_and_packet_input_enable();
903#endif
904	return result;
905}
906
907/**
908 * Does core local initialization for packet io
909 *
910 * Returns Zero on success, non-zero on failure
911 */
912int cvmx_helper_initialize_packet_io_local(void)
913{
914	return cvmx_pko_initialize_local();
915}
916
917/**
918 * Auto configure an IPD/PKO port link state and speed. This
919 * function basically does the equivalent of:
920 * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port));
921 *
922 * @ipd_port: IPD/PKO port to auto configure
923 *
924 * Returns Link state after configure
925 */
926cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port)
927{
928	cvmx_helper_link_info_t link_info;
929	int interface = cvmx_helper_get_interface_num(ipd_port);
930	int index = cvmx_helper_get_interface_index_num(ipd_port);
931
932	if (index >= cvmx_helper_ports_on_interface(interface)) {
933		link_info.u64 = 0;
934		return link_info;
935	}
936
937	link_info = cvmx_helper_link_get(ipd_port);
938	if (link_info.u64 == port_link_info[ipd_port].u64)
939		return link_info;
940
941	/* If we fail to set the link speed, port_link_info will not change */
942	cvmx_helper_link_set(ipd_port, link_info);
943
944	/*
945	 * port_link_info should be the current value, which will be
946	 * different than expect if cvmx_helper_link_set() failed.
947	 */
948	return port_link_info[ipd_port];
949}
950
951/**
952 * Return the link state of an IPD/PKO port as returned by
953 * auto negotiation. The result of this function may not match
954 * Octeon's link config if auto negotiation has changed since
955 * the last call to cvmx_helper_link_set().
956 *
957 * @ipd_port: IPD/PKO port to query
958 *
959 * Returns Link state
960 */
961cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port)
962{
963	cvmx_helper_link_info_t result;
964	int interface = cvmx_helper_get_interface_num(ipd_port);
965	int index = cvmx_helper_get_interface_index_num(ipd_port);
966
967	/* The default result will be a down link unless the code below
968	   changes it */
969	result.u64 = 0;
970
971	if (index >= cvmx_helper_ports_on_interface(interface))
972		return result;
973
974	switch (cvmx_helper_interface_get_mode(interface)) {
975	case CVMX_HELPER_INTERFACE_MODE_DISABLED:
976	case CVMX_HELPER_INTERFACE_MODE_PCIE:
977		/* Network links are not supported */
978		break;
979	case CVMX_HELPER_INTERFACE_MODE_XAUI:
980		result = __cvmx_helper_xaui_link_get(ipd_port);
981		break;
982	case CVMX_HELPER_INTERFACE_MODE_GMII:
983		if (index == 0)
984			result = __cvmx_helper_rgmii_link_get(ipd_port);
985		else {
986			result.s.full_duplex = 1;
987			result.s.link_up = 1;
988			result.s.speed = 1000;
989		}
990		break;
991	case CVMX_HELPER_INTERFACE_MODE_RGMII:
992		result = __cvmx_helper_rgmii_link_get(ipd_port);
993		break;
994	case CVMX_HELPER_INTERFACE_MODE_SPI:
995		result = __cvmx_helper_spi_link_get(ipd_port);
996		break;
997	case CVMX_HELPER_INTERFACE_MODE_SGMII:
998	case CVMX_HELPER_INTERFACE_MODE_PICMG:
999		result = __cvmx_helper_sgmii_link_get(ipd_port);
1000		break;
1001	case CVMX_HELPER_INTERFACE_MODE_NPI:
1002	case CVMX_HELPER_INTERFACE_MODE_LOOP:
1003		/* Network links are not supported */
1004		break;
1005	}
1006	return result;
1007}
1008
1009/**
1010 * Configure an IPD/PKO port for the specified link state. This
1011 * function does not influence auto negotiation at the PHY level.
1012 * The passed link state must always match the link state returned
1013 * by cvmx_helper_link_get(). It is normally best to use
1014 * cvmx_helper_link_autoconf() instead.
1015 *
1016 * @ipd_port:  IPD/PKO port to configure
1017 * @link_info: The new link state
1018 *
1019 * Returns Zero on success, negative on failure
1020 */
1021int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
1022{
1023	int result = -1;
1024	int interface = cvmx_helper_get_interface_num(ipd_port);
1025	int index = cvmx_helper_get_interface_index_num(ipd_port);
1026
1027	if (index >= cvmx_helper_ports_on_interface(interface))
1028		return -1;
1029
1030	switch (cvmx_helper_interface_get_mode(interface)) {
1031	case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1032	case CVMX_HELPER_INTERFACE_MODE_PCIE:
1033		break;
1034	case CVMX_HELPER_INTERFACE_MODE_XAUI:
1035		result = __cvmx_helper_xaui_link_set(ipd_port, link_info);
1036		break;
1037		/*
1038		 * RGMII/GMII/MII are all treated about the same. Most
1039		 * functions refer to these ports as RGMII.
1040		 */
1041	case CVMX_HELPER_INTERFACE_MODE_RGMII:
1042	case CVMX_HELPER_INTERFACE_MODE_GMII:
1043		result = __cvmx_helper_rgmii_link_set(ipd_port, link_info);
1044		break;
1045	case CVMX_HELPER_INTERFACE_MODE_SPI:
1046		result = __cvmx_helper_spi_link_set(ipd_port, link_info);
1047		break;
1048	case CVMX_HELPER_INTERFACE_MODE_SGMII:
1049	case CVMX_HELPER_INTERFACE_MODE_PICMG:
1050		result = __cvmx_helper_sgmii_link_set(ipd_port, link_info);
1051		break;
1052	case CVMX_HELPER_INTERFACE_MODE_NPI:
1053	case CVMX_HELPER_INTERFACE_MODE_LOOP:
1054		break;
1055	}
1056	/* Set the port_link_info here so that the link status is updated
1057	   no matter how cvmx_helper_link_set is called. We don't change
1058	   the value if link_set failed */
1059	if (result == 0)
1060		port_link_info[ipd_port].u64 = link_info.u64;
1061	return result;
1062}
1063
1064/**
1065 * Configure a port for internal and/or external loopback. Internal loopback
1066 * causes packets sent by the port to be received by Octeon. External loopback
1067 * causes packets received from the wire to sent out again.
1068 *
1069 * @ipd_port: IPD/PKO port to loopback.
1070 * @enable_internal:
1071 *                 Non zero if you want internal loopback
1072 * @enable_external:
1073 *                 Non zero if you want external loopback
1074 *
1075 * Returns Zero on success, negative on failure.
1076 */
1077int cvmx_helper_configure_loopback(int ipd_port, int enable_internal,
1078				   int enable_external)
1079{
1080	int result = -1;
1081	int interface = cvmx_helper_get_interface_num(ipd_port);
1082	int index = cvmx_helper_get_interface_index_num(ipd_port);
1083
1084	if (index >= cvmx_helper_ports_on_interface(interface))
1085		return -1;
1086
1087	switch (cvmx_helper_interface_get_mode(interface)) {
1088	case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1089	case CVMX_HELPER_INTERFACE_MODE_PCIE:
1090	case CVMX_HELPER_INTERFACE_MODE_SPI:
1091	case CVMX_HELPER_INTERFACE_MODE_NPI:
1092	case CVMX_HELPER_INTERFACE_MODE_LOOP:
1093		break;
1094	case CVMX_HELPER_INTERFACE_MODE_XAUI:
1095		result =
1096		    __cvmx_helper_xaui_configure_loopback(ipd_port,
1097							  enable_internal,
1098							  enable_external);
1099		break;
1100	case CVMX_HELPER_INTERFACE_MODE_RGMII:
1101	case CVMX_HELPER_INTERFACE_MODE_GMII:
1102		result =
1103		    __cvmx_helper_rgmii_configure_loopback(ipd_port,
1104							   enable_internal,
1105							   enable_external);
1106		break;
1107	case CVMX_HELPER_INTERFACE_MODE_SGMII:
1108	case CVMX_HELPER_INTERFACE_MODE_PICMG:
1109		result =
1110		    __cvmx_helper_sgmii_configure_loopback(ipd_port,
1111							   enable_internal,
1112							   enable_external);
1113		break;
1114	}
1115	return result;
1116}
1117