0cf01df3d35dcf1ca93f5bcc81da6cd0776ab0f6
[openwrt/staging/neocturne.git] /
1 From 9eea577eb1155fe4a183bc5e7bf269b0b2e7a6ba Mon Sep 17 00:00:00 2001
2 From: Christian Marangi <ansuelsmth@gmail.com>
3 Date: Fri, 15 Dec 2023 14:15:32 +0100
4 Subject: [PATCH 2/4] net: phy: extend PHY package API to support multiple
5 global address
6
7 Current API for PHY package are limited to single address to configure
8 global settings for the PHY package.
9
10 It was found that some PHY package (for example the qca807x, a PHY
11 package that is shipped with a bundle of 5 PHY) requires multiple PHY
12 address to configure global settings. An example scenario is a PHY that
13 have a dedicated PHY for PSGMII/serdes calibrarion and have a specific
14 PHY in the package where the global PHY mode is set and affects every
15 other PHY in the package.
16
17 Change the API in the following way:
18 - Change phy_package_join() to take the base addr of the PHY package
19 instead of the global PHY addr.
20 - Make __/phy_package_write/read() require an additional arg that
21 select what global PHY address to use by passing the offset from the
22 base addr passed on phy_package_join().
23
24 Each user of this API is updated to follow this new implementation
25 following a pattern where an enum is defined to declare the offset of the
26 addr.
27
28 We also drop the check if shared is defined as any user of the
29 phy_package_read/write is expected to use phy_package_join first. Misuse
30 of this will correctly trigger a kernel panic for NULL pointer
31 exception.
32
33 Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
34 Signed-off-by: David S. Miller <davem@davemloft.net>
35 ---
36 drivers/net/phy/bcm54140.c | 16 ++++++--
37 drivers/net/phy/mscc/mscc.h | 5 +++
38 drivers/net/phy/mscc/mscc_main.c | 4 +-
39 drivers/net/phy/phy_device.c | 35 +++++++++--------
40 include/linux/phy.h | 64 +++++++++++++++++++++-----------
41 5 files changed, 80 insertions(+), 44 deletions(-)
42
43 --- a/drivers/net/phy/bcm54140.c
44 +++ b/drivers/net/phy/bcm54140.c
45 @@ -128,6 +128,10 @@
46 #define BCM54140_DEFAULT_DOWNSHIFT 5
47 #define BCM54140_MAX_DOWNSHIFT 9
48
49 +enum bcm54140_global_phy {
50 + BCM54140_BASE_ADDR = 0,
51 +};
52 +
53 struct bcm54140_priv {
54 int port;
55 int base_addr;
56 @@ -429,11 +433,13 @@ static int bcm54140_base_read_rdb(struct
57 int ret;
58
59 phy_lock_mdio_bus(phydev);
60 - ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
61 + ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
62 + MII_BCM54XX_RDB_ADDR, rdb);
63 if (ret < 0)
64 goto out;
65
66 - ret = __phy_package_read(phydev, MII_BCM54XX_RDB_DATA);
67 + ret = __phy_package_read(phydev, BCM54140_BASE_ADDR,
68 + MII_BCM54XX_RDB_DATA);
69
70 out:
71 phy_unlock_mdio_bus(phydev);
72 @@ -446,11 +452,13 @@ static int bcm54140_base_write_rdb(struc
73 int ret;
74
75 phy_lock_mdio_bus(phydev);
76 - ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
77 + ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
78 + MII_BCM54XX_RDB_ADDR, rdb);
79 if (ret < 0)
80 goto out;
81
82 - ret = __phy_package_write(phydev, MII_BCM54XX_RDB_DATA, val);
83 + ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
84 + MII_BCM54XX_RDB_DATA, val);
85
86 out:
87 phy_unlock_mdio_bus(phydev);
88 --- a/drivers/net/phy/mscc/mscc.h
89 +++ b/drivers/net/phy/mscc/mscc.h
90 @@ -414,6 +414,11 @@ struct vsc8531_private {
91 * gpio_lock: used for PHC operations. Common for all PHYs as the load/save GPIO
92 * is shared.
93 */
94 +
95 +enum vsc85xx_global_phy {
96 + VSC88XX_BASE_ADDR = 0,
97 +};
98 +
99 struct vsc85xx_shared_private {
100 struct mutex gpio_lock;
101 };
102 --- a/drivers/net/phy/mscc/mscc_main.c
103 +++ b/drivers/net/phy/mscc/mscc_main.c
104 @@ -700,7 +700,7 @@ int phy_base_write(struct phy_device *ph
105 dump_stack();
106 }
107
108 - return __phy_package_write(phydev, regnum, val);
109 + return __phy_package_write(phydev, VSC88XX_BASE_ADDR, regnum, val);
110 }
111
112 /* phydev->bus->mdio_lock should be locked when using this function */
113 @@ -711,7 +711,7 @@ int phy_base_read(struct phy_device *phy
114 dump_stack();
115 }
116
117 - return __phy_package_read(phydev, regnum);
118 + return __phy_package_read(phydev, VSC88XX_BASE_ADDR, regnum);
119 }
120
121 u32 vsc85xx_csr_read(struct phy_device *phydev,
122 --- a/drivers/net/phy/phy_device.c
123 +++ b/drivers/net/phy/phy_device.c
124 @@ -1602,20 +1602,22 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_1
125 /**
126 * phy_package_join - join a common PHY group
127 * @phydev: target phy_device struct
128 - * @addr: cookie and PHY address for global register access
129 + * @base_addr: cookie and base PHY address of PHY package for offset
130 + * calculation of global register access
131 * @priv_size: if non-zero allocate this amount of bytes for private data
132 *
133 * This joins a PHY group and provides a shared storage for all phydevs in
134 * this group. This is intended to be used for packages which contain
135 * more than one PHY, for example a quad PHY transceiver.
136 *
137 - * The addr parameter serves as a cookie which has to have the same value
138 - * for all members of one group and as a PHY address to access generic
139 - * registers of a PHY package. Usually, one of the PHY addresses of the
140 - * different PHYs in the package provides access to these global registers.
141 + * The base_addr parameter serves as cookie which has to have the same values
142 + * for all members of one group and as the base PHY address of the PHY package
143 + * for offset calculation to access generic registers of a PHY package.
144 + * Usually, one of the PHY addresses of the different PHYs in the package
145 + * provides access to these global registers.
146 * The address which is given here, will be used in the phy_package_read()
147 - * and phy_package_write() convenience functions. If your PHY doesn't have
148 - * global registers you can just pick any of the PHY addresses.
149 + * and phy_package_write() convenience functions as base and added to the
150 + * passed offset in those functions.
151 *
152 * This will set the shared pointer of the phydev to the shared storage.
153 * If this is the first call for a this cookie the shared storage will be
154 @@ -1625,17 +1627,17 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_1
155 * Returns < 1 on error, 0 on success. Esp. calling phy_package_join()
156 * with the same cookie but a different priv_size is an error.
157 */
158 -int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size)
159 +int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size)
160 {
161 struct mii_bus *bus = phydev->mdio.bus;
162 struct phy_package_shared *shared;
163 int ret;
164
165 - if (addr < 0 || addr >= PHY_MAX_ADDR)
166 + if (base_addr < 0 || base_addr >= PHY_MAX_ADDR)
167 return -EINVAL;
168
169 mutex_lock(&bus->shared_lock);
170 - shared = bus->shared[addr];
171 + shared = bus->shared[base_addr];
172 if (!shared) {
173 ret = -ENOMEM;
174 shared = kzalloc(sizeof(*shared), GFP_KERNEL);
175 @@ -1647,9 +1649,9 @@ int phy_package_join(struct phy_device *
176 goto err_free;
177 shared->priv_size = priv_size;
178 }
179 - shared->addr = addr;
180 + shared->base_addr = base_addr;
181 refcount_set(&shared->refcnt, 1);
182 - bus->shared[addr] = shared;
183 + bus->shared[base_addr] = shared;
184 } else {
185 ret = -EINVAL;
186 if (priv_size && priv_size != shared->priv_size)
187 @@ -1687,7 +1689,7 @@ void phy_package_leave(struct phy_device
188 return;
189
190 if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
191 - bus->shared[shared->addr] = NULL;
192 + bus->shared[shared->base_addr] = NULL;
193 mutex_unlock(&bus->shared_lock);
194 kfree(shared->priv);
195 kfree(shared);
196 @@ -1706,7 +1708,8 @@ static void devm_phy_package_leave(struc
197 * devm_phy_package_join - resource managed phy_package_join()
198 * @dev: device that is registering this PHY package
199 * @phydev: target phy_device struct
200 - * @addr: cookie and PHY address for global register access
201 + * @base_addr: cookie and base PHY address of PHY package for offset
202 + * calculation of global register access
203 * @priv_size: if non-zero allocate this amount of bytes for private data
204 *
205 * Managed phy_package_join(). Shared storage fetched by this function,
206 @@ -1714,7 +1717,7 @@ static void devm_phy_package_leave(struc
207 * phy_package_join() for more information.
208 */
209 int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
210 - int addr, size_t priv_size)
211 + int base_addr, size_t priv_size)
212 {
213 struct phy_device **ptr;
214 int ret;
215 @@ -1724,7 +1727,7 @@ int devm_phy_package_join(struct device
216 if (!ptr)
217 return -ENOMEM;
218
219 - ret = phy_package_join(phydev, addr, priv_size);
220 + ret = phy_package_join(phydev, base_addr, priv_size);
221
222 if (!ret) {
223 *ptr = phydev;
224 --- a/include/linux/phy.h
225 +++ b/include/linux/phy.h
226 @@ -319,7 +319,8 @@ struct mdio_bus_stats {
227
228 /**
229 * struct phy_package_shared - Shared information in PHY packages
230 - * @addr: Common PHY address used to combine PHYs in one package
231 + * @base_addr: Base PHY address of PHY package used to combine PHYs
232 + * in one package and for offset calculation of phy_package_read/write
233 * @refcnt: Number of PHYs connected to this shared data
234 * @flags: Initialization of PHY package
235 * @priv_size: Size of the shared private data @priv
236 @@ -330,7 +331,7 @@ struct mdio_bus_stats {
237 * phy_package_leave().
238 */
239 struct phy_package_shared {
240 - u8 addr;
241 + u8 base_addr;
242 refcount_t refcnt;
243 unsigned long flags;
244 size_t priv_size;
245 @@ -1763,10 +1764,10 @@ int phy_ethtool_get_link_ksettings(struc
246 int phy_ethtool_set_link_ksettings(struct net_device *ndev,
247 const struct ethtool_link_ksettings *cmd);
248 int phy_ethtool_nway_reset(struct net_device *ndev);
249 -int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size);
250 +int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size);
251 void phy_package_leave(struct phy_device *phydev);
252 int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
253 - int addr, size_t priv_size);
254 + int base_addr, size_t priv_size);
255
256 #if IS_ENABLED(CONFIG_PHYLIB)
257 int __init mdio_bus_init(void);
258 @@ -1778,46 +1779,65 @@ int phy_ethtool_get_sset_count(struct ph
259 int phy_ethtool_get_stats(struct phy_device *phydev,
260 struct ethtool_stats *stats, u64 *data);
261
262 -static inline int phy_package_read(struct phy_device *phydev, u32 regnum)
263 +static inline int phy_package_address(struct phy_device *phydev,
264 + unsigned int addr_offset)
265 {
266 struct phy_package_shared *shared = phydev->shared;
267 + u8 base_addr = shared->base_addr;
268
269 - if (!shared)
270 + if (addr_offset >= PHY_MAX_ADDR - base_addr)
271 return -EIO;
272
273 - return mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
274 + /* we know that addr will be in the range 0..31 and thus the
275 + * implicit cast to a signed int is not a problem.
276 + */
277 + return base_addr + addr_offset;
278 }
279
280 -static inline int __phy_package_read(struct phy_device *phydev, u32 regnum)
281 +static inline int phy_package_read(struct phy_device *phydev,
282 + unsigned int addr_offset, u32 regnum)
283 {
284 - struct phy_package_shared *shared = phydev->shared;
285 + int addr = phy_package_address(phydev, addr_offset);
286
287 - if (!shared)
288 - return -EIO;
289 + if (addr < 0)
290 + return addr;
291 +
292 + return mdiobus_read(phydev->mdio.bus, addr, regnum);
293 +}
294 +
295 +static inline int __phy_package_read(struct phy_device *phydev,
296 + unsigned int addr_offset, u32 regnum)
297 +{
298 + int addr = phy_package_address(phydev, addr_offset);
299 +
300 + if (addr < 0)
301 + return addr;
302
303 - return __mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
304 + return __mdiobus_read(phydev->mdio.bus, addr, regnum);
305 }
306
307 static inline int phy_package_write(struct phy_device *phydev,
308 - u32 regnum, u16 val)
309 + unsigned int addr_offset, u32 regnum,
310 + u16 val)
311 {
312 - struct phy_package_shared *shared = phydev->shared;
313 + int addr = phy_package_address(phydev, addr_offset);
314
315 - if (!shared)
316 - return -EIO;
317 + if (addr < 0)
318 + return addr;
319
320 - return mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
321 + return mdiobus_write(phydev->mdio.bus, addr, regnum, val);
322 }
323
324 static inline int __phy_package_write(struct phy_device *phydev,
325 - u32 regnum, u16 val)
326 + unsigned int addr_offset, u32 regnum,
327 + u16 val)
328 {
329 - struct phy_package_shared *shared = phydev->shared;
330 + int addr = phy_package_address(phydev, addr_offset);
331
332 - if (!shared)
333 - return -EIO;
334 + if (addr < 0)
335 + return addr;
336
337 - return __mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
338 + return __mdiobus_write(phydev->mdio.bus, addr, regnum, val);
339 }
340
341 static inline bool __phy_package_set_once(struct phy_device *phydev,