c0c3e9e57e70f0ebbdb5d5be920b174789808ef1
[oweals/openwrt.git] / target / linux / generic / pending-5.4 / 743-net-sfp-add-module-start-stop-upstream-notifications.patch
1 From f9a5a54b59cb904b37bf7409a43635ab195d0214 Mon Sep 17 00:00:00 2001
2 From: Russell King <rmk+kernel@armlinux.org.uk>
3 Date: Tue, 19 Nov 2019 10:13:25 +0000
4 Subject: [PATCH 646/660] net: sfp: add module start/stop upstream
5  notifications
6
7 When dealing with some copper modules, we can't positively know the
8 module capabilities are until we have probed the PHY. Without the full
9 capabilities, we may end up failing a module that we could otherwise
10 drive with a restricted set of capabilities.
11
12 An example of this would be a module with a NBASE-T PHY plugged into
13 a host that supports phy interface modes 2500BASE-X and SGMII. The
14 PHY supports 10GBASE-R, 5000BASE-X, 2500BASE-X, SGMII interface modes,
15 which means a subset of the capabilities are compatible with the host.
16
17 However, reading the module EEPROM leads us to believe that the module
18 only supports ethtool link mode 10GBASE-T, which is incompatible with
19 the host - and thus results in the module being rejected.
20
21 This patch adds an extra notification which are triggered after the
22 SFP module's PHY probe, and a corresponding notification just before
23 the PHY is removed.
24
25 Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
26 ---
27  drivers/net/phy/sfp-bus.c | 21 +++++++++++++++++++++
28  drivers/net/phy/sfp.c     |  8 ++++++++
29  drivers/net/phy/sfp.h     |  2 ++
30  include/linux/sfp.h       |  4 ++++
31  4 files changed, 35 insertions(+)
32
33 --- a/drivers/net/phy/sfp-bus.c
34 +++ b/drivers/net/phy/sfp-bus.c
35 @@ -711,6 +711,27 @@ void sfp_module_remove(struct sfp_bus *b
36  }
37  EXPORT_SYMBOL_GPL(sfp_module_remove);
38  
39 +int sfp_module_start(struct sfp_bus *bus)
40 +{
41 +       const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
42 +       int ret = 0;
43 +
44 +       if (ops && ops->module_start)
45 +               ret = ops->module_start(bus->upstream);
46 +
47 +       return ret;
48 +}
49 +EXPORT_SYMBOL_GPL(sfp_module_start);
50 +
51 +void sfp_module_stop(struct sfp_bus *bus)
52 +{
53 +       const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
54 +
55 +       if (ops && ops->module_stop)
56 +               ops->module_stop(bus->upstream);
57 +}
58 +EXPORT_SYMBOL_GPL(sfp_module_stop);
59 +
60  static void sfp_socket_clear(struct sfp_bus *bus)
61  {
62         bus->sfp_dev = NULL;
63 --- a/drivers/net/phy/sfp.c
64 +++ b/drivers/net/phy/sfp.c
65 @@ -57,6 +57,7 @@ enum {
66         SFP_DEV_UP,
67  
68         SFP_S_DOWN = 0,
69 +       SFP_S_FAIL,
70         SFP_S_WAIT,
71         SFP_S_INIT,
72         SFP_S_INIT_TX_FAULT,
73 @@ -120,6 +121,7 @@ static const char *event_to_str(unsigned
74  
75  static const char * const sm_state_strings[] = {
76         [SFP_S_DOWN] = "down",
77 +       [SFP_S_FAIL] = "fail",
78         [SFP_S_WAIT] = "wait",
79         [SFP_S_INIT] = "init",
80         [SFP_S_INIT_TX_FAULT] = "init_tx_fault",
81 @@ -1766,6 +1768,8 @@ static void sfp_sm_main(struct sfp *sfp,
82                 if (sfp->sm_state == SFP_S_LINK_UP &&
83                     sfp->sm_dev_state == SFP_DEV_UP)
84                         sfp_sm_link_down(sfp);
85 +               if (sfp->sm_state > SFP_S_INIT)
86 +                       sfp_module_stop(sfp->sfp_bus);
87                 if (sfp->mod_phy)
88                         sfp_sm_phy_detach(sfp);
89                 sfp_module_tx_disable(sfp);
90 @@ -1833,6 +1837,10 @@ static void sfp_sm_main(struct sfp *sfp,
91                          * clear.  Probe for the PHY and check the LOS state.
92                          */
93                         sfp_sm_probe_for_phy(sfp);
94 +                       if (sfp_module_start(sfp->sfp_bus)) {
95 +                               sfp_sm_next(sfp, SFP_S_FAIL, 0);
96 +                               break;
97 +                       }
98                         sfp_sm_link_check_los(sfp);
99  
100                         /* Reset the fault retry count */
101 --- a/drivers/net/phy/sfp.h
102 +++ b/drivers/net/phy/sfp.h
103 @@ -22,6 +22,8 @@ void sfp_link_up(struct sfp_bus *bus);
104  void sfp_link_down(struct sfp_bus *bus);
105  int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
106  void sfp_module_remove(struct sfp_bus *bus);
107 +int sfp_module_start(struct sfp_bus *bus);
108 +void sfp_module_stop(struct sfp_bus *bus);
109  int sfp_link_configure(struct sfp_bus *bus, const struct sfp_eeprom_id *id);
110  struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp,
111                                     const struct sfp_socket_ops *ops);
112 --- a/include/linux/sfp.h
113 +++ b/include/linux/sfp.h
114 @@ -507,6 +507,8 @@ struct sfp_bus;
115   * @module_insert: called after a module has been detected to determine
116   *   whether the module is supported for the upstream device.
117   * @module_remove: called after the module has been removed.
118 + * @module_start: called after the PHY probe step
119 + * @module_stop: called before the PHY is removed
120   * @link_down: called when the link is non-operational for whatever
121   *   reason.
122   * @link_up: called when the link is operational.
123 @@ -520,6 +522,8 @@ struct sfp_upstream_ops {
124         void (*detach)(void *priv, struct sfp_bus *bus);
125         int (*module_insert)(void *priv, const struct sfp_eeprom_id *id);
126         void (*module_remove)(void *priv);
127 +       int (*module_start)(void *priv);
128 +       void (*module_stop)(void *priv);
129         void (*link_down)(void *priv);
130         void (*link_up)(void *priv);
131         int (*connect_phy)(void *priv, struct phy_device *);