diff mbox

[OpenWrt-Devel,5/6] ar8216: add 802.3az EEE info to swconfig get_link attribute

Message ID 54B41DFD.8060305@gmail.com
State Accepted
Headers show

Commit Message

Heiner Kallweit Jan. 12, 2015, 7:18 p.m. UTC
AR8327/AR8337 allow to read the result of EEE autonegotiation.
If EEE is autonegotiated between the link partners, display
this as part of the swconfig get_link attribute.

eee100:  100MBit EEE supported by both link partners
eee1000: 1GBit EEE supported by both link partners

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
---
 .../linux/generic/files/drivers/net/phy/ar8216.c   | 17 +++++++++++++++
 .../linux/generic/files/drivers/net/phy/ar8216.h   |  3 +++
 .../linux/generic/files/drivers/net/phy/ar8327.c   | 24 ++++++++++++++++++++++
 .../linux/generic/files/drivers/net/phy/swconfig.c |  4 +++-
 target/linux/generic/files/include/linux/switch.h  |  2 ++
 5 files changed, 49 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c
index 99d0e82..90484d6 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 4089a17..8487c3e 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 0971f80..c0262d7 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 4f2df4c..b0ba90d 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 b53431e..4291364 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 {