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
7 Current API for PHY package are limited to single address to configure
8 global settings for the PHY package.
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.
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().
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
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
33 Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
34 Signed-off-by: David S. Miller <davem@davemloft.net>
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(-)
43 --- a/drivers/net/phy/bcm54140.c
44 +++ b/drivers/net/phy/bcm54140.c
46 #define BCM54140_DEFAULT_DOWNSHIFT 5
47 #define BCM54140_MAX_DOWNSHIFT 9
49 +enum bcm54140_global_phy {
50 + BCM54140_BASE_ADDR = 0,
53 struct bcm54140_priv {
56 @@ -429,11 +433,13 @@ static int bcm54140_base_read_rdb(struct
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);
66 - ret = __phy_package_read(phydev, MII_BCM54XX_RDB_DATA);
67 + ret = __phy_package_read(phydev, BCM54140_BASE_ADDR,
68 + MII_BCM54XX_RDB_DATA);
71 phy_unlock_mdio_bus(phydev);
72 @@ -446,11 +452,13 @@ static int bcm54140_base_write_rdb(struc
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);
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);
87 phy_unlock_mdio_bus(phydev);
88 --- a/drivers/net/phy/mscc/mscc.h
89 +++ b/drivers/net/phy/mscc/mscc.h
90 @@ -416,6 +416,11 @@ struct vsc8531_private {
91 * gpio_lock: used for PHC operations. Common for all PHYs as the load/save GPIO
95 +enum vsc85xx_global_phy {
96 + VSC88XX_BASE_ADDR = 0,
99 struct vsc85xx_shared_private {
100 struct mutex gpio_lock;
102 --- a/drivers/net/phy/mscc/mscc_main.c
103 +++ b/drivers/net/phy/mscc/mscc_main.c
104 @@ -711,7 +711,7 @@ int phy_base_write(struct phy_device *ph
108 - return __phy_package_write(phydev, regnum, val);
109 + return __phy_package_write(phydev, VSC88XX_BASE_ADDR, regnum, val);
112 /* phydev->bus->mdio_lock should be locked when using this function */
113 @@ -722,7 +722,7 @@ int phy_base_read(struct phy_device *phy
117 - return __phy_package_read(phydev, regnum);
118 + return __phy_package_read(phydev, VSC88XX_BASE_ADDR, regnum);
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 @@ -1650,20 +1650,22 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_1
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
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.
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.
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 @@ -1673,17 +1675,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.
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)
161 struct mii_bus *bus = phydev->mdio.bus;
162 struct phy_package_shared *shared;
165 - if (addr < 0 || addr >= PHY_MAX_ADDR)
166 + if (base_addr < 0 || base_addr >= PHY_MAX_ADDR)
169 mutex_lock(&bus->shared_lock);
170 - shared = bus->shared[addr];
171 + shared = bus->shared[base_addr];
174 shared = kzalloc(sizeof(*shared), GFP_KERNEL);
175 @@ -1695,9 +1697,9 @@ int phy_package_join(struct phy_device *
177 shared->priv_size = priv_size;
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;
186 if (priv_size && priv_size != shared->priv_size)
187 @@ -1735,7 +1737,7 @@ void phy_package_leave(struct phy_device
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);
196 @@ -1754,7 +1756,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
205 * Managed phy_package_join(). Shared storage fetched by this function,
206 @@ -1762,7 +1765,7 @@ static void devm_phy_package_leave(struc
207 * phy_package_join() for more information.
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)
213 struct phy_device **ptr;
215 @@ -1772,7 +1775,7 @@ int devm_phy_package_join(struct device
219 - ret = phy_package_join(phydev, addr, priv_size);
220 + ret = phy_package_join(phydev, base_addr, priv_size);
224 --- a/include/linux/phy.h
225 +++ b/include/linux/phy.h
226 @@ -327,7 +327,8 @@ struct mdio_bus_stats {
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 @@ -338,7 +339,7 @@ struct mdio_bus_stats {
237 * phy_package_leave().
239 struct phy_package_shared {
245 @@ -1969,10 +1970,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);
256 int __init mdio_bus_init(void);
257 void mdio_bus_exit(void);
258 @@ -1995,46 +1996,65 @@ int __phy_hwtstamp_set(struct phy_device
259 struct kernel_hwtstamp_config *config,
260 struct netlink_ext_ack *extack);
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)
266 struct phy_package_shared *shared = phydev->shared;
267 + u8 base_addr = shared->base_addr;
270 + if (addr_offset >= PHY_MAX_ADDR - base_addr)
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.
277 + return base_addr + addr_offset;
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)
284 - struct phy_package_shared *shared = phydev->shared;
285 + int addr = phy_package_address(phydev, addr_offset);
292 + return mdiobus_read(phydev->mdio.bus, addr, regnum);
295 +static inline int __phy_package_read(struct phy_device *phydev,
296 + unsigned int addr_offset, u32 regnum)
298 + int addr = phy_package_address(phydev, addr_offset);
303 - return __mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
304 + return __mdiobus_read(phydev->mdio.bus, addr, regnum);
307 static inline int phy_package_write(struct phy_device *phydev,
308 - u32 regnum, u16 val)
309 + unsigned int addr_offset, u32 regnum,
312 - struct phy_package_shared *shared = phydev->shared;
313 + int addr = phy_package_address(phydev, addr_offset);
320 - return mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
321 + return mdiobus_write(phydev->mdio.bus, addr, regnum, val);
324 static inline int __phy_package_write(struct phy_device *phydev,
325 - u32 regnum, u16 val)
326 + unsigned int addr_offset, u32 regnum,
329 - struct phy_package_shared *shared = phydev->shared;
330 + int addr = phy_package_address(phydev, addr_offset);
337 - return __mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
338 + return __mdiobus_write(phydev->mdio.bus, addr, regnum, val);
341 static inline bool __phy_package_set_once(struct phy_device *phydev,