* [PATCH net-next 0/7] net: sfp: add support for control of rate selection
@ 2023-05-17 10:37 Russell King (Oracle)
2023-05-17 10:37 ` [PATCH net-next 1/7] net: sfp: add helper to modify signal states Russell King (Oracle)
` (7 more replies)
0 siblings, 8 replies; 10+ messages in thread
From: Russell King (Oracle) @ 2023-05-17 10:37 UTC (permalink / raw)
To: Andrew Lunn, Heiner Kallweit
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, netdev,
Paolo Abeni, Daniel Golle, Marek Behún
Hi,
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.
Thanks to Simon for reviewing.
drivers/net/phy/phylink.c | 24 ++++
drivers/net/phy/sfp-bus.c | 20 +++
drivers/net/phy/sfp.c | 310 ++++++++++++++++++++++++++++++++++++++--------
drivers/net/phy/sfp.h | 1 +
include/linux/sfp.h | 14 +++
5 files changed, 317 insertions(+), 52 deletions(-)
--
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 80Mbps down 10Mbps up. Decent connectivity at last!
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH net-next 1/7] net: sfp: add helper to modify signal states
2023-05-17 10:37 [PATCH net-next 0/7] net: sfp: add support for control of rate selection Russell King (Oracle)
@ 2023-05-17 10:37 ` Russell King (Oracle)
2023-05-17 10:37 ` [PATCH net-next 2/7] net: sfp: move rtnl lock to cover reading state Russell King (Oracle)
` (6 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Russell King (Oracle) @ 2023-05-17 10:37 UTC (permalink / raw)
To: Andrew Lunn, Heiner Kallweit
Cc: Marek Behún, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, netdev
There are a couple of locations in the code where we modify
sfp->state, and then call sfp_set_state(, sfp->state) to update
the outputs/soft state to control the module. Provide a helper
which takes a mask and new state so that this is encapsulated in
one location.
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/sfp.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index 89636dc71e48..c97a87393fdb 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -734,6 +734,12 @@ static void sfp_set_state(struct sfp *sfp, unsigned int state)
sfp_soft_set_state(sfp, state);
}
+static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set)
+{
+ sfp->state = (sfp->state & ~mask) | set;
+ sfp_set_state(sfp, sfp->state);
+}
+
static unsigned int sfp_check(void *buf, size_t len)
{
u8 *p, check;
@@ -1537,16 +1543,14 @@ static void sfp_module_tx_disable(struct sfp *sfp)
{
dev_dbg(sfp->dev, "tx disable %u -> %u\n",
sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 1);
- sfp->state |= SFP_F_TX_DISABLE;
- sfp_set_state(sfp, sfp->state);
+ sfp_mod_state(sfp, SFP_F_TX_DISABLE, SFP_F_TX_DISABLE);
}
static void sfp_module_tx_enable(struct sfp *sfp)
{
dev_dbg(sfp->dev, "tx disable %u -> %u\n",
sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 0);
- sfp->state &= ~SFP_F_TX_DISABLE;
- sfp_set_state(sfp, sfp->state);
+ sfp_mod_state(sfp, SFP_F_TX_DISABLE, 0);
}
#if IS_ENABLED(CONFIG_DEBUG_FS)
--
2.30.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 2/7] net: sfp: move rtnl lock to cover reading state
2023-05-17 10:37 [PATCH net-next 0/7] net: sfp: add support for control of rate selection Russell King (Oracle)
2023-05-17 10:37 ` [PATCH net-next 1/7] net: sfp: add helper to modify signal states Russell King (Oracle)
@ 2023-05-17 10:37 ` Russell King (Oracle)
2023-05-17 10:37 ` [PATCH net-next 3/7] net: sfp: swap order of rtnl and st_mutex locks Russell King (Oracle)
` (5 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Russell King (Oracle) @ 2023-05-17 10:37 UTC (permalink / raw)
To: Andrew Lunn, Heiner Kallweit
Cc: Marek Behún, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, netdev
As preparation to moving st_mutex inside rtnl_lock, we need to first
move the rtnl lock to cover reading the state.
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/sfp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index c97a87393fdb..3fc703e4dd21 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -2601,6 +2601,7 @@ static void sfp_check_state(struct sfp *sfp)
unsigned int state, i, changed;
mutex_lock(&sfp->st_mutex);
+ rtnl_lock();
state = sfp_get_state(sfp);
changed = state ^ sfp->state;
if (sfp->tx_fault_ignore)
@@ -2616,7 +2617,6 @@ static void sfp_check_state(struct sfp *sfp)
state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT);
sfp->state = state;
- rtnl_lock();
if (changed & SFP_F_PRESENT)
sfp_sm_event(sfp, state & SFP_F_PRESENT ?
SFP_E_INSERT : SFP_E_REMOVE);
--
2.30.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 3/7] net: sfp: swap order of rtnl and st_mutex locks
2023-05-17 10:37 [PATCH net-next 0/7] net: sfp: add support for control of rate selection Russell King (Oracle)
2023-05-17 10:37 ` [PATCH net-next 1/7] net: sfp: add helper to modify signal states Russell King (Oracle)
2023-05-17 10:37 ` [PATCH net-next 2/7] net: sfp: move rtnl lock to cover reading state Russell King (Oracle)
@ 2023-05-17 10:37 ` Russell King (Oracle)
2023-05-17 10:38 ` [PATCH net-next 4/7] net: sfp: move sm_mutex into sfp_check_state() Russell King (Oracle)
` (4 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Russell King (Oracle) @ 2023-05-17 10:37 UTC (permalink / raw)
To: Andrew Lunn, Heiner Kallweit
Cc: Marek Behún, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, netdev
Swap the order of the rtnl and st_mutex locks - st_mutex is now nested
beneath rtnl lock instead of rtnl being beneath st_mutex. This will
allow us to hold st_mutex only while manipulating the module's hardware
or software control state.
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/sfp.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index 3fc703e4dd21..ffb6c37dac96 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -2600,8 +2600,8 @@ static void sfp_check_state(struct sfp *sfp)
{
unsigned int state, i, changed;
- mutex_lock(&sfp->st_mutex);
rtnl_lock();
+ mutex_lock(&sfp->st_mutex);
state = sfp_get_state(sfp);
changed = state ^ sfp->state;
if (sfp->tx_fault_ignore)
@@ -2628,8 +2628,8 @@ static void sfp_check_state(struct sfp *sfp)
if (changed & SFP_F_LOS)
sfp_sm_event(sfp, state & SFP_F_LOS ?
SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
- rtnl_unlock();
mutex_unlock(&sfp->st_mutex);
+ rtnl_unlock();
}
static irqreturn_t sfp_irq(int irq, void *data)
--
2.30.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 4/7] net: sfp: move sm_mutex into sfp_check_state()
2023-05-17 10:37 [PATCH net-next 0/7] net: sfp: add support for control of rate selection Russell King (Oracle)
` (2 preceding siblings ...)
2023-05-17 10:37 ` [PATCH net-next 3/7] net: sfp: swap order of rtnl and st_mutex locks Russell King (Oracle)
@ 2023-05-17 10:38 ` Russell King (Oracle)
2023-05-17 10:38 ` [PATCH net-next 5/7] net: sfp: change st_mutex locking Russell King (Oracle)
` (3 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Russell King (Oracle) @ 2023-05-17 10:38 UTC (permalink / raw)
To: Andrew Lunn, Heiner Kallweit
Cc: Marek Behún, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, netdev
Provide an unlocked version of sfp_sm_event() which can be used by
sfp_check_state() to avoid having to keep re-taking the lock if
several signals have changed state.
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/sfp.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index ffb6c37dac96..e5cd36e3a421 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -2456,10 +2456,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
}
}
-static void sfp_sm_event(struct sfp *sfp, unsigned int event)
+static void __sfp_sm_event(struct sfp *sfp, unsigned int event)
{
- mutex_lock(&sfp->sm_mutex);
-
dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n",
mod_state_to_str(sfp->sm_mod_state),
dev_state_to_str(sfp->sm_dev_state),
@@ -2474,7 +2472,12 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event)
mod_state_to_str(sfp->sm_mod_state),
dev_state_to_str(sfp->sm_dev_state),
sm_state_to_str(sfp->sm_state));
+}
+static void sfp_sm_event(struct sfp *sfp, unsigned int event)
+{
+ mutex_lock(&sfp->sm_mutex);
+ __sfp_sm_event(sfp, event);
mutex_unlock(&sfp->sm_mutex);
}
@@ -2617,17 +2620,19 @@ static void sfp_check_state(struct sfp *sfp)
state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT);
sfp->state = state;
+ mutex_lock(&sfp->sm_mutex);
if (changed & SFP_F_PRESENT)
- sfp_sm_event(sfp, state & SFP_F_PRESENT ?
- SFP_E_INSERT : SFP_E_REMOVE);
+ __sfp_sm_event(sfp, state & SFP_F_PRESENT ?
+ SFP_E_INSERT : SFP_E_REMOVE);
if (changed & SFP_F_TX_FAULT)
- sfp_sm_event(sfp, state & SFP_F_TX_FAULT ?
- SFP_E_TX_FAULT : SFP_E_TX_CLEAR);
+ __sfp_sm_event(sfp, state & SFP_F_TX_FAULT ?
+ SFP_E_TX_FAULT : SFP_E_TX_CLEAR);
if (changed & SFP_F_LOS)
- sfp_sm_event(sfp, state & SFP_F_LOS ?
- SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
+ __sfp_sm_event(sfp, state & SFP_F_LOS ?
+ SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
+ mutex_unlock(&sfp->sm_mutex);
mutex_unlock(&sfp->st_mutex);
rtnl_unlock();
}
--
2.30.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 5/7] net: sfp: change st_mutex locking
2023-05-17 10:37 [PATCH net-next 0/7] net: sfp: add support for control of rate selection Russell King (Oracle)
` (3 preceding siblings ...)
2023-05-17 10:38 ` [PATCH net-next 4/7] net: sfp: move sm_mutex into sfp_check_state() Russell King (Oracle)
@ 2023-05-17 10:38 ` Russell King (Oracle)
2023-05-17 10:38 ` [PATCH net-next 6/7] net: sfp: add support for setting signalling rate Russell King (Oracle)
` (2 subsequent siblings)
7 siblings, 0 replies; 10+ messages in thread
From: Russell King (Oracle) @ 2023-05-17 10:38 UTC (permalink / raw)
To: Andrew Lunn, Heiner Kallweit
Cc: Marek Behún, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, netdev
Change st_mutex's use within SFP such that it only protects the various
state members, as it was originally supposed to, and isn't held while
making various calls outside the driver.
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/sfp.c | 56 ++++++++++++++++++++++++++++++++-----------
1 file changed, 42 insertions(+), 14 deletions(-)
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index e5cd36e3a421..bf7dac9977e1 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -242,10 +242,17 @@ struct sfp {
bool need_poll;
+ /* Access rules:
+ * state_hw_drive: st_mutex held
+ * state_hw_mask: st_mutex held
+ * state_soft_mask: st_mutex held
+ * state: st_mutex held unless reading input bits
+ */
struct mutex st_mutex; /* Protects state */
unsigned int state_hw_mask;
unsigned int state_soft_mask;
unsigned int state;
+
struct delayed_work poll;
struct delayed_work timeout;
struct mutex sm_mutex; /* Protects state machine */
@@ -692,7 +699,6 @@ static void sfp_soft_start_poll(struct sfp *sfp)
const struct sfp_eeprom_id *id = &sfp->id;
unsigned int mask = 0;
- sfp->state_soft_mask = 0;
if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE)
mask |= SFP_F_TX_DISABLE;
if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT)
@@ -700,19 +706,26 @@ static void sfp_soft_start_poll(struct sfp *sfp)
if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS)
mask |= SFP_F_LOS;
+ mutex_lock(&sfp->st_mutex);
// Poll the soft state for hardware pins we want to ignore
sfp->state_soft_mask = ~sfp->state_hw_mask & mask;
if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
!sfp->need_poll)
mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
+ mutex_unlock(&sfp->st_mutex);
}
static void sfp_soft_stop_poll(struct sfp *sfp)
{
+ mutex_lock(&sfp->st_mutex);
sfp->state_soft_mask = 0;
+ mutex_unlock(&sfp->st_mutex);
}
+/* sfp_get_state() - must be called with st_mutex held, or in the
+ * initialisation path.
+ */
static unsigned int sfp_get_state(struct sfp *sfp)
{
unsigned int soft = sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT);
@@ -725,6 +738,9 @@ static unsigned int sfp_get_state(struct sfp *sfp)
return state;
}
+/* sfp_set_state() - must be called with st_mutex held, or in the
+ * initialisation path.
+ */
static void sfp_set_state(struct sfp *sfp, unsigned int state)
{
sfp->set_state(sfp, state);
@@ -736,8 +752,10 @@ static void sfp_set_state(struct sfp *sfp, unsigned int state)
static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set)
{
+ mutex_lock(&sfp->st_mutex);
sfp->state = (sfp->state & ~mask) | set;
sfp_set_state(sfp, sfp->state);
+ mutex_unlock(&sfp->st_mutex);
}
static unsigned int sfp_check(void *buf, size_t len)
@@ -1603,16 +1621,18 @@ static void sfp_debugfs_exit(struct sfp *sfp)
static void sfp_module_tx_fault_reset(struct sfp *sfp)
{
- unsigned int state = sfp->state;
-
- if (state & SFP_F_TX_DISABLE)
- return;
+ unsigned int state;
- sfp_set_state(sfp, state | SFP_F_TX_DISABLE);
+ mutex_lock(&sfp->st_mutex);
+ state = sfp->state;
+ if (!(state & SFP_F_TX_DISABLE)) {
+ sfp_set_state(sfp, state | SFP_F_TX_DISABLE);
- udelay(T_RESET_US);
+ udelay(T_RESET_US);
- sfp_set_state(sfp, state);
+ sfp_set_state(sfp, state);
+ }
+ mutex_unlock(&sfp->st_mutex);
}
/* SFP state machine */
@@ -1957,6 +1977,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
/* SFP module inserted - read I2C data */
struct sfp_eeprom_id id;
bool cotsworks_sfbg;
+ unsigned int mask;
bool cotsworks;
u8 check;
int ret;
@@ -2096,14 +2117,13 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
if (ret < 0)
return ret;
- /* Initialise state bits to use from hardware */
- sfp->state_hw_mask = SFP_F_PRESENT;
+ mask = SFP_F_PRESENT;
if (sfp->gpio[GPIO_TX_DISABLE])
- sfp->state_hw_mask |= SFP_F_TX_DISABLE;
+ mask |= SFP_F_TX_DISABLE;
if (sfp->gpio[GPIO_TX_FAULT])
- sfp->state_hw_mask |= SFP_F_TX_FAULT;
+ mask |= SFP_F_TX_FAULT;
if (sfp->gpio[GPIO_LOS])
- sfp->state_hw_mask |= SFP_F_LOS;
+ mask |= SFP_F_LOS;
sfp->module_t_start_up = T_START_UP;
sfp->module_t_wait = T_WAIT;
@@ -2121,8 +2141,14 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
sfp->mdio_protocol = MDIO_I2C_NONE;
sfp->quirk = sfp_lookup_quirk(&id);
+
+ mutex_lock(&sfp->st_mutex);
+ /* Initialise state bits to use from hardware */
+ sfp->state_hw_mask = mask;
+
if (sfp->quirk && sfp->quirk->fixup)
sfp->quirk->fixup(sfp);
+ mutex_unlock(&sfp->st_mutex);
return 0;
}
@@ -2619,6 +2645,7 @@ static void sfp_check_state(struct sfp *sfp)
state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT);
sfp->state = state;
+ mutex_unlock(&sfp->st_mutex);
mutex_lock(&sfp->sm_mutex);
if (changed & SFP_F_PRESENT)
@@ -2633,7 +2660,6 @@ static void sfp_check_state(struct sfp *sfp)
__sfp_sm_event(sfp, state & SFP_F_LOS ?
SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
mutex_unlock(&sfp->sm_mutex);
- mutex_unlock(&sfp->st_mutex);
rtnl_unlock();
}
@@ -2652,6 +2678,8 @@ static void sfp_poll(struct work_struct *work)
sfp_check_state(sfp);
+ // st_mutex doesn't need to be held here for state_soft_mask,
+ // it's unimportant if we race while reading this.
if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) ||
sfp->need_poll)
mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
--
2.30.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 6/7] net: sfp: add support for setting signalling rate
2023-05-17 10:37 [PATCH net-next 0/7] net: sfp: add support for control of rate selection Russell King (Oracle)
` (4 preceding siblings ...)
2023-05-17 10:38 ` [PATCH net-next 5/7] net: sfp: change st_mutex locking Russell King (Oracle)
@ 2023-05-17 10:38 ` Russell King (Oracle)
2023-05-17 10:38 ` [PATCH net-next 7/7] net: sfp: add support for rate selection Russell King (Oracle)
2023-05-19 3:00 ` [PATCH net-next 0/7] net: sfp: add support for control of " patchwork-bot+netdevbpf
7 siblings, 0 replies; 10+ messages in thread
From: Russell King (Oracle) @ 2023-05-17 10:38 UTC (permalink / raw)
To: Andrew Lunn, Heiner Kallweit
Cc: Marek Behún, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, netdev
Add support to the SFP layer to allow phylink to set the signalling
rate for a SFP module. The rate given will be in units of kilo-baud
(1000 baud).
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/phylink.c | 24 ++++++++++++++++++++++++
drivers/net/phy/sfp-bus.c | 20 ++++++++++++++++++++
drivers/net/phy/sfp.c | 5 +++++
drivers/net/phy/sfp.h | 1 +
include/linux/sfp.h | 6 ++++++
5 files changed, 56 insertions(+)
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index cf53096047e6..7db67ff2812c 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -156,6 +156,23 @@ static const char *phylink_an_mode_str(unsigned int mode)
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
* @interface: phy interface mode defined by &typedef phy_interface_t
@@ -1025,6 +1042,7 @@ static void phylink_major_config(struct phylink *pl, bool restart,
{
struct phylink_pcs *pcs = NULL;
bool pcs_changed = false;
+ unsigned int rate_kbd;
int err;
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,
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);
}
diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
index 9372e5a4cadc..e8dd47bffe43 100644
--- a/drivers/net/phy/sfp-bus.c
+++ b/drivers/net/phy/sfp-bus.c
@@ -575,6 +575,26 @@ static void sfp_upstream_clear(struct sfp_bus *bus)
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
* @fwnode: firmware node for the parent device (MAC or PHY)
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index bf7dac9977e1..34bf724c00c7 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -2527,6 +2527,10 @@ static void sfp_stop(struct sfp *sfp)
sfp_sm_event(sfp, SFP_E_DEV_DOWN);
}
+static void sfp_set_signal_rate(struct sfp *sfp, unsigned int rate_kbd)
+{
+}
+
static int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo)
{
/* locking... and check module is present */
@@ -2611,6 +2615,7 @@ static const struct sfp_socket_ops sfp_module_ops = {
.detach = sfp_detach,
.start = sfp_start,
.stop = sfp_stop,
+ .set_signal_rate = sfp_set_signal_rate,
.module_info = sfp_module_info,
.module_eeprom = sfp_module_eeprom,
.module_eeprom_by_page = sfp_module_eeprom_by_page,
diff --git a/drivers/net/phy/sfp.h b/drivers/net/phy/sfp.h
index 6cf1643214d3..c7cb50d10099 100644
--- a/drivers/net/phy/sfp.h
+++ b/drivers/net/phy/sfp.h
@@ -19,6 +19,7 @@ struct sfp_socket_ops {
void (*detach)(struct sfp *sfp);
void (*start)(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_eeprom)(struct sfp *sfp, struct ethtool_eeprom *ee,
u8 *data);
diff --git a/include/linux/sfp.h b/include/linux/sfp.h
index ef06a195b3c2..2f66e03e9dbd 100644
--- a/include/linux/sfp.h
+++ b/include/linux/sfp.h
@@ -556,6 +556,7 @@ int sfp_get_module_eeprom_by_page(struct sfp_bus *bus,
struct netlink_ext_ack *extack);
void sfp_upstream_start(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);
struct sfp_bus *sfp_bus_find_fwnode(const struct fwnode_handle *fwnode);
int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
@@ -615,6 +616,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)
{
}
--
2.30.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH net-next 7/7] net: sfp: add support for rate selection
2023-05-17 10:37 [PATCH net-next 0/7] net: sfp: add support for control of rate selection Russell King (Oracle)
` (5 preceding siblings ...)
2023-05-17 10:38 ` [PATCH net-next 6/7] net: sfp: add support for setting signalling rate Russell King (Oracle)
@ 2023-05-17 10:38 ` Russell King (Oracle)
2023-05-17 15:52 ` Andrew Lunn
2023-05-19 3:00 ` [PATCH net-next 0/7] net: sfp: add support for control of " patchwork-bot+netdevbpf
7 siblings, 1 reply; 10+ messages in thread
From: Russell King (Oracle) @ 2023-05-17 10:38 UTC (permalink / raw)
To: Andrew Lunn, Heiner Kallweit
Cc: Marek Behún, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, netdev
Add support for parsing the rate select thresholds and switching of the
RS0 and RS1 signals to the transceiver. This is complicated by various
revisions of SFF-8472 and interaction of SFF-8431, SFF-8079 and
INF-8074.
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/sfp.c | 212 +++++++++++++++++++++++++++++++++++++-----
include/linux/sfp.h | 8 ++
2 files changed, 196 insertions(+), 24 deletions(-)
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index 34bf724c00c7..4799976a1609 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -24,14 +24,18 @@ enum {
GPIO_LOS,
GPIO_TX_FAULT,
GPIO_TX_DISABLE,
- GPIO_RATE_SELECT,
+ GPIO_RS0,
+ GPIO_RS1,
GPIO_MAX,
SFP_F_PRESENT = BIT(GPIO_MODDEF0),
SFP_F_LOS = BIT(GPIO_LOS),
SFP_F_TX_FAULT = BIT(GPIO_TX_FAULT),
SFP_F_TX_DISABLE = BIT(GPIO_TX_DISABLE),
- SFP_F_RATE_SELECT = BIT(GPIO_RATE_SELECT),
+ SFP_F_RS0 = BIT(GPIO_RS0),
+ SFP_F_RS1 = BIT(GPIO_RS1),
+
+ SFP_F_OUTPUTS = SFP_F_TX_DISABLE | SFP_F_RS0 | SFP_F_RS1,
SFP_E_INSERT = 0,
SFP_E_REMOVE,
@@ -148,6 +152,7 @@ static const char *gpio_names[] = {
"tx-fault",
"tx-disable",
"rate-select0",
+ "rate-select1",
};
static const enum gpiod_flags gpio_flags[] = {
@@ -156,6 +161,7 @@ static const enum gpiod_flags gpio_flags[] = {
GPIOD_IN,
GPIOD_ASIS,
GPIOD_ASIS,
+ GPIOD_ASIS,
};
/* t_start_up (SFF-8431) or t_init (SFF-8472) is the time required for a
@@ -249,6 +255,7 @@ struct sfp {
* state: st_mutex held unless reading input bits
*/
struct mutex st_mutex; /* Protects state */
+ unsigned int state_hw_drive;
unsigned int state_hw_mask;
unsigned int state_soft_mask;
unsigned int state;
@@ -269,6 +276,10 @@ struct sfp {
unsigned int module_t_start_up;
unsigned int module_t_wait;
+ unsigned int rate_kbd;
+ unsigned int rs_threshold_kbd;
+ unsigned int rs_state_mask;
+
bool have_a2;
bool tx_fault_ignore;
@@ -319,7 +330,7 @@ static bool sfp_module_supported(const struct sfp_eeprom_id *id)
static const struct sff_data sfp_data = {
.gpios = SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT |
- SFP_F_TX_DISABLE | SFP_F_RATE_SELECT,
+ SFP_F_TX_DISABLE | SFP_F_RS0 | SFP_F_RS1,
.module_supported = sfp_module_supported,
};
@@ -507,20 +518,37 @@ static unsigned int sff_gpio_get_state(struct sfp *sfp)
static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state)
{
- if (state & SFP_F_PRESENT) {
- /* If the module is present, drive the signals */
- if (sfp->gpio[GPIO_TX_DISABLE])
+ unsigned int drive;
+
+ if (state & SFP_F_PRESENT)
+ /* If the module is present, drive the requested signals */
+ drive = sfp->state_hw_drive;
+ else
+ /* Otherwise, let them float to the pull-ups */
+ drive = 0;
+
+ if (sfp->gpio[GPIO_TX_DISABLE]) {
+ if (drive & SFP_F_TX_DISABLE)
gpiod_direction_output(sfp->gpio[GPIO_TX_DISABLE],
state & SFP_F_TX_DISABLE);
- if (state & SFP_F_RATE_SELECT)
- gpiod_direction_output(sfp->gpio[GPIO_RATE_SELECT],
- state & SFP_F_RATE_SELECT);
- } else {
- /* Otherwise, let them float to the pull-ups */
- if (sfp->gpio[GPIO_TX_DISABLE])
+ else
gpiod_direction_input(sfp->gpio[GPIO_TX_DISABLE]);
- if (state & SFP_F_RATE_SELECT)
- gpiod_direction_input(sfp->gpio[GPIO_RATE_SELECT]);
+ }
+
+ if (sfp->gpio[GPIO_RS0]) {
+ if (drive & SFP_F_RS0)
+ gpiod_direction_output(sfp->gpio[GPIO_RS0],
+ state & SFP_F_RS0);
+ else
+ gpiod_direction_input(sfp->gpio[GPIO_RS0]);
+ }
+
+ if (sfp->gpio[GPIO_RS1]) {
+ if (drive & SFP_F_RS1)
+ gpiod_direction_output(sfp->gpio[GPIO_RS1],
+ state & SFP_F_RS1);
+ else
+ gpiod_direction_input(sfp->gpio[GPIO_RS1]);
}
}
@@ -682,16 +710,33 @@ static unsigned int sfp_soft_get_state(struct sfp *sfp)
return state & sfp->state_soft_mask;
}
-static void sfp_soft_set_state(struct sfp *sfp, unsigned int state)
+static void sfp_soft_set_state(struct sfp *sfp, unsigned int state,
+ unsigned int soft)
{
- u8 mask = SFP_STATUS_TX_DISABLE_FORCE;
+ u8 mask = 0;
u8 val = 0;
+ if (soft & SFP_F_TX_DISABLE)
+ mask |= SFP_STATUS_TX_DISABLE_FORCE;
if (state & SFP_F_TX_DISABLE)
val |= SFP_STATUS_TX_DISABLE_FORCE;
+ if (soft & SFP_F_RS0)
+ mask |= SFP_STATUS_RS0_SELECT;
+ if (state & SFP_F_RS0)
+ val |= SFP_STATUS_RS0_SELECT;
+
+ if (mask)
+ sfp_modify_u8(sfp, true, SFP_STATUS, mask, val);
- sfp_modify_u8(sfp, true, SFP_STATUS, mask, val);
+ val = mask = 0;
+ if (soft & SFP_F_RS1)
+ mask |= SFP_EXT_STATUS_RS1_SELECT;
+ if (state & SFP_F_RS1)
+ val |= SFP_EXT_STATUS_RS1_SELECT;
+
+ if (mask)
+ sfp_modify_u8(sfp, true, SFP_EXT_STATUS, mask, val);
}
static void sfp_soft_start_poll(struct sfp *sfp)
@@ -705,6 +750,8 @@ static void sfp_soft_start_poll(struct sfp *sfp)
mask |= SFP_F_TX_FAULT;
if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS)
mask |= SFP_F_LOS;
+ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RATE_SELECT)
+ mask |= sfp->rs_state_mask;
mutex_lock(&sfp->st_mutex);
// Poll the soft state for hardware pins we want to ignore
@@ -743,11 +790,13 @@ static unsigned int sfp_get_state(struct sfp *sfp)
*/
static void sfp_set_state(struct sfp *sfp, unsigned int state)
{
+ unsigned int soft;
+
sfp->set_state(sfp, state);
- if (state & SFP_F_PRESENT &&
- sfp->state_soft_mask & SFP_F_TX_DISABLE)
- sfp_soft_set_state(sfp, state);
+ soft = sfp->state_soft_mask & SFP_F_OUTPUTS;
+ if (state & SFP_F_PRESENT && soft)
+ sfp_soft_set_state(sfp, state, soft);
}
static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set)
@@ -1589,10 +1638,15 @@ static int sfp_debug_state_show(struct seq_file *s, void *data)
sfp->sm_fault_retries);
seq_printf(s, "PHY probe remaining retries: %d\n",
sfp->sm_phy_retries);
+ seq_printf(s, "Signalling rate: %u kBd\n", sfp->rate_kbd);
+ seq_printf(s, "Rate select threshold: %u kBd\n",
+ sfp->rs_threshold_kbd);
seq_printf(s, "moddef0: %d\n", !!(sfp->state & SFP_F_PRESENT));
seq_printf(s, "rx_los: %d\n", !!(sfp->state & SFP_F_LOS));
seq_printf(s, "tx_fault: %d\n", !!(sfp->state & SFP_F_TX_FAULT));
seq_printf(s, "tx_disable: %d\n", !!(sfp->state & SFP_F_TX_DISABLE));
+ seq_printf(s, "rs0: %d\n", !!(sfp->state & SFP_F_RS0));
+ seq_printf(s, "rs1: %d\n", !!(sfp->state & SFP_F_RS1));
return 0;
}
DEFINE_SHOW_ATTRIBUTE(sfp_debug_state);
@@ -1898,6 +1952,95 @@ static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable)
return 0;
}
+static void sfp_module_parse_rate_select(struct sfp *sfp)
+{
+ u8 rate_id;
+
+ sfp->rs_threshold_kbd = 0;
+ sfp->rs_state_mask = 0;
+
+ if (!(sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_RATE_SELECT)))
+ /* No support for RateSelect */
+ return;
+
+ /* Default to INF-8074 RateSelect operation. The signalling threshold
+ * rate is not well specified, so always select "Full Bandwidth", but
+ * SFF-8079 reveals that it is understood that RS0 will be low for
+ * 1.0625Gb/s and high for 2.125Gb/s. Choose a value half-way between.
+ * This method exists prior to SFF-8472.
+ */
+ sfp->rs_state_mask = SFP_F_RS0;
+ sfp->rs_threshold_kbd = 1594;
+
+ /* Parse the rate identifier, which is complicated due to history:
+ * SFF-8472 rev 9.5 marks this field as reserved.
+ * SFF-8079 references SFF-8472 rev 9.5 and defines bit 0. SFF-8472
+ * compliance is not required.
+ * SFF-8472 rev 10.2 defines this field using values 0..4
+ * SFF-8472 rev 11.0 redefines this field with bit 0 for SFF-8079
+ * and even values.
+ */
+ rate_id = sfp->id.base.rate_id;
+ if (rate_id == 0)
+ /* Unspecified */
+ return;
+
+ /* SFF-8472 rev 10.0..10.4 did not account for SFF-8079 using bit 0,
+ * and allocated value 3 to SFF-8431 independent tx/rx rate select.
+ * Convert this to a SFF-8472 rev 11.0 rate identifier.
+ */
+ if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV10_2 &&
+ sfp->id.ext.sff8472_compliance < SFP_SFF8472_COMPLIANCE_REV11_0 &&
+ rate_id == 3)
+ rate_id = SFF_RID_8431;
+
+ if (rate_id & SFF_RID_8079) {
+ /* SFF-8079 RateSelect / Application Select in conjunction with
+ * SFF-8472 rev 9.5. SFF-8079 defines rate_id as a bitfield
+ * with only bit 0 used, which takes precedence over SFF-8472.
+ */
+ if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_APP_SELECT_SFF8079)) {
+ /* SFF-8079 Part 1 - rate selection between Fibre
+ * Channel 1.0625/2.125/4.25 Gbd modes. Note that RS0
+ * is high for 2125, so we have to subtract 1 to
+ * include it.
+ */
+ sfp->rs_threshold_kbd = 2125 - 1;
+ sfp->rs_state_mask = SFP_F_RS0;
+ }
+ return;
+ }
+
+ /* SFF-8472 rev 9.5 does not define the rate identifier */
+ if (sfp->id.ext.sff8472_compliance <= SFP_SFF8472_COMPLIANCE_REV9_5)
+ return;
+
+ /* SFF-8472 rev 11.0 defines rate_id as a numerical value which will
+ * always have bit 0 clear due to SFF-8079's bitfield usage of rate_id.
+ */
+ switch (rate_id) {
+ case SFF_RID_8431_RX_ONLY:
+ sfp->rs_threshold_kbd = 4250;
+ sfp->rs_state_mask = SFP_F_RS0;
+ break;
+
+ case SFF_RID_8431_TX_ONLY:
+ sfp->rs_threshold_kbd = 4250;
+ sfp->rs_state_mask = SFP_F_RS1;
+ break;
+
+ case SFF_RID_8431:
+ sfp->rs_threshold_kbd = 4250;
+ sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1;
+ break;
+
+ case SFF_RID_10G8G:
+ sfp->rs_threshold_kbd = 9000;
+ sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1;
+ break;
+ }
+}
+
/* GPON modules based on Realtek RTL8672 and RTL9601C chips (e.g. V-SOL
* V2801F, CarlitoxxPro CPGOS03-0490, Ubiquiti U-Fiber Instant, ...) do
* not support multibyte reads from the EEPROM. Each multi-byte read
@@ -2117,6 +2260,8 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
if (ret < 0)
return ret;
+ sfp_module_parse_rate_select(sfp);
+
mask = SFP_F_PRESENT;
if (sfp->gpio[GPIO_TX_DISABLE])
mask |= SFP_F_TX_DISABLE;
@@ -2124,6 +2269,10 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
mask |= SFP_F_TX_FAULT;
if (sfp->gpio[GPIO_LOS])
mask |= SFP_F_LOS;
+ if (sfp->gpio[GPIO_RS0])
+ mask |= SFP_F_RS0;
+ if (sfp->gpio[GPIO_RS1])
+ mask |= SFP_F_RS1;
sfp->module_t_start_up = T_START_UP;
sfp->module_t_wait = T_WAIT;
@@ -2146,6 +2295,9 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
/* Initialise state bits to use from hardware */
sfp->state_hw_mask = mask;
+ /* We want to drive the rate select pins that the module is using */
+ sfp->state_hw_drive |= sfp->rs_state_mask;
+
if (sfp->quirk && sfp->quirk->fixup)
sfp->quirk->fixup(sfp);
mutex_unlock(&sfp->st_mutex);
@@ -2162,6 +2314,7 @@ static void sfp_sm_mod_remove(struct sfp *sfp)
memset(&sfp->id, 0, sizeof(sfp->id));
sfp->module_power_mW = 0;
+ sfp->state_hw_drive = SFP_F_TX_DISABLE;
sfp->have_a2 = false;
dev_info(sfp->dev, "module removed\n");
@@ -2529,6 +2682,16 @@ static void sfp_stop(struct sfp *sfp)
static void sfp_set_signal_rate(struct sfp *sfp, unsigned int rate_kbd)
{
+ unsigned int set;
+
+ sfp->rate_kbd = rate_kbd;
+
+ if (rate_kbd > sfp->rs_threshold_kbd)
+ set = sfp->rs_state_mask;
+ else
+ set = 0;
+
+ sfp_mod_state(sfp, SFP_F_RS0 | SFP_F_RS1, set);
}
static int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo)
@@ -2648,7 +2811,7 @@ static void sfp_check_state(struct sfp *sfp)
dev_dbg(sfp->dev, "%s %u -> %u\n", gpio_names[i],
!!(sfp->state & BIT(i)), !!(state & BIT(i)));
- state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT);
+ state |= sfp->state & SFP_F_OUTPUTS;
sfp->state = state;
mutex_unlock(&sfp->st_mutex);
@@ -2790,6 +2953,7 @@ static int sfp_probe(struct platform_device *pdev)
}
sfp->state_hw_mask = SFP_F_PRESENT;
+ sfp->state_hw_drive = SFP_F_TX_DISABLE;
sfp->get_state = sfp_gpio_get_state;
sfp->set_state = sfp_gpio_set_state;
@@ -2815,9 +2979,9 @@ static int sfp_probe(struct platform_device *pdev)
*/
sfp->state = sfp_get_state(sfp) | SFP_F_TX_DISABLE;
- if (sfp->gpio[GPIO_RATE_SELECT] &&
- gpiod_get_value_cansleep(sfp->gpio[GPIO_RATE_SELECT]))
- sfp->state |= SFP_F_RATE_SELECT;
+ if (sfp->gpio[GPIO_RS0] &&
+ gpiod_get_value_cansleep(sfp->gpio[GPIO_RS0]))
+ sfp->state |= SFP_F_RS0;
sfp_set_state(sfp, sfp->state);
sfp_module_tx_disable(sfp);
if (sfp->state & SFP_F_PRESENT) {
diff --git a/include/linux/sfp.h b/include/linux/sfp.h
index 2f66e03e9dbd..9346cd44814d 100644
--- a/include/linux/sfp.h
+++ b/include/linux/sfp.h
@@ -342,6 +342,12 @@ enum {
SFP_ENCODING = 11,
SFP_BR_NOMINAL = 12,
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_100M = 15,
SFP_LINK_LEN_50UM_OM2_10M = 16,
@@ -465,6 +471,7 @@ enum {
SFP_STATUS = 110,
SFP_STATUS_TX_DISABLE = BIT(7),
SFP_STATUS_TX_DISABLE_FORCE = BIT(6),
+ SFP_STATUS_RS0_SELECT = BIT(3),
SFP_STATUS_TX_FAULT = BIT(2),
SFP_STATUS_RX_LOS = BIT(1),
SFP_ALARM0 = 112,
@@ -496,6 +503,7 @@ enum {
SFP_WARN1_RXPWR_LOW = BIT(6),
SFP_EXT_STATUS = 118,
+ SFP_EXT_STATUS_RS1_SELECT = BIT(3),
SFP_EXT_STATUS_PWRLVL_SELECT = BIT(0),
SFP_VSL = 120,
--
2.30.2
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH net-next 7/7] net: sfp: add support for rate selection
2023-05-17 10:38 ` [PATCH net-next 7/7] net: sfp: add support for rate selection Russell King (Oracle)
@ 2023-05-17 15:52 ` Andrew Lunn
0 siblings, 0 replies; 10+ messages in thread
From: Andrew Lunn @ 2023-05-17 15:52 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: Heiner Kallweit, Marek Behún, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, netdev
> +static void sfp_module_parse_rate_select(struct sfp *sfp)
> +{
> + u8 rate_id;
> +
> + sfp->rs_threshold_kbd = 0;
> + sfp->rs_state_mask = 0;
> +
> + if (!(sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_RATE_SELECT)))
> + /* No support for RateSelect */
> + return;
> +
> + /* Default to INF-8074 RateSelect operation. The signalling threshold
> + * rate is not well specified, so always select "Full Bandwidth", but
> + * SFF-8079 reveals that it is understood that RS0 will be low for
> + * 1.0625Gb/s and high for 2.125Gb/s. Choose a value half-way between.
> + * This method exists prior to SFF-8472.
> + */
> + sfp->rs_state_mask = SFP_F_RS0;
> + sfp->rs_threshold_kbd = 1594;
> +
> + /* Parse the rate identifier, which is complicated due to history:
> + * SFF-8472 rev 9.5 marks this field as reserved.
> + * SFF-8079 references SFF-8472 rev 9.5 and defines bit 0. SFF-8472
> + * compliance is not required.
> + * SFF-8472 rev 10.2 defines this field using values 0..4
> + * SFF-8472 rev 11.0 redefines this field with bit 0 for SFF-8079
> + * and even values.
> + */
> + rate_id = sfp->id.base.rate_id;
> + if (rate_id == 0)
> + /* Unspecified */
> + return;
> +
> + /* SFF-8472 rev 10.0..10.4 did not account for SFF-8079 using bit 0,
> + * and allocated value 3 to SFF-8431 independent tx/rx rate select.
> + * Convert this to a SFF-8472 rev 11.0 rate identifier.
> + */
> + if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV10_2 &&
> + sfp->id.ext.sff8472_compliance < SFP_SFF8472_COMPLIANCE_REV11_0 &&
> + rate_id == 3)
> + rate_id = SFF_RID_8431;
> +
> + if (rate_id & SFF_RID_8079) {
> + /* SFF-8079 RateSelect / Application Select in conjunction with
> + * SFF-8472 rev 9.5. SFF-8079 defines rate_id as a bitfield
> + * with only bit 0 used, which takes precedence over SFF-8472.
> + */
> + if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_APP_SELECT_SFF8079)) {
> + /* SFF-8079 Part 1 - rate selection between Fibre
> + * Channel 1.0625/2.125/4.25 Gbd modes. Note that RS0
> + * is high for 2125, so we have to subtract 1 to
> + * include it.
> + */
> + sfp->rs_threshold_kbd = 2125 - 1;
> + sfp->rs_state_mask = SFP_F_RS0;
> + }
> + return;
> + }
> +
> + /* SFF-8472 rev 9.5 does not define the rate identifier */
> + if (sfp->id.ext.sff8472_compliance <= SFP_SFF8472_COMPLIANCE_REV9_5)
> + return;
> +
> + /* SFF-8472 rev 11.0 defines rate_id as a numerical value which will
> + * always have bit 0 clear due to SFF-8079's bitfield usage of rate_id.
> + */
> + switch (rate_id) {
> + case SFF_RID_8431_RX_ONLY:
> + sfp->rs_threshold_kbd = 4250;
> + sfp->rs_state_mask = SFP_F_RS0;
> + break;
> +
> + case SFF_RID_8431_TX_ONLY:
> + sfp->rs_threshold_kbd = 4250;
> + sfp->rs_state_mask = SFP_F_RS1;
> + break;
> +
> + case SFF_RID_8431:
> + sfp->rs_threshold_kbd = 4250;
> + sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1;
> + break;
> +
> + case SFF_RID_10G8G:
> + sfp->rs_threshold_kbd = 9000;
> + sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1;
> + break;
> + }
> +}
Having read all that, you can kind of understand why few vendors get
SFP EEPROMs correct.
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH net-next 0/7] net: sfp: add support for control of rate selection
2023-05-17 10:37 [PATCH net-next 0/7] net: sfp: add support for control of rate selection Russell King (Oracle)
` (6 preceding siblings ...)
2023-05-17 10:38 ` [PATCH net-next 7/7] net: sfp: add support for rate selection Russell King (Oracle)
@ 2023-05-19 3:00 ` patchwork-bot+netdevbpf
7 siblings, 0 replies; 10+ messages in thread
From: patchwork-bot+netdevbpf @ 2023-05-19 3:00 UTC (permalink / raw)
To: Russell King
Cc: andrew, hkallweit1, davem, edumazet, kuba, netdev, pabeni, daniel,
kabel
Hello:
This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Wed, 17 May 2023 11:37:01 +0100 you wrote:
> Hi,
>
> 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.
>
> [...]
Here is the summary with links:
- [net-next,1/7] net: sfp: add helper to modify signal states
https://git.kernel.org/netdev/net-next/c/418c1214741c
- [net-next,2/7] net: sfp: move rtnl lock to cover reading state
https://git.kernel.org/netdev/net-next/c/d47e5a430dfd
- [net-next,3/7] net: sfp: swap order of rtnl and st_mutex locks
https://git.kernel.org/netdev/net-next/c/a9fe964e7aae
- [net-next,4/7] net: sfp: move sm_mutex into sfp_check_state()
https://git.kernel.org/netdev/net-next/c/97a492050aa5
- [net-next,5/7] net: sfp: change st_mutex locking
https://git.kernel.org/netdev/net-next/c/1974fd3bf0f0
- [net-next,6/7] net: sfp: add support for setting signalling rate
https://git.kernel.org/netdev/net-next/c/dc18582211b3
- [net-next,7/7] net: sfp: add support for rate selection
https://git.kernel.org/netdev/net-next/c/fc082b39d0a2
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2023-05-19 3:00 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-05-17 10:37 [PATCH net-next 0/7] net: sfp: add support for control of rate selection Russell King (Oracle)
2023-05-17 10:37 ` [PATCH net-next 1/7] net: sfp: add helper to modify signal states Russell King (Oracle)
2023-05-17 10:37 ` [PATCH net-next 2/7] net: sfp: move rtnl lock to cover reading state Russell King (Oracle)
2023-05-17 10:37 ` [PATCH net-next 3/7] net: sfp: swap order of rtnl and st_mutex locks Russell King (Oracle)
2023-05-17 10:38 ` [PATCH net-next 4/7] net: sfp: move sm_mutex into sfp_check_state() Russell King (Oracle)
2023-05-17 10:38 ` [PATCH net-next 5/7] net: sfp: change st_mutex locking Russell King (Oracle)
2023-05-17 10:38 ` [PATCH net-next 6/7] net: sfp: add support for setting signalling rate Russell King (Oracle)
2023-05-17 10:38 ` [PATCH net-next 7/7] net: sfp: add support for rate selection Russell King (Oracle)
2023-05-17 15:52 ` Andrew Lunn
2023-05-19 3:00 ` [PATCH net-next 0/7] net: sfp: add support for control of " patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).