Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 71cc7c37 authored by Yoshihiro Shimoda's avatar Yoshihiro Shimoda Committed by David S. Miller
Browse files

net: sh_eth: add support for VLAN tag filtering



Some controllers have TSU. It can register one VLAN tag, and it can
filter other VLAN tag by hardware.
If vlan_rx_add_vid() is called twice or more, the driver will disable
the filtering.

Signed-off-by: default avatarYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6743fe6d
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
@@ -1888,6 +1888,62 @@ static void sh_eth_set_multicast_list(struct net_device *ndev)

	spin_unlock_irqrestore(&mdp->lock, flags);
}

static int sh_eth_get_vtag_index(struct sh_eth_private *mdp)
{
	if (!mdp->port)
		return TSU_VTAG0;
	else
		return TSU_VTAG1;
}

static int sh_eth_vlan_rx_add_vid(struct net_device *ndev, u16 vid)
{
	struct sh_eth_private *mdp = netdev_priv(ndev);
	int vtag_reg_index = sh_eth_get_vtag_index(mdp);

	if (unlikely(!mdp->cd->tsu))
		return -EPERM;

	/* No filtering if vid = 0 */
	if (!vid)
		return 0;

	mdp->vlan_num_ids++;

	/*
	 * The controller has one VLAN tag HW filter. So, if the filter is
	 * already enabled, the driver disables it and the filte
	 */
	if (mdp->vlan_num_ids > 1) {
		/* disable VLAN filter */
		sh_eth_tsu_write(mdp, 0, vtag_reg_index);
		return 0;
	}

	sh_eth_tsu_write(mdp, TSU_VTAG_ENABLE | (vid & TSU_VTAG_VID_MASK),
			 vtag_reg_index);

	return 0;
}

static int sh_eth_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
{
	struct sh_eth_private *mdp = netdev_priv(ndev);
	int vtag_reg_index = sh_eth_get_vtag_index(mdp);

	if (unlikely(!mdp->cd->tsu))
		return -EPERM;

	/* No filtering if vid = 0 */
	if (!vid)
		return 0;

	mdp->vlan_num_ids--;
	sh_eth_tsu_write(mdp, 0, vtag_reg_index);

	return 0;
}
#endif /* SH_ETH_HAS_TSU */

/* SuperH's TSU register init function */
@@ -2037,6 +2093,8 @@ static const struct net_device_ops sh_eth_netdev_ops = {
	.ndo_get_stats		= sh_eth_get_stats,
#if defined(SH_ETH_HAS_TSU)
	.ndo_set_rx_mode	= sh_eth_set_multicast_list,
	.ndo_vlan_rx_add_vid	= sh_eth_vlan_rx_add_vid,
	.ndo_vlan_rx_kill_vid	= sh_eth_vlan_rx_kill_vid,
#endif
	.ndo_tx_timeout		= sh_eth_tx_timeout,
	.ndo_do_ioctl		= sh_eth_do_ioctl,
@@ -2141,6 +2199,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev)
		mdp->tsu_addr = ioremap(rtsu->start,
					resource_size(rtsu));
		mdp->port = devno % 2;
		ndev->features = NETIF_F_HW_VLAN_FILTER;
	}

	/* initialize first or needed device */
+5 −0
Original line number Diff line number Diff line
@@ -679,6 +679,10 @@ enum TSU_FWSLC_BIT {
	TSU_FWSLC_CAMSEL11 = 0x0002, TSU_FWSLC_CAMSEL10 = 0x0001,
};

/* TSU_VTAGn */
#define TSU_VTAG_ENABLE		0x80000000
#define TSU_VTAG_VID_MASK	0x00000fff

/*
 * The sh ether Tx buffer descriptors.
 * This structure should be 20 bytes.
@@ -781,6 +785,7 @@ struct sh_eth_private {
	char post_fw;		/* POST forward */
	struct net_device_stats tsu_stats;	/* TSU forward status */
	int port;		/* for TSU */
	int vlan_num_ids;	/* for VLAN tag filter */

	unsigned no_ether_link:1;
	unsigned ether_link_active_low:1;