drivers: net: cpsw: fix cpsw hung with add vlan using vconfig
authorMugunthan V N <mugunthanvnm@ti.com>
Thu, 15 Jan 2015 09:29:28 +0000 (14:59 +0530)
committerDavid S. Miller <davem@davemloft.net>
Thu, 15 Jan 2015 18:57:07 +0000 (13:57 -0500)
while adding vlan in dual EMAC mode, only specific ports should be
subscribed for the vlan, else it will lead to switching mode and
if both ports connected to same switch cpsw will hung as it creates
a network loop. Fixing this by adding only specific ports in case
of dual EMAC.

Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/ti/cpsw.c

index 64d1cef..e068d48 100644 (file)
@@ -1634,16 +1634,24 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
                                unsigned short vid)
 {
        int ret;
-       int unreg_mcast_mask;
+       int unreg_mcast_mask = 0;
+       u32 port_mask;
 
-       if (priv->ndev->flags & IFF_ALLMULTI)
-               unreg_mcast_mask = ALE_ALL_PORTS;
-       else
-               unreg_mcast_mask = ALE_PORT_1 | ALE_PORT_2;
+       if (priv->data.dual_emac) {
+               port_mask = (1 << (priv->emac_port + 1)) | ALE_PORT_HOST;
+
+               if (priv->ndev->flags & IFF_ALLMULTI)
+                       unreg_mcast_mask = port_mask;
+       } else {
+               port_mask = ALE_ALL_PORTS;
+
+               if (priv->ndev->flags & IFF_ALLMULTI)
+                       unreg_mcast_mask = ALE_ALL_PORTS;
+               else
+                       unreg_mcast_mask = ALE_PORT_1 | ALE_PORT_2;
+       }
 
-       ret = cpsw_ale_add_vlan(priv->ale, vid,
-                               ALE_ALL_PORTS << priv->host_port,
-                               0, ALE_ALL_PORTS << priv->host_port,
+       ret = cpsw_ale_add_vlan(priv->ale, vid, port_mask, 0, port_mask,
                                unreg_mcast_mask << priv->host_port);
        if (ret != 0)
                return ret;
@@ -1654,8 +1662,7 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
                goto clean_vid;
 
        ret = cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast,
-                                ALE_ALL_PORTS << priv->host_port,
-                                ALE_VLAN, vid, 0);
+                                port_mask, ALE_VLAN, vid, 0);
        if (ret != 0)
                goto clean_vlan_ucast;
        return 0;