cvmx-helper-errata.c revision 210286
1/***********************license start*************** 2 * Copyright (c) 2003-2008 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 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" 24 * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS 25 * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH 26 * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY 27 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT 28 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES 29 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR 30 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET 31 * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT 32 * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU. 33 * 34 * 35 * For any questions regarding licensing please contact marketing@caviumnetworks.com 36 * 37 ***********************license end**************************************/ 38 39 40 41 42 43 44/** 45 * @file 46 * 47 * Fixes and workaround for Octeon chip errata. This file 48 * contains functions called by cvmx-helper to workaround known 49 * chip errata. For the most part, code doesn't need to call 50 * these functions directly. 51 * 52 * <hr>$Revision: 42150 $<hr> 53 */ 54#include "executive-config.h" 55#include "cvmx-config.h" 56 57#include "cvmx.h" 58#include "cvmx-fpa.h" 59#include "cvmx-pip.h" 60#include "cvmx-pko.h" 61#include "cvmx-ipd.h" 62#include "cvmx-asx.h" 63#include "cvmx-gmx.h" 64#include "cvmx-spi.h" 65#include "cvmx-pow.h" 66#include "cvmx-sysinfo.h" 67#include "cvmx-helper.h" 68#include "cvmx-helper-util.h" 69 70#ifdef CVMX_ENABLE_PKO_FUNCTIONS 71 72 73/** 74 * @INTERNAL 75 * Function to adjust internal IPD pointer alignments 76 * 77 * @return 0 on success 78 * !0 on failure 79 */ 80int __cvmx_helper_errata_fix_ipd_ptr_alignment(void) 81{ 82#define FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_FIRST_MBUFF_SKIP) 83#define FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_NOT_FIRST_MBUFF_SKIP) 84#define FIX_IPD_OUTPORT 0 85#define INTERFACE(port) (port >> 4) /* Ports 0-15 are interface 0, 16-31 are interface 1 */ 86#define INDEX(port) (port & 0xf) 87 uint64_t *p64; 88 cvmx_pko_command_word0_t pko_command; 89 cvmx_buf_ptr_t g_buffer, pkt_buffer; 90 cvmx_wqe_t *work; 91 int size, num_segs = 0, wqe_pcnt, pkt_pcnt; 92 cvmx_gmxx_prtx_cfg_t gmx_cfg; 93 int retry_cnt; 94 int retry_loop_cnt; 95 int mtu; 96 int i; 97 cvmx_helper_link_info_t link_info; 98 99 /* Save values for restore at end */ 100 uint64_t prtx_cfg = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); 101 uint64_t tx_ptr_en = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT))); 102 uint64_t rx_ptr_en = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT))); 103 uint64_t rxx_jabber = cvmx_read_csr(CVMX_GMXX_RXX_JABBER(INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); 104 uint64_t frame_max = cvmx_read_csr(CVMX_GMXX_RXX_FRM_MAX(INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); 105 106 /* Configure port to gig FDX as required for loopback mode */ 107 cvmx_helper_rgmii_internal_loopback(FIX_IPD_OUTPORT); 108 109 /* Disable reception on all ports so if traffic is present it will not interfere. */ 110 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), 0); 111 112 cvmx_wait(100000000ull); 113 114 for (retry_loop_cnt = 0;retry_loop_cnt < 10;retry_loop_cnt++) 115 { 116 retry_cnt = 100000; 117 wqe_pcnt = cvmx_read_csr(CVMX_IPD_PTR_COUNT); 118 pkt_pcnt = (wqe_pcnt >> 7) & 0x7f; 119 wqe_pcnt &= 0x7f; 120 121 num_segs = (2 + pkt_pcnt - wqe_pcnt) & 3; 122 123 if (num_segs == 0) 124 goto fix_ipd_exit; 125 126 num_segs += 1; 127 128 size = FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES + ((num_segs-1)*FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES) - 129 (FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES / 2); 130 131 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), 1 << INDEX(FIX_IPD_OUTPORT)); 132 CVMX_SYNC; 133 134 g_buffer.u64 = 0; 135 g_buffer.s.addr = cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_WQE_POOL)); 136 if (g_buffer.s.addr == 0) { 137 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT buffer allocation failure.\n"); 138 goto fix_ipd_exit; 139 } 140 141 g_buffer.s.pool = CVMX_FPA_WQE_POOL; 142 g_buffer.s.size = num_segs; 143 144 pkt_buffer.u64 = 0; 145 pkt_buffer.s.addr = cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL)); 146 if (pkt_buffer.s.addr == 0) { 147 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT buffer allocation failure.\n"); 148 goto fix_ipd_exit; 149 } 150 pkt_buffer.s.i = 1; 151 pkt_buffer.s.pool = CVMX_FPA_PACKET_POOL; 152 pkt_buffer.s.size = FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES; 153 154 p64 = (uint64_t*) cvmx_phys_to_ptr(pkt_buffer.s.addr); 155 p64[0] = 0xffffffffffff0000ull; 156 p64[1] = 0x08004510ull; 157 p64[2] = ((uint64_t)(size-14) << 48) | 0x5ae740004000ull; 158 p64[3] = 0x3a5fc0a81073c0a8ull; 159 160 for (i=0;i<num_segs;i++) 161 { 162 if (i>0) 163 pkt_buffer.s.size = FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES; 164 165 if (i==(num_segs-1)) 166 pkt_buffer.s.i = 0; 167 168 *(uint64_t*)cvmx_phys_to_ptr(g_buffer.s.addr + 8*i) = pkt_buffer.u64; 169 } 170 171 /* Build the PKO command */ 172 pko_command.u64 = 0; 173 pko_command.s.segs = num_segs; 174 pko_command.s.total_bytes = size; 175 pko_command.s.dontfree = 0; 176 pko_command.s.gather = 1; 177 178 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); 179 gmx_cfg.s.en = 1; 180 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), gmx_cfg.u64); 181 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), 1 << INDEX(FIX_IPD_OUTPORT)); 182 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), 1 << INDEX(FIX_IPD_OUTPORT)); 183 184 mtu = cvmx_read_csr(CVMX_GMXX_RXX_JABBER(INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT))); 185 cvmx_write_csr(CVMX_GMXX_RXX_JABBER(INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), 65392-14-4); 186 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), 65392-14-4); 187 188 cvmx_pko_send_packet_prepare(FIX_IPD_OUTPORT, cvmx_pko_get_base_queue(FIX_IPD_OUTPORT), CVMX_PKO_LOCK_CMD_QUEUE); 189 cvmx_pko_send_packet_finish(FIX_IPD_OUTPORT, cvmx_pko_get_base_queue(FIX_IPD_OUTPORT), pko_command, g_buffer, CVMX_PKO_LOCK_CMD_QUEUE); 190 191 CVMX_SYNC; 192 193 do { 194 work = cvmx_pow_work_request_sync(CVMX_POW_WAIT); 195 retry_cnt--; 196 } while ((work == NULL) && (retry_cnt > 0)); 197 198 if (!retry_cnt) 199 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT get_work() timeout occured.\n"); 200 201 202 /* Free packet */ 203 if (work) 204 cvmx_helper_free_packet_data(work); 205 } 206 207fix_ipd_exit: 208 209 /* Return CSR configs to saved values */ 210 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), prtx_cfg); 211 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), tx_ptr_en); 212 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), rx_ptr_en); 213 cvmx_write_csr(CVMX_GMXX_RXX_JABBER(INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), rxx_jabber); 214 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)), frame_max); 215 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), 0); 216 link_info.u64 = 0; /* Set link to down so autonegotiation will set it up again */ 217 cvmx_helper_link_set(FIX_IPD_OUTPORT, link_info); 218 219 /* Bring the link back up as autonegotiation is not done in user applications. */ 220 cvmx_helper_link_autoconf(FIX_IPD_OUTPORT); 221 222 CVMX_SYNC; 223 if (num_segs) 224 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT failed.\n"); 225 226 return(!!num_segs); 227 228} 229 230 231/** 232 * @INTERNAL 233 * Workaround ASX setup errata with CN38XX pass1 234 * 235 * @param interface Interface to setup 236 * @param port Port to setup (0..3) 237 * @param cpu_clock_hz 238 * Chip frequency in Hertz 239 * 240 * @return Zero on success, negative on failure 241 */ 242int __cvmx_helper_errata_asx_pass1(int interface, int port, int cpu_clock_hz) 243{ 244 /* Set hi water mark as per errata GMX-4 */ 245 if (cpu_clock_hz >= 325000000 && cpu_clock_hz < 375000000) 246 cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 12); 247 else if (cpu_clock_hz >= 375000000 && cpu_clock_hz < 437000000) 248 cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 11); 249 else if (cpu_clock_hz >= 437000000 && cpu_clock_hz < 550000000) 250 cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 10); 251 else if (cpu_clock_hz >= 550000000 && cpu_clock_hz < 687000000) 252 cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 9); 253 else 254 cvmx_dprintf("Illegal clock frequency (%d). CVMX_ASXX_TX_HI_WATERX not set\n", cpu_clock_hz); 255 return 0; 256} 257 258 259/** 260 * This function needs to be called on all Octeon chips with 261 * errata PKI-100. 262 * 263 * The Size field is 8 too large in WQE and next pointers 264 * 265 * The Size field generated by IPD is 8 larger than it should 266 * be. The Size field is <55:40> of both: 267 * - WORD3 in the work queue entry, and 268 * - the next buffer pointer (which precedes the packet data 269 * in each buffer). 270 * 271 * @param work Work queue entry to fix 272 * @return Zero on success. Negative on failure 273 */ 274int cvmx_helper_fix_ipd_packet_chain(cvmx_wqe_t *work) 275{ 276 uint64_t number_buffers = work->word2.s.bufs; 277 278 /* We only need to do this if the work has buffers */ 279 if (number_buffers) 280 { 281 cvmx_buf_ptr_t buffer_ptr = work->packet_ptr; 282 /* Check for errata PKI-100 */ 283 if ( (buffer_ptr.s.pool == 0) && (((uint64_t)buffer_ptr.s.size + 284 ((uint64_t)buffer_ptr.s.back << 7) + ((uint64_t)buffer_ptr.s.addr & 0x7F)) 285 != (CVMX_FPA_PACKET_POOL_SIZE+8))) { 286 /* fix is not needed */ 287 return 0; 288 } 289 /* Decrement the work packet pointer */ 290 buffer_ptr.s.size -= 8; 291 work->packet_ptr = buffer_ptr; 292 293 /* Now loop through decrementing the size for each additional buffer */ 294 while (--number_buffers) 295 { 296 /* Chain pointers are 8 bytes before the data */ 297 cvmx_buf_ptr_t *ptr = (cvmx_buf_ptr_t*)cvmx_phys_to_ptr(buffer_ptr.s.addr - 8); 298 buffer_ptr = *ptr; 299 buffer_ptr.s.size -= 8; 300 *ptr = buffer_ptr; 301 } 302 } 303 /* Make sure that these write go out before other operations such as FPA frees */ 304 CVMX_SYNCWS; 305 return 0; 306} 307 308#endif /* CVMX_ENABLE_PKO_FUNCTIONS */ 309 310 311/** 312 * Due to errata G-720, the 2nd order CDR circuit on CN52XX pass 313 * 1 doesn't work properly. The following code disables 2nd order 314 * CDR for the specified QLM. 315 * 316 * @param qlm QLM to disable 2nd order CDR for. 317 */ 318void __cvmx_helper_errata_qlm_disable_2nd_order_cdr(int qlm) 319{ 320 int lane; 321 cvmx_helper_qlm_jtag_init(); 322 /* We need to load all four lanes of the QLM, a total of 1072 bits */ 323 for (lane=0; lane<4; lane++) 324 { 325 /* Each lane has 268 bits. We need to set cfg_cdr_incx<67:64>=3 and 326 cfg_cdr_secord<77>=1. All other bits are zero. Bits go in LSB 327 first, so start off with the zeros for bits <63:0> */ 328 cvmx_helper_qlm_jtag_shift_zeros(qlm, 63 - 0 + 1); 329 /* cfg_cdr_incx<67:64>=3 */ 330 cvmx_helper_qlm_jtag_shift(qlm, 67 - 64 + 1, 3); 331 /* Zeros for bits <76:68> */ 332 cvmx_helper_qlm_jtag_shift_zeros(qlm, 76 - 68 + 1); 333 /* cfg_cdr_secord<77>=1 */ 334 cvmx_helper_qlm_jtag_shift(qlm, 77 - 77 + 1, 1); 335 /* Zeros for bits <267:78> */ 336 cvmx_helper_qlm_jtag_shift_zeros(qlm, 267 - 78 + 1); 337 } 338 cvmx_helper_qlm_jtag_update(qlm); 339} 340 341