diff options
author | Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> | 2012-02-15 12:55:06 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-02-16 17:08:09 -0500 |
commit | 71cc7c37af71b497698f7f8a68e46a458071fcef (patch) | |
tree | 5ac6cf763fd29fe93b02b2eed8404276064d1c87 | |
parent | 6743fe6df43b4dc5950f605edfeee086d0a80f06 (diff) |
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: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/renesas/sh_eth.c | 59 | ||||
-rw-r--r-- | drivers/net/ethernet/renesas/sh_eth.h | 5 |
2 files changed, 64 insertions, 0 deletions
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 99d8ce8379c8..8615961c1287 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c | |||
@@ -1888,6 +1888,62 @@ static void sh_eth_set_multicast_list(struct net_device *ndev) | |||
1888 | 1888 | ||
1889 | spin_unlock_irqrestore(&mdp->lock, flags); | 1889 | spin_unlock_irqrestore(&mdp->lock, flags); |
1890 | } | 1890 | } |
1891 | |||
1892 | static int sh_eth_get_vtag_index(struct sh_eth_private *mdp) | ||
1893 | { | ||
1894 | if (!mdp->port) | ||
1895 | return TSU_VTAG0; | ||
1896 | else | ||
1897 | return TSU_VTAG1; | ||
1898 | } | ||
1899 | |||
1900 | static int sh_eth_vlan_rx_add_vid(struct net_device *ndev, u16 vid) | ||
1901 | { | ||
1902 | struct sh_eth_private *mdp = netdev_priv(ndev); | ||
1903 | int vtag_reg_index = sh_eth_get_vtag_index(mdp); | ||
1904 | |||
1905 | if (unlikely(!mdp->cd->tsu)) | ||
1906 | return -EPERM; | ||
1907 | |||
1908 | /* No filtering if vid = 0 */ | ||
1909 | if (!vid) | ||
1910 | return 0; | ||
1911 | |||
1912 | mdp->vlan_num_ids++; | ||
1913 | |||
1914 | /* | ||
1915 | * The controller has one VLAN tag HW filter. So, if the filter is | ||
1916 | * already enabled, the driver disables it and the filte | ||
1917 | */ | ||
1918 | if (mdp->vlan_num_ids > 1) { | ||
1919 | /* disable VLAN filter */ | ||
1920 | sh_eth_tsu_write(mdp, 0, vtag_reg_index); | ||
1921 | return 0; | ||
1922 | } | ||
1923 | |||
1924 | sh_eth_tsu_write(mdp, TSU_VTAG_ENABLE | (vid & TSU_VTAG_VID_MASK), | ||
1925 | vtag_reg_index); | ||
1926 | |||
1927 | return 0; | ||
1928 | } | ||
1929 | |||
1930 | static int sh_eth_vlan_rx_kill_vid(struct net_device *ndev, u16 vid) | ||
1931 | { | ||
1932 | struct sh_eth_private *mdp = netdev_priv(ndev); | ||
1933 | int vtag_reg_index = sh_eth_get_vtag_index(mdp); | ||
1934 | |||
1935 | if (unlikely(!mdp->cd->tsu)) | ||
1936 | return -EPERM; | ||
1937 | |||
1938 | /* No filtering if vid = 0 */ | ||
1939 | if (!vid) | ||
1940 | return 0; | ||
1941 | |||
1942 | mdp->vlan_num_ids--; | ||
1943 | sh_eth_tsu_write(mdp, 0, vtag_reg_index); | ||
1944 | |||
1945 | return 0; | ||
1946 | } | ||
1891 | #endif /* SH_ETH_HAS_TSU */ | 1947 | #endif /* SH_ETH_HAS_TSU */ |
1892 | 1948 | ||
1893 | /* SuperH's TSU register init function */ | 1949 | /* SuperH's TSU register init function */ |
@@ -2037,6 +2093,8 @@ static const struct net_device_ops sh_eth_netdev_ops = { | |||
2037 | .ndo_get_stats = sh_eth_get_stats, | 2093 | .ndo_get_stats = sh_eth_get_stats, |
2038 | #if defined(SH_ETH_HAS_TSU) | 2094 | #if defined(SH_ETH_HAS_TSU) |
2039 | .ndo_set_rx_mode = sh_eth_set_multicast_list, | 2095 | .ndo_set_rx_mode = sh_eth_set_multicast_list, |
2096 | .ndo_vlan_rx_add_vid = sh_eth_vlan_rx_add_vid, | ||
2097 | .ndo_vlan_rx_kill_vid = sh_eth_vlan_rx_kill_vid, | ||
2040 | #endif | 2098 | #endif |
2041 | .ndo_tx_timeout = sh_eth_tx_timeout, | 2099 | .ndo_tx_timeout = sh_eth_tx_timeout, |
2042 | .ndo_do_ioctl = sh_eth_do_ioctl, | 2100 | .ndo_do_ioctl = sh_eth_do_ioctl, |
@@ -2141,6 +2199,7 @@ static int sh_eth_drv_probe(struct platform_device *pdev) | |||
2141 | mdp->tsu_addr = ioremap(rtsu->start, | 2199 | mdp->tsu_addr = ioremap(rtsu->start, |
2142 | resource_size(rtsu)); | 2200 | resource_size(rtsu)); |
2143 | mdp->port = devno % 2; | 2201 | mdp->port = devno % 2; |
2202 | ndev->features = NETIF_F_HW_VLAN_FILTER; | ||
2144 | } | 2203 | } |
2145 | 2204 | ||
2146 | /* initialize first or needed device */ | 2205 | /* initialize first or needed device */ |
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index 86b392e22c01..57dc26261116 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h | |||
@@ -679,6 +679,10 @@ enum TSU_FWSLC_BIT { | |||
679 | TSU_FWSLC_CAMSEL11 = 0x0002, TSU_FWSLC_CAMSEL10 = 0x0001, | 679 | TSU_FWSLC_CAMSEL11 = 0x0002, TSU_FWSLC_CAMSEL10 = 0x0001, |
680 | }; | 680 | }; |
681 | 681 | ||
682 | /* TSU_VTAGn */ | ||
683 | #define TSU_VTAG_ENABLE 0x80000000 | ||
684 | #define TSU_VTAG_VID_MASK 0x00000fff | ||
685 | |||
682 | /* | 686 | /* |
683 | * The sh ether Tx buffer descriptors. | 687 | * The sh ether Tx buffer descriptors. |
684 | * This structure should be 20 bytes. | 688 | * This structure should be 20 bytes. |
@@ -781,6 +785,7 @@ struct sh_eth_private { | |||
781 | char post_fw; /* POST forward */ | 785 | char post_fw; /* POST forward */ |
782 | struct net_device_stats tsu_stats; /* TSU forward status */ | 786 | struct net_device_stats tsu_stats; /* TSU forward status */ |
783 | int port; /* for TSU */ | 787 | int port; /* for TSU */ |
788 | int vlan_num_ids; /* for VLAN tag filter */ | ||
784 | 789 | ||
785 | unsigned no_ether_link:1; | 790 | unsigned no_ether_link:1; |
786 | unsigned ether_link_active_low:1; | 791 | unsigned ether_link_active_low:1; |