Commit 643510ce authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'net-sfp-add-support-for-control-of-rate-selection'

Russell King says:

====================
net: sfp: add support for control of rate selection

This series introduces control of the rate selection SFP pins (or
their soft state in the I2C diagnostics EEPROM). Several SNIA documents
(referenced in the commits) describe the various different modes for
these, and we implement them all for maximum compatibility, but as
we know, SFP modules tend to do their own thing, so that may not be
sufficient.

In order to implement this, we need to change the locking arrangement
in the SFP layer - we need to make st_mutex (state mutex) able to be
taken from within the rtnl lock and sm_mutex (state machine mutex).
Essentially, st_mutex protects the hard (gpio) and soft state signals.

So, patches 2 through 5 rejig the locking so that st_mutex is only
ever taken when we want to fiddle with the signal state variables,
read or write the GPIOs, or read or write the soft state.

Patch 1 adds a helper that makes the locking rejig a little easier
as it combines the update of sfp->state with setting the updated
control state to the module.

Patch 6 adds code to phylink to give the signalling rate for various
PHY interface modes that are relevant to SFPs - this is the baud rate
of the encoded signal, not the data rate, which is what matters for
SFPs. This rate is passed through the SFP bus layer into the SFP
socket driver, which initially has a stub sfp_set_signal_rate().

Patch 7 adds the code to the SFP socket driver to parse the rate
selection data in the EEPROM, configure which RS signals need to be
driven, and the signalling rate threshold. We fill in
sfp_set_signal_rate() to set the rate select pins as appropriate.
====================

