aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r--drivers/net/ethernet/ti/cpsw.c20
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.c29
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.h2
3 files changed, 49 insertions, 2 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 4683196c6592..96a61d169215 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -638,12 +638,16 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
638 if (ndev->flags & IFF_PROMISC) { 638 if (ndev->flags & IFF_PROMISC) {
639 /* Enable promiscuous mode */ 639 /* Enable promiscuous mode */
640 cpsw_set_promiscious(ndev, true); 640 cpsw_set_promiscious(ndev, true);
641 cpsw_ale_set_allmulti(priv->ale, IFF_ALLMULTI);
641 return; 642 return;
642 } else { 643 } else {
643 /* Disable promiscuous mode */ 644 /* Disable promiscuous mode */
644 cpsw_set_promiscious(ndev, false); 645 cpsw_set_promiscious(ndev, false);
645 } 646 }
646 647
648 /* Restore allmulti on vlans if necessary */
649 cpsw_ale_set_allmulti(priv->ale, priv->ndev->flags & IFF_ALLMULTI);
650
647 /* Clear all mcast from ALE */ 651 /* Clear all mcast from ALE */
648 cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port); 652 cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port);
649 653
@@ -1149,6 +1153,7 @@ static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
1149 const int port = priv->host_port; 1153 const int port = priv->host_port;
1150 u32 reg; 1154 u32 reg;
1151 int i; 1155 int i;
1156 int unreg_mcast_mask;
1152 1157
1153 reg = (priv->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN : 1158 reg = (priv->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN :
1154 CPSW2_PORT_VLAN; 1159 CPSW2_PORT_VLAN;
@@ -1158,9 +1163,14 @@ static inline void cpsw_add_default_vlan(struct cpsw_priv *priv)
1158 for (i = 0; i < priv->data.slaves; i++) 1163 for (i = 0; i < priv->data.slaves; i++)
1159 slave_write(priv->slaves + i, vlan, reg); 1164 slave_write(priv->slaves + i, vlan, reg);
1160 1165
1166 if (priv->ndev->flags & IFF_ALLMULTI)
1167 unreg_mcast_mask = ALE_ALL_PORTS;
1168 else
1169 unreg_mcast_mask = ALE_PORT_1 | ALE_PORT_2;
1170
1161 cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port, 1171 cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port,
1162 ALE_ALL_PORTS << port, ALE_ALL_PORTS << port, 1172 ALE_ALL_PORTS << port, ALE_ALL_PORTS << port,
1163 (ALE_PORT_1 | ALE_PORT_2) << port); 1173 unreg_mcast_mask << port);
1164} 1174}
1165 1175
1166static void cpsw_init_host_port(struct cpsw_priv *priv) 1176static void cpsw_init_host_port(struct cpsw_priv *priv)
@@ -1620,11 +1630,17 @@ static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv,
1620 unsigned short vid) 1630 unsigned short vid)
1621{ 1631{
1622 int ret; 1632 int ret;
1633 int unreg_mcast_mask;
1634
1635 if (priv->ndev->flags & IFF_ALLMULTI)
1636 unreg_mcast_mask = ALE_ALL_PORTS;
1637 else
1638 unreg_mcast_mask = ALE_PORT_1 | ALE_PORT_2;
1623 1639
1624 ret = cpsw_ale_add_vlan(priv->ale, vid, 1640 ret = cpsw_ale_add_vlan(priv->ale, vid,
1625 ALE_ALL_PORTS << priv->host_port, 1641 ALE_ALL_PORTS << priv->host_port,
1626 0, ALE_ALL_PORTS << priv->host_port, 1642 0, ALE_ALL_PORTS << priv->host_port,
1627 (ALE_PORT_1 | ALE_PORT_2) << priv->host_port); 1643 unreg_mcast_mask << priv->host_port);
1628 if (ret != 0) 1644 if (ret != 0)
1629 return ret; 1645 return ret;
1630 1646
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index 0579b2243bb6..3ae83879a75f 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -443,6 +443,35 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
443 return 0; 443 return 0;
444} 444}
445 445
446void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti)
447{
448 u32 ale_entry[ALE_ENTRY_WORDS];
449 int type, idx;
450 int unreg_mcast = 0;
451
452 /* Only bother doing the work if the setting is actually changing */
453 if (ale->allmulti == allmulti)
454 return;
455
456 /* Remember the new setting to check against next time */
457 ale->allmulti = allmulti;
458
459 for (idx = 0; idx < ale->params.ale_entries; idx++) {
460 cpsw_ale_read(ale, idx, ale_entry);
461 type = cpsw_ale_get_entry_type(ale_entry);
462 if (type != ALE_TYPE_VLAN)
463 continue;
464
465 unreg_mcast = cpsw_ale_get_vlan_unreg_mcast(ale_entry);
466 if (allmulti)
467 unreg_mcast |= 1;
468 else
469 unreg_mcast &= ~1;
470 cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast);
471 cpsw_ale_write(ale, idx, ale_entry);
472 }
473}
474
446struct ale_control_info { 475struct ale_control_info {
447 const char *name; 476 const char *name;
448 int offset, port_offset; 477 int offset, port_offset;
diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h
index 31cf43cab42e..c0d4127aa549 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.h
+++ b/drivers/net/ethernet/ti/cpsw_ale.h
@@ -27,6 +27,7 @@ struct cpsw_ale {
27 struct cpsw_ale_params params; 27 struct cpsw_ale_params params;
28 struct timer_list timer; 28 struct timer_list timer;
29 unsigned long ageout; 29 unsigned long ageout;
30 int allmulti;
30}; 31};
31 32
32enum cpsw_ale_control { 33enum cpsw_ale_control {
@@ -103,6 +104,7 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
103int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, 104int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
104 int reg_mcast, int unreg_mcast); 105 int reg_mcast, int unreg_mcast);
105int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port); 106int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port);
107void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti);
106 108
107int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control); 109int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control);
108int cpsw_ale_control_set(struct cpsw_ale *ale, int port, 110int cpsw_ale_control_set(struct cpsw_ale *ale, int port,