AR8216: make ARL age time configurable
authorblogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Fri, 4 Mar 2016 08:33:30 +0000 (08:33 +0000)
committerblogic <blogic@3c298f89-4303-0410-b956-a3cf2f4a3e73>
Fri, 4 Mar 2016 08:33:30 +0000 (08:33 +0000)
The default TTL for address resolution table entries is 5 minutes
for all members of the AR8216 family. This can cause issues if
e.g. Wifi clients roam to another AP and their MAC appears on
another switch port suddenly. Then the client may not be reachable
until the old ARL entry expires.
I would have expected the switch to invalidate old entries if it
detects the same MAC on another port. But that's not the case.

Therefore make the TTL for ARL entries configurable.
The effective TTL will always be a multiple of 7 seconds.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@48913 3c298f89-4303-0410-b956-a3cf2f4a3e73

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 a1b9841..817aca5 100644 (file)
@@ -1076,10 +1076,25 @@ ar8216_set_mirror_regs(struct ar8xxx_priv *priv)
                           AR8216_PORT_CTRL_MIRROR_TX);
 }
 
                           AR8216_PORT_CTRL_MIRROR_TX);
 }
 
+static inline u32
+ar8xxx_age_time_val(int age_time)
+{
+       return (age_time + AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS / 2) /
+              AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS;
+}
+
+static inline void
+ar8xxx_set_age_time(struct ar8xxx_priv *priv, int reg)
+{
+       u32 age_time = ar8xxx_age_time_val(priv->arl_age_time);
+       ar8xxx_rmw(priv, reg, AR8216_ATU_CTRL_AGE_TIME, age_time << AR8216_ATU_CTRL_AGE_TIME_S);
+}
+
 int
 ar8xxx_sw_hw_apply(struct switch_dev *dev)
 {
        struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
 int
 ar8xxx_sw_hw_apply(struct switch_dev *dev)
 {
        struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+       const struct ar8xxx_chip *chip = priv->chip;
        u8 portmask[AR8X16_MAX_PORTS];
        int i, j;
 
        u8 portmask[AR8X16_MAX_PORTS];
        int i, j;
 
@@ -1103,8 +1118,8 @@ ar8xxx_sw_hw_apply(struct switch_dev *dev)
                                        portmask[i] |= vp & ~mask;
                        }
 
                                        portmask[i] |= vp & ~mask;
                        }
 
-                       priv->chip->vtu_load_vlan(priv, priv->vlan_id[j],
-                                                priv->vlan_table[j]);
+                       chip->vtu_load_vlan(priv, priv->vlan_id[j],
+                                           priv->vlan_table[j]);
                }
        } else {
                /* vlan disabled:
                }
        } else {
                /* vlan disabled:
@@ -1120,10 +1135,14 @@ ar8xxx_sw_hw_apply(struct switch_dev *dev)
 
        /* update the port destination mask registers and tag settings */
        for (i = 0; i < dev->ports; i++) {
 
        /* update the port destination mask registers and tag settings */
        for (i = 0; i < dev->ports; i++) {
-               priv->chip->setup_port(priv, i, portmask[i]);
+               chip->setup_port(priv, i, portmask[i]);
        }
 
        }
 
-       priv->chip->set_mirror_regs(priv);
+       chip->set_mirror_regs(priv);
+
+       /* set age time */
+       if (chip->reg_arl_ctrl)
+               ar8xxx_set_age_time(priv, chip->reg_arl_ctrl);
 
        mutex_unlock(&priv->reg_mutex);
        return 0;
 
        mutex_unlock(&priv->reg_mutex);
        return 0;
@@ -1151,6 +1170,7 @@ ar8xxx_sw_reset_switch(struct switch_dev *dev)
        priv->mirror_tx = false;
        priv->source_port = 0;
        priv->monitor_port = 0;
        priv->mirror_tx = false;
        priv->source_port = 0;
        priv->monitor_port = 0;
+       priv->arl_age_time = AR8XXX_DEFAULT_ARL_AGE_TIME;
 
        chip->init_globals(priv);
 
 
        chip->init_globals(priv);
 
@@ -1407,6 +1427,34 @@ unlock:
 }
 
 int
 }
 
 int
