1 /***********************license start***************
2 * Copyright (c) 2010 Cavium Inc. (support@cavium.com). All rights
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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
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
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**************************************/
43 * Functions for ILK initialization, configuration,
46 * <hr>$Revision: 41586 $<hr>
49 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
50 #include <linux/module.h>
52 #include <asm/octeon/cvmx.h>
53 #include <asm/octeon/cvmx-config.h>
54 #include <asm/octeon/cvmx-helper.h>
55 #include <asm/octeon/cvmx-helper-cfg.h>
56 #include <asm/octeon/cvmx-ilk.h>
57 #include <asm/octeon/cvmx-bootmem.h>
58 #include <asm/octeon/cvmx-pko.h>
59 #include <asm/octeon/cvmx-qlm.h>
60 #include <asm/octeon/cvmx-ilk-defs.h>
62 #if !defined(__FreeBSD__) || !defined(_KERNEL)
63 #include "executive-config.h"
64 #include "cvmx-config.h"
67 #include "cvmx-helper.h"
68 #include "cvmx-helper-cfg.h"
70 #include "cvmx-bootmem.h"
75 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
77 int __cvmx_helper_ilk_enumerate(int interface)
79 interface -= CVMX_ILK_GBL_BASE;
80 return cvmx_ilk_chans[interface];
85 * Probe a ILK interface and determine the number of ports
86 * connected to it. The ILK interface should still be down
89 * @param interface Interface to probe
91 * @return Number of ports on the interface. Zero to disable.
93 int __cvmx_helper_ilk_probe(int interface)
96 static int pipe_base = 0, pknd_base = 0;
97 static cvmx_ilk_pipe_chan_t *pch = NULL, *tmp;
98 static cvmx_ilk_chan_pknd_t *chpknd = NULL, *tmp1;
99 static cvmx_ilk_cal_entry_t *calent = NULL, *tmp2;
101 if (!OCTEON_IS_MODEL(OCTEON_CN68XX))
104 interface -= CVMX_ILK_GBL_BASE;
105 if (interface >= CVMX_NUM_ILK_INTF)
108 /* the configuration should be done only once */
109 if (cvmx_ilk_get_intf_ena (interface))
110 return cvmx_ilk_chans[interface];
112 /* configure lanes and enable the link */
113 res = cvmx_ilk_start_interface (interface, cvmx_ilk_lane_mask[interface]);
117 /* set up the group of pipes available to ilk */
119 pipe_base = __cvmx_pko_get_pipe (interface + CVMX_ILK_GBL_BASE, 0);
127 res = cvmx_ilk_set_pipe (interface, pipe_base, cvmx_ilk_chans[interface]);
131 /* set up pipe to channel mapping */
135 pch = (cvmx_ilk_pipe_chan_t *)
136 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
137 kmalloc(CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t), GFP_KERNEL);
139 cvmx_bootmem_alloc (CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t),
140 sizeof(cvmx_ilk_pipe_chan_t));
146 memset (pch, 0, CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t));
148 for (j = 0; j < cvmx_ilk_chans[interface]; j++)
151 tmp->chan = cvmx_ilk_chan_map[interface][j];
154 res = cvmx_ilk_tx_set_channel (interface, pch, cvmx_ilk_chans[interface]);
160 pipe_base += cvmx_ilk_chans[interface];
162 /* set up channel to pkind mapping */
164 pknd_base = cvmx_helper_get_pknd (interface + CVMX_ILK_GBL_BASE, 0);
169 chpknd = (cvmx_ilk_chan_pknd_t *)
170 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
171 kmalloc(CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t), GFP_KERNEL);
173 cvmx_bootmem_alloc (CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t),
174 sizeof(cvmx_ilk_chan_pknd_t));
178 pipe_base -= cvmx_ilk_chans[interface];
184 memset (chpknd, 0, CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t));
186 for (j = 0; j < cvmx_ilk_chans[interface]; j++)
188 tmp1->chan = cvmx_ilk_chan_map[interface][j];
192 res = cvmx_ilk_rx_set_pknd (interface, chpknd, cvmx_ilk_chans[interface]);
195 pipe_base -= cvmx_ilk_chans[interface];
197 goto err_free_chpknd;
199 pknd_base += cvmx_ilk_chans[interface];
201 /* Set up tx calendar */
204 calent = (cvmx_ilk_cal_entry_t *)
205 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
206 kmalloc(CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t), GFP_KERNEL);
208 cvmx_bootmem_alloc (CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t),
209 sizeof(cvmx_ilk_cal_entry_t));
213 pipe_base -= cvmx_ilk_chans[interface];
214 pknd_base -= cvmx_ilk_chans[interface];
216 goto err_free_chpknd;
220 memset (calent, 0, CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t));
223 for (j = 0; j < cvmx_ilk_chans[interface]; j++)
225 tmp2->pipe_bpid = tmp1->pknd;
226 tmp2->ent_ctrl = PIPE_BPID;
230 res = cvmx_ilk_cal_setup_tx (interface, cvmx_ilk_chans[interface],
234 pipe_base -= cvmx_ilk_chans[interface];
235 pknd_base -= cvmx_ilk_chans[interface];
237 goto err_free_calent;
240 /* set up rx calendar. allocated memory can be reused.
241 * this is because max pkind is always less than max pipe */
242 memset (calent, 0, CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t));
245 for (j = 0; j < cvmx_ilk_chans[interface]; j++)
247 tmp2->pipe_bpid = tmp->pipe;
248 tmp2->ent_ctrl = PIPE_BPID;
252 res = cvmx_ilk_cal_setup_rx (interface, cvmx_ilk_chans[interface],
253 calent, CVMX_ILK_RX_FIFO_WM, 1);
256 pipe_base -= cvmx_ilk_chans[interface];
257 pknd_base -= cvmx_ilk_chans[interface];
259 goto err_free_calent;
261 res = __cvmx_helper_ilk_enumerate(interface + CVMX_ILK_GBL_BASE);
266 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
269 /* no free() for cvmx_bootmem_alloc() */
273 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
276 /* no free() for cvmx_bootmem_alloc() */
280 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
283 /* no free() for cvmx_bootmem_alloc() */
291 * Bringup and enable ILK interface. After this call packet
292 * I/O should be fully functional. This is called with IPD
293 * enabled but PKO disabled.
295 * @param interface Interface to bring up
297 * @return Zero on success, negative on failure
299 int __cvmx_helper_ilk_enable(int interface)
301 interface -= CVMX_ILK_GBL_BASE;
302 return cvmx_ilk_enable(interface);
307 * Return the link state of an IPD/PKO port as returned by ILK link status.
309 * @param ipd_port IPD/PKO port to query
313 cvmx_helper_link_info_t __cvmx_helper_ilk_link_get(int ipd_port)
315 cvmx_helper_link_info_t result;
316 int interface = cvmx_helper_get_interface_num(ipd_port);
318 cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1;
319 cvmx_ilk_rxx_int_t ilk_rxx_int;
323 interface -= CVMX_ILK_GBL_BASE;
327 if (retry_count > 10)
330 ilk_rxx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG1(interface));
331 ilk_rxx_int.u64 = cvmx_read_csr (CVMX_ILK_RXX_INT(interface));
333 /* Clear all RX status bits */
335 cvmx_write_csr(CVMX_ILK_RXX_INT(interface), ilk_rxx_int.u64);
337 if (ilk_rxx_cfg1.s.rx_bdry_lock_ena == 0)
339 /* We need to start looking for work boundary lock */
340 ilk_rxx_cfg1.s.rx_bdry_lock_ena = cvmx_ilk_get_intf_ln_msk(interface);
341 ilk_rxx_cfg1.s.rx_align_ena = 0;
342 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
343 //cvmx_dprintf("ILK%d: Looking for word boundary lock\n", interface);
347 if (ilk_rxx_cfg1.s.rx_align_ena == 0)
349 if (ilk_rxx_int.s.word_sync_done)
351 ilk_rxx_cfg1.s.rx_align_ena = 1;
352 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
353 //printf("ILK%d: Looking for lane alignment\n", interface);
359 if (ilk_rxx_int.s.lane_align_fail)
361 ilk_rxx_cfg1.s.rx_bdry_lock_ena = 0;
362 ilk_rxx_cfg1.s.rx_align_ena = 0;
363 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
364 cvmx_dprintf("ILK%d: Lane alignment failed\n", interface);
368 if (ilk_rxx_int.s.lane_align_done)
370 //cvmx_dprintf("ILK%d: Lane alignment complete\n", interface);
373 lanes = cvmx_pop(ilk_rxx_cfg1.s.rx_bdry_lock_ena);
375 result.s.link_up = 1;
376 result.s.full_duplex = 1;
377 result.s.speed = cvmx_qlm_get_gbaud_mhz(1+interface) * 64 / 67;
378 result.s.speed *= lanes;
381 /* If the link is down we will force disable the RX path. If it up, we'll
382 set it to match the TX state set by the if_enable call */
383 if (result.s.link_up)
385 cvmx_ilk_txx_cfg1_t ilk_txx_cfg1;
386 ilk_txx_cfg1.u64 = cvmx_read_csr(CVMX_ILK_TXX_CFG1(interface));
387 ilk_rxx_cfg1.s.pkt_ena = ilk_txx_cfg1.s.pkt_ena;
388 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
389 //cvmx_dprintf("ILK%d: link up, %d Mbps, Full duplex mode, %d lanes\n", interface, result.s.speed, lanes);
393 ilk_rxx_cfg1.s.pkt_ena = 0;
394 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
395 //cvmx_dprintf("ILK link down\n");
402 * Set the link state of an IPD/PKO port.
404 * @param ipd_port IPD/PKO port to configure
405 * @param link_info The new link state
407 * @return Zero on success, negative on failure
409 int __cvmx_helper_ilk_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
417 * Display ilk interface statistics.
420 void __cvmx_helper_ilk_show_stats (void)
423 unsigned char *pchans, num_chans;
424 unsigned int chan_tmp[CVMX_MAX_ILK_CHANS];
425 cvmx_ilk_stats_ctrl_t ilk_stats_ctrl;
427 for (i = 0; i < CVMX_NUM_ILK_INTF; i++)
429 cvmx_ilk_get_chan_info (i, &pchans, &num_chans);
431 memset (chan_tmp, 0, CVMX_MAX_ILK_CHANS * sizeof (int));
432 for (j = 0; j < num_chans; j++)
433 chan_tmp[j] = pchans[j];
435 ilk_stats_ctrl.chan_list = chan_tmp;
436 ilk_stats_ctrl.num_chans = num_chans;
437 ilk_stats_ctrl.clr_on_rd = 0;
438 cvmx_ilk_show_stats (i, &ilk_stats_ctrl);
442 #endif /* CVMX_ENABLE_PKO_FUNCTIONS */