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.

Signed-off-by: Len Sorensen <lsorense@csclub.uwaterloo.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Lennart Sorensen
2014-10-31 13:38:52 -04:00
committed by David S. Miller
parent 6f979eb3fc
commit 1e5c4bc497
3 changed files with 49 additions and 2 deletions

View File

@@ -443,6 +443,35 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
return 0;
}
void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti)
{
u32 ale_entry[ALE_ENTRY_WORDS];
int type, idx;
int unreg_mcast = 0;
/* Only bother doing the work if the setting is actually changing */
if (ale->allmulti == allmulti)
return;
/* Remember the new setting to check against next time */
ale->allmulti = allmulti;
for (idx = 0; idx < ale->params.ale_entries; idx++) {
cpsw_ale_read(ale, idx, ale_entry);
type = cpsw_ale_get_entry_type(ale_entry);
if (type != ALE_TYPE_VLAN)
continue;
unreg_mcast = cpsw_ale_get_vlan_unreg_mcast(ale_entry);
if (allmulti)
unreg_mcast |= 1;
else
unreg_mcast &= ~1;
cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast);
cpsw_ale_write(ale, idx, ale_entry);
}
}
struct ale_control_info {
const char *name;
int offset, port_offset;