diff options
author | John Crispin <john@openwrt.org> | 2014-11-19 09:19:43 +0000 |
---|---|---|
committer | John Crispin <john@openwrt.org> | 2014-11-19 09:19:43 +0000 |
commit | 9c5dfd954624992446b4f54b9eab674bb5e0d9cc (patch) | |
tree | 6a0c68e114c65887be06ba0d558cd91e3c38adfa /target/linux/ramips/files/drivers/net/ethernet/ralink/ralink_soc_eth.c | |
parent | 510ff1f1b8f7ee28986cb08381b02392847296ac (diff) | |
download | master-31e0f0ae-9c5dfd954624992446b4f54b9eab674bb5e0d9cc.tar.gz master-31e0f0ae-9c5dfd954624992446b4f54b9eab674bb5e0d9cc.tar.bz2 master-31e0f0ae-9c5dfd954624992446b4f54b9eab674bb5e0d9cc.zip |
ralink: improve tx vlan offload
hardware tx vlan offload only support max 16 vids
now use add/delete vlan interface to update vlan id table
when duplicate vlan id index detect.
disable hardware tx vlan offload support.
Signed-off-by: michael lee <igvtee@gmail.com>
SVN-Revision: 43301
Diffstat (limited to 'target/linux/ramips/files/drivers/net/ethernet/ralink/ralink_soc_eth.c')
-rw-r--r-- | target/linux/ramips/files/drivers/net/ethernet/ralink/ralink_soc_eth.c | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/target/linux/ramips/files/drivers/net/ethernet/ralink/ralink_soc_eth.c b/target/linux/ramips/files/drivers/net/ethernet/ralink/ralink_soc_eth.c index f09751040b..c62fb8f56d 100644 --- a/target/linux/ramips/files/drivers/net/ethernet/ralink/ralink_soc_eth.c +++ b/target/linux/ramips/files/drivers/net/ethernet/ralink/ralink_soc_eth.c @@ -418,6 +418,54 @@ static struct rtnl_link_stats64 *fe_get_stats64(struct net_device *dev, return storage; } +static int fe_vlan_rx_add_vid(struct net_device *dev, + __be16 proto, u16 vid) +{ + struct fe_priv *priv = netdev_priv(dev); + u32 idx = (vid & 0xf); + u32 vlan_cfg; + + if (!((fe_reg_table[FE_REG_FE_DMA_VID_BASE]) && + (dev->features | NETIF_F_HW_VLAN_CTAG_TX))) + return 0; + + if (test_bit(idx, &priv->vlan_map)) { + netdev_warn(dev, "disable tx vlan offload\n"); + dev->wanted_features &= ~NETIF_F_HW_VLAN_CTAG_TX; + netdev_update_features(dev); + } else { + vlan_cfg = fe_r32(fe_reg_table[FE_REG_FE_DMA_VID_BASE] + + ((idx >> 1) << 2)); + if (idx & 0x1) { + vlan_cfg &= 0xffff; + vlan_cfg |= (vid << 16); + } else { + vlan_cfg &= 0xffff0000; + vlan_cfg |= vid; + } + fe_w32(vlan_cfg, fe_reg_table[FE_REG_FE_DMA_VID_BASE] + + ((idx >> 1) << 2)); + set_bit(idx, &priv->vlan_map); + } + + return 0; +} + +static int fe_vlan_rx_kill_vid(struct net_device *dev, + __be16 proto, u16 vid) +{ + struct fe_priv *priv = netdev_priv(dev); + u32 idx = (vid & 0xf); + + if (!((fe_reg_table[FE_REG_FE_DMA_VID_BASE]) && + (dev->features | NETIF_F_HW_VLAN_CTAG_TX))) + return 0; + + clear_bit(idx, &priv->vlan_map); + + return 0; +} + static int fe_tx_map_dma(struct sk_buff *skb, struct net_device *dev, int idx) { @@ -1182,6 +1230,8 @@ static const struct net_device_ops fe_netdev_ops = { .ndo_change_mtu = fe_change_mtu, .ndo_tx_timeout = fe_tx_timeout, .ndo_get_stats64 = fe_get_stats64, + .ndo_vlan_rx_add_vid = fe_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = fe_vlan_rx_kill_vid, }; static int fe_probe(struct platform_device *pdev) @@ -1237,6 +1287,10 @@ static int fe_probe(struct platform_device *pdev) ~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX); netdev->features |= netdev->hw_features; + /* fake rx vlan filter func. to support tx vlan offload func */ + if (fe_reg_table[FE_REG_FE_DMA_VID_BASE]) + netdev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + priv = netdev_priv(netdev); spin_lock_init(&priv->page_lock); if (fe_reg_table[FE_REG_FE_COUNTER_BASE]) { |