aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichal Kubecek <mkubecek@suse.cz>2021-11-22 00:07:26 +0100
committerMichal Kubecek <mkubecek@suse.cz>2021-11-22 00:07:26 +0100
commit664586ecdb7bb82498fdca9946a287ec132162ee (patch)
tree3beae66493bdc1291266b4fab40a7795e2344ceb
parentcef54c4f330ddbf6c4723dd001d6a2cc4ac9ea3e (diff)
parent9538f384b535635f79ecc33234b473a898993bd0 (diff)
downloadethtool-664586ecdb7bb82498fdca9946a287ec132162ee.tar.gz
Merge branch 'review/next/module-mem-map' into master
Ido Schimmel: This patchset prepares ethtool(8) for retrieval and parsing of optional and banked module EEPROM pages, such as the ones present in CMIS. This is done by better integration of the recent 'MODULE_EEPROM_GET' netlink interface into ethtool(8). Background ========== ethtool(8) contains parsers for various module EEPROM memory maps such as SFF-8079, SFF-8636 and CMIS. Using the legacy IOCTL interface, ethtool(8) can ask the kernel to provide a buffer with the EEPROM contents. The buffer is then passed to the parsers that parse and print the EEPROM contents. The major disadvantage of this method is that in addition to ethtool(8), the kernel also needs to be familiar with the layout of the various memory maps, as it should not report to user space optional pages that do not exist. In addition, with the emergence of more complex layouts (e.g., CMIS) that include both optional and banked pages, the layout of the linear buffer provided by the kernel is unclear. For these reasons, kernel 5.13 was extended with the 'MODULE_EEPROM_GET' netlink message that allows user space to request specific EEPROM pages. Motivation ========== Unfortunately, the current integration of 'MODULE_EEPROM_GET' into ethtool(8) is not ideal. In the IOCTL path, a single large buffer is passed to the parsers, whereas in the netlink path, individual pages are passed. This is problematic for several reasons. First, this approach is not very scalable as standards such as CMIS support a lot of optional and banked pages. Passing them as separate arguments is not going to work. Second, the knowledge of which optional and banked pages are available should be encapsulated in the individual parsers, not in the common netlink code (i.e., netlink/module-eeprom.c). Currently, the common code is blindly requesting from the kernel optional pages that might not exist. Third, the difference in the way information is passed to the parsers propagates all the way to the individual parsing functions. For example, cmis_show_link_len() vs. cmis_show_link_len_from_page(). Implementation ============== In order to solve above mentioned problems and make it easier to integrate retrieval and parsing of optional and banked pages, this patchset reworks the EEPROM parsing code to use memory maps. For each parser, a structure describing the layout of the memory map is initialized with pointers to individual pages. In the IOCTL path, this structure contains pointers to sections of the linear buffer that was retrieved from the kernel. In the netlink path, this structure contains pointers to individual pages requested from the kernel. Care is taken to ensure that pages that do not exist are not requested from the kernel. After the structure is initialized, it is passed to the parsing code that parses and prints the information. This approach can be easily extended to support more optional and banked pages and allows us to keep the parsing code common to both the IOCTL and netlink paths. The only difference lies in how the memory map is initialized when the parser is invoked. Testing ======= Build tested each patch with the following configuration options: netlink | pretty-dump --------|------------ v | v x | x v | x x | v No differences in output before and after the patchset (*). Tested with QSFP (PC/AOC), QSFP-DD (PC/AOC), SFP (PC) and both IOCTL and netlink. No reports from AddressSanitizer / valgrind. (*) The only difference is in a few registers in CMIS that were not parsed correctly to begin with. Patchset overview ================= Patches #1-#4 move CMIS to use a memory map and consolidate the code paths between the IOCTL and netlink paths. Patches #5-#8 do the same for SFF-8636. Patch #9 does the same for SFF-8079. Patch #10 exports a function to allow parsers to request a specific EEPROM page. Patches #11-#13 change parsers to request only specific and valid EEPROM pages instead of getting potentially invalid pages from the common netlink code (i.e., netlink/module-eeprom.c). Patch #14 converts the common netlink code to simply call into individual parsers based on their SFF-8024 Identifier Value. The command context is passed to these parsers instead of potentially invalid pages.
-rw-r--r--cmis.c268
-rw-r--r--cmis.h8
-rw-r--r--ethtool.c8
-rw-r--r--internal.h8
-rw-r--r--netlink/extapi.h11
-rw-r--r--netlink/module-eeprom.c318
-rw-r--r--qsfp.c484
-rw-r--r--sfpid.c28
8 files changed, 635 insertions, 498 deletions
diff --git a/cmis.c b/cmis.c
index 591cc72..4798fd4 100644
--- a/cmis.c
+++ b/cmis.c
@@ -9,23 +9,35 @@
#include <stdio.h>
#include <math.h>
+#include <errno.h>
#include "internal.h"
#include "sff-common.h"
#include "cmis.h"
+#include "netlink/extapi.h"
-static void cmis_show_identifier(const __u8 *id)
+struct cmis_memory_map {
+ const __u8 *lower_memory;
+ const __u8 *upper_memory[1][2]; /* Bank, Page */
+#define page_00h upper_memory[0x0][0x0]
+#define page_01h upper_memory[0x0][0x1]
+};
+
+#define CMIS_PAGE_SIZE 0x80
+#define CMIS_I2C_ADDRESS 0x50
+
+static void cmis_show_identifier(const struct cmis_memory_map *map)
{
- sff8024_show_identifier(id, CMIS_ID_OFFSET);
+ sff8024_show_identifier(map->lower_memory, CMIS_ID_OFFSET);
}
-static void cmis_show_connector(const __u8 *id)
+static void cmis_show_connector(const struct cmis_memory_map *map)
{
- sff8024_show_connector(id, CMIS_CTOR_OFFSET);
+ sff8024_show_connector(map->page_00h, CMIS_CTOR_OFFSET);
}
-static void cmis_show_oui(const __u8 *id)
+static void cmis_show_oui(const struct cmis_memory_map *map)
{
- sff8024_show_oui(id, CMIS_VENDOR_OUI_OFFSET);
+ sff8024_show_oui(map->page_00h, CMIS_VENDOR_OUI_OFFSET);
}
/**
@@ -33,9 +45,9 @@ static void cmis_show_oui(const __u8 *id)
* [1] CMIS Rev. 3, pag. 45, section 1.7.2.1, Table 18
* [2] CMIS Rev. 4, pag. 81, section 8.2.1, Table 8-2
*/
-static void cmis_show_rev_compliance(const __u8 *id)
+static void cmis_show_rev_compliance(const struct cmis_memory_map *map)
{
- __u8 rev = id[CMIS_REV_COMPLIANCE_OFFSET];
+ __u8 rev = map->lower_memory[CMIS_REV_COMPLIANCE_OFFSET];
int major = (rev >> 4) & 0x0F;
int minor = rev & 0x0F;
@@ -49,17 +61,17 @@ static void cmis_show_rev_compliance(const __u8 *id)
* [2] CMIS Rev. 4, pag. 94, section 8.3.9, Table 8-18
* [3] QSFP-DD Hardware Rev 5.0, pag. 22, section 4.2.1
*/
-static void cmis_show_power_info(const __u8 *id)
+static void cmis_show_power_info(const struct cmis_memory_map *map)
{
float max_power = 0.0f;
__u8 base_power = 0;
__u8 power_class;
/* Get the power class (first 3 most significat bytes) */
- power_class = (id[CMIS_PWR_CLASS_OFFSET] >> 5) & 0x07;
+ power_class = (map->page_00h[CMIS_PWR_CLASS_OFFSET] >> 5) & 0x07;
/* Get the base power in multiples of 0.25W */
- base_power = id[CMIS_PWR_MAX_POWER_OFFSET];
+ base_power = map->page_00h[CMIS_PWR_MAX_POWER_OFFSET];
max_power = base_power * 0.25f;
printf("\t%-41s : %d\n", "Power class", power_class + 1);
@@ -74,20 +86,20 @@ static void cmis_show_power_info(const __u8 *id)
* [1] CMIS Rev. 3, pag. 59, section 1.7.3.10, Table 31
* [2] CMIS Rev. 4, pag. 94, section 8.3.10, Table 8-19
*/
-static void cmis_show_cbl_asm_len(const __u8 *id)
+static void cmis_show_cbl_asm_len(const struct cmis_memory_map *map)
{
static const char *fn = "Cable assembly length";
float mul = 1.0f;
float val = 0.0f;
/* Check if max length */
- if (id[CMIS_CBL_ASM_LEN_OFFSET] == CMIS_6300M_MAX_LEN) {
+ if (map->page_00h[CMIS_CBL_ASM_LEN_OFFSET] == CMIS_6300M_MAX_LEN) {
printf("\t%-41s : > 6.3km\n", fn);
return;
}
/* Get the multiplier from the first two bits */
- switch (id[CMIS_CBL_ASM_LEN_OFFSET] & CMIS_LEN_MUL_MASK) {
+ switch (map->page_00h[CMIS_CBL_ASM_LEN_OFFSET] & CMIS_LEN_MUL_MASK) {
case CMIS_MULTIPLIER_00:
mul = 0.1f;
break;
@@ -105,7 +117,7 @@ static void cmis_show_cbl_asm_len(const __u8 *id)
}
/* Get base value from first 6 bits and multiply by mul */
- val = (id[CMIS_CBL_ASM_LEN_OFFSET] & CMIS_LEN_VAL_MASK);
+ val = (map->page_00h[CMIS_CBL_ASM_LEN_OFFSET] & CMIS_LEN_VAL_MASK);
val = (float)val * mul;
printf("\t%-41s : %0.2fm\n", fn, val);
}
@@ -117,14 +129,17 @@ static void cmis_show_cbl_asm_len(const __u8 *id)
* [1] CMIS Rev. 3, pag. 63, section 1.7.4.2, Table 39
* [2] CMIS Rev. 4, pag. 99, section 8.4.2, Table 8-27
*/
-static void cmis_print_smf_cbl_len(const __u8 *id)
+static void cmis_print_smf_cbl_len(const struct cmis_memory_map *map)
{
static const char *fn = "Length (SMF)";
float mul = 1.0f;
float val = 0.0f;
+ if (!map->page_01h)
+ return;
+
/* Get the multiplier from the first two bits */
- switch (id[CMIS_SMF_LEN_OFFSET] & CMIS_LEN_MUL_MASK) {
+ switch (map->page_01h[CMIS_SMF_LEN_OFFSET] & CMIS_LEN_MUL_MASK) {
case CMIS_MULTIPLIER_00:
mul = 0.1f;
break;
@@ -136,7 +151,7 @@ static void cmis_print_smf_cbl_len(const __u8 *id)
}
/* Get base value from first 6 bits and multiply by mul */
- val = (id[CMIS_SMF_LEN_OFFSET] & CMIS_LEN_VAL_MASK);
+ val = (map->page_01h[CMIS_SMF_LEN_OFFSET] & CMIS_LEN_VAL_MASK);
val = (float)val * mul;
printf("\t%-41s : %0.2fkm\n", fn, val);
}
@@ -146,21 +161,24 @@ static void cmis_print_smf_cbl_len(const __u8 *id)
* [1] CMIS Rev. 3, pag. 71, section 1.7.4.10, Table 46
* [2] CMIS Rev. 4, pag. 105, section 8.4.10, Table 8-34
*/
-static void cmis_show_sig_integrity(const __u8 *id)
+static void cmis_show_sig_integrity(const struct cmis_memory_map *map)
{
+ if (!map->page_01h)
+ return;
+
/* CDR Bypass control: 2nd bit from each byte */
printf("\t%-41s : ", "Tx CDR bypass control");
- printf("%s\n", YESNO(id[CMIS_SIG_INTEG_TX_OFFSET] & 0x02));
+ printf("%s\n", YESNO(map->page_01h[CMIS_SIG_INTEG_TX_OFFSET] & 0x02));
printf("\t%-41s : ", "Rx CDR bypass control");
- printf("%s\n", YESNO(id[CMIS_SIG_INTEG_RX_OFFSET] & 0x02));
+ printf("%s\n", YESNO(map->page_01h[CMIS_SIG_INTEG_RX_OFFSET] & 0x02));
/* CDR Implementation: 1st bit from each byte */
printf("\t%-41s : ", "Tx CDR");
- printf("%s\n", YESNO(id[CMIS_SIG_INTEG_TX_OFFSET] & 0x01));
+ printf("%s\n", YESNO(map->page_01h[CMIS_SIG_INTEG_TX_OFFSET] & 0x01));
printf("\t%-41s : ", "Rx CDR");
- printf("%s\n", YESNO(id[CMIS_SIG_INTEG_RX_OFFSET] & 0x01));
+ printf("%s\n", YESNO(map->page_01h[CMIS_SIG_INTEG_RX_OFFSET] & 0x01));
}
/**
@@ -173,14 +191,14 @@ static void cmis_show_sig_integrity(const __u8 *id)
* --> pag. 98, section 8.4, Table 8-25
* --> page 100, section 8.4.3, 8.4.4
*/
-static void cmis_show_mit_compliance(const __u8 *id)
+static void cmis_show_mit_compliance(const struct cmis_memory_map *map)
{
static const char *cc = " (Copper cable,";
printf("\t%-41s : 0x%02x", "Transmitter technology",
- id[CMIS_MEDIA_INTF_TECH_OFFSET]);
+ map->page_00h[CMIS_MEDIA_INTF_TECH_OFFSET]);
- switch (id[CMIS_MEDIA_INTF_TECH_OFFSET]) {
+ switch (map->page_00h[CMIS_MEDIA_INTF_TECH_OFFSET]) {
case CMIS_850_VCSEL:
printf(" (850 nm VCSEL)\n");
break;
@@ -231,22 +249,22 @@ static void cmis_show_mit_compliance(const __u8 *id)
break;
}
- if (id[CMIS_MEDIA_INTF_TECH_OFFSET] >= CMIS_COPPER_UNEQUAL) {
+ if (map->page_00h[CMIS_MEDIA_INTF_TECH_OFFSET] >= CMIS_COPPER_UNEQUAL) {
printf("\t%-41s : %udb\n", "Attenuation at 5GHz",
- id[CMIS_COPPER_ATT_5GHZ]);
+ map->page_00h[CMIS_COPPER_ATT_5GHZ]);
printf("\t%-41s : %udb\n", "Attenuation at 7GHz",
- id[CMIS_COPPER_ATT_7GHZ]);
+ map->page_00h[CMIS_COPPER_ATT_7GHZ]);
printf("\t%-41s : %udb\n", "Attenuation at 12.9GHz",
- id[CMIS_COPPER_ATT_12P9GHZ]);
+ map->page_00h[CMIS_COPPER_ATT_12P9GHZ]);
printf("\t%-41s : %udb\n", "Attenuation at 25.8GHz",
- id[CMIS_COPPER_ATT_25P8GHZ]);
- } else {
+ map->page_00h[CMIS_COPPER_ATT_25P8GHZ]);
+ } else if (map->page_01h) {
printf("\t%-41s : %.3lfnm\n", "Laser wavelength",
- (((id[CMIS_NOM_WAVELENGTH_MSB] << 8) |
- id[CMIS_NOM_WAVELENGTH_LSB]) * 0.05));
+ (((map->page_01h[CMIS_NOM_WAVELENGTH_MSB] << 8) |
+ map->page_01h[CMIS_NOM_WAVELENGTH_LSB]) * 0.05));
printf("\t%-41s : %.3lfnm\n", "Laser wavelength tolerance",
- (((id[CMIS_WAVELENGTH_TOL_MSB] << 8) |
- id[CMIS_WAVELENGTH_TOL_LSB]) * 0.005));
+ (((map->page_01h[CMIS_WAVELENGTH_TOL_MSB] << 8) |
+ map->page_01h[CMIS_WAVELENGTH_TOL_LSB]) * 0.005));
}
}
@@ -266,28 +284,16 @@ static void cmis_show_mit_compliance(const __u8 *id)
* [2] CMIS Rev. 4:
* --> pag. 84, section 8.2.4, Table 8-6
*/
-static void cmis_show_mod_lvl_monitors(const __u8 *id)
+static void cmis_show_mod_lvl_monitors(const struct cmis_memory_map *map)
{
+ const __u8 *id = map->lower_memory;
+
PRINT_TEMP("Module temperature",
OFFSET_TO_TEMP(CMIS_CURR_TEMP_OFFSET));
PRINT_VCC("Module voltage",
OFFSET_TO_U16(CMIS_CURR_VCC_OFFSET));
}
-static void cmis_show_link_len_from_page(const __u8 *page_one_data)
-{
- cmis_print_smf_cbl_len(page_one_data);
- sff_show_value_with_unit(page_one_data, CMIS_OM5_LEN_OFFSET,
- "Length (OM5)", 2, "m");
- sff_show_value_with_unit(page_one_data, CMIS_OM4_LEN_OFFSET,
- "Length (OM4)", 2, "m");
- sff_show_value_with_unit(page_one_data, CMIS_OM3_LEN_OFFSET,
- "Length (OM3 50/125um)", 2, "m");
- sff_show_value_with_unit(page_one_data, CMIS_OM2_LEN_OFFSET,
- "Length (OM2 50/125um)", 1, "m");
-}
-
-
/**
* Print relevant info about the maximum supported fiber media length
* for each type of fiber media at the maximum module-supported bit rate.
@@ -295,9 +301,19 @@ static void cmis_show_link_len_from_page(const __u8 *page_one_data)
* [1] CMIS Rev. 3, page 64, section 1.7.4.2, Table 39
* [2] CMIS Rev. 4, page 99, section 8.4.2, Table 8-27
*/
-static void cmis_show_link_len(const __u8 *id)
+static void cmis_show_link_len(const struct cmis_memory_map *map)
{
- cmis_show_link_len_from_page(id);
+ cmis_print_smf_cbl_len(map);
+ if (!map->page_01h)
+ return;
+ sff_show_value_with_unit(map->page_01h, CMIS_OM5_LEN_OFFSET,
+ "Length (OM5)", 2, "m");
+ sff_show_value_with_unit(map->page_01h, CMIS_OM4_LEN_OFFSET,
+ "Length (OM4)", 2, "m");
+ sff_show_value_with_unit(map->page_01h, CMIS_OM3_LEN_OFFSET,
+ "Length (OM3 50/125um)", 2, "m");
+ sff_show_value_with_unit(map->page_01h, CMIS_OM2_LEN_OFFSET,
+ "Length (OM2 50/125um)", 1, "m");
}
/**
@@ -305,57 +321,133 @@ static void cmis_show_link_len(const __u8 *id)
* [1] CMIS Rev. 3, page 56, section 1.7.3, Table 27
* [2] CMIS Rev. 4, page 91, section 8.2, Table 8-15
*/
-static void cmis_show_vendor_info(const __u8 *id)
+static void cmis_show_vendor_info(const struct cmis_memory_map *map)
{
- const char *clei = (const char *)(id + CMIS_CLEI_START_OFFSET);
+ const char *clei;
- sff_show_ascii(id, CMIS_VENDOR_NAME_START_OFFSET,
+ sff_show_ascii(map->page_00h, CMIS_VENDOR_NAME_START_OFFSET,
CMIS_VENDOR_NAME_END_OFFSET, "Vendor name");
- cmis_show_oui(id);
- sff_show_ascii(id, CMIS_VENDOR_PN_START_OFFSET,
+ cmis_show_oui(map);
+ sff_show_ascii(map->page_00h, CMIS_VENDOR_PN_START_OFFSET,
CMIS_VENDOR_PN_END_OFFSET, "Vendor PN");
- sff_show_ascii(id, CMIS_VENDOR_REV_START_OFFSET,
+ sff_show_ascii(map->page_00h, CMIS_VENDOR_REV_START_OFFSET,
CMIS_VENDOR_REV_END_OFFSET, "Vendor rev");
- sff_show_ascii(id, CMIS_VENDOR_SN_START_OFFSET,
+ sff_show_ascii(map->page_00h, CMIS_VENDOR_SN_START_OFFSET,
CMIS_VENDOR_SN_END_OFFSET, "Vendor SN");
- sff_show_ascii(id, CMIS_DATE_YEAR_OFFSET,
+ sff_show_ascii(map->page_00h, CMIS_DATE_YEAR_OFFSET,
CMIS_DATE_VENDOR_LOT_OFFSET + 1, "Date code");
+ clei = (const char *)(map->page_00h + CMIS_CLEI_START_OFFSET);
if (*clei && strncmp(clei, CMIS_CLEI_BLANK, CMIS_CLEI_LEN))
- sff_show_ascii(id, CMIS_CLEI_START_OFFSET, CMIS_CLEI_END_OFFSET,
- "CLEI code");
+ sff_show_ascii(map->page_00h, CMIS_CLEI_START_OFFSET,
+ CMIS_CLEI_END_OFFSET, "CLEI code");
}
-void qsfp_dd_show_all(const __u8 *id)
+static void cmis_show_all_common(const struct cmis_memory_map *map)
{
- cmis_show_identifier(id);
- cmis_show_power_info(id);
- cmis_show_connector(id);
- cmis_show_cbl_asm_len(id);
- cmis_show_sig_integrity(id);
- cmis_show_mit_compliance(id);
- cmis_show_mod_lvl_monitors(id);
- cmis_show_link_len(id);
- cmis_show_vendor_info(id);
- cmis_show_rev_compliance(id);
+ cmis_show_identifier(map);
+ cmis_show_power_info(map);
+ cmis_show_connector(map);
+ cmis_show_cbl_asm_len(map);
+ cmis_show_sig_integrity(map);
+ cmis_show_mit_compliance(map);
+ cmis_show_mod_lvl_monitors(map);
+ cmis_show_link_len(map);
+ cmis_show_vendor_info(map);
+ cmis_show_rev_compliance(map);
}
-void cmis_show_all(const struct ethtool_module_eeprom *page_zero,
- const struct ethtool_module_eeprom *page_one)
+static void cmis_memory_map_init_buf(struct cmis_memory_map *map,
+ const __u8 *id)
{
- const __u8 *page_zero_data = page_zero->data;
+ /* Lower Memory and Page 00h are always present.
+ *
+ * Offset into Upper Memory is between page size and twice the page
+ * size. Therefore, set the base address of each page to base address
+ * plus page size multiplied by the page number.
+ */
+ map->lower_memory = id;
+ map->page_00h = id;
+
+ /* Page 01h is only present when the module memory model is paged and
+ * not flat.
+ */
+ if (map->lower_memory[CMIS_MEMORY_MODEL_OFFSET] &
+ CMIS_MEMORY_MODEL_MASK)
+ return;
- cmis_show_identifier(page_zero_data);
- cmis_show_power_info(page_zero_data);
- cmis_show_connector(page_zero_data);
- cmis_show_cbl_asm_len(page_zero_data);
- cmis_show_sig_integrity(page_zero_data);
- cmis_show_mit_compliance(page_zero_data);
- cmis_show_mod_lvl_monitors(page_zero_data);
+ map->page_01h = id + CMIS_PAGE_SIZE;
+}
+
+void cmis_show_all_ioctl(const __u8 *id)
+{
+ struct cmis_memory_map map = {};
+
+ cmis_memory_map_init_buf(&map, id);
+ cmis_show_all_common(&map);
+}
+
+static void cmis_request_init(struct ethtool_module_eeprom *request, u8 bank,
+ u8 page, u32 offset)
+{
+ request->offset = offset;
+ request->length = CMIS_PAGE_SIZE;
+ request->page = page;
+ request->bank = bank;
+ request->i2c_address = CMIS_I2C_ADDRESS;
+ request->data = NULL;
+}
+
+static int
+cmis_memory_map_init_pages(struct cmd_context *ctx,
+ struct cmis_memory_map *map)
+{
+ struct ethtool_module_eeprom request;
+ int ret;
+
+ /* Lower Memory and Page 00h are always present.
+ *
+ * Offset into Upper Memory is between page size and twice the page
+ * size. Therefore, set the base address of each page to its base
+ * address minus page size.
+ */
+ cmis_request_init(&request, 0, 0x0, 0);
+ ret = nl_get_eeprom_page(ctx, &request);
+ if (ret < 0)
+ return ret;
+ map->lower_memory = request.data;
+
+ cmis_request_init(&request, 0, 0x0, CMIS_PAGE_SIZE);
+ ret = nl_get_eeprom_page(ctx, &request);
+ if (ret < 0)
+ return ret;
+ map->page_00h = request.data - CMIS_PAGE_SIZE;
+
+ /* Page 01h is only present when the module memory model is paged and
+ * not flat.
+ */
+ if (map->lower_memory[CMIS_MEMORY_MODEL_OFFSET] &
+ CMIS_MEMORY_MODEL_MASK)
+ return 0;
+
+ cmis_request_init(&request, 0, 0x1, CMIS_PAGE_SIZE);
+ ret = nl_get_eeprom_page(ctx, &request);
+ if (ret < 0)
+ return ret;
+ map->page_01h = request.data - CMIS_PAGE_SIZE;
+
+ return 0;
+}
+
+int cmis_show_all_nl(struct cmd_context *ctx)
+{
+ struct cmis_memory_map map = {};
+ int ret;
- if (page_one)
- cmis_show_link_len_from_page(page_one->data - 0x80);
+ ret = cmis_memory_map_init_pages(ctx, &map);
+ if (ret < 0)
+ return ret;
+ cmis_show_all_common(&map);
- cmis_show_vendor_info(page_zero_data);
- cmis_show_rev_compliance(page_zero_data);
+ return 0;
}
diff --git a/cmis.h b/cmis.h
index e3012cc..911491d 100644
--- a/cmis.h
+++ b/cmis.h
@@ -4,6 +4,8 @@
/* Identifier and revision compliance (Page 0) */
#define CMIS_ID_OFFSET 0x00
#define CMIS_REV_COMPLIANCE_OFFSET 0x01
+#define CMIS_MEMORY_MODEL_OFFSET 0x02
+#define CMIS_MEMORY_MODEL_MASK 0x80
#define CMIS_MODULE_TYPE_OFFSET 0x55
#define CMIS_MT_MMF 0x01
@@ -98,7 +100,6 @@
* that are unique to active modules and cable assemblies.
* GlobalOffset = 2 * 0x80 + LocalOffset
*/
-#define PAG01H_UPPER_OFFSET (0x02 * 0x80)
/* Supported Link Length (Page 1) */
#define CMIS_SMF_LEN_OFFSET 0x84
@@ -120,9 +121,8 @@
#define YESNO(x) (((x) != 0) ? "Yes" : "No")
#define ONOFF(x) (((x) != 0) ? "On" : "Off")
-void qsfp_dd_show_all(const __u8 *id);
+void cmis_show_all_ioctl(const __u8 *id);
-void cmis_show_all(const struct ethtool_module_eeprom *page_zero,
- const struct ethtool_module_eeprom *page_one);
+int cmis_show_all_nl(struct cmd_context *ctx);
#endif /* CMIS_H__ */
diff --git a/ethtool.c b/ethtool.c
index 46887c7..064bc69 100644
--- a/ethtool.c
+++ b/ethtool.c
@@ -4900,16 +4900,16 @@ static int do_getmodule(struct cmd_context *ctx)
switch (modinfo.type) {
#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
case ETH_MODULE_SFF_8079:
- sff8079_show_all(eeprom->data);
+ sff8079_show_all_ioctl(eeprom->data);
break;
case ETH_MODULE_SFF_8472:
- sff8079_show_all(eeprom->data);
+ sff8079_show_all_ioctl(eeprom->data);
sff8472_show_all(eeprom->data);
break;
case ETH_MODULE_SFF_8436:
case ETH_MODULE_SFF_8636:
- sff8636_show_all(eeprom->data,
- modinfo.eeprom_len);
+ sff8636_show_all_ioctl(eeprom->data,
+ modinfo.eeprom_len);
break;
#endif
default:
diff --git a/internal.h b/internal.h
index 33e619b..0d9d816 100644
--- a/internal.h
+++ b/internal.h
@@ -384,15 +384,15 @@ int rxclass_rule_ins(struct cmd_context *ctx,
int rxclass_rule_del(struct cmd_context *ctx, __u32 loc);
/* Module EEPROM parsing code */
-void sff8079_show_all(const __u8 *id);
+void sff8079_show_all_ioctl(const __u8 *id);
+int sff8079_show_all_nl(struct cmd_context *ctx);
/* Optics diagnostics */
void sff8472_show_all(const __u8 *id);
/* QSFP Optics diagnostics */
-void sff8636_show_all(const __u8 *id, __u32 eeprom_len);
-void sff8636_show_all_paged(const struct ethtool_module_eeprom *page_zero,
- const struct ethtool_module_eeprom *page_three);
+void sff8636_show_all_ioctl(const __u8 *id, __u32 eeprom_len);
+int sff8636_show_all_nl(struct cmd_context *ctx);
/* FUJITSU Extended Socket network device */
int fjes_dump_regs(struct ethtool_drvinfo *info, struct ethtool_regs *regs);
diff --git a/netlink/extapi.h b/netlink/extapi.h
index 91bf02b..129e293 100644
--- a/netlink/extapi.h
+++ b/netlink/extapi.h
@@ -48,6 +48,9 @@ int nl_getmodule(struct cmd_context *ctx);
void nl_monitor_usage(void);
+int nl_get_eeprom_page(struct cmd_context *ctx,
+ struct ethtool_module_eeprom *request);
+
#else /* ETHTOOL_ENABLE_NETLINK */
static inline void netlink_run_handler(struct cmd_context *ctx __maybe_unused,
@@ -73,6 +76,14 @@ static inline void nl_monitor_usage(void)
{
}
+static inline int
+nl_get_eeprom_page(struct cmd_context *ctx __maybe_unused,
+ struct ethtool_module_eeprom *request __maybe_unused)
+{
+ fprintf(stderr, "Netlink not supported by ethtool.\n");
+ return -EOPNOTSUPP;
+}
+
#define nl_gset NULL
#define nl_sset NULL
#define nl_permaddr NULL
diff --git a/netlink/module-eeprom.c b/netlink/module-eeprom.c
index 48cd2cc..f359aee 100644
--- a/netlink/module-eeprom.c
+++ b/netlink/module-eeprom.c
@@ -19,7 +19,6 @@
#include "parser.h"
#define ETH_I2C_ADDRESS_LOW 0x50
-#define ETH_I2C_ADDRESS_HIGH 0x51
#define ETH_I2C_MAX_ADDRESS 0x7F
struct cmd_params {
@@ -78,120 +77,45 @@ static const struct param_parser getmodule_params[] = {
{}
};
-struct page_entry {
- struct list_head link;
- struct ethtool_module_eeprom *page;
-};
+static struct list_head eeprom_page_list = LIST_HEAD_INIT(eeprom_page_list);
-static struct list_head page_list = LIST_HEAD_INIT(page_list);
+struct eeprom_page_entry {
+ struct list_head list; /* Member of eeprom_page_list */
+ void *data;
+};
-static int cache_add(struct ethtool_module_eeprom *page)
+static int eeprom_page_list_add(void *data)
{
- struct page_entry *list_element;
+ struct eeprom_page_entry *entry;
- if (!page)
- return -1;
- list_element = malloc(sizeof(*list_element));
- if (!list_element)
+ entry = malloc(sizeof(*entry));
+ if (!entry)
return -ENOMEM;
- list_element->page = page;
-
- list_add(&list_element->link, &page_list);
- return 0;
-}
-static void page_free(struct ethtool_module_eeprom *page)
-{
- free(page->data);
- free(page);
-}
-
-static void cache_del(struct ethtool_module_eeprom *page)
-{
- struct ethtool_module_eeprom *entry;
- struct list_head *head, *next;
+ entry->data = data;
+ list_add(&entry->list, &eeprom_page_list);
- list_for_each_safe(head, next, &page_list) {
- entry = ((struct page_entry *)head)->page;
- if (entry == page) {
- list_del(head);
- free(head);
- page_free(entry);
- break;
- }
- }
+ return 0;
}
-static void cache_free(void)
+static void eeprom_page_list_flush(void)
{
- struct ethtool_module_eeprom *entry;
+ struct eeprom_page_entry *entry;
struct list_head *head, *next;
- list_for_each_safe(head, next, &page_list) {
- entry = ((struct page_entry *)head)->page;
+ list_for_each_safe(head, next, &eeprom_page_list) {
+ entry = (struct eeprom_page_entry *) head;
+ free(entry->data);
list_del(head);
- free(head);
- page_free(entry);
+ free(entry);
}
}
-static struct ethtool_module_eeprom *page_join(struct ethtool_module_eeprom *page_a,
- struct ethtool_module_eeprom *page_b)
-{
- struct ethtool_module_eeprom *joined_page;
- u32 total_length;
-
- if (!page_a || !page_b ||
- page_a->page != page_b->page ||
- page_a->bank != page_b->bank ||
- page_a->i2c_address != page_b->i2c_address)
- return NULL;
-
- total_length = page_a->length + page_b->length;
- joined_page = calloc(1, sizeof(*joined_page));
- joined_page->data = calloc(1, total_length);
- joined_page->page = page_a->page;
- joined_page->bank = page_a->bank;
- joined_page->length = total_length;
- joined_page->i2c_address = page_a->i2c_address;
-
- if (page_a->offset < page_b->offset) {
- memcpy(joined_page->data, page_a->data, page_a->length);
- memcpy(joined_page->data + page_a->length, page_b->data, page_b->length);
- joined_page->offset = page_a->offset;
- } else {
- memcpy(joined_page->data, page_b->data, page_b->length);
- memcpy(joined_page->data + page_b->length, page_a->data, page_a->length);
- joined_page->offset = page_b->offset;
- }
-
- return joined_page;
-}
-
-static struct ethtool_module_eeprom *cache_get(u32 page, u32 bank, u8 i2c_address)
-{
- struct ethtool_module_eeprom *entry;
- struct list_head *head, *next;
-
- list_for_each_safe(head, next, &page_list) {
- entry = ((struct page_entry *)head)->page;
- if (entry->page == page && entry->bank == bank &&
- entry->i2c_address == i2c_address)
- return entry;
- }
-
- return NULL;
-}
-
-static int getmodule_page_fetch_reply_cb(const struct nlmsghdr *nlhdr,
- void *data)
+static int get_eeprom_page_reply_cb(const struct nlmsghdr *nlhdr, void *data)
{
const struct nlattr *tb[ETHTOOL_A_MODULE_EEPROM_DATA + 1] = {};
+ struct ethtool_module_eeprom *request = data;
DECLARE_ATTR_TB_INFO(tb);
- struct ethtool_module_eeprom *lower_page;
- struct ethtool_module_eeprom *response;
- struct ethtool_module_eeprom *request;
- struct ethtool_module_eeprom *joined;
u8 *eeprom_data;
int ret;
@@ -199,156 +123,122 @@ static int getmodule_page_fetch_reply_cb(const struct nlmsghdr *nlhdr,
if (ret < 0)
return ret;
- if (!tb[ETHTOOL_A_MODULE_EEPROM_DATA]) {
- fprintf(stderr, "Malformed netlink message (getmodule)\n");
+ if (!tb[ETHTOOL_A_MODULE_EEPROM_DATA])
return MNL_CB_ERROR;
- }
- response = calloc(1, sizeof(*response));
- if (!response)
- return -ENOMEM;
-
- request = (struct ethtool_module_eeprom *)data;
- response->offset = request->offset;
- response->page = request->page;
- response->bank = request->bank;
- response->i2c_address = request->i2c_address;
- response->length = mnl_attr_get_payload_len(tb[ETHTOOL_A_MODULE_EEPROM_DATA]);
eeprom_data = mnl_attr_get_payload(tb[ETHTOOL_A_MODULE_EEPROM_DATA]);
+ request->data = malloc(request->length);
+ if (!request->data)
+ return MNL_CB_ERROR;
+ memcpy(request->data, eeprom_data, request->length);
- response->data = malloc(response->length);
- if (!response->data) {
- free(response);
- return -ENOMEM;
- }
- memcpy(response->data, eeprom_data, response->length);
-
- if (!request->page) {
- lower_page = cache_get(request->page, request->bank, response->i2c_address);
- if (lower_page) {
- joined = page_join(lower_page, response);
- page_free(response);
- cache_del(lower_page);
- return cache_add(joined);
- }
- }
+ ret = eeprom_page_list_add(request->data);
+ if (ret < 0)
+ goto err_list_add;
- return cache_add(response);
+ return MNL_CB_OK;
+
+err_list_add:
+ free(request->data);
+ return MNL_CB_ERROR;
}
-static int page_fetch(struct nl_context *nlctx, const struct ethtool_module_eeprom *request)
+int nl_get_eeprom_page(struct cmd_context *ctx,
+ struct ethtool_module_eeprom *request)
{
- struct nl_socket *nlsock = nlctx->ethnl_socket;
- struct nl_msg_buff *msg = &nlsock->msgbuff;
- struct ethtool_module_eeprom *page;
+ struct nl_context *nlctx = ctx->nlctx;
+ struct nl_socket *nlsock;
+ struct nl_msg_buff *msg;
int ret;
if (!request || request->i2c_address > ETH_I2C_MAX_ADDRESS)
return -EINVAL;
- /* Satisfy request right away, if region is already in cache */
- page = cache_get(request->page, request->bank, request->i2c_address);
- if (page && page->offset <= request->offset &&
- page->offset + page->length >= request->offset + request->length) {
- return 0;
- }
+ nlsock = nlctx->ethnl_socket;
+ msg = &nlsock->msgbuff;
ret = nlsock_prep_get_request(nlsock, ETHTOOL_MSG_MODULE_EEPROM_GET,
ETHTOOL_A_MODULE_EEPROM_HEADER, 0);
if (ret < 0)
return ret;
- if (ethnla_put_u32(msg, ETHTOOL_A_MODULE_EEPROM_LENGTH, request->length) ||
- ethnla_put_u32(msg, ETHTOOL_A_MODULE_EEPROM_OFFSET, request->offset) ||
- ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_PAGE, request->page) ||
- ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_BANK, request->bank) ||
- ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS, request->i2c_address))
+ if (ethnla_put_u32(msg, ETHTOOL_A_MODULE_EEPROM_LENGTH,
+ request->length) ||
+ ethnla_put_u32(msg, ETHTOOL_A_MODULE_EEPROM_OFFSET,
+ request->offset) ||
+ ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_PAGE,
+ request->page) ||
+ ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_BANK,
+ request->bank) ||
+ ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS,
+ request->i2c_address))
return -EMSGSIZE;
ret = nlsock_sendmsg(nlsock, NULL);
if (ret < 0)
return ret;
- ret = nlsock_process_reply(nlsock, getmodule_page_fetch_reply_cb, (void *)request);
- if (ret < 0)
- return ret;
-
- return nlsock_process_reply(nlsock, nomsg_reply_cb, NULL);
+ return nlsock_process_reply(nlsock, get_eeprom_page_reply_cb,
+ (void *)request);
}
-#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
-static int decoder_prefetch(struct nl_context *nlctx)
+static int eeprom_dump_hex(struct cmd_context *ctx)
{
- struct ethtool_module_eeprom *page_zero_lower = cache_get(0, 0, ETH_I2C_ADDRESS_LOW);
- struct ethtool_module_eeprom request = {0};
- u8 module_id = page_zero_lower->data[0];
- int err = 0;
-
- /* Fetch rest of page 00 */
- request.i2c_address = ETH_I2C_ADDRESS_LOW;
- request.offset = 128;
- request.length = 128;
- err = page_fetch(nlctx, &request);
- if (err)
- return err;
-
- switch (module_id) {
- case SFF8024_ID_QSFP:
- case SFF8024_ID_QSFP28:
- case SFF8024_ID_QSFP_PLUS:
- memset(&request, 0, sizeof(request));
- request.i2c_address = ETH_I2C_ADDRESS_LOW;
- request.offset = 128;
- request.length = 128;
- request.page = 3;
- break;
- case SFF8024_ID_QSFP_DD:
- case SFF8024_ID_DSFP:
- memset(&request, 0, sizeof(request));
- request.i2c_address = ETH_I2C_ADDRESS_LOW;
- request.offset = 128;
- request.length = 128;
- request.page = 1;
- break;
- }
+ struct ethtool_module_eeprom request = {
+ .length = 128,
+ .i2c_address = ETH_I2C_ADDRESS_LOW,
+ };
+ int ret;
+
+ ret = nl_get_eeprom_page(ctx, &request);
+ if (ret < 0)
+ return ret;
+
+ dump_hex(stdout, request.data, request.length, request.offset);
- return page_fetch(nlctx, &request);
+ return 0;
}
-static void decoder_print(void)
+static int eeprom_parse(struct cmd_context *ctx)
{
- struct ethtool_module_eeprom *page_three = cache_get(3, 0, ETH_I2C_ADDRESS_LOW);
- struct ethtool_module_eeprom *page_zero = cache_get(0, 0, ETH_I2C_ADDRESS_LOW);
- struct ethtool_module_eeprom *page_one = cache_get(1, 0, ETH_I2C_ADDRESS_LOW);
- u8 module_id = page_zero->data[SFF8636_ID_OFFSET];
+ struct ethtool_module_eeprom request = {
+ .length = 1,
+ .i2c_address = ETH_I2C_ADDRESS_LOW,
+ };
+ int ret;
- switch (module_id) {
+ /* Fetch the SFF-8024 Identifier Value. For all supported standards, it
+ * is located at I2C address 0x50, byte 0. See section 4.1 in SFF-8024,
+ * revision 4.9.
+ */
+ ret = nl_get_eeprom_page(ctx, &request);
+ if (ret < 0)
+ return ret;
+
+ switch (request.data[0]) {
+#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
case SFF8024_ID_SFP:
- sff8079_show_all(page_zero->data);
- break;
+ return sff8079_show_all_nl(ctx);
case SFF8024_ID_QSFP:
case SFF8024_ID_QSFP28:
case SFF8024_ID_QSFP_PLUS:
- sff8636_show_all_paged(page_zero, page_three);
- break;
+ return sff8636_show_all_nl(ctx);
case SFF8024_ID_QSFP_DD:
case SFF8024_ID_DSFP:
- cmis_show_all(page_zero, page_one);
- break;
+ return cmis_show_all_nl(ctx);
+#endif
default:
- dump_hex(stdout, page_zero->data, page_zero->length, page_zero->offset);
- break;
+ /* If we cannot recognize the memory map, default to dumping
+ * the first 128 bytes in hex.
+ */
+ return eeprom_dump_hex(ctx);
}
}
-#endif
int nl_getmodule(struct cmd_context *ctx)
{
struct cmd_params getmodule_cmd_params = {};
struct ethtool_module_eeprom request = {0};
- struct ethtool_module_eeprom *reply_page;
struct nl_context *nlctx = ctx->nlctx;
- u32 dump_length;
- u8 *eeprom_data;
int ret;
if (netlink_cmd_check(ctx, ETHTOOL_MSG_MODULE_EEPROM_GET, false))
@@ -377,12 +267,6 @@ int nl_getmodule(struct cmd_context *ctx)
return -EOPNOTSUPP;
}
- request.i2c_address = ETH_I2C_ADDRESS_LOW;
- request.length = 128;
- ret = page_fetch(nlctx, &request);
- if (ret)
- goto cleanup;
-
#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
if (getmodule_cmd_params.page || getmodule_cmd_params.bank ||
getmodule_cmd_params.offset || getmodule_cmd_params.length)
@@ -399,32 +283,22 @@ int nl_getmodule(struct cmd_context *ctx)
request.offset = 128;
if (getmodule_cmd_params.dump_hex || getmodule_cmd_params.dump_raw) {
- ret = page_fetch(nlctx, &request);
+ ret = nl_get_eeprom_page(ctx, &request);
if (ret < 0)
goto cleanup;
- reply_page = cache_get(request.page, request.bank, request.i2c_address);
- if (!reply_page) {
- ret = -EINVAL;
- goto cleanup;
- }
- eeprom_data = reply_page->data + (request.offset - reply_page->offset);
- dump_length = reply_page->length < request.length ? reply_page->length
- : request.length;
if (getmodule_cmd_params.dump_raw)
- fwrite(eeprom_data, 1, request.length, stdout);
+ fwrite(request.data, 1, request.length, stdout);
else
- dump_hex(stdout, eeprom_data, dump_length, request.offset);
+ dump_hex(stdout, request.data, request.length,
+ request.offset);
} else {
-#ifdef ETHTOOL_ENABLE_PRETTY_DUMP
- ret = decoder_prefetch(nlctx);
- if (ret)
+ ret = eeprom_parse(ctx);
+ if (ret < 0)
goto cleanup;
- decoder_print();
-#endif
}
cleanup:
- cache_free();
+ eeprom_page_list_flush();
return ret;
}
diff --git a/qsfp.c b/qsfp.c
index 3f37f10..e7c2f51 100644
--- a/qsfp.c
+++ b/qsfp.c
@@ -55,10 +55,22 @@
**/
#include <stdio.h>
#include <math.h>
+#include <errno.h>
#include "internal.h"
#include "sff-common.h"
#include "qsfp.h"
#include "cmis.h"
+#include "netlink/extapi.h"
+
+struct sff8636_memory_map {
+ const __u8 *lower_memory;
+ const __u8 *upper_memory[4];
+#define page_00h upper_memory[0x0]
+#define page_03h upper_memory[0x3]
+};
+
+#define SFF8636_PAGE_SIZE 0x80
+#define SFF8636_I2C_ADDRESS 0x50
#define MAX_DESC_SIZE 42
@@ -196,20 +208,21 @@ static struct sff8636_aw_flags {
{ NULL, 0, 0 },
};
-static void sff8636_show_identifier(const __u8 *id)
+static void sff8636_show_identifier(const struct sff8636_memory_map *map)
{
- sff8024_show_identifier(id, SFF8636_ID_OFFSET);
+ sff8024_show_identifier(map->lower_memory, SFF8636_ID_OFFSET);
}
-static void sff8636_show_ext_identifier(const __u8 *id)
+static void sff8636_show_ext_identifier(const struct sff8636_memory_map *map)
{
printf("\t%-41s : 0x%02x\n", "Extended identifier",
- id[SFF8636_EXT_ID_OFFSET]);
+ map->page_00h[SFF8636_EXT_ID_OFFSET]);
static const char *pfx =
"\tExtended identifier description :";
- switch (id[SFF8636_EXT_ID_OFFSET] & SFF8636_EXT_ID_PWR_CLASS_MASK) {
+ switch (map->page_00h[SFF8636_EXT_ID_OFFSET] &
+ SFF8636_EXT_ID_PWR_CLASS_MASK) {
case SFF8636_EXT_ID_PWR_CLASS_1:
printf("%s 1.5W max. Power consumption\n", pfx);
break;
@@ -224,17 +237,18 @@ static void sff8636_show_ext_identifier(const __u8 *id)
break;
}
- if (id[SFF8636_EXT_ID_OFFSET] & SFF8636_EXT_ID_CDR_TX_MASK)
+ if (map->page_00h[SFF8636_EXT_ID_OFFSET] & SFF8636_EXT_ID_CDR_TX_MASK)
printf("%s CDR present in TX,", pfx);
else
printf("%s No CDR in TX,", pfx);
- if (id[SFF8636_EXT_ID_OFFSET] & SFF8636_EXT_ID_CDR_RX_MASK)
+ if (map->page_00h[SFF8636_EXT_ID_OFFSET] & SFF8636_EXT_ID_CDR_RX_MASK)
printf(" CDR present in RX\n");
else
printf(" No CDR in RX\n");
- switch (id[SFF8636_EXT_ID_OFFSET] & SFF8636_EXT_ID_EPWR_CLASS_MASK) {
+ switch (map->page_00h[SFF8636_EXT_ID_OFFSET] &
+ SFF8636_EXT_ID_EPWR_CLASS_MASK) {
case SFF8636_EXT_ID_PWR_CLASS_LEGACY:
printf("%s", pfx);
break;
@@ -248,18 +262,19 @@ static void sff8636_show_ext_identifier(const __u8 *id)
printf("%s 5.0W max. Power consumption, ", pfx);
break;
}
- if (id[SFF8636_PWR_MODE_OFFSET] & SFF8636_HIGH_PWR_ENABLE)
+ if (map->lower_memory[SFF8636_PWR_MODE_OFFSET] &
+ SFF8636_HIGH_PWR_ENABLE)
printf(" High Power Class (> 3.5 W) enabled\n");
else
printf(" High Power Class (> 3.5 W) not enabled\n");
}
-static void sff8636_show_connector(const __u8 *id)
+static void sff8636_show_connector(const struct sff8636_memory_map *map)
{
- sff8024_show_connector(id, SFF8636_CTOR_OFFSET);
+ sff8024_show_connector(map->page_00h, SFF8636_CTOR_OFFSET);
}
-static void sff8636_show_transceiver(const __u8 *id)
+static void sff8636_show_transceiver(const struct sff8636_memory_map *map)
{
static const char *pfx =
"\tTransceiver type :";
@@ -267,33 +282,41 @@ static void sff8636_show_transceiver(const __u8 *id)
printf("\t%-41s : 0x%02x 0x%02x 0x%02x " \
"0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
"Transceiver codes",
- id[SFF8636_ETHERNET_COMP_OFFSET],
- id[SFF8636_SONET_COMP_OFFSET],
- id[SFF8636_SAS_COMP_OFFSET],
- id[SFF8636_GIGE_COMP_OFFSET],
- id[SFF8636_FC_LEN_OFFSET],
- id[SFF8636_FC_TECH_OFFSET],
- id[SFF8636_FC_TRANS_MEDIA_OFFSET],
- id[SFF8636_FC_SPEED_OFFSET]);
+ map->page_00h[SFF8636_ETHERNET_COMP_OFFSET],
+ map->page_00h[SFF8636_SONET_COMP_OFFSET],
+ map->page_00h[SFF8636_SAS_COMP_OFFSET],
+ map->page_00h[SFF8636_GIGE_COMP_OFFSET],
+ map->page_00h[SFF8636_FC_LEN_OFFSET],
+ map->page_00h[SFF8636_FC_TECH_OFFSET],
+ map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET],
+ map->page_00h[SFF8636_FC_SPEED_OFFSET]);
/* 10G/40G Ethernet Compliance Codes */
- if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_10G_LRM)
+ if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
+ SFF8636_ETHERNET_10G_LRM)
printf("%s 10G Ethernet: 10G Base-LRM\n", pfx);
- if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_10G_LR)
+ if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
+ SFF8636_ETHERNET_10G_LR)
printf("%s 10G Ethernet: 10G Base-LR\n", pfx);
- if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_10G_SR)
+ if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
+ SFF8636_ETHERNET_10G_SR)
printf("%s 10G Ethernet: 10G Base-SR\n", pfx);
- if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_40G_CR4)
+ if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
+ SFF8636_ETHERNET_40G_CR4)
printf("%s 40G Ethernet: 40G Base-CR4\n", pfx);
- if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_40G_SR4)
+ if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
+ SFF8636_ETHERNET_40G_SR4)
printf("%s 40G Ethernet: 40G Base-SR4\n", pfx);
- if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_40G_LR4)
+ if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
+ SFF8636_ETHERNET_40G_LR4)
printf("%s 40G Ethernet: 40G Base-LR4\n", pfx);
- if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_40G_ACTIVE)
+ if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
+ SFF8636_ETHERNET_40G_ACTIVE)
printf("%s 40G Ethernet: 40G Active Cable (XLPPI)\n", pfx);
/* Extended Specification Compliance Codes from SFF-8024 */
- if (id[SFF8636_ETHERNET_COMP_OFFSET] & SFF8636_ETHERNET_RSRVD) {
- switch (id[SFF8636_OPTION_1_OFFSET]) {
+ if (map->page_00h[SFF8636_ETHERNET_COMP_OFFSET] &
+ SFF8636_ETHERNET_RSRVD) {
+ switch (map->page_00h[SFF8636_OPTION_1_OFFSET]) {
case SFF8636_ETHERNET_UNSPECIFIED:
printf("%s (reserved or unknown)\n", pfx);
break;
@@ -484,113 +507,122 @@ static void sff8636_show_transceiver(const __u8 *id)
}
/* SONET Compliance Codes */
- if (id[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_40G_OTN))
+ if (map->page_00h[SFF8636_SONET_COMP_OFFSET] &
+ (SFF8636_SONET_40G_OTN))
printf("%s 40G OTN (OTU3B/OTU3C)\n", pfx);
- if (id[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_OC48_LR))
+ if (map->page_00h[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_OC48_LR))
printf("%s SONET: OC-48, long reach\n", pfx);
- if (id[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_OC48_IR))
+ if (map->page_00h[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_OC48_IR))
printf("%s SONET: OC-48, intermediate reach\n", pfx);
- if (id[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_OC48_SR))
+ if (map->page_00h[SFF8636_SONET_COMP_OFFSET] & (SFF8636_SONET_OC48_SR))
printf("%s SONET: OC-48, short reach\n", pfx);
/* SAS/SATA Compliance Codes */
- if (id[SFF8636_SAS_COMP_OFFSET] & (SFF8636_SAS_6G))
+ if (map->page_00h[SFF8636_SAS_COMP_OFFSET] & (SFF8636_SAS_6G))
printf("%s SAS 6.0G\n", pfx);
- if (id[SFF8636_SAS_COMP_OFFSET] & (SFF8636_SAS_3G))
+ if (map->page_00h[SFF8636_SAS_COMP_OFFSET] & (SFF8636_SAS_3G))
printf("%s SAS 3.0G\n", pfx);
/* Ethernet Compliance Codes */
- if (id[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_T)
+ if (map->page_00h[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_T)
printf("%s Ethernet: 1000BASE-T\n", pfx);
- if (id[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_CX)
+ if (map->page_00h[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_CX)
printf("%s Ethernet: 1000BASE-CX\n", pfx);
- if (id[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_LX)
+ if (map->page_00h[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_LX)
printf("%s Ethernet: 1000BASE-LX\n", pfx);
- if (id[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_SX)
+ if (map->page_00h[SFF8636_GIGE_COMP_OFFSET] & SFF8636_GIGE_1000_BASE_SX)
printf("%s Ethernet: 1000BASE-SX\n", pfx);
/* Fibre Channel link length */
- if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_VERY_LONG)
+ if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_VERY_LONG)
printf("%s FC: very long distance (V)\n", pfx);
- if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_SHORT)
+ if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_SHORT)
printf("%s FC: short distance (S)\n", pfx);
- if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_INT)
+ if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_INT)
printf("%s FC: intermediate distance (I)\n", pfx);
- if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_LONG)
+ if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_LONG)
printf("%s FC: long distance (L)\n", pfx);
- if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_MED)
+ if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_LEN_MED)
printf("%s FC: medium distance (M)\n", pfx);
/* Fibre Channel transmitter technology */
- if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_TECH_LONG_LC)
+ if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_TECH_LONG_LC)
printf("%s FC: Longwave laser (LC)\n", pfx);
- if (id[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_TECH_ELEC_INTER)
+ if (map->page_00h[SFF8636_FC_LEN_OFFSET] & SFF8636_FC_TECH_ELEC_INTER)
printf("%s FC: Electrical inter-enclosure (EL)\n", pfx);
- if (id[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_ELEC_INTRA)
+ if (map->page_00h[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_ELEC_INTRA)
printf("%s FC: Electrical intra-enclosure (EL)\n", pfx);
- if (id[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_SHORT_WO_OFC)
+ if (map->page_00h[SFF8636_FC_TECH_OFFSET] &
+ SFF8636_FC_TECH_SHORT_WO_OFC)
printf("%s FC: Shortwave laser w/o OFC (SN)\n", pfx);
- if (id[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_SHORT_W_OFC)
+ if (map->page_00h[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_SHORT_W_OFC)
printf("%s FC: Shortwave laser with OFC (SL)\n", pfx);
- if (id[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_LONG_LL)
+ if (map->page_00h[SFF8636_FC_TECH_OFFSET] & SFF8636_FC_TECH_LONG_LL)
printf("%s FC: Longwave laser (LL)\n", pfx);
/* Fibre Channel transmission media */
- if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_TW)
+ if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
+ SFF8636_FC_TRANS_MEDIA_TW)
printf("%s FC: Twin Axial Pair (TW)\n", pfx);
- if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_TP)
+ if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
+ SFF8636_FC_TRANS_MEDIA_TP)
printf("%s FC: Twisted Pair (TP)\n", pfx);
- if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_MI)
+ if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
+ SFF8636_FC_TRANS_MEDIA_MI)
printf("%s FC: Miniature Coax (MI)\n", pfx);
- if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_TV)
+ if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
+ SFF8636_FC_TRANS_MEDIA_TV)
printf("%s FC: Video Coax (TV)\n", pfx);
- if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_M6)
+ if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
+ SFF8636_FC_TRANS_MEDIA_M6)
printf("%s FC: Multimode, 62.5m (M6)\n", pfx);
- if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_M5)
+ if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
+ SFF8636_FC_TRANS_MEDIA_M5)
printf("%s FC: Multimode, 50m (M5)\n", pfx);
- if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_OM3)
+ if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
+ SFF8636_FC_TRANS_MEDIA_OM3)
printf("%s FC: Multimode, 50um (OM3)\n", pfx);
- if (id[SFF8636_FC_TRANS_MEDIA_OFFSET] & SFF8636_FC_TRANS_MEDIA_SM)
+ if (map->page_00h[SFF8636_FC_TRANS_MEDIA_OFFSET] &
+ SFF8636_FC_TRANS_MEDIA_SM)
printf("%s FC: Single Mode (SM)\n", pfx);
/* Fibre Channel speed */
- if (id[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_1200_MBPS)
+ if (map->page_00h[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_1200_MBPS)
printf("%s FC: 1200 MBytes/sec\n", pfx);
- if (id[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_800_MBPS)
+ if (map->page_00h[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_800_MBPS)
printf("%s FC: 800 MBytes/sec\n", pfx);
- if (id[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_1600_MBPS)
+ if (map->page_00h[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_1600_MBPS)
printf("%s FC: 1600 MBytes/sec\n", pfx);
- if (id[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_400_MBPS)
+ if (map->page_00h[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_400_MBPS)
printf("%s FC: 400 MBytes/sec\n", pfx);
- if (id[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_200_MBPS)
+ if (map->page_00h[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_200_MBPS)
printf("%s FC: 200 MBytes/sec\n", pfx);
- if (id[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_100_MBPS)
+ if (map->page_00h[SFF8636_FC_SPEED_OFFSET] & SFF8636_FC_SPEED_100_MBPS)
printf("%s FC: 100 MBytes/sec\n", pfx);
}
-static void sff8636_show_encoding(const __u8 *id)
+static void sff8636_show_encoding(const struct sff8636_memory_map *map)
{
- sff8024_show_encoding(id, SFF8636_ENCODING_OFFSET, ETH_MODULE_SFF_8636);
+ sff8024_show_encoding(map->page_00h, SFF8636_ENCODING_OFFSET,
+ ETH_MODULE_SFF_8636);
}
-static void sff8636_show_rate_identifier(const __u8 *id)
+static void sff8636_show_rate_identifier(const struct sff8636_memory_map *map)
{
/* TODO: Need to fix rate select logic */
printf("\t%-41s : 0x%02x\n", "Rate identifier",
- id[SFF8636_EXT_RS_OFFSET]);
+ map->page_00h[SFF8636_EXT_RS_OFFSET]);
}
-static void sff8636_show_oui(const __u8 *id, int id_offset)
-{
- sff8024_show_oui(id, id_offset);
-}
-
-static void sff8636_show_wavelength_or_copper_compliance(const __u8 *id)
+static void
+sff8636_show_wavelength_or_copper_compliance(const struct sff8636_memory_map *map)
{
printf("\t%-41s : 0x%02x", "Transmitter technology",
- (id[SFF8636_DEVICE_TECH_OFFSET] & SFF8636_TRANS_TECH_MASK));
+ map->page_00h[SFF8636_DEVICE_TECH_OFFSET] &
+ SFF8636_TRANS_TECH_MASK);
- switch (id[SFF8636_DEVICE_TECH_OFFSET] & SFF8636_TRANS_TECH_MASK) {
+ switch (map->page_00h[SFF8636_DEVICE_TECH_OFFSET] &
+ SFF8636_TRANS_TECH_MASK) {
case SFF8636_TRANS_850_VCSEL:
printf(" (850 nm VCSEL)\n");
break;
@@ -641,31 +673,26 @@ static void sff8636_show_wavelength_or_copper_compliance(const __u8 *id)
break;
}
- if ((id[SFF8636_DEVICE_TECH_OFFSET] & SFF8636_TRANS_TECH_MASK)
- >= SFF8636_TRANS_COPPER_PAS_UNEQUAL) {
+ if ((map->page_00h[SFF8636_DEVICE_TECH_OFFSET] &
+ SFF8636_TRANS_TECH_MASK) >= SFF8636_TRANS_COPPER_PAS_UNEQUAL) {
printf("\t%-41s : %udb\n", "Attenuation at 2.5GHz",
- id[SFF8636_WAVELEN_HIGH_BYTE_OFFSET]);
+ map->page_00h[SFF8636_WAVELEN_HIGH_BYTE_OFFSET]);
printf("\t%-41s : %udb\n", "Attenuation at 5.0GHz",
- id[SFF8636_WAVELEN_LOW_BYTE_OFFSET]);
+ map->page_00h[SFF8636_WAVELEN_LOW_BYTE_OFFSET]);
printf("\t%-41s : %udb\n", "Attenuation at 7.0GHz",
- id[SFF8636_WAVE_TOL_HIGH_BYTE_OFFSET]);
+ map->page_00h[SFF8636_WAVE_TOL_HIGH_BYTE_OFFSET]);
printf("\t%-41s : %udb\n", "Attenuation at 12.9GHz",
- id[SFF8636_WAVE_TOL_LOW_BYTE_OFFSET]);
+ map->page_00h[SFF8636_WAVE_TOL_LOW_BYTE_OFFSET]);
} else {
printf("\t%-41s : %.3lfnm\n", "Laser wavelength",
- (((id[SFF8636_WAVELEN_HIGH_BYTE_OFFSET] << 8) |
- id[SFF8636_WAVELEN_LOW_BYTE_OFFSET])*0.05));
+ (((map->page_00h[SFF8636_WAVELEN_HIGH_BYTE_OFFSET] << 8) |
+ map->page_00h[SFF8636_WAVELEN_LOW_BYTE_OFFSET]) * 0.05));
printf("\t%-41s : %.3lfnm\n", "Laser wavelength tolerance",
- (((id[SFF8636_WAVE_TOL_HIGH_BYTE_OFFSET] << 8) |
- id[SFF8636_WAVE_TOL_LOW_BYTE_OFFSET])*0.005));
+ (((map->page_00h[SFF8636_WAVE_TOL_HIGH_BYTE_OFFSET] << 8) |
+ map->page_00h[SFF8636_WAVE_TOL_LOW_BYTE_OFFSET]) * 0.005));
}
}
-static void sff8636_show_revision_compliance(const __u8 *id)
-{
- sff_show_revision_compliance(id, SFF8636_REV_COMPLIANCE_OFFSET);
-}
-
/*
* 2-byte internal temperature conversions:
* First byte is a signed 8-bit integer, which is the temp decimal part
@@ -674,39 +701,65 @@ static void sff8636_show_revision_compliance(const __u8 *id)
#define SFF8636_OFFSET_TO_TEMP(offset) ((__s16)OFFSET_TO_U16(offset))
#define OFFSET_TO_U16_PTR(ptr, offset) (ptr[offset] << 8 | ptr[(offset) + 1])
-static void sff8636_dom_parse(const __u8 *id, const __u8 *page_three, struct sff_diags *sd)
+static void sff8636_dom_parse(const struct sff8636_memory_map *map,
+ struct sff_diags *sd)
{
+ const __u8 *id = map->lower_memory;
int i = 0;
/* Monitoring Thresholds for Alarms and Warnings */
sd->sfp_voltage[MCURR] = OFFSET_TO_U16_PTR(id, SFF8636_VCC_CURR);
- sd->sfp_voltage[HALRM] = OFFSET_TO_U16_PTR(page_three, SFF8636_VCC_HALRM);
- sd->sfp_voltage[LALRM] = OFFSET_TO_U16_PTR(page_three, SFF8636_VCC_LALRM);
- sd->sfp_voltage[HWARN] = OFFSET_TO_U16_PTR(page_three, SFF8636_VCC_HWARN);
- sd->sfp_voltage[LWARN] = OFFSET_TO_U16_PTR(page_three, SFF8636_VCC_LWARN);
-
sd->sfp_temp[MCURR] = SFF8636_OFFSET_TO_TEMP(SFF8636_TEMP_CURR);
- sd->sfp_temp[HALRM] = (__s16)OFFSET_TO_U16_PTR(page_three, SFF8636_TEMP_HALRM);
- sd->sfp_temp[LALRM] = (__s16)OFFSET_TO_U16_PTR(page_three, SFF8636_TEMP_LALRM);
- sd->sfp_temp[HWARN] = (__s16)OFFSET_TO_U16_PTR(page_three, SFF8636_TEMP_HWARN);
- sd->sfp_temp[LWARN] = (__s16)OFFSET_TO_U16_PTR(page_three, SFF8636_TEMP_LWARN);
-
- sd->bias_cur[HALRM] = OFFSET_TO_U16_PTR(page_three, SFF8636_TX_BIAS_HALRM);
- sd->bias_cur[LALRM] = OFFSET_TO_U16_PTR(page_three, SFF8636_TX_BIAS_LALRM);
- sd->bias_cur[HWARN] = OFFSET_TO_U16_PTR(page_three, SFF8636_TX_BIAS_HWARN);
- sd->bias_cur[LWARN] = OFFSET_TO_U16_PTR(page_three, SFF8636_TX_BIAS_LWARN);
-
- sd->tx_power[HALRM] = OFFSET_TO_U16_PTR(page_three, SFF8636_TX_PWR_HALRM);
- sd->tx_power[LALRM] = OFFSET_TO_U16_PTR(page_three, SFF8636_TX_PWR_LALRM);
- sd->tx_power[HWARN] = OFFSET_TO_U16_PTR(page_three, SFF8636_TX_PWR_HWARN);
- sd->tx_power[LWARN] = OFFSET_TO_U16_PTR(page_three, SFF8636_TX_PWR_LWARN);
-
- sd->rx_power[HALRM] = OFFSET_TO_U16_PTR(page_three, SFF8636_RX_PWR_HALRM);
- sd->rx_power[LALRM] = OFFSET_TO_U16_PTR(page_three, SFF8636_RX_PWR_LALRM);
- sd->rx_power[HWARN] = OFFSET_TO_U16_PTR(page_three, SFF8636_RX_PWR_HWARN);
- sd->rx_power[LWARN] = OFFSET_TO_U16_PTR(page_three, SFF8636_RX_PWR_LWARN);
-
+ if (!map->page_03h)
+ goto out;
+
+ sd->sfp_voltage[HALRM] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_VCC_HALRM);
+ sd->sfp_voltage[LALRM] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_VCC_LALRM);
+ sd->sfp_voltage[HWARN] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_VCC_HWARN);
+ sd->sfp_voltage[LWARN] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_VCC_LWARN);
+
+ sd->sfp_temp[HALRM] = (__s16)OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_TEMP_HALRM);
+ sd->sfp_temp[LALRM] = (__s16)OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_TEMP_LALRM);
+ sd->sfp_temp[HWARN] = (__s16)OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_TEMP_HWARN);
+ sd->sfp_temp[LWARN] = (__s16)OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_TEMP_LWARN);
+
+ sd->bias_cur[HALRM] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_TX_BIAS_HALRM);
+ sd->bias_cur[LALRM] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_TX_BIAS_LALRM);
+ sd->bias_cur[HWARN] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_TX_BIAS_HWARN);
+ sd->bias_cur[LWARN] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_TX_BIAS_LWARN);
+
+ sd->tx_power[HALRM] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_TX_PWR_HALRM);
+ sd->tx_power[LALRM] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_TX_PWR_LALRM);
+ sd->tx_power[HWARN] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_TX_PWR_HWARN);
+ sd->tx_power[LWARN] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_TX_PWR_LWARN);
+
+ sd->rx_power[HALRM] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_RX_PWR_HALRM);
+ sd->rx_power[LALRM] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_RX_PWR_LALRM);
+ sd->rx_power[HWARN] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_RX_PWR_HWARN);
+ sd->rx_power[LWARN] = OFFSET_TO_U16_PTR(map->page_03h,
+ SFF8636_RX_PWR_LWARN);
+
+out:
/* Channel Specific Data */
for (i = 0; i < MAX_CHANNEL_NUM; i++) {
u8 rx_power_offset, tx_bias_offset;
@@ -740,7 +793,7 @@ static void sff8636_dom_parse(const __u8 *id, const __u8 *page_three, struct sff
}
}
-static void sff8636_show_dom(const __u8 *id, const __u8 *page_three, __u32 eeprom_len)
+static void sff8636_show_dom(const struct sff8636_memory_map *map)
{
struct sff_diags sd = {0};
char *rx_power_string = NULL;
@@ -754,20 +807,15 @@ static void sff8636_show_dom(const __u8 *id, const __u8 *page_three, __u32 eepro
* and thresholds
* If pagging support exists, then supports_alarms is marked as 1
*/
+ if (map->page_03h)
+ sd.supports_alarms = 1;
- if (eeprom_len == ETH_MODULE_SFF_8636_MAX_LEN) {
- if (!(id[SFF8636_STATUS_2_OFFSET] &
- SFF8636_STATUS_PAGE_3_PRESENT)) {
- sd.supports_alarms = 1;
- }
- }
-
- sd.rx_power_type = id[SFF8636_DIAG_TYPE_OFFSET] &
- SFF8636_RX_PWR_TYPE_MASK;
- sd.tx_power_type = id[SFF8636_DIAG_TYPE_OFFSET] &
- SFF8636_RX_PWR_TYPE_MASK;
+ sd.rx_power_type = map->page_00h[SFF8636_DIAG_TYPE_OFFSET] &
+ SFF8636_RX_PWR_TYPE_MASK;
+ sd.tx_power_type = map->page_00h[SFF8636_DIAG_TYPE_OFFSET] &
+ SFF8636_RX_PWR_TYPE_MASK;
- sff8636_dom_parse(id, page_three, &sd);
+ sff8636_dom_parse(map, &sd);
PRINT_TEMP("Module temperature", sd.sfp_temp[MCURR]);
PRINT_VCC("Module voltage", sd.sfp_voltage[MCURR]);
@@ -810,7 +858,7 @@ static void sff8636_show_dom(const __u8 *id, const __u8 *page_three, __u32 eepro
if (sd.supports_alarms) {
for (i = 0; sff8636_aw_flags[i].str; ++i) {
printf("\t%-41s : %s\n", sff8636_aw_flags[i].str,
- id[sff8636_aw_flags[i].offset]
+ map->lower_memory[sff8636_aw_flags[i].offset]
& sff8636_aw_flags[i].value ? "On" : "Off");
}
@@ -818,65 +866,151 @@ static void sff8636_show_dom(const __u8 *id, const __u8 *page_three, __u32 eepro
}
}
-static void sff8636_show_page_zero(const __u8 *id)
+static void sff8636_show_page_zero(const struct sff8636_memory_map *map)
{
- sff8636_show_ext_identifier(id);
- sff8636_show_connector(id);
- sff8636_show_transceiver(id);
- sff8636_show_encoding(id);
- sff_show_value_with_unit(id, SFF8636_BR_NOMINAL_OFFSET,
- "BR, Nominal", 100, "Mbps");
- sff8636_show_rate_identifier(id);
- sff_show_value_with_unit(id, SFF8636_SM_LEN_OFFSET,
- "Length (SMF,km)", 1, "km");
- sff_show_value_with_unit(id, SFF8636_OM3_LEN_OFFSET,
- "Length (OM3 50um)", 2, "m");
- sff_show_value_with_unit(id, SFF8636_OM2_LEN_OFFSET,
- "Length (OM2 50um)", 1, "m");
- sff_show_value_with_unit(id, SFF8636_OM1_LEN_OFFSET,
- "Length (OM1 62.5um)", 1, "m");
- sff_show_value_with_unit(id, SFF8636_CBL_LEN_OFFSET,
- "Length (Copper or Active cable)", 1, "m");
- sff8636_show_wavelength_or_copper_compliance(id);
- sff_show_ascii(id, SFF8636_VENDOR_NAME_START_OFFSET,
+ sff8636_show_ext_identifier(map);
+ sff8636_show_connector(map);
+ sff8636_show_transceiver(map);
+ sff8636_show_encoding(map);
+ sff_show_value_with_unit(map->page_00h, SFF8636_BR_NOMINAL_OFFSET,
+ "BR, Nominal", 100, "Mbps");
+ sff8636_show_rate_identifier(map);
+ sff_show_value_with_unit(map->page_00h, SFF8636_SM_LEN_OFFSET,
+ "Length (SMF,km)", 1, "km");
+ sff_show_value_with_unit(map->page_00h, SFF8636_OM3_LEN_OFFSET,
+ "Length (OM3 50um)", 2, "m");
+ sff_show_value_with_unit(map->page_00h, SFF8636_OM2_LEN_OFFSET,
+ "Length (OM2 50um)", 1, "m");
+ sff_show_value_with_unit(map->page_00h, SFF8636_OM1_LEN_OFFSET,
+ "Length (OM1 62.5um)", 1, "m");
+ sff_show_value_with_unit(map->page_00h, SFF8636_CBL_LEN_OFFSET,
+ "Length (Copper or Active cable)", 1, "m");
+ sff8636_show_wavelength_or_copper_compliance(map);
+ sff_show_ascii(map->page_00h, SFF8636_VENDOR_NAME_START_OFFSET,
SFF8636_VENDOR_NAME_END_OFFSET, "Vendor name");
- sff8636_show_oui(id, SFF8636_VENDOR_OUI_OFFSET);
- sff_show_ascii(id, SFF8636_VENDOR_PN_START_OFFSET,
+ sff8024_show_oui(map->page_00h, SFF8636_VENDOR_OUI_OFFSET);
+ sff_show_ascii(map->page_00h, SFF8636_VENDOR_PN_START_OFFSET,
SFF8636_VENDOR_PN_END_OFFSET, "Vendor PN");
- sff_show_ascii(id, SFF8636_VENDOR_REV_START_OFFSET,
+ sff_show_ascii(map->page_00h, SFF8636_VENDOR_REV_START_OFFSET,
SFF8636_VENDOR_REV_END_OFFSET, "Vendor rev");
- sff_show_ascii(id, SFF8636_VENDOR_SN_START_OFFSET,
+ sff_show_ascii(map->page_00h, SFF8636_VENDOR_SN_START_OFFSET,
SFF8636_VENDOR_SN_END_OFFSET, "Vendor SN");
- sff_show_ascii(id, SFF8636_DATE_YEAR_OFFSET,
+ sff_show_ascii(map->page_00h, SFF8636_DATE_YEAR_OFFSET,
SFF8636_DATE_VENDOR_LOT_OFFSET + 1, "Date code");
- sff8636_show_revision_compliance(id);
-
+ sff_show_revision_compliance(map->lower_memory,
+ SFF8636_REV_COMPLIANCE_OFFSET);
}
-void sff8636_show_all(const __u8 *id, __u32 eeprom_len)
+static void sff8636_show_all_common(const struct sff8636_memory_map *map)
{
- if (id[SFF8636_ID_OFFSET] == SFF8024_ID_QSFP_DD) {
- qsfp_dd_show_all(id);
- return;
- }
-
- sff8636_show_identifier(id);
- switch (id[SFF8636_ID_OFFSET]) {
+ sff8636_show_identifier(map);
+ switch (map->lower_memory[SFF8636_ID_OFFSET]) {
case SFF8024_ID_QSFP:
case SFF8024_ID_QSFP_PLUS:
case SFF8024_ID_QSFP28:
- sff8636_show_page_zero(id);
- sff8636_show_dom(id, id + 3 * 0x80, eeprom_len);
+ sff8636_show_page_zero(map);
+ sff8636_show_dom(map);
break;
}
}
-void sff8636_show_all_paged(const struct ethtool_module_eeprom *page_zero,
- const struct ethtool_module_eeprom *page_three)
+static void sff8636_memory_map_init_buf(struct sff8636_memory_map *map,
+ const __u8 *id, __u32 eeprom_len)
+{
+ /* Lower Memory and Page 00h are always present.
+ *
+ * Offset into Upper Memory is between page size and twice the page
+ * size. Therefore, set the base address of each page to base address
+ * plus page size multiplied by the page number.
+ */
+ map->lower_memory = id;
+ map->page_00h = id;
+
+ /* Page 03h is only present when the module memory model is paged and
+ * not flat and when we got a big enough buffer from the kernel.
+ */
+ if (map->lower_memory[SFF8636_STATUS_2_OFFSET] &
+ SFF8636_STATUS_PAGE_3_PRESENT ||
+ eeprom_len != ETH_MODULE_SFF_8636_MAX_LEN)
+ return;
+
+ map->page_03h = id + 3 * SFF8636_PAGE_SIZE;
+}
+
+void sff8636_show_all_ioctl(const __u8 *id, __u32 eeprom_len)
+{
+ struct sff8636_memory_map map = {};
+
+ if (id[SFF8636_ID_OFFSET] == SFF8024_ID_QSFP_DD) {
+ cmis_show_all_ioctl(id);
+ return;
+ }
+
+ sff8636_memory_map_init_buf(&map, id, eeprom_len);
+ sff8636_show_all_common(&map);
+}
+
+static void sff8636_request_init(struct ethtool_module_eeprom *request, u8 page,
+ u32 offset)
{
- sff8636_show_identifier(page_zero->data);
- sff8636_show_page_zero(page_zero->data);
- if (page_three)
- sff8636_show_dom(page_zero->data, page_three->data - 0x80,
- ETH_MODULE_SFF_8636_MAX_LEN);
+ request->offset = offset;
+ request->length = SFF8636_PAGE_SIZE;
+ request->page = page;
+ request->bank = 0;
+ request->i2c_address = SFF8636_I2C_ADDRESS;
+ request->data = NULL;
+}
+
+static int
+sff8636_memory_map_init_pages(struct cmd_context *ctx,
+ struct sff8636_memory_map *map)
+{
+ struct ethtool_module_eeprom request;
+ int ret;
+
+ /* Lower Memory and Page 00h are always present.
+ *
+ * Offset into Upper Memory is between page size and twice the page
+ * size. Therefore, set the base address of each page to its base
+ * address minus page size.
+ */
+ sff8636_request_init(&request, 0x0, 0);
+ ret = nl_get_eeprom_page(ctx, &request);
+ if (ret < 0)
+ return ret;
+ map->lower_memory = request.data;
+
+ sff8636_request_init(&request, 0x0, SFF8636_PAGE_SIZE);
+ ret = nl_get_eeprom_page(ctx, &request);
+ if (ret < 0)
+ return ret;
+ map->page_00h = request.data - SFF8636_PAGE_SIZE;
+
+ /* Page 03h is only present when the module memory model is paged and
+ * not flat.
+ */
+ if (map->lower_memory[SFF8636_STATUS_2_OFFSET] &
+ SFF8636_STATUS_PAGE_3_PRESENT)
+ return 0;
+
+ sff8636_request_init(&request, 0x3, SFF8636_PAGE_SIZE);
+ ret = nl_get_eeprom_page(ctx, &request);
+ if (ret < 0)
+ return ret;
+ map->page_03h = request.data - SFF8636_PAGE_SIZE;
+
+ return 0;
+}
+
+int sff8636_show_all_nl(struct cmd_context *ctx)
+{
+ struct sff8636_memory_map map = {};
+ int ret;
+
+ ret = sff8636_memory_map_init_pages(ctx, &map);
+ if (ret < 0)
+ return ret;
+ sff8636_show_all_common(&map);
+
+ return 0;
}
diff --git a/sfpid.c b/sfpid.c
index da2b3f4..621d1e8 100644
--- a/sfpid.c
+++ b/sfpid.c
@@ -8,8 +8,13 @@
*/
#include <stdio.h>
+#include <errno.h>
#include "internal.h"
#include "sff-common.h"
+#include "netlink/extapi.h"
+
+#define SFF8079_PAGE_SIZE 0x80
+#define SFF8079_I2C_ADDRESS_LOW 0x50
static void sff8079_show_identifier(const __u8 *id)
{
@@ -396,7 +401,7 @@ static void sff8079_show_options(const __u8 *id)
printf("%s Power level 3 requirement\n", pfx);
}
-void sff8079_show_all(const __u8 *id)
+static void sff8079_show_all_common(const __u8 *id)
{
sff8079_show_identifier(id);
if (((id[0] == 0x02) || (id[0] == 0x03)) && (id[1] == 0x04)) {
@@ -439,3 +444,24 @@ void sff8079_show_all(const __u8 *id)
sff8079_show_ascii(id, 84, 91, "Date code");
}
}
+
+void sff8079_show_all_ioctl(const __u8 *id)
+{
+ sff8079_show_all_common(id);
+}
+
+int sff8079_show_all_nl(struct cmd_context *ctx)
+{
+ struct ethtool_module_eeprom request = {
+ .length = SFF8079_PAGE_SIZE,
+ .i2c_address = SFF8079_I2C_ADDRESS_LOW,
+ };
+ int ret;
+
+ ret = nl_get_eeprom_page(ctx, &request);
+ if (ret < 0)
+ return ret;
+ sff8079_show_all_common(request.data);
+
+ return 0;
+}