+ar8xxx_sw_set_arl_age_time(struct switch_dev *dev, const struct switch_attr *attr,
+                          struct switch_val *val)
+{
+       struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+       int age_time = val->value.i;
+       u32 age_time_val;
+
+       if (age_time < 0)
+               return -EINVAL;
+
+       age_time_val = ar8xxx_age_time_val(age_time);
+       if (age_time_val == 0 || age_time_val > 0xffff)
+               return -EINVAL;
+
+       priv->arl_age_time = age_time;
+       return 0;
+}
+
+int
+ar8xxx_sw_get_arl_age_time(struct switch_dev *dev, const struct switch_attr *attr,
+                   struct switch_val *val)
+{
+       struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+       val->value.i = priv->arl_age_time;
+       return 0;
+}
+
+int
 ar8xxx_sw_get_arl_table(struct switch_dev *dev,
                        const struct switch_attr *attr,
                        struct switch_val *val)
 ar8xxx_sw_get_arl_table(struct switch_dev *dev,
                        const struct switch_attr *attr,
                        struct switch_val *val)
@@ -1633,6 +1681,7 @@ static const struct ar8xxx_chip ar8216_chip = {
 
        .reg_port_stats_start = 0x19000,
        .reg_port_stats_length = 0xa0,
 
        .reg_port_stats_start = 0x19000,
        .reg_port_stats_length = 0xa0,
+       .reg_arl_ctrl = AR8216_REG_ATU_CTRL,
 
        .name = "Atheros AR8216",
        .ports = AR8216_NUM_PORTS,
 
        .name = "Atheros AR8216",
        .ports = AR8216_NUM_PORTS,
@@ -1662,6 +1711,7 @@ static const struct ar8xxx_chip ar8236_chip = {
 
        .reg_port_stats_start = 0x20000,
        .reg_port_stats_length = 0x100,
 
        .reg_port_stats_start = 0x20000,
        .reg_port_stats_length = 0x100,
+       .reg_arl_ctrl = AR8216_REG_ATU_CTRL,
 
        .name = "Atheros AR8236",
        .ports = AR8216_NUM_PORTS,
 
        .name = "Atheros AR8236",
        .ports = AR8216_NUM_PORTS,
@@ -1691,6 +1741,7 @@ static const struct ar8xxx_chip ar8316_chip = {
 
        .reg_port_stats_start = 0x20000,
        .reg_port_stats_length = 0x100,
 
        .reg_port_stats_start = 0x20000,
        .reg_port_stats_length = 0x100,
+       .reg_arl_ctrl = AR8216_REG_ATU_CTRL,
 
        .name = "Atheros AR8316",
        .ports = AR8216_NUM_PORTS,
 
        .name = "Atheros AR8316",
        .ports = AR8216_NUM_PORTS,
index 14fe928..fb961ff 100644 (file)
@@ -33,6 +33,9 @@
 #define AR8X16_PROBE_RETRIES   10
 #define AR8X16_MAX_PORTS       8
 
 #define AR8X16_PROBE_RETRIES   10
 #define AR8X16_MAX_PORTS       8
 
+#define AR8XXX_REG_ARL_CTRL_AGE_TIME_SECS      7
+#define AR8XXX_DEFAULT_ARL_AGE_TIME            300
+
 /* Atheros specific MII registers */
 #define MII_ATH_MMD_ADDR               0x0d
 #define MII_ATH_MMD_DATA               0x0e
 /* Atheros specific MII registers */
 #define MII_ATH_MMD_ADDR               0x0d
 #define MII_ATH_MMD_DATA               0x0e
@@ -384,6 +387,8 @@ struct ar8xxx_chip {
        unsigned reg_port_stats_start;
        unsigned reg_port_stats_length;
 
        unsigned reg_port_stats_start;
        unsigned reg_port_stats_length;
 
+       unsigned reg_arl_ctrl;
+
        int (*hw_init)(struct ar8xxx_priv *priv);
        void (*cleanup)(struct ar8xxx_priv *priv);
 
        int (*hw_init)(struct ar8xxx_priv *priv);
        void (*cleanup)(struct ar8xxx_priv *priv);
 
@@ -449,6 +454,7 @@ struct ar8xxx_priv {
        u8 vlan_table[AR8X16_MAX_VLANS];
        u8 vlan_tagged;
        u16 pvid[AR8X16_MAX_PORTS];
        u8 vlan_table[AR8X16_MAX_VLANS];
        u8 vlan_tagged;
        u16 pvid[AR8X16_MAX_PORTS];
+       int arl_age_time;
 
        /* mirroring */
        bool mirror_rx;
 
        /* mirroring */
        bool mirror_rx;
@@ -539,6 +545,14 @@ ar8xxx_sw_get_port_mib(struct switch_dev *dev,
                        const struct switch_attr *attr,
                        struct switch_val *val);
 int
                        const struct switch_attr *attr,
                        struct switch_val *val);
 int
+ar8xxx_sw_get_arl_age_time(struct switch_dev *dev,
+                          const struct switch_attr *attr,
+                          struct switch_val *val);
+int
+ar8xxx_sw_set_arl_age_time(struct switch_dev *dev,
+                          const struct switch_attr *attr,
+                          struct switch_val *val);
+int
 ar8xxx_sw_get_arl_table(struct switch_dev *dev,
                        const struct switch_attr *attr,
                        struct switch_val *val);
 ar8xxx_sw_get_arl_table(struct switch_dev *dev,
                        const struct switch_attr *attr,
                        struct switch_val *val);
index 02fd2e7..9c23238 100644 (file)
@@ -1275,6 +1275,13 @@ static const struct switch_attr ar8327_sw_attr_globals[] = {
                .max = AR8327_NUM_PORTS - 1
        },
        {
                .max = AR8327_NUM_PORTS - 1
        },
        {
+               .type = SWITCH_TYPE_INT,
+               .name = "arl_age_time",
+               .description = "ARL age time (secs)",
+               .set = ar8xxx_sw_set_arl_age_time,
+               .get = ar8xxx_sw_get_arl_age_time,
+       },
+       {
                .type = SWITCH_TYPE_STRING,
                .name = "arl_table",
                .description = "Get ARL table",
                .type = SWITCH_TYPE_STRING,
                .name = "arl_table",
                .description = "Get ARL table",
@@ -1377,6 +1384,7 @@ const struct ar8xxx_chip ar8327_chip = {
 
        .reg_port_stats_start = 0x1000,
        .reg_port_stats_length = 0x100,
 
        .reg_port_stats_start = 0x1000,
        .reg_port_stats_length = 0x100,
+       .reg_arl_ctrl = AR8327_REG_ARL_CTRL,
 
        .hw_init = ar8327_hw_init,
        .cleanup = ar8327_cleanup,
 
        .hw_init = ar8327_hw_init,
        .cleanup = ar8327_cleanup,
@@ -1411,6 +1419,7 @@ const struct ar8xxx_chip ar8337_chip = {
 
        .reg_port_stats_start = 0x1000,
        .reg_port_stats_length = 0x100,
 
        .reg_port_stats_start = 0x1000,
        .reg_port_stats_length = 0x100,
+       .reg_arl_ctrl = AR8327_REG_ARL_CTRL,
 
        .hw_init = ar8327_hw_init,
        .cleanup = ar8327_cleanup,
 
        .hw_init = ar8327_hw_init,
        .cleanup = ar8327_cleanup,
index 4aca754..e8dad35 100644 (file)
 #define   AR8327_VTU_FUNC1_VID_S               16
 #define   AR8327_VTU_FUNC1_BUSY                        BIT(31)
 
 #define   AR8327_VTU_FUNC1_VID_S               16
 #define   AR8327_VTU_FUNC1_BUSY                        BIT(31)
 
+#define AR8327_REG_ARL_CTRL                    0x0618
+
 #define AR8327_REG_FWD_CTRL0                   0x620
 #define   AR8327_FWD_CTRL0_CPU_PORT_EN         BIT(10)
 #define   AR8327_FWD_CTRL0_MIRROR_PORT         BITS(4, 4)
 #define AR8327_REG_FWD_CTRL0                   0x620
 #define   AR8327_FWD_CTRL0_CPU_PORT_EN         BIT(10)
 #define   AR8327_FWD_CTRL0_MIRROR_PORT         BITS(4, 4)