diff --git a/patch/kernel/mvebu-dev/402-sfp-display-SFP-module-information.patch b/patch/kernel/mvebu-dev/402-sfp-display-SFP-module-information.patch index ca117290e..cc5d2fa39 100644 --- a/patch/kernel/mvebu-dev/402-sfp-display-SFP-module-information.patch +++ b/patch/kernel/mvebu-dev/402-sfp-display-SFP-module-information.patch @@ -1,18 +1,42 @@ -From e76632d118659347d9261a4470d9f60bfbe0044c Mon Sep 17 00:00:00 2001 +From 88e942a0b703fe54dad925f27f033869e4f10fba Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 13 Sep 2015 01:06:31 +0100 -Subject: sfp: display SFP module information +Subject: [PATCH] net: sfp: display SFP module information [*not for + mainline*] + +Display SFP module information verbosely, splitting the generic parts +into a separate file. Signed-off-by: Russell King --- ---- a/drivers/net/phy/sfp.c -+++ b/drivers/net/phy/sfp.c -@@ -531,6 +531,185 @@ static unsigned int sfp_check(void *buf, - return check; - } + drivers/net/phy/Makefile | 2 +- + drivers/net/phy/sff.c | 114 ++++++++++++++++++++ + drivers/net/phy/sff.h | 16 +++ + drivers/net/phy/sfp.c | 228 +++++++++++++++++++++++++++++++++++++-- + 4 files changed, 349 insertions(+), 11 deletions(-) + create mode 100644 drivers/net/phy/sff.c + create mode 100644 drivers/net/phy/sff.h + +--- a/drivers/net/phy/Makefile ++++ b/drivers/net/phy/Makefile +@@ -26,7 +26,7 @@ obj-$(CONFIG_PHYLIB) += libphy.o -+static const char *sfp_link_len(char *buf, size_t size, unsigned int length, -+ unsigned int multiplier) + obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += mii_timestamper.o + +-obj-$(CONFIG_SFP) += sfp.o ++obj-$(CONFIG_SFP) += sff.o sfp.o + sfp-obj-$(CONFIG_SFP) += sfp-bus.o + obj-y += $(sfp-obj-y) $(sfp-obj-m) + +--- /dev/null ++++ b/drivers/net/phy/sff.c +@@ -0,0 +1,114 @@ ++#include ++#include ++#include "sff.h" ++ ++const char *sff_link_len(char *buf, size_t size, unsigned int length, ++ unsigned int multiplier) +{ + if (length == 0) + return "unsupported/unspecified"; @@ -21,11 +45,11 @@ Signed-off-by: Russell King + *buf++ = '>'; + size -= 1; + length -= 1; -+ } ++ } + -+ length *= multiplier; ++ length *= multiplier; + -+ if (length >= 1000) ++ if (length >= 1000) + snprintf(buf, size, "%u.%0*ukm", + length / 1000, + multiplier > 100 ? 1 : @@ -36,14 +60,125 @@ Signed-off-by: Russell King + + return buf; +} ++EXPORT_SYMBOL_GPL(sff_link_len); + -+struct bitfield { ++const char *sff_bitfield(char *buf, size_t size, ++ const struct sff_bitfield *bits, unsigned int val) ++{ ++ char *p = buf; ++ int n; ++ ++ *p = '\0'; ++ while (bits->mask) { ++ if ((val & bits->mask) == bits->val) { ++ n = snprintf(p, size, "%s%s", ++ buf != p ? ", " : "", ++ bits->str); ++ if (n == size) ++ break; ++ p += n; ++ size -= n; ++ } ++ bits++; ++ } ++ ++ return buf; ++} ++EXPORT_SYMBOL_GPL(sff_bitfield); ++ ++const char *sff_connector(unsigned int connector) ++{ ++ switch (connector) { ++ case SFF8024_CONNECTOR_UNSPEC: ++ return "unknown/unspecified"; ++ case SFF8024_CONNECTOR_SC: ++ return "SC"; ++ case SFF8024_CONNECTOR_FIBERJACK: ++ return "Fiberjack"; ++ case SFF8024_CONNECTOR_LC: ++ return "LC"; ++ case SFF8024_CONNECTOR_MT_RJ: ++ return "MT-RJ"; ++ case SFF8024_CONNECTOR_MU: ++ return "MU"; ++ case SFF8024_CONNECTOR_SG: ++ return "SG"; ++ case SFF8024_CONNECTOR_OPTICAL_PIGTAIL: ++ return "Optical pigtail"; ++ case SFF8024_CONNECTOR_MPO_1X12: ++ return "MPO 1X12"; ++ case SFF8024_CONNECTOR_MPO_2X16: ++ return "MPO 2X16"; ++ case SFF8024_CONNECTOR_HSSDC_II: ++ return "HSSDC II"; ++ case SFF8024_CONNECTOR_COPPER_PIGTAIL: ++ return "Copper pigtail"; ++ case SFF8024_CONNECTOR_RJ45: ++ return "RJ45"; ++ case SFF8024_CONNECTOR_MXC_2X16: ++ return "MXC 2X16"; ++ default: ++ return "unknown"; ++ } ++} ++EXPORT_SYMBOL_GPL(sff_connector); ++ ++const char *sff_encoding(unsigned int encoding) ++{ ++ switch (encoding) { ++ case SFF8024_ENCODING_UNSPEC: ++ return "unspecified"; ++ case SFF8024_ENCODING_8472_64B66B: ++ return "64b66b"; ++ case SFF8024_ENCODING_8B10B: ++ return "8b10b"; ++ case SFF8024_ENCODING_4B5B: ++ return "4b5b"; ++ case SFF8024_ENCODING_NRZ: ++ return "NRZ"; ++ case SFF8024_ENCODING_8472_MANCHESTER: ++ return "MANCHESTER"; ++ default: ++ return "unknown"; ++ } ++} ++EXPORT_SYMBOL_GPL(sff_encoding); ++ ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ b/drivers/net/phy/sff.h +@@ -0,0 +1,16 @@ ++#ifndef SFF_H ++#define SFF_H ++ ++struct sff_bitfield { + unsigned int mask; + unsigned int val; + const char *str; +}; + -+static const struct bitfield sfp_options[] = { ++const char *sff_link_len(char *buf, size_t size, unsigned int length, ++ unsigned int multiplier); ++const char *sff_bitfield(char *buf, size_t size, ++ const struct sff_bitfield *bits, unsigned int val); ++const char *sff_connector(unsigned int connector); ++const char *sff_encoding(unsigned int encoding); ++#endif +--- a/drivers/net/phy/sfp.c ++++ b/drivers/net/phy/sfp.c +@@ -17,6 +17,7 @@ + #include + #include + ++#include "sff.h" + #include "sfp.h" + #include "swphy.h" + +@@ -1363,6 +1364,114 @@ static void sfp_hwmon_exit(struct sfp *s + } + #endif + ++static const struct sff_bitfield sfp_options[] = { + { + .mask = SFP_OPTIONS_HIGH_POWER_LEVEL, + .val = SFP_OPTIONS_HIGH_POWER_LEVEL, @@ -99,7 +234,7 @@ Signed-off-by: Russell King + }, { } +}; + -+static const struct bitfield diagmon[] = { ++static const struct sff_bitfield diagmon[] = { + { + .mask = SFP_DIAGMON_DDM, + .val = SFP_DIAGMON_DDM, @@ -119,159 +254,179 @@ Signed-off-by: Russell King + }, { } +}; + -+static const char *sfp_bitfield(char *out, size_t outsz, const struct bitfield *bits, unsigned int val) ++static const struct sff_bitfield sfp_enhopts[] = { ++ { ++ .mask = SFP_ENHOPTS_ALARMWARN, ++ .val = SFP_ENHOPTS_ALARMWARN, ++ .str = "alarmwarn", ++ }, { ++ .mask = SFP_ENHOPTS_SOFT_TX_DISABLE, ++ .val = SFP_ENHOPTS_SOFT_TX_DISABLE, ++ .str = "soft_tx_dis", ++ }, { ++ .mask = SFP_ENHOPTS_SOFT_TX_FAULT, ++ .val = SFP_ENHOPTS_SOFT_TX_FAULT, ++ .str = "soft_tx_fault", ++ }, { ++ .mask = SFP_ENHOPTS_SOFT_RX_LOS, ++ .val = SFP_ENHOPTS_SOFT_RX_LOS, ++ .str = "soft_rx_los", ++ }, { ++ .mask = SFP_ENHOPTS_SOFT_RATE_SELECT, ++ .val = SFP_ENHOPTS_SOFT_RATE_SELECT, ++ .str = "soft_rs", ++ }, { ++ .mask = SFP_ENHOPTS_APP_SELECT_SFF8079, ++ .val = SFP_ENHOPTS_APP_SELECT_SFF8079, ++ .str = "app_sel", ++ }, { ++ .mask = SFP_ENHOPTS_SOFT_RATE_SFF8431, ++ .val = SFP_ENHOPTS_SOFT_RATE_SFF8431, ++ .str = "soft_r8431", ++ }, { } ++}; ++ + /* Helpers */ + static void sfp_module_tx_disable(struct sfp *sfp) + { +@@ -1664,6 +1773,110 @@ static int sfp_cotsworks_fixup_check(str + return 0; + } + ++static void sfp_print_module_info(struct sfp *sfp, const struct sfp_eeprom_id *id, bool cotsworks) +{ -+ char *p = out; -+ int n; -+ -+ *p = '\0'; -+ while (bits->mask) { -+ if ((val & bits->mask) == bits->val) { -+ n = snprintf(p, outsz, "%s%s", -+ out != p ? ", " : "", -+ bits->str); -+ if (n == outsz) -+ break; -+ p += n; -+ outsz -= n; -+ } -+ bits++; -+ } -+ -+ return out; -+} -+ -+static const char *sfp_connector(unsigned int connector) -+{ -+ switch (connector) { -+ case SFF8024_CONNECTOR_UNSPEC: -+ return "unknown/unspecified"; -+ case SFF8024_CONNECTOR_SC: -+ return "SC"; -+ case SFF8024_CONNECTOR_FIBERJACK: -+ return "Fiberjack"; -+ case SFF8024_CONNECTOR_LC: -+ return "LC"; -+ case SFF8024_CONNECTOR_MT_RJ: -+ return "MT-RJ"; -+ case SFF8024_CONNECTOR_MU: -+ return "MU"; -+ case SFF8024_CONNECTOR_SG: -+ return "SG"; -+ case SFF8024_CONNECTOR_OPTICAL_PIGTAIL: -+ return "Optical pigtail"; -+ case SFF8024_CONNECTOR_HSSDC_II: -+ return "HSSDC II"; -+ case SFF8024_CONNECTOR_COPPER_PIGTAIL: -+ return "Copper pigtail"; -+ default: -+ return "unknown"; -+ } -+} -+ -+static const char *sfp_encoding(unsigned int encoding) -+{ -+ switch (encoding) { -+ case SFF8024_ENCODING_UNSPEC: -+ return "unspecified"; -+ case SFF8024_ENCODING_8472_64B66B: -+ return "64b66b"; -+ case SFF8024_ENCODING_8B10B: -+ return "8b10b"; -+ case SFF8024_ENCODING_4B5B: -+ return "4b5b"; -+ case SFF8024_ENCODING_NRZ: -+ return "NRZ"; -+ case SFF8024_ENCODING_8472_MANCHESTER: -+ return "MANCHESTER"; -+ default: -+ return "unknown"; -+ } -+} -+ -+ - /* hwmon */ - #if IS_ENABLED(CONFIG_HWMON) - static umode_t sfp_hwmon_is_visible(const void *data, -@@ -1670,6 +1849,7 @@ static int sfp_sm_mod_probe(struct sfp * - struct sfp_eeprom_id id; - bool cotsworks_sfbg; - bool cotsworks; ++ unsigned int br_nom, br_min, br_max; ++ char date[9]; + char options[80]; - u8 check; - int ret; - -@@ -1744,6 +1924,73 @@ static int sfp_sm_mod_probe(struct sfp * - (int)sizeof(id.ext.vendor_sn), id.ext.vendor_sn, - (int)sizeof(id.ext.datecode), id.ext.datecode); - -+ dev_info(sfp->dev, " %s connector, encoding %s, nominal bitrate %u.%uGbps +%u%% -%u%%\n", -+ sfp_connector(sfp->id.base.connector), -+ sfp_encoding(sfp->id.base.encoding), -+ sfp->id.base.br_nominal / 10, -+ sfp->id.base.br_nominal % 10, -+ sfp->id.ext.br_max, sfp->id.ext.br_min); -+ dev_info(sfp->dev, " 1000BaseSX%c 1000BaseLX%c 1000BaseCX%c 1000BaseT%c 100BaseTLX%c 1000BaseFX%c BaseBX10%c BasePX%c\n", -+ sfp->id.base.e1000_base_sx ? '+' : '-', -+ sfp->id.base.e1000_base_lx ? '+' : '-', -+ sfp->id.base.e1000_base_cx ? '+' : '-', -+ sfp->id.base.e1000_base_t ? '+' : '-', -+ sfp->id.base.e100_base_lx ? '+' : '-', -+ sfp->id.base.e100_base_fx ? '+' : '-', -+ sfp->id.base.e_base_bx10 ? '+' : '-', -+ sfp->id.base.e_base_px ? '+' : '-'); -+ dev_info(sfp->dev, " 10GBaseSR%c 10GBaseLR%c 10GBaseLRM%c 10GBaseER%c\n", -+ sfp->id.base.e10g_base_sr ? '+' : '-', -+ sfp->id.base.e10g_base_lr ? '+' : '-', -+ sfp->id.base.e10g_base_lrm ? '+' : '-', -+ sfp->id.base.e10g_base_er ? '+' : '-'); + -+ if (!sfp->id.base.sfp_ct_passive && !sfp->id.base.sfp_ct_active && -+ !sfp->id.base.e1000_base_t) { ++ /* Cotsworks also gets the date code wrong. */ ++ date[0] = id->ext.datecode[4 - 2 * cotsworks]; ++ date[1] = id->ext.datecode[5 - 2 * cotsworks]; ++ date[2] = '-'; ++ date[3] = id->ext.datecode[2 + 2 * cotsworks]; ++ date[4] = id->ext.datecode[3 + 2 * cotsworks]; ++ date[5] = '-'; ++ date[6] = id->ext.datecode[0]; ++ date[7] = id->ext.datecode[1]; ++ date[8] = '\0'; ++ ++ if (id->base.br_nominal == 0) { ++ br_min = br_nom = br_max = 0; ++ } else if (id->base.br_nominal == 255) { ++ br_nom = 250 * id->ext.br_max; ++ br_max = br_nom + br_nom * id->ext.br_min / 100; ++ br_min = br_nom - br_nom * id->ext.br_min / 100; ++ } else { ++ br_nom = id->base.br_nominal * 100; ++ br_min = br_nom - id->base.br_nominal * id->ext.br_min; ++ br_max = br_nom + id->base.br_nominal * id->ext.br_max; ++ } ++ ++ dev_info(sfp->dev, "module %.*s %.*s rev %.*s sn %.*s dc %s\n", ++ (int)sizeof(id->base.vendor_name), id->base.vendor_name, ++ (int)sizeof(id->base.vendor_pn), id->base.vendor_pn, ++ (int)sizeof(id->base.vendor_rev), id->base.vendor_rev, ++ (int)sizeof(id->ext.vendor_sn), id->ext.vendor_sn, date); ++ dev_info(sfp->dev, " %s connector, encoding %s, bitrate %u.%03u (%u.%03u-%u.%03u) Gbps\n", ++ sff_connector(id->base.connector), ++ sff_encoding(id->base.encoding), ++ br_nom / 1000, br_nom % 1000, ++ br_min / 1000, br_min % 1000, br_max / 1000, br_max % 1000); ++ dev_info(sfp->dev, " 1000BaseSX%c 1000BaseLX%c 1000BaseCX%c 1000BaseT%c 100BaseLX%c 100BaseFX%c BaseBX10%c BasePX%c\n", ++ id->base.e1000_base_sx ? '+' : '-', ++ id->base.e1000_base_lx ? '+' : '-', ++ id->base.e1000_base_cx ? '+' : '-', ++ id->base.e1000_base_t ? '+' : '-', ++ id->base.e100_base_lx ? '+' : '-', ++ id->base.e100_base_fx ? '+' : '-', ++ id->base.e_base_bx10 ? '+' : '-', ++ id->base.e_base_px ? '+' : '-'); ++ dev_info(sfp->dev, " 10GBaseSR%c 10GBaseLR%c 10GBaseLRM%c 10GBaseER%c\n", ++ id->base.e10g_base_sr ? '+' : '-', ++ id->base.e10g_base_lr ? '+' : '-', ++ id->base.e10g_base_lrm ? '+' : '-', ++ id->base.e10g_base_er ? '+' : '-'); ++ ++ if (!id->base.sfp_ct_passive && !id->base.sfp_ct_active && ++ !id->base.e1000_base_t) { + char len_9um[16], len_om[16]; + + dev_info(sfp->dev, " Wavelength %unm, fiber lengths:\n", -+ be16_to_cpup(&sfp->id.base.optical_wavelength)); ++ be16_to_cpup(&id->base.optical_wavelength)); + -+ if (sfp->id.base.link_len[0] == 255) ++ if (id->base.link_len[0] == 255) + strcpy(len_9um, ">254km"); -+ else if (sfp->id.base.link_len[1] && sfp->id.base.link_len[1] != 255) ++ else if (id->base.link_len[1] && id->base.link_len[1] != 255) + sprintf(len_9um, "%um", -+ sfp->id.base.link_len[1] * 100); -+ else if (sfp->id.base.link_len[0]) -+ sprintf(len_9um, "%ukm", sfp->id.base.link_len[0]); -+ else if (sfp->id.base.link_len[1] == 255) ++ id->base.link_len[1] * 100); ++ else if (id->base.link_len[0]) ++ sprintf(len_9um, "%ukm", id->base.link_len[0]); ++ else if (id->base.link_len[1] == 255) + strcpy(len_9um, ">25.4km"); + else + strcpy(len_9um, "unsupported"); + + dev_info(sfp->dev, " 9µm SM : %s\n", len_9um); + dev_info(sfp->dev, " 62.5µm MM OM1: %s\n", -+ sfp_link_len(len_om, sizeof(len_om), -+ sfp->id.base.link_len[3], 10)); ++ sff_link_len(len_om, sizeof(len_om), ++ id->base.link_len[3], 10)); + dev_info(sfp->dev, " 50µm MM OM2: %s\n", -+ sfp_link_len(len_om, sizeof(len_om), -+ sfp->id.base.link_len[2], 10)); ++ sff_link_len(len_om, sizeof(len_om), ++ id->base.link_len[2], 10)); + dev_info(sfp->dev, " 50µm MM OM3: %s\n", -+ sfp_link_len(len_om, sizeof(len_om), -+ sfp->id.base.link_len[5], 10)); ++ sff_link_len(len_om, sizeof(len_om), ++ id->base.link_len[5], 10)); + dev_info(sfp->dev, " 50µm MM OM4: %s\n", -+ sfp_link_len(len_om, sizeof(len_om), -+ sfp->id.base.link_len[4], 10)); ++ sff_link_len(len_om, sizeof(len_om), ++ id->base.link_len[4], 10)); + } else { + char len[16]; + dev_info(sfp->dev, " Copper length: %s\n", -+ sfp_link_len(len, sizeof(len), -+ sfp->id.base.link_len[4], 1)); ++ sff_link_len(len, sizeof(len), ++ id->base.link_len[4], 1)); + } + + dev_info(sfp->dev, " Options: %s\n", -+ sfp_bitfield(options, sizeof(options), sfp_options, -+ be16_to_cpu(sfp->id.ext.options))); ++ sff_bitfield(options, sizeof(options), sfp_options, ++ be16_to_cpu(id->ext.options))); + dev_info(sfp->dev, " Diagnostics: %s\n", -+ sfp_bitfield(options, sizeof(options), diagmon, -+ sfp->id.ext.diagmon)); ++ sff_bitfield(options, sizeof(options), diagmon, ++ id->ext.diagmon)); ++ dev_info(sfp->dev, " EnhOpts: %s\n", ++ sff_bitfield(options, sizeof(options), sfp_enhopts, ++ id->ext.enhopts)); ++} + + static int sfp_sm_mod_probe(struct sfp *sfp, bool report) + { + /* SFP module inserted - read I2C data */ +@@ -1685,9 +1898,9 @@ static int sfp_sm_mod_probe(struct sfp * + return -EAGAIN; + } + +- /* Cotsworks do not seem to update the checksums when they +- * do the final programming with the final module part number, +- * serial number and date code. ++ /* Cotsworks do not seem to update the checksums when they update the ++ * module part number, serial number and date code. They also format ++ * the date code incorrectly. + */ + cotsworks = !memcmp(id.base.vendor_name, "COTSWORKS ", 16); + cotsworks_sfbg = !memcmp(id.base.vendor_pn, "SFBG", 4); +@@ -1735,14 +1948,9 @@ static int sfp_sm_mod_probe(struct sfp * + } + } + +- sfp->id = id; ++ sfp_print_module_info(sfp, &id, cotsworks); + +- dev_info(sfp->dev, "module %.*s %.*s rev %.*s sn %.*s dc %.*s\n", +- (int)sizeof(id.base.vendor_name), id.base.vendor_name, +- (int)sizeof(id.base.vendor_pn), id.base.vendor_pn, +- (int)sizeof(id.base.vendor_rev), id.base.vendor_rev, +- (int)sizeof(id.ext.vendor_sn), id.ext.vendor_sn, +- (int)sizeof(id.ext.datecode), id.ext.datecode); ++ sfp->id = id; + /* Check whether we support this module */ if (!sfp->type->module_supported(&id)) { - dev_err(sfp->dev,