b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | From ec6036a58f979c66bbd5cd9d0d1c783a98c2c644 Mon Sep 17 00:00:00 2001 |
| 2 | From: Russell King <rmk+kernel@armlinux.org.uk> |
| 3 | Date: Tue, 5 Nov 2019 12:57:40 +0000 |
| 4 | Subject: [PATCH 630/660] net: sfp: track upstream's attachment state in state |
| 5 | machine |
| 6 | |
| 7 | Track the upstream's attachment state in the state machine rather than |
| 8 | maintaining a boolean, which ensures that we have a strict order of |
| 9 | ATTACH followed by an UP event - we can never believe that a newly |
| 10 | attached upstream will be anything but down. |
| 11 | |
| 12 | Rearrange the order of state machines so we run the module state |
| 13 | machine after the upstream device's state machine, so the module state |
| 14 | machine can check the current state of the device and take action to |
| 15 | e.g. reset back to empty state when the upstream is detached. |
| 16 | |
| 17 | This is to allow the module detection to run independently of the |
| 18 | network device becoming available. |
| 19 | |
| 20 | Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> |
| 21 | --- |
| 22 | drivers/net/phy/sfp.c | 42 +++++++++++++++++++++++++++++------------- |
| 23 | 1 file changed, 29 insertions(+), 13 deletions(-) |
| 24 | |
| 25 | --- a/drivers/net/phy/sfp.c |
| 26 | +++ b/drivers/net/phy/sfp.c |
| 27 | @@ -36,6 +36,8 @@ enum { |
| 28 | |
| 29 | SFP_E_INSERT = 0, |
| 30 | SFP_E_REMOVE, |
| 31 | + SFP_E_DEV_ATTACH, |
| 32 | + SFP_E_DEV_DETACH, |
| 33 | SFP_E_DEV_DOWN, |
| 34 | SFP_E_DEV_UP, |
| 35 | SFP_E_TX_FAULT, |
| 36 | @@ -50,7 +52,8 @@ enum { |
| 37 | SFP_MOD_PRESENT, |
| 38 | SFP_MOD_ERROR, |
| 39 | |
| 40 | - SFP_DEV_DOWN = 0, |
| 41 | + SFP_DEV_DETACHED = 0, |
| 42 | + SFP_DEV_DOWN, |
| 43 | SFP_DEV_UP, |
| 44 | |
| 45 | SFP_S_DOWN = 0, |
| 46 | @@ -80,6 +83,7 @@ static const char *mod_state_to_str(unsi |
| 47 | } |
| 48 | |
| 49 | static const char * const dev_state_strings[] = { |
| 50 | + [SFP_DEV_DETACHED] = "detached", |
| 51 | [SFP_DEV_DOWN] = "down", |
| 52 | [SFP_DEV_UP] = "up", |
| 53 | }; |
| 54 | @@ -94,6 +98,8 @@ static const char *dev_state_to_str(unsi |
| 55 | static const char * const event_strings[] = { |
| 56 | [SFP_E_INSERT] = "insert", |
| 57 | [SFP_E_REMOVE] = "remove", |
| 58 | + [SFP_E_DEV_ATTACH] = "dev_attach", |
| 59 | + [SFP_E_DEV_DETACH] = "dev_detach", |
| 60 | [SFP_E_DEV_DOWN] = "dev_down", |
| 61 | [SFP_E_DEV_UP] = "dev_up", |
| 62 | [SFP_E_TX_FAULT] = "tx_fault", |
| 63 | @@ -188,7 +194,6 @@ struct sfp { |
| 64 | struct gpio_desc *gpio[GPIO_MAX]; |
| 65 | int gpio_irq[GPIO_MAX]; |
| 66 | |
| 67 | - bool attached; |
| 68 | struct mutex st_mutex; /* Protects state */ |
| 69 | unsigned int state; |
| 70 | struct delayed_work poll; |
| 71 | @@ -1559,17 +1564,26 @@ static void sfp_sm_mod_remove(struct sfp |
| 72 | dev_info(sfp->dev, "module removed\n"); |
| 73 | } |
| 74 | |
| 75 | -/* This state machine tracks the netdev up/down state */ |
| 76 | +/* This state machine tracks the upstream's state */ |
| 77 | static void sfp_sm_device(struct sfp *sfp, unsigned int event) |
| 78 | { |
| 79 | switch (sfp->sm_dev_state) { |
| 80 | default: |
| 81 | - if (event == SFP_E_DEV_UP) |
| 82 | + if (event == SFP_E_DEV_ATTACH) |
| 83 | + sfp->sm_dev_state = SFP_DEV_DOWN; |
| 84 | + break; |
| 85 | + |
| 86 | + case SFP_DEV_DOWN: |
| 87 | + if (event == SFP_E_DEV_DETACH) |
| 88 | + sfp->sm_dev_state = SFP_DEV_DETACHED; |
| 89 | + else if (event == SFP_E_DEV_UP) |
| 90 | sfp->sm_dev_state = SFP_DEV_UP; |
| 91 | break; |
| 92 | |
| 93 | case SFP_DEV_UP: |
| 94 | - if (event == SFP_E_DEV_DOWN) |
| 95 | + if (event == SFP_E_DEV_DETACH) |
| 96 | + sfp->sm_dev_state = SFP_DEV_DETACHED; |
| 97 | + else if (event == SFP_E_DEV_DOWN) |
| 98 | sfp->sm_dev_state = SFP_DEV_DOWN; |
| 99 | break; |
| 100 | } |
| 101 | @@ -1580,17 +1594,20 @@ static void sfp_sm_device(struct sfp *sf |
| 102 | */ |
| 103 | static void sfp_sm_module(struct sfp *sfp, unsigned int event) |
| 104 | { |
| 105 | - /* Handle remove event globally, it resets this state machine */ |
| 106 | - if (event == SFP_E_REMOVE) { |
| 107 | + /* Handle remove event globally, it resets this state machine. |
| 108 | + * Also deal with upstream detachment. |
| 109 | + */ |
| 110 | + if (event == SFP_E_REMOVE || sfp->sm_dev_state < SFP_DEV_DOWN) { |
| 111 | if (sfp->sm_mod_state > SFP_MOD_PROBE) |
| 112 | sfp_sm_mod_remove(sfp); |
| 113 | - sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0); |
| 114 | + if (sfp->sm_mod_state != SFP_MOD_EMPTY) |
| 115 | + sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0); |
| 116 | return; |
| 117 | } |
| 118 | |
| 119 | switch (sfp->sm_mod_state) { |
| 120 | default: |
| 121 | - if (event == SFP_E_INSERT && sfp->attached) |
| 122 | + if (event == SFP_E_INSERT) |
| 123 | sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL); |
| 124 | break; |
| 125 | |
| 126 | @@ -1756,8 +1773,8 @@ static void sfp_sm_event(struct sfp *sfp |
| 127 | sm_state_to_str(sfp->sm_state), |
| 128 | event_to_str(event)); |
| 129 | |
| 130 | - sfp_sm_module(sfp, event); |
| 131 | sfp_sm_device(sfp, event); |
| 132 | + sfp_sm_module(sfp, event); |
| 133 | sfp_sm_main(sfp, event); |
| 134 | |
| 135 | dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n", |
| 136 | @@ -1770,15 +1787,14 @@ static void sfp_sm_event(struct sfp *sfp |
| 137 | |
| 138 | static void sfp_attach(struct sfp *sfp) |
| 139 | { |
| 140 | - sfp->attached = true; |
| 141 | + sfp_sm_event(sfp, SFP_E_DEV_ATTACH); |
| 142 | if (sfp->state & SFP_F_PRESENT) |
| 143 | sfp_sm_event(sfp, SFP_E_INSERT); |
| 144 | } |
| 145 | |
| 146 | static void sfp_detach(struct sfp *sfp) |
| 147 | { |
| 148 | - sfp->attached = false; |
| 149 | - sfp_sm_event(sfp, SFP_E_REMOVE); |
| 150 | + sfp_sm_event(sfp, SFP_E_DEV_DETACH); |
| 151 | } |
| 152 | |
| 153 | static void sfp_start(struct sfp *sfp) |