Commit 86d70e53 authored by Jeff Kirsher's avatar Jeff Kirsher

e1000e: convert to new VLAN model

This switches the e1000e driver to use the new VLAN interfaces.

CC: Jesse Gross <jesse@nicira.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
Tested-by: default avatarJeff Pieper <jeffrey.e.pieper@intel.com>
parent a5cc7642
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#ifndef _E1000_H_ #ifndef _E1000_H_
#define _E1000_H_ #define _E1000_H_
#include <linux/bitops.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
...@@ -39,6 +40,7 @@ ...@@ -39,6 +40,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/pci-aspm.h> #include <linux/pci-aspm.h>
#include <linux/crc32.h> #include <linux/crc32.h>
#include <linux/if_vlan.h>
#include "hw.h" #include "hw.h"
...@@ -280,7 +282,7 @@ struct e1000_adapter { ...@@ -280,7 +282,7 @@ struct e1000_adapter {
const struct e1000_info *ei; const struct e1000_info *ei;
struct vlan_group *vlgrp; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
u32 bd_number; u32 bd_number;
u32 rx_buffer_len; u32 rx_buffer_len;
u16 mng_vlan_id; u16 mng_vlan_id;
......
...@@ -2020,6 +2020,31 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset, ...@@ -2020,6 +2020,31 @@ static void e1000_get_strings(struct net_device *netdev, u32 stringset,
} }
} }
static int e1000e_set_flags(struct net_device *netdev, u32 data)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
bool need_reset = false;
int rc;
need_reset = (data & ETH_FLAG_RXVLAN) !=
(netdev->features & NETIF_F_HW_VLAN_RX);
rc = ethtool_op_set_flags(netdev, data, ETH_FLAG_RXVLAN |
ETH_FLAG_TXVLAN);
if (rc)
return rc;
if (need_reset) {
if (netif_running(netdev))
e1000e_reinit_locked(adapter);
else
e1000e_reset(adapter);
}
return 0;
}
static const struct ethtool_ops e1000_ethtool_ops = { static const struct ethtool_ops e1000_ethtool_ops = {
.get_settings = e1000_get_settings, .get_settings = e1000_get_settings,
.set_settings = e1000_set_settings, .set_settings = e1000_set_settings,
...@@ -2055,6 +2080,7 @@ static const struct ethtool_ops e1000_ethtool_ops = { ...@@ -2055,6 +2080,7 @@ static const struct ethtool_ops e1000_ethtool_ops = {
.get_coalesce = e1000_get_coalesce, .get_coalesce = e1000_get_coalesce,
.set_coalesce = e1000_set_coalesce, .set_coalesce = e1000_set_coalesce,
.get_flags = ethtool_op_get_flags, .get_flags = ethtool_op_get_flags,
.set_flags = e1000e_set_flags,
}; };
void e1000e_set_ethtool_ops(struct net_device *netdev) void e1000e_set_ethtool_ops(struct net_device *netdev)
......
...@@ -459,13 +459,13 @@ static void e1000_receive_skb(struct e1000_adapter *adapter, ...@@ -459,13 +459,13 @@ static void e1000_receive_skb(struct e1000_adapter *adapter,
struct net_device *netdev, struct sk_buff *skb, struct net_device *netdev, struct sk_buff *skb,
u8 status, __le16 vlan) u8 status, __le16 vlan)
{ {
u16 tag = le16_to_cpu(vlan);
skb->protocol = eth_type_trans(skb, netdev); skb->protocol = eth_type_trans(skb, netdev);
if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) if (status & E1000_RXD_STAT_VP)
vlan_gro_receive(&adapter->napi, adapter->vlgrp, __vlan_hwaccel_put_tag(skb, tag);
le16_to_cpu(vlan), skb);
else napi_gro_receive(&adapter->napi, skb);
napi_gro_receive(&adapter->napi, skb);
} }
/** /**
...@@ -2433,6 +2433,8 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid) ...@@ -2433,6 +2433,8 @@ static void e1000_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
vfta |= (1 << (vid & 0x1F)); vfta |= (1 << (vid & 0x1F));
hw->mac.ops.write_vfta(hw, index, vfta); hw->mac.ops.write_vfta(hw, index, vfta);
} }
set_bit(vid, adapter->active_vlans);
} }
static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
...@@ -2441,13 +2443,6 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) ...@@ -2441,13 +2443,6 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
u32 vfta, index; u32 vfta, index;
if (!test_bit(__E1000_DOWN, &adapter->state))
e1000_irq_disable(adapter);
vlan_group_set_device(adapter->vlgrp, vid, NULL);
if (!test_bit(__E1000_DOWN, &adapter->state))
e1000_irq_enable(adapter);
if ((adapter->hw.mng_cookie.status & if ((adapter->hw.mng_cookie.status &
E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
(vid == adapter->mng_vlan_id)) { (vid == adapter->mng_vlan_id)) {
...@@ -2463,93 +2458,105 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid) ...@@ -2463,93 +2458,105 @@ static void e1000_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
vfta &= ~(1 << (vid & 0x1F)); vfta &= ~(1 << (vid & 0x1F));
hw->mac.ops.write_vfta(hw, index, vfta); hw->mac.ops.write_vfta(hw, index, vfta);
} }
clear_bit(vid, adapter->active_vlans);
} }
static void e1000_update_mng_vlan(struct e1000_adapter *adapter) /**
* e1000e_vlan_filter_disable - helper to disable hw VLAN filtering
* @adapter: board private structure to initialize
**/
static void e1000e_vlan_filter_disable(struct e1000_adapter *adapter)
{ {
struct net_device *netdev = adapter->netdev; struct net_device *netdev = adapter->netdev;
u16 vid = adapter->hw.mng_cookie.vlan_id; struct e1000_hw *hw = &adapter->hw;
u16 old_vid = adapter->mng_vlan_id; u32 rctl;
if (!adapter->vlgrp)
return;
if (!vlan_group_get_device(adapter->vlgrp, vid)) { if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) {
adapter->mng_vlan_id = E1000_MNG_VLAN_NONE; /* disable VLAN receive filtering */
if (adapter->hw.mng_cookie.status & rctl = er32(RCTL);
E1000_MNG_DHCP_COOKIE_STATUS_VLAN) { rctl &= ~(E1000_RCTL_VFE | E1000_RCTL_CFIEN);
e1000_vlan_rx_add_vid(netdev, vid); ew32(RCTL, rctl);
adapter->mng_vlan_id = vid;
if (adapter->mng_vlan_id != (u16)E1000_MNG_VLAN_NONE) {
e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
} }
if ((old_vid != (u16)E1000_MNG_VLAN_NONE) &&
(vid != old_vid) &&
!vlan_group_get_device(adapter->vlgrp, old_vid))
e1000_vlan_rx_kill_vid(netdev, old_vid);
} else {
adapter->mng_vlan_id = vid;
} }
} }
/**
* e1000e_vlan_filter_enable - helper to enable HW VLAN filtering
* @adapter: board private structure to initialize
**/
static void e1000e_vlan_filter_enable(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 rctl;
if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) {
/* enable VLAN receive filtering */
rctl = er32(RCTL);
rctl |= E1000_RCTL_VFE;
rctl &= ~E1000_RCTL_CFIEN;
ew32(RCTL, rctl);
}
}
static void e1000_vlan_rx_register(struct net_device *netdev, /**
struct vlan_group *grp) * e1000e_vlan_strip_enable - helper to disable HW VLAN stripping
* @adapter: board private structure to initialize
**/
static void e1000e_vlan_strip_disable(struct e1000_adapter *adapter)
{ {
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw; struct e1000_hw *hw = &adapter->hw;
u32 ctrl, rctl; u32 ctrl;
if (!test_bit(__E1000_DOWN, &adapter->state)) /* disable VLAN tag insert/strip */
e1000_irq_disable(adapter); ctrl = er32(CTRL);
adapter->vlgrp = grp; ctrl &= ~E1000_CTRL_VME;
ew32(CTRL, ctrl);
}
if (grp) { /**
/* enable VLAN tag insert/strip */ * e1000e_vlan_strip_enable - helper to enable HW VLAN stripping
ctrl = er32(CTRL); * @adapter: board private structure to initialize
ctrl |= E1000_CTRL_VME; **/
ew32(CTRL, ctrl); static void e1000e_vlan_strip_enable(struct e1000_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 ctrl;
if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { /* enable VLAN tag insert/strip */
/* enable VLAN receive filtering */ ctrl = er32(CTRL);
rctl = er32(RCTL); ctrl |= E1000_CTRL_VME;
rctl &= ~E1000_RCTL_CFIEN; ew32(CTRL, ctrl);
ew32(RCTL, rctl); }
e1000_update_mng_vlan(adapter);
}
} else {
/* disable VLAN tag insert/strip */
ctrl = er32(CTRL);
ctrl &= ~E1000_CTRL_VME;
ew32(CTRL, ctrl);
if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) { static void e1000_update_mng_vlan(struct e1000_adapter *adapter)
if (adapter->mng_vlan_id != {
(u16)E1000_MNG_VLAN_NONE) { struct net_device *netdev = adapter->netdev;
e1000_vlan_rx_kill_vid(netdev, u16 vid = adapter->hw.mng_cookie.vlan_id;
adapter->mng_vlan_id); u16 old_vid = adapter->mng_vlan_id;
adapter->mng_vlan_id = E1000_MNG_VLAN_NONE;
} if (adapter->hw.mng_cookie.status &
} E1000_MNG_DHCP_COOKIE_STATUS_VLAN) {
e1000_vlan_rx_add_vid(netdev, vid);
adapter->mng_vlan_id = vid;
} }
if (!test_bit(__E1000_DOWN, &adapter->state)) if ((old_vid != (u16)E1000_MNG_VLAN_NONE) && (vid != old_vid))
e1000_irq_enable(adapter); e1000_vlan_rx_kill_vid(netdev, old_vid);
} }
static void e1000_restore_vlan(struct e1000_adapter *adapter) static void e1000_restore_vlan(struct e1000_adapter *adapter)
{ {
u16 vid; u16 vid;
e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp); e1000_vlan_rx_add_vid(adapter->netdev, 0);
if (!adapter->vlgrp)
return;
for (vid = 0; vid < VLAN_N_VID; vid++) { for_each_set_bit(vid, adapter->active_vlans, VLAN_N_VID)
if (!vlan_group_get_device(adapter->vlgrp, vid))
continue;
e1000_vlan_rx_add_vid(adapter->netdev, vid); e1000_vlan_rx_add_vid(adapter->netdev, vid);
}
} }
static void e1000_init_manageability_pt(struct e1000_adapter *adapter) static void e1000_init_manageability_pt(struct e1000_adapter *adapter)
...@@ -3039,6 +3046,8 @@ static void e1000_set_multi(struct net_device *netdev) ...@@ -3039,6 +3046,8 @@ static void e1000_set_multi(struct net_device *netdev)
if (netdev->flags & IFF_PROMISC) { if (netdev->flags & IFF_PROMISC) {
rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE); rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
rctl &= ~E1000_RCTL_VFE; rctl &= ~E1000_RCTL_VFE;
/* Do not hardware filter VLANs in promisc mode */
e1000e_vlan_filter_disable(adapter);
} else { } else {
if (netdev->flags & IFF_ALLMULTI) { if (netdev->flags & IFF_ALLMULTI) {
rctl |= E1000_RCTL_MPE; rctl |= E1000_RCTL_MPE;
...@@ -3046,8 +3055,7 @@ static void e1000_set_multi(struct net_device *netdev) ...@@ -3046,8 +3055,7 @@ static void e1000_set_multi(struct net_device *netdev)
} else { } else {
rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE); rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
} }
if (adapter->flags & FLAG_HAS_HW_VLAN_FILTER) e1000e_vlan_filter_enable(adapter);
rctl |= E1000_RCTL_VFE;
} }
ew32(RCTL, rctl); ew32(RCTL, rctl);
...@@ -3072,6 +3080,11 @@ static void e1000_set_multi(struct net_device *netdev) ...@@ -3072,6 +3080,11 @@ static void e1000_set_multi(struct net_device *netdev)
*/ */
e1000_update_mc_addr_list(hw, NULL, 0); e1000_update_mc_addr_list(hw, NULL, 0);
} }
if (netdev->features & NETIF_F_HW_VLAN_RX)
e1000e_vlan_strip_enable(adapter);
else
e1000e_vlan_strip_disable(adapter);
} }
/** /**
...@@ -3721,10 +3734,8 @@ static int e1000_close(struct net_device *netdev) ...@@ -3721,10 +3734,8 @@ static int e1000_close(struct net_device *netdev)
* kill manageability vlan ID if supported, but not if a vlan with * kill manageability vlan ID if supported, but not if a vlan with
* the same ID is registered on the host OS (let 8021q kill it) * the same ID is registered on the host OS (let 8021q kill it)
*/ */
if ((adapter->hw.mng_cookie.status & if (adapter->hw.mng_cookie.status &
E1000_MNG_DHCP_COOKIE_STATUS_VLAN) && E1000_MNG_DHCP_COOKIE_STATUS_VLAN)
!(adapter->vlgrp &&
vlan_group_get_device(adapter->vlgrp, adapter->mng_vlan_id)))
e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id); e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
/* /*
...@@ -5759,7 +5770,6 @@ static const struct net_device_ops e1000e_netdev_ops = { ...@@ -5759,7 +5770,6 @@ static const struct net_device_ops e1000e_netdev_ops = {
.ndo_tx_timeout = e1000_tx_timeout, .ndo_tx_timeout = e1000_tx_timeout,
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
.ndo_vlan_rx_register = e1000_vlan_rx_register,
.ndo_vlan_rx_add_vid = e1000_vlan_rx_add_vid, .ndo_vlan_rx_add_vid = e1000_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = e1000_vlan_rx_kill_vid, .ndo_vlan_rx_kill_vid = e1000_vlan_rx_kill_vid,
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment