ar8216: introduce enable_eee swconfig attribute to control 802.3az EEE per port
authorFelix Fietkau <nbd@openwrt.org>
Sun, 18 Jan 2015 00:53:53 +0000 (00:53 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 18 Jan 2015 00:53:53 +0000 (00:53 +0000)
Users reported network issues with AR8327 which turned out to be caused
by EEE not working correctly with certain link partners (ticket 14597).
The workaround was to disable EEE on all ports (changeset 41577).

The issue was with certain link partners only, therefore this patch
allows to control usage of EEE per port via swconfig.
Still the default is to initially disable EEE on all ports.

Successfully tested on a TL-WDR4900 (AR8327 rev.4)

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
SVN-Revision: 44021

target/linux/generic/files/drivers/net/phy/ar8216.c
target/linux/generic/files/drivers/net/phy/ar8216.h
target/linux/generic/files/drivers/net/phy/ar8327.c
target/linux/generic/files/drivers/net/phy/ar8327.h

index 2fd44253c802411042e2b12bf2439651532e4cb0..99d0e8220fa2d842cc6e8ea462f32c28044a07d3 100644 (file)
@@ -1041,6 +1041,7 @@ int
 ar8xxx_sw_reset_switch(struct switch_dev *dev)
 {
        struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+       const struct ar8xxx_chip *chip = priv->chip;
        int i;
 
        mutex_lock(&priv->reg_mutex);
@@ -1052,18 +1053,18 @@ ar8xxx_sw_reset_switch(struct switch_dev *dev)
 
        /* Configure all ports */
        for (i = 0; i < dev->ports; i++)
-               priv->chip->init_port(priv, i);
+               chip->init_port(priv, i);
 
        priv->mirror_rx = false;
        priv->mirror_tx = false;
        priv->source_port = 0;
        priv->monitor_port = 0;
 
-       priv->chip->init_globals(priv);
+       chip->init_globals(priv);
 
        mutex_unlock(&priv->reg_mutex);
 
-       return ar8xxx_sw_hw_apply(dev);
+       return chip->sw_hw_apply(dev);
 }
 
 int
@@ -1194,7 +1195,7 @@ ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev,
        return 0;
 }
 
-static int
+int
 ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,
                             const struct switch_attr *attr,
                             struct switch_val *val)
@@ -1224,7 +1225,7 @@ unlock:
        return ret;
 }
 
-static int
+int
 ar8xxx_sw_get_port_mib(struct switch_dev *dev,
                       const struct switch_attr *attr,
                       struct switch_val *val)
@@ -1390,6 +1391,7 @@ static const struct ar8xxx_chip ar8216_chip = {
        .vtu_flush = ar8216_vtu_flush,
        .vtu_load_vlan = ar8216_vtu_load_vlan,
        .set_mirror_regs = ar8216_set_mirror_regs,
+       .sw_hw_apply = ar8xxx_sw_hw_apply,
 
        .num_mibs = ARRAY_SIZE(ar8216_mibs),
        .mib_decs = ar8216_mibs,
@@ -1416,6 +1418,7 @@ static const struct ar8xxx_chip ar8236_chip = {
        .vtu_flush = ar8216_vtu_flush,
        .vtu_load_vlan = ar8216_vtu_load_vlan,
        .set_mirror_regs = ar8216_set_mirror_regs,
+       .sw_hw_apply = ar8xxx_sw_hw_apply,
 
        .num_mibs = ARRAY_SIZE(ar8236_mibs),
        .mib_decs = ar8236_mibs,
@@ -1442,6 +1445,7 @@ static const struct ar8xxx_chip ar8316_chip = {
        .vtu_flush = ar8216_vtu_flush,
        .vtu_load_vlan = ar8216_vtu_load_vlan,
        .set_mirror_regs = ar8216_set_mirror_regs,
+       .sw_hw_apply = ar8xxx_sw_hw_apply,
 
        .num_mibs = ARRAY_SIZE(ar8236_mibs),
        .mib_decs = ar8236_mibs,
index d3d044324eb4198a8d67d43ef914ddaad392dab1..4089a1705964cc6aa7f6e09fd1f4f609981b20b3 100644 (file)
@@ -371,6 +371,7 @@ struct ar8xxx_chip {
        void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask);
        void (*phy_fixup)(struct ar8xxx_priv *priv, int phy);
        void (*set_mirror_regs)(struct ar8xxx_priv *priv);
+       int (*sw_hw_apply)(struct switch_dev *dev);
 
        const struct ar8xxx_mib_desc *mib_decs;
        unsigned num_mibs;
@@ -487,6 +488,14 @@ int
 ar8xxx_sw_get_port_link(struct switch_dev *dev, int port,
                        struct switch_port_link *link);
 int
+ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,
+                             const struct switch_attr *attr,
+                             struct switch_val *val);
+int
+ar8xxx_sw_get_port_mib(struct switch_dev *dev,
+                       const struct switch_attr *attr,
+                       struct switch_val *val);
+int
 ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
 
 static inline struct ar8xxx_priv *
index f6d07c19829b1355860b8faa1378d7e390b998f4..0971f80d50f2fd16b64cf9aa858f5352b00f2f34 100644 (file)
@@ -30,7 +30,6 @@
 #include "ar8327.h"
 
 extern const struct ar8xxx_mib_desc ar8236_mibs[39];
-extern const struct switch_attr ar8xxx_sw_attr_port[2];
 extern const struct switch_attr ar8xxx_sw_attr_vlan[1];
 
 static u32
@@ -651,7 +650,9 @@ ar8327_cleanup(struct ar8xxx_priv *priv)
 static void
 ar8327_init_globals(struct ar8xxx_priv *priv)
 {
+       struct ar8327_data *data = priv->chip_data;
        u32 t;
+       int i;
 
        /* enable CPU port and disable mirror port */
        t = AR8327_FWD_CTRL0_CPU_PORT_EN |
@@ -672,14 +673,9 @@ ar8327_init_globals(struct ar8xxx_priv *priv)
        ar8xxx_reg_set(priv, AR8327_REG_MODULE_EN,
                       AR8327_MODULE_EN_MIB);
 
-       /* Disable EEE on all ports due to stability issues */
-       t = ar8xxx_read(priv, AR8327_REG_EEE_CTRL);
-       t |= AR8327_EEE_CTRL_DISABLE_PHY(0) |
-            AR8327_EEE_CTRL_DISABLE_PHY(1) |
-            AR8327_EEE_CTRL_DISABLE_PHY(2) |
-            AR8327_EEE_CTRL_DISABLE_PHY(3) |
-            AR8327_EEE_CTRL_DISABLE_PHY(4);
-       ar8xxx_write(priv, AR8327_REG_EEE_CTRL, t);
+       /* Disable EEE on all phy's due to stability issues */
+       for (i = 0; i < AR8XXX_NUM_PHYS; i++)
+               data->eee[i] = false;
 }
 
 static void
@@ -892,6 +888,73 @@ ar8327_set_mirror_regs(struct ar8xxx_priv *priv)
                           AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN);
 }
 
+static int
+ar8327_sw_set_eee(struct switch_dev *dev,
+                 const struct switch_attr *attr,
+                 struct switch_val *val)
+{
+       struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+       struct ar8327_data *data = priv->chip_data;
+       int port = val->port_vlan;
+       int phy;
+
+       if (port >= dev->ports)
+               return -EINVAL;
+       if (port == 0 || port == 6)
+               return -EOPNOTSUPP;
+
+       phy = port - 1;
+
+       data->eee[phy] = !!(val->value.i);
+
+       return 0;
+}
+
+static int
+ar8327_sw_get_eee(struct switch_dev *dev,
+                 const struct switch_attr *attr,
+                 struct switch_val *val)
+{
+       struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+       const struct ar8327_data *data = priv->chip_data;
+       int port = val->port_vlan;
+       int phy;
+
+       if (port >= dev->ports)
+               return -EINVAL;
+       if (port == 0 || port == 6)
+               return -EOPNOTSUPP;
+
+       phy = port - 1;
+
+       val->value.i = data->eee[phy];
+
+       return 0;
+}
+
+static int
+ar8327_sw_hw_apply(struct switch_dev *dev)
+{
+       struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+       const struct ar8327_data *data = priv->chip_data;
+       int ret, i;
+
+       ret = ar8xxx_sw_hw_apply(dev);
+       if (ret)
+               return ret;
+
+       for (i=0; i < AR8XXX_NUM_PHYS; i++) {
+               if (data->eee[i])
+                       ar8xxx_reg_clear(priv, AR8327_REG_EEE_CTRL,
+                              AR8327_EEE_CTRL_DISABLE_PHY(i));
+               else
+                       ar8xxx_reg_set(priv, AR8327_REG_EEE_CTRL,
+                              AR8327_EEE_CTRL_DISABLE_PHY(i));
+       }
+
+       return 0;
+}
+
 static const struct switch_attr ar8327_sw_attr_globals[] = {
        {
                .type = SWITCH_TYPE_INT,
@@ -941,14 +1004,38 @@ static const struct switch_attr ar8327_sw_attr_globals[] = {
        },
 };
 
+static const struct switch_attr ar8327_sw_attr_port[] = {
+       {
+               .type = SWITCH_TYPE_NOVAL,
+               .name = "reset_mib",
+               .description = "Reset single port MIB counters",
+               .set = ar8xxx_sw_set_port_reset_mib,
+       },
+       {
+               .type = SWITCH_TYPE_STRING,
+               .name = "mib",
+               .description = "Get port's MIB counters",
+               .set = NULL,
+               .get = ar8xxx_sw_get_port_mib,
+       },
+       {
+               .type = SWITCH_TYPE_INT,
+               .name = "enable_eee",
+               .description = "Enable EEE PHY sleep mode",
+               .set = ar8327_sw_set_eee,
+               .get = ar8327_sw_get_eee,
+               .max = 1,
+       },
+};
+
 static const struct switch_dev_ops ar8327_sw_ops = {
        .attr_global = {
                .attr = ar8327_sw_attr_globals,
                .n_attr = ARRAY_SIZE(ar8327_sw_attr_globals),
        },
        .attr_port = {
-               .attr = ar8xxx_sw_attr_port,
-               .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port),
+               .attr = ar8327_sw_attr_port,
+               .n_attr = ARRAY_SIZE(ar8327_sw_attr_port),
        },
        .attr_vlan = {
                .attr = ar8xxx_sw_attr_vlan,
@@ -958,7 +1045,7 @@ static const struct switch_dev_ops ar8327_sw_ops = {
        .set_port_pvid = ar8xxx_sw_set_pvid,
        .get_vlan_ports = ar8327_sw_get_ports,
        .set_vlan_ports = ar8327_sw_set_ports,
-       .apply_config = ar8xxx_sw_hw_apply,
+       .apply_config = ar8327_sw_hw_apply,
        .reset_switch = ar8xxx_sw_reset_switch,
        .get_port_link = ar8xxx_sw_get_port_link,
 };
@@ -987,6 +1074,7 @@ const struct ar8xxx_chip ar8327_chip = {
        .vtu_load_vlan = ar8327_vtu_load_vlan,
        .phy_fixup = ar8327_phy_fixup,
        .set_mirror_regs = ar8327_set_mirror_regs,
+       .sw_hw_apply = ar8327_sw_hw_apply,
 
        .num_mibs = ARRAY_SIZE(ar8236_mibs),
        .mib_decs = ar8236_mibs,
@@ -1017,6 +1105,7 @@ const struct ar8xxx_chip ar8337_chip = {
        .vtu_load_vlan = ar8327_vtu_load_vlan,
        .phy_fixup = ar8327_phy_fixup,
        .set_mirror_regs = ar8327_set_mirror_regs,
+       .sw_hw_apply = ar8327_sw_hw_apply,
 
        .num_mibs = ARRAY_SIZE(ar8236_mibs),
        .mib_decs = ar8236_mibs,
index c606972a04ed724cc41b092ddff9eb483876f015..1877f00c97912c57950d9ece6a1aa9b44b8f19e7 100644 (file)
@@ -219,6 +219,9 @@ struct ar8327_data {
 
        struct ar8327_led **leds;
        unsigned int num_leds;
+
+       /* all fields below are cleared on reset */
+       bool eee[AR8XXX_NUM_PHYS];
 };
 
 #endif