mirror of https://gitee.com/openkylin/linux.git
net: sfp: add module start/stop upstream notifications
When dealing with some copper modules, we can't positively know the module capabilities are until we have probed the PHY. Without the full capabilities, we may end up failing a module that we could otherwise drive with a restricted set of capabilities. An example of this would be a module with a NBASE-T PHY plugged into a host that supports phy interface modes 2500BASE-X and SGMII. The PHY supports 10GBASE-R, 5000BASE-X, 2500BASE-X, SGMII interface modes, which means a subset of the capabilities are compatible with the host. However, reading the module EEPROM leads us to believe that the module only supports ethtool link mode 10GBASE-T, which is incompatible with the host - and thus results in the module being rejected. This patch adds an extra notification which are triggered after the SFP module's PHY probe, and a corresponding notification just before the PHY is removed. Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
0fbd26a9fb
commit
74c551ca5a
|
@ -712,6 +712,27 @@ void sfp_module_remove(struct sfp_bus *bus)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(sfp_module_remove);
|
EXPORT_SYMBOL_GPL(sfp_module_remove);
|
||||||
|
|
||||||
|
int sfp_module_start(struct sfp_bus *bus)
|
||||||
|
{
|
||||||
|
const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (ops && ops->module_start)
|
||||||
|
ret = ops->module_start(bus->upstream);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sfp_module_start);
|
||||||
|
|
||||||
|
void sfp_module_stop(struct sfp_bus *bus)
|
||||||
|
{
|
||||||
|
const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
|
||||||
|
|
||||||
|
if (ops && ops->module_stop)
|
||||||
|
ops->module_stop(bus->upstream);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(sfp_module_stop);
|
||||||
|
|
||||||
static void sfp_socket_clear(struct sfp_bus *bus)
|
static void sfp_socket_clear(struct sfp_bus *bus)
|
||||||
{
|
{
|
||||||
bus->sfp_dev = NULL;
|
bus->sfp_dev = NULL;
|
||||||
|
|
|
@ -59,6 +59,7 @@ enum {
|
||||||
SFP_DEV_UP,
|
SFP_DEV_UP,
|
||||||
|
|
||||||
SFP_S_DOWN = 0,
|
SFP_S_DOWN = 0,
|
||||||
|
SFP_S_FAIL,
|
||||||
SFP_S_WAIT,
|
SFP_S_WAIT,
|
||||||
SFP_S_INIT,
|
SFP_S_INIT,
|
||||||
SFP_S_INIT_TX_FAULT,
|
SFP_S_INIT_TX_FAULT,
|
||||||
|
@ -122,6 +123,7 @@ static const char *event_to_str(unsigned short event)
|
||||||
|
|
||||||
static const char * const sm_state_strings[] = {
|
static const char * const sm_state_strings[] = {
|
||||||
[SFP_S_DOWN] = "down",
|
[SFP_S_DOWN] = "down",
|
||||||
|
[SFP_S_FAIL] = "fail",
|
||||||
[SFP_S_WAIT] = "wait",
|
[SFP_S_WAIT] = "wait",
|
||||||
[SFP_S_INIT] = "init",
|
[SFP_S_INIT] = "init",
|
||||||
[SFP_S_INIT_TX_FAULT] = "init_tx_fault",
|
[SFP_S_INIT_TX_FAULT] = "init_tx_fault",
|
||||||
|
@ -1826,6 +1828,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
|
||||||
if (sfp->sm_state == SFP_S_LINK_UP &&
|
if (sfp->sm_state == SFP_S_LINK_UP &&
|
||||||
sfp->sm_dev_state == SFP_DEV_UP)
|
sfp->sm_dev_state == SFP_DEV_UP)
|
||||||
sfp_sm_link_down(sfp);
|
sfp_sm_link_down(sfp);
|
||||||
|
if (sfp->sm_state > SFP_S_INIT)
|
||||||
|
sfp_module_stop(sfp->sfp_bus);
|
||||||
if (sfp->mod_phy)
|
if (sfp->mod_phy)
|
||||||
sfp_sm_phy_detach(sfp);
|
sfp_sm_phy_detach(sfp);
|
||||||
sfp_module_tx_disable(sfp);
|
sfp_module_tx_disable(sfp);
|
||||||
|
@ -1893,6 +1897,10 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
|
||||||
* clear. Probe for the PHY and check the LOS state.
|
* clear. Probe for the PHY and check the LOS state.
|
||||||
*/
|
*/
|
||||||
sfp_sm_probe_for_phy(sfp);
|
sfp_sm_probe_for_phy(sfp);
|
||||||
|
if (sfp_module_start(sfp->sfp_bus)) {
|
||||||
|
sfp_sm_next(sfp, SFP_S_FAIL, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
sfp_sm_link_check_los(sfp);
|
sfp_sm_link_check_los(sfp);
|
||||||
|
|
||||||
/* Reset the fault retry count */
|
/* Reset the fault retry count */
|
||||||
|
|
|
@ -22,6 +22,8 @@ void sfp_link_up(struct sfp_bus *bus);
|
||||||
void sfp_link_down(struct sfp_bus *bus);
|
void sfp_link_down(struct sfp_bus *bus);
|
||||||
int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
|
int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
|
||||||
void sfp_module_remove(struct sfp_bus *bus);
|
void sfp_module_remove(struct sfp_bus *bus);
|
||||||
|
int sfp_module_start(struct sfp_bus *bus);
|
||||||
|
void sfp_module_stop(struct sfp_bus *bus);
|
||||||
int sfp_link_configure(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
|
int sfp_link_configure(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
|
||||||
struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp,
|
struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp,
|
||||||
const struct sfp_socket_ops *ops);
|
const struct sfp_socket_ops *ops);
|
||||||
|
|
|
@ -507,6 +507,8 @@ struct sfp_bus;
|
||||||
* @module_insert: called after a module has been detected to determine
|
* @module_insert: called after a module has been detected to determine
|
||||||
* whether the module is supported for the upstream device.
|
* whether the module is supported for the upstream device.
|
||||||
* @module_remove: called after the module has been removed.
|
* @module_remove: called after the module has been removed.
|
||||||
|
* @module_start: called after the PHY probe step
|
||||||
|
* @module_stop: called before the PHY is removed
|
||||||
* @link_down: called when the link is non-operational for whatever
|
* @link_down: called when the link is non-operational for whatever
|
||||||
* reason.
|
* reason.
|
||||||
* @link_up: called when the link is operational.
|
* @link_up: called when the link is operational.
|
||||||
|
@ -520,6 +522,8 @@ struct sfp_upstream_ops {
|
||||||
void (*detach)(void *priv, struct sfp_bus *bus);
|
void (*detach)(void *priv, struct sfp_bus *bus);
|
||||||
int (*module_insert)(void *priv, const struct sfp_eeprom_id *id);
|
int (*module_insert)(void *priv, const struct sfp_eeprom_id *id);
|
||||||
void (*module_remove)(void *priv);
|
void (*module_remove)(void *priv);
|
||||||
|
int (*module_start)(void *priv);
|
||||||
|
void (*module_stop)(void *priv);
|
||||||
void (*link_down)(void *priv);
|
void (*link_down)(void *priv);
|
||||||
void (*link_up)(void *priv);
|
void (*link_up)(void *priv);
|
||||||
int (*connect_phy)(void *priv, struct phy_device *);
|
int (*connect_phy)(void *priv, struct phy_device *);
|
||||||
|
|
Loading…
Reference in New Issue