1 /***********************license start***************
2 * Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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
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.
35 * For any questions regarding licensing please contact marketing@caviumnetworks.com
37 ***********************license end**************************************/
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.
52 * <hr>$Revision: 42150 $<hr>
63 #include "cvmx-sysinfo.h"
64 #include "cvmx-helper.h"
65 #include "cvmx-helper-util.h"
67 #ifdef CVMX_ENABLE_PKO_FUNCTIONS
72 * Function to adjust internal IPD pointer alignments
74 * @return 0 on success
77 int __cvmx_helper_errata_fix_ipd_ptr_alignment(void)
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)
85 cvmx_pko_command_word0_t pko_command;
86 cvmx_buf_ptr_t g_buffer, pkt_buffer;
88 int size, num_segs = 0, wqe_pcnt, pkt_pcnt;
89 cvmx_gmxx_prtx_cfg_t gmx_cfg;
94 cvmx_helper_link_info_t link_info;
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)));
103 /* Configure port to gig FDX as required for loopback mode */
104 cvmx_helper_rgmii_internal_loopback(FIX_IPD_OUTPORT);
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);
109 cvmx_wait(100000000ull);
111 for (retry_loop_cnt = 0;retry_loop_cnt < 10;retry_loop_cnt++)
114 wqe_pcnt = cvmx_read_csr(CVMX_IPD_PTR_COUNT);
115 pkt_pcnt = (wqe_pcnt >> 7) & 0x7f;
118 num_segs = (2 + pkt_pcnt - wqe_pcnt) & 3;
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);
128 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), 1 << INDEX(FIX_IPD_OUTPORT));
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");
138 g_buffer.s.pool = CVMX_FPA_WQE_POOL;
139 g_buffer.s.size = num_segs;
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");
148 pkt_buffer.s.pool = CVMX_FPA_PACKET_POOL;
149 pkt_buffer.s.size = FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES;
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;
157 for (i=0;i<num_segs;i++)
160 pkt_buffer.s.size = FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES;
165 *(uint64_t*)cvmx_phys_to_ptr(g_buffer.s.addr + 8*i) = pkt_buffer.u64;
168 /* Build the PKO command */
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;
175 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)));
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));
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);
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);
191 work = cvmx_pow_work_request_sync(CVMX_POW_WAIT);
193 } while ((work == NULL) && (retry_cnt > 0));
196 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT get_work() timeout occured.\n");
201 cvmx_helper_free_packet_data(work);
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);
216 /* Bring the link back up as autonegotiation is not done in user applications. */
217 cvmx_helper_link_autoconf(FIX_IPD_OUTPORT);
221 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT failed.\n");
230 * Workaround ASX setup errata with CN38XX pass1
232 * @param interface Interface to setup
233 * @param port Port to setup (0..3)
234 * @param cpu_clock_hz
235 * Chip frequency in Hertz
237 * @return Zero on success, negative on failure
239 int __cvmx_helper_errata_asx_pass1(int interface, int port, int cpu_clock_hz)
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);
251 cvmx_dprintf("Illegal clock frequency (%d). CVMX_ASXX_TX_HI_WATERX not set\n", cpu_clock_hz);
257 * This function needs to be called on all Octeon chips with
260 * The Size field is 8 too large in WQE and next pointers
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
268 * @param work Work queue entry to fix
269 * @return Zero on success. Negative on failure
271 int cvmx_helper_fix_ipd_packet_chain(cvmx_wqe_t *work)
273 uint64_t number_buffers = work->word2.s.bufs;
275 /* We only need to do this if the work has buffers */
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 */
286 /* Decrement the work packet pointer */
287 buffer_ptr.s.size -= 8;
288 work->packet_ptr = buffer_ptr;
290 /* Now loop through decrementing the size for each additional buffer */
291 while (--number_buffers)
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);
296 buffer_ptr.s.size -= 8;
300 /* Make sure that these write go out before other operations such as FPA frees */
305 #endif /* CVMX_ENABLE_PKO_FUNCTIONS */
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.
313 * @param qlm QLM to disable 2nd order CDR for.
315 void __cvmx_helper_errata_qlm_disable_2nd_order_cdr(int qlm)
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++)
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);
335 cvmx_helper_qlm_jtag_update(qlm);