diff options
Diffstat (limited to 'sys/contrib/octeon-sdk/cvmx-helper-ilk.c')
-rw-r--r-- | sys/contrib/octeon-sdk/cvmx-helper-ilk.c | 442 |
1 files changed, 442 insertions, 0 deletions
diff --git a/sys/contrib/octeon-sdk/cvmx-helper-ilk.c b/sys/contrib/octeon-sdk/cvmx-helper-ilk.c new file mode 100644 index 0000000..37e1af9 --- /dev/null +++ b/sys/contrib/octeon-sdk/cvmx-helper-ilk.c @@ -0,0 +1,442 @@ +/***********************license start*************** + * Copyright (c) 2010 Cavium Inc. (support@cavium.com). All rights + * reserved. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + + * * Neither the name of Cavium Inc. nor the names of + * its contributors may be used to endorse or promote products + * derived from this software without specific prior written + * permission. + + * This Software, including technical data, may be subject to U.S. export control + * laws, including the U.S. Export Administration Act and its associated + * regulations, and may be subject to export or import regulations in other + * countries. + + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" + * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR + * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO + * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR + * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM + * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, + * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF + * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR + * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR + * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. + ***********************license end**************************************/ + +/** + * @file + * + * Functions for ILK initialization, configuration, + * and monitoring. + * + * <hr>$Revision: 41586 $<hr> + */ + +#ifdef CVMX_BUILD_FOR_LINUX_KERNEL +#include <linux/module.h> + +#include <asm/octeon/cvmx.h> +#include <asm/octeon/cvmx-config.h> +#include <asm/octeon/cvmx-helper.h> +#include <asm/octeon/cvmx-helper-cfg.h> +#include <asm/octeon/cvmx-ilk.h> +#include <asm/octeon/cvmx-bootmem.h> +#include <asm/octeon/cvmx-pko.h> +#include <asm/octeon/cvmx-qlm.h> +#include <asm/octeon/cvmx-ilk-defs.h> +#else +#if !defined(__FreeBSD__) || !defined(_KERNEL) +#include "executive-config.h" +#include "cvmx-config.h" +#endif +#include "cvmx.h" +#include "cvmx-helper.h" +#include "cvmx-helper-cfg.h" +#include "cvmx-ilk.h" +#include "cvmx-bootmem.h" +#include "cvmx-pko.h" +#include "cvmx-qlm.h" +#endif + +#ifdef CVMX_ENABLE_PKO_FUNCTIONS + +int __cvmx_helper_ilk_enumerate(int interface) +{ + interface -= CVMX_ILK_GBL_BASE; + return cvmx_ilk_chans[interface]; +} + +/** + * @INTERNAL + * Probe a ILK interface and determine the number of ports + * connected to it. The ILK interface should still be down + * after this call. + * + * @param interface Interface to probe + * + * @return Number of ports on the interface. Zero to disable. + */ +int __cvmx_helper_ilk_probe(int interface) +{ + int i, j, res = -1; + static int pipe_base = 0, pknd_base = 0; + static cvmx_ilk_pipe_chan_t *pch = NULL, *tmp; + static cvmx_ilk_chan_pknd_t *chpknd = NULL, *tmp1; + static cvmx_ilk_cal_entry_t *calent = NULL, *tmp2; + + if (!OCTEON_IS_MODEL(OCTEON_CN68XX)) + return 0; + + interface -= CVMX_ILK_GBL_BASE; + if (interface >= CVMX_NUM_ILK_INTF) + return 0; + + /* the configuration should be done only once */ + if (cvmx_ilk_get_intf_ena (interface)) + return cvmx_ilk_chans[interface]; + + /* configure lanes and enable the link */ + res = cvmx_ilk_start_interface (interface, cvmx_ilk_lane_mask[interface]); + if (res < 0) + return 0; + + /* set up the group of pipes available to ilk */ + if (pipe_base == 0) + pipe_base = __cvmx_pko_get_pipe (interface + CVMX_ILK_GBL_BASE, 0); + + if (pipe_base == -1) + { + pipe_base = 0; + return 0; + } + + res = cvmx_ilk_set_pipe (interface, pipe_base, cvmx_ilk_chans[interface]); + if (res < 0) + return 0; + + /* set up pipe to channel mapping */ + i = pipe_base; + if (pch == NULL) + { + pch = (cvmx_ilk_pipe_chan_t *) +#ifdef CVMX_BUILD_FOR_LINUX_KERNEL + kmalloc(CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t), GFP_KERNEL); +#else + cvmx_bootmem_alloc (CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t), + sizeof(cvmx_ilk_pipe_chan_t)); +#endif + if (pch == NULL) + return 0; + } + + memset (pch, 0, CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t)); + tmp = pch; + for (j = 0; j < cvmx_ilk_chans[interface]; j++) + { + tmp->pipe = i++; + tmp->chan = cvmx_ilk_chan_map[interface][j]; + tmp++; + } + res = cvmx_ilk_tx_set_channel (interface, pch, cvmx_ilk_chans[interface]); + if (res < 0) + { + res = 0; + goto err_free_pch; + } + pipe_base += cvmx_ilk_chans[interface]; + + /* set up channel to pkind mapping */ + if (pknd_base == 0) + pknd_base = cvmx_helper_get_pknd (interface + CVMX_ILK_GBL_BASE, 0); + + i = pknd_base; + if (chpknd == NULL) + { + chpknd = (cvmx_ilk_chan_pknd_t *) +#ifdef CVMX_BUILD_FOR_LINUX_KERNEL + kmalloc(CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t), GFP_KERNEL); +#else + cvmx_bootmem_alloc (CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t), + sizeof(cvmx_ilk_chan_pknd_t)); +#endif + if (chpknd == NULL) + { + pipe_base -= cvmx_ilk_chans[interface]; + res = 0; + goto err_free_pch; + } + } + + memset (chpknd, 0, CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t)); + tmp1 = chpknd; + for (j = 0; j < cvmx_ilk_chans[interface]; j++) + { + tmp1->chan = cvmx_ilk_chan_map[interface][j]; + tmp1->pknd = i++; + tmp1++; + } + res = cvmx_ilk_rx_set_pknd (interface, chpknd, cvmx_ilk_chans[interface]); + if (res < 0) + { + pipe_base -= cvmx_ilk_chans[interface]; + res = 0; + goto err_free_chpknd; + } + pknd_base += cvmx_ilk_chans[interface]; + + /* Set up tx calendar */ + if (calent == NULL) + { + calent = (cvmx_ilk_cal_entry_t *) +#ifdef CVMX_BUILD_FOR_LINUX_KERNEL + kmalloc(CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t), GFP_KERNEL); +#else + cvmx_bootmem_alloc (CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t), + sizeof(cvmx_ilk_cal_entry_t)); +#endif + if (calent == NULL) + { + pipe_base -= cvmx_ilk_chans[interface]; + pknd_base -= cvmx_ilk_chans[interface]; + res = 0; + goto err_free_chpknd; + } + } + + memset (calent, 0, CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t)); + tmp1 = chpknd; + tmp2 = calent; + for (j = 0; j < cvmx_ilk_chans[interface]; j++) + { + tmp2->pipe_bpid = tmp1->pknd; + tmp2->ent_ctrl = PIPE_BPID; + tmp1++; + tmp2++; + } + res = cvmx_ilk_cal_setup_tx (interface, cvmx_ilk_chans[interface], + calent, 1); + if (res < 0) + { + pipe_base -= cvmx_ilk_chans[interface]; + pknd_base -= cvmx_ilk_chans[interface]; + res = 0; + goto err_free_calent; + } + + /* set up rx calendar. allocated memory can be reused. + * this is because max pkind is always less than max pipe */ + memset (calent, 0, CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t)); + tmp = pch; + tmp2 = calent; + for (j = 0; j < cvmx_ilk_chans[interface]; j++) + { + tmp2->pipe_bpid = tmp->pipe; + tmp2->ent_ctrl = PIPE_BPID; + tmp++; + tmp2++; + } + res = cvmx_ilk_cal_setup_rx (interface, cvmx_ilk_chans[interface], + calent, CVMX_ILK_RX_FIFO_WM, 1); + if (res < 0) + { + pipe_base -= cvmx_ilk_chans[interface]; + pknd_base -= cvmx_ilk_chans[interface]; + res = 0; + goto err_free_calent; + } + res = __cvmx_helper_ilk_enumerate(interface + CVMX_ILK_GBL_BASE); + + goto out; + +err_free_calent: +#ifdef CVMX_BUILD_FOR_LINUX_KERNEL + kfree (calent); +#else + /* no free() for cvmx_bootmem_alloc() */ +#endif + +err_free_chpknd: +#ifdef CVMX_BUILD_FOR_LINUX_KERNEL + kfree (chpknd); +#else + /* no free() for cvmx_bootmem_alloc() */ +#endif + +err_free_pch: +#ifdef CVMX_BUILD_FOR_LINUX_KERNEL + kfree (pch); +#else + /* no free() for cvmx_bootmem_alloc() */ +#endif +out: + return res; +} + +/** + * @INTERNAL + * Bringup and enable ILK interface. After this call packet + * I/O should be fully functional. This is called with IPD + * enabled but PKO disabled. + * + * @param interface Interface to bring up + * + * @return Zero on success, negative on failure + */ +int __cvmx_helper_ilk_enable(int interface) +{ + interface -= CVMX_ILK_GBL_BASE; + return cvmx_ilk_enable(interface); +} + +/** + * @INTERNAL + * Return the link state of an IPD/PKO port as returned by ILK link status. + * + * @param ipd_port IPD/PKO port to query + * + * @return Link state + */ +cvmx_helper_link_info_t __cvmx_helper_ilk_link_get(int ipd_port) +{ + cvmx_helper_link_info_t result; + int interface = cvmx_helper_get_interface_num(ipd_port); + int retry_count = 0; + cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1; + cvmx_ilk_rxx_int_t ilk_rxx_int; + int lanes = 0; + + result.u64 = 0; + interface -= CVMX_ILK_GBL_BASE; + +retry: + retry_count++; + if (retry_count > 10) + goto out; + + ilk_rxx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG1(interface)); + ilk_rxx_int.u64 = cvmx_read_csr (CVMX_ILK_RXX_INT(interface)); + + /* Clear all RX status bits */ + if (ilk_rxx_int.u64) + cvmx_write_csr(CVMX_ILK_RXX_INT(interface), ilk_rxx_int.u64); + + if (ilk_rxx_cfg1.s.rx_bdry_lock_ena == 0) + { + /* We need to start looking for work boundary lock */ + ilk_rxx_cfg1.s.rx_bdry_lock_ena = cvmx_ilk_get_intf_ln_msk(interface); + ilk_rxx_cfg1.s.rx_align_ena = 0; + cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); + //cvmx_dprintf("ILK%d: Looking for word boundary lock\n", interface); + goto retry; + } + + if (ilk_rxx_cfg1.s.rx_align_ena == 0) + { + if (ilk_rxx_int.s.word_sync_done) + { + ilk_rxx_cfg1.s.rx_align_ena = 1; + cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); + //printf("ILK%d: Looking for lane alignment\n", interface); + goto retry; + } + goto out; + } + + if (ilk_rxx_int.s.lane_align_fail) + { + ilk_rxx_cfg1.s.rx_bdry_lock_ena = 0; + ilk_rxx_cfg1.s.rx_align_ena = 0; + cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); + cvmx_dprintf("ILK%d: Lane alignment failed\n", interface); + goto out; + } + + if (ilk_rxx_int.s.lane_align_done) + { + //cvmx_dprintf("ILK%d: Lane alignment complete\n", interface); + } + + lanes = cvmx_pop(ilk_rxx_cfg1.s.rx_bdry_lock_ena); + + result.s.link_up = 1; + result.s.full_duplex = 1; + result.s.speed = cvmx_qlm_get_gbaud_mhz(1+interface) * 64 / 67; + result.s.speed *= lanes; + +out: + /* If the link is down we will force disable the RX path. If it up, we'll + set it to match the TX state set by the if_enable call */ + if (result.s.link_up) + { + cvmx_ilk_txx_cfg1_t ilk_txx_cfg1; + ilk_txx_cfg1.u64 = cvmx_read_csr(CVMX_ILK_TXX_CFG1(interface)); + ilk_rxx_cfg1.s.pkt_ena = ilk_txx_cfg1.s.pkt_ena; + cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); + //cvmx_dprintf("ILK%d: link up, %d Mbps, Full duplex mode, %d lanes\n", interface, result.s.speed, lanes); + } + else + { + ilk_rxx_cfg1.s.pkt_ena = 0; + cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); + //cvmx_dprintf("ILK link down\n"); + } + return result; +} + +/** + * @INTERNAL + * Set the link state of an IPD/PKO port. + * + * @param ipd_port IPD/PKO port to configure + * @param link_info The new link state + * + * @return Zero on success, negative on failure + */ +int __cvmx_helper_ilk_link_set(int ipd_port, cvmx_helper_link_info_t link_info) +{ + /* nothing to do */ + + return 0; +} + +/** + * Display ilk interface statistics. + * + */ +void __cvmx_helper_ilk_show_stats (void) +{ + int i, j; + unsigned char *pchans, num_chans; + unsigned int chan_tmp[CVMX_MAX_ILK_CHANS]; + cvmx_ilk_stats_ctrl_t ilk_stats_ctrl; + + for (i = 0; i < CVMX_NUM_ILK_INTF; i++) + { + cvmx_ilk_get_chan_info (i, &pchans, &num_chans); + + memset (chan_tmp, 0, CVMX_MAX_ILK_CHANS * sizeof (int)); + for (j = 0; j < num_chans; j++) + chan_tmp[j] = pchans[j]; + + ilk_stats_ctrl.chan_list = chan_tmp; + ilk_stats_ctrl.num_chans = num_chans; + ilk_stats_ctrl.clr_on_rd = 0; + cvmx_ilk_show_stats (i, &ilk_stats_ctrl); + } +} + +#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ |