Skip to content

Commit 9eea577

Browse files
Ansueldavem330
authored andcommitted
net: phy: extend PHY package API to support multiple global address
Current API for PHY package are limited to single address to configure global settings for the PHY package. It was found that some PHY package (for example the qca807x, a PHY package that is shipped with a bundle of 5 PHY) requires multiple PHY address to configure global settings. An example scenario is a PHY that have a dedicated PHY for PSGMII/serdes calibrarion and have a specific PHY in the package where the global PHY mode is set and affects every other PHY in the package. Change the API in the following way: - Change phy_package_join() to take the base addr of the PHY package instead of the global PHY addr. - Make __/phy_package_write/read() require an additional arg that select what global PHY address to use by passing the offset from the base addr passed on phy_package_join(). Each user of this API is updated to follow this new implementation following a pattern where an enum is defined to declare the offset of the addr. We also drop the check if shared is defined as any user of the phy_package_read/write is expected to use phy_package_join first. Misuse of this will correctly trigger a kernel panic for NULL pointer exception. Signed-off-by: Christian Marangi <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ebb30cc commit 9eea577

File tree

5 files changed

+80
-44
lines changed

5 files changed

+80
-44
lines changed

drivers/net/phy/bcm54140.c

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,10 @@
128128
#define BCM54140_DEFAULT_DOWNSHIFT 5
129129
#define BCM54140_MAX_DOWNSHIFT 9
130130

131+
enum bcm54140_global_phy {
132+
BCM54140_BASE_ADDR = 0,
133+
};
134+
131135
struct bcm54140_priv {
132136
int port;
133137
int base_addr;
@@ -429,11 +433,13 @@ static int bcm54140_base_read_rdb(struct phy_device *phydev, u16 rdb)
429433
int ret;
430434

431435
phy_lock_mdio_bus(phydev);
432-
ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
436+
ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
437+
MII_BCM54XX_RDB_ADDR, rdb);
433438
if (ret < 0)
434439
goto out;
435440

436-
ret = __phy_package_read(phydev, MII_BCM54XX_RDB_DATA);
441+
ret = __phy_package_read(phydev, BCM54140_BASE_ADDR,
442+
MII_BCM54XX_RDB_DATA);
437443

438444
out:
439445
phy_unlock_mdio_bus(phydev);
@@ -446,11 +452,13 @@ static int bcm54140_base_write_rdb(struct phy_device *phydev,
446452
int ret;
447453

448454
phy_lock_mdio_bus(phydev);
449-
ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
455+
ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
456+
MII_BCM54XX_RDB_ADDR, rdb);
450457
if (ret < 0)
451458
goto out;
452459

453-
ret = __phy_package_write(phydev, MII_BCM54XX_RDB_DATA, val);
460+
ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
461+
MII_BCM54XX_RDB_DATA, val);
454462

455463
out:
456464
phy_unlock_mdio_bus(phydev);

drivers/net/phy/mscc/mscc.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,11 @@ struct vsc8531_private {
416416
* gpio_lock: used for PHC operations. Common for all PHYs as the load/save GPIO
417417
* is shared.
418418
*/
419+
420+
enum vsc85xx_global_phy {
421+
VSC88XX_BASE_ADDR = 0,
422+
};
423+
419424
struct vsc85xx_shared_private {
420425
struct mutex gpio_lock;
421426
};

drivers/net/phy/mscc/mscc_main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ int phy_base_write(struct phy_device *phydev, u32 regnum, u16 val)
711711
dump_stack();
712712
}
713713

714-
return __phy_package_write(phydev, regnum, val);
714+
return __phy_package_write(phydev, VSC88XX_BASE_ADDR, regnum, val);
715715
}
716716

717717
/* phydev->bus->mdio_lock should be locked when using this function */
@@ -722,7 +722,7 @@ int phy_base_read(struct phy_device *phydev, u32 regnum)
722722
dump_stack();
723723
}
724724

725-
return __phy_package_read(phydev, regnum);
725+
return __phy_package_read(phydev, VSC88XX_BASE_ADDR, regnum);
726726
}
727727

