1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2018-2022 Marvell International Ltd.
4  *
5  * IPD helper functions.
6  */
7 
8 #include <errno.h>
9 #include <log.h>
10 #include <time.h>
11 #include <linux/delay.h>
12 
13 #include <mach/cvmx-regs.h>
14 #include <mach/cvmx-csr.h>
15 #include <mach/cvmx-bootmem.h>
16 #include <mach/octeon-model.h>
17 #include <mach/cvmx-fuse.h>
18 #include <mach/octeon-feature.h>
19 #include <mach/cvmx-qlm.h>
20 #include <mach/octeon_qlm.h>
21 #include <mach/cvmx-pcie.h>
22 #include <mach/cvmx-coremask.h>
23 #include <mach/cvmx-range.h>
24 #include <mach/cvmx-global-resources.h>
25 
26 #include <mach/cvmx-agl-defs.h>
27 #include <mach/cvmx-bgxx-defs.h>
28 #include <mach/cvmx-ciu-defs.h>
29 #include <mach/cvmx-gmxx-defs.h>
30 #include <mach/cvmx-gserx-defs.h>
31 #include <mach/cvmx-ilk-defs.h>
32 #include <mach/cvmx-ipd-defs.h>
33 #include <mach/cvmx-pcsx-defs.h>
34 #include <mach/cvmx-pcsxx-defs.h>
35 #include <mach/cvmx-pki-defs.h>
36 #include <mach/cvmx-pko-defs.h>
37 #include <mach/cvmx-xcv-defs.h>
38 
39 #include <mach/cvmx-hwpko.h>
40 #include <mach/cvmx-ilk.h>
41 #include <mach/cvmx-ipd.h>
42 #include <mach/cvmx-pki.h>
43 #include <mach/cvmx-pko3.h>
44 #include <mach/cvmx-pko3-queue.h>
45 #include <mach/cvmx-pko3-resources.h>
46 #include <mach/cvmx-pip.h>
47 
48 #include <mach/cvmx-helper.h>
49 #include <mach/cvmx-helper-board.h>
50 #include <mach/cvmx-helper-cfg.h>
51 
52 #include <mach/cvmx-helper-bgx.h>
53 #include <mach/cvmx-helper-cfg.h>
54 #include <mach/cvmx-helper-util.h>
55 #include <mach/cvmx-helper-pki.h>
56 
57 /** It allocate pools for packet and wqe pools
58  * and sets up the FPA hardware
59  */
__cvmx_helper_ipd_setup_fpa_pools(void)60 int __cvmx_helper_ipd_setup_fpa_pools(void)
61 {
62 	cvmx_fpa_global_initialize();
63 	if (cvmx_ipd_cfg.packet_pool.buffer_count == 0)
64 		return 0;
65 	__cvmx_helper_initialize_fpa_pool(cvmx_ipd_cfg.packet_pool.pool_num,
66 					  cvmx_ipd_cfg.packet_pool.buffer_size,
67 					  cvmx_ipd_cfg.packet_pool.buffer_count,
68 					  "Packet Buffers");
69 	if (cvmx_ipd_cfg.wqe_pool.buffer_count == 0)
70 		return 0;
71 	__cvmx_helper_initialize_fpa_pool(cvmx_ipd_cfg.wqe_pool.pool_num,
72 					  cvmx_ipd_cfg.wqe_pool.buffer_size,
73 					  cvmx_ipd_cfg.wqe_pool.buffer_count,
74 					  "WQE Buffers");
75 	return 0;
76 }
77 
78 /**
79  * @INTERNAL
80  * Setup global setting for IPD/PIP not related to a specific
81  * interface or port. This must be called before IPD is enabled.
82  *
83  * @return Zero on success, negative on failure.
84  */
__cvmx_helper_ipd_global_setup(void)85 int __cvmx_helper_ipd_global_setup(void)
86 {
87 	/* Setup the packet and wqe pools*/
88 	__cvmx_helper_ipd_setup_fpa_pools();
89 	/* Setup the global packet input options */
90 	cvmx_ipd_config(cvmx_ipd_cfg.packet_pool.buffer_size / 8,
91 			cvmx_ipd_cfg.first_mbuf_skip / 8,
92 			cvmx_ipd_cfg.not_first_mbuf_skip / 8,
93 			/* The +8 is to account for the next ptr */
94 			(cvmx_ipd_cfg.first_mbuf_skip + 8) / 128,
95 			/* The +8 is to account for the next ptr */
96 			(cvmx_ipd_cfg.not_first_mbuf_skip + 8) / 128,
97 			cvmx_ipd_cfg.wqe_pool.pool_num,
98 			(cvmx_ipd_mode_t)(cvmx_ipd_cfg.cache_mode), 1);
99 	return 0;
100 }
101 
102 /**
103  * Enable or disable FCS stripping for all the ports on an interface.
104  *
105  * @param xiface
106  * @param nports number of ports
107  * @param has_fcs 0 for disable and !0 for enable
108  */
cvmx_helper_fcs_op(int xiface,int nports,int has_fcs)109 static int cvmx_helper_fcs_op(int xiface, int nports, int has_fcs)
110 {
111 	u64 port_bit;
112 	int index;
113 	int pknd;
114 	union cvmx_pip_sub_pkind_fcsx pkind_fcsx;
115 	union cvmx_pip_prt_cfgx port_cfg;
116 	struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
117 
118 	if (!octeon_has_feature(OCTEON_FEATURE_PKND))
119 		return 0;
120 	if (octeon_has_feature(OCTEON_FEATURE_PKI)) {
121 		cvmx_helper_pki_set_fcs_op(xi.node, xi.interface, nports,
122 					   has_fcs);
123 		return 0;
124 	}
125 
126 	port_bit = 0;
127 	for (index = 0; index < nports; index++)
128 		port_bit |= ((u64)1 << cvmx_helper_get_pknd(xiface, index));
129 
130 	pkind_fcsx.u64 = csr_rd(CVMX_PIP_SUB_PKIND_FCSX(0));
131 	if (has_fcs)
132 		pkind_fcsx.s.port_bit |= port_bit;
133 	else
134 		pkind_fcsx.s.port_bit &= ~port_bit;
135 	csr_wr(CVMX_PIP_SUB_PKIND_FCSX(0), pkind_fcsx.u64);
136 
137 	for (pknd = 0; pknd < 64; pknd++) {
138 		if ((1ull << pknd) & port_bit) {
139 			port_cfg.u64 = csr_rd(CVMX_PIP_PRT_CFGX(pknd));
140 			port_cfg.s.crc_en = (has_fcs) ? 1 : 0;
141 			csr_wr(CVMX_PIP_PRT_CFGX(pknd), port_cfg.u64);
142 		}
143 	}
144 
145 	return 0;
146 }
147 
148 /**
149  * @INTERNAL
150  * Configure the IPD/PIP tagging and QoS options for a specific
151  * port. This function determines the POW work queue entry
152  * contents for a port. The setup performed here is controlled by
153  * the defines in executive-config.h.
154  *
155  * @param ipd_port Port/Port kind to configure. This follows the IPD numbering,
156  *                 not the per interface numbering
157  *
158  * @return Zero on success, negative on failure
159  */
__cvmx_helper_ipd_port_setup(int ipd_port)160 static int __cvmx_helper_ipd_port_setup(int ipd_port)
161 {
162 	union cvmx_pip_prt_cfgx port_config;
163 	union cvmx_pip_prt_tagx tag_config;
164 
165 	if (octeon_has_feature(OCTEON_FEATURE_PKND)) {
166 		int xiface, index, pknd;
167 		union cvmx_pip_prt_cfgbx prt_cfgbx;
168 
169 		xiface = cvmx_helper_get_interface_num(ipd_port);
170 		index = cvmx_helper_get_interface_index_num(ipd_port);
171 		pknd = cvmx_helper_get_pknd(xiface, index);
172 
173 		port_config.u64 = csr_rd(CVMX_PIP_PRT_CFGX(pknd));
174 		tag_config.u64 = csr_rd(CVMX_PIP_PRT_TAGX(pknd));
175 
176 		port_config.s.qos = pknd & 0x7;
177 
178 		/* Default BPID to use for packets on this port-kind */
179 		prt_cfgbx.u64 = csr_rd(CVMX_PIP_PRT_CFGBX(pknd));
180 		prt_cfgbx.s.bpid = pknd;
181 		csr_wr(CVMX_PIP_PRT_CFGBX(pknd), prt_cfgbx.u64);
182 	} else {
183 		port_config.u64 = csr_rd(CVMX_PIP_PRT_CFGX(ipd_port));
184 		tag_config.u64 = csr_rd(CVMX_PIP_PRT_TAGX(ipd_port));
185 
186 		/* Have each port go to a different POW queue */
187 		port_config.s.qos = ipd_port & 0x7;
188 	}
189 
190 	/* Process the headers and place the IP header in the work queue */
191 	port_config.s.mode =
192 		(cvmx_pip_port_parse_mode_t)cvmx_ipd_cfg.port_config.parse_mode;
193 
194 	tag_config.s.ip6_src_flag =
195 		cvmx_ipd_cfg.port_config.tag_fields.ipv6_src_ip;
196 	tag_config.s.ip6_dst_flag =
197 		cvmx_ipd_cfg.port_config.tag_fields.ipv6_dst_ip;
198 	tag_config.s.ip6_sprt_flag =
199 		cvmx_ipd_cfg.port_config.tag_fields.ipv6_src_port;
200 	tag_config.s.ip6_dprt_flag =
201 		cvmx_ipd_cfg.port_config.tag_fields.ipv6_dst_port;
202 	tag_config.s.ip6_nxth_flag =
203 		cvmx_ipd_cfg.port_config.tag_fields.ipv6_next_header;
204 	tag_config.s.ip4_src_flag =
205 		cvmx_ipd_cfg.port_config.tag_fields.ipv4_src_ip;
206 	tag_config.s.ip4_dst_flag =
207 		cvmx_ipd_cfg.port_config.tag_fields.ipv4_dst_ip;
208 	tag_config.s.ip4_sprt_flag =
209 		cvmx_ipd_cfg.port_config.tag_fields.ipv4_src_port;
210 	tag_config.s.ip4_dprt_flag =
211 		cvmx_ipd_cfg.port_config.tag_fields.ipv4_dst_port;
212 	tag_config.s.ip4_pctl_flag =
213 		cvmx_ipd_cfg.port_config.tag_fields.ipv4_protocol;
214 	tag_config.s.inc_prt_flag =
215 		cvmx_ipd_cfg.port_config.tag_fields.input_port;
216 	tag_config.s.tcp6_tag_type =
217 		(cvmx_pow_tag_type_t)cvmx_ipd_cfg.port_config.tag_type;
218 	tag_config.s.tcp4_tag_type =
219 		(cvmx_pow_tag_type_t)cvmx_ipd_cfg.port_config.tag_type;
220 	tag_config.s.ip6_tag_type =
221 		(cvmx_pow_tag_type_t)cvmx_ipd_cfg.port_config.tag_type;
222 	tag_config.s.ip4_tag_type =
223 		(cvmx_pow_tag_type_t)cvmx_ipd_cfg.port_config.tag_type;
224 	tag_config.s.non_tag_type =
225 		(cvmx_pow_tag_type_t)cvmx_ipd_cfg.port_config.tag_type;
226 
227 	/* Put all packets in group 0. Other groups can be used by the app */
228 	tag_config.s.grp = 0;
229 
230 	cvmx_pip_config_port(ipd_port, port_config, tag_config);
231 
232 	/* Give the user a chance to override our setting for each port */
233 	if (cvmx_override_ipd_port_setup)
234 		cvmx_override_ipd_port_setup(ipd_port);
235 
236 	return 0;
237 }
238 
239 /**
240  * @INTERNAL
241  * Setup the IPD/PIP for the ports on an interface. Packet
242  * classification and tagging are set for every port on the
243  * interface. The number of ports on the interface must already
244  * have been probed.
245  *
246  * @param xiface to setup IPD/PIP for
247  *
248  * @return Zero on success, negative on failure
249  */
__cvmx_helper_ipd_setup_interface(int xiface)250 int __cvmx_helper_ipd_setup_interface(int xiface)
251 {
252 	cvmx_helper_interface_mode_t mode;
253 	int num_ports = cvmx_helper_ports_on_interface(xiface);
254 	struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
255 	int ipd_port = cvmx_helper_get_ipd_port(xiface, 0);
256 	int delta;
257 
258 	if (num_ports == CVMX_HELPER_CFG_INVALID_VALUE)
259 		return 0;
260 
261 	delta = 1;
262 	if (octeon_has_feature(OCTEON_FEATURE_PKND)) {
263 		if (xi.interface < CVMX_HELPER_MAX_GMX)
264 			delta = 16;
265 	}
266 
267 	while (num_ports--) {
268 		if (!cvmx_helper_is_port_valid(xiface, num_ports))
269 			continue;
270 		if (octeon_has_feature(OCTEON_FEATURE_PKI))
271 			__cvmx_helper_pki_port_setup(xi.node, ipd_port);
272 		else
273 			__cvmx_helper_ipd_port_setup(ipd_port);
274 		ipd_port += delta;
275 	}
276 	/* FCS settings */
277 	cvmx_helper_fcs_op(xiface, cvmx_helper_ports_on_interface(xiface),
278 			   __cvmx_helper_get_has_fcs(xiface));
279 
280 	mode = cvmx_helper_interface_get_mode(xiface);
281 
282 	if (mode == CVMX_HELPER_INTERFACE_MODE_LOOP)
283 		__cvmx_helper_loop_enable(xiface);
284 
285 	return 0;
286 }
287