mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 12:44:03 +02:00
Merge branch 'net-sfp-quirk-support-for-xgs-pon-ont-sticks-with-unclean-eeproms'
Martino Dell says: ==================== net: sfp: quirk support for XGS-PON ONT sticks with unclean EEPROMs Some clone XGS-PON ONT sticks return EEPROM reads where the vendor PN field contains non-printable garbage past the legitimate string instead of the SFF-8472 mandated space padding. sfp_strlen() then can't trim the field, the exact-length check in sfp_match() rejects the quirk entry before the string comparison runs, and the quirk silently never applies - so the kernel honors the module's spurious TX_FAULT and eventually disables it. Patch 1 adds an opt-in part-prefix-matching flag to the quirk table so such modules can still be matched; the vendor name is always matched exactly and existing entries behave as before. Patch 2 adds two ONT stick entries wired to the existing potron fixup: the "OEM" XGSPONST2001, which needs the prefix matching (it returns trailing garbage in the PN field on cold power-up reads), and the Fiberstore XGS-SFP-ONT-MACI, whose PN field is fully occupied by the truncated product name and matches exactly. Both quirks are in production use on a Bananapi BPI-R4 (MT7988A) router on an XGS-PON uplink, backported onto 6.12. ==================== Link: https://patch.msgid.link/20260812154708.2201266-1-tillo@tillo.ch Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
c69bd5b16b
|
|
@ -516,6 +516,15 @@ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
|
|||
{ .vendor = _v, .part = _p, .support = _s, .fixup = _f, }
|
||||
#define SFP_QUIRK_S(_v, _p, _s) SFP_QUIRK(_v, _p, _s, NULL)
|
||||
#define SFP_QUIRK_F(_v, _p, _f) SFP_QUIRK(_v, _p, NULL, _f)
|
||||
/* Like SFP_QUIRK_F, but matches the part as a prefix; the vendor name
|
||||
* is still matched exactly. Use for modules whose EEPROM vendor PN
|
||||
* field reads back with garbage past the legitimate characters instead
|
||||
* of the SFF-8472-mandated space padding, so sfp_strlen can't trim the
|
||||
* field down to the legitimate length.
|
||||
*/
|
||||
#define SFP_QUIRK_F_PREFIX(_v, _p, _f) \
|
||||
{ .vendor = _v, .part = _p, .support = NULL, .fixup = _f, \
|
||||
.part_prefix_match = true }
|
||||
|
||||
static const struct sfp_quirk sfp_quirks[] = {
|
||||
// Alcatel Lucent G-010S-P can operate at 2500base-X, but incorrectly
|
||||
|
|
@ -548,6 +557,13 @@ static const struct sfp_quirk sfp_quirks[] = {
|
|||
SFP_QUIRK("FS", "GPON-ONU-34-20BI", sfp_quirk_2500basex,
|
||||
sfp_fixup_ignore_tx_fault),
|
||||
|
||||
// Fiberstore XGS-SFP-ONT-MACI is a MAC-mode XGS-PON ONT stick with
|
||||
// ONT-class serial-passthrough TX_FAULT/LOS wiring and slow startup;
|
||||
// mask both signals and extend T_START_UP via the potron fixup. The
|
||||
// PN is the product name (XGS-SFP-ONT-MAC-I) truncated at the 16-byte
|
||||
// field width, so the field is fully occupied and matches exactly.
|
||||
SFP_QUIRK_F("FS", "XGS-SFP-ONT-MACI", sfp_fixup_potron),
|
||||
|
||||
SFP_QUIRK_F("HALNy", "HL-GSFP", sfp_fixup_halny_gsfp),
|
||||
|
||||
SFP_QUIRK_F("H-COM", "SPP425H-GAB4", sfp_fixup_potron),
|
||||
|
|
@ -608,6 +624,14 @@ static const struct sfp_quirk sfp_quirks[] = {
|
|||
SFP_QUIRK_S("OEM", "SFP-2.5G-LH20-A", sfp_quirk_2500basex),
|
||||
SFP_QUIRK_F("OEM", "RTSFP-10", sfp_fixup_rollball_cc),
|
||||
SFP_QUIRK_F("OEM", "RTSFP-10G", sfp_fixup_rollball_cc),
|
||||
|
||||
// OEM XGSPONST2001 is an XGS-PON ONT stick with broken TX_FAULT and
|
||||
// LOS indicators and slow startup, just like potron. On cold
|
||||
// power-up the EEPROM vendor PN field reads back with non-printable
|
||||
// garbage past the legitimate string instead of space padding, so
|
||||
// match the part as a prefix.
|
||||
SFP_QUIRK_F_PREFIX("OEM", "XGSPONST2001", sfp_fixup_potron),
|
||||
|
||||
SFP_QUIRK_F("Turris", "RTSFP-2.5G", sfp_fixup_rollball),
|
||||
SFP_QUIRK_F("Turris", "RTSFP-10", sfp_fixup_rollball),
|
||||
SFP_QUIRK_F("Turris", "RTSFP-10G", sfp_fixup_rollball),
|
||||
|
|
@ -629,13 +653,16 @@ static size_t sfp_strlen(const char *str, size_t maxlen)
|
|||
return size;
|
||||
}
|
||||
|
||||
static bool sfp_match(const char *qs, const char *str, size_t len)
|
||||
static bool sfp_match(const char *qs, const char *str, size_t len, bool prefix)
|
||||
{
|
||||
size_t qs_len;
|
||||
|
||||
if (!qs)
|
||||
return true;
|
||||
if (strlen(qs) != len)
|
||||
qs_len = strlen(qs);
|
||||
if (prefix ? qs_len > len : qs_len != len)
|
||||
return false;
|
||||
return !strncmp(qs, str, len);
|
||||
return !strncmp(qs, str, qs_len);
|
||||
}
|
||||
|
||||
static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id)
|
||||
|
|
@ -648,8 +675,9 @@ static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id)
|
|||
ps = sfp_strlen(id->base.vendor_pn, ARRAY_SIZE(id->base.vendor_pn));
|
||||
|
||||
for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++)
|
||||
if (sfp_match(q->vendor, id->base.vendor_name, vs) &&
|
||||
sfp_match(q->part, id->base.vendor_pn, ps))
|
||||
if (sfp_match(q->vendor, id->base.vendor_name, vs, false) &&
|
||||
sfp_match(q->part, id->base.vendor_pn, ps,
|
||||
q->part_prefix_match))
|
||||
return q;
|
||||
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ struct sfp_quirk {
|
|||
void (*support)(const struct sfp_eeprom_id *id,
|
||||
struct sfp_module_caps *caps);
|
||||
void (*fixup)(struct sfp *sfp);
|
||||
bool part_prefix_match;
|
||||
};
|
||||
|
||||
struct sfp_socket_ops {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user