Skip to content

Commit

Permalink
net: sh_eth: add support for VLAN tag filtering
Browse files Browse the repository at this point in the history
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: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Yoshihiro Shimoda authored and David S. Miller committed Feb 16, 2012
1 parent 6743fe6 commit 71cc7c3
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 0 deletions.
59 changes: 59 additions & 0 deletions drivers/net/ethernet/renesas/sh_eth.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 */
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/ethernet/renesas/sh_eth.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 71cc7c3

Please sign in to comment.