blob: 6d775eee9245e39f09d718eab6aff18755998fd6 [file] [log] [blame]
Aaron Williams47652952020-12-11 17:06:01 +01001// 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 */
45enum 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 */
62struct 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 */
73static 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 */
93static 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 */
110static 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 */
122static 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 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100135 * Return: String
Aaron Williams47652952020-12-11 17:06:01 +0100136 */
137const 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/**
Aaron Williams47652952020-12-11 17:06:01 +0100185 * @INTERNAL
186 *
187 * Extract NO_WPTR mode from PIP/IPD register
188 */
189static int __cvmx_ipd_mode_no_wptr(void)
190{
191 if (octeon_has_feature(OCTEON_FEATURE_NO_WPTR)) {
192 cvmx_ipd_ctl_status_t ipd_ctl_status;
193
194 ipd_ctl_status.u64 = csr_rd(CVMX_IPD_CTL_STATUS);
195 return ipd_ctl_status.s.no_wptr;
196 }
197 return 0;
198}
199
200static cvmx_buf_ptr_t __cvmx_packet_short_ptr[4];
201static int8_t __cvmx_wqe_pool = -1;
202
203/**
204 * @INTERNAL
205 * Prepare packet pointer templace for dynamic short
206 * packets.
207 */
208static void cvmx_packet_short_ptr_calculate(void)
209{
210 unsigned int i, off;
211 union cvmx_pip_gbl_cfg pip_gbl_cfg;
212 union cvmx_pip_ip_offset pip_ip_offset;
213
214 /* Fill in the common values for all cases */
215 for (i = 0; i < 4; i++) {
216 if (__cvmx_ipd_mode_no_wptr())
217 /* packet pool, set to 0 in hardware */
218 __cvmx_wqe_pool = 0;
219 else
220 /* WQE pool as configured */
221 __cvmx_wqe_pool = csr_rd(CVMX_IPD_WQE_FPA_QUEUE) & 7;
222
223 __cvmx_packet_short_ptr[i].s.pool = __cvmx_wqe_pool;
224 __cvmx_packet_short_ptr[i].s.size = cvmx_fpa_get_block_size(__cvmx_wqe_pool);
225 __cvmx_packet_short_ptr[i].s.size -= 32;
226 __cvmx_packet_short_ptr[i].s.addr = 32;
227 }
228
229 pip_gbl_cfg.u64 = csr_rd(CVMX_PIP_GBL_CFG);
230 pip_ip_offset.u64 = csr_rd(CVMX_PIP_IP_OFFSET);
231
232 /* RAW_FULL: index = 0 */
233 i = 0;
234 off = pip_gbl_cfg.s.raw_shf;
235 __cvmx_packet_short_ptr[i].s.addr += off;
236 __cvmx_packet_short_ptr[i].s.size -= off;
237 __cvmx_packet_short_ptr[i].s.back += off >> 7;
238
239 /* NON-IP: index = 1 */
240 i = 1;
241 off = pip_gbl_cfg.s.nip_shf;
242 __cvmx_packet_short_ptr[i].s.addr += off;
243 __cvmx_packet_short_ptr[i].s.size -= off;
244 __cvmx_packet_short_ptr[i].s.back += off >> 7;
245
246 /* IPv4: index = 2 */
247 i = 2;
248 off = (pip_ip_offset.s.offset << 3) + 4;
249 __cvmx_packet_short_ptr[i].s.addr += off;
250 __cvmx_packet_short_ptr[i].s.size -= off;
251 __cvmx_packet_short_ptr[i].s.back += off >> 7;
252
253 /* IPv6: index = 3 */
254 i = 3;
255 off = (pip_ip_offset.s.offset << 3) + 0;
256 __cvmx_packet_short_ptr[i].s.addr += off;
257 __cvmx_packet_short_ptr[i].s.size -= off;
258 __cvmx_packet_short_ptr[i].s.back += off >> 7;
259
260 /* For IPv4/IPv6: subtract work->word2.s.ip_offset
261 * to addr, if it is smaller than IP_OFFSET[OFFSET]*8
262 * which is stored in __cvmx_packet_short_ptr[3].s.addr
263 */
264}
265
266/**
267 * Extract packet data buffer pointer from work queue entry.
268 *
269 * Returns the legacy (Octeon1/Octeon2) buffer pointer structure
270 * for the linked buffer list.
271 * On CN78XX, the native buffer pointer structure is converted into
272 * the legacy format.
273 * The legacy buf_ptr is then stored in the WQE, and word0 reserved
274 * field is set to indicate that the buffer pointers were translated.
275 * If the packet data is only found inside the work queue entry,
276 * a standard buffer pointer structure is created for it.
277 */
278cvmx_buf_ptr_t cvmx_wqe_get_packet_ptr(cvmx_wqe_t *work)
279{
280 if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) {
281 cvmx_wqe_78xx_t *wqe = (void *)work;
282 cvmx_buf_ptr_t optr, lptr;
283 cvmx_buf_ptr_pki_t nptr;
284 unsigned int pool, bufs;
285 int node = cvmx_get_node_num();
286
287 /* In case of repeated calls of this function */
288 if (wqe->pki_wqe_translated || wqe->word2.software) {
289 optr.u64 = wqe->packet_ptr.u64;
290 return optr;
291 }
292
293 bufs = wqe->word0.bufs;
294 pool = wqe->word0.aura;
295 nptr.u64 = wqe->packet_ptr.u64;
296
297 optr.u64 = 0;
298 optr.s.pool = pool;
299 optr.s.addr = nptr.addr;
300 if (bufs == 1) {
301 optr.s.size = pki_dflt_pool[node].buffer_size -
302 pki_dflt_style[node].parm_cfg.first_skip - 8 -
303 wqe->word0.apad;
304 } else {
305 optr.s.size = nptr.size;
306 }
307
308 /* Calculate the "back" offset */
309 if (!nptr.packet_outside_wqe) {
310 optr.s.back = (nptr.addr -
311 cvmx_ptr_to_phys(wqe)) >> 7;
312 } else {
313 optr.s.back =
314 (pki_dflt_style[node].parm_cfg.first_skip +
315 8 + wqe->word0.apad) >> 7;
316 }
317 lptr = optr;
318
319 /* Follow pointer and convert all linked pointers */
320 while (bufs > 1) {
321 void *vptr;
322
323 vptr = cvmx_phys_to_ptr(lptr.s.addr);
324
325 memcpy(&nptr, vptr - 8, 8);
326 /*
327 * Errata (PKI-20776) PKI_BUFLINK_S's are endian-swapped
328 * CN78XX pass 1.x has a bug where the packet pointer
329 * in each segment is written in the opposite
330 * endianness of the configured mode. Fix these here
331 */
332 if (OCTEON_IS_MODEL(OCTEON_CN78XX_PASS1_X))
333 nptr.u64 = __builtin_bswap64(nptr.u64);
334 lptr.u64 = 0;
335 lptr.s.pool = pool;
336 lptr.s.addr = nptr.addr;
337 lptr.s.size = nptr.size;
338 lptr.s.back = (pki_dflt_style[0].parm_cfg.later_skip + 8) >>
339 7; /* TBD: not guaranteed !! */
340
341 memcpy(vptr - 8, &lptr, 8);
342 bufs--;
343 }
344 /* Store translated bufptr in WQE, and set indicator */
345 wqe->pki_wqe_translated = 1;
346 wqe->packet_ptr.u64 = optr.u64;
347 return optr;
348
349 } else {
350 unsigned int i;
351 unsigned int off = 0;
352 cvmx_buf_ptr_t bptr;
353
354 if (cvmx_likely(work->word2.s.bufs > 0))
355 return work->packet_ptr;
356
357 if (cvmx_unlikely(work->word2.s.software))
358 return work->packet_ptr;
359
360 /* first packet, precalculate packet_ptr templaces */
361 if (cvmx_unlikely(__cvmx_packet_short_ptr[0].u64 == 0))
362 cvmx_packet_short_ptr_calculate();
363
364 /* calculate templace index */
365 i = work->word2.s_cn38xx.not_IP | work->word2.s_cn38xx.rcv_error;
366 i = 2 ^ (i << 1);
367
368 /* IPv4/IPv6: Adjust IP offset */
369 if (cvmx_likely(i & 2)) {
370 i |= work->word2.s.is_v6;
371 off = work->word2.s.ip_offset;
372 } else {
373 /* RAWFULL/RAWSCHED should be handled here */
374 i = 1; /* not-IP */
375 off = 0;
376 }
377
378 /* Get the right templace */
379 bptr = __cvmx_packet_short_ptr[i];
380 bptr.s.addr -= off;
381 bptr.s.back = bptr.s.addr >> 7;
382
383 /* Add actual WQE paddr to the templace offset */
384 bptr.s.addr += cvmx_ptr_to_phys(work);
385
386 /* Adjust word2.bufs so that _free_data() handles it
387 * in the same way as PKO
388 */
389 work->word2.s.bufs = 1;
390
391 /* Store the new buffer pointer back into WQE */
392 work->packet_ptr = bptr;
393
394 /* Returned the synthetic buffer_pointer */
395 return bptr;
396 }
397}
398
399void cvmx_wqe_free(cvmx_wqe_t *work)
400{
401 unsigned int bufs, ncl = 1;
402 u64 paddr, paddr1;
403
404 if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) {
405 cvmx_wqe_78xx_t *wqe = (void *)work;
406 cvmx_fpa3_gaura_t aura;
407 cvmx_buf_ptr_pki_t bptr;
408
409 bufs = wqe->word0.bufs;
410
411 if (!wqe->pki_wqe_translated && bufs != 0) {
412 /* Handle cn78xx native untralsated WQE */
413
414 bptr = wqe->packet_ptr;
415
416 /* Do nothing - first packet buffer shares WQE buffer */
417 if (!bptr.packet_outside_wqe)
418 return;
419 } else if (cvmx_likely(bufs != 0)) {
420 /* Handle translated 78XX WQE */
421 paddr = (work->packet_ptr.s.addr & (~0x7full)) -
422 (work->packet_ptr.s.back << 7);
423 paddr1 = cvmx_ptr_to_phys(work);
424
425 /* do not free WQE if contains first data buffer */
426 if (paddr == paddr1)
427 return;
428 }
429
430 /* WQE is separate from packet buffer, free it */
431 aura = __cvmx_fpa3_gaura(wqe->word0.aura >> 10, wqe->word0.aura & 0x3ff);
432
433 cvmx_fpa3_free(work, aura, ncl);
434 } else {
435 /* handle legacy WQE */
436 bufs = work->word2.s_cn38xx.bufs;
437
438 if (cvmx_likely(bufs != 0)) {
439 /* Check if the first data buffer is inside WQE */
440 paddr = (work->packet_ptr.s.addr & (~0x7full)) -
441 (work->packet_ptr.s.back << 7);
442 paddr1 = cvmx_ptr_to_phys(work);
443
444 /* do not free WQE if contains first data buffer */
445 if (paddr == paddr1)
446 return;
447 }
448
449 /* precalculate packet_ptr, WQE pool number */
450 if (cvmx_unlikely(__cvmx_wqe_pool < 0))
451 cvmx_packet_short_ptr_calculate();
452 cvmx_fpa1_free(work, __cvmx_wqe_pool, ncl);
453 }
454}
455
456/**
457 * Free the packet buffers contained in a work queue entry.
458 * The work queue entry is also freed if it contains packet data.
459 * If however the packet starts outside the WQE, the WQE will
460 * not be freed. The application should call cvmx_wqe_free()
461 * to free the WQE buffer that contains no packet data.
462 *
463 * @param work Work queue entry with packet to free
464 */
465void cvmx_helper_free_packet_data(cvmx_wqe_t *work)
466{
467 u64 number_buffers;
468 u64 start_of_buffer;
469 u64 next_buffer_ptr;
470 cvmx_fpa3_gaura_t aura;
471 unsigned int ncl;
472 cvmx_buf_ptr_t buffer_ptr;
473 cvmx_buf_ptr_pki_t bptr;
474 cvmx_wqe_78xx_t *wqe = (void *)work;
475 int o3_pki_wqe = 0;
476
477 number_buffers = cvmx_wqe_get_bufs(work);
478
479 buffer_ptr.u64 = work->packet_ptr.u64;
480
481 /* Zero-out WQE WORD3 so that the WQE is freed by cvmx_wqe_free() */
482 work->packet_ptr.u64 = 0;
483
484 if (number_buffers == 0)
485 return;
486
487 /* Interpret PKI-style bufptr unless it has been translated */
488 if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE) &&
489 !wqe->pki_wqe_translated) {
490 o3_pki_wqe = 1;
491 cvmx_wqe_pki_errata_20776(work);
492 aura = __cvmx_fpa3_gaura(wqe->word0.aura >> 10,
493 wqe->word0.aura & 0x3ff);
494 } else {
495 start_of_buffer = ((buffer_ptr.s.addr >> 7) -
496 buffer_ptr.s.back) << 7;
497 next_buffer_ptr =
498 *(uint64_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr - 8);
499 /*
500 * Since the number of buffers is not zero, we know this is not
501 * a dynamic short packet. We need to check if it is a packet
502 * received with IPD_CTL_STATUS[NO_WPTR]. If this is true,
503 * we need to free all buffers except for the first one.
504 * The caller doesn't expect their WQE pointer to be freed
505 */
506 if (cvmx_ptr_to_phys(work) == start_of_buffer) {
507 buffer_ptr.u64 = next_buffer_ptr;
508 number_buffers--;
509 }
510 }
511 while (number_buffers--) {
512 if (o3_pki_wqe) {
513 bptr.u64 = buffer_ptr.u64;
514
515 ncl = (bptr.size + CVMX_CACHE_LINE_SIZE - 1) /
516 CVMX_CACHE_LINE_SIZE;
517
518 /* XXX- assumes the buffer is cache-line aligned */
519 start_of_buffer = (bptr.addr >> 7) << 7;
520
521 /*
522 * Read pointer to next buffer before we free the
523 * current buffer.
524 */
525 next_buffer_ptr = *(uint64_t *)cvmx_phys_to_ptr(bptr.addr - 8);
526 /* FPA AURA comes from WQE, includes node */
527 cvmx_fpa3_free(cvmx_phys_to_ptr(start_of_buffer),
528 aura, ncl);
529 } else {
530 ncl = (buffer_ptr.s.size + CVMX_CACHE_LINE_SIZE - 1) /
531 CVMX_CACHE_LINE_SIZE +
532 buffer_ptr.s.back;
533 /*
534 * Calculate buffer start using "back" offset,
535 * Remember the back pointer is in cache lines,
536 * not 64bit words
537 */
538 start_of_buffer = ((buffer_ptr.s.addr >> 7) -
539 buffer_ptr.s.back) << 7;
540 /*
541 * Read pointer to next buffer before we free
542 * the current buffer.
543 */
544 next_buffer_ptr =
545 *(uint64_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr - 8);
546 /* FPA pool comes from buf_ptr itself */
547 if (octeon_has_feature(OCTEON_FEATURE_CN78XX_WQE)) {
548 aura = cvmx_fpa1_pool_to_fpa3_aura(buffer_ptr.s.pool);
549 cvmx_fpa3_free(cvmx_phys_to_ptr(start_of_buffer),
550 aura, ncl);
551 } else {
552 cvmx_fpa1_free(cvmx_phys_to_ptr(start_of_buffer),
553 buffer_ptr.s.pool, ncl);
554 }
555 }
556 buffer_ptr.u64 = next_buffer_ptr;
557 }
558}
559
Aaron Williams47652952020-12-11 17:06:01 +0100560/**
561 * @INTERNAL
562 * Setup the common GMX settings that determine the number of
563 * ports. These setting apply to almost all configurations of all
564 * chips.
565 *
566 * @param xiface Interface to configure
567 * @param num_ports Number of ports on the interface
568 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100569 * Return: Zero on success, negative on failure
Aaron Williams47652952020-12-11 17:06:01 +0100570 */
571int __cvmx_helper_setup_gmx(int xiface, int num_ports)
572{
573 union cvmx_gmxx_tx_prts gmx_tx_prts;
574 union cvmx_gmxx_rx_prts gmx_rx_prts;
575 union cvmx_pko_reg_gmx_port_mode pko_mode;
576 union cvmx_gmxx_txx_thresh gmx_tx_thresh;
577 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
578 int index;
579
580 /*
581 * The common BGX settings are already done in the appropriate
582 * enable functions, nothing to do here.
583 */
584 if (octeon_has_feature(OCTEON_FEATURE_BGX))
585 return 0;
586
587 /* Tell GMX the number of TX ports on this interface */
588 gmx_tx_prts.u64 = csr_rd(CVMX_GMXX_TX_PRTS(xi.interface));
589 gmx_tx_prts.s.prts = num_ports;
590 csr_wr(CVMX_GMXX_TX_PRTS(xi.interface), gmx_tx_prts.u64);
591
592 /*
593 * Tell GMX the number of RX ports on this interface. This only applies
594 * to *GMII and XAUI ports.
595 */
596 switch (cvmx_helper_interface_get_mode(xiface)) {
597 case CVMX_HELPER_INTERFACE_MODE_RGMII:
598 case CVMX_HELPER_INTERFACE_MODE_SGMII:
599 case CVMX_HELPER_INTERFACE_MODE_QSGMII:
600 case CVMX_HELPER_INTERFACE_MODE_GMII:
601 case CVMX_HELPER_INTERFACE_MODE_XAUI:
602 case CVMX_HELPER_INTERFACE_MODE_RXAUI:
603 if (num_ports > 4) {
604 debug("%s: Illegal num_ports\n", __func__);
605 return -1;
606 }
607
608 gmx_rx_prts.u64 = csr_rd(CVMX_GMXX_RX_PRTS(xi.interface));
609 gmx_rx_prts.s.prts = num_ports;
610 csr_wr(CVMX_GMXX_RX_PRTS(xi.interface), gmx_rx_prts.u64);
611 break;
612
613 default:
614 break;
615 }
616
617 /*
618 * Skip setting CVMX_PKO_REG_GMX_PORT_MODE on 30XX, 31XX, 50XX,
619 * and 68XX.
620 */
621 if (!OCTEON_IS_MODEL(OCTEON_CN68XX)) {
622 /* Tell PKO the number of ports on this interface */
623 pko_mode.u64 = csr_rd(CVMX_PKO_REG_GMX_PORT_MODE);
624 if (xi.interface == 0) {
625 if (num_ports == 1)
626 pko_mode.s.mode0 = 4;
627 else if (num_ports == 2)
628 pko_mode.s.mode0 = 3;
629 else if (num_ports <= 4)
630 pko_mode.s.mode0 = 2;
631 else if (num_ports <= 8)
632 pko_mode.s.mode0 = 1;
633 else
634 pko_mode.s.mode0 = 0;
635 } else {
636 if (num_ports == 1)
637 pko_mode.s.mode1 = 4;
638 else if (num_ports == 2)
639 pko_mode.s.mode1 = 3;
640 else if (num_ports <= 4)
641 pko_mode.s.mode1 = 2;
642 else if (num_ports <= 8)
643 pko_mode.s.mode1 = 1;
644 else
645 pko_mode.s.mode1 = 0;
646 }
647 csr_wr(CVMX_PKO_REG_GMX_PORT_MODE, pko_mode.u64);
648 }
649
650 /*
651 * Set GMX to buffer as much data as possible before starting
652 * transmit. This reduces the chances that we have a TX under run
653 * due to memory contention. Any packet that fits entirely in the
654 * GMX FIFO can never have an under run regardless of memory load.
655 */
656 gmx_tx_thresh.u64 = csr_rd(CVMX_GMXX_TXX_THRESH(0, xi.interface));
657 /* ccn - common cnt numberator */
658 int ccn = 0x100;
659
660 /* Choose the max value for the number of ports */
661 if (num_ports <= 1)
662 gmx_tx_thresh.s.cnt = ccn / 1;
663 else if (num_ports == 2)
664 gmx_tx_thresh.s.cnt = ccn / 2;
665 else
666 gmx_tx_thresh.s.cnt = ccn / 4;
667
668 /*
669 * SPI and XAUI can have lots of ports but the GMX hardware
670 * only ever has a max of 4
671 */
672 if (num_ports > 4)
673 num_ports = 4;
674 for (index = 0; index < num_ports; index++)
675 csr_wr(CVMX_GMXX_TXX_THRESH(index, xi.interface), gmx_tx_thresh.u64);
676
677 /*
678 * For o68, we need to setup the pipes
679 */
680 if (OCTEON_IS_MODEL(OCTEON_CN68XX) && xi.interface < CVMX_HELPER_MAX_GMX) {
681 union cvmx_gmxx_txx_pipe config;
682
683 for (index = 0; index < num_ports; index++) {
684 config.u64 = 0;
685
686 if (__cvmx_helper_cfg_pko_port_base(xiface, index) >= 0) {
687 config.u64 = csr_rd(CVMX_GMXX_TXX_PIPE(index,
688 xi.interface));
689 config.s.nump = __cvmx_helper_cfg_pko_port_num(xiface,
690 index);
691 config.s.base = __cvmx_helper_cfg_pko_port_base(xiface,
692 index);
693 csr_wr(CVMX_GMXX_TXX_PIPE(index, xi.interface),
694 config.u64);
695 }
696 }
697 }
698
699 return 0;
700}
701
702int cvmx_helper_get_pko_port(int interface, int port)
703{
704 return cvmx_pko_get_base_pko_port(interface, port);
705}
706
707int cvmx_helper_get_ipd_port(int xiface, int index)
708{
709 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
710
711 if (octeon_has_feature(OCTEON_FEATURE_PKND)) {
712 const struct ipd_port_map *port_map;
713 int ipd_port;
714
715 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
716 port_map = ipd_port_map_68xx;
717 ipd_port = 0;
718 } else if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
719 port_map = ipd_port_map_78xx;
720 ipd_port = cvmx_helper_node_to_ipd_port(xi.node, 0);
721 } else if (OCTEON_IS_MODEL(OCTEON_CN73XX)) {
722 port_map = ipd_port_map_73xx;
723 ipd_port = 0;
724 } else if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) {
725 port_map = ipd_port_map_75xx;
726 ipd_port = 0;
727 } else {
728 return -1;
729 }
730
731 ipd_port += port_map[xi.interface].first_ipd_port;
732 if (port_map[xi.interface].type == GMII) {
733 cvmx_helper_interface_mode_t mode;
734
735 mode = cvmx_helper_interface_get_mode(xiface);
736 if (mode == CVMX_HELPER_INTERFACE_MODE_XAUI ||
737 (mode == CVMX_HELPER_INTERFACE_MODE_RXAUI &&
738 OCTEON_IS_MODEL(OCTEON_CN68XX))) {
739 ipd_port += port_map[xi.interface].ipd_port_adj;
740 return ipd_port;
741 } else {
742 return ipd_port + (index * 16);
743 }
744 } else if (port_map[xi.interface].type == ILK) {
745 return ipd_port + index;
746 } else if (port_map[xi.interface].type == NPI) {
747 return ipd_port + index;
748 } else if (port_map[xi.interface].type == SRIO) {
749 return ipd_port + index;
750 } else if (port_map[xi.interface].type == LB) {
751 return ipd_port + index;
752 }
753
754 debug("ERROR: %s: interface %u:%u bad mode\n",
755 __func__, xi.node, xi.interface);
756 return -1;
757 } else if (cvmx_helper_interface_get_mode(xiface) ==
758 CVMX_HELPER_INTERFACE_MODE_AGL) {
759 return 24;
760 }
761
762 switch (xi.interface) {
763 case 0:
764 return index;
765 case 1:
766 return index + 16;
767 case 2:
768 return index + 32;
769 case 3:
770 return index + 36;
771 case 4:
772 return index + 40;
773 case 5:
774 return index + 42;
775 case 6:
776 return index + 44;
777 case 7:
778 return index + 46;
779 }
780 return -1;
781}
782
783int cvmx_helper_get_pknd(int xiface, int index)
784{
785 if (octeon_has_feature(OCTEON_FEATURE_PKND))
786 return __cvmx_helper_cfg_pknd(xiface, index);
787
788 return CVMX_INVALID_PKND;
789}
790
791int cvmx_helper_get_bpid(int interface, int port)
792{
793 if (octeon_has_feature(OCTEON_FEATURE_PKND))
794 return __cvmx_helper_cfg_bpid(interface, port);
795
796 return CVMX_INVALID_BPID;
797}
798
799/**
Aaron Williams47652952020-12-11 17:06:01 +0100800 * Returns the interface number for an IPD/PKO port number.
801 *
802 * @param ipd_port IPD/PKO port number
803 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100804 * Return: Interface number
Aaron Williams47652952020-12-11 17:06:01 +0100805 */
806int cvmx_helper_get_interface_num(int ipd_port)
807{
808 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
809 const struct ipd_port_map *port_map;
810 int i;
811 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
812
813 port_map = ipd_port_map_68xx;
814 for (i = 0; i < CVMX_HELPER_MAX_IFACE; i++) {
815 if (xp.port >= port_map[i].first_ipd_port &&
816 xp.port <= port_map[i].last_ipd_port)
817 return i;
818 }
819 return -1;
820 } else if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
821 const struct ipd_port_map *port_map;
822 int i;
823 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
824
825 port_map = ipd_port_map_78xx;
826 for (i = 0; i < CVMX_HELPER_MAX_IFACE; i++) {
827 if (xp.port >= port_map[i].first_ipd_port &&
828 xp.port <= port_map[i].last_ipd_port)
829 return cvmx_helper_node_interface_to_xiface(xp.node, i);
830 }
831 return -1;
832 } else if (OCTEON_IS_MODEL(OCTEON_CN73XX)) {
833 const struct ipd_port_map *port_map;
834 int i;
835 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
836
837 port_map = ipd_port_map_73xx;
838 for (i = 0; i < CVMX_HELPER_MAX_IFACE; i++) {
839 if (xp.port >= port_map[i].first_ipd_port &&
840 xp.port <= port_map[i].last_ipd_port)
841 return i;
842 }
843 return -1;
844 } else if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) {
845 const struct ipd_port_map *port_map;
846 int i;
847 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
848
849 port_map = ipd_port_map_75xx;
850 for (i = 0; i < CVMX_HELPER_MAX_IFACE; i++) {
851 if (xp.port >= port_map[i].first_ipd_port &&
852 xp.port <= port_map[i].last_ipd_port)
853 return i;
854 }
855 return -1;
856 } else if (OCTEON_IS_MODEL(OCTEON_CN70XX) && ipd_port == 24) {
857 return 4;
858 }
859
860 if (ipd_port < 16)
861 return 0;
862 else if (ipd_port < 32)
863 return 1;
864 else if (ipd_port < 36)
865 return 2;
866 else if (ipd_port < 40)
867 return 3;
868 else if (ipd_port < 42)
869 return 4;
870 else if (ipd_port < 44)
871 return 5;
872 else if (ipd_port < 46)
873 return 6;
874 else if (ipd_port < 48)
875 return 7;
876
877 debug("%s: Illegal IPD port number %d\n", __func__, ipd_port);
878 return -1;
879}
880
881/**
882 * Returns the interface index number for an IPD/PKO port
883 * number.
884 *
885 * @param ipd_port IPD/PKO port number
886 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100887 * Return: Interface index number
Aaron Williams47652952020-12-11 17:06:01 +0100888 */
889int cvmx_helper_get_interface_index_num(int ipd_port)
890{
891 if (octeon_has_feature(OCTEON_FEATURE_PKND)) {
892 const struct ipd_port_map *port_map;
893 int port;
894 enum port_map_if_type type = INVALID_IF_TYPE;
895 int i;
896 int num_interfaces;
897
898 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
899 port_map = ipd_port_map_68xx;
900 } else if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
901 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
902
903 port_map = ipd_port_map_78xx;
904 ipd_port = xp.port;
905 } else if (OCTEON_IS_MODEL(OCTEON_CN73XX)) {
906 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
907
908 port_map = ipd_port_map_73xx;
909 ipd_port = xp.port;
910 } else if (OCTEON_IS_MODEL(OCTEON_CNF75XX)) {
911 struct cvmx_xport xp = cvmx_helper_ipd_port_to_xport(ipd_port);
912
913 port_map = ipd_port_map_75xx;
914 ipd_port = xp.port;
915 } else {
916 return -1;
917 }
918
919 num_interfaces = cvmx_helper_get_number_of_interfaces();
920
921 /* Get the interface type of the ipd port */
922 for (i = 0; i < num_interfaces; i++) {
923 if (ipd_port >= port_map[i].first_ipd_port &&
924 ipd_port <= port_map[i].last_ipd_port) {
925 type = port_map[i].type;
926 break;
927 }
928 }
929
930 /* Convert the ipd port to the interface port */
931 switch (type) {
932 /* Ethernet interfaces have a channel in lower 4 bits
933 * that is does not discriminate traffic, and is ignored.
934 */
935 case GMII:
936 port = ipd_port - port_map[i].first_ipd_port;
937
938 /* CN68XX adds 0x40 to IPD_PORT when in XAUI/RXAUI
939 * mode of operation, adjust for that case
940 */
941 if (port >= port_map[i].ipd_port_adj)
942 port -= port_map[i].ipd_port_adj;
943
944 port >>= 4;
945 return port;
946
947 /*
948 * These interfaces do not have physical ports,
949 * but have logical channels instead that separate
950 * traffic into logical streams
951 */
952 case ILK:
953 case SRIO:
954 case NPI:
955 case LB:
956 port = ipd_port - port_map[i].first_ipd_port;
957 return port;
958
959 default:
960 printf("ERROR: %s: Illegal IPD port number %#x\n",
961 __func__, ipd_port);
962 return -1;
963 }
964 }
965 if (OCTEON_IS_MODEL(OCTEON_CN70XX))
966 return ipd_port & 3;
967 if (ipd_port < 32)
968 return ipd_port & 15;
969 else if (ipd_port < 40)
970 return ipd_port & 3;
971 else if (ipd_port < 48)
972 return ipd_port & 1;
973
974 debug("%s: Illegal IPD port number\n", __func__);
975
976 return -1;
977}