1
2
3
4
5
6#include <errno.h>
7#include <i2c.h>
8#include <log.h>
9#include <malloc.h>
10#include <linux/delay.h>
11#include <display_options.h>
12
13#include <mach/cvmx-regs.h>
14#include <mach/cvmx-csr.h>
15#include <mach/cvmx-bootmem.h>
16#include <mach/octeon-model.h>
17#include <mach/cvmx-fuse.h>
18#include <mach/octeon-feature.h>
19#include <mach/cvmx-qlm.h>
20#include <mach/octeon_qlm.h>
21#include <mach/cvmx-pcie.h>
22#include <mach/cvmx-coremask.h>
23
24#include <mach/cvmx-helper.h>
25#include <mach/cvmx-helper-board.h>
26#include <mach/cvmx-helper-fdt.h>
27#include <mach/cvmx-helper-cfg.h>
28#include <mach/cvmx-helper-gpio.h>
29#include <mach/cvmx-helper-util.h>
30
31extern void octeon_i2c_unblock(int bus);
32
33static struct cvmx_fdt_sfp_info *sfp_list;
34
35
36
37
38
39
40
41
42
43static void *cvm_sfp_alloc(size_t size)
44{
45 return calloc(size, 1);
46}
47
48
49
50
51
52
53
54
55
56
57static inline void cvm_sfp_free(void *ptr, size_t size)
58{
59 free(ptr);
60}
61
62
63
64
65
66
67
68
69
70static int cvmx_qsfp_select(const struct cvmx_fdt_sfp_info *sfp, bool enable)
71{
72
73 if (!sfp->is_qsfp) {
74 debug("%s(%s, %d): not QSFP\n", __func__, sfp->name, enable);
75 return 0;
76 }
77
78 if (dm_gpio_is_valid(&sfp->select)) {
79
80 return dm_gpio_set_value(&sfp->select, !enable);
81 }
82
83 debug("%s: select GPIO unknown\n", __func__);
84 return 0;
85}
86
87static int cvmx_sfp_parse_sfp_buffer(struct cvmx_sfp_mod_info *sfp_info,
88 const uint8_t *buffer)
89{
90 u8 csum = 0;
91 bool csum_good = false;
92 int i;
93
94
95 for (i = 0; i < 0x3f; i++)
96 csum += buffer[i];
97 csum_good = csum == buffer[0x3f];
98 debug("%s: Lower checksum: 0x%02x, expected: 0x%02x\n", __func__, csum,
99 buffer[0x3f]);
100 csum = 0;
101 for (i = 0x40; i < 0x5f; i++)
102 csum += buffer[i];
103 debug("%s: Upper checksum: 0x%02x, expected: 0x%02x\n", __func__, csum,
104 buffer[0x5f]);
105 if (csum != buffer[0x5f] || !csum_good) {
106 debug("Error: SFP EEPROM checksum information is incorrect\n");
107 return -1;
108 }
109
110 sfp_info->conn_type = buffer[0];
111 if (buffer[1] < 1 || buffer[1] > 7) {
112 debug("Error: Unknown SFP extended identifier 0x%x\n",
113 buffer[1]);
114 return -1;
115 }
116 if (buffer[1] != 4) {
117 debug("Module is not SFP/SFP+/SFP28/QSFP+\n");
118 return -1;
119 }
120 sfp_info->mod_type = buffer[2];
121 sfp_info->eth_comp = buffer[3] & 0xf0;
122 sfp_info->cable_comp = buffer[0x24];
123
124
125
126
127
128
129 if ((buffer[8] & 0x0C) == 0x08) {
130 sfp_info->limiting = true;
131 sfp_info->active_cable = true;
132 } else if ((buffer[8] & 0xC) == 0x4) {
133 sfp_info->limiting = false;
134 sfp_info->active_cable = false;
135 }
136 if ((buffer[3] & 3) == 2) {
137 sfp_info->active_cable = true;
138 sfp_info->limiting = true;
139 }
140
141 switch (sfp_info->mod_type) {
142 case CVMX_SFP_MOD_OPTICAL_LC:
143 case CVMX_SFP_MOD_OPTICAL_PIGTAIL:
144 sfp_info->copper_cable = false;
145 break;
146 case CVMX_SFP_MOD_COPPER_PIGTAIL:
147 sfp_info->copper_cable = true;
148 break;
149 case CVMX_SFP_MOD_NO_SEP_CONN:
150 switch (sfp_info->cable_comp) {
151 case CVMX_SFP_CABLE_100G_25GAUI_C2M_AOC_HIGH_BER:
152 case CVMX_SFP_CABLE_100G_25GAUI_C2M_AOC_LOW_BER:
153 case CVMX_SFP_CABLE_100G_25GAUI_C2M_ACC_LOW_BER:
154 sfp_info->copper_cable = false;
155 sfp_info->limiting = true;
156 sfp_info->active_cable = true;
157 break;
158
159 case CVMX_SFP_CABLE_100G_SR4_25G_SR:
160 case CVMX_SFP_CABLE_100G_LR4_25G_LR:
161 case CVMX_SFP_CABLE_100G_ER4_25G_ER:
162 case CVMX_SFP_CABLE_100G_SR10:
163 case CVMX_SFP_CABLE_100G_CWDM4_MSA:
164 case CVMX_SFP_CABLE_100G_PSM4:
165 case CVMX_SFP_CABLE_100G_CWDM4:
166 case CVMX_SFP_CABLE_40G_ER4:
167 case CVMX_SFP_CABLE_4X10G_SR:
168 case CVMX_SFP_CABLE_G959_1_P1I1_2D1:
169 case CVMX_SFP_CABLE_G959_1_P1S1_2D2:
170 case CVMX_SFP_CABLE_G959_1_P1L1_2D2:
171 case CVMX_SFP_CABLE_100G_CLR4:
172 case CVMX_SFP_CABLE_100G_2_LAMBDA_DWDM:
173 case CVMX_SFP_CABLE_40G_SWDM4:
174 case CVMX_SFP_CABLE_100G_SWDM4:
175 case CVMX_SFP_CABLE_100G_PAM4_BIDI:
176 sfp_info->copper_cable = false;
177 break;
178
179 case CVMX_SFP_CABLE_100G_25GAUI_C2M_ACC_HIGH_BER:
180 case CVMX_SFP_CABLE_10GBASE_T:
181 case CVMX_SFP_CABLE_10GBASE_T_SR:
182 case CVMX_SFP_CABLE_5GBASE_T:
183 case CVMX_SFP_CABLE_2_5GBASE_T:
184 sfp_info->copper_cable = true;
185 sfp_info->limiting = true;
186 sfp_info->active_cable = true;
187 break;
188
189 case CVMX_SFP_CABLE_100G_CR4_25G_CR_CA_L:
190 case CVMX_SFP_CABLE_25G_CR_CA_S:
191 case CVMX_SFP_CABLE_25G_CR_CA_N:
192 case CVMX_SFP_CABLE_40G_PSM4:
193 sfp_info->copper_cable = true;
194 break;
195
196 default:
197 switch (sfp_info->eth_comp) {
198 case CVMX_SFP_CABLE_10GBASE_ER:
199 case CVMX_SFP_CABLE_10GBASE_LRM:
200 case CVMX_SFP_CABLE_10GBASE_LR:
201 case CVMX_SFP_CABLE_10GBASE_SR:
202 sfp_info->copper_cable = false;
203 break;
204 }
205 break;
206 }
207 break;
208
209 case CVMX_SFP_MOD_RJ45:
210 debug("%s: RJ45 adapter\n", __func__);
211 sfp_info->copper_cable = true;
212 sfp_info->active_cable = true;
213 sfp_info->limiting = true;
214 break;
215 case CVMX_SFP_MOD_UNKNOWN:
216
217
218
219
220 if (buffer[6] & 8) {
221 debug("RJ45 gigabit module detected\n");
222 sfp_info->mod_type = CVMX_SFP_MOD_RJ45;
223 sfp_info->copper_cable = false;
224 sfp_info->limiting = true;
225 sfp_info->active_cable = true;
226 sfp_info->max_copper_cable_len = buffer[0x12];
227 sfp_info->rate = CVMX_SFP_RATE_1G;
228 } else {
229 debug("Unknown module type 0x%x\n", sfp_info->mod_type);
230 }
231 sfp_info->limiting = true;
232 break;
233 case CVMX_SFP_MOD_MXC_2X16:
234 debug("%s: MXC 2X16\n", __func__);
235 break;
236 default:
237 sfp_info->limiting = true;
238 break;
239 }
240
241 if (sfp_info->copper_cable)
242 sfp_info->max_copper_cable_len = buffer[0x12];
243 else
244 sfp_info->max_50um_om4_cable_length = buffer[0x12] * 10;
245
246 if (buffer[0xe])
247 sfp_info->max_single_mode_cable_length = buffer[0xe] * 1000;
248 else
249 sfp_info->max_single_mode_cable_length = buffer[0xf] * 100000;
250
251 sfp_info->max_50um_om2_cable_length = buffer[0x10] * 10;
252 sfp_info->max_62_5um_om1_cable_length = buffer[0x11] * 10;
253 sfp_info->max_50um_om3_cable_length = buffer[0x13] * 10;
254
255 if (buffer[0xc] == 0xff) {
256 if (buffer[0x42] >= 255)
257 sfp_info->rate = CVMX_SFP_RATE_100G;
258 else if (buffer[0x42] >= 160)
259 sfp_info->rate = CVMX_SFP_RATE_40G;
260 else if (buffer[0x42] >= 100)
261 sfp_info->rate = CVMX_SFP_RATE_25G;
262 else
263 sfp_info->rate = CVMX_SFP_RATE_UNKNOWN;
264 } else if (buffer[0xc] >= 100) {
265 sfp_info->rate = CVMX_SFP_RATE_10G;
266 } else if (buffer[0xc] >= 10) {
267 sfp_info->rate = CVMX_SFP_RATE_1G;
268 } else {
269 sfp_info->rate = CVMX_SFP_RATE_UNKNOWN;
270 }
271
272 if (sfp_info->rate == CVMX_SFP_RATE_UNKNOWN) {
273 switch (sfp_info->cable_comp) {
274 case CVMX_SFP_CABLE_100G_SR10:
275 case CVMX_SFP_CABLE_100G_CWDM4_MSA:
276 case CVMX_SFP_CABLE_100G_PSM4:
277 case CVMX_SFP_CABLE_100G_CWDM4:
278 case CVMX_SFP_CABLE_100G_CLR4:
279 case CVMX_SFP_CABLE_100G_2_LAMBDA_DWDM:
280 case CVMX_SFP_CABLE_100G_SWDM4:
281 case CVMX_SFP_CABLE_100G_PAM4_BIDI:
282 sfp_info->rate = CVMX_SFP_RATE_100G;
283 break;
284 case CVMX_SFP_CABLE_100G_25GAUI_C2M_AOC_HIGH_BER:
285 case CVMX_SFP_CABLE_100G_SR4_25G_SR:
286 case CVMX_SFP_CABLE_100G_LR4_25G_LR:
287 case CVMX_SFP_CABLE_100G_ER4_25G_ER:
288 case CVMX_SFP_CABLE_100G_25GAUI_C2M_ACC_HIGH_BER:
289 case CVMX_SFP_CABLE_100G_CR4_25G_CR_CA_L:
290 case CVMX_SFP_CABLE_25G_CR_CA_S:
291 case CVMX_SFP_CABLE_25G_CR_CA_N:
292 case CVMX_SFP_CABLE_100G_25GAUI_C2M_AOC_LOW_BER:
293 case CVMX_SFP_CABLE_100G_25GAUI_C2M_ACC_LOW_BER:
294 sfp_info->rate = CVMX_SFP_RATE_25G;
295 break;
296 case CVMX_SFP_CABLE_40G_ER4:
297 case CVMX_SFP_CABLE_4X10G_SR:
298 case CVMX_SFP_CABLE_40G_PSM4:
299 case CVMX_SFP_CABLE_40G_SWDM4:
300 sfp_info->rate = CVMX_SFP_RATE_40G;
301 break;
302 case CVMX_SFP_CABLE_G959_1_P1I1_2D1:
303 case CVMX_SFP_CABLE_G959_1_P1S1_2D2:
304 case CVMX_SFP_CABLE_G959_1_P1L1_2D2:
305 case CVMX_SFP_CABLE_10GBASE_T:
306 case CVMX_SFP_CABLE_10GBASE_T_SR:
307 case CVMX_SFP_CABLE_5GBASE_T:
308 case CVMX_SFP_CABLE_2_5GBASE_T:
309 sfp_info->rate = CVMX_SFP_RATE_10G;
310 break;
311 default:
312 switch (sfp_info->eth_comp) {
313 case CVMX_SFP_CABLE_10GBASE_ER:
314 case CVMX_SFP_CABLE_10GBASE_LRM:
315 case CVMX_SFP_CABLE_10GBASE_LR:
316 case CVMX_SFP_CABLE_10GBASE_SR:
317 sfp_info->rate = CVMX_SFP_RATE_10G;
318 break;
319 default:
320 sfp_info->rate = CVMX_SFP_RATE_UNKNOWN;
321 break;
322 }
323 break;
324 }
325 }
326
327 if (buffer[0xc] < 0xff)
328 sfp_info->bitrate_max = buffer[0xc] * 100;
329 else
330 sfp_info->bitrate_max = buffer[0x42] * 250;
331
332 if ((buffer[8] & 0xc) == 8) {
333 if (buffer[0x3c] & 0x4)
334 sfp_info->limiting = true;
335 }
336
337
338
339
340 if ((sfp_info->rate == CVMX_SFP_RATE_25G &&
341 sfp_info->copper_cable) &&
342 (sfp_info->cable_comp == CVMX_SFP_CABLE_25G_CR_CA_S ||
343 sfp_info->max_copper_cable_len >= 5))
344 sfp_info->fec_required = true;
345
346
347
348
349 memcpy(sfp_info->vendor_name, &buffer[0x14], 16);
350 memcpy(sfp_info->vendor_oui, &buffer[0x25], 3);
351 memcpy(sfp_info->vendor_pn, &buffer[0x28], 16);
352 memcpy(sfp_info->vendor_rev, &buffer[0x38], 4);
353 memcpy(sfp_info->vendor_sn, &buffer[0x44], 16);
354 memcpy(sfp_info->date_code, &buffer[0x54], 8);
355
356 sfp_info->cooled_laser = !!(buffer[0x40] & 4);
357 sfp_info->internal_cdr = !!(buffer[0x40] & 8);
358
359 if (buffer[0x40] & 0x20)
360 sfp_info->power_level = 3;
361 else
362 sfp_info->power_level = (buffer[0x40] & 2) ? 2 : 1;
363
364 sfp_info->diag_paging = !!(buffer[0x40] & 0x10);
365 sfp_info->linear_rx_output = !(buffer[0x40] & 1);
366 sfp_info->los_implemented = !!(buffer[0x41] & 2);
367 sfp_info->los_inverted = !!(buffer[0x41] & 4);
368 sfp_info->tx_fault_implemented = !!(buffer[0x41] & 8);
369 sfp_info->tx_disable_implemented = !!(buffer[0x41] & 0x10);
370 sfp_info->rate_select_implemented = !!(buffer[0x41] & 0x20);
371 sfp_info->tuneable_transmitter = !!(buffer[0x41] & 0x40);
372 sfp_info->rx_decision_threshold_implemented = !!(buffer[0x41] & 0x80);
373
374 sfp_info->diag_monitoring = !!(buffer[0x5c] & 0x40);
375 sfp_info->diag_rx_power_averaged = !!(buffer[0x5c] & 0x8);
376 sfp_info->diag_externally_calibrated = !!(buffer[0x5c] & 0x10);
377 sfp_info->diag_internally_calibrated = !!(buffer[0x5c] & 0x20);
378 sfp_info->diag_addr_change_required = !!(buffer[0x5c] & 0x4);
379 sfp_info->diag_soft_rate_select_control = !!(buffer[0x5d] & 2);
380 sfp_info->diag_app_select_control = !!(buffer[0x5d] & 4);
381 sfp_info->diag_soft_rate_select_control = !!(buffer[0x5d] & 8);
382 sfp_info->diag_soft_rx_los_implemented = !!(buffer[0x5d] & 0x10);
383 sfp_info->diag_soft_tx_fault_implemented = !!(buffer[0x5d] & 0x20);
384 sfp_info->diag_soft_tx_disable_implemented = !!(buffer[0x5d] & 0x40);
385 sfp_info->diag_alarm_warning_flags_implemented =
386 !!(buffer[0x5d] & 0x80);
387 sfp_info->diag_rev = buffer[0x5e];
388
389 return 0;
390}
391
392static int cvmx_sfp_parse_qsfp_buffer(struct cvmx_sfp_mod_info *sfp_info,
393 const uint8_t *buffer)
394{
395 u8 csum = 0;
396 bool csum_good = false;
397 int i;
398
399
400 for (i = 0x80; i < 0xbf; i++)
401 csum += buffer[i];
402 csum_good = csum == buffer[0xbf];
403 debug("%s: Lower checksum: 0x%02x, expected: 0x%02x\n", __func__, csum,
404 buffer[0xbf]);
405 csum = 0;
406 for (i = 0xc0; i < 0xdf; i++)
407 csum += buffer[i];
408 debug("%s: Upper checksum: 0x%02x, expected: 0x%02x\n", __func__, csum,
409 buffer[0xdf]);
410 if (csum != buffer[0xdf] || !csum_good) {
411 debug("Error: SFP EEPROM checksum information is incorrect\n");
412 return -1;
413 }
414
415 sfp_info->conn_type = buffer[0x80];
416 sfp_info->mod_type = buffer[0x82];
417 sfp_info->eth_comp = buffer[0x83] & 0xf0;
418 sfp_info->cable_comp = buffer[0xa4];
419
420 switch (sfp_info->mod_type) {
421 case CVMX_SFP_MOD_COPPER_PIGTAIL:
422 case CVMX_SFP_MOD_NO_SEP_CONN:
423 debug("%s: copper pigtail or no separable cable\n", __func__);
424
425
426
427
428
429 sfp_info->copper_cable = true;
430 if ((buffer[0x88] & 0x0C) == 0x08) {
431 sfp_info->limiting = true;
432 sfp_info->active_cable = true;
433 } else if ((buffer[0x88] & 0xC) == 0x4) {
434 sfp_info->limiting = false;
435 sfp_info->active_cable = false;
436 }
437 if ((buffer[0x83] & 3) == 2) {
438 sfp_info->active_cable = true;
439 sfp_info->limiting = true;
440 }
441 break;
442 case CVMX_SFP_MOD_RJ45:
443 debug("%s: RJ45 adapter\n", __func__);
444 sfp_info->copper_cable = true;
445 sfp_info->active_cable = true;
446 sfp_info->limiting = true;
447 break;
448 case CVMX_SFP_MOD_UNKNOWN:
449 debug("Unknown module type\n");
450
451
452
453
454 if (buffer[0x86] & 8) {
455 sfp_info->mod_type = CVMX_SFP_MOD_RJ45;
456 sfp_info->copper_cable = false;
457 sfp_info->limiting = true;
458 sfp_info->active_cable = true;
459 sfp_info->max_copper_cable_len = buffer[0x92];
460 sfp_info->rate = CVMX_SFP_RATE_1G;
461 }
462 fallthrough;
463 default:
464 sfp_info->limiting = true;
465 break;
466 }
467
468 if (sfp_info->copper_cable)
469 sfp_info->max_copper_cable_len = buffer[0x92];
470 else
471 sfp_info->max_50um_om4_cable_length = buffer[0x92] * 10;
472
473 debug("%s: copper cable: %d, max copper cable len: %d\n", __func__,
474 sfp_info->copper_cable, sfp_info->max_copper_cable_len);
475 if (buffer[0xe])
476 sfp_info->max_single_mode_cable_length = buffer[0x8e] * 1000;
477 else
478 sfp_info->max_single_mode_cable_length = buffer[0x8f] * 100000;
479
480 sfp_info->max_50um_om2_cable_length = buffer[0x90] * 10;
481 sfp_info->max_62_5um_om1_cable_length = buffer[0x91] * 10;
482 sfp_info->max_50um_om3_cable_length = buffer[0x93] * 10;
483
484 if (buffer[0x8c] == 12) {
485 sfp_info->rate = CVMX_SFP_RATE_1G;
486 } else if (buffer[0x8c] == 103) {
487 sfp_info->rate = CVMX_SFP_RATE_10G;
488 } else if (buffer[0x8c] == 0xff) {
489 if (buffer[0xc2] == 103)
490 sfp_info->rate = CVMX_SFP_RATE_100G;
491 }
492
493 if (buffer[0x8c] < 0xff)
494 sfp_info->bitrate_max = buffer[0x8c] * 100;
495 else
496 sfp_info->bitrate_max = buffer[0xc2] * 250;
497
498 if ((buffer[0x88] & 0xc) == 8) {
499 if (buffer[0xbc] & 0x4)
500 sfp_info->limiting = true;
501 }
502
503
504
505
506
507
508
509 memcpy(sfp_info->vendor_name, &buffer[0x94], 16);
510 memcpy(sfp_info->vendor_oui, &buffer[0xa5], 3);
511 memcpy(sfp_info->vendor_pn, &buffer[0xa8], 16);
512 memcpy(sfp_info->vendor_rev, &buffer[0xb8], 4);
513 memcpy(sfp_info->vendor_sn, &buffer[0xc4], 16);
514 memcpy(sfp_info->date_code, &buffer[0xd4], 8);
515
516 sfp_info->linear_rx_output = !!(buffer[0xc0] & 1);
517 sfp_info->cooled_laser = !!(buffer[0xc0] & 4);
518 sfp_info->internal_cdr = !!(buffer[0xc0] & 8);
519
520 if (buffer[0xc0] & 0x20)
521 sfp_info->power_level = 3;
522 else
523 sfp_info->power_level = (buffer[0xc0] & 2) ? 2 : 1;
524
525 sfp_info->diag_paging = !!(buffer[0xc0] & 0x10);
526 sfp_info->los_implemented = !!(buffer[0xc1] & 2);
527 sfp_info->los_inverted = !!(buffer[0xc1] & 4);
528 sfp_info->tx_fault_implemented = !!(buffer[0xc1] & 8);
529 sfp_info->tx_disable_implemented = !!(buffer[0xc1] & 0x10);
530 sfp_info->rate_select_implemented = !!(buffer[0xc1] & 0x20);
531 sfp_info->tuneable_transmitter = !!(buffer[0xc1] & 0x40);
532 sfp_info->rx_decision_threshold_implemented = !!(buffer[0xc1] & 0x80);
533
534 sfp_info->diag_monitoring = !!(buffer[0xdc] & 0x40);
535 sfp_info->diag_rx_power_averaged = !!(buffer[0xdc] & 0x8);
536 sfp_info->diag_externally_calibrated = !!(buffer[0xdc] & 0x10);
537 sfp_info->diag_internally_calibrated = !!(buffer[0xdc] & 0x20);
538 sfp_info->diag_addr_change_required = !!(buffer[0xdc] & 0x4);
539 sfp_info->diag_soft_rate_select_control = !!(buffer[0xdd] & 2);
540 sfp_info->diag_app_select_control = !!(buffer[0xdd] & 4);
541 sfp_info->diag_soft_rate_select_control = !!(buffer[0xdd] & 8);
542 sfp_info->diag_soft_rx_los_implemented = !!(buffer[0xdd] & 0x10);
543 sfp_info->diag_soft_tx_fault_implemented = !!(buffer[0xdd] & 0x20);
544 sfp_info->diag_soft_tx_disable_implemented = !!(buffer[0xdd] & 0x40);
545 sfp_info->diag_alarm_warning_flags_implemented =
546 !!(buffer[0xdd] & 0x80);
547 sfp_info->diag_rev = buffer[0xde];
548
549 return 0;
550}
551
552static bool sfp_verify_checksum(const uint8_t *buffer)
553{
554 u8 csum = 0;
555 u8 offset;
556 bool csum_good = false;
557 int i;
558
559 switch (buffer[0]) {
560 case CVMX_SFP_CONN_QSFP:
561 case CVMX_SFP_CONN_QSFPP:
562 case CVMX_SFP_CONN_QSFP28:
563 case CVMX_SFP_CONN_MICRO_QSFP:
564 case CVMX_SFP_CONN_QSFP_DD:
565 offset = 0x80;
566 break;
567 default:
568 offset = 0;
569 break;
570 }
571 for (i = offset; i < offset + 0x3f; i++)
572 csum += buffer[i];
573 csum_good = csum == buffer[offset + 0x3f];
574 if (!csum_good) {
575 debug("%s: Lower checksum bad, got 0x%x, expected 0x%x\n",
576 __func__, csum, buffer[offset + 0x3f]);
577 return false;
578 }
579 csum = 0;
580 for (i = offset + 0x40; i < offset + 0x5f; i++)
581 csum += buffer[i];
582 if (csum != buffer[offset + 0x5f]) {
583 debug("%s: Upper checksum bad, got 0x%x, expected 0x%x\n",
584 __func__, csum, buffer[offset + 0x5f]);
585 return false;
586 }
587 return true;
588}
589
590
591
592
593
594
595
596
597int cvmx_sfp_read_i2c_eeprom(struct cvmx_fdt_sfp_info *sfp)
598{
599 const struct cvmx_fdt_i2c_bus_info *bus = sfp->i2c_bus;
600 int oct_bus = cvmx_fdt_i2c_get_root_bus(bus);
601 struct udevice *dev;
602 u8 buffer[256];
603 bool is_qsfp;
604 int retry;
605 int err;
606
607 if (!bus) {
608 debug("%s(%s): Error: i2c bus undefined for eeprom\n", __func__,
609 sfp->name);
610 return -1;
611 }
612
613 is_qsfp = (sfp->sfp_info.conn_type == CVMX_SFP_CONN_QSFP ||
614 sfp->sfp_info.conn_type == CVMX_SFP_CONN_QSFPP ||
615 sfp->sfp_info.conn_type == CVMX_SFP_CONN_QSFP28 ||
616 sfp->sfp_info.conn_type == CVMX_SFP_CONN_MICRO_QSFP) ||
617 sfp->is_qsfp;
618
619 err = cvmx_qsfp_select(sfp, true);
620 if (err) {
621 debug("%s: Error selecting SFP/QSFP slot\n", __func__);
622 return err;
623 }
624
625 debug("%s: Reading eeprom from i2c address %d:0x%x\n", __func__,
626 oct_bus, sfp->i2c_eeprom_addr);
627 for (retry = 0; retry < 3; retry++) {
628 err = i2c_get_chip(bus->i2c_bus, sfp->i2c_eeprom_addr, 1, &dev);
629 if (err) {
630 debug("Cannot find I2C device: %d\n", err);
631 goto error;
632 }
633
634 err = dm_i2c_read(dev, 0, buffer, 256);
635 if (err || !sfp_verify_checksum(buffer)) {
636 debug("%s: Error %d reading eeprom at 0x%x, bus %d\n",
637 __func__, err, sfp->i2c_eeprom_addr, oct_bus);
638 debug("%s: Retry %d\n", __func__, retry + 1);
639 mdelay(1000);
640 } else {
641 break;
642 }
643 }
644 if (err) {
645 debug("%s: Error reading eeprom from SFP %s\n", __func__,
646 sfp->name);
647 return -1;
648 }
649#ifdef DEBUG
650 print_buffer(0, buffer, 1, 256, 0);
651#endif
652 memset(&sfp->sfp_info, 0, sizeof(struct cvmx_sfp_mod_info));
653
654 switch (buffer[0]) {
655 case CVMX_SFP_CONN_SFP:
656 err = cvmx_sfp_parse_sfp_buffer(&sfp->sfp_info, buffer);
657 break;
658 case CVMX_SFP_CONN_QSFP:
659 case CVMX_SFP_CONN_QSFPP:
660 case CVMX_SFP_CONN_QSFP28:
661 case CVMX_SFP_CONN_MICRO_QSFP:
662 err = cvmx_sfp_parse_qsfp_buffer(&sfp->sfp_info, buffer);
663 break;
664 default:
665 debug("%s: Unknown SFP transceiver type 0x%x\n", __func__,
666 buffer[0]);
667 err = -1;
668 break;
669 }
670
671error:
672 if (is_qsfp)
673 err |= cvmx_qsfp_select(sfp, false);
674
675 if (!err) {
676 sfp->valid = true;
677 sfp->sfp_info.valid = true;
678 } else {
679 sfp->valid = false;
680 sfp->sfp_info.valid = false;
681 }
682
683 return err;
684}
685
686
687
688
689
690
691
692
693
694
695int cvmx_sfp_check_mod_abs(struct cvmx_fdt_sfp_info *sfp, void *data)
696{
697 int val;
698 int err = 0;
699 int mode;
700
701 if (!dm_gpio_is_valid(&sfp->mod_abs)) {
702 debug("%s: Error: mod_abs not set for %s\n", __func__,
703 sfp->name);
704 return -1;
705 }
706 val = dm_gpio_get_value(&sfp->mod_abs);
707 debug("%s(%s, %p) mod_abs: %d\n", __func__, sfp->name, data, val);
708 if (val >= 0 && val != sfp->last_mod_abs && sfp->mod_abs_changed) {
709 err = 0;
710 if (!val) {
711 err = cvmx_sfp_read_i2c_eeprom(sfp);
712 if (err)
713 debug("%s: Error reading SFP %s EEPROM\n",
714 __func__, sfp->name);
715 }
716 err = sfp->mod_abs_changed(sfp, val, sfp->mod_abs_changed_data);
717 }
718 debug("%s(%s (%p)): Last mod_abs: %d, current: %d, changed: %p, rc: %d, next: %p, caller: %p\n",
719 __func__, sfp->name, sfp, sfp->last_mod_abs, val,
720 sfp->mod_abs_changed, err, sfp->next_iface_sfp,
721 __builtin_return_address(0));
722
723 if (err >= 0) {
724 sfp->last_mod_abs = val;
725 mode = cvmx_helper_interface_get_mode(sfp->xiface);
726 cvmx_sfp_validate_module(sfp, mode);
727 } else {
728 debug("%s: mod_abs_changed for %s returned error\n", __func__,
729 sfp->name);
730 }
731
732 return err < 0 ? err : val;
733}
734
735
736
737
738
739
740int cvmx_sfp_read_all_modules(void)
741{
742 struct cvmx_fdt_sfp_info *sfp;
743 int val;
744 bool error = false;
745 int rc;
746
747 for (sfp = sfp_list; sfp; sfp = sfp->next) {
748 if (dm_gpio_is_valid(&sfp->mod_abs)) {
749
750 val = dm_gpio_get_value(&sfp->mod_abs);
751 sfp->last_mod_abs = val;
752 if (val)
753 continue;
754 }
755 rc = cvmx_sfp_read_i2c_eeprom(sfp);
756 if (rc) {
757 debug("%s: Error reading eeprom from SFP %s\n",
758 __func__, sfp->name);
759 error = true;
760 }
761 }
762
763 return error ? -1 : 0;
764}
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781int cvmx_sfp_register_mod_abs_changed(struct cvmx_fdt_sfp_info *sfp,
782 int (*mod_abs_changed)(struct cvmx_fdt_sfp_info *sfp,
783 int val, void *data),
784 void *mod_abs_changed_data)
785{
786 sfp->mod_abs_changed = mod_abs_changed;
787 sfp->mod_abs_changed_data = mod_abs_changed_data;
788
789 sfp->last_mod_abs = -2;
790
791 return 0;
792}
793
794
795
796
797
798
799
800
801
802
803static int cvmx_sfp_parse_sfp(struct cvmx_fdt_sfp_info *sfp, ofnode node)
804{
805 struct ofnode_phandle_args phandle;
806 int err;
807
808 sfp->name = ofnode_get_name(node);
809 sfp->of_offset = ofnode_to_offset(node);
810
811 err = gpio_request_by_name_nodev(node, "tx_disable", 0,
812 &sfp->tx_disable, GPIOD_IS_OUT);
813 if (err) {
814 printf("%s: tx_disable not found in DT!\n", __func__);
815 return -ENODEV;
816 }
817 dm_gpio_set_value(&sfp->tx_disable, 0);
818
819 err = gpio_request_by_name_nodev(node, "mod_abs", 0,
820 &sfp->mod_abs, GPIOD_IS_IN);
821 if (err) {
822 printf("%s: mod_abs not found in DT!\n", __func__);
823 return -ENODEV;
824 }
825
826 err = gpio_request_by_name_nodev(node, "tx_error", 0,
827 &sfp->tx_error, GPIOD_IS_IN);
828 if (err) {
829 printf("%s: tx_error not found in DT!\n", __func__);
830 return -ENODEV;
831 }
832
833 err = gpio_request_by_name_nodev(node, "rx_los", 0,
834 &sfp->rx_los, GPIOD_IS_IN);
835 if (err) {
836 printf("%s: rx_los not found in DT!\n", __func__);
837 return -ENODEV;
838 }
839
840 err = ofnode_parse_phandle_with_args(node, "eeprom", NULL, 0, 0,
841 &phandle);
842 if (!err) {
843 sfp->i2c_eeprom_addr = ofnode_get_addr(phandle.node);
844 debug("%s: eeprom address: 0x%x\n", __func__,
845 sfp->i2c_eeprom_addr);
846
847 debug("%s: Getting eeprom i2c bus for %s\n", __func__,
848 sfp->name);
849 sfp->i2c_bus = cvmx_ofnode_get_i2c_bus(ofnode_get_parent(phandle.node));
850 }
851
852 err = ofnode_parse_phandle_with_args(node, "diag", NULL, 0, 0,
853 &phandle);
854 if (!err) {
855 sfp->i2c_diag_addr = ofnode_get_addr(phandle.node);
856 if (!sfp->i2c_bus)
857 sfp->i2c_bus = cvmx_ofnode_get_i2c_bus(ofnode_get_parent(phandle.node));
858 }
859
860 sfp->last_mod_abs = -2;
861 sfp->last_rx_los = -2;
862
863 if (!sfp->i2c_bus) {
864 debug("%s(%s): Error: could not get i2c bus from device tree\n",
865 __func__, sfp->name);
866 err = -1;
867 }
868
869 if (err) {
870 dm_gpio_free(sfp->tx_disable.dev, &sfp->tx_disable);
871 dm_gpio_free(sfp->mod_abs.dev, &sfp->mod_abs);
872 dm_gpio_free(sfp->tx_error.dev, &sfp->tx_error);
873 dm_gpio_free(sfp->rx_los.dev, &sfp->rx_los);
874 } else {
875 sfp->valid = true;
876 }
877
878 return err;
879}
880
881
882
883
884
885
886
887
888
889
890static int cvmx_sfp_parse_qsfp(struct cvmx_fdt_sfp_info *sfp, ofnode node)
891{
892 struct ofnode_phandle_args phandle;
893 int err;
894
895 sfp->is_qsfp = true;
896 sfp->name = ofnode_get_name(node);
897 sfp->of_offset = ofnode_to_offset(node);
898
899 err = gpio_request_by_name_nodev(node, "lp_mode", 0,
900 &sfp->lp_mode, GPIOD_IS_OUT);
901 if (err) {
902 printf("%s: lp_mode not found in DT!\n", __func__);
903 return -ENODEV;
904 }
905
906 err = gpio_request_by_name_nodev(node, "mod_prs", 0,
907 &sfp->mod_abs, GPIOD_IS_IN);
908 if (err) {
909 printf("%s: mod_prs not found in DT!\n", __func__);
910 return -ENODEV;
911 }
912
913 err = gpio_request_by_name_nodev(node, "select", 0,
914 &sfp->select, GPIOD_IS_IN);
915 if (err) {
916 printf("%s: select not found in DT!\n", __func__);
917 return -ENODEV;
918 }
919
920 err = gpio_request_by_name_nodev(node, "reset", 0,
921 &sfp->reset, GPIOD_IS_OUT);
922 if (err) {
923 printf("%s: reset not found in DT!\n", __func__);
924 return -ENODEV;
925 }
926
927 err = gpio_request_by_name_nodev(node, "interrupt", 0,
928 &sfp->interrupt, GPIOD_IS_IN);
929 if (err) {
930 printf("%s: interrupt not found in DT!\n", __func__);
931 return -ENODEV;
932 }
933
934 err = ofnode_parse_phandle_with_args(node, "eeprom", NULL, 0, 0,
935 &phandle);
936 if (!err) {
937 sfp->i2c_eeprom_addr = ofnode_get_addr(phandle.node);
938 sfp->i2c_bus = cvmx_ofnode_get_i2c_bus(ofnode_get_parent(phandle.node));
939 }
940
941 err = ofnode_parse_phandle_with_args(node, "diag", NULL, 0, 0,
942 &phandle);
943 if (!err) {
944 sfp->i2c_diag_addr = ofnode_get_addr(phandle.node);
945 if (!sfp->i2c_bus)
946 sfp->i2c_bus = cvmx_ofnode_get_i2c_bus(ofnode_get_parent(phandle.node));
947 }
948
949 sfp->last_mod_abs = -2;
950 sfp->last_rx_los = -2;
951
952 if (!sfp->i2c_bus) {
953 cvmx_printf("%s(%s): Error: could not get i2c bus from device tree\n",
954 __func__, sfp->name);
955 err = -1;
956 }
957
958 if (err) {
959 dm_gpio_free(sfp->lp_mode.dev, &sfp->lp_mode);
960 dm_gpio_free(sfp->mod_abs.dev, &sfp->mod_abs);
961 dm_gpio_free(sfp->select.dev, &sfp->select);
962 dm_gpio_free(sfp->reset.dev, &sfp->reset);
963 dm_gpio_free(sfp->interrupt.dev, &sfp->interrupt);
964 } else {
965 sfp->valid = true;
966 }
967
968 return err;
969}
970
971
972
973
974
975
976
977
978int cvmx_sfp_parse_device_tree(const void *fdt_addr)
979{
980 struct cvmx_fdt_sfp_info *sfp, *first_sfp = NULL, *last_sfp = NULL;
981 ofnode node;
982 int err = 0;
983 int reg;
984 static bool parsed;
985
986 debug("%s(%p): Parsing...\n", __func__, fdt_addr);
987 if (parsed) {
988 debug("%s(%p): Already parsed\n", __func__, fdt_addr);
989 return 0;
990 }
991
992 ofnode_for_each_compatible_node(node, "ethernet,sfp-slot") {
993 if (!ofnode_valid(node))
994 continue;
995
996 sfp = cvm_sfp_alloc(sizeof(*sfp));
997 if (!sfp)
998 return -1;
999
1000 err = cvmx_sfp_parse_sfp(sfp, node);
1001 if (!err) {
1002 if (!sfp_list)
1003 sfp_list = sfp;
1004 if (last_sfp)
1005 last_sfp->next = sfp;
1006 sfp->prev = last_sfp;
1007 last_sfp = sfp;
1008 debug("%s: parsed %s\n", __func__, sfp->name);
1009 } else {
1010 debug("%s: Error parsing SFP at node %s\n",
1011 __func__, ofnode_get_name(node));
1012 return err;
1013 }
1014 }
1015
1016 ofnode_for_each_compatible_node(node, "ethernet,qsfp-slot") {
1017 if (!ofnode_valid(node))
1018 continue;
1019
1020 sfp = cvm_sfp_alloc(sizeof(*sfp));
1021 if (!sfp)
1022 return -1;
1023
1024 err = cvmx_sfp_parse_qsfp(sfp, node);
1025 if (!err) {
1026 if (!sfp_list)
1027 sfp_list = sfp;
1028 if (last_sfp)
1029 last_sfp->next = sfp;
1030 sfp->prev = last_sfp;
1031 last_sfp = sfp;
1032 debug("%s: parsed %s\n", __func__, sfp->name);
1033 } else {
1034 debug("%s: Error parsing QSFP at node %s\n",
1035 __func__, ofnode_get_name(node));
1036 return err;
1037 }
1038 }
1039
1040 if (!octeon_has_feature(OCTEON_FEATURE_BGX))
1041 return 0;
1042
1043 err = 0;
1044 ofnode_for_each_compatible_node(node, "cavium,octeon-7890-bgx-port") {
1045 int sfp_nodes[4];
1046 ofnode sfp_ofnodes[4];
1047 int num_sfp_nodes;
1048 u64 reg_addr;
1049 struct cvmx_xiface xi;
1050 int xiface, index;
1051 cvmx_helper_interface_mode_t mode;
1052 int i;
1053 int rc;
1054
1055 if (!ofnode_valid(node))
1056 break;
1057
1058 num_sfp_nodes = ARRAY_SIZE(sfp_nodes);
1059 rc = cvmx_ofnode_lookup_phandles(node, "sfp-slot",
1060 &num_sfp_nodes, sfp_ofnodes);
1061 if (rc != 0 || num_sfp_nodes < 1)
1062 rc = cvmx_ofnode_lookup_phandles(node, "qsfp-slot",
1063 &num_sfp_nodes,
1064 sfp_ofnodes);
1065
1066 if (rc < 0)
1067 continue;
1068
1069 last_sfp = NULL;
1070 for (i = 0; i < num_sfp_nodes; i++) {
1071 sfp = cvmx_sfp_find_slot_by_fdt_node(ofnode_to_offset(sfp_ofnodes[i]));
1072 debug("%s: Adding sfp %s (%p) to BGX port\n",
1073 __func__, sfp->name, sfp);
1074 if (last_sfp)
1075 last_sfp->next_iface_sfp = sfp;
1076 else
1077 first_sfp = sfp;
1078 last_sfp = sfp;
1079 }
1080 if (!first_sfp) {
1081 debug("%s: Error: could not find SFP slot for BGX port %s\n",
1082 __func__,
1083 fdt_get_name(fdt_addr, sfp_nodes[0],
1084 NULL));
1085 err = -1;
1086 break;
1087 }
1088
1089
1090 reg = ofnode_get_addr(node);
1091 if (reg < 0) {
1092 debug("%s: Error: could not get BGX port reg value\n",
1093 __func__);
1094 err = -1;
1095 break;
1096 }
1097 index = reg;
1098
1099
1100 reg_addr = ofnode_get_addr(ofnode_get_parent(node));
1101
1102 xi.node = cvmx_csr_addr_to_node(reg_addr);
1103
1104 reg_addr = cvmx_csr_addr_strip_node(reg_addr);
1105 if ((reg_addr & 0xFFFFFFFFF0000000) !=
1106 0x00011800E0000000) {
1107 debug("%s: Invalid BGX address 0x%llx\n",
1108 __func__, (unsigned long long)reg_addr);
1109 xi.node = -1;
1110 err = -1;
1111 break;
1112 }
1113
1114
1115 xi.interface = (reg_addr >> 24) & 0x0F;
1116
1117 xiface = cvmx_helper_node_interface_to_xiface(xi.node,
1118 xi.interface);
1119 debug("%s: Parsed %d SFP slots for interface 0x%x, index %d\n",
1120 __func__, num_sfp_nodes, xiface, index);
1121
1122 mode = cvmx_helper_interface_get_mode(xiface);
1123 for (sfp = first_sfp; sfp; sfp = sfp->next_iface_sfp) {
1124 sfp->xiface = xiface;
1125 sfp->index = index;
1126
1127 sfp->ipd_port[0] =
1128 cvmx_helper_get_ipd_port(xiface, index);
1129 debug("%s: sfp %s (%p) xi: 0x%x, index: 0x%x, node: %d, mode: 0x%x, next: %p\n",
1130 __func__, sfp->name, sfp, sfp->xiface,
1131 sfp->index, xi.node, mode,
1132 sfp->next_iface_sfp);
1133 if (mode == CVMX_HELPER_INTERFACE_MODE_XLAUI ||
1134 mode == CVMX_HELPER_INTERFACE_MODE_40G_KR4)
1135 for (i = 1; i < 4; i++)
1136 sfp->ipd_port[i] = -1;
1137 else
1138 for (i = 1; i < 4; i++)
1139 sfp->ipd_port[i] =
1140 cvmx_helper_get_ipd_port(
1141 xiface, i);
1142 }
1143 cvmx_helper_cfg_set_sfp_info(xiface, index, first_sfp);
1144 }
1145
1146 if (!err) {
1147 parsed = true;
1148 cvmx_sfp_read_all_modules();
1149 }
1150
1151 return err;
1152}
1153
1154
1155
1156
1157
1158
1159
1160
1161struct cvmx_fdt_sfp_info *cvmx_sfp_find_slot_by_fdt_node(int of_offset)
1162{
1163 struct cvmx_fdt_sfp_info *sfp = sfp_list;
1164
1165 while (sfp) {
1166 if (sfp->of_offset == of_offset)
1167 return sfp;
1168 sfp = sfp->next;
1169 }
1170 return NULL;
1171}
1172
1173static bool cvmx_sfp_validate_quad(struct cvmx_fdt_sfp_info *sfp,
1174 struct cvmx_phy_gpio_leds *leds)
1175{
1176 bool multi_led = leds && (leds->next);
1177 bool error = false;
1178 int mod_abs;
1179
1180 do {
1181
1182 if (dm_gpio_is_valid(&sfp->mod_abs))
1183 mod_abs = dm_gpio_get_value(&sfp->mod_abs);
1184 else
1185 mod_abs = 0;
1186 if (!mod_abs) {
1187 if (cvmx_sfp_read_i2c_eeprom(sfp)) {
1188 debug("%s: Error reading eeprom for %s\n",
1189 __func__, sfp->name);
1190 }
1191 if (sfp->sfp_info.rate < CVMX_SFP_RATE_10G) {
1192 cvmx_helper_leds_show_error(leds, true);
1193 error = true;
1194 } else if (sfp->sfp_info.rate >= CVMX_SFP_RATE_10G) {
1195
1196
1197
1198 switch (sfp->sfp_info.cable_comp) {
1199 case CVMX_SFP_CABLE_10GBASE_T:
1200 case CVMX_SFP_CABLE_10GBASE_T_SR:
1201 case CVMX_SFP_CABLE_5GBASE_T:
1202 case CVMX_SFP_CABLE_2_5GBASE_T:
1203 cvmx_helper_leds_show_error(leds, true);
1204 error = true;
1205 break;
1206 default:
1207 break;
1208 }
1209 }
1210 } else if (multi_led) {
1211 cvmx_helper_leds_show_error(leds, false);
1212 }
1213
1214 if (multi_led && leds->next)
1215 leds = leds->next;
1216 sfp = sfp->next_iface_sfp;
1217 } while (sfp);
1218
1219 if (!multi_led)
1220 cvmx_helper_leds_show_error(leds, error);
1221
1222 return error;
1223}
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237bool cvmx_sfp_validate_module(struct cvmx_fdt_sfp_info *sfp, int mode)
1238{
1239 const struct cvmx_sfp_mod_info *mod_info = &sfp->sfp_info;
1240 int xiface = sfp->xiface;
1241 int index = sfp->index;
1242 struct cvmx_phy_gpio_leds *leds;
1243 bool error = false;
1244 bool quad_mode = false;
1245
1246 debug("%s(%s, 0x%x, 0x%x, 0x%x)\n", __func__, sfp->name, xiface, index,
1247 mode);
1248 if (!sfp) {
1249 debug("%s: Error: sfp is NULL\n", __func__);
1250 return false;
1251 }
1252
1253 leds = cvmx_helper_get_port_phy_leds(xiface, index);
1254 if (!leds)
1255 debug("%s: No leds for 0x%x:0x%x\n", __func__, xiface, index);
1256
1257 if (mode != CVMX_HELPER_INTERFACE_MODE_XLAUI &&
1258 mode != CVMX_HELPER_INTERFACE_MODE_40G_KR4 && !sfp->is_qsfp &&
1259 sfp->last_mod_abs && leds) {
1260 cvmx_helper_leds_show_error(leds, false);
1261 debug("%s: %s: last_mod_abs: %d, no error\n", __func__,
1262 sfp->name, sfp->last_mod_abs);
1263 return true;
1264 }
1265
1266 switch (mode) {
1267 case CVMX_HELPER_INTERFACE_MODE_RGMII:
1268 case CVMX_HELPER_INTERFACE_MODE_GMII:
1269 case CVMX_HELPER_INTERFACE_MODE_SGMII:
1270 case CVMX_HELPER_INTERFACE_MODE_QSGMII:
1271 case CVMX_HELPER_INTERFACE_MODE_AGL:
1272 case CVMX_HELPER_INTERFACE_MODE_SPI:
1273 if ((mod_info->active_cable &&
1274 mod_info->rate != CVMX_SFP_RATE_1G) ||
1275 mod_info->rate < CVMX_SFP_RATE_1G)
1276 error = true;
1277 break;
1278 case CVMX_HELPER_INTERFACE_MODE_RXAUI:
1279 case CVMX_HELPER_INTERFACE_MODE_XAUI:
1280 case CVMX_HELPER_INTERFACE_MODE_10G_KR:
1281 case CVMX_HELPER_INTERFACE_MODE_XFI:
1282 if ((mod_info->active_cable &&
1283 mod_info->rate != CVMX_SFP_RATE_10G) ||
1284 mod_info->rate < CVMX_SFP_RATE_10G)
1285 error = true;
1286 break;
1287 case CVMX_HELPER_INTERFACE_MODE_XLAUI:
1288 case CVMX_HELPER_INTERFACE_MODE_40G_KR4:
1289 if (!sfp->is_qsfp) {
1290 quad_mode = true;
1291 error = cvmx_sfp_validate_quad(sfp, leds);
1292 } else {
1293 if ((mod_info->active_cable &&
1294 mod_info->rate != CVMX_SFP_RATE_40G) ||
1295 mod_info->rate < CVMX_SFP_RATE_25G)
1296 error = true;
1297 }
1298 break;
1299 default:
1300 debug("%s: Unsupported interface mode %d on xiface 0x%x\n",
1301 __func__, mode, xiface);
1302 return false;
1303 }
1304 debug("%s: %s: error: %d\n", __func__, sfp->name, error);
1305 if (leds && !quad_mode)
1306 cvmx_helper_leds_show_error(leds, error);
1307
1308 return !error;
1309}
1310