~funderscore blog cgit wiki get in touch
aboutsummaryrefslogtreecommitdiff
blob: 8eaeac387df4abe8888fe815d1c79802a44fd14e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2018-2022 Marvell International Ltd.
 *
 * Functions for LOOP initialization, configuration,
 * and monitoring.
 */

#include <log.h>
#include <malloc.h>
#include <net.h>
#include <linux/delay.h>

#include <mach/cvmx-regs.h>
#include <mach/cvmx-csr.h>
#include <mach/cvmx-bootmem.h>
#include <mach/octeon-model.h>
#include <mach/octeon_fdt.h>
#include <mach/cvmx-helper.h>
#include <mach/cvmx-helper-board.h>
#include <mach/cvmx-helper-cfg.h>
#include <mach/cvmx-helper-fdt.h>
#include <mach/cvmx-helper-gpio.h>

#include <mach/cvmx-agl-defs.h>
#include <mach/cvmx-bgxx-defs.h>
#include <mach/cvmx-ciu-defs.h>
#include <mach/cvmx-gmxx-defs.h>
#include <mach/cvmx-gserx-defs.h>
#include <mach/cvmx-ilk-defs.h>
#include <mach/cvmx-ipd-defs.h>
#include <mach/cvmx-lbk-defs.h>
#include <mach/cvmx-pcsx-defs.h>
#include <mach/cvmx-pcsxx-defs.h>
#include <mach/cvmx-pki-defs.h>
#include <mach/cvmx-pko-defs.h>
#include <mach/cvmx-xcv-defs.h>

#include <mach/cvmx-hwpko.h>
#include <mach/cvmx-ilk.h>
#include <mach/cvmx-pki.h>

int __cvmx_helper_loop_enumerate(int xiface)
{
	return OCTEON_IS_MODEL(OCTEON_CN68XX) ?
		       8 : (OCTEON_IS_MODEL(OCTEON_CNF71XX) ? 2 : 4);
}

/**
 * @INTERNAL
 * Probe a LOOP interface and determine the number of ports
 * connected to it. The LOOP interface should still be down
 * after this call.
 *
 * @param xiface Interface to probe
 *
 * @return Number of ports on the interface. Zero to disable.
 */
int __cvmx_helper_loop_probe(int xiface)
{
	return __cvmx_helper_loop_enumerate(xiface);
}

/**
 * @INTERNAL
 * Bringup and enable a LOOP interface. After this call packet
 * I/O should be fully functional. This is called with IPD
 * enabled but PKO disabled.
 *
 * @param interface to bring up
 *
 * @return Zero on success, negative on failure
 */
int __cvmx_helper_loop_enable(int xiface)
{
	cvmx_pip_prt_cfgx_t port_cfg;
	int num_ports, index;
	unsigned long offset;
	struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);

	num_ports = __cvmx_helper_get_num_ipd_ports(xiface);
	/*
	 * We need to disable length checking so packet < 64 bytes and jumbo
	 * frames don't get errors
	 */
	for (index = 0; index < num_ports; index++) {
		offset = ((octeon_has_feature(OCTEON_FEATURE_PKND)) ?
				  cvmx_helper_get_pknd(xiface, index) :
					cvmx_helper_get_ipd_port(xiface, index));

		if (octeon_has_feature(OCTEON_FEATURE_PKI)) {
			cvmx_pki_endis_l2_errs(xi.node, offset, 1, 0, 0);
			cvmx_pki_endis_fcs_check(xi.node, offset, 0, 0);
		} else {
			port_cfg.u64 = csr_rd(CVMX_PIP_PRT_CFGX(offset));
			port_cfg.s.maxerr_en = 0;
			port_cfg.s.minerr_en = 0;
			csr_wr(CVMX_PIP_PRT_CFGX(offset), port_cfg.u64);
		}
	}

	/*
	 * Disable FCS stripping for loopback ports
	 */
	if (!octeon_has_feature(OCTEON_FEATURE_PKND)) {
		cvmx_ipd_sub_port_fcs_t ipd_sub_port_fcs;

		ipd_sub_port_fcs.u64 = csr_rd(CVMX_IPD_SUB_PORT_FCS);
		ipd_sub_port_fcs.s.port_bit2 = 0;
		csr_wr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
	}
	/*
	 * Set PKND and BPID for loopback ports.
	 */
	if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
		cvmx_pko_reg_loopback_pkind_t lp_pknd;
		cvmx_pko_reg_loopback_bpid_t lp_bpid;

		for (index = 0; index < num_ports; index++) {
			int pknd = cvmx_helper_get_pknd(xiface, index);
			int bpid = cvmx_helper_get_bpid(xiface, index);

			lp_pknd.u64 = csr_rd(CVMX_PKO_REG_LOOPBACK_PKIND);
			lp_bpid.u64 = csr_rd(CVMX_PKO_REG_LOOPBACK_BPID);

			if (index == 0)
				lp_pknd.s.num_ports = num_ports;

			switch (index) {
			case 0:
				lp_pknd.s.pkind0 = pknd;
				lp_bpid.s.bpid0 = bpid;
				break;
			case 1:
				lp_pknd.s.pkind1 = pknd;
				lp_bpid.s.bpid1 = bpid;
				break;
			case 2:
				lp_pknd.s.pkind2 = pknd;
				lp_bpid.s.bpid2 = bpid;
				break;
			case 3:
				lp_pknd.s.pkind3 = pknd;
				lp_bpid.s.bpid3 = bpid;
				break;
			case 4:
				lp_pknd.s.pkind4 = pknd;
				lp_bpid.s.bpid4 = bpid;
				break;
			case 5:
				lp_pknd.s.pkind5 = pknd;
				lp_bpid.s.bpid5 = bpid;
				break;
			case 6:
				lp_pknd.s.pkind6 = pknd;
				lp_bpid.s.bpid6 = bpid;
				break;
			case 7:
				lp_pknd.s.pkind7 = pknd;
				lp_bpid.s.bpid7 = bpid;
				break;
			}
			csr_wr(CVMX_PKO_REG_LOOPBACK_PKIND, lp_pknd.u64);
			csr_wr(CVMX_PKO_REG_LOOPBACK_BPID, lp_bpid.u64);
		}
	} else if (octeon_has_feature(OCTEON_FEATURE_BGX)) {
		cvmx_lbk_chx_pkind_t lbk_pkind;

		for (index = 0; index < num_ports; index++) {
			lbk_pkind.u64 = 0;
			lbk_pkind.s.pkind = cvmx_helper_get_pknd(xiface, index);
			csr_wr_node(xi.node, CVMX_LBK_CHX_PKIND(index),
				    lbk_pkind.u64);
		}
	}

	return 0;
}