--- /dev/null
+From ebb30ccbbdbd6fae5177b676da4f4ac92bb4f635 Mon Sep 17 00:00:00 2001
+From: Christian Marangi <ansuelsmth@gmail.com>
+Date: Fri, 15 Dec 2023 14:15:31 +0100
+Subject: [PATCH 1/4] net: phy: make addr type u8 in phy_package_shared struct
+
+Switch addr type in phy_package_shared struct to u8.
+
+The value is already checked to be non negative and to be less than
+PHY_MAX_ADDR, hence u8 is better suited than using int.
+
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ include/linux/phy.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -330,7 +330,7 @@ struct mdio_bus_stats {
+ * phy_package_leave().
+ */
+ struct phy_package_shared {
+- int addr;
++ u8 addr;
+ refcount_t refcnt;
+ unsigned long flags;
+ size_t priv_size;
--- /dev/null
+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
+@@ -414,6 +414,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
+@@ -700,7 +700,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 */
+@@ -711,7 +711,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
+@@ -1602,20 +1602,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
+@@ -1625,17 +1627,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);
+@@ -1647,9 +1649,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)
+@@ -1687,7 +1689,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);
+@@ -1706,7 +1708,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,
+@@ -1714,7 +1717,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;
+@@ -1724,7 +1727,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
+@@ -319,7 +319,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
+@@ -330,7 +331,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;
+@@ -1763,10 +1764,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);
+
+ #if IS_ENABLED(CONFIG_PHYLIB)
+ int __init mdio_bus_init(void);
+@@ -1778,46 +1779,65 @@ int phy_ethtool_get_sset_count(struct ph
+ int phy_ethtool_get_stats(struct phy_device *phydev,
+ struct ethtool_stats *stats, u64 *data);
+
+-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,
--- /dev/null
+From 028672bd1d73cf65249a420c1de75e8d2acd2f6a Mon Sep 17 00:00:00 2001
+From: Christian Marangi <ansuelsmth@gmail.com>
+Date: Fri, 15 Dec 2023 14:15:33 +0100
+Subject: [PATCH 3/4] net: phy: restructure __phy_write/read_mmd to helper and
+ phydev user
+
+Restructure phy_write_mmd and phy_read_mmd to implement generic helper
+for direct mdiobus access for mmd and use these helper for phydev user.
+
+This is needed in preparation of PHY package API that requires generic
+access to the mdiobus and are deatched from phydev struct but instead
+access them based on PHY package base_addr and offsets.
+
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/phy-core.c | 64 ++++++++++++++++++--------------------
+ 1 file changed, 30 insertions(+), 34 deletions(-)
+
+--- a/drivers/net/phy/phy-core.c
++++ b/drivers/net/phy/phy-core.c
+@@ -528,6 +528,28 @@ static void mmd_phy_indirect(struct mii_
+ devad | MII_MMD_CTRL_NOINCR);
+ }
+
++static int mmd_phy_read(struct mii_bus *bus, int phy_addr, bool is_c45,
++ int devad, u32 regnum)
++{
++ if (is_c45)
++ return __mdiobus_c45_read(bus, phy_addr, devad, regnum);
++
++ mmd_phy_indirect(bus, phy_addr, devad, regnum);
++ /* Read the content of the MMD's selected register */
++ return __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
++}
++
++static int mmd_phy_write(struct mii_bus *bus, int phy_addr, bool is_c45,
++ int devad, u32 regnum, u16 val)
++{
++ if (is_c45)
++ return __mdiobus_c45_write(bus, phy_addr, devad, regnum, val);
++
++ mmd_phy_indirect(bus, phy_addr, devad, regnum);
++ /* Write the data into MMD's selected register */
++ return __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
++}
++
+ /**
+ * __phy_read_mmd - Convenience function for reading a register
+ * from an MMD on a given PHY.
+@@ -539,26 +561,14 @@ static void mmd_phy_indirect(struct mii_
+ */
+ int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
+ {
+- int val;
+-
+ if (regnum > (u16)~0 || devad > 32)
+ return -EINVAL;
+
+- if (phydev->drv && phydev->drv->read_mmd) {
+- val = phydev->drv->read_mmd(phydev, devad, regnum);
+- } else if (phydev->is_c45) {
+- val = __mdiobus_c45_read(phydev->mdio.bus, phydev->mdio.addr,
+- devad, regnum);
+- } else {
+- struct mii_bus *bus = phydev->mdio.bus;
+- int phy_addr = phydev->mdio.addr;
+-
+- mmd_phy_indirect(bus, phy_addr, devad, regnum);
+-
+- /* Read the content of the MMD's selected register */
+- val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
+- }
+- return val;
++ if (phydev->drv && phydev->drv->read_mmd)
++ return phydev->drv->read_mmd(phydev, devad, regnum);
++
++ return mmd_phy_read(phydev->mdio.bus, phydev->mdio.addr,
++ phydev->is_c45, devad, regnum);
+ }
+ EXPORT_SYMBOL(__phy_read_mmd);
+
+@@ -595,28 +605,14 @@ EXPORT_SYMBOL(phy_read_mmd);
+ */
+ int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
+ {
+- int ret;
+-
+ if (regnum > (u16)~0 || devad > 32)
+ return -EINVAL;
+
+- if (phydev->drv && phydev->drv->write_mmd) {
+- ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
+- } else if (phydev->is_c45) {
+- ret = __mdiobus_c45_write(phydev->mdio.bus, phydev->mdio.addr,
+- devad, regnum, val);
+- } else {
+- struct mii_bus *bus = phydev->mdio.bus;
+- int phy_addr = phydev->mdio.addr;
++ if (phydev->drv && phydev->drv->write_mmd)
++ return phydev->drv->write_mmd(phydev, devad, regnum, val);
+
+- mmd_phy_indirect(bus, phy_addr, devad, regnum);
+-
+- /* Write the data into MMD's selected register */
+- __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
+-
+- ret = 0;
+- }
+- return ret;
++ return mmd_phy_write(phydev->mdio.bus, phydev->mdio.addr,
++ phydev->is_c45, devad, regnum, val);
+ }
+ EXPORT_SYMBOL(__phy_write_mmd);
+
--- /dev/null
+From d63710fc0f1a501fd75a7025e3070a96ffa1645f Mon Sep 17 00:00:00 2001
+From: Christian Marangi <ansuelsmth@gmail.com>
+Date: Fri, 15 Dec 2023 14:15:34 +0100
+Subject: [PATCH 4/4] net: phy: add support for PHY package MMD read/write
+
+Some PHY in PHY package may require to read/write MMD regs to correctly
+configure the PHY package.
+
+Add support for these additional required function in both lock and no
+lock variant.
+
+It's assumed that the entire PHY package is either C22 or C45. We use
+C22 or C45 way of writing/reading to mmd regs based on the passed phydev
+whether it's C22 or C45.
+
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/phy-core.c | 140 +++++++++++++++++++++++++++++++++++++
+ include/linux/phy.h | 16 +++++
+ 2 files changed, 156 insertions(+)
+
+--- a/drivers/net/phy/phy-core.c
++++ b/drivers/net/phy/phy-core.c
+@@ -639,6 +639,146 @@ int phy_write_mmd(struct phy_device *phy
+ EXPORT_SYMBOL(phy_write_mmd);
+
+ /**
++ * __phy_package_read_mmd - read MMD reg relative to PHY package base addr
++ * @phydev: The phy_device struct
++ * @addr_offset: The offset to be added to PHY package base_addr
++ * @devad: The MMD to read from
++ * @regnum: The register on the MMD to read
++ *
++ * Convenience helper for reading a register of an MMD on a given PHY
++ * using the PHY package base address. The base address is added to
++ * the addr_offset value.
++ *
++ * Same calling rules as for __phy_read();
++ *
++ * NOTE: It's assumed that the entire PHY package is either C22 or C45.
++ */
++int __phy_package_read_mmd(struct phy_device *phydev,
++ unsigned int addr_offset, int devad,
++ u32 regnum)
++{
++ int addr = phy_package_address(phydev, addr_offset);
++
++ if (addr < 0)
++ return addr;
++
++ if (regnum > (u16)~0 || devad > 32)
++ return -EINVAL;
++
++ return mmd_phy_read(phydev->mdio.bus, addr, phydev->is_c45, devad,
++ regnum);
++}
++EXPORT_SYMBOL(__phy_package_read_mmd);
++
++/**
++ * phy_package_read_mmd - read MMD reg relative to PHY package base addr
++ * @phydev: The phy_device struct
++ * @addr_offset: The offset to be added to PHY package base_addr
++ * @devad: The MMD to read from
++ * @regnum: The register on the MMD to read
++ *
++ * Convenience helper for reading a register of an MMD on a given PHY
++ * using the PHY package base address. The base address is added to
++ * the addr_offset value.
++ *
++ * Same calling rules as for phy_read();
++ *
++ * NOTE: It's assumed that the entire PHY package is either C22 or C45.
++ */
++int phy_package_read_mmd(struct phy_device *phydev,
++ unsigned int addr_offset, int devad,
++ u32 regnum)
++{
++ int addr = phy_package_address(phydev, addr_offset);
++ int val;
++
++ if (addr < 0)
++ return addr;
++
++ if (regnum > (u16)~0 || devad > 32)
++ return -EINVAL;
++
++ phy_lock_mdio_bus(phydev);
++ val = mmd_phy_read(phydev->mdio.bus, addr, phydev->is_c45, devad,
++ regnum);
++ phy_unlock_mdio_bus(phydev);
++
++ return val;
++}
++EXPORT_SYMBOL(phy_package_read_mmd);
++
++/**
++ * __phy_package_write_mmd - write MMD reg relative to PHY package base addr
++ * @phydev: The phy_device struct
++ * @addr_offset: The offset to be added to PHY package base_addr
++ * @devad: The MMD to write to
++ * @regnum: The register on the MMD to write
++ * @val: value to write to @regnum
++ *
++ * Convenience helper for writing a register of an MMD on a given PHY
++ * using the PHY package base address. The base address is added to
++ * the addr_offset value.
++ *
++ * Same calling rules as for __phy_write();
++ *
++ * NOTE: It's assumed that the entire PHY package is either C22 or C45.
++ */
++int __phy_package_write_mmd(struct phy_device *phydev,
++ unsigned int addr_offset, int devad,
++ u32 regnum, u16 val)
++{
++ int addr = phy_package_address(phydev, addr_offset);
++
++ if (addr < 0)
++ return addr;
++
++ if (regnum > (u16)~0 || devad > 32)
++ return -EINVAL;
++
++ return mmd_phy_write(phydev->mdio.bus, addr, phydev->is_c45, devad,
++ regnum, val);
++}
++EXPORT_SYMBOL(__phy_package_write_mmd);
++
++/**
++ * phy_package_write_mmd - write MMD reg relative to PHY package base addr
++ * @phydev: The phy_device struct
++ * @addr_offset: The offset to be added to PHY package base_addr
++ * @devad: The MMD to write to
++ * @regnum: The register on the MMD to write
++ * @val: value to write to @regnum
++ *
++ * Convenience helper for writing a register of an MMD on a given PHY
++ * using the PHY package base address. The base address is added to
++ * the addr_offset value.
++ *
++ * Same calling rules as for phy_write();
++ *
++ * NOTE: It's assumed that the entire PHY package is either C22 or C45.
++ */
++int phy_package_write_mmd(struct phy_device *phydev,
++ unsigned int addr_offset, int devad,
++ u32 regnum, u16 val)
++{
++ int addr = phy_package_address(phydev, addr_offset);
++ int ret;
++
++ if (addr < 0)
++ return addr;
++
++ if (regnum > (u16)~0 || devad > 32)
++ return -EINVAL;
++
++ phy_lock_mdio_bus(phydev);
++ ret = mmd_phy_write(phydev->mdio.bus, addr, phydev->is_c45, devad,
++ regnum, val);
++ phy_unlock_mdio_bus(phydev);
++
++ return ret;
++}
++EXPORT_SYMBOL(phy_package_write_mmd);
++
++/**
+ * phy_modify_changed - Function for modifying a PHY register
+ * @phydev: the phy_device struct
+ * @regnum: register number to modify
+--- a/include/linux/phy.h
++++ b/include/linux/phy.h
+@@ -1840,6 +1840,22 @@ static inline int __phy_package_write(st
+ return __mdiobus_write(phydev->mdio.bus, addr, regnum, val);
+ }
+
++int __phy_package_read_mmd(struct phy_device *phydev,
++ unsigned int addr_offset, int devad,
++ u32 regnum);
++
++int phy_package_read_mmd(struct phy_device *phydev,
++ unsigned int addr_offset, int devad,
++ u32 regnum);
++
++int __phy_package_write_mmd(struct phy_device *phydev,
++ unsigned int addr_offset, int devad,
++ u32 regnum, u16 val);
++
++int phy_package_write_mmd(struct phy_device *phydev,
++ unsigned int addr_offset, int devad,
++ u32 regnum, u16 val);
++
+ static inline bool __phy_package_set_once(struct phy_device *phydev,
+ unsigned int b)
+ {
mutex_init(&dev->lock);
INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
-@@ -2931,6 +2934,74 @@ static bool phy_drv_supports_irq(struct
+@@ -2934,6 +2937,74 @@ static bool phy_drv_supports_irq(struct
return phydrv->config_intr && phydrv->handle_interrupt;
}
/**
* fwnode_mdio_find_device - Given a fwnode, find the mdio_device
* @fwnode: pointer to the mdio_device's fwnode
-@@ -3109,6 +3180,11 @@ static int phy_probe(struct device *dev)
+@@ -3112,6 +3183,11 @@ static int phy_probe(struct device *dev)
/* Set the state to READY by default */
phydev->state = PHY_READY;
#include <linux/linkmode.h>
#include <linux/netlink.h>
#include <linux/mdio.h>
-@@ -602,6 +603,7 @@ struct macsec_ops;
+@@ -603,6 +604,7 @@ struct macsec_ops;
* @phy_num_led_triggers: Number of triggers in @phy_led_triggers
* @led_link_trigger: LED trigger for link up/down
* @last_triggered: last LED trigger for link speed
* @master_slave_set: User requested master/slave configuration
* @master_slave_get: Current master/slave advertisement
* @master_slave_state: Current master/slave configuration
-@@ -694,6 +696,7 @@ struct phy_device {
+@@ -695,6 +697,7 @@ struct phy_device {
struct phy_led_trigger *led_link_trigger;
#endif
/*
* Interrupt number for this PHY
-@@ -768,6 +771,19 @@ struct phy_tdr_config {
+@@ -769,6 +772,19 @@ struct phy_tdr_config {
#define PHY_PAIR_ALL -1
/**
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
-@@ -2934,11 +2934,18 @@ static bool phy_drv_supports_irq(struct
+@@ -2937,11 +2937,18 @@ static bool phy_drv_supports_irq(struct
return phydrv->config_intr && phydrv->handle_interrupt;
}
}
static int of_phy_led(struct phy_device *phydev,
-@@ -2955,12 +2962,14 @@ static int of_phy_led(struct phy_device
+@@ -2958,12 +2965,14 @@ static int of_phy_led(struct phy_device
return -ENOMEM;
cdev = &phyled->led_cdev;
init_data.fwnode = of_fwnode_handle(led);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
-@@ -774,15 +774,19 @@ struct phy_tdr_config {
+@@ -775,15 +775,19 @@ struct phy_tdr_config {
* struct phy_led: An LED driven by the PHY
*
* @list: List of LEDs
/**
* struct phy_driver - Driver structure for a particular PHY type
*
-@@ -997,6 +1001,15 @@ struct phy_driver {
+@@ -998,6 +1002,15 @@ struct phy_driver {
int (*get_sqi)(struct phy_device *dev);
/** @get_sqi_max: Get the maximum signal quality indication */
int (*get_sqi_max)(struct phy_device *dev);
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
-@@ -2948,6 +2948,22 @@ static int phy_led_set_brightness(struct
+@@ -2951,6 +2951,22 @@ static int phy_led_set_brightness(struct
return err;
}
static int of_phy_led(struct phy_device *phydev,
struct device_node *led)
{
-@@ -2970,6 +2986,8 @@ static int of_phy_led(struct phy_device
+@@ -2973,6 +2989,8 @@ static int of_phy_led(struct phy_device
if (phydev->drv->led_brightness_set)
cdev->brightness_set_blocking = phy_led_set_brightness;
init_data.fwnode = of_fwnode_handle(led);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
-@@ -1010,6 +1010,18 @@ struct phy_driver {
+@@ -1011,6 +1011,18 @@ struct phy_driver {
*/
int (*led_brightness_set)(struct phy_device *dev,
u8 index, enum led_brightness value);
tristate "MDIO Bus/PHY emulation with fixed speed/link PHYs"
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
-@@ -3210,7 +3210,8 @@ static int phy_probe(struct device *dev)
+@@ -3213,7 +3213,8 @@ static int phy_probe(struct device *dev)
/* Get the LEDs from the device tree, and instantiate standard
* LEDs for them.
*/
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
-@@ -2971,6 +2971,7 @@ static int of_phy_led(struct phy_device
+@@ -2974,6 +2974,7 @@ static int of_phy_led(struct phy_device
struct led_init_data init_data = {};
struct led_classdev *cdev;
struct phy_led *phyled;
int err;
phyled = devm_kzalloc(dev, sizeof(*phyled), GFP_KERNEL);
-@@ -2980,10 +2981,13 @@ static int of_phy_led(struct phy_device
+@@ -2983,10 +2984,13 @@ static int of_phy_led(struct phy_device
cdev = &phyled->led_cdev;
phyled->phydev = phydev;
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
-@@ -2964,6 +2964,15 @@ static int phy_led_blink_set(struct led_
+@@ -2967,6 +2967,15 @@ static int phy_led_blink_set(struct led_
return err;
}
static int of_phy_led(struct phy_device *phydev,
struct device_node *led)
{
-@@ -2997,7 +3006,7 @@ static int of_phy_led(struct phy_device
+@@ -3000,7 +3009,7 @@ static int of_phy_led(struct phy_device
init_data.fwnode = of_fwnode_handle(led);
init_data.devname_mandatory = true;
if (err)
return err;
-@@ -3026,6 +3035,7 @@ static int of_phy_leds(struct phy_device
+@@ -3029,6 +3038,7 @@ static int of_phy_leds(struct phy_device
err = of_phy_led(phydev, led);
if (err) {
of_node_put(led);
return err;
}
}
-@@ -3231,6 +3241,9 @@ static int phy_remove(struct device *dev
+@@ -3234,6 +3244,9 @@ static int phy_remove(struct device *dev
cancel_delayed_work_sync(&phydev->state_queue);
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
-@@ -2964,6 +2964,61 @@ static int phy_led_blink_set(struct led_
+@@ -2967,6 +2967,61 @@ static int phy_led_blink_set(struct led_
return err;
}
static void phy_leds_unregister(struct phy_device *phydev)
{
struct phy_led *phyled;
-@@ -3001,6 +3056,19 @@ static int of_phy_led(struct phy_device
+@@ -3004,6 +3059,19 @@ static int of_phy_led(struct phy_device
cdev->brightness_set_blocking = phy_led_set_brightness;
if (phydev->drv->led_blink_set)
cdev->blink_set = phy_led_blink_set;
init_data.fwnode = of_fwnode_handle(led);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
-@@ -1022,6 +1022,39 @@ struct phy_driver {
+@@ -1023,6 +1023,39 @@ struct phy_driver {
int (*led_blink_set)(struct phy_device *dev, u8 index,
unsigned long *delay_on,
unsigned long *delay_off);
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
-@@ -3034,6 +3034,7 @@ static int of_phy_led(struct phy_device
+@@ -3037,6 +3037,7 @@ static int of_phy_led(struct phy_device
struct device *dev = &phydev->mdio.dev;
struct led_init_data init_data = {};
struct led_classdev *cdev;
struct phy_led *phyled;
u32 index;
int err;
-@@ -3051,6 +3052,21 @@ static int of_phy_led(struct phy_device
+@@ -3054,6 +3055,21 @@ static int of_phy_led(struct phy_device
if (index > U8_MAX)
return -EINVAL;
cdev->brightness_set_blocking = phy_led_set_brightness;
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
-@@ -787,6 +787,15 @@ struct phy_led {
+@@ -788,6 +788,15 @@ struct phy_led {
#define to_phy_led(d) container_of(d, struct phy_led, led_cdev)
/**
* struct phy_driver - Driver structure for a particular PHY type
*
-@@ -1055,6 +1064,19 @@ struct phy_driver {
+@@ -1056,6 +1065,19 @@ struct phy_driver {
int (*led_hw_control_get)(struct phy_device *dev, u8 index,
unsigned long *rules);
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
-@@ -1753,6 +1753,9 @@ void phy_detach(struct phy_device *phyde
+@@ -1756,6 +1756,9 @@ void phy_detach(struct phy_device *phyde
struct module *ndev_owner = NULL;
struct mii_bus *bus;
sysfs_remove_link(&dev->dev.kobj, "phydev");
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
-@@ -896,6 +896,12 @@ struct phy_driver {
+@@ -897,6 +897,12 @@ struct phy_driver {
/** @handle_interrupt: Override default interrupt handling */
irqreturn_t (*handle_interrupt)(struct phy_device *phydev);