blob: 50200135ddae599a03945a8f61cf95ce707b348e [file] [log] [blame]
developerec4ebe42022-04-12 11:17:45 +08001From f9a5a54b59cb904b37bf7409a43635ab195d0214 Mon Sep 17 00:00:00 2001
2From: Russell King <rmk+kernel@armlinux.org.uk>
3Date: Tue, 19 Nov 2019 10:13:25 +0000
4Subject: [PATCH 646/660] net: sfp: add module start/stop upstream
5 notifications
6
7When dealing with some copper modules, we can't positively know the
8module capabilities are until we have probed the PHY. Without the full
9capabilities, we may end up failing a module that we could otherwise
10drive with a restricted set of capabilities.
11
12An example of this would be a module with a NBASE-T PHY plugged into
13a host that supports phy interface modes 2500BASE-X and SGMII. The
14PHY supports 10GBASE-R, 5000BASE-X, 2500BASE-X, SGMII interface modes,
15which means a subset of the capabilities are compatible with the host.
16
17However, reading the module EEPROM leads us to believe that the module
18only supports ethtool link mode 10GBASE-T, which is incompatible with
19the host - and thus results in the module being rejected.
20
21This patch adds an extra notification which are triggered after the
22SFP module's PHY probe, and a corresponding notification just before
23the PHY is removed.
24
25Signed-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@@ -717,6 +717,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@@ -59,6 +59,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@@ -122,6 +123,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",
developer53810fa2022-04-19 10:14:08 +080081@@ -1926,6 +1928,8 @@ static void sfp_sm_main(struct sfp *sfp,
developerec4ebe42022-04-12 11:17:45 +080082 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);
developer53810fa2022-04-19 10:14:08 +080090@@ -1993,6 +1997,10 @@ static void sfp_sm_main(struct sfp *sfp,
developerec4ebe42022-04-12 11:17:45 +080091 * 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 *);