1 From 4e4aafcddbbfcdd6eed5780e190fcbfac8b4685a Mon Sep 17 00:00:00 2001
2 From: Andrew Lunn <andrew@lunn.ch>
3 Date: Mon, 9 Jan 2023 16:30:41 +0100
4 Subject: [PATCH] net: mdio: Add dedicated C45 API to MDIO bus drivers
6 Currently C22 and C45 transactions are mixed over a combined API calls
7 which make use of a special bit in the reg address to indicate if a
8 C45 transaction should be performed. This makes it impossible to know
9 if the bus driver actually supports C45. Additionally, many C22 only
10 drivers don't return -EOPNOTSUPP when asked to perform a C45
11 transaction, they mistaking perform a C22 transaction.
13 This is the first step to cleanly separate C22 from C45. To maintain
14 backwards compatibility until all drivers which are capable of
15 performing C45 are converted to this new API, the helper functions
16 will fall back to the older API if the new API is not
17 supported. Eventually this fallback will be removed.
19 Signed-off-by: Andrew Lunn <andrew@lunn.ch>
20 Signed-off-by: Michael Walle <michael@walle.cc>
21 Signed-off-by: Jakub Kicinski <kuba@kernel.org>
23 drivers/net/phy/mdio_bus.c | 189 +++++++++++++++++++++++++++++++++++++
24 include/linux/mdio.h | 39 ++++----
25 include/linux/phy.h | 5 +
26 3 files changed, 214 insertions(+), 19 deletions(-)
28 --- a/drivers/net/phy/mdio_bus.c
29 +++ b/drivers/net/phy/mdio_bus.c
30 @@ -832,6 +832,100 @@ int __mdiobus_modify_changed(struct mii_
31 EXPORT_SYMBOL_GPL(__mdiobus_modify_changed);
34 + * __mdiobus_c45_read - Unlocked version of the mdiobus_c45_read function
35 + * @bus: the mii_bus struct
36 + * @addr: the phy address
37 + * @devad: device address to read
38 + * @regnum: register number to read
40 + * Read a MDIO bus register. Caller must hold the mdio bus lock.
42 + * NOTE: MUST NOT be called from interrupt context.
44 +int __mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum)
48 + lockdep_assert_held_once(&bus->mdio_lock);
51 + retval = bus->read_c45(bus, addr, devad, regnum);
53 + retval = bus->read(bus, addr, mdiobus_c45_addr(devad, regnum));
55 + trace_mdio_access(bus, 1, addr, regnum, retval, retval);
56 + mdiobus_stats_acct(&bus->stats[addr], true, retval);
60 +EXPORT_SYMBOL(__mdiobus_c45_read);
63 + * __mdiobus_c45_write - Unlocked version of the mdiobus_write function
64 + * @bus: the mii_bus struct
65 + * @addr: the phy address
66 + * @devad: device address to read
67 + * @regnum: register number to write
68 + * @val: value to write to @regnum
70 + * Write a MDIO bus register. Caller must hold the mdio bus lock.
72 + * NOTE: MUST NOT be called from interrupt context.
74 +int __mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
79 + lockdep_assert_held_once(&bus->mdio_lock);
82 + err = bus->write_c45(bus, addr, devad, regnum, val);
84 + err = bus->write(bus, addr, mdiobus_c45_addr(devad, regnum),
87 + trace_mdio_access(bus, 0, addr, regnum, val, err);
88 + mdiobus_stats_acct(&bus->stats[addr], false, err);
92 +EXPORT_SYMBOL(__mdiobus_c45_write);
95 + * __mdiobus_c45_modify_changed - Unlocked version of the mdiobus_modify function
96 + * @bus: the mii_bus struct
97 + * @addr: the phy address
98 + * @devad: device address to read
99 + * @regnum: register number to modify
100 + * @mask: bit mask of bits to clear
101 + * @set: bit mask of bits to set
103 + * Read, modify, and if any change, write the register value back to the
104 + * device. Any error returns a negative number.
106 + * NOTE: MUST NOT be called from interrupt context.
108 +static int __mdiobus_c45_modify_changed(struct mii_bus *bus, int addr,
109 + int devad, u32 regnum, u16 mask,
114 + ret = __mdiobus_c45_read(bus, addr, devad, regnum);
118 + new = (ret & ~mask) | set;
122 + ret = __mdiobus_c45_write(bus, addr, devad, regnum, new);
124 + return ret < 0 ? ret : 1;
128 * mdiobus_read_nested - Nested version of the mdiobus_read function
129 * @bus: the mii_bus struct
130 * @addr: the phy address
131 @@ -879,6 +973,29 @@ int mdiobus_read(struct mii_bus *bus, in
132 EXPORT_SYMBOL(mdiobus_read);
135 + * mdiobus_c45_read - Convenience function for reading a given MII mgmt register
136 + * @bus: the mii_bus struct
137 + * @addr: the phy address
138 + * @devad: device address to read
139 + * @regnum: register number to read
141 + * NOTE: MUST NOT be called from interrupt context,
142 + * because the bus read/write functions may wait for an interrupt
143 + * to conclude the operation.
145 +int mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum)
149 + mutex_lock(&bus->mdio_lock);
150 + retval = __mdiobus_c45_read(bus, addr, devad, regnum);
151 + mutex_unlock(&bus->mdio_lock);
155 +EXPORT_SYMBOL(mdiobus_c45_read);
158 * mdiobus_write_nested - Nested version of the mdiobus_write function
159 * @bus: the mii_bus struct
160 * @addr: the phy address
161 @@ -928,6 +1045,31 @@ int mdiobus_write(struct mii_bus *bus, i
162 EXPORT_SYMBOL(mdiobus_write);
165 + * mdiobus_c45_write - Convenience function for writing a given MII mgmt register
166 + * @bus: the mii_bus struct
167 + * @addr: the phy address
168 + * @devad: device address to read
169 + * @regnum: register number to write
170 + * @val: value to write to @regnum
172 + * NOTE: MUST NOT be called from interrupt context,
173 + * because the bus read/write functions may wait for an interrupt
174 + * to conclude the operation.
176 +int mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
181 + mutex_lock(&bus->mdio_lock);
182 + err = __mdiobus_c45_write(bus, addr, devad, regnum, val);
183 + mutex_unlock(&bus->mdio_lock);
187 +EXPORT_SYMBOL(mdiobus_c45_write);
190 * mdiobus_modify - Convenience function for modifying a given mdio device
192 * @bus: the mii_bus struct
193 @@ -949,6 +1091,30 @@ int mdiobus_modify(struct mii_bus *bus,
194 EXPORT_SYMBOL_GPL(mdiobus_modify);
197 + * mdiobus_c45_modify - Convenience function for modifying a given mdio device
199 + * @bus: the mii_bus struct
200 + * @addr: the phy address
201 + * @devad: device address to read
202 + * @regnum: register number to write
203 + * @mask: bit mask of bits to clear
204 + * @set: bit mask of bits to set
206 +int mdiobus_c45_modify(struct mii_bus *bus, int addr, int devad, u32 regnum,
211 + mutex_lock(&bus->mdio_lock);
212 + err = __mdiobus_c45_modify_changed(bus, addr, devad, regnum,
214 + mutex_unlock(&bus->mdio_lock);
216 + return err < 0 ? err : 0;
218 +EXPORT_SYMBOL_GPL(mdiobus_c45_modify);
221 * mdiobus_modify_changed - Convenience function for modifying a given mdio
222 * device register and returning if it changed
223 * @bus: the mii_bus struct
224 @@ -971,6 +1137,29 @@ int mdiobus_modify_changed(struct mii_bu
225 EXPORT_SYMBOL_GPL(mdiobus_modify_changed);
228 + * mdiobus_c45_modify_changed - Convenience function for modifying a given mdio
229 + * device register and returning if it changed
230 + * @bus: the mii_bus struct
231 + * @addr: the phy address
232 + * @devad: device address to read
233 + * @regnum: register number to write
234 + * @mask: bit mask of bits to clear
235 + * @set: bit mask of bits to set
237 +int mdiobus_c45_modify_changed(struct mii_bus *bus, int devad, int addr,
238 + u32 regnum, u16 mask, u16 set)
242 + mutex_lock(&bus->mdio_lock);
243 + err = __mdiobus_c45_modify_changed(bus, addr, devad, regnum, mask, set);
244 + mutex_unlock(&bus->mdio_lock);
248 +EXPORT_SYMBOL_GPL(mdiobus_c45_modify_changed);
251 * mdio_bus_match - determine if given MDIO driver supports the given
253 * @dev: target MDIO device
254 --- a/include/linux/mdio.h
255 +++ b/include/linux/mdio.h
256 @@ -423,6 +423,17 @@ int mdiobus_modify(struct mii_bus *bus,
258 int mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum,
260 +int __mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum);
261 +int mdiobus_c45_read(struct mii_bus *bus, int addr, int devad, u32 regnum);
262 +int __mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
264 +int mdiobus_c45_write(struct mii_bus *bus, int addr, int devad, u32 regnum,
266 +int mdiobus_c45_modify(struct mii_bus *bus, int addr, int devad, u32 regnum,
267 + u16 mask, u16 set);
269 +int mdiobus_c45_modify_changed(struct mii_bus *bus, int addr, int devad,
270 + u32 regnum, u16 mask, u16 set);
272 static inline int mdiodev_read(struct mdio_device *mdiodev, u32 regnum)
274 @@ -463,29 +474,19 @@ static inline u16 mdiobus_c45_devad(u32
275 return FIELD_GET(MII_DEVADDR_C45_MASK, regnum);
278 -static inline int __mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
281 - return __mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum));
284 -static inline int __mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad,
285 - u16 regnum, u16 val)
287 - return __mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum),
291 -static inline int mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad,
293 +static inline int mdiodev_c45_modify(struct mdio_device *mdiodev, int devad,
294 + u32 regnum, u16 mask, u16 set)
296 - return mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum));
297 + return mdiobus_c45_modify(mdiodev->bus, mdiodev->addr, devad, regnum,
301 -static inline int mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad,
302 - u16 regnum, u16 val)
303 +static inline int mdiodev_c45_modify_changed(struct mdio_device *mdiodev,
304 + int devad, u32 regnum, u16 mask,
307 - return mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum), val);
308 + return mdiobus_c45_modify_changed(mdiodev->bus, mdiodev->addr, devad,
309 + regnum, mask, set);
312 int mdiobus_register_device(struct mdio_device *mdiodev);
313 --- a/include/linux/phy.h
314 +++ b/include/linux/phy.h
315 @@ -364,6 +364,11 @@ struct mii_bus {
316 int (*read)(struct mii_bus *bus, int addr, int regnum);
317 /** @write: Perform a write transfer on the bus */
318 int (*write)(struct mii_bus *bus, int addr, int regnum, u16 val);
319 + /** @read_c45: Perform a C45 read transfer on the bus */
320 + int (*read_c45)(struct mii_bus *bus, int addr, int devnum, int regnum);
321 + /** @write_c45: Perform a C45 write transfer on the bus */
322 + int (*write_c45)(struct mii_bus *bus, int addr, int devnum,
323 + int regnum, u16 val);
324 /** @reset: Perform a reset of the bus */
325 int (*reset)(struct mii_bus *bus);