Commit 9d6a5e07 authored by Justin Chen's avatar Justin Chen Committed by Stefan Bader

net: bcmgenet: use promisc for unsupported filters

BugLink: https://bugs.launchpad.net/bugs/1840081

[ Upstream commit 35cbef98 ]

Currently we silently ignore filters if we cannot meet the filter
requirements. This will lead to the MAC dropping packets that are
expected to pass. A better solution would be to set the NIC to promisc
mode when the required filters cannot be met.

Also correct the number of MDF filters supported. It should be 17,
not 16.
Signed-off-by: default avatarJustin Chen <justinpopo6@gmail.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarConnor Kuehl <connor.kuehl@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent 232b691e
...@@ -3090,39 +3090,42 @@ static void bcmgenet_timeout(struct net_device *dev) ...@@ -3090,39 +3090,42 @@ static void bcmgenet_timeout(struct net_device *dev)
netif_tx_wake_all_queues(dev); netif_tx_wake_all_queues(dev);
} }
#define MAX_MC_COUNT 16 #define MAX_MDF_FILTER 17
static inline void bcmgenet_set_mdf_addr(struct bcmgenet_priv *priv, static inline void bcmgenet_set_mdf_addr(struct bcmgenet_priv *priv,
unsigned char *addr, unsigned char *addr,
int *i, int *i)
int *mc)
{ {
u32 reg;
bcmgenet_umac_writel(priv, addr[0] << 8 | addr[1], bcmgenet_umac_writel(priv, addr[0] << 8 | addr[1],
UMAC_MDF_ADDR + (*i * 4)); UMAC_MDF_ADDR + (*i * 4));
bcmgenet_umac_writel(priv, addr[2] << 24 | addr[3] << 16 | bcmgenet_umac_writel(priv, addr[2] << 24 | addr[3] << 16 |
addr[4] << 8 | addr[5], addr[4] << 8 | addr[5],
UMAC_MDF_ADDR + ((*i + 1) * 4)); UMAC_MDF_ADDR + ((*i + 1) * 4));
reg = bcmgenet_umac_readl(priv, UMAC_MDF_CTRL);
reg |= (1 << (MAX_MC_COUNT - *mc));
bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL);
*i += 2; *i += 2;
(*mc)++;
} }
static void bcmgenet_set_rx_mode(struct net_device *dev) static void bcmgenet_set_rx_mode(struct net_device *dev)
{ {
struct bcmgenet_priv *priv = netdev_priv(dev); struct bcmgenet_priv *priv = netdev_priv(dev);
struct netdev_hw_addr *ha; struct netdev_hw_addr *ha;
int i, mc; int i, nfilter;
u32 reg; u32 reg;
netif_dbg(priv, hw, dev, "%s: %08X\n", __func__, dev->flags); netif_dbg(priv, hw, dev, "%s: %08X\n", __func__, dev->flags);
/* Promiscuous mode */ /* Number of filters needed */
nfilter = netdev_uc_count(dev) + netdev_mc_count(dev) + 2;
/*
* Turn on promicuous mode for three scenarios
* 1. IFF_PROMISC flag is set
* 2. IFF_ALLMULTI flag is set
* 3. The number of filters needed exceeds the number filters
* supported by the hardware.
*/
reg = bcmgenet_umac_readl(priv, UMAC_CMD); reg = bcmgenet_umac_readl(priv, UMAC_CMD);
if (dev->flags & IFF_PROMISC) { if ((dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) ||
(nfilter > MAX_MDF_FILTER)) {
reg |= CMD_PROMISC; reg |= CMD_PROMISC;
bcmgenet_umac_writel(priv, reg, UMAC_CMD); bcmgenet_umac_writel(priv, reg, UMAC_CMD);
bcmgenet_umac_writel(priv, 0, UMAC_MDF_CTRL); bcmgenet_umac_writel(priv, 0, UMAC_MDF_CTRL);
...@@ -3132,32 +3135,24 @@ static void bcmgenet_set_rx_mode(struct net_device *dev) ...@@ -3132,32 +3135,24 @@ static void bcmgenet_set_rx_mode(struct net_device *dev)
bcmgenet_umac_writel(priv, reg, UMAC_CMD); bcmgenet_umac_writel(priv, reg, UMAC_CMD);
} }
/* UniMac doesn't support ALLMULTI */
if (dev->flags & IFF_ALLMULTI) {
netdev_warn(dev, "ALLMULTI is not supported\n");
return;
}
/* update MDF filter */ /* update MDF filter */
i = 0; i = 0;
mc = 0;
/* Broadcast */ /* Broadcast */
bcmgenet_set_mdf_addr(priv, dev->broadcast, &i, &mc); bcmgenet_set_mdf_addr(priv, dev->broadcast, &i);
/* my own address.*/ /* my own address.*/
bcmgenet_set_mdf_addr(priv, dev->dev_addr, &i, &mc); bcmgenet_set_mdf_addr(priv, dev->dev_addr, &i);
/* Unicast list*/
if (netdev_uc_count(dev) > (MAX_MC_COUNT - mc))
return;
if (!netdev_uc_empty(dev)) /* Unicast */
netdev_for_each_uc_addr(ha, dev) netdev_for_each_uc_addr(ha, dev)
bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc); bcmgenet_set_mdf_addr(priv, ha->addr, &i);
/* Multicast */
if (netdev_mc_empty(dev) || netdev_mc_count(dev) >= (MAX_MC_COUNT - mc))
return;
/* Multicast */
netdev_for_each_mc_addr(ha, dev) netdev_for_each_mc_addr(ha, dev)
bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc); bcmgenet_set_mdf_addr(priv, ha->addr, &i);
/* Enable filters */
reg = GENMASK(MAX_MDF_FILTER - 1, MAX_MDF_FILTER - nfilter);
bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL);
} }
/* Set the hardware MAC address. */ /* Set the hardware MAC address. */
......
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