mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 22:44:27 -05:00 
			
		
		
		
	Changelog: https://cdn.kernel.org/pub/linux/kernel/v6.x/ChangeLog-6.6.27
Removed upstreamed:
	pending-6.6/981-gcc-plugins-stackleak-Avoid-.head.txt.section.patch[1]
All patches automatically rebased.
1. 9dff96b8b3
Build system: x86/64
Build-tested: flogic/xiaomi_redmi-router-ax6000-ubootmod, ramips/tplink_archer-a6-v3, x86/64/AMD Cezanne
Run-tested: flogic/xiaomi_redmi-router-ax6000-ubootmod, ramips/tplink_archer-a6-v3, x86/64/AMD Cezanne
Signed-off-by: John Audia <therealgraysky@proton.me>
		
	
			
		
			
				
	
	
		
			342 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			342 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 9eea577eb1155fe4a183bc5e7bf269b0b2e7a6ba Mon Sep 17 00:00:00 2001
 | 
						|
From: Christian Marangi <ansuelsmth@gmail.com>
 | 
						|
Date: Fri, 15 Dec 2023 14:15:32 +0100
 | 
						|
Subject: [PATCH 2/4] 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>
 | 
						|
---
 | 
						|
 drivers/net/phy/bcm54140.c       | 16 ++++++--
 | 
						|
 drivers/net/phy/mscc/mscc.h      |  5 +++
 | 
						|
 drivers/net/phy/mscc/mscc_main.c |  4 +-
 | 
						|
 drivers/net/phy/phy_device.c     | 35 +++++++++--------
 | 
						|
 include/linux/phy.h              | 64 +++++++++++++++++++++-----------
 | 
						|
 5 files changed, 80 insertions(+), 44 deletions(-)
 | 
						|
 | 
						|
--- a/drivers/net/phy/bcm54140.c
 | 
						|
+++ b/drivers/net/phy/bcm54140.c
 | 
						|
@@ -128,6 +128,10 @@
 | 
						|
 #define BCM54140_DEFAULT_DOWNSHIFT 5
 | 
						|
 #define BCM54140_MAX_DOWNSHIFT 9
 | 
						|
 
 | 
						|
+enum bcm54140_global_phy {
 | 
						|
+	BCM54140_BASE_ADDR = 0,
 | 
						|
+};
 | 
						|
+
 | 
						|
 struct bcm54140_priv {
 | 
						|
 	int port;
 | 
						|
 	int base_addr;
 | 
						|
@@ -429,11 +433,13 @@ static int bcm54140_base_read_rdb(struct
 | 
						|
 	int ret;
 | 
						|
 
 | 
						|
 	phy_lock_mdio_bus(phydev);
 | 
						|
-	ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
 | 
						|
+	ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
 | 
						|
+				  MII_BCM54XX_RDB_ADDR, rdb);
 | 
						|
 	if (ret < 0)
 | 
						|
 		goto out;
 | 
						|
 
 | 
						|
-	ret = __phy_package_read(phydev, MII_BCM54XX_RDB_DATA);
 | 
						|
+	ret = __phy_package_read(phydev, BCM54140_BASE_ADDR,
 | 
						|
+				 MII_BCM54XX_RDB_DATA);
 | 
						|
 
 | 
						|
 out:
 | 
						|
 	phy_unlock_mdio_bus(phydev);
 | 
						|
@@ -446,11 +452,13 @@ static int bcm54140_base_write_rdb(struc
 | 
						|
 	int ret;
 | 
						|
 
 | 
						|
 	phy_lock_mdio_bus(phydev);
 | 
						|
-	ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
 | 
						|
+	ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
 | 
						|
+				  MII_BCM54XX_RDB_ADDR, rdb);
 | 
						|
 	if (ret < 0)
 | 
						|
 		goto out;
 | 
						|
 
 | 
						|
-	ret = __phy_package_write(phydev, MII_BCM54XX_RDB_DATA, val);
 | 
						|
+	ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
 | 
						|
+				  MII_BCM54XX_RDB_DATA, val);
 | 
						|
 
 | 
						|
 out:
 | 
						|
 	phy_unlock_mdio_bus(phydev);
 | 
						|
--- a/drivers/net/phy/mscc/mscc.h
 | 
						|
+++ b/drivers/net/phy/mscc/mscc.h
 | 
						|
@@ -416,6 +416,11 @@ struct vsc8531_private {
 | 
						|
  * gpio_lock: used for PHC operations. Common for all PHYs as the load/save GPIO
 | 
						|
  * is shared.
 | 
						|
  */
 | 
						|
+
 | 
						|
+enum vsc85xx_global_phy {
 | 
						|
+	VSC88XX_BASE_ADDR = 0,
 | 
						|
+};
 | 
						|
+
 | 
						|
 struct vsc85xx_shared_private {
 | 
						|
 	struct mutex gpio_lock;
 | 
						|
 };
 | 
						|
--- a/drivers/net/phy/mscc/mscc_main.c
 | 
						|
+++ b/drivers/net/phy/mscc/mscc_main.c
 | 
						|
@@ -711,7 +711,7 @@ int phy_base_write(struct phy_device *ph
 | 
						|
 		dump_stack();
 | 
						|
 	}
 | 
						|
 
 | 
						|
-	return __phy_package_write(phydev, regnum, val);
 | 
						|
+	return __phy_package_write(phydev, VSC88XX_BASE_ADDR, regnum, val);
 | 
						|
 }
 | 
						|
 
 | 
						|
 /* phydev->bus->mdio_lock should be locked when using this function */
 | 
						|
@@ -722,7 +722,7 @@ int phy_base_read(struct phy_device *phy
 | 
						|
 		dump_stack();
 | 
						|
 	}
 | 
						|
 
 | 
						|
-	return __phy_package_read(phydev, regnum);
 | 
						|
+	return __phy_package_read(phydev, VSC88XX_BASE_ADDR, regnum);
 | 
						|
 }
 | 
						|
 
 | 
						|
 u32 vsc85xx_csr_read(struct phy_device *phydev,
 | 
						|
--- a/drivers/net/phy/phy_device.c
 | 
						|
+++ b/drivers/net/phy/phy_device.c
 | 
						|
@@ -1658,20 +1658,22 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_1
 | 
						|
 /**
 | 
						|
  * phy_package_join - join a common PHY group
 | 
						|
  * @phydev: target phy_device struct
 | 
						|
- * @addr: cookie and PHY address for global register access
 | 
						|
+ * @base_addr: cookie and base PHY address of PHY package for offset
 | 
						|
+ *   calculation of global register access
 | 
						|
  * @priv_size: if non-zero allocate this amount of bytes for private data
 | 
						|
  *
 | 
						|
  * This joins a PHY group and provides a shared storage for all phydevs in
 | 
						|
  * this group. This is intended to be used for packages which contain
 | 
						|
  * more than one PHY, for example a quad PHY transceiver.
 | 
						|
  *
 | 
						|
- * The addr parameter serves as a cookie which has to have the same value
 | 
						|
- * for all members of one group and as a PHY address to access generic
 | 
						|
- * registers of a PHY package. Usually, one of the PHY addresses of the
 | 
						|
- * different PHYs in the package provides access to these global registers.
 | 
						|
+ * The base_addr parameter serves as cookie which has to have the same values
 | 
						|
+ * for all members of one group and as the base PHY address of the PHY package
 | 
						|
+ * for offset calculation to access generic registers of a PHY package.
 | 
						|
+ * Usually, one of the PHY addresses of the different PHYs in the package
 | 
						|
+ * provides access to these global registers.
 | 
						|
  * The address which is given here, will be used in the phy_package_read()
 | 
						|
- * and phy_package_write() convenience functions. If your PHY doesn't have
 | 
						|
- * global registers you can just pick any of the PHY addresses.
 | 
						|
+ * and phy_package_write() convenience functions as base and added to the
 | 
						|
+ * passed offset in those functions.
 | 
						|
  *
 | 
						|
  * This will set the shared pointer of the phydev to the shared storage.
 | 
						|
  * If this is the first call for a this cookie the shared storage will be
 | 
						|
@@ -1681,17 +1683,17 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_1
 | 
						|
  * Returns < 1 on error, 0 on success. Esp. calling phy_package_join()
 | 
						|
  * with the same cookie but a different priv_size is an error.
 | 
						|
  */
 | 
						|
-int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size)
 | 
						|
+int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size)
 | 
						|
 {
 | 
						|
 	struct mii_bus *bus = phydev->mdio.bus;
 | 
						|
 	struct phy_package_shared *shared;
 | 
						|
 	int ret;
 | 
						|
 
 | 
						|
-	if (addr < 0 || addr >= PHY_MAX_ADDR)
 | 
						|
+	if (base_addr < 0 || base_addr >= PHY_MAX_ADDR)
 | 
						|
 		return -EINVAL;
 | 
						|
 
 | 
						|
 	mutex_lock(&bus->shared_lock);
 | 
						|
-	shared = bus->shared[addr];
 | 
						|
+	shared = bus->shared[base_addr];
 | 
						|
 	if (!shared) {
 | 
						|
 		ret = -ENOMEM;
 | 
						|
 		shared = kzalloc(sizeof(*shared), GFP_KERNEL);
 | 
						|
@@ -1703,9 +1705,9 @@ int phy_package_join(struct phy_device *
 | 
						|
 				goto err_free;
 | 
						|
 			shared->priv_size = priv_size;
 | 
						|
 		}
 | 
						|
-		shared->addr = addr;
 | 
						|
+		shared->base_addr = base_addr;
 | 
						|
 		refcount_set(&shared->refcnt, 1);
 | 
						|
-		bus->shared[addr] = shared;
 | 
						|
+		bus->shared[base_addr] = shared;
 | 
						|
 	} else {
 | 
						|
 		ret = -EINVAL;
 | 
						|
 		if (priv_size && priv_size != shared->priv_size)
 | 
						|
@@ -1743,7 +1745,7 @@ void phy_package_leave(struct phy_device
 | 
						|
 		return;
 | 
						|
 
 | 
						|
 	if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
 | 
						|
-		bus->shared[shared->addr] = NULL;
 | 
						|
+		bus->shared[shared->base_addr] = NULL;
 | 
						|
 		mutex_unlock(&bus->shared_lock);
 | 
						|
 		kfree(shared->priv);
 | 
						|
 		kfree(shared);
 | 
						|
@@ -1762,7 +1764,8 @@ static void devm_phy_package_leave(struc
 | 
						|
  * devm_phy_package_join - resource managed phy_package_join()
 | 
						|
  * @dev: device that is registering this PHY package
 | 
						|
  * @phydev: target phy_device struct
 | 
						|
- * @addr: cookie and PHY address for global register access
 | 
						|
+ * @base_addr: cookie and base PHY address of PHY package for offset
 | 
						|
+ *   calculation of global register access
 | 
						|
  * @priv_size: if non-zero allocate this amount of bytes for private data
 | 
						|
  *
 | 
						|
  * Managed phy_package_join(). Shared storage fetched by this function,
 | 
						|
@@ -1770,7 +1773,7 @@ static void devm_phy_package_leave(struc
 | 
						|
  * phy_package_join() for more information.
 | 
						|
  */
 | 
						|
 int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
 | 
						|
-			  int addr, size_t priv_size)
 | 
						|
+			  int base_addr, size_t priv_size)
 | 
						|
 {
 | 
						|
 	struct phy_device **ptr;
 | 
						|
 	int ret;
 | 
						|
@@ -1780,7 +1783,7 @@ int devm_phy_package_join(struct device
 | 
						|
 	if (!ptr)
 | 
						|
 		return -ENOMEM;
 | 
						|
 
 | 
						|
-	ret = phy_package_join(phydev, addr, priv_size);
 | 
						|
+	ret = phy_package_join(phydev, base_addr, priv_size);
 | 
						|
 
 | 
						|
 	if (!ret) {
 | 
						|
 		*ptr = phydev;
 | 
						|
--- a/include/linux/phy.h
 | 
						|
+++ b/include/linux/phy.h
 | 
						|
@@ -327,7 +327,8 @@ struct mdio_bus_stats {
 | 
						|
 
 | 
						|
 /**
 | 
						|
  * struct phy_package_shared - Shared information in PHY packages
 | 
						|
- * @addr: Common PHY address used to combine PHYs in one package
 | 
						|
+ * @base_addr: Base PHY address of PHY package used to combine PHYs
 | 
						|
+ *   in one package and for offset calculation of phy_package_read/write
 | 
						|
  * @refcnt: Number of PHYs connected to this shared data
 | 
						|
  * @flags: Initialization of PHY package
 | 
						|
  * @priv_size: Size of the shared private data @priv
 | 
						|
@@ -338,7 +339,7 @@ struct mdio_bus_stats {
 | 
						|
  * phy_package_leave().
 | 
						|
  */
 | 
						|
 struct phy_package_shared {
 | 
						|
-	u8 addr;
 | 
						|
+	u8 base_addr;
 | 
						|
 	refcount_t refcnt;
 | 
						|
 	unsigned long flags;
 | 
						|
 	size_t priv_size;
 | 
						|
@@ -1969,10 +1970,10 @@ int phy_ethtool_get_link_ksettings(struc
 | 
						|
 int phy_ethtool_set_link_ksettings(struct net_device *ndev,
 | 
						|
 				   const struct ethtool_link_ksettings *cmd);
 | 
						|
 int phy_ethtool_nway_reset(struct net_device *ndev);
 | 
						|
-int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size);
 | 
						|
+int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size);
 | 
						|
 void phy_package_leave(struct phy_device *phydev);
 | 
						|
 int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
 | 
						|
-			  int addr, size_t priv_size);
 | 
						|
+			  int base_addr, size_t priv_size);
 | 
						|
 
 | 
						|
 int __init mdio_bus_init(void);
 | 
						|
 void mdio_bus_exit(void);
 | 
						|
@@ -1995,46 +1996,65 @@ int __phy_hwtstamp_set(struct phy_device
 | 
						|
 		       struct kernel_hwtstamp_config *config,
 | 
						|
 		       struct netlink_ext_ack *extack);
 | 
						|
 
 | 
						|
-static inline int phy_package_read(struct phy_device *phydev, u32 regnum)
 | 
						|
+static inline int phy_package_address(struct phy_device *phydev,
 | 
						|
+				      unsigned int addr_offset)
 | 
						|
 {
 | 
						|
 	struct phy_package_shared *shared = phydev->shared;
 | 
						|
+	u8 base_addr = shared->base_addr;
 | 
						|
 
 | 
						|
-	if (!shared)
 | 
						|
+	if (addr_offset >= PHY_MAX_ADDR - base_addr)
 | 
						|
 		return -EIO;
 | 
						|
 
 | 
						|
-	return mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
 | 
						|
+	/* we know that addr will be in the range 0..31 and thus the
 | 
						|
+	 * implicit cast to a signed int is not a problem.
 | 
						|
+	 */
 | 
						|
+	return base_addr + addr_offset;
 | 
						|
 }
 | 
						|
 
 | 
						|
-static inline int __phy_package_read(struct phy_device *phydev, u32 regnum)
 | 
						|
+static inline int phy_package_read(struct phy_device *phydev,
 | 
						|
+				   unsigned int addr_offset, u32 regnum)
 | 
						|
 {
 | 
						|
-	struct phy_package_shared *shared = phydev->shared;
 | 
						|
+	int addr = phy_package_address(phydev, addr_offset);
 | 
						|
 
 | 
						|
-	if (!shared)
 | 
						|
-		return -EIO;
 | 
						|
+	if (addr < 0)
 | 
						|
+		return addr;
 | 
						|
+
 | 
						|
+	return mdiobus_read(phydev->mdio.bus, addr, regnum);
 | 
						|
+}
 | 
						|
+
 | 
						|
+static inline int __phy_package_read(struct phy_device *phydev,
 | 
						|
+				     unsigned int addr_offset, u32 regnum)
 | 
						|
+{
 | 
						|
+	int addr = phy_package_address(phydev, addr_offset);
 | 
						|
+
 | 
						|
+	if (addr < 0)
 | 
						|
+		return addr;
 | 
						|
 
 | 
						|
-	return __mdiobus_read(phydev->mdio.bus, shared->addr, regnum);
 | 
						|
+	return __mdiobus_read(phydev->mdio.bus, addr, regnum);
 | 
						|
 }
 | 
						|
 
 | 
						|
 static inline int phy_package_write(struct phy_device *phydev,
 | 
						|
-				    u32 regnum, u16 val)
 | 
						|
+				    unsigned int addr_offset, u32 regnum,
 | 
						|
+				    u16 val)
 | 
						|
 {
 | 
						|
-	struct phy_package_shared *shared = phydev->shared;
 | 
						|
+	int addr = phy_package_address(phydev, addr_offset);
 | 
						|
 
 | 
						|
-	if (!shared)
 | 
						|
-		return -EIO;
 | 
						|
+	if (addr < 0)
 | 
						|
+		return addr;
 | 
						|
 
 | 
						|
-	return mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
 | 
						|
+	return mdiobus_write(phydev->mdio.bus, addr, regnum, val);
 | 
						|
 }
 | 
						|
 
 | 
						|
 static inline int __phy_package_write(struct phy_device *phydev,
 | 
						|
-				      u32 regnum, u16 val)
 | 
						|
+				      unsigned int addr_offset, u32 regnum,
 | 
						|
+				      u16 val)
 | 
						|
 {
 | 
						|
-	struct phy_package_shared *shared = phydev->shared;
 | 
						|
+	int addr = phy_package_address(phydev, addr_offset);
 | 
						|
 
 | 
						|
-	if (!shared)
 | 
						|
-		return -EIO;
 | 
						|
+	if (addr < 0)
 | 
						|
+		return addr;
 | 
						|
 
 | 
						|
-	return __mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val);
 | 
						|
+	return __mdiobus_write(phydev->mdio.bus, addr, regnum, val);
 | 
						|
 }
 | 
						|
 
 | 
						|
 static inline bool __phy_package_set_once(struct phy_device *phydev,
 |