cvmx-ilk.c revision 232809
1/***********************license start***************
2 * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3 * reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 *   * Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 *
13 *   * Redistributions in binary form must reproduce the above
14 *     copyright notice, this list of conditions and the following
15 *     disclaimer in the documentation and/or other materials provided
16 *     with the distribution.
17
18 *   * Neither the name of Cavium Inc. nor the names of
19 *     its contributors may be used to endorse or promote products
20 *     derived from this software without specific prior written
21 *     permission.
22
23 * This Software, including technical data, may be subject to U.S. export  control
24 * laws, including the U.S. Export Administration Act and its  associated
25 * regulations, and may be subject to export or import  regulations in other
26 * countries.
27
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
39
40/**
41 * @file
42 *
43 * Support library for the ILK
44 *
45 * <hr>$Revision: 49448 $<hr>
46 */
47#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
48#include <linux/module.h>
49#include <asm/octeon/cvmx.h>
50#include <asm/octeon/cvmx-config.h>
51#include <asm/octeon/cvmx-sysinfo.h>
52#include <asm/octeon/cvmx-pko.h>
53#include <asm/octeon/cvmx-ilk.h>
54#include <asm/octeon/cvmx-ilk-defs.h>
55#include <asm/octeon/cvmx-helper-util.h>
56#include <asm/octeon/cvmx-helper-ilk.h>
57#else
58#include "cvmx.h"
59#include "cvmx-config.h"
60#include "cvmx-sysinfo.h"
61#include "cvmx-pko.h"
62#include "cvmx-ilk.h"
63#include "cvmx-helper-util.h"
64#include "cvmx-helper-ilk.h"
65#endif
66
67#ifdef CVMX_ENABLE_HELPER_FUNCTIONS
68
69/*
70 * global configurations. to disable the 2nd ILK, set
71 * cvmx_ilk_lane_mask[CVMX_NUM_ILK_INTF] = {0xff, 0x0} and
72 * cvmx_ilk_chans[CVMX_NUM_ILK_INTF] = {8, 0}
73 */
74unsigned char cvmx_ilk_lane_mask[CVMX_NUM_ILK_INTF] = {0xf, 0xf0};
75//#define SINGLE_PORT_SIM_ILK
76#ifdef SINGLE_PORT_SIM_ILK
77unsigned char cvmx_ilk_chans[CVMX_NUM_ILK_INTF] = {1, 1};
78unsigned char cvmx_ilk_chan_map[CVMX_NUM_ILK_INTF][CVMX_MAX_ILK_CHANS] =
79{{0},
80 {0}};
81#else /* sample case */
82unsigned char cvmx_ilk_chans[CVMX_NUM_ILK_INTF] = {8, 8};
83unsigned char cvmx_ilk_chan_map[CVMX_NUM_ILK_INTF][CVMX_MAX_ILK_CHANS] =
84{{0, 1, 2, 3, 4, 5, 6, 7},
85 {0, 1, 2, 3, 4, 5, 6, 7}};
86#endif
87
88/* Default callbacks, can be overridden
89 *  using cvmx_ilk_get_callbacks/cvmx_ilk_set_callbacks
90 */
91static cvmx_ilk_callbacks_t cvmx_ilk_callbacks = {
92  .calendar_setup_rx   = cvmx_ilk_cal_setup_rx,
93};
94
95static cvmx_ilk_intf_t cvmx_ilk_intf_cfg[CVMX_NUM_ILK_INTF];
96
97/**
98 * Get current ILK initialization callbacks
99 *
100 * @param callbacks  Pointer to the callbacks structure.to fill
101 *
102 * @return Pointer to cvmx_ilk_callbacks_t structure.
103 */
104void cvmx_ilk_get_callbacks(cvmx_ilk_callbacks_t * callbacks)
105{
106    memcpy(callbacks, &cvmx_ilk_callbacks, sizeof(cvmx_ilk_callbacks));
107}
108
109/**
110 * Set new ILK initialization callbacks
111 *
112 * @param new_callbacks  Pointer to an updated callbacks structure.
113 */
114void cvmx_ilk_set_callbacks(cvmx_ilk_callbacks_t * new_callbacks)
115{
116    memcpy(&cvmx_ilk_callbacks, new_callbacks, sizeof(cvmx_ilk_callbacks));
117}
118
119/**
120 * Initialize and start the ILK interface.
121 *
122 * @param interface The identifier of the packet interface to configure and
123 *                  use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
124 *                  ilk1.
125 *
126 * @param lane_mask the lane group for this interface
127 *
128 * @return Zero on success, negative of failure.
129 */
130int cvmx_ilk_start_interface (int interface, unsigned char lane_mask)
131{
132    int res = -1;
133    int other_intf, this_qlm, other_qlm;
134    unsigned char uni_mask;
135    cvmx_mio_qlmx_cfg_t mio_qlmx_cfg, other_mio_qlmx_cfg;
136    cvmx_ilk_txx_cfg0_t ilk_txx_cfg0;
137    cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0;
138    cvmx_ilk_ser_cfg_t ilk_ser_cfg;
139
140    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
141        return res;
142
143    if (interface >= CVMX_NUM_ILK_INTF)
144        return res;
145
146    if (lane_mask == 0)
147        return res;
148
149    /* check conflicts between 2 ilk interfaces. 1 lane can be assigned to 1
150     * interface only */
151    other_intf = !interface;
152    this_qlm = interface + CVMX_ILK_QLM_BASE;
153    other_qlm = other_intf + CVMX_ILK_QLM_BASE;
154    if (cvmx_ilk_intf_cfg[other_intf].lane_en_mask & lane_mask)
155    {
156        cvmx_dprintf ("ILK%d: %s: lane assignment conflict\n", interface,
157                      __FUNCTION__);
158        return res;
159    }
160
161    /* check the legality of the lane mask. interface 0 can have 8 lanes,
162     * while interface 1 can have 4 lanes at most */
163    uni_mask = lane_mask >> (interface * 4);
164    if ((uni_mask != 0x1 && uni_mask != 0x3 && uni_mask != 0xf &&
165         uni_mask != 0xff) || (interface == 1 && lane_mask > 0xf0))
166    {
167#if CVMX_ENABLE_DEBUG_PRINTS
168        cvmx_dprintf ("ILK%d: %s: incorrect lane mask: 0x%x \n", interface,
169                      __FUNCTION__, uni_mask);
170#endif
171        return res;
172    }
173
174    /* check the availability of qlms. qlm_cfg = 001 means the chip is fused
175     * to give this qlm to ilk */
176    mio_qlmx_cfg.u64 = cvmx_read_csr (CVMX_MIO_QLMX_CFG(this_qlm));
177    other_mio_qlmx_cfg.u64 = cvmx_read_csr (CVMX_MIO_QLMX_CFG(other_qlm));
178    if (mio_qlmx_cfg.s.qlm_cfg != 1 ||
179        (uni_mask == 0xff && other_mio_qlmx_cfg.s.qlm_cfg != 1))
180    {
181#if CVMX_ENABLE_DEBUG_PRINTS
182        cvmx_dprintf ("ILK%d: %s: qlm unavailable\n", interface, __FUNCTION__);
183#endif
184        return res;
185    }
186
187    /* power up the serdes */
188    ilk_ser_cfg.u64 = cvmx_read_csr (CVMX_ILK_SER_CFG);
189    if (ilk_ser_cfg.s.ser_pwrup == 0)
190    {
191        ilk_ser_cfg.s.ser_rxpol_auto = 1;
192        ilk_ser_cfg.s.ser_rxpol = 0;
193        ilk_ser_cfg.s.ser_txpol = 0;
194        ilk_ser_cfg.s.ser_reset_n = 0xff;
195        ilk_ser_cfg.s.ser_haul = 0;
196    }
197    ilk_ser_cfg.s.ser_pwrup |= ((interface ==0) && (lane_mask > 0xf)) ?
198                               0x3 : (1 << interface);
199    cvmx_write_csr (CVMX_ILK_SER_CFG, ilk_ser_cfg.u64);
200
201    /* configure the lane enable of the interface */
202    ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface));
203    ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface));
204    ilk_txx_cfg0.s.lane_ena = ilk_rxx_cfg0.s.lane_ena = lane_mask;
205    cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64);
206    cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64);
207
208    /* write to local cache. for lane speed, if interface 0 has 8 lanes,
209     * assume both qlms have the same speed */
210    cvmx_ilk_intf_cfg[interface].intf_en = 1;
211    cvmx_ilk_intf_cfg[interface].lane_en_mask = lane_mask;
212    res = 0;
213
214    return res;
215}
216
217/**
218 * set pipe group base and length for the interface
219 *
220 * @param interface The identifier of the packet interface to configure and
221 *                  use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
222 *                  ilk1.
223 *
224 * @param pipe_base the base of the pipe group
225 * @param pipe_len  the length of the pipe group
226 *
227 * @return Zero on success, negative of failure.
228 */
229int cvmx_ilk_set_pipe (int interface, int pipe_base, unsigned int pipe_len)
230{
231    int res = -1;
232    cvmx_ilk_txx_pipe_t ilk_txx_pipe;
233
234    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
235        return res;
236
237    if (interface >= CVMX_NUM_ILK_INTF)
238        return res;
239
240    /* base should be between 0 and 127. base + length should be <127 */
241    if (!(pipe_base >= 0 && pipe_base <= 127) || (pipe_base + pipe_len > 127))
242    {
243#if CVMX_ENABLE_DEBUG_PRINTS
244        cvmx_dprintf ("ILK%d: %s: pipe base/length out of bounds\n", interface,
245                      __FUNCTION__);
246#endif
247        return res;
248    }
249
250    /* set them in ilk tx section */
251    ilk_txx_pipe.u64 = cvmx_read_csr (CVMX_ILK_TXX_PIPE(interface));
252    ilk_txx_pipe.s.base = pipe_base;
253    ilk_txx_pipe.s.nump = pipe_len;
254    cvmx_write_csr (CVMX_ILK_TXX_PIPE(interface), ilk_txx_pipe.u64);
255    res = 0;
256
257    return res;
258}
259
260/**
261 * set logical channels for tx
262 *
263 * @param interface The identifier of the packet interface to configure and
264 *                  use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
265 *                  ilk1.
266 *
267 * @param pch     pointer to an array of pipe-channel pair
268 * @param num_chs the number of entries in the pipe-channel array
269 *
270 * @return Zero on success, negative of failure.
271 */
272int cvmx_ilk_tx_set_channel (int interface, cvmx_ilk_pipe_chan_t *pch,
273                             unsigned int num_chs)
274{
275    int res = -1;
276    cvmx_ilk_txx_idx_pmap_t ilk_txx_idx_pmap;
277    unsigned int i;
278
279    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
280        return res;
281
282    if (interface >= CVMX_NUM_ILK_INTF)
283        return res;
284
285    if (pch == NULL || num_chs > CVMX_MAX_ILK_PIPES)
286        return res;
287
288    /* write the pair to ilk tx */
289    for (i = 0; i < num_chs; i++)
290    {
291        ilk_txx_idx_pmap.u64 = 0;
292        ilk_txx_idx_pmap.s.index = pch->pipe;
293        cvmx_write_csr(CVMX_ILK_TXX_IDX_PMAP(interface), ilk_txx_idx_pmap.u64);
294        cvmx_write_csr(CVMX_ILK_TXX_MEM_PMAP(interface), pch->chan);
295        pch++;
296    }
297    res = 0;
298
299    return res;
300}
301
302/**
303 * set pkind for rx
304 *
305 * @param interface The identifier of the packet interface to configure and
306 *                  use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
307 *                  ilk1.
308 *
309 * @param chpknd    pointer to an array of channel-pkind pair
310 * @param num_pknd the number of entries in the channel-pkind array
311 *
312 * @return Zero on success, negative of failure.
313 */
314int cvmx_ilk_rx_set_pknd (int interface, cvmx_ilk_chan_pknd_t *chpknd,
315                          unsigned int num_pknd)
316{
317    int res = -1;
318    cvmx_ilk_rxf_idx_pmap_t ilk_rxf_idx_pmap;
319    unsigned int i;
320
321    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
322        return res;
323
324    if (interface >= CVMX_NUM_ILK_INTF)
325        return res;
326
327    if (chpknd == NULL || num_pknd > CVMX_MAX_ILK_PKNDS)
328        return res;
329
330    /* write the pair to ilk rx. note the channels for different interfaces
331     * are given in *chpknd and interface is not used as a param */
332    for (i = 0; i < num_pknd; i++)
333    {
334        ilk_rxf_idx_pmap.u64 = 0;
335        ilk_rxf_idx_pmap.s.index = interface * 256 + chpknd->chan;
336        cvmx_write_csr (CVMX_ILK_RXF_IDX_PMAP, ilk_rxf_idx_pmap.u64);
337        cvmx_write_csr (CVMX_ILK_RXF_MEM_PMAP, chpknd->pknd);
338        chpknd++;
339    }
340    res = 0;
341
342    return res;
343}
344
345/**
346 * configure calendar for rx
347 *
348 * @param interface The identifier of the packet interface to configure and
349 *                  use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
350 *                  ilk1.
351 *
352 * @param cal_depth the number of calendar entries
353 * @param pent      pointer to calendar entries
354 *
355 * @return Zero on success, negative of failure.
356 */
357int cvmx_ilk_rx_cal_conf (int interface, int cal_depth,
358                          cvmx_ilk_cal_entry_t *pent)
359{
360    int res = -1, num_grp, num_rest, i, j;
361    cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0;
362    cvmx_ilk_rxx_idx_cal_t ilk_rxx_idx_cal;
363    cvmx_ilk_rxx_mem_cal0_t ilk_rxx_mem_cal0;
364    cvmx_ilk_rxx_mem_cal1_t ilk_rxx_mem_cal1;
365    unsigned long int tmp;
366
367    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
368        return res;
369
370    if (interface >= CVMX_NUM_ILK_INTF)
371        return res;
372
373    if (cal_depth < CVMX_ILK_RX_MIN_CAL || cal_depth > CVMX_ILK_MAX_CAL
374        || pent == NULL)
375        return res;
376
377    /* mandatory link-level fc as workarounds for ILK-15397 and ILK-15479 */
378    /* TODO: test effectiveness */
379#if 0
380    if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_0) && pent->ent_ctrl == PIPE_BPID)
381        for (i = 0; i < cal_depth; i++)
382            pent->ent_ctrl = LINK;
383#endif
384
385    /* set the depth */
386    ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface));
387    ilk_rxx_cfg0.s.cal_depth = cal_depth;
388    cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64);
389
390    /* set the calendar index */
391    num_grp = cal_depth / CVMX_ILK_CAL_GRP_SZ;
392    num_rest = cal_depth % CVMX_ILK_CAL_GRP_SZ;
393    ilk_rxx_idx_cal.u64 = 0;
394    ilk_rxx_idx_cal.s.inc = 1;
395    cvmx_write_csr (CVMX_ILK_RXX_IDX_CAL(interface), ilk_rxx_idx_cal.u64);
396
397    /* set the calendar entries. each group has both cal0 and cal1 registers */
398    for (i = 0; i < num_grp; i++)
399    {
400        ilk_rxx_mem_cal0.u64 = 0;
401        for (j = 0; j < CVMX_ILK_CAL_GRP_SZ/2; j++)
402        {
403            tmp = 0;
404            tmp = pent->pipe_bpid & ~(~tmp << CVMX_ILK_PIPE_BPID_SZ);
405            tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j;
406            ilk_rxx_mem_cal0.u64 |= tmp;
407
408            tmp = 0;
409            tmp = pent->ent_ctrl & ~(~tmp << CVMX_ILK_ENT_CTRL_SZ);
410            tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j +
411                    CVMX_ILK_PIPE_BPID_SZ;
412            ilk_rxx_mem_cal0.u64 |= tmp;
413            pent++;
414        }
415        cvmx_write_csr(CVMX_ILK_RXX_MEM_CAL0(interface), ilk_rxx_mem_cal0.u64);
416
417        ilk_rxx_mem_cal1.u64 = 0;
418        for (j = 0; j < CVMX_ILK_CAL_GRP_SZ/2; j++)
419        {
420            tmp = 0;
421            tmp = pent->pipe_bpid & ~(~tmp << CVMX_ILK_PIPE_BPID_SZ);
422            tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j;
423            ilk_rxx_mem_cal1.u64 |= tmp;
424
425            tmp = 0;
426            tmp = pent->ent_ctrl & ~(~tmp << CVMX_ILK_ENT_CTRL_SZ);
427            tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j +
428                    CVMX_ILK_PIPE_BPID_SZ;
429            ilk_rxx_mem_cal1.u64 |= tmp;
430            pent++;
431        }
432        cvmx_write_csr(CVMX_ILK_RXX_MEM_CAL1(interface), ilk_rxx_mem_cal1.u64);
433    }
434
435    /* set the calendar entries, the fraction of a group. but both cal0 and
436     * cal1 must be written */
437    ilk_rxx_mem_cal0.u64 = 0;
438    ilk_rxx_mem_cal1.u64 = 0;
439    for (i = 0; i < num_rest; i++)
440    {
441        if (i < CVMX_ILK_CAL_GRP_SZ/2)
442        {
443            tmp = 0;
444            tmp = pent->pipe_bpid & ~(~tmp << CVMX_ILK_PIPE_BPID_SZ);
445            tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * i;
446            ilk_rxx_mem_cal0.u64 |= tmp;
447
448            tmp = 0;
449            tmp = pent->ent_ctrl & ~(~tmp << CVMX_ILK_ENT_CTRL_SZ);
450            tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * i +
451                    CVMX_ILK_PIPE_BPID_SZ;
452            ilk_rxx_mem_cal0.u64 |= tmp;
453            pent++;
454        }
455
456        if (i >= CVMX_ILK_CAL_GRP_SZ/2)
457        {
458            tmp = 0;
459            tmp = pent->pipe_bpid & ~(~tmp << CVMX_ILK_PIPE_BPID_SZ);
460            tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) *
461                    (i - CVMX_ILK_CAL_GRP_SZ/2);
462            ilk_rxx_mem_cal1.u64 |= tmp;
463
464            tmp = 0;
465            tmp = pent->ent_ctrl & ~(~tmp << CVMX_ILK_ENT_CTRL_SZ);
466            tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) *
467                    (i - CVMX_ILK_CAL_GRP_SZ/2) + CVMX_ILK_PIPE_BPID_SZ;
468            ilk_rxx_mem_cal1.u64 |= tmp;
469            pent++;
470        }
471    }
472    cvmx_write_csr(CVMX_ILK_RXX_MEM_CAL0(interface), ilk_rxx_mem_cal0.u64);
473    cvmx_write_csr(CVMX_ILK_RXX_MEM_CAL1(interface), ilk_rxx_mem_cal1.u64);
474    cvmx_read_csr (CVMX_ILK_RXX_MEM_CAL1(interface));
475
476    return 0;
477}
478
479/**
480 * set high water mark for rx
481 *
482 * @param interface The identifier of the packet interface to configure and
483 *                  use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
484 *                  ilk1.
485 *
486 * @param hi_wm     high water mark for this interface
487 *
488 * @return Zero on success, negative of failure.
489 */
490int cvmx_ilk_rx_set_hwm (int interface, int hi_wm)
491{
492    int res = -1;
493    cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1;
494
495    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
496        return res;
497
498    if (interface >= CVMX_NUM_ILK_INTF)
499        return res;
500
501    if (hi_wm <= 0)
502        return res;
503
504    /* set the hwm */
505    ilk_rxx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG1(interface));
506    ilk_rxx_cfg1.s.rx_fifo_hwm = hi_wm;
507    cvmx_write_csr (CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
508    res = 0;
509
510    return res;
511}
512
513/**
514 * enable calendar for rx
515 *
516 * @param interface The identifier of the packet interface to configure and
517 *                  use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
518 *                  ilk1.
519 *
520 * @param cal_ena   enable or disable calendar
521 *
522 * @return Zero on success, negative of failure.
523 */
524int cvmx_ilk_rx_cal_ena (int interface, unsigned char cal_ena)
525{
526    int res = -1;
527    cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0;
528
529    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
530        return res;
531
532    if (interface >= CVMX_NUM_ILK_INTF)
533        return res;
534
535    /* set the enable */
536    ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface));
537    ilk_rxx_cfg0.s.cal_ena = cal_ena;
538    cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64);
539    cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface));
540    res = 0;
541
542    return res;
543}
544
545/**
546 * set up calendar for rx
547 *
548 * @param interface The identifier of the packet interface to configure and
549 *                  use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
550 *                  ilk1.
551 *
552 * @param cal_depth the number of calendar entries
553 * @param pent      pointer to calendar entries
554 * @param hi_wm     high water mark for this interface
555 * @param cal_ena   enable or disable calendar
556 *
557 * @return Zero on success, negative of failure.
558 */
559int cvmx_ilk_cal_setup_rx (int interface, int cal_depth,
560                           cvmx_ilk_cal_entry_t *pent, int hi_wm,
561                           unsigned char cal_ena)
562{
563    int res = -1;
564
565    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
566        return res;
567
568    if (interface >= CVMX_NUM_ILK_INTF)
569        return res;
570
571    res = cvmx_ilk_rx_cal_conf (interface, cal_depth, pent);
572    if (res < 0)
573        return res;
574
575    res = cvmx_ilk_rx_set_hwm (interface, hi_wm);
576    if (res < 0)
577        return res;
578
579    res = cvmx_ilk_rx_cal_ena (interface, cal_ena);
580    return res;
581}
582#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
583EXPORT_SYMBOL(cvmx_ilk_cal_setup_rx);
584#endif
585
586/**
587 * configure calendar for tx
588 *
589 * @param interface The identifier of the packet interface to configure and
590 *                  use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
591 *                  ilk1.
592 *
593 * @param cal_depth the number of calendar entries
594 * @param pent      pointer to calendar entries
595 *
596 * @return Zero on success, negative of failure.
597 */
598int cvmx_ilk_tx_cal_conf (int interface, int cal_depth,
599                          cvmx_ilk_cal_entry_t *pent)
600{
601    int res = -1, num_grp, num_rest, i, j;
602    cvmx_ilk_txx_cfg0_t ilk_txx_cfg0;
603    cvmx_ilk_txx_idx_cal_t ilk_txx_idx_cal;
604    cvmx_ilk_txx_mem_cal0_t ilk_txx_mem_cal0;
605    cvmx_ilk_txx_mem_cal1_t ilk_txx_mem_cal1;
606    unsigned long int tmp;
607    cvmx_ilk_cal_entry_t *ent_tmp;
608
609    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
610        return res;
611
612    if (interface >= CVMX_NUM_ILK_INTF)
613        return res;
614
615    if (cal_depth < CVMX_ILK_TX_MIN_CAL || cal_depth > CVMX_ILK_MAX_CAL
616        || pent == NULL)
617        return res;
618
619    /* mandatory link-level fc as workarounds for ILK-15397 and ILK-15479 */
620    /* TODO: test effectiveness */
621#if 0
622    if (OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_0) && pent->ent_ctrl == PIPE_BPID)
623        for (i = 0; i < cal_depth; i++)
624            pent->ent_ctrl = LINK;
625#endif
626
627    /* tx calendar depth must be a multiple of 8 */
628    num_grp = (cal_depth - 1) / CVMX_ILK_CAL_GRP_SZ + 1;
629    num_rest = cal_depth % CVMX_ILK_CAL_GRP_SZ;
630    if (num_rest != 0)
631    {
632        ent_tmp = pent + cal_depth;
633        for (i = num_rest; i < 8; i++, ent_tmp++)
634        {
635            ent_tmp->pipe_bpid = 0;
636            ent_tmp->ent_ctrl = XOFF;
637        }
638    }
639    cal_depth = num_grp * 8;
640
641    /* set the depth */
642    ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface));
643    ilk_txx_cfg0.s.cal_depth = cal_depth;
644    cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64);
645
646    /* set the calendar index */
647    ilk_txx_idx_cal.u64 = 0;
648    ilk_txx_idx_cal.s.inc = 1;
649    cvmx_write_csr (CVMX_ILK_TXX_IDX_CAL(interface), ilk_txx_idx_cal.u64);
650
651    /* set the calendar entries. each group has both cal0 and cal1 registers */
652    for (i = 0; i < num_grp; i++)
653    {
654        ilk_txx_mem_cal0.u64 = 0;
655        for (j = 0; j < CVMX_ILK_CAL_GRP_SZ/2; j++)
656        {
657            tmp = 0;
658            tmp = pent->pipe_bpid & ~(~tmp << CVMX_ILK_PIPE_BPID_SZ);
659            tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j;
660            ilk_txx_mem_cal0.u64 |= tmp;
661
662            tmp = 0;
663            tmp = pent->ent_ctrl & ~(~tmp << CVMX_ILK_ENT_CTRL_SZ);
664            tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j +
665                    CVMX_ILK_PIPE_BPID_SZ;
666            ilk_txx_mem_cal0.u64 |= tmp;
667            pent++;
668        }
669        cvmx_write_csr(CVMX_ILK_TXX_MEM_CAL0(interface), ilk_txx_mem_cal0.u64);
670
671        ilk_txx_mem_cal1.u64 = 0;
672        for (j = 0; j < CVMX_ILK_CAL_GRP_SZ/2; j++)
673        {
674            tmp = 0;
675            tmp = pent->pipe_bpid & ~(~tmp << CVMX_ILK_PIPE_BPID_SZ);
676            tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j;
677            ilk_txx_mem_cal1.u64 |= tmp;
678
679            tmp = 0;
680            tmp = pent->ent_ctrl & ~(~tmp << CVMX_ILK_ENT_CTRL_SZ);
681            tmp <<= (CVMX_ILK_PIPE_BPID_SZ + CVMX_ILK_ENT_CTRL_SZ) * j +
682                    CVMX_ILK_PIPE_BPID_SZ;
683            ilk_txx_mem_cal1.u64 |= tmp;
684            pent++;
685        }
686        cvmx_write_csr(CVMX_ILK_TXX_MEM_CAL1(interface), ilk_txx_mem_cal1.u64);
687    }
688    cvmx_read_csr (CVMX_ILK_TXX_MEM_CAL1(interface));
689
690    return 0;
691}
692
693/**
694 * configure backpressure for tx
695 *
696 * @param interface The identifier of the packet interface to configure and
697 *                  use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
698 *                  ilk1.
699 *
700 * @param cal_depth the number of calendar entries
701 * @param pent      pointer to calendar entries
702 *
703 * @return Zero on success, negative of failure.
704 */
705int cvmx_ilk_bp_conf (int interface, int cal_depth, cvmx_ilk_cal_entry_t *pent)
706{
707    int res = -1, i;
708    cvmx_ipd_ctl_status_t ipd_ctl_status;
709    cvmx_ilk_cal_entry_t *tmp;
710    unsigned char bpid;
711    cvmx_ipd_bpidx_mbuf_th_t ipd_bpidx_mbuf_th;
712
713    /* enable bp for the interface */
714    ipd_ctl_status.u64 = cvmx_read_csr (CVMX_IPD_CTL_STATUS);
715    ipd_ctl_status.s.pbp_en = 1;
716    cvmx_write_csr (CVMX_IPD_CTL_STATUS, ipd_ctl_status.u64);
717
718    /* enable bp for each id */
719    for (i = 0, tmp = pent; i < cal_depth; i++, tmp++)
720    {
721        bpid = tmp->pipe_bpid;
722        ipd_bpidx_mbuf_th.u64 =
723            cvmx_read_csr (CVMX_IPD_BPIDX_MBUF_TH(bpid));
724        ipd_bpidx_mbuf_th.s.page_cnt = 1; /* 256 buffers */
725        ipd_bpidx_mbuf_th.s.bp_enb = 1;
726        cvmx_write_csr (CVMX_IPD_BPIDX_MBUF_TH(bpid), ipd_bpidx_mbuf_th.u64);
727    }
728    res = 0;
729
730    return res;
731}
732
733/**
734 * enable calendar for tx
735 *
736 * @param interface The identifier of the packet interface to configure and
737 *                  use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
738 *                  ilk1.
739 *
740 * @param cal_ena   enable or disable calendar
741 *
742 * @return Zero on success, negative of failure.
743 */
744int cvmx_ilk_tx_cal_ena (int interface, unsigned char cal_ena)
745{
746    int res = -1;
747    cvmx_ilk_txx_cfg0_t ilk_txx_cfg0;
748
749    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
750        return res;
751
752    if (interface >= CVMX_NUM_ILK_INTF)
753        return res;
754
755    /* set the enable */
756    ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface));
757    ilk_txx_cfg0.s.cal_ena = cal_ena;
758    cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64);
759    cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface));
760    res = 0;
761
762    return res;
763}
764
765/**
766 * set up calendar for tx
767 *
768 * @param interface The identifier of the packet interface to configure and
769 *                  use as a ILK interface. cn68xx has 2 interfaces: ilk0 and
770 *                  ilk1.
771 *
772 * @param cal_depth the number of calendar entries
773 * @param pent      pointer to calendar entries
774 * @param cal_ena   enable or disable calendar
775 *
776 * @return Zero on success, negative of failure.
777 */
778int cvmx_ilk_cal_setup_tx (int interface, int cal_depth,
779                           cvmx_ilk_cal_entry_t *pent, unsigned char cal_ena)
780{
781    int res = -1;
782
783    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
784        return res;
785
786    if (interface >= CVMX_NUM_ILK_INTF)
787        return res;
788
789    res = cvmx_ilk_tx_cal_conf (interface, cal_depth, pent);
790    if (res < 0)
791        return res;
792
793#ifdef CVMX_ILK_BP_CONF_ENA
794    res = cvmx_ilk_bp_conf (interface, cal_depth, pent);
795    if (res < 0)
796        return res;
797#endif
798
799    res = cvmx_ilk_tx_cal_ena (interface, cal_ena);
800    return res;
801}
802#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
803EXPORT_SYMBOL(cvmx_ilk_cal_setup_tx);
804#endif
805
806#ifdef CVMX_ILK_STATS_ENA
807static void cvmx_ilk_reg_dump_rx (int interface)
808{
809    int i;
810    cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0;
811    cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1;
812    cvmx_ilk_rxx_int_t ilk_rxx_int;
813    cvmx_ilk_rxx_jabber_t ilk_rxx_jabber;
814    cvmx_ilk_rx_lnex_cfg_t ilk_rx_lnex_cfg;
815    cvmx_ilk_rx_lnex_int_t ilk_rx_lnex_int;
816    cvmx_ilk_gbl_cfg_t ilk_gbl_cfg;
817    cvmx_ilk_ser_cfg_t ilk_ser_cfg;
818    cvmx_ilk_rxf_idx_pmap_t ilk_rxf_idx_pmap;
819    cvmx_ilk_rxf_mem_pmap_t ilk_rxf_mem_pmap;
820    cvmx_ilk_rxx_idx_cal_t ilk_rxx_idx_cal;
821    cvmx_ilk_rxx_mem_cal0_t ilk_rxx_mem_cal0;
822    cvmx_ilk_rxx_mem_cal1_t ilk_rxx_mem_cal1;
823
824    ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface));
825    cvmx_dprintf ("ilk rxx cfg0: 0x%16lx\n", ilk_rxx_cfg0.u64);
826
827    ilk_rxx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG1(interface));
828    cvmx_dprintf ("ilk rxx cfg1: 0x%16lx\n", ilk_rxx_cfg1.u64);
829
830    ilk_rxx_int.u64 = cvmx_read_csr (CVMX_ILK_RXX_INT(interface));
831    cvmx_dprintf ("ilk rxx int: 0x%16lx\n", ilk_rxx_int.u64);
832    cvmx_write_csr (CVMX_ILK_RXX_INT(interface), ilk_rxx_int.u64);
833
834    ilk_rxx_jabber.u64 = cvmx_read_csr (CVMX_ILK_RXX_JABBER(interface));
835    cvmx_dprintf ("ilk rxx jabber: 0x%16lx\n", ilk_rxx_jabber.u64);
836
837#define LNE_NUM_DBG 4
838    for (i = 0; i < LNE_NUM_DBG; i++)
839    {
840        ilk_rx_lnex_cfg.u64 = cvmx_read_csr (CVMX_ILK_RX_LNEX_CFG(i));
841        cvmx_dprintf ("ilk rx lnex cfg lane: %d  0x%16lx\n", i,
842                      ilk_rx_lnex_cfg.u64);
843    }
844
845    for (i = 0; i < LNE_NUM_DBG; i++)
846    {
847        ilk_rx_lnex_int.u64 = cvmx_read_csr (CVMX_ILK_RX_LNEX_INT(i));
848        cvmx_dprintf ("ilk rx lnex int lane: %d  0x%16lx\n", i,
849                      ilk_rx_lnex_int.u64);
850        cvmx_write_csr (CVMX_ILK_RX_LNEX_INT(i), ilk_rx_lnex_int.u64);
851    }
852
853    ilk_gbl_cfg.u64 = cvmx_read_csr (CVMX_ILK_GBL_CFG);
854    cvmx_dprintf ("ilk gbl cfg: 0x%16lx\n", ilk_gbl_cfg.u64);
855
856    ilk_ser_cfg.u64 = cvmx_read_csr (CVMX_ILK_SER_CFG);
857    cvmx_dprintf ("ilk ser cfg: 0x%16lx\n", ilk_ser_cfg.u64);
858
859#define CHAN_NUM_DBG 8
860    ilk_rxf_idx_pmap.u64 = 0;
861    ilk_rxf_idx_pmap.s.index = interface * 256;
862    ilk_rxf_idx_pmap.s.inc = 1;
863    cvmx_write_csr (CVMX_ILK_RXF_IDX_PMAP, ilk_rxf_idx_pmap.u64);
864    for (i = 0; i < CHAN_NUM_DBG; i++)
865    {
866        ilk_rxf_mem_pmap.u64 = cvmx_read_csr (CVMX_ILK_RXF_MEM_PMAP);
867        cvmx_dprintf ("ilk rxf mem pmap chan: %3d  0x%16lx\n", i,
868                      ilk_rxf_mem_pmap.u64);
869    }
870
871#define CAL_NUM_DBG 2
872    ilk_rxx_idx_cal.u64 = 0;
873    ilk_rxx_idx_cal.s.inc = 1;
874    cvmx_write_csr (CVMX_ILK_RXX_IDX_CAL(interface), ilk_rxx_idx_cal.u64);
875    for (i = 0; i < CAL_NUM_DBG; i++)
876    {
877        ilk_rxx_idx_cal.u64 = cvmx_read_csr(CVMX_ILK_RXX_IDX_CAL(interface));
878        cvmx_dprintf ("ilk rxx idx cal: 0x%16lx\n", ilk_rxx_idx_cal.u64);
879
880        ilk_rxx_mem_cal0.u64 = cvmx_read_csr(CVMX_ILK_RXX_MEM_CAL0(interface));
881        cvmx_dprintf ("ilk rxx mem cal0: 0x%16lx\n", ilk_rxx_mem_cal0.u64);
882        ilk_rxx_mem_cal1.u64 = cvmx_read_csr(CVMX_ILK_RXX_MEM_CAL1(interface));
883        cvmx_dprintf ("ilk rxx mem cal1: 0x%16lx\n", ilk_rxx_mem_cal1.u64);
884    }
885}
886
887static void cvmx_ilk_reg_dump_tx (int interface)
888{
889    int i;
890    cvmx_ilk_txx_cfg0_t ilk_txx_cfg0;
891    cvmx_ilk_txx_cfg1_t ilk_txx_cfg1;
892    cvmx_ilk_txx_idx_pmap_t ilk_txx_idx_pmap;
893    cvmx_ilk_txx_mem_pmap_t ilk_txx_mem_pmap;
894    cvmx_ilk_txx_int_t ilk_txx_int;
895    cvmx_ilk_txx_pipe_t ilk_txx_pipe;
896    cvmx_ilk_txx_idx_cal_t ilk_txx_idx_cal;
897    cvmx_ilk_txx_mem_cal0_t ilk_txx_mem_cal0;
898    cvmx_ilk_txx_mem_cal1_t ilk_txx_mem_cal1;
899
900    ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface));
901    cvmx_dprintf ("ilk txx cfg0: 0x%16lx\n", ilk_txx_cfg0.u64);
902
903    ilk_txx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG1(interface));
904    cvmx_dprintf ("ilk txx cfg1: 0x%16lx\n", ilk_txx_cfg1.u64);
905
906    ilk_txx_pipe.u64 = cvmx_read_csr (CVMX_ILK_TXX_PIPE(interface));
907    cvmx_dprintf ("ilk txx pipe: 0x%16lx\n", ilk_txx_pipe.u64);
908
909    ilk_txx_idx_pmap.u64 = 0;
910    ilk_txx_idx_pmap.s.index = ilk_txx_pipe.s.base;
911    ilk_txx_idx_pmap.s.inc = 1;
912    cvmx_write_csr (CVMX_ILK_TXX_IDX_PMAP(interface), ilk_txx_idx_pmap.u64);
913    for (i = 0; i < CHAN_NUM_DBG; i++)
914    {
915        ilk_txx_mem_pmap.u64 = cvmx_read_csr (CVMX_ILK_TXX_MEM_PMAP(interface));
916        cvmx_dprintf ("ilk txx mem pmap pipe: %3d  0x%16lx\n",
917                      ilk_txx_pipe.s.base + i, ilk_txx_mem_pmap.u64);
918    }
919
920    ilk_txx_int.u64 = cvmx_read_csr (CVMX_ILK_TXX_INT(interface));
921    cvmx_dprintf ("ilk txx int: 0x%16lx\n", ilk_txx_int.u64);
922
923    ilk_txx_idx_cal.u64 = 0;
924    ilk_txx_idx_cal.s.inc = 1;
925    cvmx_write_csr (CVMX_ILK_TXX_IDX_CAL(interface), ilk_txx_idx_cal.u64);
926    for (i = 0; i < CAL_NUM_DBG; i++)
927    {
928        ilk_txx_idx_cal.u64 = cvmx_read_csr(CVMX_ILK_TXX_IDX_CAL(interface));
929        cvmx_dprintf ("ilk txx idx cal: 0x%16lx\n", ilk_txx_idx_cal.u64);
930
931        ilk_txx_mem_cal0.u64 = cvmx_read_csr(CVMX_ILK_TXX_MEM_CAL0(interface));
932        cvmx_dprintf ("ilk txx mem cal0: 0x%16lx\n", ilk_txx_mem_cal0.u64);
933        ilk_txx_mem_cal1.u64 = cvmx_read_csr(CVMX_ILK_TXX_MEM_CAL1(interface));
934        cvmx_dprintf ("ilk txx mem cal1: 0x%16lx\n", ilk_txx_mem_cal1.u64);
935    }
936}
937#endif
938
939/**
940 * show run time status
941 *
942 * @param interface The identifier of the packet interface to enable. cn68xx
943 *                  has 2 interfaces: ilk0 and ilk1.
944 *
945 * @return nothing
946 */
947#ifdef CVMX_ILK_RUNTIME_DBG
948void cvmx_ilk_runtime_status (int interface)
949{
950    cvmx_ilk_txx_cfg1_t ilk_txx_cfg1;
951    cvmx_ilk_txx_flow_ctl0_t ilk_txx_flow_ctl0;
952    cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1;
953    cvmx_ilk_rxx_int_t ilk_rxx_int;
954    cvmx_ilk_rxx_flow_ctl0_t ilk_rxx_flow_ctl0;
955    cvmx_ilk_rxx_flow_ctl1_t ilk_rxx_flow_ctl1;
956    cvmx_ilk_gbl_int_t ilk_gbl_int;
957
958    cvmx_dprintf ("\nilk run-time status: interface: %d\n", interface);
959
960    ilk_txx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG1(interface));
961    cvmx_dprintf ("\nilk txx cfg1: 0x%16lx\n", ilk_txx_cfg1.u64);
962    if (ilk_txx_cfg1.s.rx_link_fc)
963        cvmx_dprintf ("link flow control received\n");
964    if (ilk_txx_cfg1.s.tx_link_fc)
965        cvmx_dprintf ("link flow control sent\n");
966
967    ilk_txx_flow_ctl0.u64 = cvmx_read_csr (CVMX_ILK_TXX_FLOW_CTL0(interface));
968    cvmx_dprintf ("\nilk txx flow ctl0: 0x%16lx\n", ilk_txx_flow_ctl0.u64);
969
970    ilk_rxx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG1(interface));
971    cvmx_dprintf ("\nilk rxx cfg1: 0x%16lx\n", ilk_rxx_cfg1.u64);
972    cvmx_dprintf ("rx fifo count: %d\n", ilk_rxx_cfg1.s.rx_fifo_cnt);
973
974    ilk_rxx_int.u64 = cvmx_read_csr (CVMX_ILK_RXX_INT(interface));
975    cvmx_dprintf ("\nilk rxx int: 0x%16lx\n", ilk_rxx_int.u64);
976    if (ilk_rxx_int.s.pkt_drop_rxf)
977        cvmx_dprintf ("rx fifo packet drop\n");
978    if (ilk_rxx_int.u64)
979        cvmx_write_csr (CVMX_ILK_RXX_INT(interface), ilk_rxx_int.u64);
980
981    ilk_rxx_flow_ctl0.u64 = cvmx_read_csr (CVMX_ILK_RXX_FLOW_CTL0(interface));
982    cvmx_dprintf ("\nilk rxx flow ctl0: 0x%16lx\n", ilk_rxx_flow_ctl0.u64);
983
984    ilk_rxx_flow_ctl1.u64 = cvmx_read_csr (CVMX_ILK_RXX_FLOW_CTL1(interface));
985    cvmx_dprintf ("\nilk rxx flow ctl1: 0x%16lx\n", ilk_rxx_flow_ctl1.u64);
986
987    ilk_gbl_int.u64 = cvmx_read_csr (CVMX_ILK_GBL_INT);
988    cvmx_dprintf ("\nilk gbl int: 0x%16lx\n", ilk_gbl_int.u64);
989    if (ilk_gbl_int.s.rxf_push_full)
990        cvmx_dprintf ("rx fifo overflow\n");
991    if (ilk_gbl_int.u64)
992        cvmx_write_csr (CVMX_ILK_GBL_INT, ilk_gbl_int.u64);
993}
994#endif
995
996/**
997 * enable interface
998 *
999 * @param interface The identifier of the packet interface to enable. cn68xx
1000 *                  has 2 interfaces: ilk0 and ilk1.
1001 *
1002 * @return Zero on success, negative of failure.
1003 */
1004//#define CVMX_ILK_STATS_ENA 1
1005int cvmx_ilk_enable (int interface)
1006{
1007    int res = -1;
1008    int retry_count = 0;
1009    cvmx_helper_link_info_t result;
1010    cvmx_ilk_txx_cfg1_t ilk_txx_cfg1;
1011    cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1;
1012#ifdef CVMX_ILK_STATS_ENA
1013    cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0;
1014    cvmx_ilk_txx_cfg0_t ilk_txx_cfg0;
1015#endif
1016
1017    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
1018        return res;
1019
1020    if (interface >= CVMX_NUM_ILK_INTF)
1021        return res;
1022
1023    result.u64 = 0;
1024
1025#ifdef CVMX_ILK_STATS_ENA
1026    cvmx_dprintf ("\n");
1027    cvmx_dprintf ("<<<< ILK%d: Before enabling ilk\n", interface);
1028    cvmx_ilk_reg_dump_rx (interface);
1029    cvmx_ilk_reg_dump_tx (interface);
1030#endif
1031
1032    /* RX packet will be enabled only if link is up */
1033
1034    /* TX side */
1035    ilk_txx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG1(interface));
1036    ilk_txx_cfg1.s.pkt_ena = 1;
1037    ilk_txx_cfg1.s.rx_link_fc_ign = 1; /* cannot use link fc workaround */
1038    cvmx_write_csr (CVMX_ILK_TXX_CFG1(interface), ilk_txx_cfg1.u64);
1039    cvmx_read_csr (CVMX_ILK_TXX_CFG1(interface));
1040
1041#ifdef CVMX_ILK_STATS_ENA
1042    /* RX side stats */
1043    ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface));
1044    ilk_rxx_cfg0.s.lnk_stats_ena = 1;
1045    cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64);
1046
1047    /* TX side stats */
1048    ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface));
1049    ilk_txx_cfg0.s.lnk_stats_ena = 1;
1050    cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64);
1051#endif
1052
1053retry:
1054    retry_count++;
1055    if (retry_count > 10)
1056       goto out;
1057
1058    /* Make sure the link is up, so that packets can be sent. */
1059    result = __cvmx_helper_ilk_link_get(cvmx_helper_get_ipd_port(interface + CVMX_ILK_GBL_BASE, 0));
1060
1061    /* Small delay before another retry. */
1062    cvmx_wait_usec(100);
1063
1064    ilk_rxx_cfg1.u64 = cvmx_read_csr(CVMX_ILK_RXX_CFG1(interface));
1065    if (ilk_rxx_cfg1.s.pkt_ena == 0)
1066       goto retry;
1067
1068out:
1069
1070#ifdef CVMX_ILK_STATS_ENA
1071    cvmx_dprintf (">>>> ILK%d: After ILK is enabled\n", interface);
1072    cvmx_ilk_reg_dump_rx (interface);
1073    cvmx_ilk_reg_dump_tx (interface);
1074#endif
1075
1076    if (result.s.link_up)
1077        return 0;
1078
1079    return -1;
1080}
1081
1082/**
1083 * Disable interface
1084 *
1085 * @param interface The identifier of the packet interface to disable. cn68xx
1086 *                  has 2 interfaces: ilk0 and ilk1.
1087 *
1088 * @return Zero on success, negative of failure.
1089 */
1090int cvmx_ilk_disable (int interface)
1091{
1092    int res = -1;
1093    cvmx_ilk_txx_cfg1_t ilk_txx_cfg1;
1094    cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1;
1095#ifdef CVMX_ILK_STATS_ENA
1096    cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0;
1097    cvmx_ilk_txx_cfg0_t ilk_txx_cfg0;
1098#endif
1099
1100    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
1101        return res;
1102
1103    if (interface >= CVMX_NUM_ILK_INTF)
1104        return res;
1105
1106    /* TX side */
1107    ilk_txx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG1(interface));
1108    ilk_txx_cfg1.s.pkt_ena = 0;
1109    cvmx_write_csr (CVMX_ILK_TXX_CFG1(interface), ilk_txx_cfg1.u64);
1110
1111    /* RX side */
1112    ilk_rxx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG1(interface));
1113    ilk_rxx_cfg1.s.pkt_ena = 0;
1114    cvmx_write_csr (CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
1115
1116#ifdef CVMX_ILK_STATS_ENA
1117    /* RX side stats */
1118    ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface));
1119    ilk_rxx_cfg0.s.lnk_stats_ena = 0;
1120    cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64);
1121
1122    /* RX side stats */
1123    ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface));
1124    ilk_txx_cfg0.s.lnk_stats_ena = 0;
1125    cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64);
1126#endif
1127
1128    return 0;
1129}
1130
1131/**
1132 * Provide interface enable status
1133 *
1134 * @param interface The identifier of the packet interface to disable. cn68xx
1135 *                  has 2 interfaces: ilk0 and ilk1.
1136 *
1137 * @return Zero, not enabled; One, enabled.
1138 */
1139int cvmx_ilk_get_intf_ena (int interface)
1140{
1141    return cvmx_ilk_intf_cfg[interface].intf_en;
1142}
1143
1144/**
1145 * bit counter
1146 *
1147 * @param uc the byte to be counted
1148 *
1149 * @return number of bits set
1150 */
1151unsigned char cvmx_ilk_bit_count (unsigned char uc)
1152{
1153    unsigned char count;
1154
1155    for (count = 0; uc > 0; uc &= uc-1)
1156        count++;
1157
1158    return count;
1159}
1160
1161/**
1162 * Provide interface lane mask
1163 *
1164 * @param interface The identifier of the packet interface to disable. cn68xx
1165 *                  has 2 interfaces: ilk0 and ilk1.
1166 *
1167 * @return lane mask
1168 */
1169unsigned char cvmx_ilk_get_intf_ln_msk (int interface)
1170{
1171    return cvmx_ilk_intf_cfg[interface].lane_en_mask;
1172}
1173
1174/**
1175 * Provide channel info
1176 *
1177 * @param interface The identifier of the packet interface to disable. cn68xx
1178 *                  has 2 interfaces: ilk0 and ilk1.
1179 * @param chans    A pointer to a channel array
1180 * @param num_chan A pointer to the number of channels
1181 *
1182 * @return Zero on success, negative of failure.
1183 */
1184int cvmx_ilk_get_chan_info (int interface, unsigned char **chans,
1185                            unsigned char *num_chan)
1186{
1187    *chans = cvmx_ilk_chan_map[interface];
1188    *num_chan = cvmx_ilk_chans[interface];
1189
1190    return 0;
1191}
1192
1193/**
1194 * Show channel statistics
1195 *
1196 * @param interface The identifier of the packet interface to disable. cn68xx
1197 *                  has 2 interfaces: ilk0 and ilk1.
1198 * @param pstats A pointer to cvmx_ilk_stats_ctrl_t that specifies which
1199 *               logical channels to access
1200 *
1201 * @return nothing
1202 */
1203void cvmx_ilk_show_stats (int interface, cvmx_ilk_stats_ctrl_t *pstats)
1204{
1205    unsigned int i;
1206    cvmx_ilk_rxx_idx_stat0_t ilk_rxx_idx_stat0;
1207    cvmx_ilk_rxx_idx_stat1_t ilk_rxx_idx_stat1;
1208    cvmx_ilk_rxx_mem_stat0_t ilk_rxx_mem_stat0;
1209    cvmx_ilk_rxx_mem_stat1_t ilk_rxx_mem_stat1;
1210
1211    cvmx_ilk_txx_idx_stat0_t ilk_txx_idx_stat0;
1212    cvmx_ilk_txx_idx_stat1_t ilk_txx_idx_stat1;
1213    cvmx_ilk_txx_mem_stat0_t ilk_txx_mem_stat0;
1214    cvmx_ilk_txx_mem_stat1_t ilk_txx_mem_stat1;
1215
1216    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
1217        return;
1218
1219    if (interface >= CVMX_NUM_ILK_INTF)
1220        return;
1221
1222    if (pstats == NULL)
1223        return;
1224
1225    /* discrete channels */
1226    if (pstats->chan_list != NULL)
1227    {
1228        for (i = 0; i < pstats->num_chans; i++)
1229        {
1230
1231            /* get the number of rx packets */
1232            ilk_rxx_idx_stat0.u64 = 0;
1233            ilk_rxx_idx_stat0.s.index = *pstats->chan_list;
1234            ilk_rxx_idx_stat0.s.clr = pstats->clr_on_rd;
1235            cvmx_write_csr (CVMX_ILK_RXX_IDX_STAT0(interface),
1236                            ilk_rxx_idx_stat0.u64);
1237            ilk_rxx_mem_stat0.u64 = cvmx_read_csr
1238                                    (CVMX_ILK_RXX_MEM_STAT0(interface));
1239
1240            /* get the number of rx bytes */
1241            ilk_rxx_idx_stat1.u64 = 0;
1242            ilk_rxx_idx_stat1.s.index = *pstats->chan_list;
1243            ilk_rxx_idx_stat1.s.clr = pstats->clr_on_rd;
1244            cvmx_write_csr (CVMX_ILK_RXX_IDX_STAT1(interface),
1245                            ilk_rxx_idx_stat1.u64);
1246            ilk_rxx_mem_stat1.u64 = cvmx_read_csr
1247                                    (CVMX_ILK_RXX_MEM_STAT1(interface));
1248
1249            cvmx_dprintf ("ILK%d Channel%d Rx: %d packets %d bytes\n", interface,
1250                    *pstats->chan_list, ilk_rxx_mem_stat0.s.rx_pkt,
1251                    (unsigned int) ilk_rxx_mem_stat1.s.rx_bytes);
1252
1253            /* get the number of tx packets */
1254            ilk_txx_idx_stat0.u64 = 0;
1255            ilk_txx_idx_stat0.s.index = *pstats->chan_list;
1256            ilk_txx_idx_stat0.s.clr = pstats->clr_on_rd;
1257            cvmx_write_csr (CVMX_ILK_TXX_IDX_STAT0(interface),
1258                            ilk_txx_idx_stat0.u64);
1259            ilk_txx_mem_stat0.u64 = cvmx_read_csr
1260                                    (CVMX_ILK_TXX_MEM_STAT0(interface));
1261
1262            /* get the number of tx bytes */
1263            ilk_txx_idx_stat1.u64 = 0;
1264            ilk_txx_idx_stat1.s.index = *pstats->chan_list;
1265            ilk_txx_idx_stat1.s.clr = pstats->clr_on_rd;
1266            cvmx_write_csr (CVMX_ILK_TXX_IDX_STAT1(interface),
1267                            ilk_txx_idx_stat1.u64);
1268            ilk_txx_mem_stat1.u64 = cvmx_read_csr
1269                                    (CVMX_ILK_TXX_MEM_STAT1(interface));
1270
1271            cvmx_dprintf ("ILK%d Channel%d Tx: %d packets %d bytes\n", interface,
1272                    *pstats->chan_list, ilk_txx_mem_stat0.s.tx_pkt,
1273                    (unsigned int) ilk_txx_mem_stat1.s.tx_bytes);
1274
1275            pstats++;
1276        }
1277        return;
1278    }
1279
1280    /* continuous channels */
1281    ilk_rxx_idx_stat0.u64 = 0;
1282    ilk_rxx_idx_stat0.s.index = pstats->chan_start;
1283    ilk_rxx_idx_stat0.s.inc = pstats->chan_step;
1284    ilk_rxx_idx_stat0.s.clr = pstats->clr_on_rd;
1285    cvmx_write_csr (CVMX_ILK_RXX_IDX_STAT0(interface), ilk_rxx_idx_stat0.u64);
1286
1287    ilk_rxx_idx_stat1.u64 = 0;
1288    ilk_rxx_idx_stat1.s.index = pstats->chan_start;
1289    ilk_rxx_idx_stat1.s.inc = pstats->chan_step;
1290    ilk_rxx_idx_stat1.s.clr = pstats->clr_on_rd;
1291    cvmx_write_csr (CVMX_ILK_RXX_IDX_STAT1(interface), ilk_rxx_idx_stat1.u64);
1292
1293    ilk_txx_idx_stat0.u64 = 0;
1294    ilk_txx_idx_stat0.s.index = pstats->chan_start;
1295    ilk_txx_idx_stat0.s.inc = pstats->chan_step;
1296    ilk_txx_idx_stat0.s.clr = pstats->clr_on_rd;
1297    cvmx_write_csr (CVMX_ILK_TXX_IDX_STAT0(interface), ilk_txx_idx_stat0.u64);
1298
1299    ilk_txx_idx_stat1.u64 = 0;
1300    ilk_txx_idx_stat1.s.index = pstats->chan_start;
1301    ilk_txx_idx_stat1.s.inc = pstats->chan_step;
1302    ilk_txx_idx_stat1.s.clr = pstats->clr_on_rd;
1303    cvmx_write_csr (CVMX_ILK_TXX_IDX_STAT1(interface), ilk_txx_idx_stat1.u64);
1304
1305    for (i = pstats->chan_start; i <= pstats->chan_end; i += pstats->chan_step)
1306    {
1307        ilk_rxx_mem_stat0.u64 = cvmx_read_csr
1308                                (CVMX_ILK_RXX_MEM_STAT0(interface));
1309        ilk_rxx_mem_stat1.u64 = cvmx_read_csr
1310                                (CVMX_ILK_RXX_MEM_STAT1(interface));
1311        cvmx_dprintf ("ILK%d Channel%d Rx: %d packets %d bytes\n", interface, i,
1312                ilk_rxx_mem_stat0.s.rx_pkt,
1313                (unsigned int) ilk_rxx_mem_stat1.s.rx_bytes);
1314
1315        ilk_txx_mem_stat0.u64 = cvmx_read_csr
1316                                (CVMX_ILK_TXX_MEM_STAT0(interface));
1317        ilk_txx_mem_stat1.u64 = cvmx_read_csr
1318                                (CVMX_ILK_TXX_MEM_STAT1(interface));
1319        cvmx_dprintf ("ILK%d Channel%d Tx: %d packets %d bytes\n", interface, i,
1320                ilk_rxx_mem_stat0.s.rx_pkt,
1321                (unsigned int) ilk_rxx_mem_stat1.s.rx_bytes);
1322    }
1323
1324    return;
1325}
1326
1327/**
1328 * enable or disable loopbacks
1329 *
1330 * @param interface The identifier of the packet interface to disable. cn68xx
1331 *                  has 2 interfaces: ilk0 and ilk1.
1332 * @param enable    Enable or disable loopback
1333 * @param mode      Internal or external loopback
1334 *
1335 * @return Zero on success, negative of failure.
1336 */
1337int cvmx_ilk_lpbk (int interface, cvmx_ilk_lpbk_ena_t enable,
1338                   cvmx_ilk_lpbk_mode_t mode)
1339{
1340    int res = -1;
1341    cvmx_ilk_txx_cfg0_t ilk_txx_cfg0;
1342    cvmx_ilk_rxx_cfg0_t ilk_rxx_cfg0;
1343
1344    if (!(OCTEON_IS_MODEL(OCTEON_CN68XX)))
1345        return res;
1346
1347    if (interface >= CVMX_NUM_ILK_INTF)
1348        return res;
1349
1350    /* internal loopback. only 1 type of loopback can be on at 1 time */
1351    if (mode == CVMX_ILK_LPBK_INT)
1352    {
1353        if (enable == CVMX_ILK_LPBK_ENA)
1354        {
1355            ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface));
1356            ilk_txx_cfg0.s.ext_lpbk = CVMX_ILK_LPBK_DISA;
1357            ilk_txx_cfg0.s.ext_lpbk_fc = CVMX_ILK_LPBK_DISA;
1358            cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64);
1359
1360            ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface));
1361            ilk_rxx_cfg0.s.ext_lpbk = CVMX_ILK_LPBK_DISA;
1362            ilk_rxx_cfg0.s.ext_lpbk_fc = CVMX_ILK_LPBK_DISA;
1363            cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64);
1364        }
1365
1366        ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface));
1367        ilk_txx_cfg0.s.int_lpbk = enable;
1368        cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64);
1369
1370        res = 0;
1371        return res;
1372    }
1373
1374    /* external loopback. only 1 type of loopback can be on at 1 time */
1375    if (enable == CVMX_ILK_LPBK_ENA)
1376    {
1377        ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface));
1378        ilk_txx_cfg0.s.int_lpbk = CVMX_ILK_LPBK_DISA;
1379        cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64);
1380    }
1381
1382    ilk_txx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_TXX_CFG0(interface));
1383    ilk_txx_cfg0.s.ext_lpbk = enable;
1384    ilk_txx_cfg0.s.ext_lpbk_fc = enable;
1385    cvmx_write_csr (CVMX_ILK_TXX_CFG0(interface), ilk_txx_cfg0.u64);
1386
1387    ilk_rxx_cfg0.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG0(interface));
1388    ilk_rxx_cfg0.s.ext_lpbk = enable;
1389    ilk_rxx_cfg0.s.ext_lpbk_fc = enable;
1390    cvmx_write_csr (CVMX_ILK_RXX_CFG0(interface), ilk_rxx_cfg0.u64);
1391
1392    res = 0;
1393    return res;
1394}
1395
1396#endif /* CVMX_ENABLE_HELPER_FUNCTIONS */
1397