aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/generic/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch')
-rw-r--r--target/linux/generic/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch153
1 files changed, 153 insertions, 0 deletions
diff --git a/target/linux/generic/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch b/target/linux/generic/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch
new file mode 100644
index 0000000000..5ee44dbf0c
--- /dev/null
+++ b/target/linux/generic/backport-5.4/732-v5.5-net-sfp-track-upstream-s-attachment-state-in-state-m.patch
@@ -0,0 +1,153 @@
+From ec6036a58f979c66bbd5cd9d0d1c783a98c2c644 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Tue, 5 Nov 2019 12:57:40 +0000
+Subject: [PATCH 630/660] net: sfp: track upstream's attachment state in state
+ machine
+
+Track the upstream's attachment state in the state machine rather than
+maintaining a boolean, which ensures that we have a strict order of
+ATTACH followed by an UP event - we can never believe that a newly
+attached upstream will be anything but down.
+
+Rearrange the order of state machines so we run the module state
+machine after the upstream device's state machine, so the module state
+machine can check the current state of the device and take action to
+e.g. reset back to empty state when the upstream is detached.
+
+This is to allow the module detection to run independently of the
+network device becoming available.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 42 +++++++++++++++++++++++++++++-------------
+ 1 file changed, 29 insertions(+), 13 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -34,6 +34,8 @@ enum {
+
+ SFP_E_INSERT = 0,
+ SFP_E_REMOVE,
++ SFP_E_DEV_ATTACH,
++ SFP_E_DEV_DETACH,
+ SFP_E_DEV_DOWN,
+ SFP_E_DEV_UP,
+ SFP_E_TX_FAULT,
+@@ -48,7 +50,8 @@ enum {
+ SFP_MOD_PRESENT,
+ SFP_MOD_ERROR,
+
+- SFP_DEV_DOWN = 0,
++ SFP_DEV_DETACHED = 0,
++ SFP_DEV_DOWN,
+ SFP_DEV_UP,
+
+ SFP_S_DOWN = 0,
+@@ -78,6 +81,7 @@ static const char *mod_state_to_str(unsi
+ }
+
+ static const char * const dev_state_strings[] = {
++ [SFP_DEV_DETACHED] = "detached",
+ [SFP_DEV_DOWN] = "down",
+ [SFP_DEV_UP] = "up",
+ };
+@@ -92,6 +96,8 @@ static const char *dev_state_to_str(unsi
+ static const char * const event_strings[] = {
+ [SFP_E_INSERT] = "insert",
+ [SFP_E_REMOVE] = "remove",
++ [SFP_E_DEV_ATTACH] = "dev_attach",
++ [SFP_E_DEV_DETACH] = "dev_detach",
+ [SFP_E_DEV_DOWN] = "dev_down",
+ [SFP_E_DEV_UP] = "dev_up",
+ [SFP_E_TX_FAULT] = "tx_fault",
+@@ -186,7 +192,6 @@ struct sfp {
+ struct gpio_desc *gpio[GPIO_MAX];
+ int gpio_irq[GPIO_MAX];
+
+- bool attached;
+ struct mutex st_mutex; /* Protects state */
+ unsigned int state;
+ struct delayed_work poll;
+@@ -1494,17 +1499,26 @@ static void sfp_sm_mod_remove(struct sfp
+ dev_info(sfp->dev, "module removed\n");
+ }
+
+-/* This state machine tracks the netdev up/down state */
++/* This state machine tracks the upstream's state */
+ static void sfp_sm_device(struct sfp *sfp, unsigned int event)
+ {
+ switch (sfp->sm_dev_state) {
+ default:
+- if (event == SFP_E_DEV_UP)
++ if (event == SFP_E_DEV_ATTACH)
++ sfp->sm_dev_state = SFP_DEV_DOWN;
++ break;
++
++ case SFP_DEV_DOWN:
++ if (event == SFP_E_DEV_DETACH)
++ sfp->sm_dev_state = SFP_DEV_DETACHED;
++ else if (event == SFP_E_DEV_UP)
+ sfp->sm_dev_state = SFP_DEV_UP;
+ break;
+
+ case SFP_DEV_UP:
+- if (event == SFP_E_DEV_DOWN)
++ if (event == SFP_E_DEV_DETACH)
++ sfp->sm_dev_state = SFP_DEV_DETACHED;
++ else if (event == SFP_E_DEV_DOWN)
+ sfp->sm_dev_state = SFP_DEV_DOWN;
+ break;
+ }
+@@ -1515,17 +1529,20 @@ static void sfp_sm_device(struct sfp *sf
+ */
+ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
+ {
+- /* Handle remove event globally, it resets this state machine */
+- if (event == SFP_E_REMOVE) {
++ /* Handle remove event globally, it resets this state machine.
++ * Also deal with upstream detachment.
++ */
++ if (event == SFP_E_REMOVE || sfp->sm_dev_state < SFP_DEV_DOWN) {
+ if (sfp->sm_mod_state > SFP_MOD_PROBE)
+ sfp_sm_mod_remove(sfp);
+- sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
++ if (sfp->sm_mod_state != SFP_MOD_EMPTY)
++ sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+ return;
+ }
+
+ switch (sfp->sm_mod_state) {
+ default:
+- if (event == SFP_E_INSERT && sfp->attached)
++ if (event == SFP_E_INSERT)
+ sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
+ break;
+
+@@ -1691,8 +1708,8 @@ static void sfp_sm_event(struct sfp *sfp
+ sm_state_to_str(sfp->sm_state),
+ event_to_str(event));
+
+- sfp_sm_module(sfp, event);
+ sfp_sm_device(sfp, event);
++ sfp_sm_module(sfp, event);
+ sfp_sm_main(sfp, event);
+
+ dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n",
+@@ -1705,15 +1722,14 @@ static void sfp_sm_event(struct sfp *sfp
+
+ static void sfp_attach(struct sfp *sfp)
+ {
+- sfp->attached = true;
++ sfp_sm_event(sfp, SFP_E_DEV_ATTACH);
+ if (sfp->state & SFP_F_PRESENT)
+ sfp_sm_event(sfp, SFP_E_INSERT);
+ }
+
+ static void sfp_detach(struct sfp *sfp)
+ {
+- sfp->attached = false;
+- sfp_sm_event(sfp, SFP_E_REMOVE);
++ sfp_sm_event(sfp, SFP_E_DEV_DETACH);
+ }
+
+ static void sfp_start(struct sfp *sfp)