diff options
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/common.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 67 |
3 files changed, 69 insertions, 0 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 6208a68a331d..127f75862962 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -473,6 +473,7 @@ struct mac_device_info { unsigned int xlgmac; unsigned int num_vlan; u32 vlan_filter[32]; + unsigned int promisc; }; struct stmmac_rx_routing { diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index 28cac28253b8..61f3249bd724 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -90,6 +90,7 @@ #define GMAC_VLAN_CSVL BIT(19) #define GMAC_VLAN_VLC GENMASK(17, 16) #define GMAC_VLAN_VLC_SHIFT 16 +#define GMAC_VLAN_VLHT GENMASK(15, 0) /* MAC VLAN Tag */ #define GMAC_VLAN_TAG_VID GENMASK(15, 0) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 39692d15d80c..ecd834e0e121 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -450,6 +450,12 @@ static int dwmac4_add_hw_vlan_rx_fltr(struct net_device *dev, if (vid > 4095) return -EINVAL; + if (hw->promisc) { + netdev_err(dev, + "Adding VLAN in promisc mode not supported\n"); + return -EPERM; + } + /* Single Rx VLAN Filter */ if (hw->num_vlan == 1) { /* For single VLAN filter, VID 0 means VLAN promiscuous */ @@ -499,6 +505,12 @@ static int dwmac4_del_hw_vlan_rx_fltr(struct net_device *dev, { int i, ret = 0; + if (hw->promisc) { + netdev_err(dev, + "Deleting VLAN in promisc mode not supported\n"); + return -EPERM; + } + /* Single Rx VLAN Filter */ if (hw->num_vlan == 1) { if ((hw->vlan_filter[0] & GMAC_VLAN_TAG_VID) == vid) { @@ -523,9 +535,45 @@ static int dwmac4_del_hw_vlan_rx_fltr(struct net_device *dev, return ret; } +static void dwmac4_vlan_promisc_enable(struct net_device *dev, + struct mac_device_info *hw) +{ + void __iomem *ioaddr = hw->pcsr; + u32 value; + u32 hash; + u32 val; + int i; + + /* Single Rx VLAN Filter */ + if (hw->num_vlan == 1) { + dwmac4_write_single_vlan(dev, 0); + return; + } + + /* Extended Rx VLAN Filter Enable */ + for (i = 0; i < hw->num_vlan; i++) { + if (hw->vlan_filter[i] & GMAC_VLAN_TAG_DATA_VEN) { + val = hw->vlan_filter[i] & ~GMAC_VLAN_TAG_DATA_VEN; + dwmac4_write_vlan_filter(dev, hw, i, val); + } + } + + hash = readl(ioaddr + GMAC_VLAN_HASH_TABLE); + if (hash & GMAC_VLAN_VLHT) { + value = readl(ioaddr + GMAC_VLAN_TAG); + if (value & GMAC_VLAN_VTHM) { + value &= ~GMAC_VLAN_VTHM; + writel(value, ioaddr + GMAC_VLAN_TAG); + } + } +} + static void dwmac4_restore_hw_vlan_rx_fltr(struct net_device *dev, struct mac_device_info *hw) { + void __iomem *ioaddr = hw->pcsr; + u32 value; + u32 hash; u32 val; int i; @@ -542,6 +590,13 @@ static void dwmac4_restore_hw_vlan_rx_fltr(struct net_device *dev, dwmac4_write_vlan_filter(dev, hw, i, val); } } + + hash = readl(ioaddr + GMAC_VLAN_HASH_TABLE); + if (hash & GMAC_VLAN_VLHT) { + value = readl(ioaddr + GMAC_VLAN_TAG); + value |= GMAC_VLAN_VTHM; + writel(value, ioaddr + GMAC_VLAN_TAG); + } } static void dwmac4_set_filter(struct mac_device_info *hw, @@ -624,6 +679,18 @@ static void dwmac4_set_filter(struct mac_device_info *hw, value |= GMAC_PACKET_FILTER_VTFE; writel(value, ioaddr + GMAC_PACKET_FILTER); + + if (dev->flags & IFF_PROMISC) { + if (!hw->promisc) { + hw->promisc = 1; + dwmac4_vlan_promisc_enable(dev, hw); + } + } else { + if (hw->promisc) { + hw->promisc = 0; + dwmac4_restore_hw_vlan_rx_fltr(dev, hw); + } + } } static void dwmac4_flow_ctrl(struct mac_device_info *hw, unsigned int duplex, |