Commit 2824db74 authored by David S. Miller's avatar David S. Miller

Merge branch 'SFP-updates'

Russell King says:

====================
SFP updates

Included in this series are a further few updates for SFP support:

- Adding support for Fiberstore's non-standard BiDi modules operating
  at 1310nm/1550nm wavelengths rather than the 1000BASE-BX standard of
  1310nm/1490nm.
- Adding support for negotiating the PHY interface mode with the MAC,
  so that modules supporting faster speeds and Gigabit ethernet work
  with Gigabit-only MACs.
- Adding support for high power (>1W) SFP modules.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 44d15d93 3bb35261
...@@ -33,6 +33,10 @@ Optional Properties: ...@@ -33,6 +33,10 @@ Optional Properties:
Select (AKA RS1) output gpio signal (SFP+ only), low: low Tx rate, high: Select (AKA RS1) output gpio signal (SFP+ only), low: low Tx rate, high:
high Tx rate. Must not be present for SFF modules high Tx rate. Must not be present for SFF modules
- maximum-power-milliwatt : Maximum module power consumption
Specifies the maximum power consumption allowable by a module in the
slot, in milli-Watts. Presently, modules can be up to 1W, 1.5W or 2W.
Example #1: Direct serdes to SFP connection Example #1: Direct serdes to SFP connection
sfp_eth3: sfp-eth3 { sfp_eth3: sfp-eth3 {
...@@ -40,6 +44,7 @@ sfp_eth3: sfp-eth3 { ...@@ -40,6 +44,7 @@ sfp_eth3: sfp-eth3 {
i2c-bus = <&sfp_1g_i2c>; i2c-bus = <&sfp_1g_i2c>;
los-gpios = <&cpm_gpio2 22 GPIO_ACTIVE_HIGH>; los-gpios = <&cpm_gpio2 22 GPIO_ACTIVE_HIGH>;
mod-def0-gpios = <&cpm_gpio2 21 GPIO_ACTIVE_LOW>; mod-def0-gpios = <&cpm_gpio2 21 GPIO_ACTIVE_LOW>;
maximum-power-milliwatt = <1000>;
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&cpm_sfp_1g_pins &cps_sfp_1g_pins>; pinctrl-0 = <&cpm_sfp_1g_pins &cps_sfp_1g_pins>;
tx-disable-gpios = <&cps_gpio1 24 GPIO_ACTIVE_HIGH>; tx-disable-gpios = <&cps_gpio1 24 GPIO_ACTIVE_HIGH>;
......
...@@ -1584,25 +1584,14 @@ static int phylink_sfp_module_insert(void *upstream, ...@@ -1584,25 +1584,14 @@ static int phylink_sfp_module_insert(void *upstream,
bool changed; bool changed;
u8 port; u8 port;
sfp_parse_support(pl->sfp_bus, id, support);
port = sfp_parse_port(pl->sfp_bus, id, support);
iface = sfp_parse_interface(pl->sfp_bus, id);
ASSERT_RTNL(); ASSERT_RTNL();
switch (iface) { sfp_parse_support(pl->sfp_bus, id, support);
case PHY_INTERFACE_MODE_SGMII: port = sfp_parse_port(pl->sfp_bus, id, support);
case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_2500BASEX:
case PHY_INTERFACE_MODE_10GKR:
break;
default:
return -EINVAL;
}
memset(&config, 0, sizeof(config)); memset(&config, 0, sizeof(config));
linkmode_copy(config.advertising, support); linkmode_copy(config.advertising, support);
config.interface = iface; config.interface = PHY_INTERFACE_MODE_NA;
config.speed = SPEED_UNKNOWN; config.speed = SPEED_UNKNOWN;
config.duplex = DUPLEX_UNKNOWN; config.duplex = DUPLEX_UNKNOWN;
config.pause = MLO_PAUSE_AN; config.pause = MLO_PAUSE_AN;
...@@ -1610,6 +1599,22 @@ static int phylink_sfp_module_insert(void *upstream, ...@@ -1610,6 +1599,22 @@ static int phylink_sfp_module_insert(void *upstream,
/* Ignore errors if we're expecting a PHY to attach later */ /* Ignore errors if we're expecting a PHY to attach later */
ret = phylink_validate(pl, support, &config); ret = phylink_validate(pl, support, &config);
if (ret) {
netdev_err(pl->netdev, "validation with support %*pb failed: %d\n",
__ETHTOOL_LINK_MODE_MASK_NBITS, support, ret);
return ret;
}
iface = sfp_select_interface(pl->sfp_bus, id, config.advertising);
if (iface == PHY_INTERFACE_MODE_NA) {
netdev_err(pl->netdev,
"selection of interface failed, advertisment %*pb\n",
__ETHTOOL_LINK_MODE_MASK_NBITS, config.advertising);
return -EINVAL;
}
config.interface = iface;
ret = phylink_validate(pl, support, &config);
if (ret) { if (ret) {
netdev_err(pl->netdev, "validation of %s/%s with support %*pb failed: %d\n", netdev_err(pl->netdev, "validation of %s/%s with support %*pb failed: %d\n",
phylink_an_mode_str(MLO_AN_INBAND), phylink_an_mode_str(MLO_AN_INBAND),
......
...@@ -105,68 +105,6 @@ int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id, ...@@ -105,68 +105,6 @@ int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
} }
EXPORT_SYMBOL_GPL(sfp_parse_port); EXPORT_SYMBOL_GPL(sfp_parse_port);
/**
* sfp_parse_interface() - Parse the phy_interface_t
* @bus: a pointer to the &struct sfp_bus structure for the sfp module
* @id: a pointer to the module's &struct sfp_eeprom_id
*
* Derive the phy_interface_t mode for the information found in the
* module's identifying EEPROM. There is no standard or defined way
* to derive this information, so we use some heuristics.
*
* If the encoding is 64b66b, then the module must be >= 10G, so
* return %PHY_INTERFACE_MODE_10GKR.
*
* If it's 8b10b, then it's 1G or slower. If it's definitely a fibre
* module, return %PHY_INTERFACE_MODE_1000BASEX mode, otherwise return
* %PHY_INTERFACE_MODE_SGMII mode.
*
* If the encoding is not known, return %PHY_INTERFACE_MODE_NA.
*/
phy_interface_t sfp_parse_interface(struct sfp_bus *bus,
const struct sfp_eeprom_id *id)
{
phy_interface_t iface;
/* Setting the serdes link mode is guesswork: there's no field in
* the EEPROM which indicates what mode should be used.
*
* If the module wants 64b66b, then it must be >= 10G.
*
* If it's a gigabit-only fiber module, it probably does not have
* a PHY, so switch to 802.3z negotiation mode. Otherwise, switch
* to SGMII mode (which is required to support non-gigabit speeds).
*/
switch (id->base.encoding) {
case SFP_ENCODING_8472_64B66B:
iface = PHY_INTERFACE_MODE_10GKR;
break;
case SFP_ENCODING_8B10B:
if (!id->base.e1000_base_t &&
!id->base.e100_base_lx &&
!id->base.e100_base_fx)
iface = PHY_INTERFACE_MODE_1000BASEX;
else
iface = PHY_INTERFACE_MODE_SGMII;
break;
default:
if (id->base.e1000_base_cx) {
iface = PHY_INTERFACE_MODE_1000BASEX;
break;
}
iface = PHY_INTERFACE_MODE_NA;
dev_err(bus->sfp_dev,
"SFP module encoding does not support 8b10b nor 64b66b\n");
break;
}
return iface;
}
EXPORT_SYMBOL_GPL(sfp_parse_interface);
/** /**
* sfp_parse_support() - Parse the eeprom id for supported link modes * sfp_parse_support() - Parse the eeprom id for supported link modes
* @bus: a pointer to the &struct sfp_bus structure for the sfp module * @bus: a pointer to the &struct sfp_bus structure for the sfp module
...@@ -180,10 +118,7 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, ...@@ -180,10 +118,7 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
unsigned long *support) unsigned long *support)
{ {
unsigned int br_min, br_nom, br_max; unsigned int br_min, br_nom, br_max;
__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
phylink_set(support, Autoneg);
phylink_set(support, Pause);
phylink_set(support, Asym_Pause);
/* Decode the bitrate information to MBd */ /* Decode the bitrate information to MBd */
br_min = br_nom = br_max = 0; br_min = br_nom = br_max = 0;
...@@ -201,20 +136,20 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, ...@@ -201,20 +136,20 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
/* Set ethtool support from the compliance fields. */ /* Set ethtool support from the compliance fields. */
if (id->base.e10g_base_sr) if (id->base.e10g_base_sr)
phylink_set(support, 10000baseSR_Full); phylink_set(modes, 10000baseSR_Full);
if (id->base.e10g_base_lr) if (id->base.e10g_base_lr)
phylink_set(support, 10000baseLR_Full); phylink_set(modes, 10000baseLR_Full);
if (id->base.e10g_base_lrm) if (id->base.e10g_base_lrm)
phylink_set(support, 10000baseLRM_Full); phylink_set(modes, 10000baseLRM_Full);
if (id->base.e10g_base_er) if (id->base.e10g_base_er)
phylink_set(support, 10000baseER_Full); phylink_set(modes, 10000baseER_Full);
if (id->base.e1000_base_sx || if (id->base.e1000_base_sx ||
id->base.e1000_base_lx || id->base.e1000_base_lx ||
id->base.e1000_base_cx) id->base.e1000_base_cx)
phylink_set(support, 1000baseX_Full); phylink_set(modes, 1000baseX_Full);
if (id->base.e1000_base_t) { if (id->base.e1000_base_t) {
phylink_set(support, 1000baseT_Half); phylink_set(modes, 1000baseT_Half);
phylink_set(support, 1000baseT_Full); phylink_set(modes, 1000baseT_Full);
} }
/* 1000Base-PX or 1000Base-BX10 */ /* 1000Base-PX or 1000Base-BX10 */
...@@ -228,20 +163,20 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, ...@@ -228,20 +163,20 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
if ((id->base.sfp_ct_passive || id->base.sfp_ct_active) && br_nom) { if ((id->base.sfp_ct_passive || id->base.sfp_ct_active) && br_nom) {
/* This may look odd, but some manufacturers use 12000MBd */ /* This may look odd, but some manufacturers use 12000MBd */
if (br_min <= 12000 && br_max >= 10300) if (br_min <= 12000 && br_max >= 10300)
phylink_set(support, 10000baseCR_Full); phylink_set(modes, 10000baseCR_Full);
if (br_min <= 3200 && br_max >= 3100) if (br_min <= 3200 && br_max >= 3100)
phylink_set(support, 2500baseX_Full); phylink_set(modes, 2500baseX_Full);
if (br_min <= 1300 && br_max >= 1200) if (br_min <= 1300 && br_max >= 1200)
phylink_set(support, 1000baseX_Full); phylink_set(modes, 1000baseX_Full);
} }
if (id->base.sfp_ct_passive) { if (id->base.sfp_ct_passive) {
if (id->base.passive.sff8431_app_e) if (id->base.passive.sff8431_app_e)
phylink_set(support, 10000baseCR_Full); phylink_set(modes, 10000baseCR_Full);
} }
if (id->base.sfp_ct_active) { if (id->base.sfp_ct_active) {
if (id->base.active.sff8431_app_e || if (id->base.active.sff8431_app_e ||
id->base.active.sff8431_lim) { id->base.active.sff8431_lim) {
phylink_set(support, 10000baseCR_Full); phylink_set(modes, 10000baseCR_Full);
} }
} }
...@@ -249,18 +184,18 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, ...@@ -249,18 +184,18 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
case 0x00: /* Unspecified */ case 0x00: /* Unspecified */
break; break;
case 0x02: /* 100Gbase-SR4 or 25Gbase-SR */ case 0x02: /* 100Gbase-SR4 or 25Gbase-SR */
phylink_set(support, 100000baseSR4_Full); phylink_set(modes, 100000baseSR4_Full);
phylink_set(support, 25000baseSR_Full); phylink_set(modes, 25000baseSR_Full);
break; break;
case 0x03: /* 100Gbase-LR4 or 25Gbase-LR */ case 0x03: /* 100Gbase-LR4 or 25Gbase-LR */
case 0x04: /* 100Gbase-ER4 or 25Gbase-ER */ case 0x04: /* 100Gbase-ER4 or 25Gbase-ER */
phylink_set(support, 100000baseLR4_ER4_Full); phylink_set(modes, 100000baseLR4_ER4_Full);
break; break;
case 0x0b: /* 100Gbase-CR4 or 25Gbase-CR CA-L */ case 0x0b: /* 100Gbase-CR4 or 25Gbase-CR CA-L */
case 0x0c: /* 25Gbase-CR CA-S */ case 0x0c: /* 25Gbase-CR CA-S */
case 0x0d: /* 25Gbase-CR CA-N */ case 0x0d: /* 25Gbase-CR CA-N */
phylink_set(support, 100000baseCR4_Full); phylink_set(modes, 100000baseCR4_Full);
phylink_set(support, 25000baseCR_Full); phylink_set(modes, 25000baseCR_Full);
break; break;
default: default:
dev_warn(bus->sfp_dev, dev_warn(bus->sfp_dev,
...@@ -274,13 +209,70 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, ...@@ -274,13 +209,70 @@ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
id->base.fc_speed_200 || id->base.fc_speed_200 ||
id->base.fc_speed_400) { id->base.fc_speed_400) {
if (id->base.br_nominal >= 31) if (id->base.br_nominal >= 31)
phylink_set(support, 2500baseX_Full); phylink_set(modes, 2500baseX_Full);
if (id->base.br_nominal >= 12) if (id->base.br_nominal >= 12)
phylink_set(support, 1000baseX_Full); phylink_set(modes, 1000baseX_Full);
} }
/* If we haven't discovered any modes that this module supports, try
* the encoding and bitrate to determine supported modes. Some BiDi
* modules (eg, 1310nm/1550nm) are not 1000BASE-BX compliant due to
* the differing wavelengths, so do not set any transceiver bits.
*/
if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS)) {
/* If the encoding and bit rate allows 1000baseX */
if (id->base.encoding == SFP_ENCODING_8B10B && br_nom &&
br_min <= 1300 && br_max >= 1200)
phylink_set(modes, 1000baseX_Full);
}
bitmap_or(support, support, modes, __ETHTOOL_LINK_MODE_MASK_NBITS);
phylink_set(support, Autoneg);
phylink_set(support, Pause);
phylink_set(support, Asym_Pause);
} }
EXPORT_SYMBOL_GPL(sfp_parse_support); EXPORT_SYMBOL_GPL(sfp_parse_support);
/**
* sfp_select_interface() - Select appropriate phy_interface_t mode
* @bus: a pointer to the &struct sfp_bus structure for the sfp module
* @id: a pointer to the module's &struct sfp_eeprom_id
* @link_modes: ethtool link modes mask
*
* Derive the phy_interface_t mode for the information found in the
* module's identifying EEPROM and the link modes mask. There is no
* standard or defined way to derive this information, so we decide
* based upon the link mode mask.
*/
phy_interface_t sfp_select_interface(struct sfp_bus *bus,
const struct sfp_eeprom_id *id,
unsigned long *link_modes)
{
if (phylink_test(link_modes, 10000baseCR_Full) ||
phylink_test(link_modes, 10000baseSR_Full) ||
phylink_test(link_modes, 10000baseLR_Full) ||
phylink_test(link_modes, 10000baseLRM_Full) ||
phylink_test(link_modes, 10000baseER_Full))
return PHY_INTERFACE_MODE_10GKR;
if (phylink_test(link_modes, 2500baseX_Full))
return PHY_INTERFACE_MODE_2500BASEX;
if (id->base.e1000_base_t ||
id->base.e100_base_lx ||
id->base.e100_base_fx)
return PHY_INTERFACE_MODE_SGMII;
if (phylink_test(link_modes, 1000baseX_Full))
return PHY_INTERFACE_MODE_1000BASEX;
dev_warn(bus->sfp_dev, "Unable to ascertain link mode\n");
return PHY_INTERFACE_MODE_NA;
}
EXPORT_SYMBOL_GPL(sfp_select_interface);
static LIST_HEAD(sfp_buses); static LIST_HEAD(sfp_buses);
static DEFINE_MUTEX(sfp_mutex); static DEFINE_MUTEX(sfp_mutex);
......
...@@ -42,6 +42,7 @@ enum { ...@@ -42,6 +42,7 @@ enum {
SFP_MOD_EMPTY = 0, SFP_MOD_EMPTY = 0,
SFP_MOD_PROBE, SFP_MOD_PROBE,
SFP_MOD_HPOWER,
SFP_MOD_PRESENT, SFP_MOD_PRESENT,
SFP_MOD_ERROR, SFP_MOD_ERROR,
...@@ -86,6 +87,7 @@ static const enum gpiod_flags gpio_flags[] = { ...@@ -86,6 +87,7 @@ static const enum gpiod_flags gpio_flags[] = {
* access the I2C EEPROM. However, Avago modules require 300ms. * access the I2C EEPROM. However, Avago modules require 300ms.
*/ */
#define T_PROBE_INIT msecs_to_jiffies(300) #define T_PROBE_INIT msecs_to_jiffies(300)
#define T_HPOWER_LEVEL msecs_to_jiffies(300)
#define T_PROBE_RETRY msecs_to_jiffies(100) #define T_PROBE_RETRY msecs_to_jiffies(100)
/* SFP modules appear to always have their PHY configured for bus address /* SFP modules appear to always have their PHY configured for bus address
...@@ -110,10 +112,12 @@ struct sfp { ...@@ -110,10 +112,12 @@ struct sfp {
struct sfp_bus *sfp_bus; struct sfp_bus *sfp_bus;
struct phy_device *mod_phy; struct phy_device *mod_phy;
const struct sff_data *type; const struct sff_data *type;
u32 max_power_mW;
unsigned int (*get_state)(struct sfp *); unsigned int (*get_state)(struct sfp *);
void (*set_state)(struct sfp *, unsigned int); void (*set_state)(struct sfp *, unsigned int);
int (*read)(struct sfp *, bool, u8, void *, size_t); int (*read)(struct sfp *, bool, u8, void *, size_t);
int (*write)(struct sfp *, bool, u8, void *, size_t);
struct gpio_desc *gpio[GPIO_MAX]; struct gpio_desc *gpio[GPIO_MAX];
...@@ -201,10 +205,11 @@ static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state) ...@@ -201,10 +205,11 @@ static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state)
} }
} }
static int sfp__i2c_read(struct i2c_adapter *i2c, u8 bus_addr, u8 dev_addr, static int sfp_i2c_read(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
void *buf, size_t len) size_t len)
{ {
struct i2c_msg msgs[2]; struct i2c_msg msgs[2];
u8 bus_addr = a2 ? 0x51 : 0x50;
int ret; int ret;
msgs[0].addr = bus_addr; msgs[0].addr = bus_addr;
...@@ -216,17 +221,38 @@ static int sfp__i2c_read(struct i2c_adapter *i2c, u8 bus_addr, u8 dev_addr, ...@@ -216,17 +221,38 @@ static int sfp__i2c_read(struct i2c_adapter *i2c, u8 bus_addr, u8 dev_addr,
msgs[1].len = len; msgs[1].len = len;
msgs[1].buf = buf; msgs[1].buf = buf;
ret = i2c_transfer(i2c, msgs, ARRAY_SIZE(msgs)); ret = i2c_transfer(sfp->i2c, msgs, ARRAY_SIZE(msgs));
if (ret < 0) if (ret < 0)
return ret; return ret;
return ret == ARRAY_SIZE(msgs) ? len : 0; return ret == ARRAY_SIZE(msgs) ? len : 0;
} }
static int sfp_i2c_read(struct sfp *sfp, bool a2, u8 addr, void *buf, static int sfp_i2c_write(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
size_t len) size_t len)
{ {
return sfp__i2c_read(sfp->i2c, a2 ? 0x51 : 0x50, addr, buf, len); struct i2c_msg msgs[1];
u8 bus_addr = a2 ? 0x51 : 0x50;
int ret;
msgs[0].addr = bus_addr;
msgs[0].flags = 0;
msgs[0].len = 1 + len;
msgs[0].buf = kmalloc(1 + len, GFP_KERNEL);
if (!msgs[0].buf)
return -ENOMEM;
msgs[0].buf[0] = dev_addr;
memcpy(&msgs[0].buf[1], buf, len);
ret = i2c_transfer(sfp->i2c, msgs, ARRAY_SIZE(msgs));
kfree(msgs[0].buf);
if (ret < 0)
return ret;
return ret == ARRAY_SIZE(msgs) ? len : 0;
} }
static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
...@@ -239,6 +265,7 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) ...@@ -239,6 +265,7 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
sfp->i2c = i2c; sfp->i2c = i2c;
sfp->read = sfp_i2c_read; sfp->read = sfp_i2c_read;
sfp->write = sfp_i2c_write;
i2c_mii = mdio_i2c_alloc(sfp->dev, i2c); i2c_mii = mdio_i2c_alloc(sfp->dev, i2c);
if (IS_ERR(i2c_mii)) if (IS_ERR(i2c_mii))
...@@ -274,6 +301,11 @@ static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) ...@@ -274,6 +301,11 @@ static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
return sfp->read(sfp, a2, addr, buf, len); return sfp->read(sfp, a2, addr, buf, len);
} }
static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
{
return sfp->write(sfp, a2, addr, buf, len);
}
static unsigned int sfp_check(void *buf, size_t len) static unsigned int sfp_check(void *buf, size_t len)
{ {
u8 *p, check; u8 *p, check;
...@@ -462,21 +494,83 @@ static void sfp_sm_mod_init(struct sfp *sfp) ...@@ -462,21 +494,83 @@ static void sfp_sm_mod_init(struct sfp *sfp)
sfp_sm_probe_phy(sfp); sfp_sm_probe_phy(sfp);
} }
static int sfp_sm_mod_hpower(struct sfp *sfp)
{
u32 power;
u8 val;
int err;
power = 1000;
if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL))
power = 1500;
if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL))
power = 2000;
if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE &&
(sfp->id.ext.diagmon & (SFP_DIAGMON_DDM | SFP_DIAGMON_ADDRMODE)) !=
SFP_DIAGMON_DDM) {
/* The module appears not to implement bus address 0xa2,
* or requires an address change sequence, so assume that
* the module powers up in the indicated power mode.
*/
if (power > sfp->max_power_mW) {
dev_err(sfp->dev,
"Host does not support %u.%uW modules\n",
power / 1000, (power / 100) % 10);
return -EINVAL;
}
return 0;
}
if (power > sfp->max_power_mW) {
dev_warn(sfp->dev,
"Host does not support %u.%uW modules, module left in power mode 1\n",
power / 1000, (power / 100) % 10);
return 0;
}
if (power <= 1000)
return 0;
err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
if (err != sizeof(val)) {
dev_err(sfp->dev, "Failed to read EEPROM: %d\n", err);
err = -EAGAIN;
goto err;
}
val |= BIT(0);
err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
if (err != sizeof(val)) {
dev_err(sfp->dev, "Failed to write EEPROM: %d\n", err);
err = -EAGAIN;
goto err;
}
dev_info(sfp->dev, "Module switched to %u.%uW power level\n",
power / 1000, (power / 100) % 10);
return T_HPOWER_LEVEL;
err:
return err;
}
static int sfp_sm_mod_probe(struct sfp *sfp) static int sfp_sm_mod_probe(struct sfp *sfp)
{ {
/* SFP module inserted - read I2C data */ /* SFP module inserted - read I2C data */
struct sfp_eeprom_id id; struct sfp_eeprom_id id;
u8 check; u8 check;
int err; int ret;
err = sfp_read(sfp, false, 0, &id, sizeof(id)); ret = sfp_read(sfp, false, 0, &id, sizeof(id));
if (err < 0) { if (ret < 0) {
dev_err(sfp->dev, "failed to read EEPROM: %d\n", err); dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret);
return -EAGAIN; return -EAGAIN;
} }
if (err != sizeof(id)) { if (ret != sizeof(id)) {
dev_err(sfp->dev, "EEPROM short read: %d\n", err); dev_err(sfp->dev, "EEPROM short read: %d\n", ret);
return -EAGAIN; return -EAGAIN;
} }
...@@ -521,7 +615,11 @@ static int sfp_sm_mod_probe(struct sfp *sfp) ...@@ -521,7 +615,11 @@ static int sfp_sm_mod_probe(struct sfp *sfp)
dev_warn(sfp->dev, dev_warn(sfp->dev,
"module address swap to access page 0xA2 is not supported.\n"); "module address swap to access page 0xA2 is not supported.\n");
return sfp_module_insert(sfp->sfp_bus, &sfp->id); ret = sfp_module_insert(sfp->sfp_bus, &sfp->id);
if (ret < 0)
return ret;
return sfp_sm_mod_hpower(sfp);
} }
static void sfp_sm_mod_remove(struct sfp *sfp) static void sfp_sm_mod_remove(struct sfp *sfp)
...@@ -560,17 +658,25 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event) ...@@ -560,17 +658,25 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event)
if (event == SFP_E_REMOVE) { if (event == SFP_E_REMOVE) {
sfp_sm_ins_next(sfp, SFP_MOD_EMPTY, 0); sfp_sm_ins_next(sfp, SFP_MOD_EMPTY, 0);
} else if (event == SFP_E_TIMEOUT) { } else if (event == SFP_E_TIMEOUT) {
int err = sfp_sm_mod_probe(sfp); int val = sfp_sm_mod_probe(sfp);
if (err == 0) if (val == 0)
sfp_sm_ins_next(sfp, SFP_MOD_PRESENT, 0); sfp_sm_ins_next(sfp, SFP_MOD_PRESENT, 0);
else if (err == -EAGAIN) else if (val > 0)
sfp_sm_set_timer(sfp, T_PROBE_RETRY); sfp_sm_ins_next(sfp, SFP_MOD_HPOWER, val);
else else if (val != -EAGAIN)
sfp_sm_ins_next(sfp, SFP_MOD_ERROR, 0); sfp_sm_ins_next(sfp, SFP_MOD_ERROR, 0);
else
sfp_sm_set_timer(sfp, T_PROBE_RETRY);
} }
break; break;
case SFP_MOD_HPOWER:
if (event == SFP_E_TIMEOUT) {
sfp_sm_ins_next(sfp, SFP_MOD_PRESENT, 0);
break;
}
/* fallthrough */
case SFP_MOD_PRESENT: case SFP_MOD_PRESENT:
case SFP_MOD_ERROR: case SFP_MOD_ERROR:
if (event == SFP_E_REMOVE) { if (event == SFP_E_REMOVE) {
...@@ -889,6 +995,14 @@ static int sfp_probe(struct platform_device *pdev) ...@@ -889,6 +995,14 @@ static int sfp_probe(struct platform_device *pdev)
if (!(sfp->gpio[GPIO_MODDEF0])) if (!(sfp->gpio[GPIO_MODDEF0]))
sfp->get_state = sff_gpio_get_state; sfp->get_state = sff_gpio_get_state;
device_property_read_u32(&pdev->dev, "maximum-power-milliwatt",
&sfp->max_power_mW);
if (!sfp->max_power_mW)
sfp->max_power_mW = 1000;
dev_info(sfp->dev, "Host maximum power %u.%uW\n",
sfp->max_power_mW / 1000, (sfp->max_power_mW / 100) % 10);
sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops); sfp->sfp_bus = sfp_register_socket(sfp->dev, sfp, &sfp_module_ops);
if (!sfp->sfp_bus) if (!sfp->sfp_bus)
return -ENOMEM; return -ENOMEM;
......
...@@ -422,10 +422,11 @@ struct sfp_upstream_ops { ...@@ -422,10 +422,11 @@ struct sfp_upstream_ops {
#if IS_ENABLED(CONFIG_SFP) #if IS_ENABLED(CONFIG_SFP)
int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id, int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
unsigned long *support); unsigned long *support);
phy_interface_t sfp_parse_interface(struct sfp_bus *bus,
const struct sfp_eeprom_id *id);
void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
unsigned long *support); unsigned long *support);
phy_interface_t sfp_select_interface(struct sfp_bus *bus,
const struct sfp_eeprom_id *id,
unsigned long *link_modes);
int sfp_get_module_info(struct sfp_bus *bus, struct ethtool_modinfo *modinfo); int sfp_get_module_info(struct sfp_bus *bus, struct ethtool_modinfo *modinfo);
int sfp_get_module_eeprom(struct sfp_bus *bus, struct ethtool_eeprom *ee, int sfp_get_module_eeprom(struct sfp_bus *bus, struct ethtool_eeprom *ee,
...@@ -444,18 +445,19 @@ static inline int sfp_parse_port(struct sfp_bus *bus, ...@@ -444,18 +445,19 @@ static inline int sfp_parse_port(struct sfp_bus *bus,
return PORT_OTHER; return PORT_OTHER;
} }
static inline phy_interface_t sfp_parse_interface(struct sfp_bus *bus,
const struct sfp_eeprom_id *id)
{
return PHY_INTERFACE_MODE_NA;
}
static inline void sfp_parse_support(struct sfp_bus *bus, static inline void sfp_parse_support(struct sfp_bus *bus,
const struct sfp_eeprom_id *id, const struct sfp_eeprom_id *id,
unsigned long *support) unsigned long *support)
{ {
} }
static inline phy_interface_t sfp_select_interface(struct sfp_bus *bus,
const struct sfp_eeprom_id *id,
unsigned long *link_modes)
{
return PHY_INTERFACE_MODE_NA;
}
static inline int sfp_get_module_info(struct sfp_bus *bus, static inline int sfp_get_module_info(struct sfp_bus *bus,
struct ethtool_modinfo *modinfo) struct ethtool_modinfo *modinfo)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment