History

drivers: net: cpsw: Support ALLMULTI and fix IFF_PROMISC in switch mode

The cpsw driver did not support the IFF_ALLMULTI flag which makes dynamic multicast routing not work. Related to this, when enabling IFF_PROMISC in switch mode, all registered multicast addresses are flushed, resulting in only broadcast and unicast traffic being received. A new cpsw_ale_set_allmulti function now scans through the ALE entry table and adds/removes the host port from the unregistered multicast port mask of each vlan entry depending on the state of IFF_ALLMULTI. In promiscious mode, cpsw_ale_set_allmulti is used to force reception of all multicast traffic in addition to the unicast and broadcast traffic. With this change dynamic multicast and promiscious mode both work in switch mode.

Lennart Sorensen committed 12 years ago

Commit 10738ee1 parent 35532c23 files · +49 −2Browse files

Unified · Split

3 files
  1. drivers/net/ethernet/ti/cpsw.c +18 −2
  2. drivers/net/ethernet/ti/cpsw_ale.c +29 −0
  3. drivers/net/ethernet/ti/cpsw_ale.h +2 −0
drivers/net/ethernet/ti/cpsw.c+18−2
@@ -638,12 +638,16 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev) · 637 unmodified lines
638638 if (ndev->flags & IFF_PROMISC) {
639639 /* Enable promiscuous mode */
640640 cpsw_set_promiscious(ndev, true);
641+ cpsw_ale_set_allmulti(priv->ale, IFF_ALLMULTI);
641642 return;
642643 } else {
643644 /* Disable promiscuous mode */
644645 cpsw_set_promiscious(ndev, false);
645646 }
646647
648+ /* Restore allmulti on vlans if necessary */
649+ cpsw_ale_set_allmulti(priv->ale, priv->ndev->flags & IFF_ALLMULTI);
650+
647651 /* Clear all mcast from ALE */
648652 cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port);
649653
@@ -1149,6 +1153,7 @@ static inline void cpsw_add_default_vlan(struct cpsw_priv *priv) · 499 unmodified lines
11491153 const int port = priv->host_port;
11501154 u32 reg;
11511155 int i;
1156+ int unreg_mcast_mask;
11521157
11531158 reg = (priv->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN :
11541159 CPSW2_PORT_VLAN;
@@ -1158,9 +1163,14 @@ static inline void cpsw_add_default_vlan(struct cpsw_priv *priv) · 3 unmodified lines
11581163 for (i = 0; i < priv->data.slaves; i++)
11591164 slave_write(priv->slaves + i, vlan, reg);
11601165
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+
11611171 cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port,
11621172 ALE_ALL_PORTS << port, ALE_ALL_PORTS << port,
1163− (ALE_PORT_1 | ALE_PORT_2) << port);
1173+ unreg_mcast_mask << port);
11641174 }
11651175
11661176 static 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, · 453 unmodified lines
16201630 unsigned short vid)
16211631 {
16221632 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;
16231639
16241640 ret = cpsw_ale_add_vlan(priv->ale, vid,
16251641 ALE_ALL_PORTS << priv->host_port,
16261642 0, ALE_ALL_PORTS << priv->host_port,
1627− (ALE_PORT_1 | ALE_PORT_2) << priv->host_port);
1643+ unreg_mcast_mask << priv->host_port);
16281644 if (ret != 0)
16291645 return ret;
16301646
drivers/net/ethernet/ti/cpsw_ale.c+29−0
@@ -443,6 +443,35 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) · 442 unmodified lines
443443 return 0;
444444 }
445445
446+void 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+
446475 struct ale_control_info {
447476 const char *name;
448477 int offset, port_offset;
drivers/net/ethernet/ti/cpsw_ale.h+2−0
@@ -27,6 +27,7 @@ struct cpsw_ale { · 26 unmodified lines
2727 struct cpsw_ale_params params;
2828 struct timer_list timer;
2929 unsigned long ageout;
30+ int allmulti;
3031 };
3132
3233 enum cpsw_ale_control {
@@ -103,6 +104,7 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, · 70 unmodified lines
103104 int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
104105 int reg_mcast, int unreg_mcast);
105106 int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port);
107+void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti);
106108
107109 int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control);
108110 int cpsw_ale_control_set(struct cpsw_ale *ale, int port,

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t