diff options
Diffstat (limited to 'target/linux/realtek/patches-5.10/800-net-mdio-support-hardware-assisted-indirect-access.patch')
-rw-r--r-- | target/linux/realtek/patches-5.10/800-net-mdio-support-hardware-assisted-indirect-access.patch | 840 |
1 files changed, 0 insertions, 840 deletions
diff --git a/target/linux/realtek/patches-5.10/800-net-mdio-support-hardware-assisted-indirect-access.patch b/target/linux/realtek/patches-5.10/800-net-mdio-support-hardware-assisted-indirect-access.patch deleted file mode 100644 index aca017c03a..0000000000 --- a/target/linux/realtek/patches-5.10/800-net-mdio-support-hardware-assisted-indirect-access.patch +++ /dev/null @@ -1,840 +0,0 @@ -From 5d84f16b0036b33487b94abef15ad3c224c81ee9 Mon Sep 17 00:00:00 2001 -From: Daniel Golle <daniel@makrotopia.org> -Date: Thu, 3 Feb 2022 16:38:50 +0000 -Subject: [PATCH] net: mdio: support hardware-assisted indirect access - -MDIO controllers found in Switch-SoCs can offload some MDIO operations -to the hardware: - * MMD register access via Clause-22 - Instead of using multiple operations to access MMD registers via - MII register MII_MMD_CTRL and MII_MMD_DATA some controllers - allow transparent access to MMD PHY registers. - - * paged MII register access - Some PHYs (namely RealTek and Vitesse) use vendor-defined MII - register 0x1f for paged access. Some MDIO host controllers support - transparent paged access when used with such PHYs. - - * add convenience accessors to fully support paged access also on - multi-PHY packages (like the embedded PHYs in RTL83xx): - phy_package_read_paged and phy_package_write_paged - phy_package_port_read and phy_package_port_write - phy_package_port_read_paged and phy_package_port_write_paged - -Signed-off-by: Daniel Golle <daniel@makrotopia.org> ---- - drivers/net/phy/mdio_bus.c | 335 ++++++++++++++++++++++++++++++++++++- - drivers/net/phy/phy-core.c | 66 +++++++- - include/linux/mdio.h | 59 +++++++ - include/linux/phy.h | 129 ++++++++++++++ - include/uapi/linux/mii.h | 1 + - 5 files changed, 580 insertions(+), 10 deletions(-) - ---- a/drivers/net/phy/mdio_bus.c -+++ b/drivers/net/phy/mdio_bus.c -@@ -739,6 +739,32 @@ out: - } - - /** -+ * __mdiobus_select_page - Unlocked version of the mdiobus_select_page function -+ * @bus: the mii_bus struct -+ * @addr: the phy address -+ * @page: register page to select -+ * -+ * Selects a MDIO bus register page. Caller must hold the mdio bus lock. -+ * -+ * NOTE: MUST NOT be called from interrupt context. -+ */ -+int __mdiobus_select_page(struct mii_bus *bus, int addr, u16 page) -+{ -+ lockdep_assert_held_once(&bus->mdio_lock); -+ -+ if (bus->selected_page[addr] == page) -+ return 0; -+ -+ bus->selected_page[addr] = page; -+ if (bus->read_paged) -+ return 0; -+ -+ return bus->write(bus, addr, MII_MAINPAGE, page); -+ -+} -+EXPORT_SYMBOL(__mdiobus_select_page); -+ -+/** - * __mdiobus_read - Unlocked version of the mdiobus_read function - * @bus: the mii_bus struct - * @addr: the phy address -@@ -754,7 +780,10 @@ int __mdiobus_read(struct mii_bus *bus, - - WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock)); - -- retval = bus->read(bus, addr, regnum); -+ if (bus->read_paged) -+ retval = bus->read_paged(bus, addr, bus->selected_page[addr], regnum); -+ else -+ retval = bus->read(bus, addr, regnum); - - trace_mdio_access(bus, 1, addr, regnum, retval, retval); - mdiobus_stats_acct(&bus->stats[addr], true, retval); -@@ -764,6 +793,40 @@ int __mdiobus_read(struct mii_bus *bus, - EXPORT_SYMBOL(__mdiobus_read); - - /** -+ * __mdiobus_read_paged - Unlocked version of the mdiobus_read_paged function -+ * @bus: the mii_bus struct -+ * @addr: the phy address -+ * @page: the register page to access -+ * @regnum: register number to read -+ * -+ * Read a MDIO bus register. Caller must hold the mdio bus lock. -+ * -+ * NOTE: MUST NOT be called from interrupt context. -+ */ -+int __mdiobus_read_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum) -+{ -+ int retval; -+ int oldpage; -+ -+ lockdep_assert_held_once(&bus->mdio_lock); -+ -+ if (bus->read_paged) { -+ retval = bus->read_paged(bus, addr, page, regnum); -+ } else { -+ oldpage = bus->selected_page[addr]; -+ __mdiobus_select_page(bus, addr, page); -+ retval = bus->read(bus, addr, regnum); -+ __mdiobus_select_page(bus, addr, oldpage); -+ } -+ -+ trace_mdio_access(bus, 1, addr, regnum, retval, retval); -+ mdiobus_stats_acct(&bus->stats[addr], true, retval); -+ -+ return retval; -+} -+EXPORT_SYMBOL(__mdiobus_read_paged); -+ -+/** - * __mdiobus_write - Unlocked version of the mdiobus_write function - * @bus: the mii_bus struct - * @addr: the phy address -@@ -780,7 +843,10 @@ int __mdiobus_write(struct mii_bus *bus, - - WARN_ON_ONCE(!mutex_is_locked(&bus->mdio_lock)); - -- err = bus->write(bus, addr, regnum, val); -+ if (bus->write_paged) -+ err = bus->write_paged(bus, addr, bus->selected_page[addr], regnum, val); -+ else -+ err = bus->write(bus, addr, regnum, val); - - trace_mdio_access(bus, 0, addr, regnum, val, err); - mdiobus_stats_acct(&bus->stats[addr], false, err); -@@ -790,6 +856,39 @@ int __mdiobus_write(struct mii_bus *bus, - EXPORT_SYMBOL(__mdiobus_write); - - /** -+ * __mdiobus_write_paged - Unlocked version of the mdiobus_write_paged function -+ * @bus: the mii_bus struct -+ * @addr: the phy address -+ * @page: the register page to access -+ * @regnum: register number to write -+ * @val: value to write to @regnum -+ * -+ * Write a MDIO bus register. Caller must hold the mdio bus lock. -+ * -+ * NOTE: MUST NOT be called from interrupt context. -+ */ -+int __mdiobus_write_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val) -+{ -+ int err, oldpage; -+ -+ lockdep_assert_held_once(&bus->mdio_lock); -+ -+ if (bus->write_paged) { -+ err = bus->write_paged(bus, addr, page, regnum, val); -+ } else { -+ oldpage = bus->selected_page[addr]; -+ __mdiobus_select_page(bus, addr, page); -+ err = bus->write(bus, addr, regnum, val); -+ __mdiobus_select_page(bus, addr, oldpage); -+ } -+ trace_mdio_access(bus, 0, addr, regnum, val, err); -+ mdiobus_stats_acct(&bus->stats[addr], false, err); -+ return err; -+} -+EXPORT_SYMBOL(__mdiobus_write_paged); -+ -+ -+/** - * __mdiobus_modify_changed - Unlocked version of the mdiobus_modify function - * @bus: the mii_bus struct - * @addr: the phy address -@@ -822,6 +921,43 @@ int __mdiobus_modify_changed(struct mii_ - EXPORT_SYMBOL_GPL(__mdiobus_modify_changed); - - /** -+ * __mdiobus_modify_changed_paged - Unlocked version of the mdiobus_modify_paged function -+ * @bus: the mii_bus struct -+ * @addr: the phy address -+ * @regnum: register number to modify -+ * @mask: bit mask of bits to clear -+ * @set: bit mask of bits to set -+ * -+ * Read, modify, and if any change, write the register value back to the -+ * device. Any error returns a negative number. -+ * -+ * NOTE: MUST NOT be called from interrupt context. -+ */ -+int __mdiobus_modify_changed_paged(struct mii_bus *bus, int addr, u32 regnum, u16 page, -+ u16 mask, u16 set) -+{ -+ int new, ret, oldpage; -+ -+ oldpage = bus->selected_page[addr]; -+ __mdiobus_select_page(bus, addr, page); -+ -+ ret = __mdiobus_read_paged(bus, addr, page, regnum); -+ if (ret < 0) -+ return ret; -+ -+ new = (ret & ~mask) | set; -+ if (new == ret) -+ return 0; -+ -+ ret = __mdiobus_write_paged(bus, addr, page, regnum, new); -+ -+ __mdiobus_select_page(bus, addr, oldpage); -+ -+ return ret < 0 ? ret : 1; -+} -+EXPORT_SYMBOL_GPL(__mdiobus_modify_changed_paged); -+ -+/** - * mdiobus_read_nested - Nested version of the mdiobus_read function - * @bus: the mii_bus struct - * @addr: the phy address -@@ -847,6 +983,79 @@ int mdiobus_read_nested(struct mii_bus * - EXPORT_SYMBOL(mdiobus_read_nested); - - /** -+ * mdiobus_select_page_nested - Nested version of the mdiobus_select_page function -+ * @bus: the mii_bus struct -+ * @addr: the phy address -+ * @page: register page to access -+ * -+ * In case of nested MDIO bus access avoid lockdep false positives by -+ * using mutex_lock_nested(). -+ * -+ * NOTE: MUST NOT be called from interrupt context, -+ * because the bus read/write functions may wait for an interrupt -+ * to conclude the operation. -+ */ -+int mdiobus_select_page_nested(struct mii_bus *bus, int addr, u16 page) -+{ -+ int retval; -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ retval = __mdiobus_select_page(bus, addr, page); -+ mutex_unlock(&bus->mdio_lock); -+ -+ return retval; -+} -+EXPORT_SYMBOL(mdiobus_select_page_nested); -+ -+/** -+ * mdiobus_read_paged_nested - Nested version of the mdiobus_read_paged function -+ * @bus: the mii_bus struct -+ * @addr: the phy address -+ * @page: register page to access -+ * @regnum: register number to read -+ * -+ * In case of nested MDIO bus access avoid lockdep false positives by -+ * using mutex_lock_nested(). -+ * -+ * NOTE: MUST NOT be called from interrupt context, -+ * because the bus read/write functions may wait for an interrupt -+ * to conclude the operation. -+ */ -+int mdiobus_read_paged_nested(struct mii_bus *bus, int addr, u16 page, u32 regnum) -+{ -+ int retval; -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ retval = __mdiobus_read_paged(bus, addr, page, regnum); -+ mutex_unlock(&bus->mdio_lock); -+ -+ return retval; -+} -+EXPORT_SYMBOL(mdiobus_read_paged_nested); -+ -+/** -+ * mdiobus_select_page - Convenience function for setting the MII register page -+ * @bus: the mii_bus struct -+ * @addr: the phy address -+ * @page: the register page to set -+ * -+ * NOTE: MUST NOT be called from interrupt context, -+ * because the bus read/write functions may wait for an interrupt -+ * to conclude the operation. -+ */ -+int mdiobus_select_page(struct mii_bus *bus, int addr, u16 page) -+{ -+ int retval; -+ -+ mutex_lock(&bus->mdio_lock); -+ retval = __mdiobus_select_page(bus, addr, page); -+ mutex_unlock(&bus->mdio_lock); -+ -+ return retval; -+} -+EXPORT_SYMBOL(mdiobus_select_page); -+ -+/** - * mdiobus_read - Convenience function for reading a given MII mgmt register - * @bus: the mii_bus struct - * @addr: the phy address -@@ -869,6 +1078,29 @@ int mdiobus_read(struct mii_bus *bus, in - EXPORT_SYMBOL(mdiobus_read); - - /** -+ * mdiobus_read_paged - Convenience function for reading a given paged MII mgmt register -+ * @bus: the mii_bus struct -+ * @addr: the phy address -+ * @page: register page to access -+ * @regnum: register number to read -+ * -+ * NOTE: MUST NOT be called from interrupt context, -+ * because the bus read/write functions may wait for an interrupt -+ * to conclude the operation. -+ */ -+int mdiobus_read_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum) -+{ -+ int retval; -+ -+ mutex_lock(&bus->mdio_lock); -+ retval = __mdiobus_read_paged(bus, addr, page, regnum); -+ mutex_unlock(&bus->mdio_lock); -+ -+ return retval; -+} -+EXPORT_SYMBOL(mdiobus_read_paged); -+ -+/** - * mdiobus_write_nested - Nested version of the mdiobus_write function - * @bus: the mii_bus struct - * @addr: the phy address -@@ -895,6 +1127,33 @@ int mdiobus_write_nested(struct mii_bus - EXPORT_SYMBOL(mdiobus_write_nested); - - /** -+ * mdiobus_write_paged_nested - Nested version of the mdiobus_write_aged function -+ * @bus: the mii_bus struct -+ * @addr: the phy address -+ * @page: the register page to access -+ * @regnum: register number to write -+ * @val: value to write to @regnum -+ * -+ * In case of nested MDIO bus access avoid lockdep false positives by -+ * using mutex_lock_nested(). -+ * -+ * NOTE: MUST NOT be called from interrupt context, -+ * because the bus read/write functions may wait for an interrupt -+ * to conclude the operation. -+ */ -+int mdiobus_write_paged_nested(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val) -+{ -+ int err; -+ -+ mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); -+ err = __mdiobus_write_paged(bus, addr, page, regnum, val); -+ mutex_unlock(&bus->mdio_lock); -+ -+ return err; -+} -+EXPORT_SYMBOL(mdiobus_write_paged_nested); -+ -+/** - * mdiobus_write - Convenience function for writing a given MII mgmt register - * @bus: the mii_bus struct - * @addr: the phy address -@@ -918,6 +1177,30 @@ int mdiobus_write(struct mii_bus *bus, i - EXPORT_SYMBOL(mdiobus_write); - - /** -+ * mdiobus_write_paged - Convenience function for writing a given paged MII mgmt register -+ * @bus: the mii_bus struct -+ * @addr: the phy address -+ * @page: the register page to access -+ * @regnum: register number to write -+ * @val: value to write to @regnum -+ * -+ * NOTE: MUST NOT be called from interrupt context, -+ * because the bus read/write functions may wait for an interrupt -+ * to conclude the operation. -+ */ -+int mdiobus_write_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val) -+{ -+ int err; -+ -+ mutex_lock(&bus->mdio_lock); -+ err = __mdiobus_write_paged(bus, addr, page, regnum, val); -+ mutex_unlock(&bus->mdio_lock); -+ -+ return err; -+} -+EXPORT_SYMBOL(mdiobus_write_paged); -+ -+/** - * mdiobus_modify - Convenience function for modifying a given mdio device - * register - * @bus: the mii_bus struct -@@ -939,6 +1222,51 @@ int mdiobus_modify(struct mii_bus *bus, - EXPORT_SYMBOL_GPL(mdiobus_modify); - - /** -+ * mdiobus_modify_paged - Convenience function for modifying a given mdio device -+ * register -+ * @bus: the mii_bus struct -+ * @addr: the phy address -+ * @page: the register page to access -+ * @regnum: register number to write -+ * @mask: bit mask of bits to clear -+ * @set: bit mask of bits to set -+ */ -+int mdiobus_modify_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 mask, u16 set) -+{ -+ int err; -+ -+ mutex_lock(&bus->mdio_lock); -+ err = __mdiobus_modify_changed_paged(bus, addr, page, regnum, mask, set); -+ mutex_unlock(&bus->mdio_lock); -+ -+ return err < 0 ? err : 0; -+} -+EXPORT_SYMBOL_GPL(mdiobus_modify_paged); -+ -+/** -+ * mdiobus_modify_changed_paged - Convenience function for modifying a given paged -+ * mdio device register and returning if it changed -+ * @bus: the mii_bus struct -+ * @addr: the phy address -+ * @page: the register page to access -+ * @regnum: register number to write -+ * @mask: bit mask of bits to clear -+ * @set: bit mask of bits to set -+ */ -+int mdiobus_modify_changed_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, -+ u16 mask, u16 set) -+{ -+ int err; -+ -+ mutex_lock(&bus->mdio_lock); -+ err = __mdiobus_modify_changed_paged(bus, addr, page, regnum, mask, set); -+ mutex_unlock(&bus->mdio_lock); -+ -+ return err; -+} -+EXPORT_SYMBOL_GPL(mdiobus_modify_changed_paged); -+ -+/** - * mdio_bus_match - determine if given MDIO driver supports the given - * MDIO device - * @dev: target MDIO device ---- a/drivers/net/phy/phy-core.c -+++ b/drivers/net/phy/phy-core.c -@@ -481,10 +481,16 @@ int __phy_read_mmd(struct phy_device *ph - 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); -+ if (bus->access_capabilities & MDIOBUS_ACCESS_C22_MMD) { -+ val = __mdiobus_c22_mmd_read(phydev->mdio.bus, -+ phydev->mdio.addr, -+ devad, regnum); -+ } else { -+ 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; - } -@@ -537,12 +543,18 @@ int __phy_write_mmd(struct phy_device *p - struct mii_bus *bus = phydev->mdio.bus; - int phy_addr = phydev->mdio.addr; - -- mmd_phy_indirect(bus, phy_addr, devad, regnum); -+ if (bus->access_capabilities & MDIOBUS_ACCESS_C22_MMD) { -+ ret = __mdiobus_c22_mmd_write(phydev->mdio.bus, -+ phydev->mdio.addr, -+ devad, regnum, val); -+ } else { -+ 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); -+ /* Write the data into MMD's selected register */ -+ __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val); - -- ret = 0; -+ ret = 0; -+ } - } - return ret; - } -@@ -748,6 +760,13 @@ EXPORT_SYMBOL_GPL(phy_modify_mmd); - - static int __phy_read_page(struct phy_device *phydev) - { -+ if (phydev->drv && phydev->drv->flags & PHY_HAS_REALTEK_PAGES) { -+ struct mii_bus *bus = phydev->mdio.bus; -+ int phy_addr = phydev->mdio.addr; -+ -+ return bus->selected_page[phy_addr]; -+ } -+ - if (WARN_ONCE(!phydev->drv->read_page, "read_page callback not available, PHY driver not loaded?\n")) - return -EOPNOTSUPP; - -@@ -756,6 +775,13 @@ static int __phy_read_page(struct phy_de - - static int __phy_write_page(struct phy_device *phydev, int page) - { -+ if (phydev->drv && phydev->drv->flags & PHY_HAS_REALTEK_PAGES) { -+ struct mii_bus *bus = phydev->mdio.bus; -+ int phy_addr = phydev->mdio.addr; -+ -+ return __mdiobus_select_page(bus, phy_addr, page); -+ } -+ - if (WARN_ONCE(!phydev->drv->write_page, "write_page callback not available, PHY driver not loaded?\n")) - return -EOPNOTSUPP; - -@@ -857,6 +883,18 @@ int phy_read_paged(struct phy_device *ph - { - int ret = 0, oldpage; - -+ if (phydev->drv && phydev->drv->flags & PHY_HAS_REALTEK_PAGES) { -+ struct mii_bus *bus = phydev->mdio.bus; -+ int phy_addr = phydev->mdio.addr; -+ -+ if (bus->read_paged) { -+ phy_lock_mdio_bus(phydev); -+ ret = bus->read_paged(bus, phy_addr, page, regnum); -+ phy_unlock_mdio_bus(phydev); -+ return ret; -+ } -+ } -+ - oldpage = phy_select_page(phydev, page); - if (oldpage >= 0) - ret = __phy_read(phydev, regnum); -@@ -878,6 +916,18 @@ int phy_write_paged(struct phy_device *p - { - int ret = 0, oldpage; - -+ if (phydev->drv && phydev->drv->flags & PHY_HAS_REALTEK_PAGES) { -+ struct mii_bus *bus = phydev->mdio.bus; -+ int phy_addr = phydev->mdio.addr; -+ -+ if (bus->write_paged) { -+ phy_lock_mdio_bus(phydev); -+ ret = bus->write_paged(bus, phy_addr, page, regnum, val); -+ phy_unlock_mdio_bus(phydev); -+ return ret; -+ } -+ } -+ - oldpage = phy_select_page(phydev, page); - if (oldpage >= 0) - ret = __phy_write(phydev, regnum, val); ---- a/include/linux/mdio.h -+++ b/include/linux/mdio.h -@@ -14,6 +14,7 @@ - * IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips. - */ - #define MII_ADDR_C45 (1<<30) -+#define MII_ADDR_C22_MMD (1<<29) - #define MII_DEVADDR_C45_SHIFT 16 - #define MII_DEVADDR_C45_MASK GENMASK(20, 16) - #define MII_REGADDR_C45_MASK GENMASK(15, 0) -@@ -327,11 +328,19 @@ static inline void mii_10gbt_stat_mod_li - advertising, lpa & MDIO_AN_10GBT_STAT_LP10G); - } - -+int __mdiobus_select_page(struct mii_bus *bus, int addr, u16 page); - int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum); - int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val); - int __mdiobus_modify_changed(struct mii_bus *bus, int addr, u32 regnum, - u16 mask, u16 set); - -+int __mdiobus_read_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum); -+int __mdiobus_write_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val); -+int __mdiobus_modify_changed_paged(struct mii_bus *bus, int addr, u32 regnum, u16 page, -+ u16 mask, u16 set); -+ -+int mdiobus_select_page(struct mii_bus *bus, int addr, u16 page); -+int mdiobus_select_page_nested(struct mii_bus *bus, int addr, u16 page); - int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum); - int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum); - int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val); -@@ -339,11 +348,51 @@ int mdiobus_write_nested(struct mii_bus - int mdiobus_modify(struct mii_bus *bus, int addr, u32 regnum, u16 mask, - u16 set); - -+int mdiobus_read_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum); -+int mdiobus_read_nested_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum); -+int mdiobus_write_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val); -+int mdiobus_write_nested_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 val); -+int mdiobus_modify_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, u16 mask, -+ u16 set); -+int mdiobus_modify_changed_paged(struct mii_bus *bus, int addr, u16 page, u32 regnum, -+ u16 mask, u16 set); -+ -+static inline int mdiodev_read_paged(struct mdio_device *mdiodev, u16 page, -+ u32 regnum) -+{ -+ return mdiobus_read_paged(mdiodev->bus, mdiodev->addr, page, regnum); -+} -+ -+static inline int mdiodev_write_paged(struct mdio_device *mdiodev, u16 page, -+ u32 regnum, u16 val) -+{ -+ return mdiobus_write_paged(mdiodev->bus, mdiodev->addr, page, regnum, val); -+} -+ -+static inline int mdiodev_modify_paged(struct mdio_device *mdiodev, u16 page, -+ u32 regnum, u16 mask, u16 set) -+{ -+ return mdiobus_modify_paged(mdiodev->bus, mdiodev->addr, page, regnum, -+ mask, set); -+} -+ -+static inline int mdiodev_modify_changed_paged(struct mdio_device *mdiodev, u16 page, -+ u32 regnum, u16 mask, u16 set) -+{ -+ return mdiobus_modify_changed_paged(mdiodev->bus, mdiodev->addr, page, regnum, -+ mask, set); -+} -+ - static inline u32 mdiobus_c45_addr(int devad, u16 regnum) - { - return MII_ADDR_C45 | devad << MII_DEVADDR_C45_SHIFT | regnum; - } - -+static inline u32 mdiobus_c22_mmd_addr(int devad, u16 regnum) -+{ -+ return MII_ADDR_C22_MMD | devad << MII_DEVADDR_C45_SHIFT | regnum; -+} -+ - static inline u16 mdiobus_c45_regad(u32 regnum) - { - return FIELD_GET(MII_REGADDR_C45_MASK, regnum); -@@ -367,6 +416,19 @@ static inline int __mdiobus_c45_write(st - val); - } - -+static inline int __mdiobus_c22_mmd_read(struct mii_bus *bus, int prtad, -+ int devad, u16 regnum) -+{ -+ return __mdiobus_read(bus, prtad, mdiobus_c22_mmd_addr(devad, regnum)); -+} -+ -+static inline int __mdiobus_c22_mmd_write(struct mii_bus *bus, int prtad, -+ int devad, u16 regnum, u16 val) -+{ -+ return __mdiobus_write(bus, prtad, mdiobus_c22_mmd_addr(devad, regnum), -+ val); -+} -+ - static inline int mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad, - u16 regnum) - { ---- a/include/linux/phy.h -+++ b/include/linux/phy.h -@@ -80,6 +80,7 @@ extern const int phy_10gbit_features_arr - #define PHY_IS_INTERNAL 0x00000001 - #define PHY_RST_AFTER_CLK_EN 0x00000002 - #define PHY_POLL_CABLE_TEST 0x00000004 -+#define PHY_HAS_REALTEK_PAGES 0x00000010 - #define MDIO_DEVICE_IS_PHY 0x80000000 - - /** -@@ -374,6 +375,22 @@ struct mii_bus { - - /** @shared: shared state across different PHYs */ - struct phy_package_shared *shared[PHY_MAX_ADDR]; -+ -+ /** @access_capabilities: hardware-assisted access capabilties */ -+ enum { -+ MDIOBUS_ACCESS_SOFTWARE_ONLY = 0, -+ MDIOBUS_ACCESS_C22_MMD = 0x1, -+ } access_capabilities; -+ -+ /** @read: Perform a read transfer on the bus, offloading page access */ -+ int (*read_paged)(struct mii_bus *bus, int addr, u16 page, int regnum); -+ /** @write: Perform a write transfer on the bus, offloading page access */ -+ int (*write_paged)(struct mii_bus *bus, int addr, u16 page, int regnum, u16 val); -+ /** currently selected page when page access is offloaded -+ * array should be PHY_MAX_ADDR+1size, but current design of the MDIO driver -+ * uses port addresses as phy addresses and they are up to 6 bit. -+ */ -+ u16 selected_page[64]; - }; - #define to_mii_bus(d) container_of(d, struct mii_bus, dev) - -@@ -1651,6 +1668,66 @@ static inline int __phy_package_read(str - return __mdiobus_read(phydev->mdio.bus, shared->addr, regnum); - } - -+static inline int phy_package_read_port(struct phy_device *phydev, u16 port, u32 regnum) -+{ -+ struct phy_package_shared *shared = phydev->shared; -+ -+ if (!shared) -+ return -EIO; -+ -+ return mdiobus_read(phydev->mdio.bus, shared->addr + port, regnum); -+} -+ -+static inline int __phy_package_read_port(struct phy_device *phydev, u16 port, u32 regnum) -+{ -+ struct phy_package_shared *shared = phydev->shared; -+ -+ if (!shared) -+ return -EIO; -+ -+ return __mdiobus_read(phydev->mdio.bus, shared->addr + port, regnum); -+} -+ -+static inline int phy_package_read_paged(struct phy_device *phydev, u16 page, u32 regnum) -+{ -+ struct phy_package_shared *shared = phydev->shared; -+ -+ if (!shared) -+ return -EIO; -+ -+ return mdiobus_read_paged(phydev->mdio.bus, shared->addr, page, regnum); -+} -+ -+static inline int __phy_package_read_paged(struct phy_device *phydev, u16 page, u32 regnum) -+{ -+ struct phy_package_shared *shared = phydev->shared; -+ -+ if (!shared) -+ return -EIO; -+ -+ return __mdiobus_read_paged(phydev->mdio.bus, shared->addr, page, regnum); -+} -+ -+static inline int phy_package_port_read_paged(struct phy_device *phydev, u16 port, u16 page, u32 regnum) -+{ -+ struct phy_package_shared *shared = phydev->shared; -+ -+ if (!shared) -+ return -EIO; -+ -+ return mdiobus_read_paged(phydev->mdio.bus, shared->addr + port, page, regnum); -+} -+ -+static inline int __phy_package_port_read_paged(struct phy_device *phydev, u16 port, u16 page, u32 regnum) -+{ -+ struct phy_package_shared *shared = phydev->shared; -+ -+ if (!shared) -+ return -EIO; -+ -+ return __mdiobus_read_paged(phydev->mdio.bus, shared->addr + port, page, regnum); -+} -+ - static inline int phy_package_write(struct phy_device *phydev, - u32 regnum, u16 val) - { -@@ -1673,6 +1750,72 @@ static inline int __phy_package_write(st - return __mdiobus_write(phydev->mdio.bus, shared->addr, regnum, val); - } - -+static inline int phy_package_port_write(struct phy_device *phydev, -+ u16 port, u32 regnum, u16 val) -+{ -+ struct phy_package_shared *shared = phydev->shared; -+ -+ if (!shared) -+ return -EIO; -+ -+ return mdiobus_write(phydev->mdio.bus, shared->addr + port, regnum, val); -+} -+ -+static inline int __phy_package_port_write(struct phy_device *phydev, -+ u16 port, u32 regnum, u16 val) -+{ -+ struct phy_package_shared *shared = phydev->shared; -+ -+ if (!shared) -+ return -EIO; -+ -+ return __mdiobus_write(phydev->mdio.bus, shared->addr + port, regnum, val); -+} -+ -+static inline int phy_package_port_write_paged(struct phy_device *phydev, -+ u16 port, u16 page, u32 regnum, u16 val) -+{ -+ struct phy_package_shared *shared = phydev->shared; -+ -+ if (!shared) -+ return -EIO; -+ -+ return mdiobus_write_paged(phydev->mdio.bus, shared->addr + port, page, regnum, val); -+} -+ -+static inline int __phy_package_port_write_paged(struct phy_device *phydev, -+ u16 port, u16 page, u32 regnum, u16 val) -+{ -+ struct phy_package_shared *shared = phydev->shared; -+ -+ if (!shared) -+ return -EIO; -+ -+ return __mdiobus_write_paged(phydev->mdio.bus, shared->addr + port, page, regnum, val); -+} -+ -+static inline int phy_package_write_paged(struct phy_device *phydev, -+ u16 page, u32 regnum, u16 val) -+{ -+ struct phy_package_shared *shared = phydev->shared; -+ -+ if (!shared) -+ return -EIO; -+ -+ return mdiobus_write_paged(phydev->mdio.bus, shared->addr, page, regnum, val); -+} -+ -+static inline int __phy_package_write_paged(struct phy_device *phydev, -+ u16 page, u32 regnum, u16 val) -+{ -+ struct phy_package_shared *shared = phydev->shared; -+ -+ if (!shared) -+ return -EIO; -+ -+ return __mdiobus_write_paged(phydev->mdio.bus, shared->addr, page, regnum, val); -+} -+ - static inline bool __phy_package_set_once(struct phy_device *phydev, - unsigned int b) - { ---- a/include/uapi/linux/mii.h -+++ b/include/uapi/linux/mii.h -@@ -36,6 +36,7 @@ - #define MII_RESV2 0x1a /* Reserved... */ - #define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ - #define MII_NCONFIG 0x1c /* Network interface config */ -+#define MII_MAINPAGE 0x1f /* Page register */ - - /* Basic mode control register. */ - #define BMCR_RESV 0x003f /* Unused... */ |