Commit 18c49b91 authored by Jiri Pirko's avatar Jiri Pirko Committed by David S. Miller

qlge: do vlan cleanup

- unify vlan and nonvlan path
- kill qdev->vlgrp and qlge_vlan_rx_register
- allow to turn on/off rx/tx vlan accel via ethtool (set_features)
Signed-off-by: default avatarJiri Pirko <jpirko@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f1b553fb
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/if_vlan.h>
/* /*
* General definitions... * General definitions...
...@@ -2052,7 +2053,7 @@ struct ql_adapter { ...@@ -2052,7 +2053,7 @@ struct ql_adapter {
struct nic_stats nic_stats; struct nic_stats nic_stats;
struct vlan_group *vlgrp; unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
/* PCI Configuration information for this device */ /* PCI Configuration information for this device */
struct pci_dev *pdev; struct pci_dev *pdev;
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/bitops.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/list.h> #include <linux/list.h>
...@@ -33,6 +34,7 @@ ...@@ -33,6 +34,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/delay.h> #include <linux/delay.h>
...@@ -415,7 +417,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type, ...@@ -415,7 +417,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
(qdev-> (qdev->
func << CAM_OUT_FUNC_SHIFT) | func << CAM_OUT_FUNC_SHIFT) |
(0 << CAM_OUT_CQ_ID_SHIFT)); (0 << CAM_OUT_CQ_ID_SHIFT));
if (qdev->vlgrp) if (qdev->ndev->features & NETIF_F_HW_VLAN_RX)
cam_output |= CAM_OUT_RV; cam_output |= CAM_OUT_RV;
/* route to NIC core */ /* route to NIC core */
ql_write32(qdev, MAC_ADDR_DATA, cam_output); ql_write32(qdev, MAC_ADDR_DATA, cam_output);
...@@ -1507,9 +1509,8 @@ static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev, ...@@ -1507,9 +1509,8 @@ static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev,
rx_ring->rx_bytes += length; rx_ring->rx_bytes += length;
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
skb_record_rx_queue(skb, rx_ring->cq_id); skb_record_rx_queue(skb, rx_ring->cq_id);
if (qdev->vlgrp && (vlan_id != 0xffff)) if (vlan_id != 0xffff)
vlan_gro_frags(&rx_ring->napi, qdev->vlgrp, vlan_id); __vlan_hwaccel_put_tag(skb, vlan_id);
else
napi_gro_frags(napi); napi_gro_frags(napi);
} }
...@@ -1594,17 +1595,12 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev, ...@@ -1594,17 +1595,12 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,
} }
skb_record_rx_queue(skb, rx_ring->cq_id); skb_record_rx_queue(skb, rx_ring->cq_id);
if (skb->ip_summed == CHECKSUM_UNNECESSARY) { if (vlan_id != 0xffff)
if (qdev->vlgrp && (vlan_id != 0xffff)) __vlan_hwaccel_put_tag(skb, vlan_id);
vlan_gro_receive(napi, qdev->vlgrp, vlan_id, skb); if (skb->ip_summed == CHECKSUM_UNNECESSARY)
else
napi_gro_receive(napi, skb); napi_gro_receive(napi, skb);
} else {
if (qdev->vlgrp && (vlan_id != 0xffff))
vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id);
else else
netif_receive_skb(skb); netif_receive_skb(skb);
}
return; return;
err_out: err_out:
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
...@@ -1707,18 +1703,12 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev, ...@@ -1707,18 +1703,12 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
} }
skb_record_rx_queue(skb, rx_ring->cq_id); skb_record_rx_queue(skb, rx_ring->cq_id);
if (skb->ip_summed == CHECKSUM_UNNECESSARY) { if (vlan_id != 0xffff)
if (qdev->vlgrp && (vlan_id != 0xffff)) __vlan_hwaccel_put_tag(skb, vlan_id);
vlan_gro_receive(&rx_ring->napi, qdev->vlgrp, if (skb->ip_summed == CHECKSUM_UNNECESSARY)
vlan_id, skb);
else
napi_gro_receive(&rx_ring->napi, skb); napi_gro_receive(&rx_ring->napi, skb);
} else {
if (qdev->vlgrp && (vlan_id != 0xffff))
vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id);
else else
netif_receive_skb(skb); netif_receive_skb(skb);
}
} }
static void ql_realign_skb(struct sk_buff *skb, int len) static void ql_realign_skb(struct sk_buff *skb, int len)
...@@ -2028,22 +2018,12 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev, ...@@ -2028,22 +2018,12 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
rx_ring->rx_packets++; rx_ring->rx_packets++;
rx_ring->rx_bytes += skb->len; rx_ring->rx_bytes += skb->len;
skb_record_rx_queue(skb, rx_ring->cq_id); skb_record_rx_queue(skb, rx_ring->cq_id);
if (skb->ip_summed == CHECKSUM_UNNECESSARY) { if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) && (vlan_id != 0))
if (qdev->vlgrp && __vlan_hwaccel_put_tag(skb, vlan_id);
(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) && if (skb->ip_summed == CHECKSUM_UNNECESSARY)
(vlan_id != 0))
vlan_gro_receive(&rx_ring->napi, qdev->vlgrp,
vlan_id, skb);
else
napi_gro_receive(&rx_ring->napi, skb); napi_gro_receive(&rx_ring->napi, skb);
} else {
if (qdev->vlgrp &&
(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) &&
(vlan_id != 0))
vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id);
else else
netif_receive_skb(skb); netif_receive_skb(skb);
}
} }
/* Process an inbound completion from an rx ring. */ /* Process an inbound completion from an rx ring. */
...@@ -2334,71 +2314,111 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget) ...@@ -2334,71 +2314,111 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget)
return work_done; return work_done;
} }
static void qlge_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp) static void qlge_vlan_mode(struct net_device *ndev, u32 features)
{ {
struct ql_adapter *qdev = netdev_priv(ndev); struct ql_adapter *qdev = netdev_priv(ndev);
qdev->vlgrp = grp; if (features & NETIF_F_HW_VLAN_RX) {
if (grp) { netif_printk(qdev, ifup, KERN_DEBUG, ndev,
netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
"Turning on VLAN in NIC_RCV_CFG.\n"); "Turning on VLAN in NIC_RCV_CFG.\n");
ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK | ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK |
NIC_RCV_CFG_VLAN_MATCH_AND_NON); NIC_RCV_CFG_VLAN_MATCH_AND_NON);
} else { } else {
netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev, netif_printk(qdev, ifup, KERN_DEBUG, ndev,
"Turning off VLAN in NIC_RCV_CFG.\n"); "Turning off VLAN in NIC_RCV_CFG.\n");
ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK); ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK);
} }
} }
static void qlge_vlan_rx_add_vid(struct net_device *ndev, u16 vid) static u32 qlge_fix_features(struct net_device *ndev, u32 features)
{
/*
* Since there is no support for separate rx/tx vlan accel
* enable/disable make sure tx flag is always in same state as rx.
*/
if (features & NETIF_F_HW_VLAN_RX)
features |= NETIF_F_HW_VLAN_TX;
else
features &= ~NETIF_F_HW_VLAN_TX;
return features;
}
static int qlge_set_features(struct net_device *ndev, u32 features)
{
u32 changed = ndev->features ^ features;
if (changed & NETIF_F_HW_VLAN_RX)
qlge_vlan_mode(ndev, features);
return 0;
}
static void __qlge_vlan_rx_add_vid(struct ql_adapter *qdev, u16 vid)
{ {
struct ql_adapter *qdev = netdev_priv(ndev);
u32 enable_bit = MAC_ADDR_E; u32 enable_bit = MAC_ADDR_E;
int status;
status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
if (status)
return;
if (ql_set_mac_addr_reg if (ql_set_mac_addr_reg
(qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) { (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) {
netif_err(qdev, ifup, qdev->ndev, netif_err(qdev, ifup, qdev->ndev,
"Failed to init vlan address.\n"); "Failed to init vlan address.\n");
} }
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
} }
static void qlge_vlan_rx_kill_vid(struct net_device *ndev, u16 vid) static void qlge_vlan_rx_add_vid(struct net_device *ndev, u16 vid)
{ {
struct ql_adapter *qdev = netdev_priv(ndev); struct ql_adapter *qdev = netdev_priv(ndev);
u32 enable_bit = 0;
int status; int status;
status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
if (status) if (status)
return; return;
__qlge_vlan_rx_add_vid(qdev, vid);
set_bit(vid, qdev->active_vlans);
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
}
static void __qlge_vlan_rx_kill_vid(struct ql_adapter *qdev, u16 vid)
{
u32 enable_bit = 0;
if (ql_set_mac_addr_reg if (ql_set_mac_addr_reg
(qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) { (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) {
netif_err(qdev, ifup, qdev->ndev, netif_err(qdev, ifup, qdev->ndev,
"Failed to clear vlan address.\n"); "Failed to clear vlan address.\n");
} }
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); }
static void qlge_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
{
struct ql_adapter *qdev = netdev_priv(ndev);
int status;
status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
if (status)
return;
__qlge_vlan_rx_kill_vid(qdev, vid);
clear_bit(vid, qdev->active_vlans);
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
} }
static void qlge_restore_vlan(struct ql_adapter *qdev) static void qlge_restore_vlan(struct ql_adapter *qdev)
{ {
qlge_vlan_rx_register(qdev->ndev, qdev->vlgrp); int status;
if (qdev->vlgrp) {
u16 vid; u16 vid;
for (vid = 0; vid < VLAN_N_VID; vid++) {
if (!vlan_group_get_device(qdev->vlgrp, vid)) status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
continue; if (status)
qlge_vlan_rx_add_vid(qdev->ndev, vid); return;
}
} for_each_set_bit(vid, qdev->active_vlans, VLAN_N_VID)
__qlge_vlan_rx_add_vid(qdev, vid);
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
} }
/* MSI-X Multiple Vector Interrupt Handler for inbound completions. */ /* MSI-X Multiple Vector Interrupt Handler for inbound completions. */
...@@ -4661,7 +4681,8 @@ static const struct net_device_ops qlge_netdev_ops = { ...@@ -4661,7 +4681,8 @@ static const struct net_device_ops qlge_netdev_ops = {
.ndo_set_mac_address = qlge_set_mac_address, .ndo_set_mac_address = qlge_set_mac_address,
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
.ndo_tx_timeout = qlge_tx_timeout, .ndo_tx_timeout = qlge_tx_timeout,
.ndo_vlan_rx_register = qlge_vlan_rx_register, .ndo_fix_features = qlge_fix_features,
.ndo_set_features = qlge_set_features,
.ndo_vlan_rx_add_vid = qlge_vlan_rx_add_vid, .ndo_vlan_rx_add_vid = qlge_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = qlge_vlan_rx_kill_vid, .ndo_vlan_rx_kill_vid = qlge_vlan_rx_kill_vid,
}; };
......
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