1 /**
2 * Description:
3 *
4 * This module adds CMIS support to ethtool. The changes are similar to
5 * the ones already existing in qsfp.c, but customized to use the memory
6 * addresses and logic as defined in the specification's document.
7 *
8 */
9
10 #include <stdio.h>
11 #include <math.h>
12 #include <errno.h>
13 #include "internal.h"
14 #include "sff-common.h"
15 #include "cmis.h"
16 #include "netlink/extapi.h"
17
18 /* The maximum number of supported Banks. Relevant documents:
19 * [1] CMIS Rev. 5, page. 128, section 8.4.4, Table 8-40
20 */
21 #define CMIS_MAX_BANKS 4
22 #define CMIS_CHANNELS_PER_BANK 8
23 #define CMIS_MAX_CHANNEL_NUM (CMIS_MAX_BANKS * CMIS_CHANNELS_PER_BANK)
24
25 /* We are not parsing further than Page 11h. */
26 #define CMIS_MAX_PAGES 18
27
28 struct cmis_memory_map {
29 const __u8 *lower_memory;
30 const __u8 *upper_memory[CMIS_MAX_BANKS][CMIS_MAX_PAGES];
31 #define page_00h upper_memory[0x0][0x0]
32 #define page_01h upper_memory[0x0][0x1]
33 #define page_02h upper_memory[0x0][0x2]
34 };
35
36 #define CMIS_PAGE_SIZE 0x80
37 #define CMIS_I2C_ADDRESS 0x50
38
39 static struct {
40 const char *str;
41 int offset;
42 __u8 value; /* Alarm is on if (offset & value) != 0. */
43 } cmis_aw_mod_flags[] = {
44 { "Module temperature high alarm",
45 CMIS_TEMP_AW_OFFSET, CMIS_TEMP_HALARM_STATUS },
46 { "Module temperature low alarm",
47 CMIS_TEMP_AW_OFFSET, CMIS_TEMP_LALARM_STATUS },
48 { "Module temperature high warning",
49 CMIS_TEMP_AW_OFFSET, CMIS_TEMP_HWARN_STATUS },
50 { "Module temperature low warning",
51 CMIS_TEMP_AW_OFFSET, CMIS_TEMP_LWARN_STATUS },
52
53 { "Module voltage high alarm",
54 CMIS_VCC_AW_OFFSET, CMIS_VCC_HALARM_STATUS },
55 { "Module voltage low alarm",
56 CMIS_VCC_AW_OFFSET, CMIS_VCC_LALARM_STATUS },
57 { "Module voltage high warning",
58 CMIS_VCC_AW_OFFSET, CMIS_VCC_HWARN_STATUS },
59 { "Module voltage low warning",
60 CMIS_VCC_AW_OFFSET, CMIS_VCC_LWARN_STATUS },
61
62 { NULL, 0, 0 },
63 };
64
65 static struct {
66 const char *fmt_str;
67 int offset;
68 int adver_offset; /* In Page 01h. */
69 __u8 adver_value; /* Supported if (offset & value) != 0. */
70 } cmis_aw_chan_flags[] = {
71 { "Laser bias current high alarm (Chan %d)",
72 CMIS_TX_BIAS_AW_HALARM_OFFSET,
73 CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_BIAS_MON_MASK },
74 { "Laser bias current low alarm (Chan %d)",
75 CMIS_TX_BIAS_AW_LALARM_OFFSET,
76 CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_BIAS_MON_MASK },
77 { "Laser bias current high warning (Chan %d)",
78 CMIS_TX_BIAS_AW_HWARN_OFFSET,
79 CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_BIAS_MON_MASK },
80 { "Laser bias current low warning (Chan %d)",
81 CMIS_TX_BIAS_AW_LWARN_OFFSET,
82 CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_BIAS_MON_MASK },
83
84 { "Laser tx power high alarm (Channel %d)",
85 CMIS_TX_PWR_AW_HALARM_OFFSET,
86 CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_PWR_MON_MASK },
87 { "Laser tx power low alarm (Channel %d)",
88 CMIS_TX_PWR_AW_LALARM_OFFSET,
89 CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_PWR_MON_MASK },
90 { "Laser tx power high warning (Channel %d)",
91 CMIS_TX_PWR_AW_HWARN_OFFSET,
92 CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_PWR_MON_MASK },
93 { "Laser tx power low warning (Channel %d)",
94 CMIS_TX_PWR_AW_LWARN_OFFSET,
95 CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_TX_PWR_MON_MASK },
96
97 { "Laser rx power high alarm (Channel %d)",
98 CMIS_RX_PWR_AW_HALARM_OFFSET,
99 CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_RX_PWR_MON_MASK },
100 { "Laser rx power low alarm (Channel %d)",
101 CMIS_RX_PWR_AW_LALARM_OFFSET,
102 CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_RX_PWR_MON_MASK },
103 { "Laser rx power high warning (Channel %d)",
104 CMIS_RX_PWR_AW_HWARN_OFFSET,
105 CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_RX_PWR_MON_MASK },
106 { "Laser rx power low warning (Channel %d)",
107 CMIS_RX_PWR_AW_LWARN_OFFSET,
108 CMIS_DIAG_CHAN_ADVER_OFFSET, CMIS_RX_PWR_MON_MASK },
109
110 { NULL, 0, 0, 0 },
111 };
112
cmis_show_identifier(const struct cmis_memory_map * map)113 static void cmis_show_identifier(const struct cmis_memory_map *map)
114 {
115 sff8024_show_identifier(map->lower_memory, CMIS_ID_OFFSET);
116 }
117
cmis_show_connector(const struct cmis_memory_map * map)118 static void cmis_show_connector(const struct cmis_memory_map *map)
119 {
120 sff8024_show_connector(map->page_00h, CMIS_CTOR_OFFSET);
121 }
122
cmis_show_oui(const struct cmis_memory_map * map)123 static void cmis_show_oui(const struct cmis_memory_map *map)
124 {
125 sff8024_show_oui(map->page_00h, CMIS_VENDOR_OUI_OFFSET);
126 }
127
128 /**
129 * Print the revision compliance. Relevant documents:
130 * [1] CMIS Rev. 3, pag. 45, section 1.7.2.1, Table 18
131 * [2] CMIS Rev. 4, pag. 81, section 8.2.1, Table 8-2
132 */
cmis_show_rev_compliance(const struct cmis_memory_map * map)133 static void cmis_show_rev_compliance(const struct cmis_memory_map *map)
134 {
135 __u8 rev = map->lower_memory[CMIS_REV_COMPLIANCE_OFFSET];
136 int major = (rev >> 4) & 0x0F;
137 int minor = rev & 0x0F;
138
139 printf("\t%-41s : Rev. %d.%d\n", "Revision compliance", major, minor);
140 }
141
142 static void
cmis_show_signals_one(const struct cmis_memory_map * map,const char * name,int off,int ioff,unsigned int imask)143 cmis_show_signals_one(const struct cmis_memory_map *map, const char *name,
144 int off, int ioff, unsigned int imask)
145 {
146 unsigned int v;
147 int i;
148
149 if (!map->page_01h)
150 return;
151
152 v = 0;
153 for (i = 0; i < CMIS_MAX_BANKS && map->upper_memory[i][0x11]; i++)
154 v |= map->upper_memory[i][0x11][off] << (i * 8);
155
156 if (map->page_01h[ioff] & imask)
157 sff_show_lane_status(name, i * 8, "Yes", "No", v);
158 }
159
cmis_show_signals(const struct cmis_memory_map * map)160 static void cmis_show_signals(const struct cmis_memory_map *map)
161 {
162 cmis_show_signals_one(map, "Rx loss of signal", CMIS_RX_LOS_OFFSET,
163 CMIS_DIAG_FLAGS_RX_OFFSET, CMIS_DIAG_FL_RX_LOS);
164 cmis_show_signals_one(map, "Tx loss of signal", CMIS_TX_LOS_OFFSET,
165 CMIS_DIAG_FLAGS_TX_OFFSET, CMIS_DIAG_FL_TX_LOS);
166
167 cmis_show_signals_one(map, "Rx loss of lock", CMIS_RX_LOL_OFFSET,
168 CMIS_DIAG_FLAGS_RX_OFFSET, CMIS_DIAG_FL_RX_LOL);
169 cmis_show_signals_one(map, "Tx loss of lock", CMIS_TX_LOL_OFFSET,
170 CMIS_DIAG_FLAGS_TX_OFFSET, CMIS_DIAG_FL_TX_LOL);
171
172 cmis_show_signals_one(map, "Tx fault", CMIS_TX_FAIL_OFFSET,
173 CMIS_DIAG_FLAGS_TX_OFFSET, CMIS_DIAG_FL_TX_FAIL);
174
175 cmis_show_signals_one(map, "Tx adaptive eq fault",
176 CMIS_TX_EQ_FAIL_OFFSET, CMIS_DIAG_FLAGS_TX_OFFSET,
177 CMIS_DIAG_FL_TX_ADAPTIVE_EQ_FAIL);
178 }
179
180 /**
181 * Print information about the device's power consumption.
182 * Relevant documents:
183 * [1] CMIS Rev. 3, pag. 59, section 1.7.3.9, Table 30
184 * [2] CMIS Rev. 4, pag. 94, section 8.3.9, Table 8-18
185 * [3] QSFP-DD Hardware Rev 5.0, pag. 22, section 4.2.1
186 */
cmis_show_power_info(const struct cmis_memory_map * map)187 static void cmis_show_power_info(const struct cmis_memory_map *map)
188 {
189 float max_power = 0.0f;
190 __u8 base_power = 0;
191 __u8 power_class;
192
193 /* Get the power class (first 3 most significat bytes) */
194 power_class = (map->page_00h[CMIS_PWR_CLASS_OFFSET] >> 5) & 0x07;
195
196 /* Get the base power in multiples of 0.25W */
197 base_power = map->page_00h[CMIS_PWR_MAX_POWER_OFFSET];
198 max_power = base_power * 0.25f;
199
200 printf("\t%-41s : %d\n", "Power class", power_class + 1);
201 printf("\t%-41s : %.02fW\n", "Max power", max_power);
202 }
203
204 /**
205 * Print the cable assembly length, for both passive copper and active
206 * optical or electrical cables. The base length (bits 5-0) must be
207 * multiplied with the SMF length multiplier (bits 7-6) to obtain the
208 * correct value. Relevant documents:
209 * [1] CMIS Rev. 3, pag. 59, section 1.7.3.10, Table 31
210 * [2] CMIS Rev. 4, pag. 94, section 8.3.10, Table 8-19
211 */
cmis_show_cbl_asm_len(const struct cmis_memory_map * map)212 static void cmis_show_cbl_asm_len(const struct cmis_memory_map *map)
213 {
214 static const char *fn = "Cable assembly length";
215 float mul = 1.0f;
216 float val = 0.0f;
217
218 /* Check if max length */
219 if (map->page_00h[CMIS_CBL_ASM_LEN_OFFSET] == CMIS_6300M_MAX_LEN) {
220 printf("\t%-41s : > 6.3km\n", fn);
221 return;
222 }
223
224 /* Get the multiplier from the first two bits */
225 switch (map->page_00h[CMIS_CBL_ASM_LEN_OFFSET] & CMIS_LEN_MUL_MASK) {
226 case CMIS_MULTIPLIER_00:
227 mul = 0.1f;
228 break;
229 case CMIS_MULTIPLIER_01:
230 mul = 1.0f;
231 break;
232 case CMIS_MULTIPLIER_10:
233 mul = 10.0f;
234 break;
235 case CMIS_MULTIPLIER_11:
236 mul = 100.0f;
237 break;
238 default:
239 break;
240 }
241
242 /* Get base value from first 6 bits and multiply by mul */
243 val = (map->page_00h[CMIS_CBL_ASM_LEN_OFFSET] & CMIS_LEN_VAL_MASK);
244 val = (float)val * mul;
245 printf("\t%-41s : %0.2fm\n", fn, val);
246 }
247
248 /**
249 * Print the length for SMF fiber. The base length (bits 5-0) must be
250 * multiplied with the SMF length multiplier (bits 7-6) to obtain the
251 * correct value. Relevant documents:
252 * [1] CMIS Rev. 3, pag. 63, section 1.7.4.2, Table 39
253 * [2] CMIS Rev. 4, pag. 99, section 8.4.2, Table 8-27
254 */
cmis_print_smf_cbl_len(const struct cmis_memory_map * map)255 static void cmis_print_smf_cbl_len(const struct cmis_memory_map *map)
256 {
257 static const char *fn = "Length (SMF)";
258 float mul = 1.0f;
259 float val = 0.0f;
260
261 if (!map->page_01h)
262 return;
263
264 /* Get the multiplier from the first two bits */
265 switch (map->page_01h[CMIS_SMF_LEN_OFFSET] & CMIS_LEN_MUL_MASK) {
266 case CMIS_MULTIPLIER_00:
267 mul = 0.1f;
268 break;
269 case CMIS_MULTIPLIER_01:
270 mul = 1.0f;
271 break;
272 default:
273 break;
274 }
275
276 /* Get base value from first 6 bits and multiply by mul */
277 val = (map->page_01h[CMIS_SMF_LEN_OFFSET] & CMIS_LEN_VAL_MASK);
278 val = (float)val * mul;
279 printf("\t%-41s : %0.2fkm\n", fn, val);
280 }
281
282 /**
283 * Print relevant signal integrity control properties. Relevant documents:
284 * [1] CMIS Rev. 3, pag. 71, section 1.7.4.10, Table 46
285 * [2] CMIS Rev. 4, pag. 105, section 8.4.10, Table 8-34
286 */
cmis_show_sig_integrity(const struct cmis_memory_map * map)287 static void cmis_show_sig_integrity(const struct cmis_memory_map *map)
288 {
289 if (!map->page_01h)
290 return;
291
292 /* CDR Bypass control: 2nd bit from each byte */
293 printf("\t%-41s : ", "Tx CDR bypass control");
294 printf("%s\n", YESNO(map->page_01h[CMIS_SIG_INTEG_TX_OFFSET] & 0x02));
295
296 printf("\t%-41s : ", "Rx CDR bypass control");
297 printf("%s\n", YESNO(map->page_01h[CMIS_SIG_INTEG_RX_OFFSET] & 0x02));
298
299 /* CDR Implementation: 1st bit from each byte */
300 printf("\t%-41s : ", "Tx CDR");
301 printf("%s\n", YESNO(map->page_01h[CMIS_SIG_INTEG_TX_OFFSET] & 0x01));
302
303 printf("\t%-41s : ", "Rx CDR");
304 printf("%s\n", YESNO(map->page_01h[CMIS_SIG_INTEG_RX_OFFSET] & 0x01));
305 }
306
307 /**
308 * Print relevant media interface technology info. Relevant documents:
309 * [1] CMIS Rev. 3
310 * --> pag. 61, section 1.7.3.14, Table 36
311 * --> pag. 64, section 1.7.4.3, 1.7.4.4
312 * [2] CMIS Rev. 4
313 * --> pag. 97, section 8.3.14, Table 8-24
314 * --> pag. 98, section 8.4, Table 8-25
315 * --> page 100, section 8.4.3, 8.4.4
316 */
cmis_show_mit_compliance(const struct cmis_memory_map * map)317 static void cmis_show_mit_compliance(const struct cmis_memory_map *map)
318 {
319 static const char *cc = " (Copper cable,";
320
321 printf("\t%-41s : 0x%02x", "Transmitter technology",
322 map->page_00h[CMIS_MEDIA_INTF_TECH_OFFSET]);
323
324 switch (map->page_00h[CMIS_MEDIA_INTF_TECH_OFFSET]) {
325 case CMIS_850_VCSEL:
326 printf(" (850 nm VCSEL)\n");
327 break;
328 case CMIS_1310_VCSEL:
329 printf(" (1310 nm VCSEL)\n");
330 break;
331 case CMIS_1550_VCSEL:
332 printf(" (1550 nm VCSEL)\n");
333 break;
334 case CMIS_1310_FP:
335 printf(" (1310 nm FP)\n");
336 break;
337 case CMIS_1310_DFB:
338 printf(" (1310 nm DFB)\n");
339 break;
340 case CMIS_1550_DFB:
341 printf(" (1550 nm DFB)\n");
342 break;
343 case CMIS_1310_EML:
344 printf(" (1310 nm EML)\n");
345 break;
346 case CMIS_1550_EML:
347 printf(" (1550 nm EML)\n");
348 break;
349 case CMIS_OTHERS:
350 printf(" (Others/Undefined)\n");
351 break;
352 case CMIS_1490_DFB:
353 printf(" (1490 nm DFB)\n");
354 break;
355 case CMIS_COPPER_UNEQUAL:
356 printf("%s unequalized)\n", cc);
357 break;
358 case CMIS_COPPER_PASS_EQUAL:
359 printf("%s passive equalized)\n", cc);
360 break;
361 case CMIS_COPPER_NF_EQUAL:
362 printf("%s near and far end limiting active equalizers)\n", cc);
363 break;
364 case CMIS_COPPER_F_EQUAL:
365 printf("%s far end limiting active equalizers)\n", cc);
366 break;
367 case CMIS_COPPER_N_EQUAL:
368 printf("%s near end limiting active equalizers)\n", cc);
369 break;
370 case CMIS_COPPER_LINEAR_EQUAL:
371 printf("%s linear active equalizers)\n", cc);
372 break;
373 }
374
375 if (map->page_00h[CMIS_MEDIA_INTF_TECH_OFFSET] >= CMIS_COPPER_UNEQUAL) {
376 printf("\t%-41s : %udb\n", "Attenuation at 5GHz",
377 map->page_00h[CMIS_COPPER_ATT_5GHZ]);
378 printf("\t%-41s : %udb\n", "Attenuation at 7GHz",
379 map->page_00h[CMIS_COPPER_ATT_7GHZ]);
380 printf("\t%-41s : %udb\n", "Attenuation at 12.9GHz",
381 map->page_00h[CMIS_COPPER_ATT_12P9GHZ]);
382 printf("\t%-41s : %udb\n", "Attenuation at 25.8GHz",
383 map->page_00h[CMIS_COPPER_ATT_25P8GHZ]);
384 } else if (map->page_01h) {
385 printf("\t%-41s : %.3lfnm\n", "Laser wavelength",
386 (((map->page_01h[CMIS_NOM_WAVELENGTH_MSB] << 8) |
387 map->page_01h[CMIS_NOM_WAVELENGTH_LSB]) * 0.05));
388 printf("\t%-41s : %.3lfnm\n", "Laser wavelength tolerance",
389 (((map->page_01h[CMIS_WAVELENGTH_TOL_MSB] << 8) |
390 map->page_01h[CMIS_WAVELENGTH_TOL_LSB]) * 0.005));
391 }
392 }
393
394 /**
395 * Print relevant info about the maximum supported fiber media length
396 * for each type of fiber media at the maximum module-supported bit rate.
397 * Relevant documents:
398 * [1] CMIS Rev. 3, page 64, section 1.7.4.2, Table 39
399 * [2] CMIS Rev. 4, page 99, section 8.4.2, Table 8-27
400 */
cmis_show_link_len(const struct cmis_memory_map * map)401 static void cmis_show_link_len(const struct cmis_memory_map *map)
402 {
403 cmis_print_smf_cbl_len(map);
404 if (!map->page_01h)
405 return;
406 sff_show_value_with_unit(map->page_01h, CMIS_OM5_LEN_OFFSET,
407 "Length (OM5)", 2, "m");
408 sff_show_value_with_unit(map->page_01h, CMIS_OM4_LEN_OFFSET,
409 "Length (OM4)", 2, "m");
410 sff_show_value_with_unit(map->page_01h, CMIS_OM3_LEN_OFFSET,
411 "Length (OM3 50/125um)", 2, "m");
412 sff_show_value_with_unit(map->page_01h, CMIS_OM2_LEN_OFFSET,
413 "Length (OM2 50/125um)", 1, "m");
414 }
415
416 /**
417 * Show relevant information about the vendor. Relevant documents:
418 * [1] CMIS Rev. 3, page 56, section 1.7.3, Table 27
419 * [2] CMIS Rev. 4, page 91, section 8.2, Table 8-15
420 */
cmis_show_vendor_info(const struct cmis_memory_map * map)421 static void cmis_show_vendor_info(const struct cmis_memory_map *map)
422 {
423 const char *clei;
424
425 sff_show_ascii(map->page_00h, CMIS_VENDOR_NAME_START_OFFSET,
426 CMIS_VENDOR_NAME_END_OFFSET, "Vendor name");
427 cmis_show_oui(map);
428 sff_show_ascii(map->page_00h, CMIS_VENDOR_PN_START_OFFSET,
429 CMIS_VENDOR_PN_END_OFFSET, "Vendor PN");
430 sff_show_ascii(map->page_00h, CMIS_VENDOR_REV_START_OFFSET,
431 CMIS_VENDOR_REV_END_OFFSET, "Vendor rev");
432 sff_show_ascii(map->page_00h, CMIS_VENDOR_SN_START_OFFSET,
433 CMIS_VENDOR_SN_END_OFFSET, "Vendor SN");
434 sff_show_ascii(map->page_00h, CMIS_DATE_YEAR_OFFSET,
435 CMIS_DATE_VENDOR_LOT_OFFSET + 1, "Date code");
436
437 clei = (const char *)(map->page_00h + CMIS_CLEI_START_OFFSET);
438 if (*clei && strncmp(clei, CMIS_CLEI_BLANK, CMIS_CLEI_LEN))
439 sff_show_ascii(map->page_00h, CMIS_CLEI_START_OFFSET,
440 CMIS_CLEI_END_OFFSET, "CLEI code");
441 }
442
443 /* Print the current Module State. Relevant documents:
444 * [1] CMIS Rev. 5, pag. 57, section 6.3.2.2, Figure 6-3
445 * [2] CMIS Rev. 5, pag. 60, section 6.3.2.3, Figure 6-4
446 * [3] CMIS Rev. 5, pag. 107, section 8.2.2, Table 8-6
447 */
cmis_show_mod_state(const struct cmis_memory_map * map)448 static void cmis_show_mod_state(const struct cmis_memory_map *map)
449 {
450 __u8 mod_state;
451
452 mod_state = (map->lower_memory[CMIS_MODULE_STATE_OFFSET] &
453 CMIS_MODULE_STATE_MASK) >> 1;
454 printf("\t%-41s : 0x%02x", "Module State", mod_state);
455 switch (mod_state) {
456 case CMIS_MODULE_STATE_MODULE_LOW_PWR:
457 printf(" (ModuleLowPwr)\n");
458 break;
459 case CMIS_MODULE_STATE_MODULE_PWR_UP:
460 printf(" (ModulePwrUp)\n");
461 break;
462 case CMIS_MODULE_STATE_MODULE_READY:
463 printf(" (ModuleReady)\n");
464 break;
465 case CMIS_MODULE_STATE_MODULE_PWR_DN:
466 printf(" (ModulePwrDn)\n");
467 break;
468 case CMIS_MODULE_STATE_MODULE_FAULT:
469 printf(" (ModuleFault)\n");
470 break;
471 default:
472 printf(" (reserved or unknown)\n");
473 break;
474 }
475 }
476
477 /* Print the Module Fault Information. Relevant documents:
478 * [1] CMIS Rev. 5, pag. 64, section 6.3.2.12
479 * [2] CMIS Rev. 5, pag. 115, section 8.2.10, Table 8-15
480 */
cmis_show_mod_fault_cause(const struct cmis_memory_map * map)481 static void cmis_show_mod_fault_cause(const struct cmis_memory_map *map)
482 {
483 __u8 mod_state, fault_cause;
484
485 mod_state = (map->lower_memory[CMIS_MODULE_STATE_OFFSET] &
486 CMIS_MODULE_STATE_MASK) >> 1;
487 if (mod_state != CMIS_MODULE_STATE_MODULE_FAULT)
488 return;
489
490 fault_cause = map->lower_memory[CMIS_MODULE_FAULT_OFFSET];
491 printf("\t%-41s : 0x%02x", "Module Fault Cause", fault_cause);
492 switch (fault_cause) {
493 case CMIS_MODULE_FAULT_NO_FAULT:
494 printf(" (No fault detected / not supported)\n");
495 break;
496 case CMIS_MODULE_FAULT_TEC_RUNAWAY:
497 printf(" (TEC runaway)\n");
498 break;
499 case CMIS_MODULE_FAULT_DATA_MEM_CORRUPTED:
500 printf(" (Data memory corrupted)\n");
501 break;
502 case CMIS_MODULE_FAULT_PROG_MEM_CORRUPTED:
503 printf(" (Program memory corrupted)\n");
504 break;
505 default:
506 printf(" (reserved or unknown)\n");
507 break;
508 }
509 }
510
511 /* Print the current Module-Level Controls. Relevant documents:
512 * [1] CMIS Rev. 5, pag. 58, section 6.3.2.2, Table 6-12
513 * [2] CMIS Rev. 5, pag. 111, section 8.2.6, Table 8-10
514 */
cmis_show_mod_lvl_controls(const struct cmis_memory_map * map)515 static void cmis_show_mod_lvl_controls(const struct cmis_memory_map *map)
516 {
517 printf("\t%-41s : ", "LowPwrAllowRequestHW");
518 printf("%s\n", ONOFF(map->lower_memory[CMIS_MODULE_CONTROL_OFFSET] &
519 CMIS_LOW_PWR_ALLOW_REQUEST_HW_MASK));
520 printf("\t%-41s : ", "LowPwrRequestSW");
521 printf("%s\n", ONOFF(map->lower_memory[CMIS_MODULE_CONTROL_OFFSET] &
522 CMIS_LOW_PWR_REQUEST_SW_MASK));
523 }
524
cmis_parse_dom_power_type(const struct cmis_memory_map * map,struct sff_diags * sd)525 static void cmis_parse_dom_power_type(const struct cmis_memory_map *map,
526 struct sff_diags *sd)
527 {
528 sd->rx_power_type = map->page_01h[CMIS_DIAG_TYPE_OFFSET] &
529 CMIS_RX_PWR_TYPE_MASK;
530 sd->tx_power_type = map->page_01h[CMIS_DIAG_CHAN_ADVER_OFFSET] &
531 CMIS_TX_PWR_MON_MASK;
532 }
533
cmis_parse_dom_mod_lvl_monitors(const struct cmis_memory_map * map,struct sff_diags * sd)534 static void cmis_parse_dom_mod_lvl_monitors(const struct cmis_memory_map *map,
535 struct sff_diags *sd)
536 {
537 sd->sfp_voltage[MCURR] = OFFSET_TO_U16_PTR(map->lower_memory,
538 CMIS_CURR_VCC_OFFSET);
539 sd->sfp_temp[MCURR] = (__s16)OFFSET_TO_U16_PTR(map->lower_memory,
540 CMIS_CURR_TEMP_OFFSET);
541 }
542
cmis_parse_dom_mod_lvl_thresh(const struct cmis_memory_map * map,struct sff_diags * sd)543 static void cmis_parse_dom_mod_lvl_thresh(const struct cmis_memory_map *map,
544 struct sff_diags *sd)
545 {
546 /* Page is not present in IOCTL path. */
547 if (!map->page_02h)
548 return;
549 sd->supports_alarms = 1;
550
551 sd->sfp_voltage[HALRM] = OFFSET_TO_U16_PTR(map->page_02h,
552 CMIS_VCC_HALRM_OFFSET);
553 sd->sfp_voltage[LALRM] = OFFSET_TO_U16_PTR(map->page_02h,
554 CMIS_VCC_LALRM_OFFSET);
555 sd->sfp_voltage[HWARN] = OFFSET_TO_U16_PTR(map->page_02h,
556 CMIS_VCC_HWARN_OFFSET);
557 sd->sfp_voltage[LWARN] = OFFSET_TO_U16_PTR(map->page_02h,
558 CMIS_VCC_LWARN_OFFSET);
559
560 sd->sfp_temp[HALRM] = (__s16)OFFSET_TO_U16_PTR(map->page_02h,
561 CMIS_TEMP_HALRM_OFFSET);
562 sd->sfp_temp[LALRM] = (__s16)OFFSET_TO_U16_PTR(map->page_02h,
563 CMIS_TEMP_LALRM_OFFSET);
564 sd->sfp_temp[HWARN] = (__s16)OFFSET_TO_U16_PTR(map->page_02h,
565 CMIS_TEMP_HWARN_OFFSET);
566 sd->sfp_temp[LWARN] = (__s16)OFFSET_TO_U16_PTR(map->page_02h,
567 CMIS_TEMP_LWARN_OFFSET);
568 }
569
cmis_tx_bias_mul(const struct cmis_memory_map * map)570 static __u8 cmis_tx_bias_mul(const struct cmis_memory_map *map)
571 {
572 switch (map->page_01h[CMIS_DIAG_CHAN_ADVER_OFFSET] &
573 CMIS_TX_BIAS_MUL_MASK) {
574 case CMIS_TX_BIAS_MUL_1:
575 return 0;
576 case CMIS_TX_BIAS_MUL_2:
577 return 1;
578 case CMIS_TX_BIAS_MUL_4:
579 return 2;
580 }
581
582 return 0;
583 }
584
585 static void
cmis_parse_dom_chan_lvl_monitors_bank(const struct cmis_memory_map * map,struct sff_diags * sd,int bank)586 cmis_parse_dom_chan_lvl_monitors_bank(const struct cmis_memory_map *map,
587 struct sff_diags *sd, int bank)
588 {
589 const __u8 *page_11h = map->upper_memory[bank][0x11];
590 int i;
591
592 if (!page_11h)
593 return;
594
595 for (i = 0; i < CMIS_CHANNELS_PER_BANK; i++) {
596 __u8 tx_bias_offset, rx_power_offset, tx_power_offset;
597 int chan = bank * CMIS_CHANNELS_PER_BANK + i;
598 __u8 bias_mul = cmis_tx_bias_mul(map);
599
600 tx_bias_offset = CMIS_TX_BIAS_OFFSET + i * sizeof(__u16);
601 rx_power_offset = CMIS_RX_PWR_OFFSET + i * sizeof(__u16);
602 tx_power_offset = CMIS_TX_PWR_OFFSET + i * sizeof(__u16);
603
604 sd->scd[chan].bias_cur = OFFSET_TO_U16_PTR(page_11h,
605 tx_bias_offset);
606 sd->scd[chan].bias_cur >>= bias_mul;
607 sd->scd[chan].rx_power = OFFSET_TO_U16_PTR(page_11h,
608 rx_power_offset);
609 sd->scd[chan].tx_power = OFFSET_TO_U16_PTR(page_11h,
610 tx_power_offset);
611 }
612 }
613
cmis_parse_dom_chan_lvl_monitors(const struct cmis_memory_map * map,struct sff_diags * sd)614 static void cmis_parse_dom_chan_lvl_monitors(const struct cmis_memory_map *map,
615 struct sff_diags *sd)
616 {
617 int i;
618
619 for (i = 0; i < CMIS_MAX_BANKS; i++)
620 cmis_parse_dom_chan_lvl_monitors_bank(map, sd, i);
621 }
622
cmis_parse_dom_chan_lvl_thresh(const struct cmis_memory_map * map,struct sff_diags * sd)623 static void cmis_parse_dom_chan_lvl_thresh(const struct cmis_memory_map *map,
624 struct sff_diags *sd)
625 {
626 __u8 bias_mul = cmis_tx_bias_mul(map);
627
628 if (!map->page_02h)
629 return;
630
631 sd->bias_cur[HALRM] = OFFSET_TO_U16_PTR(map->page_02h,
632 CMIS_TX_BIAS_HALRM_OFFSET);
633 sd->bias_cur[HALRM] >>= bias_mul;
634 sd->bias_cur[LALRM] = OFFSET_TO_U16_PTR(map->page_02h,
635 CMIS_TX_BIAS_LALRM_OFFSET);
636 sd->bias_cur[LALRM] >>= bias_mul;
637 sd->bias_cur[HWARN] = OFFSET_TO_U16_PTR(map->page_02h,
638 CMIS_TX_BIAS_HWARN_OFFSET);
639 sd->bias_cur[HWARN] >>= bias_mul;
640 sd->bias_cur[LWARN] = OFFSET_TO_U16_PTR(map->page_02h,
641 CMIS_TX_BIAS_LWARN_OFFSET);
642 sd->bias_cur[LWARN] >>= bias_mul;
643
644 sd->tx_power[HALRM] = OFFSET_TO_U16_PTR(map->page_02h,
645 CMIS_TX_PWR_HALRM_OFFSET);
646 sd->tx_power[LALRM] = OFFSET_TO_U16_PTR(map->page_02h,
647 CMIS_TX_PWR_LALRM_OFFSET);
648 sd->tx_power[HWARN] = OFFSET_TO_U16_PTR(map->page_02h,
649 CMIS_TX_PWR_HWARN_OFFSET);
650 sd->tx_power[LWARN] = OFFSET_TO_U16_PTR(map->page_02h,
651 CMIS_TX_PWR_LWARN_OFFSET);
652
653 sd->rx_power[HALRM] = OFFSET_TO_U16_PTR(map->page_02h,
654 CMIS_RX_PWR_HALRM_OFFSET);
655 sd->rx_power[LALRM] = OFFSET_TO_U16_PTR(map->page_02h,
656 CMIS_RX_PWR_LALRM_OFFSET);
657 sd->rx_power[HWARN] = OFFSET_TO_U16_PTR(map->page_02h,
658 CMIS_RX_PWR_HWARN_OFFSET);
659 sd->rx_power[LWARN] = OFFSET_TO_U16_PTR(map->page_02h,
660 CMIS_RX_PWR_LWARN_OFFSET);
661 }
662
cmis_parse_dom(const struct cmis_memory_map * map,struct sff_diags * sd)663 static void cmis_parse_dom(const struct cmis_memory_map *map,
664 struct sff_diags *sd)
665 {
666 cmis_parse_dom_power_type(map, sd);
667 cmis_parse_dom_mod_lvl_monitors(map, sd);
668 cmis_parse_dom_mod_lvl_thresh(map, sd);
669 cmis_parse_dom_chan_lvl_monitors(map, sd);
670 cmis_parse_dom_chan_lvl_thresh(map, sd);
671 }
672
673 /* Print module-level monitoring values. Relevant documents:
674 * [1] CMIS Rev. 5, page 110, section 8.2.5, Table 8-9
675 */
cmis_show_dom_mod_lvl_monitors(const struct sff_diags * sd)676 static void cmis_show_dom_mod_lvl_monitors(const struct sff_diags *sd)
677 {
678 PRINT_TEMP("Module temperature", sd->sfp_temp[MCURR]);
679 PRINT_VCC("Module voltage", sd->sfp_voltage[MCURR]);
680 }
681
682 /* Print channel Tx laser bias current. Relevant documents:
683 * [1] CMIS Rev. 5, page 165, section 8.9.4, Table 8-79
684 */
685 static void
cmis_show_dom_chan_lvl_tx_bias_bank(const struct cmis_memory_map * map,const struct sff_diags * sd,int bank)686 cmis_show_dom_chan_lvl_tx_bias_bank(const struct cmis_memory_map *map,
687 const struct sff_diags *sd, int bank)
688 {
689 const __u8 *page_11h = map->upper_memory[bank][0x11];
690 int i;
691
692 if (!page_11h)
693 return;
694
695 for (i = 0; i < CMIS_CHANNELS_PER_BANK; i++) {
696 int chan = bank * CMIS_CHANNELS_PER_BANK + i;
697 char fmt_str[80];
698
699 snprintf(fmt_str, 80, "%s (Channel %d)",
700 "Laser tx bias current", chan + 1);
701 PRINT_BIAS(fmt_str, sd->scd[chan].bias_cur);
702 }
703 }
704
cmis_show_dom_chan_lvl_tx_bias(const struct cmis_memory_map * map,const struct sff_diags * sd)705 static void cmis_show_dom_chan_lvl_tx_bias(const struct cmis_memory_map *map,
706 const struct sff_diags *sd)
707 {
708 int i;
709
710 if(!(map->page_01h[CMIS_DIAG_CHAN_ADVER_OFFSET] &
711 CMIS_TX_BIAS_MON_MASK))
712 return;
713
714 for (i = 0; i < CMIS_MAX_BANKS; i++)
715 cmis_show_dom_chan_lvl_tx_bias_bank(map, sd, i);
716 }
717
718 /* Print channel Tx average optical power. Relevant documents:
719 * [1] CMIS Rev. 5, page 165, section 8.9.4, Table 8-79
720 */
721 static void
cmis_show_dom_chan_lvl_tx_power_bank(const struct cmis_memory_map * map,const struct sff_diags * sd,int bank)722 cmis_show_dom_chan_lvl_tx_power_bank(const struct cmis_memory_map *map,
723 const struct sff_diags *sd, int bank)
724 {
725 const __u8 *page_11h = map->upper_memory[bank][0x11];
726 int i;
727
728 if (!page_11h)
729 return;
730
731 for (i = 0; i < CMIS_CHANNELS_PER_BANK; i++) {
732 int chan = bank * CMIS_CHANNELS_PER_BANK + i;
733 char fmt_str[80];
734
735 snprintf(fmt_str, 80, "%s (Channel %d)",
736 "Transmit avg optical power", chan + 1);
737 PRINT_xX_PWR(fmt_str, sd->scd[chan].tx_power);
738 }
739 }
740
cmis_show_dom_chan_lvl_tx_power(const struct cmis_memory_map * map,const struct sff_diags * sd)741 static void cmis_show_dom_chan_lvl_tx_power(const struct cmis_memory_map *map,
742 const struct sff_diags *sd)
743 {
744 int i;
745
746 if (!sd->tx_power_type)
747 return;
748
749 for (i = 0; i < CMIS_MAX_BANKS; i++)
750 cmis_show_dom_chan_lvl_tx_power_bank(map, sd, i);
751 }
752
753 /* Print channel Rx input optical power. Relevant documents:
754 * [1] CMIS Rev. 5, page 165, section 8.9.4, Table 8-79
755 */
756 static void
cmis_show_dom_chan_lvl_rx_power_bank(const struct cmis_memory_map * map,const struct sff_diags * sd,int bank)757 cmis_show_dom_chan_lvl_rx_power_bank(const struct cmis_memory_map *map,
758 const struct sff_diags *sd, int bank)
759 {
760 const __u8 *page_11h = map->upper_memory[bank][0x11];
761 int i;
762
763 if (!page_11h)
764 return;
765
766 for (i = 0; i < CMIS_CHANNELS_PER_BANK; i++) {
767 int chan = bank * CMIS_CHANNELS_PER_BANK + i;
768 char *rx_power_str;
769 char fmt_str[80];
770
771 if (!sd->rx_power_type)
772 rx_power_str = "Receiver signal OMA";
773 else
774 rx_power_str = "Rcvr signal avg optical power";
775
776 snprintf(fmt_str, 80, "%s (Channel %d)", rx_power_str,
777 chan + 1);
778 PRINT_xX_PWR(fmt_str, sd->scd[chan].rx_power);
779 }
780 }
781
cmis_show_dom_chan_lvl_rx_power(const struct cmis_memory_map * map,const struct sff_diags * sd)782 static void cmis_show_dom_chan_lvl_rx_power(const struct cmis_memory_map *map,
783 const struct sff_diags *sd)
784 {
785 int i;
786
787 if(!(map->page_01h[CMIS_DIAG_CHAN_ADVER_OFFSET] & CMIS_RX_PWR_MON_MASK))
788 return;
789
790 for (i = 0; i < CMIS_MAX_BANKS; i++)
791 cmis_show_dom_chan_lvl_rx_power_bank(map, sd, i);
792 }
793
cmis_show_dom_chan_lvl_monitors(const struct cmis_memory_map * map,const struct sff_diags * sd)794 static void cmis_show_dom_chan_lvl_monitors(const struct cmis_memory_map *map,
795 const struct sff_diags *sd)
796 {
797 cmis_show_dom_chan_lvl_tx_bias(map, sd);
798 cmis_show_dom_chan_lvl_tx_power(map, sd);
799 cmis_show_dom_chan_lvl_rx_power(map, sd);
800 }
801
802 /* Print module-level flags. Relevant documents:
803 * [1] CMIS Rev. 5, page 109, section 8.2.4, Table 8-8
804 */
cmis_show_dom_mod_lvl_flags(const struct cmis_memory_map * map)805 static void cmis_show_dom_mod_lvl_flags(const struct cmis_memory_map *map)
806 {
807 int i;
808
809 for (i = 0; cmis_aw_mod_flags[i].str; i++) {
810 printf("\t%-41s : %s\n", cmis_aw_mod_flags[i].str,
811 map->lower_memory[cmis_aw_mod_flags[i].offset] &
812 cmis_aw_mod_flags[i].value ? "On" : "Off");
813 }
814 }
815
816 /* Print channel-level flags. Relevant documents:
817 * [1] CMIS Rev. 5, page 162, section 8.9.3, Table 8-77
818 * [1] CMIS Rev. 5, page 164, section 8.9.3, Table 8-78
819 */
cmis_show_dom_chan_lvl_flags_chan(const struct cmis_memory_map * map,int bank,int chan)820 static void cmis_show_dom_chan_lvl_flags_chan(const struct cmis_memory_map *map,
821 int bank, int chan)
822 {
823 const __u8 *page_11h = map->upper_memory[bank][0x11];
824 int i;
825
826 for (i = 0; cmis_aw_chan_flags[i].fmt_str; i++) {
827 char str[80];
828
829 if (!(map->page_01h[cmis_aw_chan_flags[i].adver_offset] &
830 cmis_aw_chan_flags[i].adver_value))
831 continue;
832
833 snprintf(str, 80, cmis_aw_chan_flags[i].fmt_str, chan + 1);
834 printf("\t%-41s : %s\n", str,
835 page_11h[cmis_aw_chan_flags[i].offset] & chan ?
836 "On" : "Off");
837 }
838 }
839
840 static void
cmis_show_dom_chan_lvl_flags_bank(const struct cmis_memory_map * map,int bank)841 cmis_show_dom_chan_lvl_flags_bank(const struct cmis_memory_map *map,
842 int bank)
843 {
844 const __u8 *page_11h = map->upper_memory[bank][0x11];
845 int i;
846
847 if (!page_11h)
848 return;
849
850 for (i = 0; i < CMIS_CHANNELS_PER_BANK; i++) {
851 int chan = bank * CMIS_CHANNELS_PER_BANK + i;
852
853 cmis_show_dom_chan_lvl_flags_chan(map, bank, chan);
854 }
855 }
856
cmis_show_dom_chan_lvl_flags(const struct cmis_memory_map * map)857 static void cmis_show_dom_chan_lvl_flags(const struct cmis_memory_map *map)
858 {
859 int i;
860
861 for (i = 0; i < CMIS_MAX_BANKS; i++)
862 cmis_show_dom_chan_lvl_flags_bank(map, i);
863 }
864
865
cmis_show_dom(const struct cmis_memory_map * map)866 static void cmis_show_dom(const struct cmis_memory_map *map)
867 {
868 struct sff_diags sd = {};
869
870 /* Diagnostic information is only relevant when the module memory
871 * model is paged and not flat.
872 */
873 if (map->lower_memory[CMIS_MEMORY_MODEL_OFFSET] &
874 CMIS_MEMORY_MODEL_MASK)
875 return;
876
877 cmis_parse_dom(map, &sd);
878
879 cmis_show_dom_mod_lvl_monitors(&sd);
880 cmis_show_dom_chan_lvl_monitors(map, &sd);
881 cmis_show_dom_mod_lvl_flags(map);
882 cmis_show_dom_chan_lvl_flags(map);
883 if (sd.supports_alarms)
884 sff_show_thresholds(sd);
885 }
886
cmis_show_all_common(const struct cmis_memory_map * map)887 static void cmis_show_all_common(const struct cmis_memory_map *map)
888 {
889 cmis_show_identifier(map);
890 cmis_show_power_info(map);
891 cmis_show_connector(map);
892 cmis_show_cbl_asm_len(map);
893 cmis_show_sig_integrity(map);
894 cmis_show_mit_compliance(map);
895 cmis_show_link_len(map);
896 cmis_show_vendor_info(map);
897 cmis_show_rev_compliance(map);
898 cmis_show_signals(map);
899 cmis_show_mod_state(map);
900 cmis_show_mod_fault_cause(map);
901 cmis_show_mod_lvl_controls(map);
902 cmis_show_dom(map);
903 }
904
cmis_memory_map_init_buf(struct cmis_memory_map * map,const __u8 * id)905 static void cmis_memory_map_init_buf(struct cmis_memory_map *map,
906 const __u8 *id)
907 {
908 /* Lower Memory and Page 00h are always present.
909 *
910 * Offset into Upper Memory is between page size and twice the page
911 * size. Therefore, set the base address of each page to base address
912 * plus page size multiplied by the page number.
913 */
914 map->lower_memory = id;
915 map->page_00h = id;
916
917 /* Page 01h is only present when the module memory model is paged and
918 * not flat.
919 */
920 if (map->lower_memory[CMIS_MEMORY_MODEL_OFFSET] &
921 CMIS_MEMORY_MODEL_MASK)
922 return;
923
924 map->page_01h = id + CMIS_PAGE_SIZE;
925 }
926
cmis_show_all_ioctl(const __u8 * id)927 void cmis_show_all_ioctl(const __u8 *id)
928 {
929 struct cmis_memory_map map = {};
930
931 cmis_memory_map_init_buf(&map, id);
932 cmis_show_all_common(&map);
933 }
934
cmis_request_init(struct ethtool_module_eeprom * request,u8 bank,u8 page,u32 offset)935 static void cmis_request_init(struct ethtool_module_eeprom *request, u8 bank,
936 u8 page, u32 offset)
937 {
938 request->offset = offset;
939 request->length = CMIS_PAGE_SIZE;
940 request->page = page;
941 request->bank = bank;
942 request->i2c_address = CMIS_I2C_ADDRESS;
943 request->data = NULL;
944 }
945
cmis_num_banks_get(const struct cmis_memory_map * map,int * p_num_banks)946 static int cmis_num_banks_get(const struct cmis_memory_map *map,
947 int *p_num_banks)
948 {
949 switch (map->page_01h[CMIS_PAGES_ADVER_OFFSET] &
950 CMIS_BANKS_SUPPORTED_MASK) {
951 case CMIS_BANK_0_SUPPORTED:
952 *p_num_banks = 1;
953 break;
954 case CMIS_BANK_0_1_SUPPORTED:
955 *p_num_banks = 2;
956 break;
957 case CMIS_BANK_0_3_SUPPORTED:
958 *p_num_banks = 4;
959 break;
960 default:
961 return -EINVAL;
962 }
963
964 return 0;
965 }
966
967 static int
cmis_memory_map_init_pages(struct cmd_context * ctx,struct cmis_memory_map * map)968 cmis_memory_map_init_pages(struct cmd_context *ctx,
969 struct cmis_memory_map *map)
970 {
971 struct ethtool_module_eeprom request;
972 int num_banks, i, ret;
973
974 /* Lower Memory and Page 00h are always present.
975 *
976 * Offset into Upper Memory is between page size and twice the page
977 * size. Therefore, set the base address of each page to its base
978 * address minus page size.
979 */
980 cmis_request_init(&request, 0, 0x0, 0);
981 ret = nl_get_eeprom_page(ctx, &request);
982 if (ret < 0)
983 return ret;
984 map->lower_memory = request.data;
985
986 cmis_request_init(&request, 0, 0x0, CMIS_PAGE_SIZE);
987 ret = nl_get_eeprom_page(ctx, &request);
988 if (ret < 0)
989 return ret;
990 map->page_00h = request.data - CMIS_PAGE_SIZE;
991
992 /* Pages 01h and 02h are only present when the module memory model is
993 * paged and not flat.
994 */
995 if (map->lower_memory[CMIS_MEMORY_MODEL_OFFSET] &
996 CMIS_MEMORY_MODEL_MASK)
997 return 0;
998
999 cmis_request_init(&request, 0, 0x1, CMIS_PAGE_SIZE);
1000 ret = nl_get_eeprom_page(ctx, &request);
1001 if (ret < 0)
1002 return ret;
1003 map->page_01h = request.data - CMIS_PAGE_SIZE;
1004
1005 cmis_request_init(&request, 0, 0x2, CMIS_PAGE_SIZE);
1006 ret = nl_get_eeprom_page(ctx, &request);
1007 if (ret < 0)
1008 return ret;
1009 map->page_02h = request.data - CMIS_PAGE_SIZE;
1010
1011 /* Bank 0 of Page 11h provides lane-specific registers for the first 8
1012 * lanes, and each additional Banks provides support for an additional
1013 * 8 lanes. Only initialize supported Banks.
1014 */
1015 ret = cmis_num_banks_get(map, &num_banks);
1016 if (ret < 0)
1017 return ret;
1018
1019 for (i = 0; i < num_banks; i++) {
1020 cmis_request_init(&request, i, 0x11, CMIS_PAGE_SIZE);
1021 ret = nl_get_eeprom_page(ctx, &request);
1022 if (ret < 0)
1023 return ret;
1024 map->upper_memory[i][0x11] = request.data - CMIS_PAGE_SIZE;
1025 }
1026
1027 return 0;
1028 }
1029
cmis_show_all_nl(struct cmd_context * ctx)1030 int cmis_show_all_nl(struct cmd_context *ctx)
1031 {
1032 struct cmis_memory_map map = {};
1033 int ret;
1034
1035 ret = cmis_memory_map_init_pages(ctx, &map);
1036 if (ret < 0)
1037 return ret;
1038 cmis_show_all_common(&map);
1039
1040 return 0;
1041 }
1042