Commit 25906052 authored by Mugunthan V N's avatar Mugunthan V N Committed by David S. Miller

drivers: net: cpsw: fix multicast flush in dual emac mode

Since ALE table is a common resource for both the interfaces in Dual EMAC
mode and while bringing up the second interface in cpsw_ndo_set_rx_mode()
all the multicast entries added by the first interface is flushed out and
only second interface multicast addresses are added. Fixing this by
flushing multicast addresses based on dual EMAC port vlans which will not
affect the other emac port multicast addresses.

Fixes: d9ba8f9e (driver: net: ethernet: cpsw: dual emac interface implementation)
Cc: <stable@vger.kernel.org> # v3.9+
Signed-off-by: default avatarMugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fd48e639
...@@ -610,7 +610,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable) ...@@ -610,7 +610,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
/* Clear all mcast from ALE */ /* Clear all mcast from ALE */
cpsw_ale_flush_multicast(ale, ALE_ALL_PORTS << cpsw_ale_flush_multicast(ale, ALE_ALL_PORTS <<
priv->host_port); priv->host_port, -1);
/* Flood All Unicast Packets to Host port */ /* Flood All Unicast Packets to Host port */
cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 1); cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 1);
...@@ -634,6 +634,12 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable) ...@@ -634,6 +634,12 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable)
static void cpsw_ndo_set_rx_mode(struct net_device *ndev) static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
{ {
struct cpsw_priv *priv = netdev_priv(ndev); struct cpsw_priv *priv = netdev_priv(ndev);
int vid;
if (priv->data.dual_emac)
vid = priv->slaves[priv->emac_port].port_vlan;
else
vid = priv->data.default_vlan;
if (ndev->flags & IFF_PROMISC) { if (ndev->flags & IFF_PROMISC) {
/* Enable promiscuous mode */ /* Enable promiscuous mode */
...@@ -649,7 +655,8 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev) ...@@ -649,7 +655,8 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
cpsw_ale_set_allmulti(priv->ale, priv->ndev->flags & IFF_ALLMULTI); cpsw_ale_set_allmulti(priv->ale, priv->ndev->flags & IFF_ALLMULTI);
/* Clear all mcast from ALE */ /* Clear all mcast from ALE */
cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port); cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port,
vid);
if (!netdev_mc_empty(ndev)) { if (!netdev_mc_empty(ndev)) {
struct netdev_hw_addr *ha; struct netdev_hw_addr *ha;
......
...@@ -234,7 +234,7 @@ static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry, ...@@ -234,7 +234,7 @@ static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry,
cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
} }
int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask) int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid)
{ {
u32 ale_entry[ALE_ENTRY_WORDS]; u32 ale_entry[ALE_ENTRY_WORDS];
int ret, idx; int ret, idx;
...@@ -245,6 +245,14 @@ int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask) ...@@ -245,6 +245,14 @@ int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask)
if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR) if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR)
continue; continue;
/* if vid passed is -1 then remove all multicast entry from
* the table irrespective of vlan id, if a valid vlan id is
* passed then remove only multicast added to that vlan id.
* if vlan id doesn't match then move on to next entry.
*/
if (vid != -1 && cpsw_ale_get_vlan_id(ale_entry) != vid)
continue;
if (cpsw_ale_get_mcast(ale_entry)) { if (cpsw_ale_get_mcast(ale_entry)) {
u8 addr[6]; u8 addr[6];
......
...@@ -92,7 +92,7 @@ void cpsw_ale_stop(struct cpsw_ale *ale); ...@@ -92,7 +92,7 @@ void cpsw_ale_stop(struct cpsw_ale *ale);
int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout); int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout);
int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask); int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask);
int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask); int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid);
int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
int flags, u16 vid); int flags, u16 vid);
int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment