1 /***********************license start***********************************
2 * Copyright (c) 2003-2017 Cavium Inc. ([email protected]). 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
24 * control laws, including the U.S. Export Administration Act and its
25 * associated regulations, and may be subject to export or import
26 * regulations in other 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
31 * TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
32 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
33 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
34 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
35 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT,
36 * QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK
37 * ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
39 #include <bdk.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include "libbdk-arch/bdk-csrs-gser.h"
43 #include "libbdk-arch/bdk-csrs-gsern.h"
44 #include "libbdk-hal/if/bdk-if.h"
45 #include "libbdk-hal/bdk-qlm.h"
46 #include "libbdk-hal/qlm/bdk-qlm-common.h"
47
48 /* This code is an optional part of the BDK. It is only linked in
49 if BDK_REQUIRE() needs it */
50 BDK_REQUIRE_DEFINE(QLM);
51
52 /**
53 * Convert a mode into a configuration variable string value
54 *
55 * @param mode Mode to convert
56 *
57 * @return configuration value string
58 */
bdk_qlm_mode_to_cfg_str(bdk_qlm_modes_t mode)59 const char *bdk_qlm_mode_to_cfg_str(bdk_qlm_modes_t mode)
60 {
61 #define MODE_CASE(m) case (m): return (#m)+13
62 switch (mode)
63 {
64 MODE_CASE(BDK_QLM_MODE_DISABLED);
65 MODE_CASE(BDK_QLM_MODE_PCIE_1X1);
66 MODE_CASE(BDK_QLM_MODE_PCIE_2X1);
67 MODE_CASE(BDK_QLM_MODE_PCIE_1X2);
68 MODE_CASE(BDK_QLM_MODE_PCIE_1X4);
69 MODE_CASE(BDK_QLM_MODE_PCIE_1X8);
70 MODE_CASE(BDK_QLM_MODE_PCIE_1X16);
71
72 MODE_CASE(BDK_QLM_MODE_SATA_4X1);
73 MODE_CASE(BDK_QLM_MODE_SATA_2X1);
74
75 MODE_CASE(BDK_QLM_MODE_ILK);
76 MODE_CASE(BDK_QLM_MODE_SGMII_4X1);
77 MODE_CASE(BDK_QLM_MODE_SGMII_2X1);
78 MODE_CASE(BDK_QLM_MODE_SGMII_1X1);
79 MODE_CASE(BDK_QLM_MODE_XAUI_1X4);
80 MODE_CASE(BDK_QLM_MODE_RXAUI_2X2);
81 MODE_CASE(BDK_QLM_MODE_RXAUI_1X2);
82 MODE_CASE(BDK_QLM_MODE_OCI);
83 MODE_CASE(BDK_QLM_MODE_XFI_4X1);
84 MODE_CASE(BDK_QLM_MODE_XFI_2X1);
85 MODE_CASE(BDK_QLM_MODE_XFI_1X1);
86 MODE_CASE(BDK_QLM_MODE_XLAUI_1X4);
87 MODE_CASE(BDK_QLM_MODE_10G_KR_4X1);
88 MODE_CASE(BDK_QLM_MODE_10G_KR_2X1);
89 MODE_CASE(BDK_QLM_MODE_10G_KR_1X1);
90 MODE_CASE(BDK_QLM_MODE_40G_KR4_1X4);
91 MODE_CASE(BDK_QLM_MODE_QSGMII_4X1);
92 MODE_CASE(BDK_QLM_MODE_25G_4X1);
93 MODE_CASE(BDK_QLM_MODE_25G_2X1);
94 MODE_CASE(BDK_QLM_MODE_50G_2X2);
95 MODE_CASE(BDK_QLM_MODE_50G_1X2);
96 MODE_CASE(BDK_QLM_MODE_100G_1X4);
97 MODE_CASE(BDK_QLM_MODE_25G_KR_4X1);
98 MODE_CASE(BDK_QLM_MODE_25G_KR_2X1);
99 MODE_CASE(BDK_QLM_MODE_50G_KR_2X2);
100 MODE_CASE(BDK_QLM_MODE_50G_KR_1X2);
101 MODE_CASE(BDK_QLM_MODE_100G_KR4_1X4);
102 MODE_CASE(BDK_QLM_MODE_USXGMII_4X1);
103 MODE_CASE(BDK_QLM_MODE_USXGMII_2X1);
104
105 case BDK_QLM_MODE_LAST: break; /* fall through error */
106 }
107 return "INVALID_QLM_MODE_VALUE";
108 }
109
110 /**
111 * Convert a configuration variable value string into a mode
112 *
113 * @param val Configuration variable value
114 *
115 * @return mode
116 */
bdk_qlm_cfg_string_to_mode(const char * val)117 bdk_qlm_modes_t bdk_qlm_cfg_string_to_mode(const char *val)
118 {
119 bdk_qlm_modes_t mode;
120
121 for (mode = 0; mode < BDK_QLM_MODE_LAST; mode++)
122 {
123 if (0 == strcmp(val, bdk_qlm_mode_to_cfg_str(mode)))
124 {
125 return mode;
126 }
127 }
128 return -1;
129 }
130
131 /**
132 * Convert a mode into a human understandable string
133 *
134 * @param mode Mode to convert
135 *
136 * @return Easy to read string
137 */
bdk_qlm_mode_tostring(bdk_qlm_modes_t mode)138 const char *bdk_qlm_mode_tostring(bdk_qlm_modes_t mode)
139 {
140 const char *result = "Unknown, update bdk_qlm_mode_tostring()";
141 switch (mode)
142 {
143 case BDK_QLM_MODE_DISABLED:
144 result = "Disabled";
145 break;
146 case BDK_QLM_MODE_PCIE_1X1:
147 result = "1 PCIe, 1 lane";
148 break;
149 case BDK_QLM_MODE_PCIE_2X1:
150 result = "2 PCIe, 1 lane each";
151 break;
152 case BDK_QLM_MODE_PCIE_1X2:
153 result = "1 PCIe, 2 lanes";
154 break;
155 case BDK_QLM_MODE_PCIE_1X4:
156 result = "1 PCIe, 4 lanes";
157 break;
158 case BDK_QLM_MODE_PCIE_1X8:
159 result = "1 PCIe, 8 lanes";
160 break;
161 case BDK_QLM_MODE_PCIE_1X16:
162 result = "1 PCIe, 16 lanes";
163 break;
164
165 case BDK_QLM_MODE_SATA_4X1:
166 result = "4 SATA, one lane each";
167 break;
168 case BDK_QLM_MODE_SATA_2X1:
169 result = "2 SATA, one lane each";
170 break;
171
172 case BDK_QLM_MODE_ILK:
173 result = "Interlaken";
174 break;
175 case BDK_QLM_MODE_SGMII_4X1:
176 result = "4 SGMII, 1 lane each";
177 break;
178 case BDK_QLM_MODE_SGMII_2X1:
179 result = "2 SGMII, 1 lane each";
180 break;
181 case BDK_QLM_MODE_SGMII_1X1:
182 result = "1 SGMII, 1 lane";
183 break;
184 case BDK_QLM_MODE_XAUI_1X4:
185 result = "1 XAUI, 4 lanes";
186 break;
187 case BDK_QLM_MODE_RXAUI_2X2:
188 result = "2 RXAUI, 2 lanes each";
189 break;
190 case BDK_QLM_MODE_RXAUI_1X2:
191 result = "1 RXAUI, 2 lanes each";
192 break;
193 case BDK_QLM_MODE_OCI:
194 result = "Cavium Coherent Processor Interconnect";
195 break;
196 case BDK_QLM_MODE_XFI_4X1:
197 result = "4 XFI, 1 lane each";
198 break;
199 case BDK_QLM_MODE_XFI_2X1:
200 result = "2 XFI, 1 lane each";
201 break;
202 case BDK_QLM_MODE_XFI_1X1:
203 result = "1 XFI, 1 lane";
204 break;
205 case BDK_QLM_MODE_XLAUI_1X4:
206 result = "1 XLAUI, 4 lanes";
207 break;
208 case BDK_QLM_MODE_10G_KR_4X1:
209 result = "4 10GBASE-KR, 1 lane each";
210 break;
211 case BDK_QLM_MODE_10G_KR_2X1:
212 result = "2 10GBASE-KR, 1 lane each";
213 break;
214 case BDK_QLM_MODE_10G_KR_1X1:
215 result = "1 10GBASE-KR, 1 lane";
216 break;
217 case BDK_QLM_MODE_40G_KR4_1X4:
218 result = "1 40GBASE-KR4, 4 lanes";
219 break;
220 case BDK_QLM_MODE_QSGMII_4X1:
221 result = "4 QSGMII, 1 lane";
222 break;
223 case BDK_QLM_MODE_25G_4X1:
224 result = "4 25G, 1 lane each";
225 break;
226 case BDK_QLM_MODE_25G_2X1:
227 result = "2 25G, 1 lane each";
228 break;
229 case BDK_QLM_MODE_50G_2X2:
230 result = "2 50G, 2 lanes each";
231 break;
232 case BDK_QLM_MODE_50G_1X2:
233 result = "1 50G, 2 lanes";
234 break;
235 case BDK_QLM_MODE_100G_1X4:
236 result = "1 100G, 4 lanes";
237 break;
238 case BDK_QLM_MODE_25G_KR_4X1:
239 result = "4 25G, 1 lane each";
240 break;
241 case BDK_QLM_MODE_25G_KR_2X1:
242 result = "2 25G, 1 lane each";
243 break;
244 case BDK_QLM_MODE_50G_KR_2X2:
245 result = "2 50G, 2 lanes each";
246 break;
247 case BDK_QLM_MODE_50G_KR_1X2:
248 result = "1 50G, 2 lanes";
249 break;
250 case BDK_QLM_MODE_100G_KR4_1X4:
251 result = "1 100G, 4 lanes";
252 break;
253 case BDK_QLM_MODE_USXGMII_4X1:
254 result = "4 USXGMII, 1 lane each";
255 break;
256 case BDK_QLM_MODE_USXGMII_2X1:
257 result = "2 USXGMII, 1 lane each";
258 break;
259
260 case BDK_QLM_MODE_LAST:
261 break; /* fallthrough error */
262 }
263 return result;
264 }
265
bdk_qlm_measure_clock(bdk_node_t node,int qlm)266 int bdk_qlm_measure_clock(bdk_node_t node, int qlm)
267 {
268 int ref_clock = __bdk_qlm_measure_refclock(node, qlm);
269 BDK_TRACE(QLM, "N%d.QLM%d: Ref clock %d Hz\n", node, qlm, ref_clock);
270
271 return ref_clock;
272 }
273
274 /**
275 * Set the QLM's clock source.
276 *
277 * @param node Node to use in a Numa setup
278 * @param qlm QLM to configure
279 * @param clk Clock source for QLM
280 *
281 * @return Zero on success, negative on failure
282 */
bdk_qlm_set_clock(bdk_node_t node,int qlm,bdk_qlm_clock_t clk)283 int bdk_qlm_set_clock(bdk_node_t node, int qlm, bdk_qlm_clock_t clk)
284 {
285 if (CAVIUM_IS_MODEL(CAVIUM_CN8XXX))
286 {
287 int sel;
288 int com1;
289 switch (clk)
290 {
291 case BDK_QLM_CLK_COMMON_0:
292 sel = 1;
293 com1 = 0;
294 break;
295 case BDK_QLM_CLK_COMMON_1:
296 sel = 1;
297 com1 = 1;
298 break;
299 case BDK_QLM_CLK_EXTERNAL:
300 sel = 0;
301 com1 = 0;
302 break;
303 default:
304 bdk_warn("Unrecognized clock mode %d for QLM%d on node %d.\n",
305 clk, qlm, node);
306 return -1;
307 }
308
309 BDK_CSR_MODIFY(c, node, BDK_GSERX_REFCLK_SEL(qlm),
310 c.s.com_clk_sel = sel;
311 c.s.use_com1 = com1);
312 }
313 else
314 {
315 int cclksel;
316 switch (clk)
317 {
318 case BDK_QLM_CLK_COMMON_0:
319 cclksel = 0;
320 break;
321 case BDK_QLM_CLK_COMMON_1:
322 cclksel = 1;
323 break;
324 case BDK_QLM_CLK_COMMON_2:
325 cclksel = 2;
326 break;
327 case BDK_QLM_CLK_EXTERNAL:
328 cclksel = 3;
329 break;
330 default:
331 bdk_warn("Unrecognized clock mode %d for QLM%d on node %d.\n",
332 clk, qlm, node);
333 return -1;
334 }
335 BDK_CSR_MODIFY(c, node, BDK_GSERNX_COMMON_REFCLK_BCFG(qlm),
336 c.s.pwdn = (clk == BDK_QLM_CLK_EXTERNAL) ? 0 : 1;
337 c.s.cclksel = cclksel);
338 }
339 return 0;
340 }
341
342 /**
343 * Display an eye diagram for the given QLM lane. The eye data can be in "eye", or
344 * captured during the call if "eye" is NULL.
345 *
346 * @param node Node to use in numa setup
347 * @param qlm QLM to use
348 * @param qlm_lane Which lane
349 * @param format Display format. 0 = raw, 1 = Color ASCII
350 * @param eye Eye data to display, or NULL if the data should be captured.
351 *
352 * @return Zero on success, negative on failure
353 */
bdk_qlm_eye_display(bdk_node_t node,int qlm,int qlm_lane,int format,const bdk_qlm_eye_t * eye)354 int bdk_qlm_eye_display(bdk_node_t node, int qlm, int qlm_lane, int format, const bdk_qlm_eye_t *eye)
355 {
356 int result;
357 int need_free = 0;
358 if (eye == NULL)
359 {
360 bdk_qlm_eye_t *eye_data = malloc(sizeof(bdk_qlm_eye_t));
361 if (eye_data == NULL)
362 {
363 bdk_error("Failed to allocate space for eye\n");
364 return -1;
365 }
366 if (bdk_qlm_eye_capture(node, qlm, qlm_lane, eye_data)) {
367 free(eye_data);
368 return -1;
369 }
370 eye = eye_data;
371 need_free = 1;
372 }
373
374 /* Calculate the max eye width */
375 int eye_width = 0;
376 for (int y = 0; y < eye->height; y++)
377 {
378 int width = 0;
379 for (int x = 0; x < eye->width; x++)
380 {
381 if (eye->data[y][x] == 0)
382 {
383 width++;
384 }
385 }
386 if (width > eye_width)
387 eye_width = width;
388 }
389
390 /* Calculate the max eye height */
391 int eye_height = 0;
392 for (int x = 0; x < eye->width; x++)
393 {
394 int height = 0;
395 for (int y = 0; y < eye->height; y++)
396 {
397 if (eye->data[y][x] == 0)
398 {
399 height++;
400 }
401 }
402 if (height > eye_height)
403 eye_height = height;
404 }
405
406 printf("\nEye Diagram for Node %d, QLM %d, Lane %d\n", node, qlm, qlm_lane);
407
408 if (format == 0) /* Raw */
409 {
410 for (int y = 0; y < eye->height; y++)
411 {
412 for (int x = 0; x < eye->width; x++)
413 printf("%u\t", eye->data[y][x]);
414 printf("\n");
415 }
416 result = 0;
417 }
418 else
419 result = -1;
420
421 if (need_free)
422 free((void*)eye);
423 return result;
424 }
425