728728
u32 vsc85xx_csr_read(struct phy_device *phydev,

drivers/net/phy/phy_device.c

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,20 +1651,22 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_10g);
16511651
/**
16521652
* phy_package_join - join a common PHY group
16531653
* @phydev: target phy_device struct
1654-
* @addr: cookie and PHY address for global register access
1654+
* @base_addr: cookie and base PHY address of PHY package for offset
1655+
* calculation of global register access
16551656
* @priv_size: if non-zero allocate this amount of bytes for private data
16561657
*
16571658
* This joins a PHY group and provides a shared storage for all phydevs in
16581659
* this group. This is intended to be used for packages which contain
16591660
* more than one PHY, for example a quad PHY transceiver.
16601661
*
1661-
* The addr parameter serves as a cookie which has to have the same value
1662-
* for all members of one group and as a PHY address to access generic
1663-
* registers of a PHY package. Usually, one of the PHY addresses of the
1664-
* different PHYs in the package provides access to these global registers.
1662+
* The base_addr parameter serves as cookie which has to have the same values
1663+
* for all members of one group and as the base PHY address of the PHY package
1664+
* for offset calculation to access generic registers of a PHY package.
1665+
* Usually, one of the PHY addresses of the different PHYs in the package
1666+
* provides access to these global registers.
16651667
* The address which is given here, will be used in the phy_package_read()
1666-
* and phy_package_write() convenience functions. If your PHY doesn't have
1667-
* global registers you can just pick any of the PHY addresses.
1668+
* and phy_package_write() convenience functions as base and added to the
1669+
* passed offset in those functions.
16681670
*
16691671
* This will set the shared pointer of the phydev to the shared storage.
16701672
* If this is the first call for a this cookie the shared storage will be
@@ -1674,17 +1676,17 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_10g);
16741676
* Returns < 1 on error, 0 on success. Esp. calling phy_package_join()
16751677
* with the same cookie but a different priv_size is an error.
16761678
*/
1677-
int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size)
1679+
int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size)
16781680
{
16791681
struct mii_bus *bus = phydev->mdio.bus;
16801682
struct phy_package_shared *shared;
16811683
int ret;
16821684

1683-
if (addr < 0 || addr >= PHY_MAX_ADDR)
1685+
if (base_addr < 0 || base_addr >= PHY_MAX_ADDR)
16841686
return -EINVAL;
16851687

16861688
mutex_lock(&bus->shared_lock);
1687-
shared = bus->shared[addr];
1689+
shared = bus->shared[base_addr];
16881690
if (!shared) {
16891691
ret = -ENOMEM;
16901692
shared = kzalloc(sizeof(*shared), GFP_KERNEL);
@@ -1696,9 +1698,9 @@ int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size)
16961698
goto err_free;
16971699
shared->priv_size = priv_size;
16981700
}
1699-
shared->addr = addr;
1701+
shared->base_addr = base_addr;
17001702
refcount_set(&shared->refcnt, 1);
1701-
bus->shared[addr] = shared;
1703+
bus->shared[base_addr] = shared;
17021704
} else {
17031705
ret = -EINVAL;
17041706
if (priv_size && priv_size != shared->priv_size)
@@ -1736,7 +1738,7 @@ void phy_package_leave(struct phy_device *phydev)
17361738
return;
17371739

17381740
if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
1739-
bus->shared[shared->addr] = NULL;
1741+
bus->shared[shared->base_addr] = NULL;
17401742
mutex_unlock(&bus->shared_lock);
17411743
kfree(shared->priv);
17421744
kfree(shared);
@@ -1755,15 +1757,16 @@ static void devm_phy_package_leave(struct device *dev, void *res)
17551757
* devm_phy_package_join - resource managed phy_package_join()
17561758
* @dev: device that is registering this PHY package
17571759
* @phydev: target phy_device struct
1758-
* @addr: cookie and PHY address for global register access
1760+
* @base_addr: cookie and base PHY address of PHY package for offset
1761+
* calculation of global register access
17591762
* @priv_size: if non-zero allocate this amount of bytes for private data
17601763
*
17611764
* Managed phy_package_join(). Shared storage fetched by this function,
17621765
* phy_package_leave() is automatically called on driver detach. See
17631766
* phy_package_join() for more information.
17641767
*/
17651768
int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
1766-
int addr, size_t priv_size)
1769+
int base_addr, size_t priv_size)
17671770
{
17681771
struct phy_device **ptr;
17691772
int ret;
@@ -1773,7 +1776,7 @@ int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
17731776
if (!ptr)
17741777
return -ENOMEM;
17751778

1776-
ret = phy_package_join(phydev, addr, priv_size);
1779+
ret = phy_package_join(phydev, base_addr, priv_size);
17771780

17781781
if (!ret) {
17791782
*ptr = phydev;

include/linux/phy.h

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,8 @@ struct mdio_bus_stats {
327327

328328
/**
329329
* struct phy_package_shared - Shared information in PHY packages
330-
* @addr: Common PHY address used to combine PHYs in one package
330+
* @base_addr: Base PHY address of PHY package used to combine PHYs
331+
* in one package and for offset calculation of phy_package_read/write
331332
* @refcnt: Number of PHYs connected to this shared data
332333
* @flags: Initialization of PHY package
333334
* @priv_size: Size of the shared private data @priv
@@ -338,7 +339,7 @@ struct mdio_bus_stats {
338339
* phy_package_leave().
339340
*/
340341
struct phy_package_shared {
341-
u8 addr;
342+
u8 base_addr;
342343
refcount_t refcnt;
343344
unsigned long flags;
344345
size_t priv_size;
@@ -1976,10 +1977,10 @@ int phy_ethtool_get_link_ksettings(struct net_device *ndev,
19761977
int phy_ethtool_set_link_ksettings(struct net_device *ndev,
19771978
const struct ethtool_link_ksettings *cmd);
19781979
int phy_ethtool_nway_reset(struct net_device *ndev);
1979-
int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size);
1980+
int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size);
19801981
void phy_package_leave(struct phy_device *phydev);
19811982
int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
1982-
int addr, size_t priv_size);
1983+
int base_addr, size_t priv_size);
19831984

19841985
int __init mdio_bus_init(void);
19851986
void mdio_bus_exit(void);
@@ -2002,46 +2003,65 @@ int __phy_hwtstamp_set(struct phy_device *phydev,
20022003
struct kernel_hwtstamp_config *config,
20032004
struct netlink_ext_ack *extack);
20042005

2005-
static inline int phy_package_read(struct phy_device *phydev, u32 regnum)
2006+
static inline int phy_package_address(struct phy_device *phydev,
2007+
unsigned int addr_offset)
20062008
{
20072009
struct phy_package_shared *shared = phydev->shared;
2010+
u8 base_addr = shared->base_addr;
20082011

2009-
if (!shared)
2012+
if (addr_offset >= PHY_MAX_ADDR - base_addr)
20102013
return -EIO;
20112014

2012-
return mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
2015+
/* we know that addr will be in the range 0..31 and thus the
2016+
* implicit cast to a signed int is not a problem.
2017+
*/
2018+
return base_addr + addr_offset;
20132019
}
20142020

2015-
static inline int __phy_package_read(struct phy_device *phydev, u32 regnum)
2021+
static inline int phy_package_read(struct phy_device *phydev,
2022+
unsigned int addr_offset, u32 regnum)
20162023
{
2017-
struct phy_package_shared *shared = phydev->shared;
2024+
int addr = phy_package_address(phydev, addr_offset);
20182025

2019-
if (!shared)
2020-
return -EIO;
2026+
if (addr < 0)
2027+
return addr;
2028+
2029+
return mdiobus_read(phydev->mdio.bus, addr, regnum);
2030+
}
2031+
2032+
static inline int __phy_package_read(struct phy_device *phydev,
2033+
unsigned int addr_offset, u32 regnum)
2034+
{
2035+
int addr = phy_package_address(phydev, addr_offset);
2036+
2037+
if (addr < 0)
2038+
return addr;
20212039

2022-
return __mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
2040+
return __mdiobus_read(phydev->mdio.bus, addr, regnum);
20232041
}
20242042

20252043
static inline int phy_package_write(struct phy_device *phydev,
2026-
u32 regnum, u16 val)
2044+
unsigned int addr_offset, u32 regnum,
2045+
u16 val)
20272046
{
2028-
struct phy_package_shared *shared = phydev->shared;
2047+
int addr = phy_package_address(phydev, addr_offset);
20292048

2030-
if (!shared)
2031-
return -EIO;
2049+
if (addr < 0)
2050+
return addr;
20322051

2033-
return mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
2052+
return mdiobus_write(phydev->mdio.bus, addr, regnum, val);
20342053
}
20352054

20362055
static inline int __phy_package_write(struct phy_device *phydev,
2037-
u32 regnum, u16 val)
2056+
unsigned int addr_offset, u32 regnum,
2057+
u16 val)
20382058
{
2039-
struct phy_package_shared *shared = phydev->shared;
2059+
int addr = phy_package_address(phydev, addr_offset);
20402060

2041-
if (!shared)
2042-
return -EIO;
2061+
if (addr < 0)
2062+
return addr;
20432063

2044-
return __mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
2064+
return __mdiobus_write(phydev->mdio.bus, addr, regnum, val);
20452065
}
20462066

20472067
static inline bool __phy_package_set_once(struct phy_device *phydev,

0 commit comments

Comments
 (0)