mirror of
https://github.com/openwrt/openwrt.git
synced 2025-03-13 15:56:55 +00:00
realtek: switch to use generic MDIO accessor functions
Instead of directly calling SoC-specific functions in order to access (paged) MII registers or MMD registers, create infrastructure to allow using the generic phy_*, phy_*_paged and phy_*_mmd functions. Signed-off-by: Daniel Golle <daniel@makrotopia.org>
This commit is contained in:
parent
af93bf6129
commit
b53202a8c3
@ -292,11 +292,14 @@ static int __init rtl83xx_mdio_probe(struct rtl838x_switch_priv *priv)
|
||||
*/
|
||||
bus->read = priv->mii_bus->read;
|
||||
bus->write = priv->mii_bus->write;
|
||||
bus->read_paged = priv->mii_bus->read_paged;
|
||||
bus->write_paged = priv->mii_bus->write_paged;
|
||||
snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", bus->name, dev->id);
|
||||
|
||||
bus->parent = dev;
|
||||
priv->ds->slave_mii_bus = bus;
|
||||
priv->ds->slave_mii_bus->priv = priv;
|
||||
priv->ds->slave_mii_bus->priv = priv->mii_bus->priv;
|
||||
priv->ds->slave_mii_bus->access_capabilities = priv->mii_bus->access_capabilities;
|
||||
|
||||
ret = mdiobus_register(priv->ds->slave_mii_bus);
|
||||
if (ret && mii_np) {
|
||||
|
@ -1623,7 +1623,7 @@ static int rtl838x_set_link_ksettings(struct net_device *ndev,
|
||||
return phylink_ethtool_ksettings_set(priv->phylink, cmd);
|
||||
}
|
||||
|
||||
static int rtl838x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
static int rtl838x_mdio_read_paged(struct mii_bus *bus, int mii_id, u16 page, int regnum)
|
||||
{
|
||||
u32 val;
|
||||
int err;
|
||||
@ -1631,13 +1631,29 @@ static int rtl838x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
|
||||
if (mii_id >= 24 && mii_id <= 27 && priv->id == 0x8380)
|
||||
return rtl838x_read_sds_phy(mii_id, regnum);
|
||||
err = rtl838x_read_phy(mii_id, 0, regnum, &val);
|
||||
|
||||
if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
|
||||
err = rtl838x_read_mmd_phy(mii_id,
|
||||
mdiobus_c45_devad(regnum),
|
||||
regnum, &val);
|
||||
pr_debug("MMD: %d dev %x register %x read %x, err %d\n", mii_id,
|
||||
mdiobus_c45_devad(regnum), mdiobus_c45_regad(regnum),
|
||||
val, err);
|
||||
} else {
|
||||
pr_debug("PHY: %d register %x read %x, err %d\n", mii_id, regnum, val, err);
|
||||
err = rtl838x_read_phy(mii_id, page, regnum, &val);
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
return val;
|
||||
}
|
||||
|
||||
static int rtl839x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
static int rtl838x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
{
|
||||
return rtl838x_mdio_read_paged(bus, mii_id, 0, regnum);
|
||||
}
|
||||
|
||||
static int rtl839x_mdio_read_paged(struct mii_bus *bus, int mii_id, u16 page, int regnum)
|
||||
{
|
||||
u32 val;
|
||||
int err;
|
||||
@ -1646,22 +1662,37 @@ static int rtl839x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
if (mii_id >= 48 && mii_id <= 49 && priv->id == 0x8393)
|
||||
return rtl839x_read_sds_phy(mii_id, regnum);
|
||||
|
||||
err = rtl839x_read_phy(mii_id, 0, regnum, &val);
|
||||
if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
|
||||
err = rtl839x_read_mmd_phy(mii_id,
|
||||
mdiobus_c45_devad(regnum),
|
||||
regnum, &val);
|
||||
pr_debug("MMD: %d dev %x register %x read %x, err %d\n", mii_id,
|
||||
mdiobus_c45_devad(regnum), mdiobus_c45_regad(regnum),
|
||||
val, err);
|
||||
} else {
|
||||
err = rtl839x_read_phy(mii_id, page, regnum, &val);
|
||||
pr_debug("PHY: %d register %x read %x, err %d\n", mii_id, regnum, val, err);
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
return val;
|
||||
}
|
||||
|
||||
static int rtl930x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
static int rtl839x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
{
|
||||
return rtl839x_mdio_read_paged(bus, mii_id, 0, regnum);
|
||||
}
|
||||
|
||||
static int rtl930x_mdio_read_paged(struct mii_bus *bus, int mii_id, u16 page, int regnum)
|
||||
{
|
||||
u32 val;
|
||||
int err;
|
||||
struct rtl838x_eth_priv *priv = bus->priv;
|
||||
|
||||
if (priv->phy_is_internal[mii_id])
|
||||
return rtl930x_read_sds_phy(priv->sds_id[mii_id], 0, regnum);
|
||||
return rtl930x_read_sds_phy(priv->sds_id[mii_id], page, regnum);
|
||||
|
||||
if (regnum & MII_ADDR_C45) {
|
||||
if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
|
||||
err = rtl930x_read_mmd_phy(mii_id,
|
||||
mdiobus_c45_devad(regnum),
|
||||
regnum, &val);
|
||||
@ -1669,7 +1700,7 @@ static int rtl930x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
mdiobus_c45_devad(regnum), mdiobus_c45_regad(regnum),
|
||||
val, err);
|
||||
} else {
|
||||
err = rtl930x_read_phy(mii_id, 0, regnum, &val);
|
||||
err = rtl930x_read_phy(mii_id, page, regnum, &val);
|
||||
pr_debug("PHY: %d register %x read %x, err %d\n", mii_id, regnum, val, err);
|
||||
}
|
||||
if (err)
|
||||
@ -1677,16 +1708,20 @@ static int rtl930x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
return val;
|
||||
}
|
||||
|
||||
static int rtl930x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
{
|
||||
return rtl930x_mdio_read_paged(bus, mii_id, 0, regnum);
|
||||
}
|
||||
|
||||
static int rtl931x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
static int rtl931x_mdio_read_paged(struct mii_bus *bus, int mii_id, u16 page, int regnum)
|
||||
{
|
||||
u32 val;
|
||||
int err, v;
|
||||
struct rtl838x_eth_priv *priv = bus->priv;
|
||||
|
||||
pr_debug("%s: In here, port %d\n", __func__, mii_id);
|
||||
if (priv->sds_id[mii_id] >= 0 && mii_id >= 52) {
|
||||
v = rtl931x_read_sds_phy(priv->sds_id[mii_id], 0, regnum);
|
||||
if (priv->phy_is_internal[mii_id]) {
|
||||
v = rtl931x_read_sds_phy(priv->sds_id[mii_id], page, regnum);
|
||||
if (v < 0) {
|
||||
err = v;
|
||||
} else {
|
||||
@ -1694,7 +1729,7 @@ static int rtl931x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
val = v;
|
||||
}
|
||||
} else {
|
||||
if (regnum & MII_ADDR_C45) {
|
||||
if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
|
||||
err = rtl931x_read_mmd_phy(mii_id,
|
||||
mdiobus_c45_devad(regnum),
|
||||
regnum, &val);
|
||||
@ -1702,7 +1737,7 @@ static int rtl931x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
mdiobus_c45_devad(regnum), mdiobus_c45_regad(regnum),
|
||||
val, err);
|
||||
} else {
|
||||
err = rtl931x_read_phy(mii_id, 0, regnum, &val);
|
||||
err = rtl931x_read_phy(mii_id, page, regnum, &val);
|
||||
pr_debug("PHY: %d register %x read %x, err %d\n", mii_id, regnum, val, err);
|
||||
}
|
||||
}
|
||||
@ -1712,7 +1747,12 @@ static int rtl931x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
return val;
|
||||
}
|
||||
|
||||
static int rtl838x_mdio_write(struct mii_bus *bus, int mii_id,
|
||||
static int rtl931x_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
|
||||
{
|
||||
return rtl931x_mdio_read_paged(bus, mii_id, 0, regnum);
|
||||
}
|
||||
|
||||
static int rtl838x_mdio_write_paged(struct mii_bus *bus, int mii_id, u16 page,
|
||||
int regnum, u16 value)
|
||||
{
|
||||
u32 offset = 0;
|
||||
@ -1725,12 +1765,28 @@ static int rtl838x_mdio_write(struct mii_bus *bus, int mii_id,
|
||||
sw_w32(value, RTL838X_SDS4_FIB_REG0 + offset + (regnum << 2));
|
||||
return 0;
|
||||
}
|
||||
err = rtl838x_write_phy(mii_id, 0, regnum, value);
|
||||
|
||||
if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
|
||||
err = rtl838x_write_mmd_phy(mii_id, mdiobus_c45_devad(regnum),
|
||||
regnum, value);
|
||||
pr_debug("MMD: %d dev %x register %x write %x, err %d\n", mii_id,
|
||||
mdiobus_c45_devad(regnum), mdiobus_c45_regad(regnum),
|
||||
value, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
err = rtl838x_write_phy(mii_id, page, regnum, value);
|
||||
pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rtl839x_mdio_write(struct mii_bus *bus, int mii_id,
|
||||
static int rtl838x_mdio_write(struct mii_bus *bus, int mii_id,
|
||||
int regnum, u16 value)
|
||||
{
|
||||
return rtl838x_mdio_write_paged(bus, mii_id, 0, regnum, value);
|
||||
}
|
||||
|
||||
static int rtl839x_mdio_write_paged(struct mii_bus *bus, int mii_id, u16 page,
|
||||
int regnum, u16 value)
|
||||
{
|
||||
struct rtl838x_eth_priv *priv = bus->priv;
|
||||
@ -1739,7 +1795,41 @@ static int rtl839x_mdio_write(struct mii_bus *bus, int mii_id,
|
||||
if (mii_id >= 48 && mii_id <= 49 && priv->id == 0x8393)
|
||||
return rtl839x_write_sds_phy(mii_id, regnum, value);
|
||||
|
||||
err = rtl839x_write_phy(mii_id, 0, regnum, value);
|
||||
if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
|
||||
err = rtl839x_write_mmd_phy(mii_id, mdiobus_c45_devad(regnum),
|
||||
regnum, value);
|
||||
pr_debug("MMD: %d dev %x register %x write %x, err %d\n", mii_id,
|
||||
mdiobus_c45_devad(regnum), mdiobus_c45_regad(regnum),
|
||||
value, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
err = rtl839x_write_phy(mii_id, page, regnum, value);
|
||||
pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rtl839x_mdio_write(struct mii_bus *bus, int mii_id,
|
||||
int regnum, u16 value)
|
||||
{
|
||||
return rtl839x_mdio_write_paged(bus, mii_id, 0, regnum, value);
|
||||
}
|
||||
|
||||
static int rtl930x_mdio_write_paged(struct mii_bus *bus, int mii_id, u16 page,
|
||||
int regnum, u16 value)
|
||||
{
|
||||
struct rtl838x_eth_priv *priv = bus->priv;
|
||||
int err;
|
||||
|
||||
if (priv->phy_is_internal[mii_id])
|
||||
return rtl930x_write_sds_phy(priv->sds_id[mii_id], page, regnum, value);
|
||||
|
||||
if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD))
|
||||
return rtl930x_write_mmd_phy(mii_id, mdiobus_c45_devad(regnum),
|
||||
regnum, value);
|
||||
|
||||
err = rtl930x_write_phy(mii_id, page, regnum, value);
|
||||
pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err);
|
||||
return err;
|
||||
}
|
||||
@ -1747,31 +1837,19 @@ static int rtl839x_mdio_write(struct mii_bus *bus, int mii_id,
|
||||
static int rtl930x_mdio_write(struct mii_bus *bus, int mii_id,
|
||||
int regnum, u16 value)
|
||||
{
|
||||
struct rtl838x_eth_priv *priv = bus->priv;
|
||||
int err;
|
||||
|
||||
if (priv->sds_id[mii_id] >= 0)
|
||||
return rtl930x_write_sds_phy(priv->sds_id[mii_id], 0, regnum, value);
|
||||
|
||||
if (regnum & MII_ADDR_C45)
|
||||
return rtl930x_write_mmd_phy(mii_id, mdiobus_c45_devad(regnum),
|
||||
regnum, value);
|
||||
|
||||
err = rtl930x_write_phy(mii_id, 0, regnum, value);
|
||||
pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err);
|
||||
return err;
|
||||
return rtl930x_mdio_write_paged(bus, mii_id, 0, regnum, value);
|
||||
}
|
||||
|
||||
static int rtl931x_mdio_write(struct mii_bus *bus, int mii_id,
|
||||
static int rtl931x_mdio_write_paged(struct mii_bus *bus, int mii_id, u16 page,
|
||||
int regnum, u16 value)
|
||||
{
|
||||
struct rtl838x_eth_priv *priv = bus->priv;
|
||||
int err;
|
||||
|
||||
if (priv->sds_id[mii_id] >= 0 && mii_id >= 52)
|
||||
return rtl931x_write_sds_phy(priv->sds_id[mii_id], 0, regnum, value);
|
||||
if (priv->phy_is_internal[mii_id])
|
||||
return rtl931x_write_sds_phy(priv->sds_id[mii_id], page, regnum, value);
|
||||
|
||||
if (regnum & MII_ADDR_C45) {
|
||||
if (regnum & (MII_ADDR_C45 | MII_ADDR_C22_MMD)) {
|
||||
err = rtl931x_write_mmd_phy(mii_id, mdiobus_c45_devad(regnum),
|
||||
regnum, value);
|
||||
pr_debug("MMD: %d dev %x register %x write %x, err %d\n", mii_id,
|
||||
@ -1781,11 +1859,17 @@ static int rtl931x_mdio_write(struct mii_bus *bus, int mii_id,
|
||||
return err;
|
||||
}
|
||||
|
||||
err = rtl931x_write_phy(mii_id, 0, regnum, value);
|
||||
err = rtl931x_write_phy(mii_id, page, regnum, value);
|
||||
pr_debug("PHY: %d register %x write %x, err %d\n", mii_id, regnum, value, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int rtl931x_mdio_write(struct mii_bus *bus, int mii_id,
|
||||
int regnum, u16 value)
|
||||
{
|
||||
return rtl931x_mdio_write_paged(bus, mii_id, 0, regnum, value);
|
||||
}
|
||||
|
||||
static int rtl838x_mdio_reset(struct mii_bus *bus)
|
||||
{
|
||||
pr_debug("%s called\n", __func__);
|
||||
@ -2047,30 +2131,39 @@ static int rtl838x_mdio_init(struct rtl838x_eth_priv *priv)
|
||||
case RTL8380_FAMILY_ID:
|
||||
priv->mii_bus->name = "rtl838x-eth-mdio";
|
||||
priv->mii_bus->read = rtl838x_mdio_read;
|
||||
priv->mii_bus->read_paged = rtl838x_mdio_read_paged;
|
||||
priv->mii_bus->write = rtl838x_mdio_write;
|
||||
priv->mii_bus->write_paged = rtl838x_mdio_write_paged;
|
||||
priv->mii_bus->reset = rtl838x_mdio_reset;
|
||||
break;
|
||||
case RTL8390_FAMILY_ID:
|
||||
priv->mii_bus->name = "rtl839x-eth-mdio";
|
||||
priv->mii_bus->read = rtl839x_mdio_read;
|
||||
priv->mii_bus->read_paged = rtl839x_mdio_read_paged;
|
||||
priv->mii_bus->write = rtl839x_mdio_write;
|
||||
priv->mii_bus->write_paged = rtl839x_mdio_write_paged;
|
||||
priv->mii_bus->reset = rtl839x_mdio_reset;
|
||||
break;
|
||||
case RTL9300_FAMILY_ID:
|
||||
priv->mii_bus->name = "rtl930x-eth-mdio";
|
||||
priv->mii_bus->read = rtl930x_mdio_read;
|
||||
priv->mii_bus->read_paged = rtl930x_mdio_read_paged;
|
||||
priv->mii_bus->write = rtl930x_mdio_write;
|
||||
priv->mii_bus->write_paged = rtl930x_mdio_write_paged;
|
||||
priv->mii_bus->reset = rtl930x_mdio_reset;
|
||||
priv->mii_bus->probe_capabilities = MDIOBUS_C22_C45;
|
||||
break;
|
||||
case RTL9310_FAMILY_ID:
|
||||
priv->mii_bus->name = "rtl931x-eth-mdio";
|
||||
priv->mii_bus->read = rtl931x_mdio_read;
|
||||
priv->mii_bus->read_paged = rtl931x_mdio_read_paged;
|
||||
priv->mii_bus->write = rtl931x_mdio_write;
|
||||
priv->mii_bus->write_paged = rtl931x_mdio_write_paged;
|
||||
priv->mii_bus->reset = rtl931x_mdio_reset;
|
||||
priv->mii_bus->probe_capabilities = MDIOBUS_C22_C45;
|
||||
break;
|
||||
}
|
||||
priv->mii_bus->access_capabilities = MDIOBUS_ACCESS_C22_MMD;
|
||||
priv->mii_bus->priv = priv;
|
||||
priv->mii_bus->parent = &priv->pdev->dev;
|
||||
|
||||
|
@ -442,8 +442,12 @@ struct rtl838x_eth_reg {
|
||||
|
||||
int rtl838x_write_phy(u32 port, u32 page, u32 reg, u32 val);
|
||||
int rtl838x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
|
||||
int rtl838x_write_mmd_phy(u32 port, u32 addr, u32 reg, u32 val);
|
||||
int rtl838x_read_mmd_phy(u32 port, u32 addr, u32 reg, u32 *val);
|
||||
int rtl839x_write_phy(u32 port, u32 page, u32 reg, u32 val);
|
||||
int rtl839x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
|
||||
int rtl839x_read_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 *val);
|
||||
int rtl839x_write_mmd_phy(u32 port, u32 devnum, u32 regnum, u32 val);
|
||||
int rtl930x_write_phy(u32 port, u32 page, u32 reg, u32 val);
|
||||
int rtl930x_read_phy(u32 port, u32 page, u32 reg, u32 *val);
|
||||
int rtl931x_write_phy(u32 port, u32 page, u32 reg, u32 val);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
// TODO: not really used
|
||||
struct rtl838x_phy_priv {
|
||||
struct rtl83xx_shared_private {
|
||||
char *name;
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,840 @@
|
||||
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
|
||||
@@ -734,6 +734,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
|
||||
@@ -749,7 +775,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);
|
||||
@@ -759,6 +788,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
|
||||
@@ -775,7 +838,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);
|
||||
@@ -785,6 +851,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
|
||||
@@ -817,6 +916,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
|
||||
@@ -842,6 +978,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
|
||||
@@ -864,6 +1073,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
|
||||
@@ -890,6 +1122,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
|
||||
@@ -913,6 +1172,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
|
||||
@@ -934,6 +1217,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... */
|
Loading…
x
Reference in New Issue
Block a user