diff options
Diffstat (limited to 'target/linux/generic/files')
5 files changed, 49 insertions, 1 deletions
diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c index 99d0e8220f..90484d6462 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -332,6 +332,20 @@ ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 data) mutex_unlock(&bus->mdio_lock); } +u16 +ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr) +{ + struct mii_bus *bus = priv->mii_bus; + u16 data; + + mutex_lock(&bus->mdio_lock); + bus->write(bus, phy_addr, MII_ATH_MMD_ADDR, addr); + data = bus->read(bus, phy_addr, MII_ATH_MMD_DATA); + mutex_unlock(&bus->mdio_lock); + + return data; +} + static int ar8xxx_reg_wait(struct ar8xxx_priv *priv, u32 reg, u32 mask, u32 val, unsigned timeout) @@ -453,6 +467,9 @@ ar8216_read_port_link(struct ar8xxx_priv *priv, int port, link->tx_flow = !!(status & AR8216_PORT_STATUS_TXFLOW); link->rx_flow = !!(status & AR8216_PORT_STATUS_RXFLOW); + if (link->aneg && link->duplex && priv->chip->read_port_eee_status) + link->eee = priv->chip->read_port_eee_status(priv, port); + speed = (status & AR8216_PORT_STATUS_SPEED) >> AR8216_PORT_STATUS_SPEED_S; diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.h b/target/linux/generic/files/drivers/net/phy/ar8216.h index 4089a17059..8487c3ea49 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.h +++ b/target/linux/generic/files/drivers/net/phy/ar8216.h @@ -366,6 +366,7 @@ struct ar8xxx_chip { void (*init_port)(struct ar8xxx_priv *priv, int port); void (*setup_port)(struct ar8xxx_priv *priv, int port, u32 members); u32 (*read_port_status)(struct ar8xxx_priv *priv, int port); + u32 (*read_port_eee_status)(struct ar8xxx_priv *priv, int port); int (*atu_flush)(struct ar8xxx_priv *priv); void (*vtu_flush)(struct ar8xxx_priv *priv); void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask); @@ -432,6 +433,8 @@ ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr, u16 dbg_addr, u16 dbg_data); void ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 data); +u16 +ar8xxx_phy_mmd_read(struct ar8xxx_priv *priv, int phy_addr, u16 addr); void ar8xxx_phy_init(struct ar8xxx_priv *priv); int diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.c b/target/linux/generic/files/drivers/net/phy/ar8327.c index 0971f80d50..c0262d7145 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8327.c +++ b/target/linux/generic/files/drivers/net/phy/ar8327.c @@ -25,6 +25,7 @@ #include <linux/workqueue.h> #include <linux/of_device.h> #include <linux/leds.h> +#include <linux/mdio.h> #include "ar8216.h" #include "ar8327.h" @@ -712,6 +713,27 @@ ar8327_read_port_status(struct ar8xxx_priv *priv, int port) return ar8xxx_read(priv, AR8327_REG_PORT_STATUS(port)); } +static u32 +ar8327_read_port_eee_status(struct ar8xxx_priv *priv, int port) +{ + int phy; + u16 t; + + if (port >= priv->dev.ports) + return 0; + + if (port == 0 || port == 6) + return 0; + + phy = port - 1; + + /* EEE Ability Auto-negotiation Result */ + ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x8000); + t = ar8xxx_phy_mmd_read(priv, phy, 0x4007); + + return mmd_eee_adv_to_ethtool_adv_t(t); +} + static int ar8327_atu_flush(struct ar8xxx_priv *priv) { @@ -1069,6 +1091,7 @@ const struct ar8xxx_chip ar8327_chip = { .init_port = ar8327_init_port, .setup_port = ar8327_setup_port, .read_port_status = ar8327_read_port_status, + .read_port_eee_status = ar8327_read_port_eee_status, .atu_flush = ar8327_atu_flush, .vtu_flush = ar8327_vtu_flush, .vtu_load_vlan = ar8327_vtu_load_vlan, @@ -1100,6 +1123,7 @@ const struct ar8xxx_chip ar8337_chip = { .init_port = ar8327_init_port, .setup_port = ar8327_setup_port, .read_port_status = ar8327_read_port_status, + .read_port_eee_status = ar8327_read_port_eee_status, .atu_flush = ar8327_atu_flush, .vtu_flush = ar8327_vtu_flush, .vtu_load_vlan = ar8327_vtu_load_vlan, diff --git a/target/linux/generic/files/drivers/net/phy/swconfig.c b/target/linux/generic/files/drivers/net/phy/swconfig.c index 4f2df4cf8a..b0ba90d16f 100644 --- a/target/linux/generic/files/drivers/net/phy/swconfig.c +++ b/target/linux/generic/files/drivers/net/phy/swconfig.c @@ -167,12 +167,14 @@ swconfig_get_link(struct switch_dev *dev, const struct switch_attr *attr, if (link.link) len = snprintf(dev->buf, sizeof(dev->buf), - "port:%d link:up speed:%s %s-duplex %s%s%s", + "port:%d link:up speed:%s %s-duplex %s%s%s%s%s", val->port_vlan, swconfig_speed_str(link.speed), link.duplex ? "full" : "half", link.tx_flow ? "txflow " : "", link.rx_flow ? "rxflow " : "", + link.eee & ADVERTISED_100baseT_Full ? "eee100 " : "", + link.eee & ADVERTISED_1000baseT_Full ? "eee1000 " : "", link.aneg ? "auto" : ""); else len = snprintf(dev->buf, sizeof(dev->buf), "port:%d link:down", diff --git a/target/linux/generic/files/include/linux/switch.h b/target/linux/generic/files/include/linux/switch.h index b53431e0a1..4291364562 100644 --- a/target/linux/generic/files/include/linux/switch.h +++ b/target/linux/generic/files/include/linux/switch.h @@ -54,6 +54,8 @@ struct switch_port_link { bool tx_flow; bool rx_flow; enum switch_port_speed speed; + /* in ethtool adv_t format */ + u32 eee; }; struct switch_port_stats { |