cvmx-helper-ilk.c revision 232809
1/***********************license start***************
2 * Copyright (c) 2010  Cavium Inc. (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 Inc. 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 INC. 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 * @file
42 *
43 * Functions for ILK initialization, configuration,
44 * and monitoring.
45 *
46 * <hr>$Revision: 41586 $<hr>
47 */
48
49#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
50#include <linux/module.h>
51
52#include <asm/octeon/cvmx.h>
53#include <asm/octeon/cvmx-config.h>
54#include <asm/octeon/cvmx-helper.h>
55#include <asm/octeon/cvmx-helper-cfg.h>
56#include <asm/octeon/cvmx-ilk.h>
57#include <asm/octeon/cvmx-bootmem.h>
58#include <asm/octeon/cvmx-pko.h>
59#include <asm/octeon/cvmx-qlm.h>
60#include <asm/octeon/cvmx-ilk-defs.h>
61#else
62#include "executive-config.h"
63#include "cvmx-config.h"
64#include "cvmx.h"
65#include "cvmx-helper.h"
66#include "cvmx-helper-cfg.h"
67#include "cvmx-ilk.h"
68#include "cvmx-bootmem.h"
69#include "cvmx-pko.h"
70#include "cvmx-qlm.h"
71#endif
72
73#ifdef CVMX_ENABLE_PKO_FUNCTIONS
74
75int __cvmx_helper_ilk_enumerate(int interface)
76{
77    interface -= CVMX_ILK_GBL_BASE;
78    return cvmx_ilk_chans[interface];
79}
80
81/**
82 * @INTERNAL
83 * Probe a ILK interface and determine the number of ports
84 * connected to it. The ILK interface should still be down
85 * after this call.
86 *
87 * @param interface Interface to probe
88 *
89 * @return Number of ports on the interface. Zero to disable.
90 */
91int __cvmx_helper_ilk_probe(int interface)
92{
93    int i, j, res = -1;
94    static int pipe_base = 0, pknd_base = 0;
95    static cvmx_ilk_pipe_chan_t *pch = NULL, *tmp;
96    static cvmx_ilk_chan_pknd_t *chpknd = NULL, *tmp1;
97    static cvmx_ilk_cal_entry_t *calent = NULL, *tmp2;
98
99    if (!OCTEON_IS_MODEL(OCTEON_CN68XX))
100        return 0;
101
102    interface -= CVMX_ILK_GBL_BASE;
103    if (interface >= CVMX_NUM_ILK_INTF)
104        return 0;
105
106    /* the configuration should be done only once */
107    if (cvmx_ilk_get_intf_ena (interface))
108        return cvmx_ilk_chans[interface];
109
110    /* configure lanes and enable the link */
111    res = cvmx_ilk_start_interface (interface, cvmx_ilk_lane_mask[interface]);
112    if (res < 0)
113        return 0;
114
115    /* set up the group of pipes available to ilk */
116    if (pipe_base == 0)
117        pipe_base = __cvmx_pko_get_pipe (interface + CVMX_ILK_GBL_BASE, 0);
118
119    if (pipe_base == -1)
120    {
121        pipe_base = 0;
122        return 0;
123    }
124
125    res = cvmx_ilk_set_pipe (interface, pipe_base, cvmx_ilk_chans[interface]);
126    if (res < 0)
127        return 0;
128
129    /* set up pipe to channel mapping */
130    i = pipe_base;
131    if (pch == NULL)
132    {
133        pch = (cvmx_ilk_pipe_chan_t *)
134#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
135        kmalloc(CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t), GFP_KERNEL);
136#else
137        cvmx_bootmem_alloc (CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t),
138                            sizeof(cvmx_ilk_pipe_chan_t));
139#endif
140        if (pch == NULL)
141            return 0;
142    }
143
144    memset (pch, 0, CVMX_MAX_ILK_CHANS * sizeof(cvmx_ilk_pipe_chan_t));
145    tmp = pch;
146    for (j = 0; j < cvmx_ilk_chans[interface]; j++)
147    {
148        tmp->pipe = i++;
149        tmp->chan = cvmx_ilk_chan_map[interface][j];
150        tmp++;
151    }
152    res = cvmx_ilk_tx_set_channel (interface, pch, cvmx_ilk_chans[interface]);
153    if (res < 0)
154    {
155        res = 0;
156        goto err_free_pch;
157    }
158    pipe_base += cvmx_ilk_chans[interface];
159
160    /* set up channel to pkind mapping */
161    if (pknd_base == 0)
162        pknd_base = cvmx_helper_get_pknd (interface + CVMX_ILK_GBL_BASE, 0);
163
164    i = pknd_base;
165    if (chpknd == NULL)
166    {
167        chpknd = (cvmx_ilk_chan_pknd_t *)
168#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
169        kmalloc(CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t), GFP_KERNEL);
170#else
171        cvmx_bootmem_alloc (CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t),
172                            sizeof(cvmx_ilk_chan_pknd_t));
173#endif
174        if (chpknd == NULL)
175        {
176            pipe_base -= cvmx_ilk_chans[interface];
177            res = 0;
178            goto err_free_pch;
179        }
180    }
181
182    memset (chpknd, 0, CVMX_MAX_ILK_PKNDS * sizeof(cvmx_ilk_chan_pknd_t));
183    tmp1 = chpknd;
184    for (j = 0; j < cvmx_ilk_chans[interface]; j++)
185    {
186        tmp1->chan = cvmx_ilk_chan_map[interface][j];
187        tmp1->pknd = i++;
188        tmp1++;
189    }
190    res = cvmx_ilk_rx_set_pknd (interface, chpknd, cvmx_ilk_chans[interface]);
191    if (res < 0)
192    {
193        pipe_base -= cvmx_ilk_chans[interface];
194        res = 0;
195        goto err_free_chpknd;
196    }
197    pknd_base += cvmx_ilk_chans[interface];
198
199    /* Set up tx calendar */
200    if (calent == NULL)
201    {
202        calent = (cvmx_ilk_cal_entry_t *)
203#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
204        kmalloc(CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t), GFP_KERNEL);
205#else
206        cvmx_bootmem_alloc (CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t),
207                            sizeof(cvmx_ilk_cal_entry_t));
208#endif
209        if (calent == NULL)
210        {
211            pipe_base -= cvmx_ilk_chans[interface];
212            pknd_base -= cvmx_ilk_chans[interface];
213            res = 0;
214            goto err_free_chpknd;
215        }
216    }
217
218    memset (calent, 0, CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t));
219    tmp1 = chpknd;
220    tmp2 = calent;
221    for (j = 0; j < cvmx_ilk_chans[interface]; j++)
222    {
223        tmp2->pipe_bpid = tmp1->pknd;
224        tmp2->ent_ctrl = PIPE_BPID;
225        tmp1++;
226        tmp2++;
227    }
228    res = cvmx_ilk_cal_setup_tx (interface, cvmx_ilk_chans[interface],
229                                 calent, 1);
230    if (res < 0)
231    {
232        pipe_base -= cvmx_ilk_chans[interface];
233        pknd_base -= cvmx_ilk_chans[interface];
234        res = 0;
235        goto err_free_calent;
236    }
237
238    /* set up rx calendar. allocated memory can be reused.
239     * this is because max pkind is always less than max pipe */
240    memset (calent, 0, CVMX_MAX_ILK_PIPES * sizeof(cvmx_ilk_cal_entry_t));
241    tmp = pch;
242    tmp2 = calent;
243    for (j = 0; j < cvmx_ilk_chans[interface]; j++)
244    {
245        tmp2->pipe_bpid = tmp->pipe;
246        tmp2->ent_ctrl = PIPE_BPID;
247        tmp++;
248        tmp2++;
249    }
250    res = cvmx_ilk_cal_setup_rx (interface, cvmx_ilk_chans[interface],
251                                 calent, CVMX_ILK_RX_FIFO_WM, 1);
252    if (res < 0)
253    {
254        pipe_base -= cvmx_ilk_chans[interface];
255        pknd_base -= cvmx_ilk_chans[interface];
256        res = 0;
257        goto err_free_calent;
258    }
259    res = __cvmx_helper_ilk_enumerate(interface + CVMX_ILK_GBL_BASE);
260
261    goto out;
262
263err_free_calent:
264#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
265    kfree (calent);
266#else
267    /* no free() for cvmx_bootmem_alloc() */
268#endif
269
270err_free_chpknd:
271#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
272    kfree (chpknd);
273#else
274    /* no free() for cvmx_bootmem_alloc() */
275#endif
276
277err_free_pch:
278#ifdef CVMX_BUILD_FOR_LINUX_KERNEL
279    kfree (pch);
280#else
281    /* no free() for cvmx_bootmem_alloc() */
282#endif
283out:
284    return res;
285}
286
287/**
288 * @INTERNAL
289 * Bringup and enable ILK interface. After this call packet
290 * I/O should be fully functional. This is called with IPD
291 * enabled but PKO disabled.
292 *
293 * @param interface Interface to bring up
294 *
295 * @return Zero on success, negative on failure
296 */
297int __cvmx_helper_ilk_enable(int interface)
298{
299    interface -= CVMX_ILK_GBL_BASE;
300    return cvmx_ilk_enable(interface);
301}
302
303/**
304 * @INTERNAL
305 * Return the link state of an IPD/PKO port as returned by ILK link status.
306 *
307 * @param ipd_port IPD/PKO port to query
308 *
309 * @return Link state
310 */
311cvmx_helper_link_info_t __cvmx_helper_ilk_link_get(int ipd_port)
312{
313    cvmx_helper_link_info_t result;
314    int interface = cvmx_helper_get_interface_num(ipd_port);
315    int retry_count = 0;
316    cvmx_ilk_rxx_cfg1_t ilk_rxx_cfg1;
317    cvmx_ilk_rxx_int_t ilk_rxx_int;
318    int lanes = 0;
319
320    result.u64 = 0;
321    interface -= CVMX_ILK_GBL_BASE;
322
323retry:
324    retry_count++;
325    if (retry_count > 10)
326        goto out;
327
328    ilk_rxx_cfg1.u64 = cvmx_read_csr (CVMX_ILK_RXX_CFG1(interface));
329    ilk_rxx_int.u64 = cvmx_read_csr (CVMX_ILK_RXX_INT(interface));
330
331    /* Clear all RX status bits */
332    if (ilk_rxx_int.u64)
333        cvmx_write_csr(CVMX_ILK_RXX_INT(interface), ilk_rxx_int.u64);
334
335    if (ilk_rxx_cfg1.s.rx_bdry_lock_ena == 0)
336    {
337        /* We need to start looking for work boundary lock */
338        ilk_rxx_cfg1.s.rx_bdry_lock_ena = cvmx_ilk_get_intf_ln_msk(interface);
339        ilk_rxx_cfg1.s.rx_align_ena = 0;
340        cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
341        //cvmx_dprintf("ILK%d: Looking for word boundary lock\n", interface);
342        goto retry;
343    }
344
345    if (ilk_rxx_cfg1.s.rx_align_ena == 0)
346    {
347        if (ilk_rxx_int.s.word_sync_done)
348        {
349            ilk_rxx_cfg1.s.rx_align_ena = 1;
350            cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
351            //printf("ILK%d: Looking for lane alignment\n", interface);
352            goto retry;
353        }
354        goto out;
355    }
356
357    if (ilk_rxx_int.s.lane_align_fail)
358    {
359        ilk_rxx_cfg1.s.rx_bdry_lock_ena = 0;
360        ilk_rxx_cfg1.s.rx_align_ena = 0;
361        cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
362        cvmx_dprintf("ILK%d: Lane alignment failed\n", interface);
363        goto out;
364    }
365
366    if (ilk_rxx_int.s.lane_align_done)
367    {
368        //cvmx_dprintf("ILK%d: Lane alignment complete\n", interface);
369    }
370
371    lanes = cvmx_pop(ilk_rxx_cfg1.s.rx_bdry_lock_ena);
372
373    result.s.link_up = 1;
374    result.s.full_duplex = 1;
375    result.s.speed = cvmx_qlm_get_gbaud_mhz(1+interface) * 64 / 67;
376    result.s.speed *= lanes;
377
378out:
379    /* If the link is down we will force disable the RX path. If it up, we'll
380        set it to match the TX state set by the if_enable call */
381    if (result.s.link_up)
382    {
383        cvmx_ilk_txx_cfg1_t ilk_txx_cfg1;
384        ilk_txx_cfg1.u64 = cvmx_read_csr(CVMX_ILK_TXX_CFG1(interface));
385        ilk_rxx_cfg1.s.pkt_ena = ilk_txx_cfg1.s.pkt_ena;
386        cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
387        //cvmx_dprintf("ILK%d: link up, %d Mbps, Full duplex mode, %d lanes\n", interface, result.s.speed, lanes);
388    }
389    else
390    {
391        ilk_rxx_cfg1.s.pkt_ena = 0;
392        cvmx_write_csr(CVMX_ILK_RXX_CFG1(interface), ilk_rxx_cfg1.u64);
393        //cvmx_dprintf("ILK link down\n");
394    }
395    return result;
396}
397
398/**
399 * @INTERNAL
400 * Set the link state of an IPD/PKO port.
401 *
402 * @param ipd_port  IPD/PKO port to configure
403 * @param link_info The new link state
404 *
405 * @return Zero on success, negative on failure
406 */
407int __cvmx_helper_ilk_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
408{
409    /* nothing to do */
410
411    return 0;
412}
413
414/**
415 * Display ilk interface statistics.
416 *
417 */
418void __cvmx_helper_ilk_show_stats (void)
419{
420    int i, j;
421    unsigned char *pchans, num_chans;
422    unsigned int chan_tmp[CVMX_MAX_ILK_CHANS];
423    cvmx_ilk_stats_ctrl_t ilk_stats_ctrl;
424
425    for (i = 0; i < CVMX_NUM_ILK_INTF; i++)
426    {
427        cvmx_ilk_get_chan_info (i, &pchans, &num_chans);
428
429        memset (chan_tmp, 0, CVMX_MAX_ILK_CHANS * sizeof (int));
430        for (j = 0; j < num_chans; j++)
431            chan_tmp[j] = pchans[j];
432
433        ilk_stats_ctrl.chan_list = chan_tmp;
434        ilk_stats_ctrl.num_chans = num_chans;
435        ilk_stats_ctrl.clr_on_rd = 0;
436        cvmx_ilk_show_stats (i, &ilk_stats_ctrl);
437    }
438}
439
440#endif /* CVMX_ENABLE_PKO_FUNCTIONS */
441