]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/contrib/octeon-sdk/cvmx-ilk.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / contrib / octeon-sdk / cvmx-ilk.c
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  */
76 unsigned char cvmx_ilk_lane_mask[CVMX_NUM_ILK_INTF] = {0xf, 0xf0};
77 //#define SINGLE_PORT_SIM_ILK
78 #ifdef SINGLE_PORT_SIM_ILK
79 unsigned char cvmx_ilk_chans[CVMX_NUM_ILK_INTF] = {1, 1};
80 unsigned char cvmx_ilk_chan_map[CVMX_NUM_ILK_INTF][CVMX_MAX_ILK_CHANS] =
81 {{0},
82  {0}};
83 #else /* sample case */
84 unsigned char cvmx_ilk_chans[CVMX_NUM_ILK_INTF] = {8, 8};
85 unsigned 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  */
93 static cvmx_ilk_callbacks_t cvmx_ilk_callbacks = {
94   .calendar_setup_rx   = cvmx_ilk_cal_setup_rx,
95 };
96
97 static 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  */
106 void 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  */
116 void 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  */
132 int 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  */
231 int 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  */
274 int 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  */
316 int 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  */
359 static 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  */
492 static 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  */
526 static 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  */
561 int 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
585 EXPORT_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  */
600 static 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  */
708 static 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  */
748 static 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  */
782 int 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
807 EXPORT_SYMBOL(cvmx_ilk_cal_setup_tx);
808 #endif
809
810 #ifdef CVMX_ILK_STATS_ENA
811 static 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
891 static 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
952 void 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
1009 int 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
1057 retry:
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
1072 out:
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  */
1094 int 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  */
1143 int 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  */
1155 unsigned 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  */
1173 unsigned 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  */
1188 int 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  */
1207 void 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  */
1341 int 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 */