cvmx-helper-ilk.c revision 232809
1/***********************license start*************** 2 * Copyright (c) 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 * Functions for ILK initialization, configuration, 44 * and monitoring. 45 * 46 * <hr>$Revision: 41586 $<hr> 47 */ 48 49#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 50#include <linux/module.h> 51 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> 61#else 62#include "executive-config.h" 63#include "cvmx-config.h" 64#include "cvmx.h" 65#include "cvmx-helper.h" 66#include "cvmx-helper-cfg.h" 67#include "cvmx-ilk.h" 68#include "cvmx-bootmem.h" 69#include "cvmx-pko.h" 70#include "cvmx-qlm.h" 71#endif 72 73#ifdef CVMX_ENABLE_PKO_FUNCTIONS 74 75int __cvmx_helper_ilk_enumerate(int interface) 76{ 77 interface -= CVMX_ILK_GBL_BASE; 78 return cvmx_ilk_chans[interface]; 79} 80 81/** 82 * @INTERNAL 83 * Probe a ILK interface and determine the number of ports 84 * connected to it. The ILK interface should still be down 85 * after this call. 86 * 87 * @param interface Interface to probe 88 * 89 * @return Number of ports on the interface. Zero to disable. 90 */ 91int __cvmx_helper_ilk_probe(int interface) 92{ 93 int i, j, res = -1; 94 static int pipe_base = 0, pknd_base = 0; 95 static cvmx_ilk_pipe_chan_t *pch = NULL, *tmp; 96 static cvmx_ilk_chan_pknd_t *chpknd = NULL, *tmp1; 97 static cvmx_ilk_cal_entry_t *calent = NULL, *tmp2; 98 99 if (!OCTEON_IS_MODEL(OCTEON_CN68XX)) 100 return 0; 101 102 interface -= CVMX_ILK_GBL_BASE; 103 if (interface >= CVMX_NUM_ILK_INTF) 104 return 0; 105 106 /* the configuration should be done only once */ 107 if (cvmx_ilk_get_intf_ena (interface)) 108 return cvmx_ilk_chans[interface]; 109 110 /* configure lanes and enable the link */ 111 res = cvmx_ilk_start_interface (interface, cvmx_ilk_lane_mask[interface]); 112 if (res < 0) 113 return 0; 114 115 /* set up the group of pipes available to ilk */ 116 if (pipe_base == 0) 117 pipe_base = __cvmx_pko_get_pipe (interface + CVMX_ILK_GBL_BASE, 0); 118 119 if (pipe_base == -1) 120 { 121 pipe_base = 0; 122 return 0; 123 } 124 125 res = cvmx_ilk_set_pipe (interface, pipe_base, cvmx_ilk_chans[interface]); 126 if (res < 0) 127 return 0; 128 129 /* set up pipe to channel mapping */ 130 i = pipe_base; 131 if (pch == NULL) 132 { 133 pch = (cvmx_ilk_pipe_chan_t *) 134#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 135 kmalloc(CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t), GFP_KERNEL); 136#else 137 cvmx_bootmem_alloc (CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t), 138 sizeof(cvmx_ilk_pipe_chan_t)); 139#endif 140 if (pch == NULL) 141 return 0; 142 } 143 144 memset (pch, 0, CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t)); 145 tmp = pch; 146 for (j = 0; j < cvmx_ilk_chans[interface]; j++) 147 { 148 tmp->pipe = i++; 149 tmp->chan = cvmx_ilk_chan_map[interface][j]; 150 tmp++; 151 } 152 res = cvmx_ilk_tx_set_channel (interface, pch, cvmx_ilk_chans[interface]); 153 if (res < 0) 154 { 155 res = 0; 156 goto err_free_pch; 157 } 158 pipe_base += cvmx_ilk_chans[interface]; 159 160 /* set up channel to pkind mapping */ 161 if (pknd_base == 0) 162 pknd_base = cvmx_helper_get_pknd (interface + CVMX_ILK_GBL_BASE, 0); 163 164 i = pknd_base; 165 if (chpknd == NULL) 166 { 167 chpknd = (cvmx_ilk_chan_pknd_t *) 168#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 169 kmalloc(CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t), GFP_KERNEL); 170#else 171 cvmx_bootmem_alloc (CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t), 172 sizeof(cvmx_ilk_chan_pknd_t)); 173#endif 174 if (chpknd == NULL) 175 { 176 pipe_base -= cvmx_ilk_chans[interface]; 177 res = 0; 178 goto err_free_pch; 179 } 180 } 181 182 memset (chpknd, 0, CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t)); 183 tmp1 = chpknd; 184 for (j = 0; j < cvmx_ilk_chans[interface]; j++) 185 { 186 tmp1->chan = cvmx_ilk_chan_map[interface][j]; 187 tmp1->pknd = i++; 188 tmp1++; 189 } 190 res = cvmx_ilk_rx_set_pknd (interface, chpknd, cvmx_ilk_chans[interface]); 191 if (res < 0) 192 { 193 pipe_base -= cvmx_ilk_chans[interface]; 194 res = 0; 195 goto err_free_chpknd; 196 } 197 pknd_base += cvmx_ilk_chans[interface]; 198 199 /* Set up tx calendar */ 200 if (calent == NULL) 201 { 202 calent = (cvmx_ilk_cal_entry_t *) 203#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 204 kmalloc(CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t), GFP_KERNEL); 205#else 206 cvmx_bootmem_alloc (CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t), 207 sizeof(cvmx_ilk_cal_entry_t)); 208#endif 209 if (calent == NULL) 210 { 211 pipe_base -= cvmx_ilk_chans[interface]; 212 pknd_base -= cvmx_ilk_chans[interface]; 213 res = 0; 214 goto err_free_chpknd; 215 } 216 } 217 218 memset (calent, 0, CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t)); 219 tmp1 = chpknd; 220 tmp2 = calent; 221 for (j = 0; j < cvmx_ilk_chans[interface]; j++) 222 { 223 tmp2->pipe_bpid = tmp1->pknd; 224 tmp2->ent_ctrl = PIPE_BPID; 225 tmp1++; 226 tmp2++; 227 } 228 res = cvmx_ilk_cal_setup_tx (interface, cvmx_ilk_chans[interface], 229 calent, 1); 230 if (res < 0) 231 { 232 pipe_base -= cvmx_ilk_chans[interface]; 233 pknd_base -= cvmx_ilk_chans[interface]; 234 res = 0; 235 goto err_free_calent; 236 } 237 238 /* set up rx calendar. allocated memory can be reused. 239 * this is because max pkind is always less than max pipe */ 240 memset (calent, 0, CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t)); 241 tmp = pch; 242 tmp2 = calent; 243 for (j = 0; j < cvmx_ilk_chans[interface]; j++) 244 { 245 tmp2->pipe_bpid = tmp->pipe; 246 tmp2->ent_ctrl = PIPE_BPID; 247 tmp++; 248 tmp2++; 249 } 250 res = cvmx_ilk_cal_setup_rx (interface, cvmx_ilk_chans[interface], 251 calent, CVMX_ILK_RX_FIFO_WM, 1); 252 if (res < 0) 253 { 254 pipe_base -= cvmx_ilk_chans[interface]; 255 pknd_base -= cvmx_ilk_chans[interface]; 256 res = 0; 257 goto err_free_calent; 258 } 259 res = __cvmx_helper_ilk_enumerate(interface + CVMX_ILK_GBL_BASE); 260 261 goto out; 262 263err_free_calent: 264#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 265 kfree (calent); 266#else 267 /* no free() for cvmx_bootmem_alloc() */ 268#endif 269 270err_free_chpknd: 271#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 272 kfree (chpknd); 273#else 274 /* no free() for cvmx_bootmem_alloc() */ 275#endif 276 277err_free_pch: 278#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 279 kfree (pch); 280#else 281 /* no free() for cvmx_bootmem_alloc() */ 282#endif 283out: 284 return res; 285} 286 287/** 288 * @INTERNAL 289 * Bringup and enable ILK interface. After this call packet 290 * I/O should be fully functional. This is called with IPD 291 * enabled but PKO disabled. 292 * 293 * @param interface Interface to bring up 294 * 295 * @return Zero on success, negative on failure 296 */ 297int __cvmx_helper_ilk_enable(int interface) 298{ 299 interface -= CVMX_ILK_GBL_BASE; 300 return cvmx_ilk_enable(interface); 301} 302 303/** 304 * @INTERNAL 305 * Return the link state of an IPD/PKO port as returned by ILK link status. 306 * 307 * @param ipd_port IPD/PKO port to query 308 * 309 * @return Link state 310 */ 311cvmx_helper_link_info_t __cvmx_helper_ilk_link_get(int ipd_port) 312{ 313 cvmx_helper_link_info_t result; 314 int interface = cvmx_helper_get_interface_num(ipd_port); 315 int retry_count = 0; 316 cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1; 317 cvmx_ilk_rxx_int_t ilk_rxx_int; 318 int lanes = 0; 319 320 result.u64 = 0; 321 interface -= CVMX_ILK_GBL_BASE; 322 323retry: 324 retry_count++; 325 if (retry_count > 10) 326 goto out; 327 328 ilk_rxx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG1(interface)); 329 ilk_rxx_int.u64 = cvmx_read_csr (CVMX_ILK_RXX_INT(interface)); 330 331 /* Clear all RX status bits */ 332 if (ilk_rxx_int.u64) 333 cvmx_write_csr(CVMX_ILK_RXX_INT(interface), ilk_rxx_int.u64); 334 335 if (ilk_rxx_cfg1.s.rx_bdry_lock_ena == 0) 336 { 337 /* We need to start looking for work boundary lock */ 338 ilk_rxx_cfg1.s.rx_bdry_lock_ena = cvmx_ilk_get_intf_ln_msk(interface); 339 ilk_rxx_cfg1.s.rx_align_ena = 0; 340 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); 341 //cvmx_dprintf("ILK%d: Looking for word boundary lock\n", interface); 342 goto retry; 343 } 344 345 if (ilk_rxx_cfg1.s.rx_align_ena == 0) 346 { 347 if (ilk_rxx_int.s.word_sync_done) 348 { 349 ilk_rxx_cfg1.s.rx_align_ena = 1; 350 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); 351 //printf("ILK%d: Looking for lane alignment\n", interface); 352 goto retry; 353 } 354 goto out; 355 } 356 357 if (ilk_rxx_int.s.lane_align_fail) 358 { 359 ilk_rxx_cfg1.s.rx_bdry_lock_ena = 0; 360 ilk_rxx_cfg1.s.rx_align_ena = 0; 361 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); 362 cvmx_dprintf("ILK%d: Lane alignment failed\n", interface); 363 goto out; 364 } 365 366 if (ilk_rxx_int.s.lane_align_done) 367 { 368 //cvmx_dprintf("ILK%d: Lane alignment complete\n", interface); 369 } 370 371 lanes = cvmx_pop(ilk_rxx_cfg1.s.rx_bdry_lock_ena); 372 373 result.s.link_up = 1; 374 result.s.full_duplex = 1; 375 result.s.speed = cvmx_qlm_get_gbaud_mhz(1+interface) * 64 / 67; 376 result.s.speed *= lanes; 377 378out: 379 /* If the link is down we will force disable the RX path. If it up, we'll 380 set it to match the TX state set by the if_enable call */ 381 if (result.s.link_up) 382 { 383 cvmx_ilk_txx_cfg1_t ilk_txx_cfg1; 384 ilk_txx_cfg1.u64 = cvmx_read_csr(CVMX_ILK_TXX_CFG1(interface)); 385 ilk_rxx_cfg1.s.pkt_ena = ilk_txx_cfg1.s.pkt_ena; 386 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); 387 //cvmx_dprintf("ILK%d: link up, %d Mbps, Full duplex mode, %d lanes\n", interface, result.s.speed, lanes); 388 } 389 else 390 { 391 ilk_rxx_cfg1.s.pkt_ena = 0; 392 cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64); 393 //cvmx_dprintf("ILK link down\n"); 394 } 395 return result; 396} 397 398/** 399 * @INTERNAL 400 * Set the link state of an IPD/PKO port. 401 * 402 * @param ipd_port IPD/PKO port to configure 403 * @param link_info The new link state 404 * 405 * @return Zero on success, negative on failure 406 */ 407int __cvmx_helper_ilk_link_set(int ipd_port, cvmx_helper_link_info_t link_info) 408{ 409 /* nothing to do */ 410 411 return 0; 412} 413 414/** 415 * Display ilk interface statistics. 416 * 417 */ 418void __cvmx_helper_ilk_show_stats (void) 419{ 420 int i, j; 421 unsigned char *pchans, num_chans; 422 unsigned int chan_tmp[CVMX_MAX_ILK_CHANS]; 423 cvmx_ilk_stats_ctrl_t ilk_stats_ctrl; 424 425 for (i = 0; i < CVMX_NUM_ILK_INTF; i++) 426 { 427 cvmx_ilk_get_chan_info (i, &pchans, &num_chans); 428 429 memset (chan_tmp, 0, CVMX_MAX_ILK_CHANS * sizeof (int)); 430 for (j = 0; j < num_chans; j++) 431 chan_tmp[j] = pchans[j]; 432 433 ilk_stats_ctrl.chan_list = chan_tmp; 434 ilk_stats_ctrl.num_chans = num_chans; 435 ilk_stats_ctrl.clr_on_rd = 0; 436 cvmx_ilk_show_stats (i, &ilk_stats_ctrl); 437 } 438} 439 440#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ 441