Link: https://lore.kernel.org/r/ZGSuTY8GqjM+sqta@shell.armlinux.org.ukSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 90223c11 fc082b39
...@@ -156,6 +156,23 @@ static const char *phylink_an_mode_str(unsigned int mode) ...@@ -156,6 +156,23 @@ static const char *phylink_an_mode_str(unsigned int mode)
return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown"; return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown";
} }
static unsigned int phylink_interface_signal_rate(phy_interface_t interface)
{
switch (interface) {
case PHY_INTERFACE_MODE_SGMII:
case PHY_INTERFACE_MODE_1000BASEX: /* 1.25Mbd */
return 1250;
case PHY_INTERFACE_MODE_2500BASEX: /* 3.125Mbd */
return 3125;
case PHY_INTERFACE_MODE_5GBASER: /* 5.15625Mbd */
return 5156;
case PHY_INTERFACE_MODE_10GBASER: /* 10.3125Mbd */
return 10313;
default:
return 0;
}
}
/** /**
* phylink_interface_max_speed() - get the maximum speed of a phy interface * phylink_interface_max_speed() - get the maximum speed of a phy interface
* @interface: phy interface mode defined by &typedef phy_interface_t * @interface: phy interface mode defined by &typedef phy_interface_t
...@@ -1025,6 +1042,7 @@ static void phylink_major_config(struct phylink *pl, bool restart, ...@@ -1025,6 +1042,7 @@ static void phylink_major_config(struct phylink *pl, bool restart,
{ {
struct phylink_pcs *pcs = NULL; struct phylink_pcs *pcs = NULL;
bool pcs_changed = false; bool pcs_changed = false;
unsigned int rate_kbd;
int err; int err;
phylink_dbg(pl, "major config %s\n", phy_modes(state->interface)); phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
...@@ -1084,6 +1102,12 @@ static void phylink_major_config(struct phylink *pl, bool restart, ...@@ -1084,6 +1102,12 @@ static void phylink_major_config(struct phylink *pl, bool restart,
ERR_PTR(err)); ERR_PTR(err));
} }
if (pl->sfp_bus) {
rate_kbd = phylink_interface_signal_rate(state->interface);
if (rate_kbd)
sfp_upstream_set_signal_rate(pl->sfp_bus, rate_kbd);
}
phylink_pcs_poll_start(pl); phylink_pcs_poll_start(pl);
} }
......
...@@ -575,6 +575,26 @@ static void sfp_upstream_clear(struct sfp_bus *bus) ...@@ -575,6 +575,26 @@ static void sfp_upstream_clear(struct sfp_bus *bus)
bus->upstream = NULL; bus->upstream = NULL;
} }
/**
* sfp_upstream_set_signal_rate() - set data signalling rate
* @bus: a pointer to the &struct sfp_bus structure for the sfp module
* @rate_kbd: signalling rate in units of 1000 baud
*
* Configure the rate select settings on the SFP module for the signalling
* rate (not the same as the data rate).
*
* Locks that may be held:
* Phylink's state_mutex
* rtnl lock
* SFP's sm_mutex
*/
void sfp_upstream_set_signal_rate(struct sfp_bus *bus, unsigned int rate_kbd)
{
if (bus->registered)
bus->socket_ops->set_signal_rate(bus->sfp, rate_kbd);
}
EXPORT_SYMBOL_GPL(sfp_upstream_set_signal_rate);
/** /**
* sfp_bus_find_fwnode() - parse and locate the SFP bus from fwnode * sfp_bus_find_fwnode() - parse and locate the SFP bus from fwnode
* @fwnode: firmware node for the parent device (MAC or PHY) * @fwnode: firmware node for the parent device (MAC or PHY)
......
This diff is collapsed.
...@@ -19,6 +19,7 @@ struct sfp_socket_ops { ...@@ -19,6 +19,7 @@ struct sfp_socket_ops {
void (*detach)(struct sfp *sfp); void (*detach)(struct sfp *sfp);
void (*start)(struct sfp *sfp); void (*start)(struct sfp *sfp);
void (*stop)(struct sfp *sfp); void (*stop)(struct sfp *sfp);
void (*set_signal_rate)(struct sfp *sfp, unsigned int rate_kbd);
int (*module_info)(struct sfp *sfp, struct ethtool_modinfo *modinfo); int (*module_info)(struct sfp *sfp, struct ethtool_modinfo *modinfo);
int (*module_eeprom)(struct sfp *sfp, struct ethtool_eeprom *ee, int (*module_eeprom)(struct sfp *sfp, struct ethtool_eeprom *ee,
u8 *data); u8 *data);
......
...@@ -342,6 +342,12 @@ enum { ...@@ -342,6 +342,12 @@ enum {
SFP_ENCODING = 11, SFP_ENCODING = 11,
SFP_BR_NOMINAL = 12, SFP_BR_NOMINAL = 12,
SFP_RATE_ID = 13, SFP_RATE_ID = 13,
SFF_RID_8079 = 0x01,
SFF_RID_8431_RX_ONLY = 0x02,
SFF_RID_8431_TX_ONLY = 0x04,
SFF_RID_8431 = 0x06,
SFF_RID_10G8G = 0x0e,
SFP_LINK_LEN_SM_KM = 14, SFP_LINK_LEN_SM_KM = 14,
SFP_LINK_LEN_SM_100M = 15, SFP_LINK_LEN_SM_100M = 15,
SFP_LINK_LEN_50UM_OM2_10M = 16, SFP_LINK_LEN_50UM_OM2_10M = 16,
...@@ -465,6 +471,7 @@ enum { ...@@ -465,6 +471,7 @@ enum {
SFP_STATUS = 110, SFP_STATUS = 110,
SFP_STATUS_TX_DISABLE = BIT(7), SFP_STATUS_TX_DISABLE = BIT(7),
SFP_STATUS_TX_DISABLE_FORCE = BIT(6), SFP_STATUS_TX_DISABLE_FORCE = BIT(6),
SFP_STATUS_RS0_SELECT = BIT(3),
SFP_STATUS_TX_FAULT = BIT(2), SFP_STATUS_TX_FAULT = BIT(2),
SFP_STATUS_RX_LOS = BIT(1), SFP_STATUS_RX_LOS = BIT(1),
SFP_ALARM0 = 112, SFP_ALARM0 = 112,
...@@ -496,6 +503,7 @@ enum { ...@@ -496,6 +503,7 @@ enum {
SFP_WARN1_RXPWR_LOW = BIT(6), SFP_WARN1_RXPWR_LOW = BIT(6),
SFP_EXT_STATUS = 118, SFP_EXT_STATUS = 118,
SFP_EXT_STATUS_RS1_SELECT = BIT(3),
SFP_EXT_STATUS_PWRLVL_SELECT = BIT(0), SFP_EXT_STATUS_PWRLVL_SELECT = BIT(0),
SFP_VSL = 120, SFP_VSL = 120,
...@@ -556,6 +564,7 @@ int sfp_get_module_eeprom_by_page(struct sfp_bus *bus, ...@@ -556,6 +564,7 @@ int sfp_get_module_eeprom_by_page(struct sfp_bus *bus,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
void sfp_upstream_start(struct sfp_bus *bus); void sfp_upstream_start(struct sfp_bus *bus);
void sfp_upstream_stop(struct sfp_bus *bus); void sfp_upstream_stop(struct sfp_bus *bus);
void sfp_upstream_set_signal_rate(struct sfp_bus *bus, unsigned int rate_kbd);
void sfp_bus_put(struct sfp_bus *bus); void sfp_bus_put(struct sfp_bus *bus);
struct sfp_bus *sfp_bus_find_fwnode(const struct fwnode_handle *fwnode); struct sfp_bus *sfp_bus_find_fwnode(const struct fwnode_handle *fwnode);
int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream, int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
...@@ -615,6 +624,11 @@ static inline void sfp_upstream_stop(struct sfp_bus *bus) ...@@ -615,6 +624,11 @@ static inline void sfp_upstream_stop(struct sfp_bus *bus)
{ {
} }
static inline void sfp_upstream_set_signal_rate(struct sfp_bus *bus,
unsigned int rate_kbd)
{
}
static inline void sfp_bus_put(struct sfp_bus *bus) static inline void sfp_bus_put(struct sfp_bus *bus)
{ {
} }
......
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