 c16517d26d
			
		
	
	c16517d26d
	
	
	
		
			
			No changes were done to the patches while coping them. Currently they do not apply on top of kernel 5.4. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
		
			
				
	
	
		
			132 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			132 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
| From f9a5a54b59cb904b37bf7409a43635ab195d0214 Mon Sep 17 00:00:00 2001
 | |
| From: Russell King <rmk+kernel@armlinux.org.uk>
 | |
| Date: Tue, 19 Nov 2019 10:13:25 +0000
 | |
| Subject: [PATCH 646/660] 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.
 | |
| 
 | |
| Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
 | |
| ---
 | |
|  drivers/net/phy/sfp-bus.c | 21 +++++++++++++++++++++
 | |
|  drivers/net/phy/sfp.c     |  8 ++++++++
 | |
|  drivers/net/phy/sfp.h     |  2 ++
 | |
|  include/linux/sfp.h       |  4 ++++
 | |
|  4 files changed, 35 insertions(+)
 | |
| 
 | |
| --- a/drivers/net/phy/sfp-bus.c
 | |
| +++ b/drivers/net/phy/sfp-bus.c
 | |
| @@ -711,6 +711,27 @@ void sfp_module_remove(struct sfp_bus *b
 | |
|  }
 | |
|  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)
 | |
|  {
 | |
|  	bus->sfp_dev = NULL;
 | |
| --- a/drivers/net/phy/sfp.c
 | |
| +++ b/drivers/net/phy/sfp.c
 | |
| @@ -57,6 +57,7 @@ enum {
 | |
|  	SFP_DEV_UP,
 | |
|  
 | |
|  	SFP_S_DOWN = 0,
 | |
| +	SFP_S_FAIL,
 | |
|  	SFP_S_WAIT,
 | |
|  	SFP_S_INIT,
 | |
|  	SFP_S_INIT_TX_FAULT,
 | |
| @@ -120,6 +121,7 @@ static const char *event_to_str(unsigned
 | |
|  
 | |
|  static const char * const sm_state_strings[] = {
 | |
|  	[SFP_S_DOWN] = "down",
 | |
| +	[SFP_S_FAIL] = "fail",
 | |
|  	[SFP_S_WAIT] = "wait",
 | |
|  	[SFP_S_INIT] = "init",
 | |
|  	[SFP_S_INIT_TX_FAULT] = "init_tx_fault",
 | |
| @@ -1766,6 +1768,8 @@ static void sfp_sm_main(struct sfp *sfp,
 | |
|  		if (sfp->sm_state == SFP_S_LINK_UP &&
 | |
|  		    sfp->sm_dev_state == SFP_DEV_UP)
 | |
|  			sfp_sm_link_down(sfp);
 | |
| +		if (sfp->sm_state > SFP_S_INIT)
 | |
| +			sfp_module_stop(sfp->sfp_bus);
 | |
|  		if (sfp->mod_phy)
 | |
|  			sfp_sm_phy_detach(sfp);
 | |
|  		sfp_module_tx_disable(sfp);
 | |
| @@ -1833,6 +1837,10 @@ static void sfp_sm_main(struct sfp *sfp,
 | |
|  			 * clear.  Probe for the PHY and check the LOS state.
 | |
|  			 */
 | |
|  			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);
 | |
|  
 | |
|  			/* Reset the fault retry count */
 | |
| --- a/drivers/net/phy/sfp.h
 | |
| +++ b/drivers/net/phy/sfp.h
 | |
| @@ -22,6 +22,8 @@ void sfp_link_up(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);
 | |
|  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);
 | |
|  struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp,
 | |
|  				    const struct sfp_socket_ops *ops);
 | |
| --- a/include/linux/sfp.h
 | |
| +++ b/include/linux/sfp.h
 | |
| @@ -507,6 +507,8 @@ struct sfp_bus;
 | |
|   * @module_insert: called after a module has been detected to determine
 | |
|   *   whether the module is supported for the upstream device.
 | |
|   * @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
 | |
|   *   reason.
 | |
|   * @link_up: called when the link is operational.
 | |
| @@ -520,6 +522,8 @@ struct sfp_upstream_ops {
 | |
|  	void (*detach)(void *priv, struct sfp_bus *bus);
 | |
|  	int (*module_insert)(void *priv, const struct sfp_eeprom_id *id);
 | |
|  	void (*module_remove)(void *priv);
 | |
| +	int (*module_start)(void *priv);
 | |
| +	void (*module_stop)(void *priv);
 | |
|  	void (*link_down)(void *priv);
 | |
|  	void (*link_up)(void *priv);
 | |
|  	int (*connect_phy)(void *priv, struct phy_device *);
 |