Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
#include <linux/if_vlan.h>

/*
 * General definitions...
@@ -2052,7 +2053,7 @@ struct ql_adapter {

	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 */
	struct pci_dev *pdev;
+91 −70
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
 */
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/bitops.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/list.h>
@@ -33,6 +34,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/skbuff.h>
#include <linux/if_vlan.h>
#include <linux/delay.h>
@@ -415,7 +417,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
				      (qdev->
				       func << CAM_OUT_FUNC_SHIFT) |
					(0 << CAM_OUT_CQ_ID_SHIFT));
			if (qdev->vlgrp)
			if (qdev->ndev->features & NETIF_F_HW_VLAN_RX)
				cam_output |= CAM_OUT_RV;
			/* route to NIC core */
			ql_write32(qdev, MAC_ADDR_DATA, cam_output);
@@ -1507,9 +1509,8 @@ static void ql_process_mac_rx_gro_page(struct ql_adapter *qdev,
	rx_ring->rx_bytes += length;
	skb->ip_summed = CHECKSUM_UNNECESSARY;
	skb_record_rx_queue(skb, rx_ring->cq_id);
	if (qdev->vlgrp && (vlan_id != 0xffff))
		vlan_gro_frags(&rx_ring->napi, qdev->vlgrp, vlan_id);
	else
	if (vlan_id != 0xffff)
		__vlan_hwaccel_put_tag(skb, vlan_id);
	napi_gro_frags(napi);
}

@@ -1594,17 +1595,12 @@ static void ql_process_mac_rx_page(struct ql_adapter *qdev,
	}

	skb_record_rx_queue(skb, rx_ring->cq_id);
	if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
		if (qdev->vlgrp && (vlan_id != 0xffff))
			vlan_gro_receive(napi, qdev->vlgrp, vlan_id, skb);
		else
	if (vlan_id != 0xffff)
		__vlan_hwaccel_put_tag(skb, vlan_id);
	if (skb->ip_summed == CHECKSUM_UNNECESSARY)
		napi_gro_receive(napi, skb);
	} else {
		if (qdev->vlgrp && (vlan_id != 0xffff))
			vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id);
	else
		netif_receive_skb(skb);
	}
	return;
err_out:
	dev_kfree_skb_any(skb);
@@ -1707,19 +1703,13 @@ static void ql_process_mac_rx_skb(struct ql_adapter *qdev,
	}

	skb_record_rx_queue(skb, rx_ring->cq_id);
	if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
		if (qdev->vlgrp && (vlan_id != 0xffff))
			vlan_gro_receive(&rx_ring->napi, qdev->vlgrp,
						vlan_id, skb);
		else
	if (vlan_id != 0xffff)
		__vlan_hwaccel_put_tag(skb, vlan_id);
	if (skb->ip_summed == CHECKSUM_UNNECESSARY)
		napi_gro_receive(&rx_ring->napi, skb);
	} else {
		if (qdev->vlgrp && (vlan_id != 0xffff))
			vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id);
	else
		netif_receive_skb(skb);
}
}

static void ql_realign_skb(struct sk_buff *skb, int len)
{
@@ -2028,23 +2018,13 @@ static void ql_process_mac_split_rx_intr(struct ql_adapter *qdev,
	rx_ring->rx_packets++;
	rx_ring->rx_bytes += skb->len;
	skb_record_rx_queue(skb, rx_ring->cq_id);
	if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
		if (qdev->vlgrp &&
			(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) &&
			(vlan_id != 0))
			vlan_gro_receive(&rx_ring->napi, qdev->vlgrp,
				vlan_id, skb);
		else
	if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) && (vlan_id != 0))
		__vlan_hwaccel_put_tag(skb, vlan_id);
	if (skb->ip_summed == CHECKSUM_UNNECESSARY)
		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
		netif_receive_skb(skb);
}
}

/* Process an inbound completion from an rx ring. */
static unsigned long ql_process_mac_rx_intr(struct ql_adapter *qdev,
@@ -2334,71 +2314,111 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget)
	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);

	qdev->vlgrp = grp;
	if (grp) {
		netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
	if (features & NETIF_F_HW_VLAN_RX) {
		netif_printk(qdev, ifup, KERN_DEBUG, ndev,
			     "Turning on VLAN in NIC_RCV_CFG.\n");
		ql_write32(qdev, NIC_RCV_CFG, NIC_RCV_CFG_VLAN_MASK |
				 NIC_RCV_CFG_VLAN_MATCH_AND_NON);
	} else {
		netif_printk(qdev, ifup, KERN_DEBUG, qdev->ndev,
		netif_printk(qdev, ifup, KERN_DEBUG, ndev,
			     "Turning off VLAN in NIC_RCV_CFG.\n");
		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;
	int status;

	status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
	if (status)
		return;
	if (ql_set_mac_addr_reg
	    (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) {
		netif_err(qdev, ifup, qdev->ndev,
			  "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);
	u32 enable_bit = 0;
	int status;

	status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
	if (status)
		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
	    (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) {
		netif_err(qdev, ifup, qdev->ndev,
			  "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)
{
	qlge_vlan_rx_register(qdev->ndev, qdev->vlgrp);

	if (qdev->vlgrp) {
	int status;
	u16 vid;
		for (vid = 0; vid < VLAN_N_VID; vid++) {
			if (!vlan_group_get_device(qdev->vlgrp, vid))
				continue;
			qlge_vlan_rx_add_vid(qdev->ndev, vid);
		}
	}

	status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
	if (status)
		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. */
@@ -4661,7 +4681,8 @@ static const struct net_device_ops qlge_netdev_ops = {
	.ndo_set_mac_address	= qlge_set_mac_address,
	.ndo_validate_addr	= eth_validate_addr,
	.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_kill_vid	= qlge_vlan_rx_kill_vid,
};