drivers: net: ethernet: cpsw: add multicast address to ALE table
Adding multicast address to ALE table via netdev ops to subscribe, transmit or receive multicast frames to and from the network Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
8ef29f8aae
commit
5c50a856d5
|
@ -70,6 +70,8 @@ do { \
|
|||
dev_notice(priv->dev, format, ## __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define ALE_ALL_PORTS 0x7
|
||||
|
||||
#define CPSW_MAJOR_VERSION(reg) (reg >> 8 & 0x7)
|
||||
#define CPSW_MINOR_VERSION(reg) (reg & 0xff)
|
||||
#define CPSW_RTL_VERSION(reg) ((reg >> 11) & 0x1f)
|
||||
|
@ -228,6 +230,30 @@ struct cpsw_priv {
|
|||
(func)((priv)->slaves + idx, ##arg); \
|
||||
} while (0)
|
||||
|
||||
static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
|
||||
{
|
||||
struct cpsw_priv *priv = netdev_priv(ndev);
|
||||
|
||||
if (ndev->flags & IFF_PROMISC) {
|
||||
/* Enable promiscuous mode */
|
||||
dev_err(priv->dev, "Ignoring Promiscuous mode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear all mcast from ALE */
|
||||
cpsw_ale_flush_multicast(priv->ale, ALE_ALL_PORTS << priv->host_port);
|
||||
|
||||
if (!netdev_mc_empty(ndev)) {
|
||||
struct netdev_hw_addr *ha;
|
||||
|
||||
/* program multicast address list into ALE register */
|
||||
netdev_for_each_mc_addr(ha, ndev) {
|
||||
cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr,
|
||||
ALE_ALL_PORTS << priv->host_port, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void cpsw_intr_enable(struct cpsw_priv *priv)
|
||||
{
|
||||
__raw_writel(0xFF, &priv->ss_regs->tx_en);
|
||||
|
@ -673,6 +699,7 @@ static const struct net_device_ops cpsw_netdev_ops = {
|
|||
.ndo_change_mtu = eth_change_mtu,
|
||||
.ndo_tx_timeout = cpsw_ndo_tx_timeout,
|
||||
.ndo_get_stats = cpsw_ndo_get_stats,
|
||||
.ndo_set_rx_mode = cpsw_ndo_set_rx_mode,
|
||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||
.ndo_poll_controller = cpsw_ndo_poll_controller,
|
||||
#endif
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
#include "cpsw_ale.h"
|
||||
|
||||
|
@ -211,10 +212,34 @@ static void cpsw_ale_flush_mcast(struct cpsw_ale *ale, u32 *ale_entry,
|
|||
mask &= ~port_mask;
|
||||
|
||||
/* free if only remaining port is host port */
|
||||
if (mask == BIT(ale->params.ale_ports))
|
||||
cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
|
||||
else
|
||||
if (mask)
|
||||
cpsw_ale_set_port_mask(ale_entry, mask);
|
||||
else
|
||||
cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
|
||||
}
|
||||
|
||||
int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask)
|
||||
{
|
||||
u32 ale_entry[ALE_ENTRY_WORDS];
|
||||
int ret, idx;
|
||||
|
||||
for (idx = 0; idx < ale->params.ale_entries; idx++) {
|
||||
cpsw_ale_read(ale, idx, ale_entry);
|
||||
ret = cpsw_ale_get_entry_type(ale_entry);
|
||||
if (ret != ALE_TYPE_ADDR && ret != ALE_TYPE_VLAN_ADDR)
|
||||
continue;
|
||||
|
||||
if (cpsw_ale_get_mcast(ale_entry)) {
|
||||
u8 addr[6];
|
||||
|
||||
cpsw_ale_get_addr(ale_entry, addr);
|
||||
if (!is_broadcast_ether_addr(addr))
|
||||
cpsw_ale_flush_mcast(ale, ale_entry, port_mask);
|
||||
}
|
||||
|
||||
cpsw_ale_write(ale, idx, ale_entry);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry,
|
||||
|
|
|
@ -80,6 +80,7 @@ void cpsw_ale_stop(struct cpsw_ale *ale);
|
|||
|
||||
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_multicast(struct cpsw_ale *ale, int port_mask);
|
||||
int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags);
|
||||
int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port);
|
||||
int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
|
||||
|
|
Loading…
Reference in a new issue