generic: 6.1: backport PHY package MMD patch
authorChristian Marangi <ansuelsmth@gmail.com>
Thu, 1 Feb 2024 15:26:32 +0000 (16:26 +0100)
committerChristian Marangi <ansuelsmth@gmail.com>
Thu, 1 Feb 2024 20:28:46 +0000 (21:28 +0100)
Backport PHY package MMD patch merged upstream that add support for
writing MMD regs for the PHY package and support for writing to PHY
package at an offset.

All affected patches automatically refreshed.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
13 files changed:
target/linux/generic/backport-6.1/714-v6.8-01-net-phy-make-addr-type-u8-in-phy_package_shared-stru.patch [new file with mode: 0644]
target/linux/generic/backport-6.1/714-v6.8-02-net-phy-extend-PHY-package-API-to-support-multiple-g.patch [new file with mode: 0644]
target/linux/generic/backport-6.1/714-v6.8-03-net-phy-restructure-__phy_write-read_mmd-to-helper-a.patch [new file with mode: 0644]
target/linux/generic/backport-6.1/714-v6.8-04-net-phy-add-support-for-PHY-package-MMD-read-write.patch [new file with mode: 0644]
target/linux/generic/backport-6.1/801-v6.4-05-net-phy-Add-a-binding-for-PHY-LEDs.patch
target/linux/generic/backport-6.1/801-v6.4-06-net-phy-phy_device-Call-into-the-PHY-driver-to-set-L.patch
target/linux/generic/backport-6.1/801-v6.4-08-net-phy-phy_device-Call-into-the-PHY-driver-to-set-L.patch
target/linux/generic/backport-6.1/820-v6.4-net-phy-fix-circular-LEDS_CLASS-dependencies.patch
target/linux/generic/backport-6.1/821-v6.4-net-phy-Fix-reading-LED-reg-property.patch
target/linux/generic/backport-6.1/822-v6.4-net-phy-Manual-remove-LEDs-to-ensure-correct-orderin.patch
target/linux/generic/backport-6.1/826-v6.6-02-net-phy-phy_device-Call-into-the-PHY-driver-to-set-L.patch
target/linux/generic/backport-6.1/835-v6.9-net-phy-add-support-for-PHY-LEDs-polarity-modes.patch
target/linux/generic/pending-6.1/703-phy-add-detach-callback-to-struct-phy_driver.patch

diff --git a/target/linux/generic/backport-6.1/714-v6.8-01-net-phy-make-addr-type-u8-in-phy_package_shared-stru.patch b/target/linux/generic/backport-6.1/714-v6.8-01-net-phy-make-addr-type-u8-in-phy_package_shared-stru.patch
new file mode 100644 (file)
index 0000000..6decc34
--- /dev/null
@@ -0,0 +1,28 @@
+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;
diff --git a/target/linux/generic/backport-6.1/714-v6.8-02-net-phy-extend-PHY-package-API-to-support-multiple-g.patch b/target/linux/generic/backport-6.1/714-v6.8-02-net-phy-extend-PHY-package-API-to-support-multiple-g.patch
new file mode 100644 (file)
index 0000000..0cf01df
--- /dev/null
@@ -0,0 +1,341 @@
+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,
diff --git a/target/linux/generic/backport-6.1/714-v6.8-03-net-phy-restructure-__phy_write-read_mmd-to-helper-a.patch b/target/linux/generic/backport-6.1/714-v6.8-03-net-phy-restructure-__phy_write-read_mmd-to-helper-a.patch
new file mode 100644 (file)
index 0000000..4a17d46
--- /dev/null
@@ -0,0 +1,116 @@
+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);
diff --git a/target/linux/generic/backport-6.1/714-v6.8-04-net-phy-add-support-for-PHY-package-MMD-read-write.patch b/target/linux/generic/backport-6.1/714-v6.8-04-net-phy-add-support-for-PHY-package-MMD-read-write.patch
new file mode 100644 (file)
index 0000000..a628a37
--- /dev/null
@@ -0,0 +1,196 @@
+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)
+ {
index d33fc72dd1ea9a6b95c2d0f7bfeec2650def80bd..c958362e96d68ed9d77c893b9d0c5bd1a16ada4d 100644 (file)
@@ -56,7 +56,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
  
        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;
  }
  
@@ -131,7 +131,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
  /**
   * 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;
  
@@ -153,7 +153,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
  #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
@@ -161,7 +161,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
   * @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
@@ -169,7 +169,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
  
        /*
         * 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
  
  /**
index c1678ce2ea3a241c99702ffb59efcacc11df7521..3c2477a63a13c697f8f1927771f25acdf06ed353 100644 (file)
@@ -20,7 +20,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
 
 --- 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;
  }
  
@@ -41,7 +41,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
  }
  
  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;
@@ -59,7 +59,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
        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
@@ -79,7 +79,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
  /**
   * 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);
index f234b2bff13018b8be2d898f4cc9a182d87e6515..35d83d8a6a507d1469922e5905b8b0253a8cd429 100644 (file)
@@ -18,7 +18,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
 
 --- 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;
  }
  
@@ -41,7 +41,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
  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;
@@ -52,7 +52,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
        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);
index 1de086417b6112570333620068338ac7e87d1666..66dbcb8a904c95969882486b502e1559703be39b 100644 (file)
@@ -53,7 +53,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
        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.
         */
index d6081d0e637c3a107fa932b355d9e4626aa29fba..3710cfade2032857e14602b8616343c9ff7c489e 100644 (file)
@@ -18,7 +18,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 
 --- 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;
@@ -26,7 +26,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
        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;
  
index 8f076be640c9c4d07db6de57b84fca04cb880c45..80ac785cdb48f843383e773687973310313fe4f0 100644 (file)
@@ -22,7 +22,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
 
 --- 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;
  }
  
@@ -38,7 +38,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
  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;
  
@@ -47,7 +47,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
        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);
@@ -55,7 +55,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
                        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);
  
index daa970884e62b7e84b436837213d19c7be00b4b6..0bf1e03c49e990e5bdd55aa8c8911706cbc1d7dd 100644 (file)
@@ -23,7 +23,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 
 --- 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;
  }
  
@@ -85,7 +85,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  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;
@@ -107,7 +107,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
        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);
index 604b3db270214a6f67fad37ee932dd4860c8e75c..97fbd2bfc5bb4f34076e2207492b35d591c7c82f 100644 (file)
@@ -28,7 +28,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
 
 --- 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;
@@ -36,7 +36,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
        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;
  
@@ -60,7 +60,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
                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)
  
@@ -76,7 +76,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  /**
   * 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);
  
index aa852e7fec936f76b78811a1e670089e2e22f77b..b658d5205e8d2b29d15c770ac26291742f22955c 100644 (file)
@@ -11,7 +11,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
 
 --- 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;
  
@@ -23,7 +23,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
                        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);