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