Commit c89f44ff authored by Chuah, Kim Tatt's avatar Chuah, Kim Tatt Committed by David S. Miller
Browse files

net: stmmac: Add support for VLAN promiscuous mode



For dwmac4, enable VLAN promiscuity when MAC controller is requested to
enter promiscuous mode.

Signed-off-by: default avatarChuah, Kim Tatt <kim.tatt.chuah@intel.com>
Signed-off-by: default avatarOng Boon Leong <boon.leong.ong@intel.com>
Signed-off-by: default avatarTan, Tee Min <tee.min.tan@intel.com>
Signed-off-by: default avatarWong Vee Khee <vee.khee.wong@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 58e64a31
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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 {
+1 −0
Original line number Diff line number Diff line
@@ -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)
+67 −0
Original line number Diff line number Diff line
@@ -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,