9b34d40a0ff3c2ab073c7bbecba6ff9da86dc336
[openwrt/openwrt.git] / target / linux / generic / backport-5.4 / 737-v5.5-net-phy-add-core-phylib-sfp-support.patch
1 From eb156db588ac583cdae7b91eaac9c0ad3a358e63 Mon Sep 17 00:00:00 2001
2 From: Russell King <rmk+kernel@armlinux.org.uk>
3 Date: Sun, 15 Sep 2019 20:05:34 +0100
4 Subject: [PATCH 635/660] net: phy: add core phylib sfp support
5
6 Add core phylib help for supporting SFP sockets on PHYs. This provides
7 a mechanism to inform the SFP layer about PHY up/down events, and also
8 unregister the SFP bus when the PHY is going away.
9
10 Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
11 ---
12 drivers/net/phy/phy.c | 7 ++++
13 drivers/net/phy/phy_device.c | 66 ++++++++++++++++++++++++++++++++++++
14 include/linux/phy.h | 11 ++++++
15 3 files changed, 84 insertions(+)
16
17 --- a/drivers/net/phy/phy.c
18 +++ b/drivers/net/phy/phy.c
19 @@ -30,6 +30,7 @@
20 #include <linux/ethtool.h>
21 #include <linux/phy.h>
22 #include <linux/phy_led_triggers.h>
23 +#include <linux/sfp.h>
24 #include <linux/workqueue.h>
25 #include <linux/mdio.h>
26 #include <linux/io.h>
27 @@ -871,6 +872,9 @@ void phy_stop(struct phy_device *phydev)
28 if (phy_interrupt_is_valid(phydev))
29 phy_disable_interrupts(phydev);
30
31 + if (phydev->sfp_bus)
32 + sfp_upstream_stop(phydev->sfp_bus);
33 +
34 phydev->state = PHY_HALTED;
35
36 out_unlock:
37 @@ -899,6 +903,9 @@ void phy_start(struct phy_device *phydev
38
39 mutex_lock(&phydev->lock);
40
41 + if (phydev->sfp_bus)
42 + sfp_upstream_start(phydev->sfp_bus);
43 +
44 switch (phydev->state) {
45 case PHY_STARTING:
46 phydev->state = PHY_PENDING;
47 --- a/drivers/net/phy/phy_device.c
48 +++ b/drivers/net/phy/phy_device.c
49 @@ -31,6 +31,7 @@
50 #include <linux/ethtool.h>
51 #include <linux/phy.h>
52 #include <linux/phy_led_triggers.h>
53 +#include <linux/sfp.h>
54 #include <linux/mdio.h>
55 #include <linux/io.h>
56 #include <linux/uaccess.h>
57 @@ -944,6 +945,65 @@ void phy_attached_print(struct phy_devic
58 EXPORT_SYMBOL(phy_attached_print);
59
60 /**
61 + * phy_sfp_attach - attach the SFP bus to the PHY upstream network device
62 + * @upstream: pointer to the phy device
63 + * @bus: sfp bus representing cage being attached
64 + *
65 + * This is used to fill in the sfp_upstream_ops .attach member.
66 + */
67 +void phy_sfp_attach(void *upstream, struct sfp_bus *bus)
68 +{
69 + struct phy_device *phydev = upstream;
70 +
71 + if (phydev->attached_dev)
72 + phydev->attached_dev->sfp_bus = bus;
73 + phydev->sfp_bus_attached = true;
74 +}
75 +EXPORT_SYMBOL(phy_sfp_attach);
76 +
77 +/**
78 + * phy_sfp_detach - detach the SFP bus from the PHY upstream network device
79 + * @upstream: pointer to the phy device
80 + * @bus: sfp bus representing cage being attached
81 + *
82 + * This is used to fill in the sfp_upstream_ops .detach member.
83 + */
84 +void phy_sfp_detach(void *upstream, struct sfp_bus *bus)
85 +{
86 + struct phy_device *phydev = upstream;
87 +
88 + if (phydev->attached_dev)
89 + phydev->attached_dev->sfp_bus = NULL;
90 + phydev->sfp_bus_attached = false;
91 +}
92 +EXPORT_SYMBOL(phy_sfp_detach);
93 +
94 +/**
95 + * phy_sfp_probe - probe for a SFP cage attached to this PHY device
96 + * @phydev: Pointer to phy_device
97 + * @ops: SFP's upstream operations
98 + */
99 +int phy_sfp_probe(struct phy_device *phydev,
100 + const struct sfp_upstream_ops *ops)
101 +{
102 + struct sfp_bus *bus;
103 + int ret;
104 +
105 + if (phydev->mdio.dev.fwnode) {
106 + bus = sfp_bus_find_fwnode(phydev->mdio.dev.fwnode);
107 + if (IS_ERR(bus))
108 + return PTR_ERR(bus);
109 +
110 + phydev->sfp_bus = bus;
111 +
112 + ret = sfp_bus_add_upstream(bus, phydev, ops);
113 + sfp_bus_put(bus);
114 + }
115 + return 0;
116 +}
117 +EXPORT_SYMBOL(phy_sfp_probe);
118 +
119 +/**
120 * phy_attach_direct - attach a network device to a given PHY device pointer
121 * @dev: network device to attach
122 * @phydev: Pointer to phy_device to attach
123 @@ -1016,6 +1076,9 @@ int phy_attach_direct(struct net_device
124 phydev->attached_dev = dev;
125 dev->phydev = phydev;
126
127 + if (phydev->sfp_bus_attached)
128 + dev->sfp_bus = phydev->sfp_bus;
129 +
130 /* Some Ethernet drivers try to connect to a PHY device before
131 * calling register_netdevice() -> netdev_register_kobject() and
132 * does the dev->dev.kobj initialization. Here we only check for
133 @@ -1950,6 +2013,9 @@ static int phy_remove(struct device *dev
134 phydev->state = PHY_DOWN;
135 mutex_unlock(&phydev->lock);
136
137 + sfp_bus_del_upstream(phydev->sfp_bus);
138 + phydev->sfp_bus = NULL;
139 +
140 if (phydev->drv && phydev->drv->remove) {
141 phydev->drv->remove(phydev);
142
143 --- a/include/linux/phy.h
144 +++ b/include/linux/phy.h
145 @@ -184,6 +184,8 @@ static inline const char *phy_modes(phy_
146
147 struct device;
148 struct phylink;
149 +struct sfp_bus;
150 +struct sfp_upstream_ops;
151 struct sk_buff;
152
153 /*
154 @@ -382,6 +384,8 @@ struct phy_c45_device_ids {
155 * irq: IRQ number of the PHY's interrupt (-1 if none)
156 * phy_timer: The timer for handling the state machine
157 * phy_queue: A work_queue for the phy_mac_interrupt
158 + * sfp_bus_attached: flag indicating whether the SFP bus has been attached
159 + * sfp_bus: SFP bus attached to this PHY's fiber port
160 * attached_dev: The attached enet driver's device instance ptr
161 * adjust_link: Callback for the enet controller to respond to
162 * changes in the link state.
163 @@ -471,6 +475,9 @@ struct phy_device {
164
165 struct mutex lock;
166
167 + /* This may be modified under the rtnl lock */
168 + bool sfp_bus_attached;
169 + struct sfp_bus *sfp_bus;
170 struct phylink *phylink;
171 struct net_device *attached_dev;
172
173 @@ -1031,6 +1038,10 @@ int phy_suspend(struct phy_device *phyde
174 int phy_resume(struct phy_device *phydev);
175 int __phy_resume(struct phy_device *phydev);
176 int phy_loopback(struct phy_device *phydev, bool enable);
177 +void phy_sfp_attach(void *upstream, struct sfp_bus *bus);
178 +void phy_sfp_detach(void *upstream, struct sfp_bus *bus);
179 +int phy_sfp_probe(struct phy_device *phydev,
180 + const struct sfp_upstream_ops *ops);
181 struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
182 phy_interface_t interface);
183 struct phy_device *phy_find_first(struct mii_bus *bus);