]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/contrib/octeon-sdk/cvmx-helper-ilk.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / contrib / octeon-sdk / cvmx-helper-ilk.c
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
77 int __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  */
93 int __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
265 err_free_calent:
266 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
267     kfree (calent);
268 #else
269     /* no free() for cvmx_bootmem_alloc() */
270 #endif
271
272 err_free_chpknd:
273 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
274     kfree (chpknd);
275 #else
276     /* no free() for cvmx_bootmem_alloc() */ 
277 #endif
278
279 err_free_pch:
280 #ifdef CVMX_BUILD_FOR_LINUX_KERNEL
281     kfree (pch);
282 #else
283     /* no free() for cvmx_bootmem_alloc() */ 
284 #endif
285 out:
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  */
299 int __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  */
313 cvmx_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
325 retry:
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
380 out:
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  */
409 int __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  */
420 void __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 */