Skip to content

Commit 9ce3335

Browse files
committed
Merge branch 'sfp-quirks'
Russell King says: ==================== Add rudimentary SFP module quirk support The SFP module EEPROM describes the capabilities of the module, but doesn't describe the host interface. We have a certain amount of guess-work to work out how to configure the host - which works most of the time. However, there are some (such as GPON) modules which are able to support different host interfaces, such as 1000BASE-X and 2500BASE-X. The module will switch between each mode until it achieves link with the host. There is no defined way to describe this in the SFP EEPROM, so we can only recognise the module and handle it appropriately. This series adds the necessary recognition of the modules using a quirk system, and tweaks the support mask to allow them to link with the host at 2500BASE-X, thereby allowing the user to achieve full line rate. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
2 parents 9bb59a2 + b0eae33 commit 9ce3335

File tree

1 file changed

+79
-0
lines changed

1 file changed

+79
-0
lines changed

drivers/net/phy/sfp-bus.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010

1111
#include "sfp.h"
1212

13+
struct sfp_quirk {
14+
const char *vendor;
15+
const char *part;
16+
void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes);
17+
};
18+
1319
/**
1420
* struct sfp_bus - internal representation of a sfp bus
1521
*/
@@ -22,6 +28,7 @@ struct sfp_bus {
2228
const struct sfp_socket_ops *socket_ops;
2329
struct device *sfp_dev;
2430
struct sfp *sfp;
31+
const struct sfp_quirk *sfp_quirk;
2532

2633
const struct sfp_upstream_ops *upstream_ops;
2734
void *upstream;
@@ -31,6 +38,71 @@ struct sfp_bus {
3138
bool started;
3239
};
3340

41+
static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,
42+
unsigned long *modes)
43+
{
44+
phylink_set(modes, 2500baseX_Full);
45+
}
46+
47+
static const struct sfp_quirk sfp_quirks[] = {
48+
{
49+
// Alcatel Lucent G-010S-P can operate at 2500base-X, but
50+
// incorrectly report 2500MBd NRZ in their EEPROM
51+
.vendor = "ALCATELLUCENT",
52+
.part = "G010SP",
53+
.modes = sfp_quirk_2500basex,
54+
}, {
55+
// Alcatel Lucent G-010S-A can operate at 2500base-X, but
56+
// report 3.2GBd NRZ in their EEPROM
57+
.vendor = "ALCATELLUCENT",
58+
.part = "3FE46541AA",
59+
.modes = sfp_quirk_2500basex,
60+
}, {
61+
// Huawei MA5671A can operate at 2500base-X, but report 1.2GBd
62+
// NRZ in their EEPROM
63+
.vendor = "HUAWEI",
64+
.part = "MA5671A",
65+
.modes = sfp_quirk_2500basex,
66+
},
67+
};
68+
69+
static size_t sfp_strlen(const char *str, size_t maxlen)
70+
{
71+
size_t size, i;
72+
73+
/* Trailing characters should be filled with space chars */
74+
for (i = 0, size = 0; i < maxlen; i++)
75+
if (str[i] != ' ')
76+
size = i + 1;
77+
78+
return size;
79+
}
80+
81+
static bool sfp_match(const char *qs, const char *str, size_t len)
82+
{
83+
if (!qs)
84+
return true;
85+
if (strlen(qs) != len)
86+
return false;
87+
return !strncmp(qs, str, len);
88+
}
89+
90+
static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id)
91+
{
92+
const struct sfp_quirk *q;
93+
unsigned int i;
94+
size_t vs, ps;
95+
96+
vs = sfp_strlen(id->base.vendor_name, ARRAY_SIZE(id->base.vendor_name));
97+
ps = sfp_strlen(id->base.vendor_pn, ARRAY_SIZE(id->base.vendor_pn));
98+
99+
for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++)
100+
if (sfp_match(q->vendor, id->base.vendor_name, vs) &&
101+
sfp_match(q->part, id->base.vendor_pn, ps))
102+
return q;
103+
104+
return NULL;
105+
}
34106
/**
35107
* sfp_parse_port() - Parse the EEPROM base ID, setting the port type
36108
* @bus: a pointer to the &struct sfp_bus structure for the sfp module
@@ -234,6 +306,9 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
234306
phylink_set(modes, 1000baseX_Full);
235307
}
236308

309+
if (bus->sfp_quirk)
310+
bus->sfp_quirk->modes(id, modes);
311+
237312
bitmap_or(support, support, modes, __ETHTOOL_LINK_MODE_MASK_NBITS);
238313

239314
phylink_set(support, Autoneg);
@@ -610,6 +685,8 @@ int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id)
610685
const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
611686
int ret = 0;
612687

688+
bus->sfp_quirk = sfp_lookup_quirk(id);
689+
613690
if (ops && ops->module_insert)
614691
ret = ops->module_insert(bus->upstream, id);
615692

@@ -623,6 +700,8 @@ void sfp_module_remove(struct sfp_bus *bus)
623700

624701
if (ops && ops->module_remove)
625702
ops->module_remove(bus->upstream);
703+
704+
bus->sfp_quirk = NULL;
626705
}
627706
EXPORT_SYMBOL_GPL(sfp_module_remove);
628707

0 commit comments

Comments
 (0)