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