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