1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2020 Marvell International Ltd.
4  *
5  * Small helper utilities.
6  */
7 
8 #include <log.h>
9 #include <time.h>
10 #include <linux/delay.h>
11 
12 #include <mach/cvmx-regs.h>
13 #include <mach/cvmx-csr-enums.h>
14 #include <mach/octeon-model.h>
15 #include <mach/octeon-feature.h>
16 #include <mach/cvmx-gmxx-defs.h>
17 #include <mach/cvmx-ipd-defs.h>
18 #include <mach/cvmx-pko-defs.h>
19 #include <mach/cvmx-ipd.h>
20 #include <mach/cvmx-hwpko.h>
21 #include <mach/cvmx-pki.h>
22 #include <mach/cvmx-pip.h>
23 #include <mach/cvmx-helper.h>
24 #include <mach/cvmx-helper-util.h>
25 #include <mach/cvmx-helper-pki.h>
26 
27 /**
28  * @INTERNAL
29  * These are the interface types needed to convert interface numbers to ipd
30  * ports.
31  *
32  * @param GMII
33  *	This type is used for sgmii, rgmii, xaui and rxaui interfaces.
34  * @param ILK
35  *	This type is used for ilk interfaces.
36  * @param SRIO
37  *	This type is used for serial-RapidIo interfaces.
38  * @param NPI
39  *	This type is used for npi interfaces.
40  * @param LB
41  *	This type is used for loopback interfaces.
42  * @param INVALID_IF_TYPE
43  *	This type indicates the interface hasn't been configured.
44  */
45 enum port_map_if_type { INVALID_IF_TYPE = 0, GMII, ILK, SRIO, NPI, LB };
46 
47 /**
48  * @INTERNAL
49  * This structure is used to map interface numbers to ipd ports.
50  *
51  * @param type
52  *	Interface type
53  * @param first_ipd_port
54  *	First IPD port number assigned to this interface.
55  * @param last_ipd_port
56  *	Last IPD port number assigned to this interface.
57  * @param ipd_port_adj
58  *	Different octeon chips require different ipd ports for the
59  *	same interface port/mode configuration. This value is used
60  *	to account for that difference.
61  */
62 struct ipd_port_map {
63 	enum port_map_if_type type;
64 	int first_ipd_port;
65 	int last_ipd_port;
66 	int ipd_port_adj;
67 };
68 
69 /**
70  * @INTERNAL
71  * Interface number to ipd port map for the octeon 68xx.
72  */
73 static const struct ipd_port_map ipd_port_map_68xx[CVMX_HELPER_MAX_IFACE] = {
74 	{ GMII, 0x800, 0x8ff, 0x40 }, /* Interface 0 */
75 	{ GMII, 0x900, 0x9ff, 0x40 }, /* Interface 1 */
76 	{ GMII, 0xa00, 0xaff, 0x40 }, /* Interface 2 */
77 	{ GMII, 0xb00, 0xbff, 0x40 }, /* Interface 3 */
78 	{ GMII, 0xc00, 0xcff, 0x40 }, /* Interface 4 */
79 	{ ILK, 0x400, 0x4ff, 0x00 },  /* Interface 5 */
80 	{ ILK, 0x500, 0x5ff, 0x00 },  /* Interface 6 */
81 	{ NPI, 0x100, 0x120, 0x00 },  /* Interface 7 */
82 	{ LB, 0x000, 0x008, 0x00 },   /* Interface 8 */
83 };
84 
85 /**
86  * @INTERNAL
87  * Interface number to ipd port map for the octeon 78xx.
88  *
89  * This mapping corresponds to WQE(CHAN) enumeration in
90  * HRM Sections 11.15, PKI_CHAN_E, Section 11.6
91  *
92  */
93 static const struct ipd_port_map ipd_port_map_78xx[CVMX_HELPER_MAX_IFACE] = {
94 	{ GMII, 0x800, 0x83f, 0x00 }, /* Interface 0 - BGX0 */
95 	{ GMII, 0x900, 0x93f, 0x00 }, /* Interface 1  -BGX1 */
96 	{ GMII, 0xa00, 0xa3f, 0x00 }, /* Interface 2  -BGX2 */
97 	{ GMII, 0xb00, 0xb3f, 0x00 }, /* Interface 3 - BGX3 */
98 	{ GMII, 0xc00, 0xc3f, 0x00 }, /* Interface 4 - BGX4 */
99 	{ GMII, 0xd00, 0xd3f, 0x00 }, /* Interface 5 - BGX5 */
100 	{ ILK, 0x400, 0x4ff, 0x00 },  /* Interface 6 - ILK0 */
101 	{ ILK, 0x500, 0x5ff, 0x00 },  /* Interface 7 - ILK1 */
102 	{ NPI, 0x100, 0x13f, 0x00 },  /* Interface 8 - DPI */
103 	{ LB, 0x000, 0x03f, 0x00 },   /* Interface 9 - LOOPBACK */
104 };
105 
106 /**
107  * @INTERNAL
108  * Interface number to ipd port map for the octeon 73xx.
109  */
110 static const struct ipd_port_map ipd_port_map_73xx[CVMX_HELPER_MAX_IFACE] = {
111 	{ GMII, 0x800, 0x83f, 0x00 }, /* Interface 0 - BGX(0,0-3) */
112 	{ GMII, 0x900, 0x93f, 0x00 }, /* Interface 1  -BGX(1,0-3) */
113 	{ GMII, 0xa00, 0xa3f, 0x00 }, /* Interface 2  -BGX(2,0-3) */
114 	{ NPI, 0x100, 0x17f, 0x00 },  /* Interface 3 - DPI */
115 	{ LB, 0x000, 0x03f, 0x00 },   /* Interface 4 - LOOPBACK */
116 };
117 
118 /**
119  * @INTERNAL
120  * Interface number to ipd port map for the octeon 75xx.
121  */
122 static const struct ipd_port_map ipd_port_map_75xx[CVMX_HELPER_MAX_IFACE] = {
123 	{ GMII, 0x800, 0x83f, 0x00 }, /* Interface 0 - BGX0 */
124 	{ SRIO, 0x240, 0x241, 0x00 }, /* Interface 1 - SRIO 0 */
125 	{ SRIO, 0x242, 0x243, 0x00 }, /* Interface 2 - SRIO 1 */
126 	{ NPI, 0x100, 0x13f, 0x00 },  /* Interface 3 - DPI */
127 	{ LB, 0x000, 0x03f, 0x00 },   /* Interface 4 - LOOPBACK */
128 };
129 
130 /**
131  * Convert a interface mode into a human readable string
132  *
133  * @param mode   Mode to convert
134  *
135  * @return String
136  */
cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t mode)137 const char *cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t mode)
138 {
139 	switch (mode) {
140 	case CVMX_HELPER_INTERFACE_MODE_DISABLED:
141 		return "DISABLED";
142 	case CVMX_HELPER_INTERFACE_MODE_RGMII:
143 		return "RGMII";
144 	case CVMX_HELPER_INTERFACE_MODE_GMII:
145 		return "GMII";
146 	case CVMX_HELPER_INTERFACE_MODE_SPI:
147 		return "SPI";
148 	case CVMX_HELPER_INTERFACE_MODE_PCIE:
149 		return "PCIE";
150 	case CVMX_HELPER_INTERFACE_MODE_XAUI:
151 		return "XAUI";
152 	case CVMX_HELPER_INTERFACE_MODE_RXAUI:
153 		return "RXAUI";
154 	case CVMX_HELPER_INTERFACE_MODE_SGMII:
155 		return "SGMII";
156 	case CVMX_HELPER_INTERFACE_MODE_QSGMII:
157 		return "QSGMII";
158 	case CVMX_HELPER_INTERFACE_MODE_PICMG:
159 		return "PICMG";
160 	case CVMX_HELPER_INTERFACE_MODE_NPI:
161 		return "NPI";
162 	case CVMX_HELPER_INTERFACE_MODE_LOOP:
163 		return "LOOP";
164 	case CVMX_HELPER_INTERFACE_MODE_SRIO:
165 		return "SRIO";
166 	case CVMX_HELPER_INTERFACE_MODE_ILK:
167 		return "ILK";
168 	case CVMX_HELPER_INTERFACE_MODE_AGL:
169 		return "AGL";
170 	case CVMX_HELPER_INTERFACE_MODE_XLAUI:
171 		return "XLAUI";
172 	case CVMX_HELPER_INTERFACE_MODE_XFI:
173 		return "XFI";
174 	case CVMX_HELPER_INTERFACE_MODE_40G_KR4:
175 		return "40G_KR4";
176 	case CVMX_HELPER_INTERFACE_MODE_10G_KR:
177 		return "10G_KR";
178 	case CVMX_HELPER_INTERFACE_MODE_MIXED:
179 		return "MIXED";
180 	}
181 	return "UNKNOWN";
182 }
183 
184 /**
185  * Debug routine to dump the packet structure to the console
186  *
187  * @param work   Work queue entry containing the packet to dump
188  * @return
189  */
cvmx_helper_dump_packet(cvmx_wqe_t * work)190 int cvmx_helper_dump_packet(cvmx_wqe_t *work)
191 {
192 	u64 count;
193 	u64 remaining_bytes;
194 	union cvmx_buf_ptr buffer_ptr;
195 	cvmx_buf_ptr_pki_t bptr;
196 	cvmx_wqe_78xx_t *wqe = (void *)work;
197 	u64 start_of_buffer;
198 	u8 *data_address;
199 	u8 *end_of_data;
200 
201 	if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) {
202 		cvmx_pki_dump_wqe(wqe);
203 		cvmx_wqe_pki_errata_20776(work);
204 	} else {
205 		debug("WORD0 = %lx\n", (unsigned long)work->word0.u64);
206 		debug("WORD1 = %lx\n", (unsigned long)work->word1.u64);
207 		debug("WORD2 = %lx\n", (unsigned long)work->word2.u64);
208 		debug("Packet Length:   %u\n", cvmx_wqe_get_len(work));
209 		debug("    Input Port:  %u\n", cvmx_wqe_get_port(work));
210 		debug("    QoS:         %u\n", cvmx_wqe_get_qos(work));
211 		debug("    Buffers:     %u\n", cvmx_wqe_get_bufs(work));
212 	}
213 
214 	if (cvmx_wqe_get_bufs(work) == 0) {
215 		int wqe_pool;
216 
217 		if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) {
218 			debug("%s: ERROR: Unexpected bufs==0 in WQE\n", __func__);
219 			return -1;
220 		}
221 		wqe_pool = (int)cvmx_fpa_get_wqe_pool();
222 		buffer_ptr.u64 = 0;
223 		buffer_ptr.s.pool = wqe_pool;
224 
225 		buffer_ptr.s.size = 128;
226 		buffer_ptr.s.addr = cvmx_ptr_to_phys(work->packet_data);
227 		if (cvmx_likely(!work->word2.s.not_IP)) {
228 			union cvmx_pip_ip_offset pip_ip_offset;
229 
230 			pip_ip_offset.u64 = csr_rd(CVMX_PIP_IP_OFFSET);
231 			buffer_ptr.s.addr +=
232 				(pip_ip_offset.s.offset << 3) - work->word2.s.ip_offset;
233 			buffer_ptr.s.addr += (work->word2.s.is_v6 ^ 1) << 2;
234 		} else {
235 			/*
236 			 * WARNING: This code assume that the packet
237 			 * is not RAW. If it was, we would use
238 			 * PIP_GBL_CFG[RAW_SHF] instead of
239 			 * PIP_GBL_CFG[NIP_SHF].
240 			 */
241 			union cvmx_pip_gbl_cfg pip_gbl_cfg;
242 
243 			pip_gbl_cfg.u64 = csr_rd(CVMX_PIP_GBL_CFG);
244 			buffer_ptr.s.addr += pip_gbl_cfg.s.nip_shf;
245 		}
246 	} else {
247 		buffer_ptr = work->packet_ptr;
248 	}
249 
250 	remaining_bytes = cvmx_wqe_get_len(work);
251 
252 	while (remaining_bytes) {
253 		/* native cn78xx buffer format, unless legacy-translated */
254 		if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE) && !wqe->pki_wqe_translated) {
255 			bptr.u64 = buffer_ptr.u64;
256 			/* XXX- assumes cache-line aligned buffer */
257 			start_of_buffer = (bptr.addr >> 7) << 7;
258 			debug("    Buffer Start:%llx\n", (unsigned long long)start_of_buffer);
259 			debug("    Buffer Data: %llx\n", (unsigned long long)bptr.addr);
260 			debug("    Buffer Size: %u\n", bptr.size);
261 			data_address = (uint8_t *)cvmx_phys_to_ptr(bptr.addr);
262 			end_of_data = data_address + bptr.size;
263 		} else {
264 			start_of_buffer = ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7;
265 			debug("    Buffer Start:%llx\n", (unsigned long long)start_of_buffer);
266 			debug("    Buffer I   : %u\n", buffer_ptr.s.i);
267 			debug("    Buffer Back: %u\n", buffer_ptr.s.back);
268 			debug("    Buffer Pool: %u\n", buffer_ptr.s.pool);
269 			debug("    Buffer Data: %llx\n", (unsigned long long)buffer_ptr.s.addr);
270 			debug("    Buffer Size: %u\n", buffer_ptr.s.size);
271 			data_address = (uint8_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr);
272 			end_of_data = data_address + buffer_ptr.s.size;
273 		}
274 
275 		debug("\t\t");
276 		count = 0;
277 		while (data_address < end_of_data) {
278 			if (remaining_bytes == 0)
279 				break;
280 
281 			remaining_bytes--;
282 			debug("%02x", (unsigned int)*data_address);
283 			data_address++;
284 			if (remaining_bytes && count == 7) {
285 				debug("\n\t\t");
286 				count = 0;
287 			} else {
288 				count++;
289 			}
290 		}
291 		debug("\n");
292 
293 		if (remaining_bytes) {
294 			if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE) &&
295 			    !wqe->pki_wqe_translated)
296 				buffer_ptr.u64 = *(uint64_t *)cvmx_phys_to_ptr(bptr.addr - 8);
297 			else
298 				buffer_ptr.u64 =
299 					*(uint64_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr - 8);
300 		}
301 	}
302 	return 0;
303 }
304 
305 /**
306  * @INTERNAL
307  *
308  * Extract NO_WPTR mode from PIP/IPD register
309  */
__cvmx_ipd_mode_no_wptr(void)310 static int __cvmx_ipd_mode_no_wptr(void)
311 {
312 	if (octeon_has_feature(OCTEON_FEATURE_NO_WPTR)) {
313 		cvmx_ipd_ctl_status_t ipd_ctl_status;
314 
315 		ipd_ctl_status.u64 = csr_rd(CVMX_IPD_CTL_STATUS);
316 		return ipd_ctl_status.s.no_wptr;
317 	}
318 	return 0;
319 }
320 
321 static cvmx_buf_ptr_t __cvmx_packet_short_ptr[4];
322 static int8_t __cvmx_wqe_pool = -1;
323 
324 /**
325  * @INTERNAL
326  * Prepare packet pointer templace for dynamic short
327  * packets.
328  */
cvmx_packet_short_ptr_calculate(void)329 static void cvmx_packet_short_ptr_calculate(void)
330 {
331 	unsigned int i, off;
332 	union cvmx_pip_gbl_cfg pip_gbl_cfg;
333 	union cvmx_pip_ip_offset pip_ip_offset;
334 
335 	/* Fill in the common values for all cases */
336 	for (i = 0; i < 4; i++) {
337 		if (__cvmx_ipd_mode_no_wptr())
338 			/* packet pool, set to 0 in hardware */
339 			__cvmx_wqe_pool = 0;
340 		else
341 			/* WQE pool as configured */
342 			__cvmx_wqe_pool = csr_rd(CVMX_IPD_WQE_FPA_QUEUE) & 7;
343 
344 		__cvmx_packet_short_ptr[i].s.pool = __cvmx_wqe_pool;
345 		__cvmx_packet_short_ptr[i].s.size = cvmx_fpa_get_block_size(__cvmx_wqe_pool);
346 		__cvmx_packet_short_ptr[i].s.size -= 32;
347 		__cvmx_packet_short_ptr[i].s.addr = 32;
348 	}
349 
350 	pip_gbl_cfg.u64 = csr_rd(CVMX_PIP_GBL_CFG);
351 	pip_ip_offset.u64 = csr_rd(CVMX_PIP_IP_OFFSET);
352 
353 	/* RAW_FULL: index = 0 */
354 	i = 0;
355 	off = pip_gbl_cfg.s.raw_shf;
356 	__cvmx_packet_short_ptr[i].s.addr += off;
357 	__cvmx_packet_short_ptr[i].s.size -= off;
358 	__cvmx_packet_short_ptr[i].s.back += off >> 7;
359 
360 	/* NON-IP: index = 1 */
361 	i = 1;
362 	off = pip_gbl_cfg.s.nip_shf;
363 	__cvmx_packet_short_ptr[i].s.addr += off;
364 	__cvmx_packet_short_ptr[i].s.size -= off;
365 	__cvmx_packet_short_ptr[i].s.back += off >> 7;
366 
367 	/* IPv4: index = 2 */
368 	i = 2;
369 	off = (pip_ip_offset.s.offset << 3) + 4;
370 	__cvmx_packet_short_ptr[i].s.addr += off;
371 	__cvmx_packet_short_ptr[i].s.size -= off;
372 	__cvmx_packet_short_ptr[i].s.back += off >> 7;
373 
374 	/* IPv6: index = 3 */
375 	i = 3;
376 	off = (pip_ip_offset.s.offset << 3) + 0;
377 	__cvmx_packet_short_ptr[i].s.addr += off;
378 	__cvmx_packet_short_ptr[i].s.size -= off;
379 	__cvmx_packet_short_ptr[i].s.back += off >> 7;
380 
381 	/* For IPv4/IPv6: subtract work->word2.s.ip_offset
382 	 * to addr, if it is smaller than IP_OFFSET[OFFSET]*8
383 	 * which is stored in __cvmx_packet_short_ptr[3].s.addr
384 	 */
385 }
386 
387 /**
388  * Extract packet data buffer pointer from work queue entry.
389  *
390  * Returns the legacy (Octeon1/Octeon2) buffer pointer structure
391  * for the linked buffer list.
392  * On CN78XX, the native buffer pointer structure is converted into
393  * the legacy format.
394  * The legacy buf_ptr is then stored in the WQE, and word0 reserved
395  * field is set to indicate that the buffer pointers were translated.
396  * If the packet data is only found inside the work queue entry,
397  * a standard buffer pointer structure is created for it.
398  */
cvmx_wqe_get_packet_ptr(cvmx_wqe_t * work)399 cvmx_buf_ptr_t cvmx_wqe_get_packet_ptr(cvmx_wqe_t *work)
400 {
401 	if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) {
402 		cvmx_wqe_78xx_t *wqe = (void *)work;
403 		cvmx_buf_ptr_t optr, lptr;
404 		cvmx_buf_ptr_pki_t nptr;
405 		unsigned int pool, bufs;
406 		int node = cvmx_get_node_num();
407 
408 		/* In case of repeated calls of this function */
409 		if (wqe->pki_wqe_translated || wqe->word2.software) {
410 			optr.u64 = wqe->packet_ptr.u64;
411 			return optr;
412 		}
413 
414 		bufs = wqe->word0.bufs;
415 		pool = wqe->word0.aura;
416 		nptr.u64 = wqe->packet_ptr.u64;
417 
418 		optr.u64 = 0;
419 		optr.s.pool = pool;
420 		optr.s.addr = nptr.addr;
421 		if (bufs == 1) {
422 			optr.s.size = pki_dflt_pool[node].buffer_size -
423 				      pki_dflt_style[node].parm_cfg.first_skip - 8 -
424 				      wqe->word0.apad;
425 		} else {
426 			optr.s.size = nptr.size;
427 		}
428 
429 		/* Calculate the "back" offset */
430 		if (!nptr.packet_outside_wqe) {
431 			optr.s.back = (nptr.addr -
432 				       cvmx_ptr_to_phys(wqe)) >> 7;
433 		} else {
434 			optr.s.back =
435 				(pki_dflt_style[node].parm_cfg.first_skip +
436 				 8 + wqe->word0.apad) >> 7;
437 		}
438 		lptr = optr;
439 
440 		/* Follow pointer and convert all linked pointers */
441 		while (bufs > 1) {
442 			void *vptr;
443 
444 			vptr = cvmx_phys_to_ptr(lptr.s.addr);
445 
446 			memcpy(&nptr, vptr - 8, 8);
447 			/*
448 			 * Errata (PKI-20776) PKI_BUFLINK_S's are endian-swapped
449 			 * CN78XX pass 1.x has a bug where the packet pointer
450 			 * in each segment is written in the opposite
451 			 * endianness of the configured mode. Fix these here
452 			 */
453 			if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X))
454 				nptr.u64 = __builtin_bswap64(nptr.u64);
455 			lptr.u64 = 0;
456 			lptr.s.pool = pool;
457 			lptr.s.addr = nptr.addr;
458 			lptr.s.size = nptr.size;
459 			lptr.s.back = (pki_dflt_style[0].parm_cfg.later_skip + 8) >>
460 				      7; /* TBD: not guaranteed !! */
461 
462 			memcpy(vptr - 8, &lptr, 8);
463 			bufs--;
464 		}
465 		/* Store translated bufptr in WQE, and set indicator */
466 		wqe->pki_wqe_translated = 1;
467 		wqe->packet_ptr.u64 = optr.u64;
468 		return optr;
469 
470 	} else {
471 		unsigned int i;
472 		unsigned int off = 0;
473 		cvmx_buf_ptr_t bptr;
474 
475 		if (cvmx_likely(work->word2.s.bufs > 0))
476 			return work->packet_ptr;
477 
478 		if (cvmx_unlikely(work->word2.s.software))
479 			return work->packet_ptr;
480 
481 		/* first packet, precalculate packet_ptr templaces */
482 		if (cvmx_unlikely(__cvmx_packet_short_ptr[0].u64 == 0))
483 			cvmx_packet_short_ptr_calculate();
484 
485 		/* calculate templace index */
486 		i = work->word2.s_cn38xx.not_IP | work->word2.s_cn38xx.rcv_error;
487 		i = 2 ^ (i << 1);
488 
489 		/* IPv4/IPv6: Adjust IP offset */
490 		if (cvmx_likely(i & 2)) {
491 			i |= work->word2.s.is_v6;
492 			off = work->word2.s.ip_offset;
493 		} else {
494 			/* RAWFULL/RAWSCHED should be handled here */
495 			i = 1; /* not-IP */
496 			off = 0;
497 		}
498 
499 		/* Get the right templace */
500 		bptr = __cvmx_packet_short_ptr[i];
501 		bptr.s.addr -= off;
502 		bptr.s.back = bptr.s.addr >> 7;
503 
504 		/* Add actual WQE paddr to the templace offset */
505 		bptr.s.addr += cvmx_ptr_to_phys(work);
506 
507 		/* Adjust word2.bufs so that _free_data() handles it
508 		 * in the same way as PKO
509 		 */
510 		work->word2.s.bufs = 1;
511 
512 		/* Store the new buffer pointer back into WQE */
513 		work->packet_ptr = bptr;
514 
515 		/* Returned the synthetic buffer_pointer */
516 		return bptr;
517 	}
518 }
519 
cvmx_wqe_free(cvmx_wqe_t * work)520 void cvmx_wqe_free(cvmx_wqe_t *work)
521 {
522 	unsigned int bufs, ncl = 1;
523 	u64 paddr, paddr1;
524 
525 	if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) {
526 		cvmx_wqe_78xx_t *wqe = (void *)work;
527 		cvmx_fpa3_gaura_t aura;
528 		cvmx_buf_ptr_pki_t bptr;
529 
530 		bufs = wqe->word0.bufs;
531 
532 		if (!wqe->pki_wqe_translated && bufs != 0) {
533 			/* Handle cn78xx native untralsated WQE */
534 
535 			bptr = wqe->packet_ptr;
536 
537 			/* Do nothing - first packet buffer shares WQE buffer */
538 			if (!bptr.packet_outside_wqe)
539 				return;
540 		} else if (cvmx_likely(bufs != 0)) {
541 			/* Handle translated 78XX WQE */
542 			paddr = (work->packet_ptr.s.addr & (~0x7full)) -
543 				(work->packet_ptr.s.back << 7);
544 			paddr1 = cvmx_ptr_to_phys(work);
545 
546 			/* do not free WQE if contains first data buffer */
547 			if (paddr == paddr1)
548 				return;
549 		}
550 
551 		/* WQE is separate from packet buffer, free it */
552 		aura = __cvmx_fpa3_gaura(wqe->word0.aura >> 10, wqe->word0.aura & 0x3ff);
553 
554 		cvmx_fpa3_free(work, aura, ncl);
555 	} else {
556 		/* handle legacy WQE */
557 		bufs = work->word2.s_cn38xx.bufs;
558 
559 		if (cvmx_likely(bufs != 0)) {
560 			/* Check if the first data buffer is inside WQE */
561 			paddr = (work->packet_ptr.s.addr & (~0x7full)) -
562 				(work->packet_ptr.s.back << 7);
563 			paddr1 = cvmx_ptr_to_phys(work);
564 
565 			/* do not free WQE if contains first data buffer */
566 			if (paddr == paddr1)
567 				return;
568 		}
569 
570 		/* precalculate packet_ptr, WQE pool number */
571 		if (cvmx_unlikely(__cvmx_wqe_pool < 0))
572 			cvmx_packet_short_ptr_calculate();
573 		cvmx_fpa1_free(work, __cvmx_wqe_pool, ncl);
574 	}
575 }
576 
577 /**
578  * Free the packet buffers contained in a work queue entry.
579  * The work queue entry is also freed if it contains packet data.
580  * If however the packet starts outside the WQE, the WQE will
581  * not be freed. The application should call cvmx_wqe_free()
582  * to free the WQE buffer that contains no packet data.
583  *
584  * @param work   Work queue entry with packet to free
585  */
cvmx_helper_free_packet_data(cvmx_wqe_t * work)586 void cvmx_helper_free_packet_data(cvmx_wqe_t *work)
587 {
588 	u64 number_buffers;
589 	u64 start_of_buffer;
590 	u64 next_buffer_ptr;
591 	cvmx_fpa3_gaura_t aura;
592 	unsigned int ncl;
593 	cvmx_buf_ptr_t buffer_ptr;
594 	cvmx_buf_ptr_pki_t bptr;
595 	cvmx_wqe_78xx_t *wqe = (void *)work;
596 	int o3_pki_wqe = 0;
597 
598 	number_buffers = cvmx_wqe_get_bufs(work);
599 
600 	buffer_ptr.u64 = work->packet_ptr.u64;
601 
602 	/* Zero-out WQE WORD3 so that the WQE is freed by cvmx_wqe_free() */
603 	work->packet_ptr.u64 = 0;
604 
605 	if (number_buffers == 0)
606 		return;
607 
608 	/* Interpret PKI-style bufptr unless it has been translated */
609 	if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE) &&
610 	    !wqe->pki_wqe_translated) {
611 		o3_pki_wqe = 1;
612 		cvmx_wqe_pki_errata_20776(work);
613 		aura = __cvmx_fpa3_gaura(wqe->word0.aura >> 10,
614 					 wqe->word0.aura & 0x3ff);
615 	} else {
616 		start_of_buffer = ((buffer_ptr.s.addr >> 7) -
617 				   buffer_ptr.s.back) << 7;
618 		next_buffer_ptr =
619 			*(uint64_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr - 8);
620 		/*
621 		 * Since the number of buffers is not zero, we know this is not
622 		 * a dynamic short packet. We need to check if it is a packet
623 		 * received with IPD_CTL_STATUS[NO_WPTR]. If this is true,
624 		 * we need to free all buffers except for the first one.
625 		 * The caller doesn't expect their WQE pointer to be freed
626 		 */
627 		if (cvmx_ptr_to_phys(work) == start_of_buffer) {
628 			buffer_ptr.u64 = next_buffer_ptr;
629 			number_buffers--;
630 		}
631 	}
632 	while (number_buffers--) {
633 		if (o3_pki_wqe) {
634 			bptr.u64 = buffer_ptr.u64;
635 
636 			ncl = (bptr.size + CVMX_CACHE_LINE_SIZE - 1) /
637 				CVMX_CACHE_LINE_SIZE;
638 
639 			/* XXX- assumes the buffer is cache-line aligned */
640 			start_of_buffer = (bptr.addr >> 7) << 7;
641 
642 			/*
643 			 * Read pointer to next buffer before we free the
644 			 * current buffer.
645 			 */
646 			next_buffer_ptr = *(uint64_t *)cvmx_phys_to_ptr(bptr.addr - 8);
647 			/* FPA AURA comes from WQE, includes node */
648 			cvmx_fpa3_free(cvmx_phys_to_ptr(start_of_buffer),
649 				       aura, ncl);
650 		} else {
651 			ncl = (buffer_ptr.s.size + CVMX_CACHE_LINE_SIZE - 1) /
652 				      CVMX_CACHE_LINE_SIZE +
653 			      buffer_ptr.s.back;
654 			/*
655 			 * Calculate buffer start using "back" offset,
656 			 * Remember the back pointer is in cache lines,
657 			 * not 64bit words
658 			 */
659 			start_of_buffer = ((buffer_ptr.s.addr >> 7) -
660 					   buffer_ptr.s.back) << 7;
661 			/*
662 			 * Read pointer to next buffer before we free
663 			 * the current buffer.
664 			 */
665 			next_buffer_ptr =
666 				*(uint64_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr - 8);
667 			/* FPA pool comes from buf_ptr itself */
668 			if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) {
669 				aura = cvmx_fpa1_pool_to_fpa3_aura(buffer_ptr.s.pool);
670 				cvmx_fpa3_free(cvmx_phys_to_ptr(start_of_buffer),
671 					       aura, ncl);
672 			} else {
673 				cvmx_fpa1_free(cvmx_phys_to_ptr(start_of_buffer),
674 					       buffer_ptr.s.pool, ncl);
675 			}
676 		}
677 		buffer_ptr.u64 = next_buffer_ptr;
678 	}
679 }
680 
cvmx_helper_setup_legacy_red(int pass_thresh,int drop_thresh)681 void cvmx_helper_setup_legacy_red(int pass_thresh, int drop_thresh)
682 {
683 	unsigned int node = cvmx_get_node_num();
684 	int aura, bpid;
685 	int buf_cnt;
686 	bool ena_red = 0, ena_drop = 0, ena_bp = 0;
687 
688 #define FPA_RED_AVG_DLY 1
689 #define FPA_RED_LVL_DLY 3
690 #define FPA_QOS_AVRG	0
691 	/* Trying to make it backward compatible with older chips */
692 
693 	/* Setting up avg_dly and prb_dly, enable bits */
694 	if (octeon_has_feature(OCTEON_FEATURE_FPA3)) {
695 		cvmx_fpa3_config_red_params(node, FPA_QOS_AVRG,
696 					    FPA_RED_LVL_DLY, FPA_RED_AVG_DLY);
697 	}
698 
699 	/* Disable backpressure on queued buffers which is aura in 78xx*/
700 	/*
701 	 * Assumption is that all packets from all interface and ports goes
702 	 * in same poolx/aurax for backward compatibility
703 	 */
704 	aura = cvmx_fpa_get_packet_pool();
705 	buf_cnt = cvmx_fpa_get_packet_pool_buffer_count();
706 	pass_thresh = buf_cnt - pass_thresh;
707 	drop_thresh = buf_cnt - drop_thresh;
708 	/* Map aura to bpid 0*/
709 	bpid = 0;
710 	cvmx_pki_write_aura_bpid(node, aura, bpid);
711 	/* Don't enable back pressure */
712 	ena_bp = 0;
713 	/* enable RED */
714 	ena_red = 1;
715 	/*
716 	 * This will enable RED on all interfaces since
717 	 * they all have packet buffer coming from  same aura
718 	 */
719 	cvmx_helper_setup_aura_qos(node, aura, ena_red, ena_drop, pass_thresh,
720 				   drop_thresh, ena_bp, 0);
721 }
722 
723 /**
724  * Setup Random Early Drop to automatically begin dropping packets.
725  *
726  * @param pass_thresh
727  *               Packets will begin slowly dropping when there are less than
728  *               this many packet buffers free in FPA 0.
729  * @param drop_thresh
730  *               All incoming packets will be dropped when there are less
731  *               than this many free packet buffers in FPA 0.
732  * @return Zero on success. Negative on failure
733  */
cvmx_helper_setup_red(int pass_thresh,int drop_thresh)734 int cvmx_helper_setup_red(int pass_thresh, int drop_thresh)
735 {
736 	if (octeon_has_feature(OCTEON_FEATURE_PKI))
737 		cvmx_helper_setup_legacy_red(pass_thresh, drop_thresh);
738 	else
739 		cvmx_ipd_setup_red(pass_thresh, drop_thresh);
740 	return 0;
741 }
742 
743 /**
744  * @INTERNAL
745  * Setup the common GMX settings that determine the number of
746  * ports. These setting apply to almost all configurations of all
747  * chips.
748  *
749  * @param xiface Interface to configure
750  * @param num_ports Number of ports on the interface
751  *
752  * @return Zero on success, negative on failure
753  */
__cvmx_helper_setup_gmx(int xiface,int num_ports)754 int __cvmx_helper_setup_gmx(int xiface, int num_ports)
755 {
756 	union cvmx_gmxx_tx_prts gmx_tx_prts;
757 	union cvmx_gmxx_rx_prts gmx_rx_prts;
758 	union cvmx_pko_reg_gmx_port_mode pko_mode;
759 	union cvmx_gmxx_txx_thresh gmx_tx_thresh;
760 	struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
761 	int index;
762 
763 	/*
764 	 * The common BGX settings are already done in the appropriate
765 	 * enable functions, nothing to do here.
766 	 */
767 	if (octeon_has_feature(OCTEON_FEATURE_BGX))
768 		return 0;
769 
770 	/* Tell GMX the number of TX ports on this interface */
771 	gmx_tx_prts.u64 = csr_rd(CVMX_GMXX_TX_PRTS(xi.interface));
772 	gmx_tx_prts.s.prts = num_ports;
773 	csr_wr(CVMX_GMXX_TX_PRTS(xi.interface), gmx_tx_prts.u64);
774 
775 	/*
776 	 * Tell GMX the number of RX ports on this interface.  This only applies
777 	 * to *GMII and XAUI ports.
778 	 */
779 	switch (cvmx_helper_interface_get_mode(xiface)) {
780 	case CVMX_HELPER_INTERFACE_MODE_RGMII:
781 	case CVMX_HELPER_INTERFACE_MODE_SGMII:
782 	case CVMX_HELPER_INTERFACE_MODE_QSGMII:
783 	case CVMX_HELPER_INTERFACE_MODE_GMII:
784 	case CVMX_HELPER_INTERFACE_MODE_XAUI:
785 	case CVMX_HELPER_INTERFACE_MODE_RXAUI:
786 		if (num_ports > 4) {
787 			debug("%s: Illegal num_ports\n", __func__);
788 			return -1;
789 		}
790 
791 		gmx_rx_prts.u64 = csr_rd(CVMX_GMXX_RX_PRTS(xi.interface));
792 		gmx_rx_prts.s.prts = num_ports;
793 		csr_wr(CVMX_GMXX_RX_PRTS(xi.interface), gmx_rx_prts.u64);
794 		break;
795 
796 	default:
797 		break;
798 	}
799 
800 	/*
801 	 * Skip setting CVMX_PKO_REG_GMX_PORT_MODE on 30XX, 31XX, 50XX,
802 	 * and 68XX.
803 	 */
804 	if (!OCTEON_IS_MODEL(OCTEON_CN68XX)) {
805 		/* Tell PKO the number of ports on this interface */
806 		pko_mode.u64 = csr_rd(CVMX_PKO_REG_GMX_PORT_MODE);
807 		if (xi.interface == 0) {
808 			if (num_ports == 1)
809 				pko_mode.s.mode0 = 4;
810 			else if (num_ports == 2)
811 				pko_mode.s.mode0 = 3;
812 			else if (num_ports <= 4)
813 				pko_mode.s.mode0 = 2;
814 			else if (num_ports <= 8)
815 				pko_mode.s.mode0 = 1;
816 			else
817 				pko_mode.s.mode0 = 0;
818 		} else {
819 			if (num_ports == 1)
820 				pko_mode.s.mode1 = 4;
821 			else if (num_ports == 2)
822 				pko_mode.s.mode1 = 3;
823 			else if (num_ports <= 4)
824 				pko_mode.s.mode1 = 2;
825 			else if (num_ports <= 8)
826 				pko_mode.s.mode1 = 1;
827 			else
828 				pko_mode.s.mode1 = 0;
829 		}
830 		csr_wr(CVMX_PKO_REG_GMX_PORT_MODE, pko_mode.u64);
831 	}
832 
833 	/*
834 	 * Set GMX to buffer as much data as possible before starting
835 	 * transmit. This reduces the chances that we have a TX under run
836 	 * due to memory contention. Any packet that fits entirely in the
837 	 * GMX FIFO can never have an under run regardless of memory load.
838 	 */
839 	gmx_tx_thresh.u64 = csr_rd(CVMX_GMXX_TXX_THRESH(0, xi.interface));
840 	/* ccn - common cnt numberator */
841 	int ccn = 0x100;
842 
843 	/* Choose the max value for the number of ports */
844 	if (num_ports <= 1)
845 		gmx_tx_thresh.s.cnt = ccn / 1;
846 	else if (num_ports == 2)
847 		gmx_tx_thresh.s.cnt = ccn / 2;
848 	else
849 		gmx_tx_thresh.s.cnt = ccn / 4;
850 
851 	/*
852 	 * SPI and XAUI can have lots of ports but the GMX hardware
853 	 * only ever has a max of 4
854 	 */
855 	if (num_ports > 4)
856 		num_ports = 4;
857 	for (index = 0; index < num_ports; index++)
858 		csr_wr(CVMX_GMXX_TXX_THRESH(index, xi.interface), gmx_tx_thresh.u64);
859 
860 	/*
861 	 * For o68, we need to setup the pipes
862 	 */
863 	if (OCTEON_IS_MODEL(OCTEON_CN68XX) && xi.interface < CVMX_HELPER_MAX_GMX) {
864 		union cvmx_gmxx_txx_pipe config;
865 
866 		for (index = 0; index < num_ports; index++) {
867 			config.u64 = 0;
868 
869 			if (__cvmx_helper_cfg_pko_port_base(xiface, index) >= 0) {
870 				config.u64 = csr_rd(CVMX_GMXX_TXX_PIPE(index,
871 								       xi.interface));
872 				config.s.nump = __cvmx_helper_cfg_pko_port_num(xiface,
873 									       index);
874 				config.s.base = __cvmx_helper_cfg_pko_port_base(xiface,
875 										index);
876 				csr_wr(CVMX_GMXX_TXX_PIPE(index, xi.interface),
877 				       config.u64);
878 			}
879 		}
880 	}
881 
882 	return 0;
883 }
884 
cvmx_helper_get_pko_port(int interface,int port)885 int cvmx_helper_get_pko_port(int interface, int port)
886 {
887 	return cvmx_pko_get_base_pko_port(interface, port);
888 }
889 
cvmx_helper_get_ipd_port(int xiface,int index)890 int cvmx_helper_get_ipd_port(int xiface, int index)
891 {
892 	struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
893 
894 	if (octeon_has_feature(OCTEON_FEATURE_PKND)) {
895 		const struct ipd_port_map *port_map;
896 		int ipd_port;
897 
898 		if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
899 			port_map = ipd_port_map_68xx;
900 			ipd_port = 0;
901 		} else if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
902 			port_map = ipd_port_map_78xx;
903 			ipd_port = cvmx_helper_node_to_ipd_port(xi.node, 0);
904 		} else if (OCTEON_IS_MODEL(OCTEON_CN73XX)) {
905 			port_map = ipd_port_map_73xx;
906 			ipd_port = 0;
907 		} else if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) {
908 			port_map = ipd_port_map_75xx;
909 			ipd_port = 0;
910 		} else {
911 			return -1;
912 		}
913 
914 		ipd_port += port_map[xi.interface].first_ipd_port;
915 		if (port_map[xi.interface].type == GMII) {
916 			cvmx_helper_interface_mode_t mode;
917 
918 			mode = cvmx_helper_interface_get_mode(xiface);
919 			if (mode == CVMX_HELPER_INTERFACE_MODE_XAUI ||
920 			    (mode == CVMX_HELPER_INTERFACE_MODE_RXAUI &&
921 			     OCTEON_IS_MODEL(OCTEON_CN68XX))) {
922 				ipd_port += port_map[xi.interface].ipd_port_adj;
923 				return ipd_port;
924 			} else {
925 				return ipd_port + (index * 16);
926 			}
927 		} else if (port_map[xi.interface].type == ILK) {
928 			return ipd_port + index;
929 		} else if (port_map[xi.interface].type == NPI) {
930 			return ipd_port + index;
931 		} else if (port_map[xi.interface].type == SRIO) {
932 			return ipd_port + index;
933 		} else if (port_map[xi.interface].type == LB) {
934 			return ipd_port + index;
935 		}
936 
937 		debug("ERROR: %s: interface %u:%u bad mode\n",
938 		      __func__, xi.node, xi.interface);
939 		return -1;
940 	} else if (cvmx_helper_interface_get_mode(xiface) ==
941 		   CVMX_HELPER_INTERFACE_MODE_AGL) {
942 		return 24;
943 	}
944 
945 	switch (xi.interface) {
946 	case 0:
947 		return index;
948 	case 1:
949 		return index + 16;
950 	case 2:
951 		return index + 32;
952 	case 3:
953 		return index + 36;
954 	case 4:
955 		return index + 40;
956 	case 5:
957 		return index + 42;
958 	case 6:
959 		return index + 44;
960 	case 7:
961 		return index + 46;
962 	}
963 	return -1;
964 }
965 
cvmx_helper_get_pknd(int xiface,int index)966 int cvmx_helper_get_pknd(int xiface, int index)
967 {
968 	if (octeon_has_feature(OCTEON_FEATURE_PKND))
969 		return __cvmx_helper_cfg_pknd(xiface, index);
970 
971 	return CVMX_INVALID_PKND;
972 }
973 
cvmx_helper_get_bpid(int interface,int port)974 int cvmx_helper_get_bpid(int interface, int port)
975 {
976 	if (octeon_has_feature(OCTEON_FEATURE_PKND))
977 		return __cvmx_helper_cfg_bpid(interface, port);
978 
979 	return CVMX_INVALID_BPID;
980 }
981 
982 /**
983  * Display interface statistics.
984  *
985  * @param port IPD/PKO port number
986  *
987  * @return none
988  */
cvmx_helper_show_stats(int port)989 void cvmx_helper_show_stats(int port)
990 {
991 	cvmx_pip_port_status_t status;
992 	cvmx_pko_port_status_t pko_status;
993 
994 	/* ILK stats */
995 	if (octeon_has_feature(OCTEON_FEATURE_ILK))
996 		__cvmx_helper_ilk_show_stats();
997 
998 	/* PIP stats */
999 	cvmx_pip_get_port_stats(port, 0, &status);
1000 	debug("port %d: the number of packets - ipd: %d\n", port,
1001 	      (int)status.packets);
1002 
1003 	/* PKO stats */
1004 	cvmx_pko_get_port_status(port, 0, &pko_status);
1005 	debug("port %d: the number of packets - pko: %d\n", port,
1006 	      (int)pko_status.packets);
1007 
1008 	/* TODO: other stats */
1009 }
1010 
1011 /**
1012  * Returns the interface number for an IPD/PKO port number.
1013  *
1014  * @param ipd_port IPD/PKO port number
1015  *
1016  * @return Interface number
1017  */
cvmx_helper_get_interface_num(int ipd_port)1018 int cvmx_helper_get_interface_num(int ipd_port)
1019 {
1020 	if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
1021 		const struct ipd_port_map *port_map;
1022 		int i;
1023 		struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
1024 
1025 		port_map = ipd_port_map_68xx;
1026 		for (i = 0; i < CVMX_HELPER_MAX_IFACE; i++) {
1027 			if (xp.port >= port_map[i].first_ipd_port &&
1028 			    xp.port <= port_map[i].last_ipd_port)
1029 				return i;
1030 		}
1031 		return -1;
1032 	} else if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
1033 		const struct ipd_port_map *port_map;
1034 		int i;
1035 		struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
1036 
1037 		port_map = ipd_port_map_78xx;
1038 		for (i = 0; i < CVMX_HELPER_MAX_IFACE; i++) {
1039 			if (xp.port >= port_map[i].first_ipd_port &&
1040 			    xp.port <= port_map[i].last_ipd_port)
1041 				return cvmx_helper_node_interface_to_xiface(xp.node, i);
1042 		}
1043 		return -1;
1044 	} else if (OCTEON_IS_MODEL(OCTEON_CN73XX)) {
1045 		const struct ipd_port_map *port_map;
1046 		int i;
1047 		struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
1048 
1049 		port_map = ipd_port_map_73xx;
1050 		for (i = 0; i < CVMX_HELPER_MAX_IFACE; i++) {
1051 			if (xp.port >= port_map[i].first_ipd_port &&
1052 			    xp.port <= port_map[i].last_ipd_port)
1053 				return i;
1054 		}
1055 		return -1;
1056 	} else if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) {
1057 		const struct ipd_port_map *port_map;
1058 		int i;
1059 		struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
1060 
1061 		port_map = ipd_port_map_75xx;
1062 		for (i = 0; i < CVMX_HELPER_MAX_IFACE; i++) {
1063 			if (xp.port >= port_map[i].first_ipd_port &&
1064 			    xp.port <= port_map[i].last_ipd_port)
1065 				return i;
1066 		}
1067 		return -1;
1068 	} else if (OCTEON_IS_MODEL(OCTEON_CN70XX) && ipd_port == 24) {
1069 		return 4;
1070 	}
1071 
1072 	if (ipd_port < 16)
1073 		return 0;
1074 	else if (ipd_port < 32)
1075 		return 1;
1076 	else if (ipd_port < 36)
1077 		return 2;
1078 	else if (ipd_port < 40)
1079 		return 3;
1080 	else if (ipd_port < 42)
1081 		return 4;
1082 	else if (ipd_port < 44)
1083 		return 5;
1084 	else if (ipd_port < 46)
1085 		return 6;
1086 	else if (ipd_port < 48)
1087 		return 7;
1088 
1089 	debug("%s: Illegal IPD port number %d\n", __func__, ipd_port);
1090 	return -1;
1091 }
1092 
1093 /**
1094  * Returns the interface index number for an IPD/PKO port
1095  * number.
1096  *
1097  * @param ipd_port IPD/PKO port number
1098  *
1099  * @return Interface index number
1100  */
cvmx_helper_get_interface_index_num(int ipd_port)1101 int cvmx_helper_get_interface_index_num(int ipd_port)
1102 {
1103 	if (octeon_has_feature(OCTEON_FEATURE_PKND)) {
1104 		const struct ipd_port_map *port_map;
1105 		int port;
1106 		enum port_map_if_type type = INVALID_IF_TYPE;
1107 		int i;
1108 		int num_interfaces;
1109 
1110 		if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
1111 			port_map = ipd_port_map_68xx;
1112 		} else if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
1113 			struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
1114 
1115 			port_map = ipd_port_map_78xx;
1116 			ipd_port = xp.port;
1117 		} else if (OCTEON_IS_MODEL(OCTEON_CN73XX)) {
1118 			struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
1119 
1120 			port_map = ipd_port_map_73xx;
1121 			ipd_port = xp.port;
1122 		} else if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) {
1123 			struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
1124 
1125 			port_map = ipd_port_map_75xx;
1126 			ipd_port = xp.port;
1127 		} else {
1128 			return -1;
1129 		}
1130 
1131 		num_interfaces = cvmx_helper_get_number_of_interfaces();
1132 
1133 		/* Get the interface type of the ipd port */
1134 		for (i = 0; i < num_interfaces; i++) {
1135 			if (ipd_port >= port_map[i].first_ipd_port &&
1136 			    ipd_port <= port_map[i].last_ipd_port) {
1137 				type = port_map[i].type;
1138 				break;
1139 			}
1140 		}
1141 
1142 		/* Convert the ipd port to the interface port */
1143 		switch (type) {
1144 		/* Ethernet interfaces have a channel in lower 4 bits
1145 		 * that is does not discriminate traffic, and is ignored.
1146 		 */
1147 		case GMII:
1148 			port = ipd_port - port_map[i].first_ipd_port;
1149 
1150 			/* CN68XX adds 0x40 to IPD_PORT when in XAUI/RXAUI
1151 			 * mode of operation, adjust for that case
1152 			 */
1153 			if (port >= port_map[i].ipd_port_adj)
1154 				port -= port_map[i].ipd_port_adj;
1155 
1156 			port >>= 4;
1157 			return port;
1158 
1159 		/*
1160 		 * These interfaces do not have physical ports,
1161 		 * but have logical channels instead that separate
1162 		 * traffic into logical streams
1163 		 */
1164 		case ILK:
1165 		case SRIO:
1166 		case NPI:
1167 		case LB:
1168 			port = ipd_port - port_map[i].first_ipd_port;
1169 			return port;
1170 
1171 		default:
1172 			printf("ERROR: %s: Illegal IPD port number %#x\n",
1173 			       __func__, ipd_port);
1174 			return -1;
1175 		}
1176 	}
1177 	if (OCTEON_IS_MODEL(OCTEON_CN70XX))
1178 		return ipd_port & 3;
1179 	if (ipd_port < 32)
1180 		return ipd_port & 15;
1181 	else if (ipd_port < 40)
1182 		return ipd_port & 3;
1183 	else if (ipd_port < 48)
1184 		return ipd_port & 1;
1185 
1186 	debug("%s: Illegal IPD port number\n", __func__);
1187 
1188 	return -1;
1189 }
1190 
1191 /**
1192  * Prints out a buffer with the address, hex bytes, and ASCII
1193  *
1194  * @param	addr	Start address to print on the left
1195  * @param[in]	buffer	array of bytes to print
1196  * @param	count	Number of bytes to print
1197  */
cvmx_print_buffer_u8(unsigned int addr,const uint8_t * buffer,size_t count)1198 void cvmx_print_buffer_u8(unsigned int addr, const uint8_t *buffer,
1199 			  size_t count)
1200 {
1201 	uint i;
1202 
1203 	while (count) {
1204 		unsigned int linelen = count < 16 ? count : 16;
1205 
1206 		debug("%08x:", addr);
1207 
1208 		for (i = 0; i < linelen; i++)
1209 			debug(" %0*x", 2, buffer[i]);
1210 
1211 		while (i++ < 17)
1212 			debug("   ");
1213 
1214 		for (i = 0; i < linelen; i++) {
1215 			if (buffer[i] >= 0x20 && buffer[i] < 0x7f)
1216 				debug("%c", buffer[i]);
1217 			else
1218 				debug(".");
1219 		}
1220 		debug("\n");
1221 		addr += linelen;
1222 		buffer += linelen;
1223 		count -= linelen;
1224 	}
1225 }
1226