blob: 6223ff2c84b266e45999df091d6f9dbd67215006 [file] [log] [blame]
Aaron Williams223d67e2022-04-07 09:11:32 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018-2022 Marvell International Ltd.
4 *
5 * Support library for the ILK
6 */
7
8#include <time.h>
9#include <log.h>
10#include <linux/delay.h>
11
12#include <mach/cvmx-regs.h>
13#include <mach/cvmx-csr.h>
14#include <mach/cvmx-bootmem.h>
15#include <mach/octeon-model.h>
16#include <mach/cvmx-fuse.h>
17#include <mach/octeon-feature.h>
18#include <mach/cvmx-qlm.h>
19#include <mach/octeon_qlm.h>
20#include <mach/cvmx-pcie.h>
21#include <mach/cvmx-coremask.h>
22
23#include <mach/cvmx-agl-defs.h>
24#include <mach/cvmx-bgxx-defs.h>
25#include <mach/cvmx-ciu-defs.h>
26#include <mach/cvmx-gmxx-defs.h>
27#include <mach/cvmx-gserx-defs.h>
28#include <mach/cvmx-ilk-defs.h>
29#include <mach/cvmx-ipd-defs.h>
30#include <mach/cvmx-pcsx-defs.h>
31#include <mach/cvmx-pcsxx-defs.h>
32#include <mach/cvmx-pki-defs.h>
33#include <mach/cvmx-pko-defs.h>
34#include <mach/cvmx-xcv-defs.h>
35
36#include <mach/cvmx-hwpko.h>
37#include <mach/cvmx-ilk.h>
38#include <mach/cvmx-pki.h>
39
40#include <mach/cvmx-helper.h>
41#include <mach/cvmx-helper-board.h>
42#include <mach/cvmx-helper-cfg.h>
43
44/*
45 * global configurations.
46 *
47 * for cn68, the default is {0xf, 0xf0}. to disable the 2nd ILK, set
48 * cvmx_ilk_lane_mask[CVMX_NUM_ILK_INTF] = {0xff, 0x0} and
49 * cvmx_ilk_chans[CVMX_NUM_ILK_INTF] = {8, 0}
50 */
51unsigned short cvmx_ilk_lane_mask[CVMX_MAX_NODES][CVMX_NUM_ILK_INTF] = {
52 [0 ... CVMX_MAX_NODES - 1] = { 0x000f, 0x00f0 }
53};
54
55int cvmx_ilk_chans[CVMX_MAX_NODES][CVMX_NUM_ILK_INTF] = {
56 [0 ... CVMX_MAX_NODES - 1] = { 8, 8 }
57};
58
59static cvmx_ilk_intf_t cvmx_ilk_intf_cfg[CVMX_MAX_NODES][CVMX_NUM_ILK_INTF];
60
61cvmx_ilk_LA_mode_t cvmx_ilk_LA_mode[CVMX_NUM_ILK_INTF] = { { 0, 0 }, { 0, 0 } };
62/**
63 * User-overrideable callback function that returns whether or not an interface
64 * should use look-aside mode.
65 *
66 * @param interface - interface being checked
67 * @param channel - channel number, can be 0 or 1 or -1 to see if LA mode
68 * should be enabled for the interface.
69 * @return 0 to not use LA-mode, 1 to use LA-mode.
70 */
71int cvmx_ilk_use_la_mode(int interface, int channel)
72{
73 if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_0))
74 return 0;
75
76 if (interface >= CVMX_NUM_ILK_INTF) {
77 debug("ERROR: invalid interface=%d in %s\n",
78 interface, __func__);
79 return -1;
80 }
81 return cvmx_ilk_LA_mode[interface].ilk_LA_mode;
82}
83
84/**
85 * User-overrideable callback function that returns whether or not an interface
86 * in look-aside mode should enable the RX calendar.
87 *
88 * @param interface - interface to check
89 * @return 1 to enable RX calendar, 0 to disable RX calendar.
90 *
91 * NOTE: For the CN68XX pass 2.0 this will enable the RX calendar for interface
92 * 0 and not interface 1. It is up to the customer to override this behavior.
93 */
94int cvmx_ilk_la_mode_enable_rx_calendar(int interface)
95{
96 /* There is an errata in the CN68XX pass 2.0 where if connected
97 * in a loopback configuration or back to back then only one interface
98 * can have the RX calendar enabled.
99 */
100 if (interface >= CVMX_NUM_ILK_INTF) {
101 debug("ERROR: invalid interface=%d in %s\n",
102 interface, __func__);
103 return -1;
104 }
105 return cvmx_ilk_LA_mode[interface].ilk_LA_mode_cal_ena;
106}
107
108/**
109 * Initialize and start the ILK interface.
110 *
111 * @param interface The identifier of the packet interface to configure and
112 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
113 * ilk1.
114 *
115 * @param lane_mask the lane group for this interface
116 *
117 * @return Zero on success, negative on failure.
118 */
119int cvmx_ilk_start_interface(int interface, unsigned short lane_mask)
120{
121 int res = -1;
122 int other_intf, this_qlm, other_qlm;
123 unsigned short uni_mask;
124 cvmx_ilk_txx_cfg0_t ilk_txx_cfg0;
125 cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0;
126 cvmx_ilk_ser_cfg_t ilk_ser_cfg;
127 int node = (interface >> 4) & 0xf;
128
129 interface &= 0xf;
130
131 if (!octeon_has_feature(OCTEON_FEATURE_ILK))
132 return res;
133
134 if (interface >= CVMX_NUM_ILK_INTF)
135 return res;
136
137 if (lane_mask == 0)
138 return res;
139
140 /* check conflicts between 2 ilk interfaces. 1 lane can be assigned to 1
141 * interface only
142 */
143 other_intf = !interface;
144 if (cvmx_ilk_lane_mask[node][other_intf] & lane_mask) {
145 debug("ILK%d:%d: %s: lane assignment conflict\n", node,
146 interface, __func__);
147 return res;
148 }
149
150 /* check the legality of the lane mask. interface 0 can have 8 lanes,
151 * while interface 1 can have 4 lanes at most
152 */
153 uni_mask = lane_mask >> (interface * 4);
154 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
155 cvmx_mio_qlmx_cfg_t mio_qlmx_cfg, other_mio_qlmx_cfg;
156
157 if ((uni_mask != 0x1 && uni_mask != 0x3 && uni_mask != 0xf &&
158 uni_mask != 0xff) ||
159 (interface == 1 && lane_mask > 0xf0)) {
160 debug("ILK%d: %s: incorrect lane mask: 0x%x\n",
161 interface, __func__, uni_mask);
162 return res;
163 }
164 /* check the availability of qlms. qlm_cfg = 001 means the chip
165 * is fused to give this qlm to ilk
166 */
167 this_qlm = interface + CVMX_ILK_QLM_BASE();
168 other_qlm = other_intf + CVMX_ILK_QLM_BASE();
169 mio_qlmx_cfg.u64 = csr_rd(CVMX_MIO_QLMX_CFG(this_qlm));
170 other_mio_qlmx_cfg.u64 = csr_rd(CVMX_MIO_QLMX_CFG(other_qlm));
171 if (mio_qlmx_cfg.s.qlm_cfg != 1 ||
172 (uni_mask == 0xff && other_mio_qlmx_cfg.s.qlm_cfg != 1)) {
173 debug("ILK%d: %s: qlm unavailable\n", interface,
174 __func__);
175 return res;
176 }
177 /* Has 8 lanes */
178 lane_mask &= 0xff;
179 }
180
181 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
182 int qlm;
183 unsigned short lane_mask_all = 0;
184
185 /* QLM 4 - QLM 7 can be configured for ILK. Get the lane mask
186 * of all the qlms that are configured for ilk
187 */
188 for (qlm = 4; qlm < 8; qlm++) {
189 cvmx_gserx_cfg_t gserx_cfg;
190 cvmx_gserx_phy_ctl_t phy_ctl;
191
192 /* Make sure QLM is powered and out of reset */
193 phy_ctl.u64 =
194 csr_rd_node(node, CVMX_GSERX_PHY_CTL(qlm));
195 if (phy_ctl.s.phy_pd || phy_ctl.s.phy_reset)
196 continue;
197
198 /* Make sure QLM is in ILK mode */
199 gserx_cfg.u64 = csr_rd_node(node, CVMX_GSERX_CFG(qlm));
200 if (gserx_cfg.s.ila)
201 lane_mask_all |= ((1 << 4) - 1)
202 << (4 * (qlm - 4));
203 }
204
205 if ((lane_mask_all & lane_mask) != lane_mask) {
206 debug("ILK%d: %s: incorrect lane mask: 0x%x\n",
207 interface, __func__, lane_mask);
208 return res;
209 }
210 }
211
212 /* power up the serdes */
213 ilk_ser_cfg.u64 = csr_rd_node(node, CVMX_ILK_SER_CFG);
214 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
215 if (ilk_ser_cfg.cn68xx.ser_pwrup == 0) {
216 ilk_ser_cfg.cn68xx.ser_rxpol_auto = 1;
217 ilk_ser_cfg.cn68xx.ser_rxpol = 0;
218 ilk_ser_cfg.cn68xx.ser_txpol = 0;
219 ilk_ser_cfg.cn68xx.ser_reset_n = 0xff;
220 ilk_ser_cfg.cn68xx.ser_haul = 0;
221 }
222 ilk_ser_cfg.cn68xx.ser_pwrup |=
223 ((interface == 0) && (lane_mask > 0xf)) ?
224 0x3 :
225 (1 << interface);
226 }
227 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
228 ilk_ser_cfg.cn78xx.ser_rxpol_auto = 1;
229 ilk_ser_cfg.cn78xx.ser_rxpol = 0;
230 ilk_ser_cfg.cn78xx.ser_txpol = 0;
231 ilk_ser_cfg.cn78xx.ser_reset_n = 0xffff;
232 }
233 csr_wr_node(node, CVMX_ILK_SER_CFG, ilk_ser_cfg.u64);
234
235 if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS2_X)) {
236 /* Workaround for Errata (G-16467) */
237 int qlm = (interface) ? 2 : 1;
238 int start_qlm, end_qlm;
239
240 /* Apply the workaround to both the QLMs if configured for x8 lanes */
241 if (cvmx_pop(lane_mask) > 4) {
242 start_qlm = 1;
243 end_qlm = 2;
244 } else {
245 start_qlm = qlm;
246 end_qlm = qlm;
247 }
248
249 for (qlm = start_qlm; qlm <= end_qlm; qlm++) {
250#ifdef CVMX_QLM_DUMP_STATE
251 debug("%s:%d: ILK%d: Applying workaround for Errata G-16467\n",
252 __func__, __LINE__, qlm);
253 cvmx_qlm_display_registers(qlm);
254 debug("\n");
255#endif
256 /* This workaround only applies to QLMs running ILK at 6.25Ghz */
257 if ((cvmx_qlm_get_gbaud_mhz(qlm) == 6250) &&
258 (cvmx_qlm_jtag_get(qlm, 0, "clkf_byp") != 20)) {
259 udelay(100); /* Wait 100us for links to stabalize */
260 cvmx_qlm_jtag_set(qlm, -1, "clkf_byp", 20);
261 /* Allow the QLM to exit reset */
262 cvmx_qlm_jtag_set(qlm, -1, "cfg_rst_n_clr", 0);
263 udelay(100); /* Wait 100us for links to stabalize */
264 /* Allow TX on QLM */
265 cvmx_qlm_jtag_set(qlm, -1, "cfg_tx_idle_set",
266 0);
267 }
268#ifdef CVMX_QLM_DUMP_STATE
269 debug("%s:%d: ILK%d: Done applying workaround for Errata G-16467\n",
270 __func__, __LINE__, qlm);
271 cvmx_qlm_display_registers(qlm);
272 debug("\n\n");
273#endif
274 }
275 }
276
277 /* Initialize all calendar entries to xoff state */
278 __cvmx_ilk_clear_cal((node << 4) | interface);
279
280 /* Enable ILK LA mode if configured. */
281 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
282 if (cvmx_ilk_use_la_mode(interface, 0)) {
283 cvmx_ilk_txx_cfg1_t ilk_txx_cfg1;
284 cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1;
285
286 ilk_txx_cfg1.u64 = csr_rd(CVMX_ILK_TXX_CFG1(interface));
287 ilk_rxx_cfg1.u64 = csr_rd(CVMX_ILK_RXX_CFG1(interface));
288 ilk_txx_cfg1.s.la_mode = 1;
289 ilk_txx_cfg1.s.tx_link_fc_jam = 1;
290 ilk_txx_cfg1.s.rx_link_fc_ign = 1;
291 ilk_rxx_cfg1.s.la_mode = 1;
292 csr_wr(CVMX_ILK_TXX_CFG1(interface), ilk_txx_cfg1.u64);
293 csr_wr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
294 cvmx_ilk_intf_cfg[node][interface].la_mode =
295 1; /* Enable look-aside mode */
296 } else {
297 cvmx_ilk_intf_cfg[node][interface].la_mode =
298 0; /* Disable look-aside mode */
299 }
300 }
301 if (OCTEON_IS_MODEL(OCTEON_CN78XX))
302 cvmx_ilk_intf_cfg[node][interface].la_mode = 0;
303
304 /* configure the lane enable of the interface */
305 ilk_txx_cfg0.u64 = csr_rd_node(node, CVMX_ILK_TXX_CFG0(interface));
306 ilk_rxx_cfg0.u64 = csr_rd_node(node, CVMX_ILK_RXX_CFG0(interface));
307 ilk_rxx_cfg0.s.lane_ena = lane_mask;
308 ilk_txx_cfg0.s.lane_ena = lane_mask;
309 csr_wr_node(node, CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64);
310 csr_wr_node(node, CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64);
311
312 /* For 10.3125Gbs data rate, set SER_LIMIT to 0x3ff for x8 & x12 mode */
313 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
314 cvmx_gserx_lane_mode_t lmode0, lmode1;
315
316 lmode0.u64 = csr_rd_node(node, CVMX_GSERX_LANE_MODE(5));
317 lmode1.u64 = csr_rd_node(node, CVMX_GSERX_LANE_MODE(7));
318 if ((lmode0.s.lmode == 5 || lmode1.s.lmode == 5) &&
319 (lane_mask == 0xfff || lane_mask == 0xfff0 ||
320 lane_mask == 0xff || lane_mask == 0xff00)) {
321 cvmx_ilk_txx_cfg1_t ilk_txx_cfg1;
322
323 ilk_txx_cfg1.u64 =
324 csr_rd_node(node, CVMX_ILK_TXX_CFG1(interface));
325 ilk_txx_cfg1.s.ser_limit = 0x3ff;
326 csr_wr_node(node, CVMX_ILK_TXX_CFG1(interface),
327 ilk_txx_cfg1.u64);
328 }
329 }
330
331 /* write to local cache. for lane speed, if interface 0 has 8 lanes,
332 * assume both qlms have the same speed
333 */
334 cvmx_ilk_intf_cfg[node][interface].intf_en = 1;
335 res = 0;
336
337 return res;
338}
339
340/**
341 * set pipe group base and length for the interface
342 *
343 * @param xiface The identifier of the packet interface to configure and
344 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
345 * ilk1.
346 *
347 * @param pipe_base the base of the pipe group
348 * @param pipe_len the length of the pipe group
349 *
350 * @return Zero on success, negative on failure.
351 */
352int cvmx_ilk_set_pipe(int xiface, int pipe_base, unsigned int pipe_len)
353{
354 int res = -1;
355 cvmx_ilk_txx_pipe_t ilk_txx_pipe;
356 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
357 int interface = xi.interface - CVMX_ILK_GBL_BASE();
358
359 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
360 return res;
361
362 if (interface >= CVMX_NUM_ILK_INTF)
363 return res;
364
365 /* set them in ilk tx section */
366 ilk_txx_pipe.u64 = csr_rd_node(xi.node, CVMX_ILK_TXX_PIPE(interface));
367 ilk_txx_pipe.s.base = pipe_base;
368 ilk_txx_pipe.s.nump = pipe_len;
369 csr_wr_node(xi.node, CVMX_ILK_TXX_PIPE(interface), ilk_txx_pipe.u64);
370 res = 0;
371
372 return res;
373}
374
375/**
376 * set logical channels for tx
377 *
378 * @param interface The identifier of the packet interface to configure and
379 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
380 * ilk1.
381 *
382 * @param pch pointer to an array of pipe-channel pair
383 * @param num_chs the number of entries in the pipe-channel array
384 *
385 * @return Zero on success, negative on failure.
386 */
387int cvmx_ilk_tx_set_channel(int interface, cvmx_ilk_pipe_chan_t *pch,
388 unsigned int num_chs)
389{
390 int res = -1;
391 cvmx_ilk_txx_idx_pmap_t ilk_txx_idx_pmap;
392 cvmx_ilk_txx_mem_pmap_t ilk_txx_mem_pmap;
393 unsigned int i;
394
395 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
396 return res;
397
398 if (interface >= CVMX_NUM_ILK_INTF)
399 return res;
400
401 if (!pch || num_chs > CVMX_ILK_MAX_PIPES)
402 return res;
403
404 if (cvmx_ilk_use_la_mode(interface, 0)) {
405 ilk_txx_idx_pmap.u64 = 0;
406 ilk_txx_mem_pmap.u64 = 0;
407 for (i = 0; i < num_chs; i++) {
408 ilk_txx_idx_pmap.s.index = pch->pipe;
409 ilk_txx_mem_pmap.s.channel = pch->chan;
410 ilk_txx_mem_pmap.s.remap = 1;
411 csr_wr(CVMX_ILK_TXX_IDX_PMAP(interface),
412 ilk_txx_idx_pmap.u64);
413 csr_wr(CVMX_ILK_TXX_MEM_PMAP(interface),
414 ilk_txx_mem_pmap.u64);
415 pch++;
416 }
417 } else {
418 /* write the pair to ilk tx */
419 ilk_txx_mem_pmap.u64 = 0;
420 ilk_txx_idx_pmap.u64 = 0;
421 for (i = 0; i < num_chs; i++) {
422 ilk_txx_idx_pmap.s.index = pch->pipe;
423 ilk_txx_mem_pmap.s.channel = pch->chan;
424 csr_wr(CVMX_ILK_TXX_IDX_PMAP(interface),
425 ilk_txx_idx_pmap.u64);
426 csr_wr(CVMX_ILK_TXX_MEM_PMAP(interface),
427 ilk_txx_mem_pmap.u64);
428 pch++;
429 }
430 }
431 res = 0;
432
433 return res;
434}
435
436/**
437 * set pkind for rx
438 *
439 * @param xiface The identifier of the packet interface to configure and
440 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
441 * ilk1.
442 *
443 * @param chpknd pointer to an array of channel-pkind pair
444 * @param num_pknd the number of entries in the channel-pkind array
445 *
446 * @return Zero on success, negative on failure.
447 */
448int cvmx_ilk_rx_set_pknd(int xiface, cvmx_ilk_chan_pknd_t *chpknd,
449 unsigned int num_pknd)
450{
451 int res = -1;
452 cvmx_ilk_rxf_idx_pmap_t ilk_rxf_idx_pmap;
453 unsigned int i;
454 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
455 int interface = xi.interface - CVMX_ILK_GBL_BASE();
456
457 if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
458 return res;
459
460 if (interface >= CVMX_NUM_ILK_INTF)
461 return res;
462
463 if (!chpknd || num_pknd > CVMX_ILK_MAX_PKNDS)
464 return res;
465
466 res = 0;
467
468 for (i = 0; i < num_pknd; i++) {
469 ilk_rxf_idx_pmap.u64 = 0;
470 /* write the pair to ilk rx. note the channels for different
471 * interfaces are given in *chpknd and interface is not used
472 * as a param
473 */
474 if (chpknd->chan < 2 &&
475 cvmx_ilk_use_la_mode(interface, chpknd->chan)) {
476 ilk_rxf_idx_pmap.s.index =
477 interface * 256 + 128 + chpknd->chan;
478 csr_wr(CVMX_ILK_RXF_IDX_PMAP, ilk_rxf_idx_pmap.u64);
479 csr_wr(CVMX_ILK_RXF_MEM_PMAP, chpknd->pknd);
480 }
481 ilk_rxf_idx_pmap.s.index = interface * 256 + chpknd->chan;
482 csr_wr(CVMX_ILK_RXF_IDX_PMAP, ilk_rxf_idx_pmap.u64);
483 csr_wr(CVMX_ILK_RXF_MEM_PMAP, chpknd->pknd);
484 chpknd++;
485 }
486
487 return res;
488}
489
490/**
491 * configure calendar for rx
492 *
493 * @param intf The identifier of the packet interface to configure and
494 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
495 * ilk1.
496 *
497 * @param cal_depth the number of calendar entries
498 * @param pent pointer to calendar entries
499 *
500 * @return Zero on success, negative on failure.
501 */
502int cvmx_ilk_rx_cal_conf(int intf, int cal_depth, cvmx_ilk_cal_entry_t *pent)
503{
504 int res = -1, i;
505 cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0;
506 int num_entries;
507 int node = (intf >> 4) & 0xf;
508 int interface = intf & 0xf;
509
510 if (!octeon_has_feature(OCTEON_FEATURE_ILK))
511 return res;
512
513 if (interface >= CVMX_NUM_ILK_INTF)
514 return res;
515
516 if (cal_depth < CVMX_ILK_RX_MIN_CAL || cal_depth > CVMX_ILK_MAX_CAL ||
517 (OCTEON_IS_MODEL(OCTEON_CN68XX) && !pent))
518 return res;
519
520 /* mandatory link-level fc as workarounds for ILK-15397 and
521 * ILK-15479
522 */
523 /* TODO: test effectiveness */
524
525 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
526 /* Update the calendar for each channel */
527 if ((cvmx_ilk_use_la_mode(interface, 0) == 0) ||
528 (cvmx_ilk_use_la_mode(interface, 0) &&
529 cvmx_ilk_la_mode_enable_rx_calendar(interface))) {
530 for (i = 0; i < cal_depth; i++) {
531 __cvmx_ilk_write_rx_cal_entry(
532 interface, i, pent[i].pipe_bpid);
533 }
534 }
535
536 /* Update the depth */
537 ilk_rxx_cfg0.u64 = csr_rd(CVMX_ILK_RXX_CFG0(interface));
538 num_entries = 1 + cal_depth + (cal_depth - 1) / 15;
539 ilk_rxx_cfg0.s.cal_depth = num_entries;
540 if (cvmx_ilk_use_la_mode(interface, 0)) {
541 ilk_rxx_cfg0.s.mproto_ign = 1;
542 ilk_rxx_cfg0.s.lnk_stats_ena = 1;
543 ilk_rxx_cfg0.s.lnk_stats_wrap = 1;
544 }
545 csr_wr(CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64);
546 }
547
548 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
549 ilk_rxx_cfg0.u64 =
550 csr_rd_node(node, CVMX_ILK_RXX_CFG0(interface));
551 /*
552 * Make sure cal_ena is 0 for programming the calendar table,
553 * as per Errata ILK-19398
554 */
555 ilk_rxx_cfg0.s.cal_ena = 0;
556 csr_wr_node(node, CVMX_ILK_RXX_CFG0(interface),
557 ilk_rxx_cfg0.u64);
558
559 for (i = 0; i < cal_depth; i++)
560 __cvmx_ilk_write_rx_cal_entry(intf, i, 0);
561
562 ilk_rxx_cfg0.u64 =
563 csr_rd_node(node, CVMX_ILK_RXX_CFG0(interface));
564 num_entries = 1 + cal_depth + (cal_depth - 1) / 15;
565 ilk_rxx_cfg0.s.cal_depth = num_entries;
566 csr_wr_node(node, CVMX_ILK_RXX_CFG0(interface),
567 ilk_rxx_cfg0.u64);
568 }
569
570 return 0;
571}
572
573/**
574 * set high water mark for rx
575 *
576 * @param intf The identifier of the packet interface to configure and
577 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
578 * ilk1.
579 *
580 * @param hi_wm high water mark for this interface
581 *
582 * @return Zero on success, negative on failure.
583 */
584int cvmx_ilk_rx_set_hwm(int intf, int hi_wm)
585{
586 int res = -1;
587 cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1;
588 int node = (intf >> 4) & 0xf;
589 int interface = intf & 0xf;
590
591 if (!octeon_has_feature(OCTEON_FEATURE_ILK))
592 return res;
593
594 if (interface >= CVMX_NUM_ILK_INTF)
595 return res;
596
597 if (hi_wm <= 0)
598 return res;
599
600 /* set the hwm */
601 ilk_rxx_cfg1.u64 = csr_rd_node(node, CVMX_ILK_RXX_CFG1(interface));
602 ilk_rxx_cfg1.s.rx_fifo_hwm = hi_wm;
603 csr_wr_node(node, CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
604 res = 0;
605
606 return res;
607}
608
609/**
610 * enable calendar for rx
611 *
612 * @param intf The identifier of the packet interface to configure and
613 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
614 * ilk1.
615 *
616 * @param cal_ena enable or disable calendar
617 *
618 * @return Zero on success, negative on failure.
619 */
620int cvmx_ilk_rx_cal_ena(int intf, unsigned char cal_ena)
621{
622 int res = -1;
623 cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0;
624 int node = (intf >> 4) & 0xf;
625 int interface = intf & 0xf;
626
627 if (!octeon_has_feature(OCTEON_FEATURE_ILK))
628 return res;
629
630 if (interface >= CVMX_NUM_ILK_INTF)
631 return res;
632
633 if (cvmx_ilk_use_la_mode(interface, 0) &&
634 !cvmx_ilk_la_mode_enable_rx_calendar(interface))
635 return 0;
636
637 /* set the enable */
638 ilk_rxx_cfg0.u64 = csr_rd_node(node, CVMX_ILK_RXX_CFG0(interface));
639 ilk_rxx_cfg0.s.cal_ena = cal_ena;
640 csr_wr_node(node, CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64);
641 csr_rd_node(node, CVMX_ILK_RXX_CFG0(interface));
642 res = 0;
643
644 return res;
645}
646
647/**
648 * set up calendar for rx
649 *
650 * @param intf The identifier of the packet interface to configure and
651 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
652 * ilk1.
653 *
654 * @param cal_depth the number of calendar entries
655 * @param pent pointer to calendar entries
656 * @param hi_wm high water mark for this interface
657 * @param cal_ena enable or disable calendar
658 *
659 * @return Zero on success, negative on failure.
660 */
661int cvmx_ilk_cal_setup_rx(int intf, int cal_depth, cvmx_ilk_cal_entry_t *pent,
662 int hi_wm, unsigned char cal_ena)
663{
664 int res = -1;
665
666 if (!octeon_has_feature(OCTEON_FEATURE_ILK))
667 return res;
668
669 res = cvmx_ilk_rx_cal_conf(intf, cal_depth, pent);
670 if (res < 0)
671 return res;
672
673 res = cvmx_ilk_rx_set_hwm(intf, hi_wm);
674 if (res < 0)
675 return res;
676
677 res = cvmx_ilk_rx_cal_ena(intf, cal_ena);
678 return res;
679}
680
681/**
682 * configure calendar for tx
683 *
684 * @param intf The identifier of the packet interface to configure and
685 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
686 * ilk1.
687 *
688 * @param cal_depth the number of calendar entries
689 * @param pent pointer to calendar entries
690 *
691 * @return Zero on success, negative on failure.
692 */
693int cvmx_ilk_tx_cal_conf(int intf, int cal_depth, cvmx_ilk_cal_entry_t *pent)
694{
695 int res = -1, i;
696 cvmx_ilk_txx_cfg0_t ilk_txx_cfg0;
697 int num_entries;
698 int node = (intf >> 4) & 0xf;
699 int interface = intf & 0xf;
700
701 if (!octeon_has_feature(OCTEON_FEATURE_ILK))
702 return res;
703
704 if (interface >= CVMX_NUM_ILK_INTF)
705 return res;
706
707 if (cal_depth < CVMX_ILK_TX_MIN_CAL || cal_depth > CVMX_ILK_MAX_CAL ||
708 (OCTEON_IS_MODEL(OCTEON_CN68XX) && !pent))
709 return res;
710
711 /* mandatory link-level fc as workarounds for ILK-15397 and
712 * ILK-15479
713 */
714 /* TODO: test effectiveness */
715
716 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
717 /* Update the calendar for each channel */
718 for (i = 0; i < cal_depth; i++) {
719 __cvmx_ilk_write_tx_cal_entry(interface, i,
720 pent[i].pipe_bpid);
721 }
722
723 /* Set the depth (must be multiple of 8)*/
724 ilk_txx_cfg0.u64 = csr_rd(CVMX_ILK_TXX_CFG0(interface));
725 num_entries = 1 + cal_depth + (cal_depth - 1) / 15;
726 ilk_txx_cfg0.s.cal_depth = (num_entries + 7) & ~7;
727 csr_wr(CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64);
728 }
729
730 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
731 ilk_txx_cfg0.u64 =
732 csr_rd_node(node, CVMX_ILK_TXX_CFG0(interface));
733 /*
734 * Make sure cal_ena is 0 for programming the calendar table,
735 * as per Errata ILK-19398
736 */
737 ilk_txx_cfg0.s.cal_ena = 0;
738 csr_wr_node(node, CVMX_ILK_TXX_CFG0(interface),
739 ilk_txx_cfg0.u64);
740
741 for (i = 0; i < cal_depth; i++)
742 __cvmx_ilk_write_tx_cal_entry(intf, i, 0);
743
744 ilk_txx_cfg0.u64 =
745 csr_rd_node(node, CVMX_ILK_TXX_CFG0(interface));
746 num_entries = 1 + cal_depth + (cal_depth - 1) / 15;
747 /* cal_depth[2:0] needs to be zero, round up */
748 ilk_txx_cfg0.s.cal_depth = (num_entries + 7) & 0x1f8;
749 csr_wr_node(node, CVMX_ILK_TXX_CFG0(interface),
750 ilk_txx_cfg0.u64);
751 }
752
753 return 0;
754}
755
756/**
757 * enable calendar for tx
758 *
759 * @param intf The identifier of the packet interface to configure and
760 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
761 * ilk1.
762 *
763 * @param cal_ena enable or disable calendar
764 *
765 * @return Zero on success, negative on failure.
766 */
767int cvmx_ilk_tx_cal_ena(int intf, unsigned char cal_ena)
768{
769 int res = -1;
770 cvmx_ilk_txx_cfg0_t ilk_txx_cfg0;
771 int node = (intf >> 4) & 0xf;
772 int interface = intf & 0xf;
773
774 if (!octeon_has_feature(OCTEON_FEATURE_ILK))
775 return res;
776
777 if (interface >= CVMX_NUM_ILK_INTF)
778 return res;
779
780 /* set the enable */
781 ilk_txx_cfg0.u64 = csr_rd_node(node, CVMX_ILK_TXX_CFG0(interface));
782 ilk_txx_cfg0.s.cal_ena = cal_ena;
783 csr_wr_node(node, CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64);
784 csr_rd_node(node, CVMX_ILK_TXX_CFG0(interface));
785 res = 0;
786
787 return res;
788}
789
790/**
791 * set up calendar for tx
792 *
793 * @param intf The identifier of the packet interface to configure and
794 * use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
795 * ilk1.
796 *
797 * @param cal_depth the number of calendar entries
798 * @param pent pointer to calendar entries
799 * @param cal_ena enable or disable calendar
800 *
801 * @return Zero on success, negative on failure.
802 */
803int cvmx_ilk_cal_setup_tx(int intf, int cal_depth, cvmx_ilk_cal_entry_t *pent,
804 unsigned char cal_ena)
805{
806 int res = -1;
807
808 if (!octeon_has_feature(OCTEON_FEATURE_ILK))
809 return res;
810
811 res = cvmx_ilk_tx_cal_conf(intf, cal_depth, pent);
812 if (res < 0)
813 return res;
814
815 res = cvmx_ilk_tx_cal_ena(intf, cal_ena);
816 return res;
817}
818
819/* #define CVMX_ILK_STATS_ENA 1 */
820#ifdef CVMX_ILK_STATS_ENA
821static void cvmx_ilk_reg_dump_rx(int intf)
822{
823 int i;
824 cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0;
825 cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1;
826 cvmx_ilk_rxx_int_t ilk_rxx_int;
827 cvmx_ilk_rxx_jabber_t ilk_rxx_jabber;
828 cvmx_ilk_rx_lnex_cfg_t ilk_rx_lnex_cfg;
829 cvmx_ilk_rx_lnex_int_t ilk_rx_lnex_int;
830 cvmx_ilk_gbl_cfg_t ilk_gbl_cfg;
831 cvmx_ilk_ser_cfg_t ilk_ser_cfg;
832 cvmx_ilk_rxf_idx_pmap_t ilk_rxf_idx_pmap;
833 cvmx_ilk_rxf_mem_pmap_t ilk_rxf_mem_pmap;
834 cvmx_ilk_rxx_idx_cal_t ilk_rxx_idx_cal;
835 cvmx_ilk_rxx_mem_cal0_t ilk_rxx_mem_cal0;
836 cvmx_ilk_rxx_mem_cal1_t ilk_rxx_mem_cal1;
837 int node = (intf >> 4) & 0xf;
838 int interface = intf & 0xf;
839
840 ilk_rxx_cfg0.u64 = csr_rd_node(node, CVMX_ILK_RXX_CFG0(interface));
841 debug("ilk rxx cfg0: 0x%16lx\n", ilk_rxx_cfg0.u64);
842
843 ilk_rxx_cfg1.u64 = csr_rd_node(node, CVMX_ILK_RXX_CFG1(interface));
844 debug("ilk rxx cfg1: 0x%16lx\n", ilk_rxx_cfg1.u64);
845
846 ilk_rxx_int.u64 = csr_rd_node(node, CVMX_ILK_RXX_INT(interface));
847 debug("ilk rxx int: 0x%16lx\n", ilk_rxx_int.u64);
848 csr_wr_node(node, CVMX_ILK_RXX_INT(interface), ilk_rxx_int.u64);
849
850 ilk_rxx_jabber.u64 = csr_rd_node(node, CVMX_ILK_RXX_JABBER(interface));
851 debug("ilk rxx jabber: 0x%16lx\n", ilk_rxx_jabber.u64);
852
853#define LNE_NUM_DBG 4
854 for (i = 0; i < LNE_NUM_DBG; i++) {
855 ilk_rx_lnex_cfg.u64 =
856 csr_rd_node(node, CVMX_ILK_RX_LNEX_CFG(i));
857 debug("ilk rx lnex cfg lane: %d 0x%16lx\n", i,
858 ilk_rx_lnex_cfg.u64);
859 }
860
861 for (i = 0; i < LNE_NUM_DBG; i++) {
862 ilk_rx_lnex_int.u64 =
863 csr_rd_node(node, CVMX_ILK_RX_LNEX_INT(i));
864 debug("ilk rx lnex int lane: %d 0x%16lx\n", i,
865 ilk_rx_lnex_int.u64);
866 csr_wr_node(node, CVMX_ILK_RX_LNEX_INT(i), ilk_rx_lnex_int.u64);
867 }
868
869 ilk_gbl_cfg.u64 = csr_rd_node(node, CVMX_ILK_GBL_CFG);
870 debug("ilk gbl cfg: 0x%16lx\n", ilk_gbl_cfg.u64);
871
872 ilk_ser_cfg.u64 = csr_rd_node(node, CVMX_ILK_SER_CFG);
873 debug("ilk ser cfg: 0x%16lx\n", ilk_ser_cfg.u64);
874
875#define CHAN_NUM_DBG 8
876 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
877 ilk_rxf_idx_pmap.u64 = 0;
878 ilk_rxf_idx_pmap.s.index = interface * 256;
879 ilk_rxf_idx_pmap.s.inc = 1;
880 csr_wr(CVMX_ILK_RXF_IDX_PMAP, ilk_rxf_idx_pmap.u64);
881 for (i = 0; i < CHAN_NUM_DBG; i++) {
882 ilk_rxf_mem_pmap.u64 = csr_rd(CVMX_ILK_RXF_MEM_PMAP);
883 debug("ilk rxf mem pmap chan: %3d 0x%16lx\n", i,
884 ilk_rxf_mem_pmap.u64);
885 }
886 }
887 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
888 cvmx_ilk_rxx_chax_t rxx_chax;
889
890 for (i = 0; i < CHAN_NUM_DBG; i++) {
891 rxx_chax.u64 = csr_rd_node(
892 node, CVMX_ILK_RXX_CHAX(i, interface));
893 debug("ilk chan: %d pki chan: 0x%x\n", i,
894 rxx_chax.s.port_kind);
895 }
896 }
897
898#define CAL_NUM_DBG 2
899 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
900 ilk_rxx_idx_cal.u64 = 0;
901 ilk_rxx_idx_cal.s.inc = 1;
902 csr_wr(CVMX_ILK_RXX_IDX_CAL(interface), ilk_rxx_idx_cal.u64);
903 for (i = 0; i < CAL_NUM_DBG; i++) {
904 ilk_rxx_idx_cal.u64 =
905 csr_rd(CVMX_ILK_RXX_IDX_CAL(interface));
906 debug("ilk rxx idx cal: 0x%16lx\n",
907 ilk_rxx_idx_cal.u64);
908
909 ilk_rxx_mem_cal0.u64 =
910 csr_rd(CVMX_ILK_RXX_MEM_CAL0(interface));
911 debug("ilk rxx mem cal0: 0x%16lx\n",
912 ilk_rxx_mem_cal0.u64);
913 ilk_rxx_mem_cal1.u64 =
914 csr_rd(CVMX_ILK_RXX_MEM_CAL1(interface));
915 debug("ilk rxx mem cal1: 0x%16lx\n",
916 ilk_rxx_mem_cal1.u64);
917 }
918 }
919 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
920 cvmx_ilk_rxx_cal_entryx_t rxx_cal_entryx;
921
922 for (i = 0; i < CAL_NUM_DBG; i++) {
923 rxx_cal_entryx.u64 = csr_rd_node(
924 node, CVMX_ILK_RXX_CAL_ENTRYX(i, interface));
925 debug("ilk rxx cal idx: %d\n", i);
926 debug("ilk rxx cal ctl: 0x%x\n", rxx_cal_entryx.s.ctl);
927 debug("ilk rxx cal pko chan: 0x%x\n",
928 rxx_cal_entryx.s.channel);
929 }
930 }
931}
932
933static void cvmx_ilk_reg_dump_tx(int intf)
934{
935 int i;
936 cvmx_ilk_txx_cfg0_t ilk_txx_cfg0;
937 cvmx_ilk_txx_cfg1_t ilk_txx_cfg1;
938 cvmx_ilk_txx_idx_pmap_t ilk_txx_idx_pmap;
939 cvmx_ilk_txx_mem_pmap_t ilk_txx_mem_pmap;
940 cvmx_ilk_txx_int_t ilk_txx_int;
941 cvmx_ilk_txx_pipe_t ilk_txx_pipe;
942 cvmx_ilk_txx_idx_cal_t ilk_txx_idx_cal;
943 cvmx_ilk_txx_mem_cal0_t ilk_txx_mem_cal0;
944 cvmx_ilk_txx_mem_cal1_t ilk_txx_mem_cal1;
945 int node = (intf >> 4) & 0xf;
946 int interface = intf & 0xf;
947
948 ilk_txx_cfg0.u64 = csr_rd_node(node, CVMX_ILK_TXX_CFG0(interface));
949 debug("ilk txx cfg0: 0x%16lx\n", ilk_txx_cfg0.u64);
950
951 ilk_txx_cfg1.u64 = csr_rd_node(node, CVMX_ILK_TXX_CFG1(interface));
952 debug("ilk txx cfg1: 0x%16lx\n", ilk_txx_cfg1.u64);
953
954 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
955 ilk_txx_pipe.u64 = csr_rd(CVMX_ILK_TXX_PIPE(interface));
956 debug("ilk txx pipe: 0x%16lx\n", ilk_txx_pipe.u64);
957
958 ilk_txx_idx_pmap.u64 = 0;
959 ilk_txx_idx_pmap.s.index = ilk_txx_pipe.s.base;
960 ilk_txx_idx_pmap.s.inc = 1;
961 csr_wr(CVMX_ILK_TXX_IDX_PMAP(interface), ilk_txx_idx_pmap.u64);
962 for (i = 0; i < CHAN_NUM_DBG; i++) {
963 ilk_txx_mem_pmap.u64 =
964 csr_rd(CVMX_ILK_TXX_MEM_PMAP(interface));
965 debug("ilk txx mem pmap pipe: %3d 0x%16lx\n",
966 ilk_txx_pipe.s.base + i, ilk_txx_mem_pmap.u64);
967 }
968 }
969
970 ilk_txx_int.u64 = csr_rd_node(node, CVMX_ILK_TXX_INT(interface));
971 debug("ilk txx int: 0x%16lx\n", ilk_txx_int.u64);
972
973 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
974 ilk_txx_idx_cal.u64 = 0;
975 ilk_txx_idx_cal.s.inc = 1;
976 csr_wr(CVMX_ILK_TXX_IDX_CAL(interface), ilk_txx_idx_cal.u64);
977 for (i = 0; i < CAL_NUM_DBG; i++) {
978 ilk_txx_idx_cal.u64 =
979 csr_rd(CVMX_ILK_TXX_IDX_CAL(interface));
980 debug("ilk txx idx cal: 0x%16lx\n",
981 ilk_txx_idx_cal.u64);
982
983 ilk_txx_mem_cal0.u64 =
984 csr_rd(CVMX_ILK_TXX_MEM_CAL0(interface));
985 debug("ilk txx mem cal0: 0x%16lx\n",
986 ilk_txx_mem_cal0.u64);
987 ilk_txx_mem_cal1.u64 =
988 csr_rd(CVMX_ILK_TXX_MEM_CAL1(interface));
989 debug("ilk txx mem cal1: 0x%16lx\n",
990 ilk_txx_mem_cal1.u64);
991 }
992 }
993 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
994 cvmx_ilk_txx_cal_entryx_t txx_cal_entryx;
995
996 for (i = 0; i < CAL_NUM_DBG; i++) {
997 txx_cal_entryx.u64 = csr_rd_node(
998 node, CVMX_ILK_TXX_CAL_ENTRYX(i, interface));
999 debug("ilk txx cal idx: %d\n", i);
1000 debug("ilk txx cal ctl: 0x%x\n", txx_cal_entryx.s.ctl);
1001 debug("ilk txx cal pki chan: 0x%x\n",
1002 txx_cal_entryx.s.channel);
1003 }
1004 }
1005}
1006#endif
1007
1008/**
1009 * show run time status
1010 *
1011 * @param interface The identifier of the packet interface to enable. cn68xx
1012 * has 2 interfaces: ilk0 and ilk1.
1013 *
1014 * @return nothing
1015 */
1016#ifdef CVMX_ILK_RUNTIME_DBG
1017void cvmx_ilk_runtime_status(int interface)
1018{
1019 cvmx_ilk_txx_cfg1_t ilk_txx_cfg1;
1020 cvmx_ilk_txx_flow_ctl0_t ilk_txx_flow_ctl0;
1021 cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1;
1022 cvmx_ilk_rxx_int_t ilk_rxx_int;
1023 cvmx_ilk_rxx_flow_ctl0_t ilk_rxx_flow_ctl0;
1024 cvmx_ilk_rxx_flow_ctl1_t ilk_rxx_flow_ctl1;
1025 cvmx_ilk_gbl_int_t ilk_gbl_int;
1026
1027 debug("\nilk run-time status: interface: %d\n", interface);
1028
1029 ilk_txx_cfg1.u64 = csr_rd_node(node, CVMX_ILK_TXX_CFG1(interface));
1030 debug("\nilk txx cfg1: 0x%16lx\n", ilk_txx_cfg1.u64);
1031 if (ilk_txx_cfg1.s.rx_link_fc)
1032 debug("link flow control received\n");
1033 if (ilk_txx_cfg1.s.tx_link_fc)
1034 debug("link flow control sent\n");
1035
1036 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
1037 ilk_txx_flow_ctl0.u64 =
1038 csr_rd(CVMX_ILK_TXX_FLOW_CTL0(interface));
1039 debug("\nilk txx flow ctl0: 0x%16lx\n", ilk_txx_flow_ctl0.u64);
1040 }
1041 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
1042 int i;
1043 cvmx_ilk_txx_cha_xonx_t txx_cha_xonx;
1044
1045 for (i = 0; i < 4; i++) {
1046 txx_cha_xonx.u64 = csr_rd_node(
1047 node, CVMX_ILK_TXX_CHA_XONX(i, interface));
1048 debug("\nilk txx cha xon: 0x%16lx\n", txx_cha_xonx.u64);
1049 }
1050 }
1051
1052 ilk_rxx_cfg1.u64 = csr_rd_node(node, CVMX_ILK_RXX_CFG1(interface));
1053 debug("\nilk rxx cfg1: 0x%16lx\n", ilk_rxx_cfg1.u64);
1054 debug("rx fifo count: %d\n", ilk_rxx_cfg1.s.rx_fifo_cnt);
1055
1056 ilk_rxx_int.u64 = csr_rd_node(node, CVMX_ILK_RXX_INT(interface));
1057 debug("\nilk rxx int: 0x%16lx\n", ilk_rxx_int.u64);
1058 if (ilk_rxx_int.s.pkt_drop_rxf)
1059 debug("rx fifo packet drop\n");
1060 if (ilk_rxx_int.u64)
1061 csr_wr_node(node, CVMX_ILK_RXX_INT(interface), ilk_rxx_int.u64);
1062
1063 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
1064 ilk_rxx_flow_ctl0.u64 =
1065 csr_rd(CVMX_ILK_RXX_FLOW_CTL0(interface));
1066 debug("\nilk rxx flow ctl0: 0x%16lx\n", ilk_rxx_flow_ctl0.u64);
1067
1068 ilk_rxx_flow_ctl1.u64 =
1069 csr_rd(CVMX_ILK_RXX_FLOW_CTL1(interface));
1070 debug("\nilk rxx flow ctl1: 0x%16lx\n", ilk_rxx_flow_ctl1.u64);
1071 }
1072 if (OCTEON_IS_MODEL(OCTEON_CN78XX)) {
1073 int i;
1074 cvmx_ilk_rxx_cha_xonx_t rxx_cha_xonx;
1075
1076 for (i = 0; i < 4; i++) {
1077 rxx_cha_xonx.u64 = csr_rd_node(
1078 node, CVMX_ILK_RXX_CHA_XONX(i, interface));
1079 debug("\nilk rxx cha xon: 0x%16lx\n", rxx_cha_xonx.u64);
1080 }
1081 }
1082
1083 ilk_gbl_int.u64 = csr_rd_node(node, CVMX_ILK_GBL_INT);
1084 debug("\nilk gbl int: 0x%16lx\n", ilk_gbl_int.u64);
1085 if (ilk_gbl_int.s.rxf_push_full)
1086 debug("rx fifo overflow\n");
1087 if (ilk_gbl_int.u64)
1088 csr_wr_node(node, CVMX_ILK_GBL_INT, ilk_gbl_int.u64);
1089}
1090#endif
1091
1092/**
1093 * enable interface
1094 *
1095 * @param xiface The identifier of the packet interface to enable. cn68xx
1096 * has 2 interfaces: ilk0 and ilk1.
1097 *
1098 * @return Zero on success, negative on failure.
1099 */
1100int cvmx_ilk_enable(int xiface)
1101{
1102 int res = -1;
1103 int retry_count = 0;
1104 cvmx_helper_link_info_t result;
1105 cvmx_ilk_txx_cfg1_t ilk_txx_cfg1;
1106 cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1;
1107#ifdef CVMX_ILK_STATS_ENA
1108 cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0;
1109 cvmx_ilk_txx_cfg0_t ilk_txx_cfg0;
1110#endif
1111 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
1112 int node = xi.node;
1113 int interface = xi.interface - CVMX_ILK_GBL_BASE();
1114
1115 if (!octeon_has_feature(OCTEON_FEATURE_ILK))
1116 return res;
1117
1118 if (interface >= CVMX_NUM_ILK_INTF)
1119 return res;
1120
1121 result.u64 = 0;
1122
1123#ifdef CVMX_ILK_STATS_ENA
1124 debug("\n");
1125 debug("<<<< ILK%d: Before enabling ilk\n", interface);
1126 cvmx_ilk_reg_dump_rx(intf);
1127 cvmx_ilk_reg_dump_tx(intf);
1128#endif
1129
1130 /* RX packet will be enabled only if link is up */
1131
1132 /* TX side */
1133 ilk_txx_cfg1.u64 = csr_rd_node(node, CVMX_ILK_TXX_CFG1(interface));
1134 ilk_txx_cfg1.s.pkt_ena = 1;
1135 if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
1136 if (cvmx_ilk_use_la_mode(interface, 0)) {
1137 ilk_txx_cfg1.s.la_mode = 1;
1138 ilk_txx_cfg1.s.tx_link_fc_jam = 1;
1139 }
1140 }
1141 csr_wr_node(node, CVMX_ILK_TXX_CFG1(interface), ilk_txx_cfg1.u64);
1142 csr_rd_node(node, CVMX_ILK_TXX_CFG1(interface));
1143
1144#ifdef CVMX_ILK_STATS_ENA
1145 /* RX side stats */
1146 ilk_rxx_cfg0.u64 = csr_rd_node(node, CVMX_ILK_RXX_CFG0(interface));
1147 ilk_rxx_cfg0.s.lnk_stats_ena = 1;
1148 csr_wr_node(node, CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64);
1149
1150 /* TX side stats */
1151 ilk_txx_cfg0.u64 = csr_rd_node(node, CVMX_ILK_TXX_CFG0(interface));
1152 ilk_txx_cfg0.s.lnk_stats_ena = 1;
1153 csr_wr_node(node, CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64);
1154#endif
1155
1156retry:
1157 retry_count++;
1158 if (retry_count > 10)
1159 goto out;
1160
1161 /* Make sure the link is up, so that packets can be sent. */
1162 result = __cvmx_helper_ilk_link_get(
1163 cvmx_helper_get_ipd_port((interface + CVMX_ILK_GBL_BASE()), 0));
1164
1165 /* Small delay before another retry. */
1166 udelay(100);
1167
1168 ilk_rxx_cfg1.u64 = csr_rd_node(node, CVMX_ILK_RXX_CFG1(interface));
1169 if (ilk_rxx_cfg1.s.pkt_ena == 0)
1170 goto retry;
1171
1172out:
1173
1174#ifdef CVMX_ILK_STATS_ENA
1175 debug(">>>> ILK%d: After ILK is enabled\n", interface);
1176 cvmx_ilk_reg_dump_rx(intf);
1177 cvmx_ilk_reg_dump_tx(intf);
1178#endif
1179
1180 if (result.s.link_up)
1181 return 0;
1182
1183 return -1;
1184}
1185
1186/**
1187 * Provide interface enable status
1188 *
1189 * @param xiface The identifier of the packet xiface to disable. cn68xx
1190 * has 2 interfaces: ilk0 and ilk1.
1191 *
1192 * @return Zero, not enabled; One, enabled.
1193 */
1194int cvmx_ilk_get_intf_ena(int xiface)
1195{
1196 struct cvmx_xiface xi = cvmx_helper_xiface_to_node_interface(xiface);
1197 int interface = xi.interface - CVMX_ILK_GBL_BASE();
1198 return cvmx_ilk_intf_cfg[xi.node][interface].intf_en;
1199}