Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <ansuelsmth@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Christian Marangi and committed by
David S. Miller
9eea577e ebb30ccb

+80 -44
+12 -4
drivers/net/phy/bcm54140.c
··· 128 128 #define BCM54140_DEFAULT_DOWNSHIFT 5 129 129 #define BCM54140_MAX_DOWNSHIFT 9 130 130 131 + enum bcm54140_global_phy { 132 + BCM54140_BASE_ADDR = 0, 133 + }; 134 + 131 135 struct bcm54140_priv { 132 136 int port; 133 137 int base_addr; ··· 433 429 int ret; 434 430 435 431 phy_lock_mdio_bus(phydev); 436 - ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb); 432 + ret = __phy_package_write(phydev, BCM54140_BASE_ADDR, 433 + MII_BCM54XX_RDB_ADDR, rdb); 437 434 if (ret < 0) 438 435 goto out; 439 436 440 - ret = __phy_package_read(phydev, MII_BCM54XX_RDB_DATA); 437 + ret = __phy_package_read(phydev, BCM54140_BASE_ADDR, 438 + MII_BCM54XX_RDB_DATA); 441 439 442 440 out: 443 441 phy_unlock_mdio_bus(phydev); ··· 452 446 int ret; 453 447 454 448 phy_lock_mdio_bus(phydev); 455 - ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb); 449 + ret = __phy_package_write(phydev, BCM54140_BASE_ADDR, 450 + MII_BCM54XX_RDB_ADDR, rdb); 456 451 if (ret < 0) 457 452 goto out; 458 453 459 - ret = __phy_package_write(phydev, MII_BCM54XX_RDB_DATA, val); 454 + ret = __phy_package_write(phydev, BCM54140_BASE_ADDR, 455 + MII_BCM54XX_RDB_DATA, val); 460 456 461 457 out: 462 458 phy_unlock_mdio_bus(phydev);
+5
drivers/net/phy/mscc/mscc.h
··· 416 416 * gpio_lock: used for PHC operations. Common for all PHYs as the load/save GPIO 417 417 * is shared. 418 418 */ 419 + 420 + enum vsc85xx_global_phy { 421 + VSC88XX_BASE_ADDR = 0, 422 + }; 423 + 419 424 struct vsc85xx_shared_private { 420 425 struct mutex gpio_lock; 421 426 };
+2 -2
drivers/net/phy/mscc/mscc_main.c
··· 711 711 dump_stack(); 712 712 } 713 713 714 - return __phy_package_write(phydev, regnum, val); 714 + return __phy_package_write(phydev, VSC88XX_BASE_ADDR, regnum, val); 715 715 } 716 716 717 717 /* phydev->bus->mdio_lock should be locked when using this function */ ··· 722 722 dump_stack(); 723 723 } 724 724 725 - return __phy_package_read(phydev, regnum); 725 + return __phy_package_read(phydev, VSC88XX_BASE_ADDR, regnum); 726 726 } 727 727 728 728 u32 vsc85xx_csr_read(struct phy_device *phydev,
+19 -16
drivers/net/phy/phy_device.c
··· 1651 1651 /** 1652 1652 * phy_package_join - join a common PHY group 1653 1653 * @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 1655 1656 * @priv_size: if non-zero allocate this amount of bytes for private data 1656 1657 * 1657 1658 * This joins a PHY group and provides a shared storage for all phydevs in 1658 1659 * this group. This is intended to be used for packages which contain 1659 1660 * more than one PHY, for example a quad PHY transceiver. 1660 1661 * 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. 1665 1667 * 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. 1668 1670 * 1669 1671 * This will set the shared pointer of the phydev to the shared storage. 1670 1672 * If this is the first call for a this cookie the shared storage will be ··· 1676 1674 * Returns < 1 on error, 0 on success. Esp. calling phy_package_join() 1677 1675 * with the same cookie but a different priv_size is an error. 1678 1676 */ 1679 - int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size) 1677 + int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size) 1680 1678 { 1681 1679 struct mii_bus *bus = phydev->mdio.bus; 1682 1680 struct phy_package_shared *shared; 1683 1681 int ret; 1684 1682 1685 - if (addr < 0 || addr >= PHY_MAX_ADDR) 1683 + if (base_addr < 0 || base_addr >= PHY_MAX_ADDR) 1686 1684 return -EINVAL; 1687 1685 1688 1686 mutex_lock(&bus->shared_lock); 1689 - shared = bus->shared[addr]; 1687 + shared = bus->shared[base_addr]; 1690 1688 if (!shared) { 1691 1689 ret = -ENOMEM; 1692 1690 shared = kzalloc(sizeof(*shared), GFP_KERNEL); ··· 1698 1696 goto err_free; 1699 1697 shared->priv_size = priv_size; 1700 1698 } 1701 - shared->addr = addr; 1699 + shared->base_addr = base_addr; 1702 1700 refcount_set(&shared->refcnt, 1); 1703 - bus->shared[addr] = shared; 1701 + bus->shared[base_addr] = shared; 1704 1702 } else { 1705 1703 ret = -EINVAL; 1706 1704 if (priv_size && priv_size != shared->priv_size) ··· 1738 1736 return; 1739 1737 1740 1738 if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) { 1741 - bus->shared[shared->addr] = NULL; 1739 + bus->shared[shared->base_addr] = NULL; 1742 1740 mutex_unlock(&bus->shared_lock); 1743 1741 kfree(shared->priv); 1744 1742 kfree(shared); ··· 1757 1755 * devm_phy_package_join - resource managed phy_package_join() 1758 1756 * @dev: device that is registering this PHY package 1759 1757 * @phydev: target phy_device struct 1760 - * @addr: cookie and PHY address for global register access 1758 + * @base_addr: cookie and base PHY address of PHY package for offset 1759 + * calculation of global register access 1761 1760 * @priv_size: if non-zero allocate this amount of bytes for private data 1762 1761 * 1763 1762 * Managed phy_package_join(). Shared storage fetched by this function, ··· 1766 1763 * phy_package_join() for more information. 1767 1764 */ 1768 1765 int devm_phy_package_join(struct device *dev, struct phy_device *phydev, 1769 - int addr, size_t priv_size) 1766 + int base_addr, size_t priv_size) 1770 1767 { 1771 1768 struct phy_device **ptr; 1772 1769 int ret; ··· 1776 1773 if (!ptr) 1777 1774 return -ENOMEM; 1778 1775 1779 - ret = phy_package_join(phydev, addr, priv_size); 1776 + ret = phy_package_join(phydev, base_addr, priv_size); 1780 1777 1781 1778 if (!ret) { 1782 1779 *ptr = phydev;
+42 -22
include/linux/phy.h
··· 327 327 328 328 /** 329 329 * 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 331 332 * @refcnt: Number of PHYs connected to this shared data 332 333 * @flags: Initialization of PHY package 333 334 * @priv_size: Size of the shared private data @priv ··· 339 338 * phy_package_leave(). 340 339 */ 341 340 struct phy_package_shared { 342 - u8 addr; 341 + u8 base_addr; 343 342 refcount_t refcnt; 344 343 unsigned long flags; 345 344 size_t priv_size; ··· 1977 1976 int phy_ethtool_set_link_ksettings(struct net_device *ndev, 1978 1977 const struct ethtool_link_ksettings *cmd); 1979 1978 int phy_ethtool_nway_reset(struct net_device *ndev); 1980 - int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size); 1979 + int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size); 1981 1980 void phy_package_leave(struct phy_device *phydev); 1982 1981 int devm_phy_package_join(struct device *dev, struct phy_device *phydev, 1983 - int addr, size_t priv_size); 1982 + int base_addr, size_t priv_size); 1984 1983 1985 1984 int __init mdio_bus_init(void); 1986 1985 void mdio_bus_exit(void); ··· 2003 2002 struct kernel_hwtstamp_config *config, 2004 2003 struct netlink_ext_ack *extack); 2005 2004 2006 - static inline int phy_package_read(struct phy_device *phydev, u32 regnum) 2005 + static inline int phy_package_address(struct phy_device *phydev, 2006 + unsigned int addr_offset) 2007 2007 { 2008 2008 struct phy_package_shared *shared = phydev->shared; 2009 + u8 base_addr = shared->base_addr; 2009 2010 2010 - if (!shared) 2011 + if (addr_offset >= PHY_MAX_ADDR - base_addr) 2011 2012 return -EIO; 2012 2013 2013 - return mdiobus_read(phydev->mdio.bus, shared->addr, regnum); 2014 + /* we know that addr will be in the range 0..31 and thus the 2015 + * implicit cast to a signed int is not a problem. 2016 + */ 2017 + return base_addr + addr_offset; 2014 2018 } 2015 2019 2016 - static inline int __phy_package_read(struct phy_device *phydev, u32 regnum) 2020 + static inline int phy_package_read(struct phy_device *phydev, 2021 + unsigned int addr_offset, u32 regnum) 2017 2022 { 2018 - struct phy_package_shared *shared = phydev->shared; 2023 + int addr = phy_package_address(phydev, addr_offset); 2019 2024 2020 - if (!shared) 2021 - return -EIO; 2025 + if (addr < 0) 2026 + return addr; 2022 2027 2023 - return __mdiobus_read(phydev->mdio.bus, shared->addr, regnum); 2028 + return mdiobus_read(phydev->mdio.bus, addr, regnum); 2029 + } 2030 + 2031 + static inline int __phy_package_read(struct phy_device *phydev, 2032 + unsigned int addr_offset, u32 regnum) 2033 + { 2034 + int addr = phy_package_address(phydev, addr_offset); 2035 + 2036 + if (addr < 0) 2037 + return addr; 2038 + 2039 + return __mdiobus_read(phydev->mdio.bus, addr, regnum); 2024 2040 } 2025 2041 2026 2042 static inline int phy_package_write(struct phy_device *phydev, 2027 - u32 regnum, u16 val) 2043 + unsigned int addr_offset, u32 regnum, 2044 + u16 val) 2028 2045 { 2029 - struct phy_package_shared *shared = phydev->shared; 2046 + int addr = phy_package_address(phydev, addr_offset); 2030 2047 2031 - if (!shared) 2032 - return -EIO; 2048 + if (addr < 0) 2049 + return addr; 2033 2050 2034 - return mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val); 2051 + return mdiobus_write(phydev->mdio.bus, addr, regnum, val); 2035 2052 } 2036 2053 2037 2054 static inline int __phy_package_write(struct phy_device *phydev, 2038 - u32 regnum, u16 val) 2055 + unsigned int addr_offset, u32 regnum, 2056 + u16 val) 2039 2057 { 2040 - struct phy_package_shared *shared = phydev->shared; 2058 + int addr = phy_package_address(phydev, addr_offset); 2041 2059 2042 - if (!shared) 2043 - return -EIO; 2060 + if (addr < 0) 2061 + return addr; 2044 2062 2045 - return __mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val); 2063 + return __mdiobus_write(phydev->mdio.bus, addr, regnum, val); 2046 2064 } 2047 2065 2048 2066 static inline bool __phy_package_set_once(struct phy_device *phydev,