cvmx-helper-util.c revision 215990
1/***********************license start*************** 2 * Copyright (c) 2003-2010 Cavium Networks (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 Networks 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 NETWORKS 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 42 43 44 45 46/** 47 * @file 48 * 49 * Small helper utilities. 50 * 51 * <hr>$Revision: 49448 $<hr> 52 */ 53#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 54#include <linux/module.h> 55 56#include <asm/octeon/cvmx.h> 57#include <asm/octeon/cvmx-config.h> 58#include <asm/octeon/cvmx-pip.h> 59#include <asm/octeon/cvmx-ipd.h> 60#include <asm/octeon/cvmx-helper.h> 61#include <asm/octeon/cvmx-gmxx-defs.h> 62#include <asm/octeon/cvmx-pko-defs.h> 63#else 64#if !defined(__FreeBSD__) || !defined(_KERNEL) 65#include "executive-config.h" 66#include "cvmx-config.h" 67#endif 68#include "cvmx.h" 69#include "cvmx-bootmem.h" 70#include "cvmx-fpa.h" 71#include "cvmx-pip.h" 72#include "cvmx-pko.h" 73#include "cvmx-ipd.h" 74#include "cvmx-gmx.h" 75#include "cvmx-spi.h" 76#include "cvmx-sysinfo.h" 77#include "cvmx-helper.h" 78#include "cvmx-helper-util.h" 79#include "cvmx-version.h" 80#endif 81 82#ifdef CVMX_ENABLE_HELPER_FUNCTIONS 83 84#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 85/** 86 * Get the version of the CVMX libraries. 87 * 88 * @return Version string. Note this buffer is allocated statically 89 * and will be shared by all callers. 90 */ 91const char *cvmx_helper_get_version(void) 92{ 93 return OCTEON_SDK_VERSION_STRING; 94} 95#endif 96 97/** 98 * Convert a interface mode into a human readable string 99 * 100 * @param mode Mode to convert 101 * 102 * @return String 103 */ 104const char *cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t mode) 105{ 106 switch (mode) 107 { 108 case CVMX_HELPER_INTERFACE_MODE_DISABLED: return "DISABLED"; 109 case CVMX_HELPER_INTERFACE_MODE_RGMII: return "RGMII"; 110 case CVMX_HELPER_INTERFACE_MODE_GMII: return "GMII"; 111 case CVMX_HELPER_INTERFACE_MODE_SPI: return "SPI"; 112 case CVMX_HELPER_INTERFACE_MODE_PCIE: return "PCIE"; 113 case CVMX_HELPER_INTERFACE_MODE_XAUI: return "XAUI"; 114 case CVMX_HELPER_INTERFACE_MODE_SGMII: return "SGMII"; 115 case CVMX_HELPER_INTERFACE_MODE_PICMG: return "PICMG"; 116 case CVMX_HELPER_INTERFACE_MODE_NPI: return "NPI"; 117 case CVMX_HELPER_INTERFACE_MODE_LOOP: return "LOOP"; 118 case CVMX_HELPER_INTERFACE_MODE_SRIO: return "SRIO"; 119 } 120 return "UNKNOWN"; 121} 122 123 124/** 125 * Debug routine to dump the packet structure to the console 126 * 127 * @param work Work queue entry containing the packet to dump 128 * @return 129 */ 130int cvmx_helper_dump_packet(cvmx_wqe_t *work) 131{ 132 uint64_t count; 133 uint64_t remaining_bytes; 134 cvmx_buf_ptr_t buffer_ptr; 135 uint64_t start_of_buffer; 136 uint8_t * data_address; 137 uint8_t * end_of_data; 138 139 cvmx_dprintf("Packet Length: %u\n", work->len); 140 cvmx_dprintf(" Input Port: %u\n", work->ipprt); 141 cvmx_dprintf(" QoS: %u\n", work->qos); 142 cvmx_dprintf(" Buffers: %u\n", work->word2.s.bufs); 143 144 if (work->word2.s.bufs == 0) 145 { 146 cvmx_ipd_wqe_fpa_queue_t wqe_pool; 147 wqe_pool.u64 = cvmx_read_csr(CVMX_IPD_WQE_FPA_QUEUE); 148 buffer_ptr.u64 = 0; 149 buffer_ptr.s.pool = wqe_pool.s.wqe_pool; 150 buffer_ptr.s.size = 128; 151 buffer_ptr.s.addr = cvmx_ptr_to_phys(work->packet_data); 152 if (cvmx_likely(!work->word2.s.not_IP)) 153 { 154 cvmx_pip_ip_offset_t pip_ip_offset; 155 pip_ip_offset.u64 = cvmx_read_csr(CVMX_PIP_IP_OFFSET); 156 buffer_ptr.s.addr += (pip_ip_offset.s.offset<<3) - work->word2.s.ip_offset; 157 buffer_ptr.s.addr += (work->word2.s.is_v6^1)<<2; 158 } 159 else 160 { 161 /* WARNING: This code assume that the packet is not RAW. If it was, 162 we would use PIP_GBL_CFG[RAW_SHF] instead of 163 PIP_GBL_CFG[NIP_SHF] */ 164 cvmx_pip_gbl_cfg_t pip_gbl_cfg; 165 pip_gbl_cfg.u64 = cvmx_read_csr(CVMX_PIP_GBL_CFG); 166 buffer_ptr.s.addr += pip_gbl_cfg.s.nip_shf; 167 } 168 } 169 else 170 buffer_ptr = work->packet_ptr; 171 remaining_bytes = work->len; 172 173 while (remaining_bytes) 174 { 175 start_of_buffer = ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7; 176 cvmx_dprintf(" Buffer Start:%llx\n", (unsigned long long)start_of_buffer); 177 cvmx_dprintf(" Buffer I : %u\n", buffer_ptr.s.i); 178 cvmx_dprintf(" Buffer Back: %u\n", buffer_ptr.s.back); 179 cvmx_dprintf(" Buffer Pool: %u\n", buffer_ptr.s.pool); 180 cvmx_dprintf(" Buffer Data: %llx\n", (unsigned long long)buffer_ptr.s.addr); 181 cvmx_dprintf(" Buffer Size: %u\n", buffer_ptr.s.size); 182 183 cvmx_dprintf("\t\t"); 184 data_address = (uint8_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr); 185 end_of_data = data_address + buffer_ptr.s.size; 186 count = 0; 187 while (data_address < end_of_data) 188 { 189 if (remaining_bytes == 0) 190 break; 191 else 192 remaining_bytes--; 193 cvmx_dprintf("%02x", (unsigned int)*data_address); 194 data_address++; 195 if (remaining_bytes && (count == 7)) 196 { 197 cvmx_dprintf("\n\t\t"); 198 count = 0; 199 } 200 else 201 count++; 202 } 203 cvmx_dprintf("\n"); 204 205 if (remaining_bytes) 206 buffer_ptr = *(cvmx_buf_ptr_t*)cvmx_phys_to_ptr(buffer_ptr.s.addr - 8); 207 } 208 return 0; 209} 210 211 212/** 213 * Setup Random Early Drop on a specific input queue 214 * 215 * @param queue Input queue to setup RED on (0-7) 216 * @param pass_thresh 217 * Packets will begin slowly dropping when there are less than 218 * this many packet buffers free in FPA 0. 219 * @param drop_thresh 220 * All incomming packets will be dropped when there are less 221 * than this many free packet buffers in FPA 0. 222 * @return Zero on success. Negative on failure 223 */ 224int cvmx_helper_setup_red_queue(int queue, int pass_thresh, int drop_thresh) 225{ 226 cvmx_ipd_qosx_red_marks_t red_marks; 227 cvmx_ipd_red_quex_param_t red_param; 228 229 /* Set RED to begin dropping packets when there are pass_thresh buffers 230 left. It will linearly drop more packets until reaching drop_thresh 231 buffers */ 232 red_marks.u64 = 0; 233 red_marks.s.drop = drop_thresh; 234 red_marks.s.pass = pass_thresh; 235 cvmx_write_csr(CVMX_IPD_QOSX_RED_MARKS(queue), red_marks.u64); 236 237 /* Use the actual queue 0 counter, not the average */ 238 red_param.u64 = 0; 239 red_param.s.prb_con = (255ul<<24) / (red_marks.s.pass - red_marks.s.drop); 240 red_param.s.avg_con = 1; 241 red_param.s.new_con = 255; 242 red_param.s.use_pcnt = 1; 243 cvmx_write_csr(CVMX_IPD_RED_QUEX_PARAM(queue), red_param.u64); 244 return 0; 245} 246 247 248/** 249 * Setup Random Early Drop to automatically begin dropping packets. 250 * 251 * @param pass_thresh 252 * Packets will begin slowly dropping when there are less than 253 * this many packet buffers free in FPA 0. 254 * @param drop_thresh 255 * All incomming packets will be dropped when there are less 256 * than this many free packet buffers in FPA 0. 257 * @return Zero on success. Negative on failure 258 */ 259int cvmx_helper_setup_red(int pass_thresh, int drop_thresh) 260{ 261 cvmx_ipd_portx_bp_page_cnt_t page_cnt; 262 cvmx_ipd_bp_prt_red_end_t ipd_bp_prt_red_end; 263 cvmx_ipd_red_port_enable_t red_port_enable; 264 int queue; 265 int interface; 266 int port; 267 268 /* Disable backpressure based on queued buffers. It needs SW support */ 269 page_cnt.u64 = 0; 270 page_cnt.s.bp_enb = 0; 271 page_cnt.s.page_cnt = 100; 272 for (interface=0; interface<2; interface++) 273 { 274 for (port=cvmx_helper_get_first_ipd_port(interface); port<cvmx_helper_get_last_ipd_port(interface); port++) 275 cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port), page_cnt.u64); 276 } 277 278 for (queue=0; queue<8; queue++) 279 cvmx_helper_setup_red_queue(queue, pass_thresh, drop_thresh); 280 281 /* Shutoff the dropping based on the per port page count. SW isn't 282 decrementing it right now */ 283 ipd_bp_prt_red_end.u64 = 0; 284 ipd_bp_prt_red_end.s.prt_enb = 0; 285 cvmx_write_csr(CVMX_IPD_BP_PRT_RED_END, ipd_bp_prt_red_end.u64); 286 287 red_port_enable.u64 = 0; 288 red_port_enable.s.prt_enb = 0xfffffffffull; 289 red_port_enable.s.avg_dly = 10000; 290 red_port_enable.s.prb_dly = 10000; 291 cvmx_write_csr(CVMX_IPD_RED_PORT_ENABLE, red_port_enable.u64); 292 293 /* Shutoff the dropping of packets based on RED for SRIO ports */ 294 if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) 295 { 296 cvmx_ipd_red_port_enable2_t red_port_enable2; 297 red_port_enable2.u64 = 0; 298 red_port_enable2.s.prt_enb = 0xf0; 299 cvmx_write_csr(CVMX_IPD_RED_PORT_ENABLE2, red_port_enable2.u64); 300 } 301 302 return 0; 303} 304#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 305EXPORT_SYMBOL(cvmx_helper_setup_red); 306#endif 307 308 309/** 310 * @INTERNAL 311 * Setup the common GMX settings that determine the number of 312 * ports. These setting apply to almost all configurations of all 313 * chips. 314 * 315 * @param interface Interface to configure 316 * @param num_ports Number of ports on the interface 317 * 318 * @return Zero on success, negative on failure 319 */ 320int __cvmx_helper_setup_gmx(int interface, int num_ports) 321{ 322 cvmx_gmxx_tx_prts_t gmx_tx_prts; 323 cvmx_gmxx_rx_prts_t gmx_rx_prts; 324 cvmx_pko_reg_gmx_port_mode_t pko_mode; 325 cvmx_gmxx_txx_thresh_t gmx_tx_thresh; 326 int index; 327 328 /* Tell GMX the number of TX ports on this interface */ 329 gmx_tx_prts.u64 = cvmx_read_csr(CVMX_GMXX_TX_PRTS(interface)); 330 gmx_tx_prts.s.prts = num_ports; 331 cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), gmx_tx_prts.u64); 332 333 /* Tell GMX the number of RX ports on this interface. This only 334 ** applies to *GMII and XAUI ports */ 335 if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_RGMII 336 || cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_SGMII 337 || cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_GMII 338 || cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_XAUI) 339 { 340 if (num_ports > 4) 341 { 342 cvmx_dprintf("__cvmx_helper_setup_gmx: Illegal num_ports\n"); 343 return(-1); 344 } 345 346 gmx_rx_prts.u64 = cvmx_read_csr(CVMX_GMXX_RX_PRTS(interface)); 347 gmx_rx_prts.s.prts = num_ports; 348 cvmx_write_csr(CVMX_GMXX_RX_PRTS(interface), gmx_rx_prts.u64); 349 } 350 351 /* Skip setting CVMX_PKO_REG_GMX_PORT_MODE on 30XX, 31XX, and 50XX */ 352 if (!OCTEON_IS_MODEL(OCTEON_CN30XX) && !OCTEON_IS_MODEL(OCTEON_CN31XX) && !OCTEON_IS_MODEL(OCTEON_CN50XX)) 353 { 354 /* Tell PKO the number of ports on this interface */ 355 pko_mode.u64 = cvmx_read_csr(CVMX_PKO_REG_GMX_PORT_MODE); 356 if (interface == 0) 357 { 358 if (num_ports == 1) 359 pko_mode.s.mode0 = 4; 360 else if (num_ports == 2) 361 pko_mode.s.mode0 = 3; 362 else if (num_ports <= 4) 363 pko_mode.s.mode0 = 2; 364 else if (num_ports <= 8) 365 pko_mode.s.mode0 = 1; 366 else 367 pko_mode.s.mode0 = 0; 368 } 369 else 370 { 371 if (num_ports == 1) 372 pko_mode.s.mode1 = 4; 373 else if (num_ports == 2) 374 pko_mode.s.mode1 = 3; 375 else if (num_ports <= 4) 376 pko_mode.s.mode1 = 2; 377 else if (num_ports <= 8) 378 pko_mode.s.mode1 = 1; 379 else 380 pko_mode.s.mode1 = 0; 381 } 382 cvmx_write_csr(CVMX_PKO_REG_GMX_PORT_MODE, pko_mode.u64); 383 } 384 385 /* Set GMX to buffer as much data as possible before starting transmit. 386 This reduces the chances that we have a TX under run due to memory 387 contention. Any packet that fits entirely in the GMX FIFO can never 388 have an under run regardless of memory load */ 389 gmx_tx_thresh.u64 = cvmx_read_csr(CVMX_GMXX_TXX_THRESH(0, interface)); 390 if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) 391 { 392 /* These chips have a fixed max threshold of 0x40 */ 393 gmx_tx_thresh.s.cnt = 0x40; 394 } 395 else 396 { 397 /* Choose the max value for the number of ports */ 398 if (num_ports <= 1) 399 gmx_tx_thresh.s.cnt = 0x100 / 1; 400 else if (num_ports == 2) 401 gmx_tx_thresh.s.cnt = 0x100 / 2; 402 else 403 gmx_tx_thresh.s.cnt = 0x100 / 4; 404 } 405 /* SPI and XAUI can have lots of ports but the GMX hardware only ever has 406 a max of 4 */ 407 if (num_ports > 4) 408 num_ports = 4; 409 for (index=0; index<num_ports; index++) 410 cvmx_write_csr(CVMX_GMXX_TXX_THRESH(index, interface), gmx_tx_thresh.u64); 411 412 return 0; 413} 414 415 416/** 417 * Returns the IPD/PKO port number for a port on the given 418 * interface. 419 * 420 * @param interface Interface to use 421 * @param port Port on the interface 422 * 423 * @return IPD/PKO port number 424 */ 425int cvmx_helper_get_ipd_port(int interface, int port) 426{ 427 switch (interface) 428 { 429 case 0: return port; 430 case 1: return port + 16; 431 case 2: return port + 32; 432 case 3: return port + 36; 433 case 4: return port + 40; 434 case 5: return port + 42; 435 } 436 return -1; 437} 438#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 439EXPORT_SYMBOL(cvmx_helper_get_ipd_port); 440#endif 441 442#endif /* CVMX_ENABLE_HELPER_FUNCTIONS */ 443 444 445/** 446 * Returns the interface number for an IPD/PKO port number. 447 * 448 * @param ipd_port IPD/PKO port number 449 * 450 * @return Interface number 451 */ 452int cvmx_helper_get_interface_num(int ipd_port) 453{ 454 if (ipd_port < 16) 455 return 0; 456 else if (ipd_port < 32) 457 return 1; 458 else if (ipd_port < 36) 459 return 2; 460 else if (ipd_port < 40) 461 return 3; 462 else if (ipd_port < 42) 463 return 4; 464 else if (ipd_port < 44) 465 return 5; 466 else 467 cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD port number\n"); 468 469 return -1; 470} 471#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 472EXPORT_SYMBOL(cvmx_helper_get_interface_num); 473#endif 474 475 476/** 477 * Returns the interface index number for an IPD/PKO port 478 * number. 479 * 480 * @param ipd_port IPD/PKO port number 481 * 482 * @return Interface index number 483 */ 484int cvmx_helper_get_interface_index_num(int ipd_port) 485{ 486 if (ipd_port < 32) 487 return ipd_port & 15; 488 else if (ipd_port < 40) 489 return ipd_port & 3; 490 else if (ipd_port < 44) 491 return ipd_port & 1; 492 else 493 cvmx_dprintf("cvmx_helper_get_interface_index_num: Illegal IPD port number\n"); 494 495 return -1; 496} 497#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 498EXPORT_SYMBOL(cvmx_helper_get_interface_index_num); 499#endif 500