1210284Sjmallett/***********************license start*************** 2232812Sjmallett * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights 3215990Sjmallett * reserved. 4210284Sjmallett * 5210284Sjmallett * 6215990Sjmallett * Redistribution and use in source and binary forms, with or without 7215990Sjmallett * modification, are permitted provided that the following conditions are 8215990Sjmallett * met: 9210284Sjmallett * 10215990Sjmallett * * Redistributions of source code must retain the above copyright 11215990Sjmallett * notice, this list of conditions and the following disclaimer. 12210284Sjmallett * 13215990Sjmallett * * Redistributions in binary form must reproduce the above 14215990Sjmallett * copyright notice, this list of conditions and the following 15215990Sjmallett * disclaimer in the documentation and/or other materials provided 16215990Sjmallett * with the distribution. 17215990Sjmallett 18232812Sjmallett * * Neither the name of Cavium Inc. nor the names of 19215990Sjmallett * its contributors may be used to endorse or promote products 20215990Sjmallett * derived from this software without specific prior written 21215990Sjmallett * permission. 22215990Sjmallett 23215990Sjmallett * This Software, including technical data, may be subject to U.S. export control 24215990Sjmallett * laws, including the U.S. Export Administration Act and its associated 25215990Sjmallett * regulations, and may be subject to export or import regulations in other 26215990Sjmallett * countries. 27215990Sjmallett 28215990Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR 30215990Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO 31215990Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR 32215990Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM 33215990Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, 34215990Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF 35215990Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR 36215990Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR 37215990Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 38210284Sjmallett ***********************license end**************************************/ 39210284Sjmallett 40210284Sjmallett 41210284Sjmallett 42210284Sjmallett 43210284Sjmallett 44210284Sjmallett 45215990Sjmallett 46210284Sjmallett/** 47210284Sjmallett * @file 48210284Sjmallett * 49210284Sjmallett * Small helper utilities. 50210284Sjmallett * 51232812Sjmallett * <hr>$Revision: 70030 $<hr> 52210284Sjmallett */ 53215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 54215990Sjmallett#include <linux/module.h> 55232812Sjmallett#include <linux/slab.h> \ 56215990Sjmallett 57215990Sjmallett#include <asm/octeon/cvmx.h> 58215990Sjmallett#include <asm/octeon/cvmx-config.h> 59215990Sjmallett#include <asm/octeon/cvmx-pip.h> 60215990Sjmallett#include <asm/octeon/cvmx-ipd.h> 61215990Sjmallett#include <asm/octeon/cvmx-helper.h> 62215990Sjmallett#include <asm/octeon/cvmx-gmxx-defs.h> 63215990Sjmallett#include <asm/octeon/cvmx-pko-defs.h> 64232812Sjmallett#include <asm/octeon/cvmx-pko.h> 65232812Sjmallett#include <asm/octeon/cvmx-sli-defs.h> 66232812Sjmallett#include <asm/octeon/cvmx-pexp-defs.h> 67232812Sjmallett#include <asm/octeon/cvmx-helper-cfg.h> 68215990Sjmallett#else 69215990Sjmallett#if !defined(__FreeBSD__) || !defined(_KERNEL) 70215990Sjmallett#include "executive-config.h" 71215990Sjmallett#include "cvmx-config.h" 72215990Sjmallett#endif 73210284Sjmallett#include "cvmx.h" 74210284Sjmallett#include "cvmx-bootmem.h" 75210284Sjmallett#include "cvmx-fpa.h" 76210284Sjmallett#include "cvmx-pip.h" 77210284Sjmallett#include "cvmx-pko.h" 78232812Sjmallett#include "cvmx-ilk.h" 79210284Sjmallett#include "cvmx-ipd.h" 80210284Sjmallett#include "cvmx-gmx.h" 81210284Sjmallett#include "cvmx-spi.h" 82210284Sjmallett#include "cvmx-sysinfo.h" 83210284Sjmallett#include "cvmx-helper.h" 84210284Sjmallett#include "cvmx-helper-util.h" 85210284Sjmallett#include "cvmx-version.h" 86232812Sjmallett#include "cvmx-helper-ilk.h" 87232812Sjmallett#include "cvmx-helper-cfg.h" 88215990Sjmallett#endif 89210284Sjmallett 90210284Sjmallett#ifdef CVMX_ENABLE_HELPER_FUNCTIONS 91210284Sjmallett 92232812Sjmallettstruct cvmx_iface { 93232812Sjmallett int cvif_ipd_nports; 94232812Sjmallett int cvif_has_fcs; /* PKO fcs for this interface. */ 95232812Sjmallett enum cvmx_pko_padding cvif_padding; 96232812Sjmallett cvmx_helper_link_info_t *cvif_ipd_port_link_info; 97232812Sjmallett}; 98232812Sjmallett 99232812Sjmallett/* 100232812Sjmallett * This has to be static as u-boot expects to probe an interface and 101232812Sjmallett * gets the number of its ports. 102232812Sjmallett */ 103232812Sjmallettstatic CVMX_SHARED struct cvmx_iface cvmx_interfaces[CVMX_HELPER_MAX_IFACE]; 104232812Sjmallett 105215990Sjmallett#ifndef CVMX_BUILD_FOR_LINUX_KERNEL 106210284Sjmallett/** 107210284Sjmallett * Get the version of the CVMX libraries. 108210284Sjmallett * 109210284Sjmallett * @return Version string. Note this buffer is allocated statically 110210284Sjmallett * and will be shared by all callers. 111210284Sjmallett */ 112210284Sjmallettconst char *cvmx_helper_get_version(void) 113210284Sjmallett{ 114210284Sjmallett return OCTEON_SDK_VERSION_STRING; 115210284Sjmallett} 116215990Sjmallett#endif 117210284Sjmallett 118210284Sjmallett/** 119210284Sjmallett * Convert a interface mode into a human readable string 120210284Sjmallett * 121210284Sjmallett * @param mode Mode to convert 122210284Sjmallett * 123210284Sjmallett * @return String 124210284Sjmallett */ 125210284Sjmallettconst char *cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t mode) 126210284Sjmallett{ 127210284Sjmallett switch (mode) 128210284Sjmallett { 129210284Sjmallett case CVMX_HELPER_INTERFACE_MODE_DISABLED: return "DISABLED"; 130210284Sjmallett case CVMX_HELPER_INTERFACE_MODE_RGMII: return "RGMII"; 131210284Sjmallett case CVMX_HELPER_INTERFACE_MODE_GMII: return "GMII"; 132210284Sjmallett case CVMX_HELPER_INTERFACE_MODE_SPI: return "SPI"; 133210284Sjmallett case CVMX_HELPER_INTERFACE_MODE_PCIE: return "PCIE"; 134210284Sjmallett case CVMX_HELPER_INTERFACE_MODE_XAUI: return "XAUI"; 135232812Sjmallett case CVMX_HELPER_INTERFACE_MODE_RXAUI: return "RXAUI"; 136210284Sjmallett case CVMX_HELPER_INTERFACE_MODE_SGMII: return "SGMII"; 137210284Sjmallett case CVMX_HELPER_INTERFACE_MODE_PICMG: return "PICMG"; 138210284Sjmallett case CVMX_HELPER_INTERFACE_MODE_NPI: return "NPI"; 139210284Sjmallett case CVMX_HELPER_INTERFACE_MODE_LOOP: return "LOOP"; 140215990Sjmallett case CVMX_HELPER_INTERFACE_MODE_SRIO: return "SRIO"; 141232812Sjmallett case CVMX_HELPER_INTERFACE_MODE_ILK: return "ILK"; 142210284Sjmallett } 143210284Sjmallett return "UNKNOWN"; 144210284Sjmallett} 145210284Sjmallett 146210284Sjmallett 147210284Sjmallett/** 148210284Sjmallett * Debug routine to dump the packet structure to the console 149210284Sjmallett * 150210284Sjmallett * @param work Work queue entry containing the packet to dump 151210284Sjmallett * @return 152210284Sjmallett */ 153210284Sjmallettint cvmx_helper_dump_packet(cvmx_wqe_t *work) 154210284Sjmallett{ 155210284Sjmallett uint64_t count; 156210284Sjmallett uint64_t remaining_bytes; 157210284Sjmallett cvmx_buf_ptr_t buffer_ptr; 158210284Sjmallett uint64_t start_of_buffer; 159210284Sjmallett uint8_t * data_address; 160210284Sjmallett uint8_t * end_of_data; 161210284Sjmallett 162232812Sjmallett cvmx_dprintf("Packet Length: %u\n", cvmx_wqe_get_len(work)); 163232812Sjmallett cvmx_dprintf(" Input Port: %u\n", cvmx_wqe_get_port(work)); 164232812Sjmallett cvmx_dprintf(" QoS: %u\n", cvmx_wqe_get_qos(work)); 165210284Sjmallett cvmx_dprintf(" Buffers: %u\n", work->word2.s.bufs); 166210284Sjmallett 167210284Sjmallett if (work->word2.s.bufs == 0) 168210284Sjmallett { 169210284Sjmallett cvmx_ipd_wqe_fpa_queue_t wqe_pool; 170210284Sjmallett wqe_pool.u64 = cvmx_read_csr(CVMX_IPD_WQE_FPA_QUEUE); 171210284Sjmallett buffer_ptr.u64 = 0; 172210284Sjmallett buffer_ptr.s.pool = wqe_pool.s.wqe_pool; 173210284Sjmallett buffer_ptr.s.size = 128; 174210284Sjmallett buffer_ptr.s.addr = cvmx_ptr_to_phys(work->packet_data); 175210284Sjmallett if (cvmx_likely(!work->word2.s.not_IP)) 176210284Sjmallett { 177210284Sjmallett cvmx_pip_ip_offset_t pip_ip_offset; 178210284Sjmallett pip_ip_offset.u64 = cvmx_read_csr(CVMX_PIP_IP_OFFSET); 179210284Sjmallett buffer_ptr.s.addr += (pip_ip_offset.s.offset<<3) - work->word2.s.ip_offset; 180210284Sjmallett buffer_ptr.s.addr += (work->word2.s.is_v6^1)<<2; 181210284Sjmallett } 182210284Sjmallett else 183210284Sjmallett { 184210284Sjmallett /* WARNING: This code assume that the packet is not RAW. If it was, 185210284Sjmallett we would use PIP_GBL_CFG[RAW_SHF] instead of 186210284Sjmallett PIP_GBL_CFG[NIP_SHF] */ 187210284Sjmallett cvmx_pip_gbl_cfg_t pip_gbl_cfg; 188210284Sjmallett pip_gbl_cfg.u64 = cvmx_read_csr(CVMX_PIP_GBL_CFG); 189210284Sjmallett buffer_ptr.s.addr += pip_gbl_cfg.s.nip_shf; 190210284Sjmallett } 191210284Sjmallett } 192210284Sjmallett else 193210284Sjmallett buffer_ptr = work->packet_ptr; 194232812Sjmallett remaining_bytes = cvmx_wqe_get_len(work); 195210284Sjmallett 196210284Sjmallett while (remaining_bytes) 197210284Sjmallett { 198210284Sjmallett start_of_buffer = ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7; 199210284Sjmallett cvmx_dprintf(" Buffer Start:%llx\n", (unsigned long long)start_of_buffer); 200210284Sjmallett cvmx_dprintf(" Buffer I : %u\n", buffer_ptr.s.i); 201210284Sjmallett cvmx_dprintf(" Buffer Back: %u\n", buffer_ptr.s.back); 202210284Sjmallett cvmx_dprintf(" Buffer Pool: %u\n", buffer_ptr.s.pool); 203210284Sjmallett cvmx_dprintf(" Buffer Data: %llx\n", (unsigned long long)buffer_ptr.s.addr); 204210284Sjmallett cvmx_dprintf(" Buffer Size: %u\n", buffer_ptr.s.size); 205210284Sjmallett 206210284Sjmallett cvmx_dprintf("\t\t"); 207210284Sjmallett data_address = (uint8_t *)cvmx_phys_to_ptr(buffer_ptr.s.addr); 208210284Sjmallett end_of_data = data_address + buffer_ptr.s.size; 209210284Sjmallett count = 0; 210210284Sjmallett while (data_address < end_of_data) 211210284Sjmallett { 212210284Sjmallett if (remaining_bytes == 0) 213210284Sjmallett break; 214210284Sjmallett else 215210284Sjmallett remaining_bytes--; 216210284Sjmallett cvmx_dprintf("%02x", (unsigned int)*data_address); 217210284Sjmallett data_address++; 218210284Sjmallett if (remaining_bytes && (count == 7)) 219210284Sjmallett { 220210284Sjmallett cvmx_dprintf("\n\t\t"); 221210284Sjmallett count = 0; 222210284Sjmallett } 223210284Sjmallett else 224210284Sjmallett count++; 225210284Sjmallett } 226210284Sjmallett cvmx_dprintf("\n"); 227210284Sjmallett 228210284Sjmallett if (remaining_bytes) 229210284Sjmallett buffer_ptr = *(cvmx_buf_ptr_t*)cvmx_phys_to_ptr(buffer_ptr.s.addr - 8); 230210284Sjmallett } 231210284Sjmallett return 0; 232210284Sjmallett} 233210284Sjmallett 234210284Sjmallett 235210284Sjmallett/** 236210284Sjmallett * Setup Random Early Drop on a specific input queue 237210284Sjmallett * 238210284Sjmallett * @param queue Input queue to setup RED on (0-7) 239210284Sjmallett * @param pass_thresh 240210284Sjmallett * Packets will begin slowly dropping when there are less than 241210284Sjmallett * this many packet buffers free in FPA 0. 242210284Sjmallett * @param drop_thresh 243210284Sjmallett * All incomming packets will be dropped when there are less 244210284Sjmallett * than this many free packet buffers in FPA 0. 245210284Sjmallett * @return Zero on success. Negative on failure 246210284Sjmallett */ 247210284Sjmallettint cvmx_helper_setup_red_queue(int queue, int pass_thresh, int drop_thresh) 248210284Sjmallett{ 249215990Sjmallett cvmx_ipd_qosx_red_marks_t red_marks; 250210284Sjmallett cvmx_ipd_red_quex_param_t red_param; 251210284Sjmallett 252210284Sjmallett /* Set RED to begin dropping packets when there are pass_thresh buffers 253210284Sjmallett left. It will linearly drop more packets until reaching drop_thresh 254210284Sjmallett buffers */ 255210284Sjmallett red_marks.u64 = 0; 256210284Sjmallett red_marks.s.drop = drop_thresh; 257210284Sjmallett red_marks.s.pass = pass_thresh; 258210284Sjmallett cvmx_write_csr(CVMX_IPD_QOSX_RED_MARKS(queue), red_marks.u64); 259210284Sjmallett 260210284Sjmallett /* Use the actual queue 0 counter, not the average */ 261210284Sjmallett red_param.u64 = 0; 262210284Sjmallett red_param.s.prb_con = (255ul<<24) / (red_marks.s.pass - red_marks.s.drop); 263210284Sjmallett red_param.s.avg_con = 1; 264210284Sjmallett red_param.s.new_con = 255; 265210284Sjmallett red_param.s.use_pcnt = 1; 266210284Sjmallett cvmx_write_csr(CVMX_IPD_RED_QUEX_PARAM(queue), red_param.u64); 267210284Sjmallett return 0; 268210284Sjmallett} 269210284Sjmallett 270210284Sjmallett 271210284Sjmallett/** 272210284Sjmallett * Setup Random Early Drop to automatically begin dropping packets. 273210284Sjmallett * 274210284Sjmallett * @param pass_thresh 275210284Sjmallett * Packets will begin slowly dropping when there are less than 276210284Sjmallett * this many packet buffers free in FPA 0. 277210284Sjmallett * @param drop_thresh 278210284Sjmallett * All incomming packets will be dropped when there are less 279210284Sjmallett * than this many free packet buffers in FPA 0. 280210284Sjmallett * @return Zero on success. Negative on failure 281210284Sjmallett */ 282210284Sjmallettint cvmx_helper_setup_red(int pass_thresh, int drop_thresh) 283210284Sjmallett{ 284210284Sjmallett int queue; 285210284Sjmallett int interface; 286210284Sjmallett int port; 287210284Sjmallett 288232812Sjmallett /* 289232812Sjmallett * Disable backpressure based on queued buffers. It needs SW support 290232812Sjmallett */ 291232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PKND)) 292210284Sjmallett { 293232812Sjmallett int bpid; 294232812Sjmallett for (interface = 0; interface < CVMX_HELPER_MAX_GMX; interface++) 295232812Sjmallett { 296232812Sjmallett int num_ports; 297232812Sjmallett 298232812Sjmallett num_ports = cvmx_helper_ports_on_interface(interface); 299232812Sjmallett for (port = 0; port < num_ports; port++) { 300232812Sjmallett bpid = cvmx_helper_get_bpid(interface, port); 301232812Sjmallett if (bpid == CVMX_INVALID_BPID) 302232812Sjmallett cvmx_dprintf( 303232812Sjmallett "setup_red: cvmx_helper_get_bpid(%d, %d) = %d\n", 304232812Sjmallett interface, port, cvmx_helper_get_bpid(interface, port)); 305232812Sjmallett else 306232812Sjmallett cvmx_write_csr(CVMX_IPD_BPIDX_MBUF_TH(bpid), 0); 307232812Sjmallett } 308232812Sjmallett } 309210284Sjmallett } 310232812Sjmallett else 311232812Sjmallett { 312232812Sjmallett cvmx_ipd_portx_bp_page_cnt_t page_cnt; 313210284Sjmallett 314232812Sjmallett page_cnt.u64 = 0; 315232812Sjmallett page_cnt.s.bp_enb = 0; 316232812Sjmallett page_cnt.s.page_cnt = 100; 317232812Sjmallett for (interface = 0; interface < CVMX_HELPER_MAX_GMX; interface++) 318232812Sjmallett { 319232812Sjmallett for (port = cvmx_helper_get_first_ipd_port(interface); 320232812Sjmallett port < cvmx_helper_get_last_ipd_port(interface); port++) 321232812Sjmallett cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port), page_cnt.u64); 322232812Sjmallett } 323232812Sjmallett } 324232812Sjmallett 325232812Sjmallett for (queue = 0; queue < 8; queue++) 326210284Sjmallett cvmx_helper_setup_red_queue(queue, pass_thresh, drop_thresh); 327210284Sjmallett 328232812Sjmallett /* 329232812Sjmallett * Shutoff the dropping based on the per port page count. SW isn't 330232812Sjmallett * decrementing it right now 331232812Sjmallett */ 332232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PKND)) 333232812Sjmallett cvmx_write_csr(CVMX_IPD_ON_BP_DROP_PKTX(0), 0); 334232812Sjmallett else 335232812Sjmallett cvmx_write_csr(CVMX_IPD_BP_PRT_RED_END, 0); 336210284Sjmallett 337232812Sjmallett#define IPD_RED_AVG_DLY 1000 338232812Sjmallett#define IPD_RED_PRB_DLY 1000 339232812Sjmallett /* 340232812Sjmallett * Setting up avg_dly and prb_dly, enable bits 341232812Sjmallett */ 342232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PKND)) 343232812Sjmallett { 344232812Sjmallett cvmx_ipd_red_delay_t red_delay; 345232812Sjmallett cvmx_ipd_red_bpid_enablex_t red_bpid_enable; 346210284Sjmallett 347232812Sjmallett red_delay.u64 = 0; 348232812Sjmallett red_delay.s.avg_dly = IPD_RED_AVG_DLY; 349232812Sjmallett red_delay.s.prb_dly = IPD_RED_PRB_DLY; 350232812Sjmallett cvmx_write_csr(CVMX_IPD_RED_DELAY, red_delay.u64); 351232812Sjmallett 352232812Sjmallett /* 353232812Sjmallett * Only enable the gmx ports 354232812Sjmallett */ 355232812Sjmallett red_bpid_enable.u64 = 0; 356232812Sjmallett for (interface = 0; interface < CVMX_HELPER_MAX_GMX; interface++) 357232812Sjmallett { 358232812Sjmallett int num_ports = cvmx_helper_ports_on_interface(interface); 359232812Sjmallett for (port = 0; port < num_ports; port++) 360232812Sjmallett red_bpid_enable.u64 |= (((uint64_t) 1) << 361232812Sjmallett cvmx_helper_get_bpid(interface, port)); 362232812Sjmallett } 363232812Sjmallett cvmx_write_csr(CVMX_IPD_RED_BPID_ENABLEX(0), red_bpid_enable.u64); 364232812Sjmallett } 365232812Sjmallett else 366215990Sjmallett { 367232812Sjmallett cvmx_ipd_red_port_enable_t red_port_enable; 368232812Sjmallett 369232812Sjmallett red_port_enable.u64 = 0; 370232812Sjmallett red_port_enable.s.prt_enb = 0xfffffffffull; 371232812Sjmallett red_port_enable.s.avg_dly = IPD_RED_AVG_DLY; 372232812Sjmallett red_port_enable.s.prb_dly = IPD_RED_PRB_DLY; 373232812Sjmallett cvmx_write_csr(CVMX_IPD_RED_PORT_ENABLE, red_port_enable.u64); 374232812Sjmallett 375232812Sjmallett /* 376232812Sjmallett * Shutoff the dropping of packets based on RED for SRIO ports 377232812Sjmallett */ 378232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_SRIO)) 379232812Sjmallett { 380232812Sjmallett cvmx_ipd_red_port_enable2_t red_port_enable2; 381232812Sjmallett red_port_enable2.u64 = 0; 382232812Sjmallett red_port_enable2.s.prt_enb = 0xf0; 383232812Sjmallett cvmx_write_csr(CVMX_IPD_RED_PORT_ENABLE2, red_port_enable2.u64); 384232812Sjmallett } 385215990Sjmallett } 386215990Sjmallett 387210284Sjmallett return 0; 388210284Sjmallett} 389215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 390215990SjmallettEXPORT_SYMBOL(cvmx_helper_setup_red); 391215990Sjmallett#endif 392210284Sjmallett 393210284Sjmallett 394210284Sjmallett/** 395210284Sjmallett * @INTERNAL 396210284Sjmallett * Setup the common GMX settings that determine the number of 397210284Sjmallett * ports. These setting apply to almost all configurations of all 398210284Sjmallett * chips. 399210284Sjmallett * 400210284Sjmallett * @param interface Interface to configure 401210284Sjmallett * @param num_ports Number of ports on the interface 402210284Sjmallett * 403210284Sjmallett * @return Zero on success, negative on failure 404210284Sjmallett */ 405210284Sjmallettint __cvmx_helper_setup_gmx(int interface, int num_ports) 406210284Sjmallett{ 407210284Sjmallett cvmx_gmxx_tx_prts_t gmx_tx_prts; 408210284Sjmallett cvmx_gmxx_rx_prts_t gmx_rx_prts; 409210284Sjmallett cvmx_pko_reg_gmx_port_mode_t pko_mode; 410210284Sjmallett cvmx_gmxx_txx_thresh_t gmx_tx_thresh; 411210284Sjmallett int index; 412210284Sjmallett 413232812Sjmallett /* 414232812Sjmallett * Tell GMX the number of TX ports on this interface 415232812Sjmallett */ 416210284Sjmallett gmx_tx_prts.u64 = cvmx_read_csr(CVMX_GMXX_TX_PRTS(interface)); 417210284Sjmallett gmx_tx_prts.s.prts = num_ports; 418210284Sjmallett cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), gmx_tx_prts.u64); 419210284Sjmallett 420232812Sjmallett /* 421232812Sjmallett * Tell GMX the number of RX ports on this interface. This only applies 422232812Sjmallett * to GMII and XAUI ports 423232812Sjmallett */ 424210284Sjmallett if (cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_RGMII 425210284Sjmallett || cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_SGMII 426210284Sjmallett || cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_GMII 427210284Sjmallett || cvmx_helper_interface_get_mode(interface) == CVMX_HELPER_INTERFACE_MODE_XAUI) 428210284Sjmallett { 429210284Sjmallett if (num_ports > 4) 430210284Sjmallett { 431210284Sjmallett cvmx_dprintf("__cvmx_helper_setup_gmx: Illegal num_ports\n"); 432210284Sjmallett return(-1); 433210284Sjmallett } 434210284Sjmallett 435210284Sjmallett gmx_rx_prts.u64 = cvmx_read_csr(CVMX_GMXX_RX_PRTS(interface)); 436210284Sjmallett gmx_rx_prts.s.prts = num_ports; 437210284Sjmallett cvmx_write_csr(CVMX_GMXX_RX_PRTS(interface), gmx_rx_prts.u64); 438210284Sjmallett } 439210284Sjmallett 440232812Sjmallett /* 441232812Sjmallett * Skip setting CVMX_PKO_REG_GMX_PORT_MODE on 30XX, 31XX, 50XX, 442232812Sjmallett * and 68XX. 443232812Sjmallett */ 444232812Sjmallett if (!OCTEON_IS_MODEL(OCTEON_CN30XX) && !OCTEON_IS_MODEL(OCTEON_CN31XX) && 445232812Sjmallett !OCTEON_IS_MODEL(OCTEON_CN50XX) && !OCTEON_IS_MODEL(OCTEON_CN68XX)) 446210284Sjmallett { 447210284Sjmallett /* Tell PKO the number of ports on this interface */ 448210284Sjmallett pko_mode.u64 = cvmx_read_csr(CVMX_PKO_REG_GMX_PORT_MODE); 449210284Sjmallett if (interface == 0) 450210284Sjmallett { 451210284Sjmallett if (num_ports == 1) 452210284Sjmallett pko_mode.s.mode0 = 4; 453210284Sjmallett else if (num_ports == 2) 454210284Sjmallett pko_mode.s.mode0 = 3; 455210284Sjmallett else if (num_ports <= 4) 456210284Sjmallett pko_mode.s.mode0 = 2; 457210284Sjmallett else if (num_ports <= 8) 458210284Sjmallett pko_mode.s.mode0 = 1; 459210284Sjmallett else 460210284Sjmallett pko_mode.s.mode0 = 0; 461210284Sjmallett } 462210284Sjmallett else 463210284Sjmallett { 464210284Sjmallett if (num_ports == 1) 465210284Sjmallett pko_mode.s.mode1 = 4; 466210284Sjmallett else if (num_ports == 2) 467210284Sjmallett pko_mode.s.mode1 = 3; 468210284Sjmallett else if (num_ports <= 4) 469210284Sjmallett pko_mode.s.mode1 = 2; 470210284Sjmallett else if (num_ports <= 8) 471210284Sjmallett pko_mode.s.mode1 = 1; 472210284Sjmallett else 473210284Sjmallett pko_mode.s.mode1 = 0; 474210284Sjmallett } 475210284Sjmallett cvmx_write_csr(CVMX_PKO_REG_GMX_PORT_MODE, pko_mode.u64); 476210284Sjmallett } 477210284Sjmallett 478232812Sjmallett /* 479232812Sjmallett * Set GMX to buffer as much data as possible before starting 480232812Sjmallett * transmit. This reduces the chances that we have a TX under run 481232812Sjmallett * due to memory contention. Any packet that fits entirely in the 482232812Sjmallett * GMX FIFO can never have an under run regardless of memory load. 483232812Sjmallett */ 484210284Sjmallett gmx_tx_thresh.u64 = cvmx_read_csr(CVMX_GMXX_TXX_THRESH(0, interface)); 485232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN31XX) || 486232812Sjmallett OCTEON_IS_MODEL(OCTEON_CN50XX)) 487210284Sjmallett /* These chips have a fixed max threshold of 0x40 */ 488210284Sjmallett gmx_tx_thresh.s.cnt = 0x40; 489210284Sjmallett else 490210284Sjmallett { 491232812Sjmallett /* ccn - common cnt numberator */ 492232812Sjmallett int ccn = 0x100; 493232812Sjmallett 494210284Sjmallett /* Choose the max value for the number of ports */ 495210284Sjmallett if (num_ports <= 1) 496232812Sjmallett gmx_tx_thresh.s.cnt = ccn / 1; 497210284Sjmallett else if (num_ports == 2) 498232812Sjmallett gmx_tx_thresh.s.cnt = ccn / 2; 499210284Sjmallett else 500232812Sjmallett gmx_tx_thresh.s.cnt = ccn / 4; 501210284Sjmallett } 502232812Sjmallett 503232812Sjmallett /* 504232812Sjmallett * SPI and XAUI can have lots of ports but the GMX hardware only ever has 505232812Sjmallett * a max of 4 506232812Sjmallett */ 507210284Sjmallett if (num_ports > 4) 508210284Sjmallett num_ports = 4; 509232812Sjmallett for (index = 0; index < num_ports; index++) 510232812Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_THRESH(index, interface), 511232812Sjmallett gmx_tx_thresh.u64); 512210284Sjmallett 513232812Sjmallett /* 514232812Sjmallett * For o68, we need to setup the pipes 515232812Sjmallett */ 516232812Sjmallett if (OCTEON_IS_MODEL(OCTEON_CN68XX) && interface < CVMX_HELPER_MAX_GMX) 517232812Sjmallett { 518232812Sjmallett cvmx_gmxx_txx_pipe_t config; 519232812Sjmallett 520232812Sjmallett for (index = 0; index < num_ports; index++) 521232812Sjmallett { 522232812Sjmallett config.u64 = 0; 523232812Sjmallett 524232812Sjmallett if (__cvmx_helper_cfg_pko_port_base(interface, index) >= 0) 525232812Sjmallett { 526232812Sjmallett config.u64 = cvmx_read_csr( 527232812Sjmallett CVMX_GMXX_TXX_PIPE(index, interface)); 528232812Sjmallett config.s.nump = __cvmx_helper_cfg_pko_port_num(interface, index); 529232812Sjmallett config.s.base = __cvmx_helper_cfg_pko_port_base(interface, index); 530232812Sjmallett cvmx_write_csr(CVMX_GMXX_TXX_PIPE(index, interface), 531232812Sjmallett config.u64); 532232812Sjmallett } 533232812Sjmallett } 534232812Sjmallett } 535232812Sjmallett 536210284Sjmallett return 0; 537210284Sjmallett} 538210284Sjmallett 539232812Sjmallettint cvmx_helper_get_pko_port(int interface, int port) 540232812Sjmallett{ 541232812Sjmallett return cvmx_pko_get_base_pko_port(interface, port); 542232812Sjmallett} 543232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 544232812SjmallettEXPORT_SYMBOL(cvmx_helper_get_pko_port); 545232812Sjmallett#endif 546210284Sjmallett 547210284Sjmallettint cvmx_helper_get_ipd_port(int interface, int port) 548210284Sjmallett{ 549232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PKND)) 550232812Sjmallett { 551232812Sjmallett if (interface >= 0 && interface <= 4) 552232812Sjmallett { 553232812Sjmallett cvmx_helper_interface_mode_t mode = cvmx_helper_interface_get_mode(interface); 554232812Sjmallett if (mode == CVMX_HELPER_INTERFACE_MODE_XAUI || mode == CVMX_HELPER_INTERFACE_MODE_RXAUI) 555232812Sjmallett return 0x840 + (interface * 0x100); 556232812Sjmallett else 557232812Sjmallett return 0x800 + (interface * 0x100) + (port * 16); 558232812Sjmallett } 559232812Sjmallett else if (interface == 5 || interface == 6) 560232812Sjmallett return 0x400 + (interface - 5) * 0x100 + port; 561232812Sjmallett else if (interface == 7) 562232812Sjmallett return 0x100 + port; 563232812Sjmallett else if (interface == 8) 564232812Sjmallett return port; 565232812Sjmallett else 566232812Sjmallett return -1; 567232812Sjmallett } 568210284Sjmallett switch (interface) 569210284Sjmallett { 570210284Sjmallett case 0: return port; 571210284Sjmallett case 1: return port + 16; 572210284Sjmallett case 2: return port + 32; 573210284Sjmallett case 3: return port + 36; 574215990Sjmallett case 4: return port + 40; 575215990Sjmallett case 5: return port + 42; 576232812Sjmallett case 6: return port + 44; 577210284Sjmallett } 578210284Sjmallett return -1; 579210284Sjmallett} 580215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 581215990SjmallettEXPORT_SYMBOL(cvmx_helper_get_ipd_port); 582215990Sjmallett#endif 583210284Sjmallett 584232812Sjmallettint __cvmx_helper_get_num_ipd_ports(int interface) 585232812Sjmallett{ 586232812Sjmallett struct cvmx_iface *piface; 587210284Sjmallett 588232812Sjmallett if (interface >= cvmx_helper_get_number_of_interfaces()) 589232812Sjmallett return -1; 590210284Sjmallett 591232812Sjmallett piface = &cvmx_interfaces[interface]; 592232812Sjmallett return piface->cvif_ipd_nports; 593232812Sjmallett} 594232812Sjmallett 595232812Sjmallettenum cvmx_pko_padding __cvmx_helper_get_pko_padding(int interface) 596232812Sjmallett{ 597232812Sjmallett struct cvmx_iface *piface; 598232812Sjmallett 599232812Sjmallett if (interface >= cvmx_helper_get_number_of_interfaces()) 600232812Sjmallett return CVMX_PKO_PADDING_NONE; 601232812Sjmallett 602232812Sjmallett piface = &cvmx_interfaces[interface]; 603232812Sjmallett return piface->cvif_padding; 604232812Sjmallett} 605232812Sjmallett 606232812Sjmallettint __cvmx_helper_init_interface(int interface, int num_ipd_ports, int has_fcs, enum cvmx_pko_padding pad) 607232812Sjmallett{ 608232812Sjmallett struct cvmx_iface *piface; 609232812Sjmallett int sz; 610232812Sjmallett 611232812Sjmallett if (interface >= cvmx_helper_get_number_of_interfaces()) 612232812Sjmallett return -1; 613232812Sjmallett 614232812Sjmallett piface = &cvmx_interfaces[interface]; 615232812Sjmallett piface->cvif_ipd_nports = num_ipd_ports; 616232812Sjmallett piface->cvif_padding = pad; 617232812Sjmallett 618232812Sjmallett piface->cvif_has_fcs = has_fcs; 619232812Sjmallett 620232812Sjmallett /* 621232812Sjmallett * allocate the per-ipd_port link_info structure 622232812Sjmallett */ 623232812Sjmallett sz = piface->cvif_ipd_nports * sizeof(cvmx_helper_link_info_t); 624232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 625232812Sjmallett if (sz == 0) 626232812Sjmallett sz = sizeof(cvmx_helper_link_info_t); 627232812Sjmallett piface->cvif_ipd_port_link_info = (cvmx_helper_link_info_t *)kmalloc(sz, GFP_KERNEL); 628232812Sjmallett if (ZERO_OR_NULL_PTR(piface->cvif_ipd_port_link_info)) 629232812Sjmallett panic("Cannot allocate memory in __cvmx_helper_init_interface."); 630232812Sjmallett#else 631232812Sjmallett piface->cvif_ipd_port_link_info = (cvmx_helper_link_info_t *)cvmx_bootmem_alloc(sz, sizeof(cvmx_helper_link_info_t)); 632232812Sjmallett#endif 633232812Sjmallett if (!piface->cvif_ipd_port_link_info) 634232812Sjmallett return -1; 635232812Sjmallett 636232812Sjmallett /* Initialize 'em */ { 637232812Sjmallett int i; 638232812Sjmallett cvmx_helper_link_info_t *p; 639232812Sjmallett p = piface->cvif_ipd_port_link_info; 640232812Sjmallett 641232812Sjmallett for (i = 0; i < piface->cvif_ipd_nports; i++) 642232812Sjmallett { 643232812Sjmallett (*p).u64 = 0; 644232812Sjmallett p++; 645232812Sjmallett } 646232812Sjmallett } 647232812Sjmallett 648232812Sjmallett return 0; 649232812Sjmallett} 650232812Sjmallett 651232812Sjmallett/* 652232812Sjmallett * Shut down the interfaces; free the resources. 653232812Sjmallett * @INTERNAL 654232812Sjmallett */ 655232812Sjmallettvoid __cvmx_helper_shutdown_interfaces(void) 656232812Sjmallett{ 657232812Sjmallett int i; 658232812Sjmallett int nifaces; /* number of interfaces */ 659232812Sjmallett struct cvmx_iface *piface; 660232812Sjmallett 661232812Sjmallett nifaces = cvmx_helper_get_number_of_interfaces(); 662232812Sjmallett for (i = 0; i < nifaces; i++) 663232812Sjmallett { 664232812Sjmallett piface = cvmx_interfaces + i; 665232812Sjmallett if (piface->cvif_ipd_port_link_info) 666232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 667232812Sjmallett kfree(piface->cvif_ipd_port_link_info); 668232812Sjmallett#else 669232812Sjmallett /* 670232812Sjmallett * For SE apps, bootmem was meant to be allocated and never 671232812Sjmallett * freed. 672232812Sjmallett */ 673232812Sjmallett#endif 674232812Sjmallett piface->cvif_ipd_port_link_info = 0; 675232812Sjmallett } 676232812Sjmallett} 677232812Sjmallett 678232812Sjmallettint __cvmx_helper_set_link_info(int interface, int port, 679232812Sjmallett cvmx_helper_link_info_t link_info) 680232812Sjmallett{ 681232812Sjmallett struct cvmx_iface *piface; 682232812Sjmallett 683232812Sjmallett if (interface >= cvmx_helper_get_number_of_interfaces()) 684232812Sjmallett return -1; 685232812Sjmallett 686232812Sjmallett piface = &cvmx_interfaces[interface]; 687232812Sjmallett 688232812Sjmallett if (piface->cvif_ipd_port_link_info) 689232812Sjmallett { 690232812Sjmallett piface->cvif_ipd_port_link_info[port] = link_info; 691232812Sjmallett return 0; 692232812Sjmallett } 693232812Sjmallett 694232812Sjmallett return -1; 695232812Sjmallett} 696232812Sjmallett 697232812Sjmallettcvmx_helper_link_info_t __cvmx_helper_get_link_info(int interface, int port) 698232812Sjmallett{ 699232812Sjmallett struct cvmx_iface *piface; 700232812Sjmallett cvmx_helper_link_info_t err; 701232812Sjmallett 702232812Sjmallett err.u64 = 0; 703232812Sjmallett 704232812Sjmallett if (interface >= cvmx_helper_get_number_of_interfaces()) 705232812Sjmallett return err; 706232812Sjmallett piface = &cvmx_interfaces[interface]; 707232812Sjmallett 708232812Sjmallett if (piface->cvif_ipd_port_link_info) 709232812Sjmallett return piface->cvif_ipd_port_link_info[port]; 710232812Sjmallett 711232812Sjmallett return err; 712232812Sjmallett} 713232812Sjmallett 714232812Sjmallettint __cvmx_helper_get_has_fcs(int interface) 715232812Sjmallett{ 716232812Sjmallett return cvmx_interfaces[interface].cvif_has_fcs; 717232812Sjmallett} 718232812Sjmallett 719232812Sjmallettint cvmx_helper_get_pknd(int interface, int port) 720232812Sjmallett{ 721232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PKND)) 722232812Sjmallett return __cvmx_helper_cfg_pknd(interface, port); 723232812Sjmallett 724232812Sjmallett return CVMX_INVALID_PKND; 725232812Sjmallett} 726232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 727232812SjmallettEXPORT_SYMBOL(cvmx_helper_get_pknd); 728232812Sjmallett#endif 729232812Sjmallett 730232812Sjmallettint cvmx_helper_get_bpid(int interface, int port) 731232812Sjmallett{ 732232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PKND)) 733232812Sjmallett return __cvmx_helper_cfg_bpid(interface, port); 734232812Sjmallett 735232812Sjmallett return CVMX_INVALID_BPID; 736232812Sjmallett} 737232812Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 738232812SjmallettEXPORT_SYMBOL(cvmx_helper_get_bpid); 739232812Sjmallett#endif 740232812Sjmallett 741210284Sjmallett/** 742232812Sjmallett * Display interface statistics. 743232812Sjmallett * 744232812Sjmallett * @param port IPD/PKO port number 745232812Sjmallett * 746232812Sjmallett * @return none 747232812Sjmallett */ 748232812Sjmallettvoid cvmx_helper_show_stats(int port) 749232812Sjmallett{ 750232812Sjmallett cvmx_pip_port_status_t status; 751232812Sjmallett cvmx_pko_port_status_t pko_status; 752232812Sjmallett 753232812Sjmallett /* ILK stats */ 754232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_ILK)) 755232812Sjmallett __cvmx_helper_ilk_show_stats(); 756232812Sjmallett 757232812Sjmallett /* PIP stats */ 758232812Sjmallett cvmx_pip_get_port_status (port, 0, &status); 759232812Sjmallett cvmx_dprintf ("port %d: the number of packets - ipd: %d\n", port, (int)status.packets); 760232812Sjmallett 761232812Sjmallett /* PKO stats */ 762232812Sjmallett cvmx_pko_get_port_status (port, 0, &pko_status); 763232812Sjmallett cvmx_dprintf ("port %d: the number of packets - pko: %d\n", port, (int)pko_status.packets); 764232812Sjmallett 765232812Sjmallett /* TODO: other stats */ 766232812Sjmallett} 767232812Sjmallett#endif /* CVMX_ENABLE_HELPER_FUNCTIONS */ 768232812Sjmallett 769232812Sjmallett/** 770210284Sjmallett * Returns the interface number for an IPD/PKO port number. 771210284Sjmallett * 772210284Sjmallett * @param ipd_port IPD/PKO port number 773210284Sjmallett * 774210284Sjmallett * @return Interface number 775210284Sjmallett */ 776210284Sjmallettint cvmx_helper_get_interface_num(int ipd_port) 777210284Sjmallett{ 778232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PKND)) 779232812Sjmallett { 780232812Sjmallett if (ipd_port >= 0x800 && ipd_port < 0x900) 781232812Sjmallett return 0; 782232812Sjmallett else if (ipd_port >= 0x900 && ipd_port < 0xa00) 783232812Sjmallett return 1; 784232812Sjmallett else if (ipd_port >= 0xa00 && ipd_port < 0xb00) 785232812Sjmallett return 2; 786232812Sjmallett else if (ipd_port >= 0xb00 && ipd_port < 0xc00) 787232812Sjmallett return 3; 788232812Sjmallett else if (ipd_port >= 0xc00 && ipd_port < 0xd00) 789232812Sjmallett return 4; 790232812Sjmallett else if (ipd_port >= 0x400 && ipd_port < 0x500) 791232812Sjmallett return 5; 792232812Sjmallett else if (ipd_port >= 0x500 && ipd_port < 0x600) 793232812Sjmallett return 6; 794232812Sjmallett else if (ipd_port >= 0x100 && ipd_port < 0x120) 795232812Sjmallett return 7; 796232812Sjmallett else if (ipd_port < 8) 797232812Sjmallett return 8; 798232812Sjmallett } else { 799232812Sjmallett if (ipd_port < 16) 800232812Sjmallett return 0; 801232812Sjmallett else if (ipd_port < 32) 802232812Sjmallett return 1; 803232812Sjmallett else if (ipd_port < 36) 804232812Sjmallett return 2; 805232812Sjmallett else if (ipd_port < 40) 806232812Sjmallett return 3; 807232812Sjmallett else if (ipd_port < 42) 808232812Sjmallett return 4; 809232812Sjmallett else if (ipd_port < 44) 810232812Sjmallett return 5; 811232812Sjmallett else if (ipd_port < 46) 812232812Sjmallett return 6; 813232812Sjmallett } 814232812Sjmallett cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD port number %d\n", ipd_port); 815210284Sjmallett return -1; 816210284Sjmallett} 817215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 818215990SjmallettEXPORT_SYMBOL(cvmx_helper_get_interface_num); 819215990Sjmallett#endif 820210284Sjmallett 821210284Sjmallett 822210284Sjmallett/** 823210284Sjmallett * Returns the interface index number for an IPD/PKO port 824210284Sjmallett * number. 825210284Sjmallett * 826210284Sjmallett * @param ipd_port IPD/PKO port number 827210284Sjmallett * 828210284Sjmallett * @return Interface index number 829210284Sjmallett */ 830210284Sjmallettint cvmx_helper_get_interface_index_num(int ipd_port) 831210284Sjmallett{ 832232812Sjmallett if (octeon_has_feature(OCTEON_FEATURE_PKND)) 833232812Sjmallett { 834232812Sjmallett if (ipd_port >= 0x800 && ipd_port < 0xd00) 835232812Sjmallett { 836232812Sjmallett int port = ((ipd_port & 0xff) >> 6); 837232812Sjmallett return ((port) ? (port - 1) : ((ipd_port & 0xff) >> 4)); 838232812Sjmallett } 839232812Sjmallett else if (ipd_port >= 0x400 && ipd_port < 0x600) 840232812Sjmallett return (ipd_port & 0xff); 841232812Sjmallett else if (ipd_port >= 0x100 && ipd_port < 0x120) 842232812Sjmallett return (ipd_port & 0xff); 843232812Sjmallett else if (ipd_port < 8) 844232812Sjmallett return ipd_port; 845232812Sjmallett else 846232812Sjmallett cvmx_dprintf("cvmx_helper_get_interface_index_num: Illegal IPD port number %d\n", ipd_port); 847232812Sjmallett return -1; 848232812Sjmallett } 849210284Sjmallett if (ipd_port < 32) 850210284Sjmallett return ipd_port & 15; 851210284Sjmallett else if (ipd_port < 40) 852210284Sjmallett return ipd_port & 3; 853215990Sjmallett else if (ipd_port < 44) 854232812Sjmallett return ipd_port & 1; 855232812Sjmallett else if (ipd_port < 46) 856232812Sjmallett return ipd_port & 1; 857210284Sjmallett else 858210284Sjmallett cvmx_dprintf("cvmx_helper_get_interface_index_num: Illegal IPD port number\n"); 859210284Sjmallett 860210284Sjmallett return -1; 861210284Sjmallett} 862215990Sjmallett#ifdef CVMX_BUILD_FOR_LINUX_KERNEL 863215990SjmallettEXPORT_SYMBOL(cvmx_helper_get_interface_index_num); 864215990Sjmallett#endif 865