Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Russell King and committed by
David S. Miller
74c551ca 0fbd26a9

+35
+21
drivers/net/phy/sfp-bus.c
··· 712 712 } 713 713 EXPORT_SYMBOL_GPL(sfp_module_remove); 714 714 715 + int sfp_module_start(struct sfp_bus *bus) 716 + { 717 + const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus); 718 + int ret = 0; 719 + 720 + if (ops && ops->module_start) 721 + ret = ops->module_start(bus->upstream); 722 + 723 + return ret; 724 + } 725 + EXPORT_SYMBOL_GPL(sfp_module_start); 726 + 727 + void sfp_module_stop(struct sfp_bus *bus) 728 + { 729 + const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus); 730 + 731 + if (ops && ops->module_stop) 732 + ops->module_stop(bus->upstream); 733 + } 734 + EXPORT_SYMBOL_GPL(sfp_module_stop); 735 + 715 736 static void sfp_socket_clear(struct sfp_bus *bus) 716 737 { 717 738 bus->sfp_dev = NULL;
+8
drivers/net/phy/sfp.c
··· 59 59 SFP_DEV_UP, 60 60 61 61 SFP_S_DOWN = 0, 62 + SFP_S_FAIL, 62 63 SFP_S_WAIT, 63 64 SFP_S_INIT, 64 65 SFP_S_INIT_TX_FAULT, ··· 123 122 124 123 static const char * const sm_state_strings[] = { 125 124 [SFP_S_DOWN] = "down", 125 + [SFP_S_FAIL] = "fail", 126 126 [SFP_S_WAIT] = "wait", 127 127 [SFP_S_INIT] = "init", 128 128 [SFP_S_INIT_TX_FAULT] = "init_tx_fault", ··· 1828 1826 if (sfp->sm_state == SFP_S_LINK_UP && 1829 1827 sfp->sm_dev_state == SFP_DEV_UP) 1830 1828 sfp_sm_link_down(sfp); 1829 + if (sfp->sm_state > SFP_S_INIT) 1830 + sfp_module_stop(sfp->sfp_bus); 1831 1831 if (sfp->mod_phy) 1832 1832 sfp_sm_phy_detach(sfp); 1833 1833 sfp_module_tx_disable(sfp); ··· 1897 1893 * clear. Probe for the PHY and check the LOS state. 1898 1894 */ 1899 1895 sfp_sm_probe_for_phy(sfp); 1896 + if (sfp_module_start(sfp->sfp_bus)) { 1897 + sfp_sm_next(sfp, SFP_S_FAIL, 0); 1898 + break; 1899 + } 1900 1900 sfp_sm_link_check_los(sfp); 1901 1901 1902 1902 /* Reset the fault retry count */
+2
drivers/net/phy/sfp.h
··· 22 22 void sfp_link_down(struct sfp_bus *bus); 23 23 int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id); 24 24 void sfp_module_remove(struct sfp_bus *bus); 25 + int sfp_module_start(struct sfp_bus *bus); 26 + void sfp_module_stop(struct sfp_bus *bus); 25 27 int sfp_link_configure(struct sfp_bus *bus, const struct sfp_eeprom_id *id); 26 28 struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp, 27 29 const struct sfp_socket_ops *ops);
+4
include/linux/sfp.h
··· 507 507 * @module_insert: called after a module has been detected to determine 508 508 * whether the module is supported for the upstream device. 509 509 * @module_remove: called after the module has been removed. 510 + * @module_start: called after the PHY probe step 511 + * @module_stop: called before the PHY is removed 510 512 * @link_down: called when the link is non-operational for whatever 511 513 * reason. 512 514 * @link_up: called when the link is operational. ··· 522 520 void (*detach)(void *priv, struct sfp_bus *bus); 523 521 int (*module_insert)(void *priv, const struct sfp_eeprom_id *id); 524 522 void (*module_remove)(void *priv); 523 + int (*module_start)(void *priv); 524 + void (*module_stop)(void *priv); 525 525 void (*link_down)(void *priv); 526 526 void (*link_up)(void *priv); 527 527 int (*connect_phy)(void *priv, struct phy_device *);