Commit d5790663 authored by Amit Kumar Salecha's avatar Amit Kumar Salecha Committed by David S. Miller
Browse files

qlcnic: support vlan rx accleration



Implemented vlan rx accleration in driver.
This helps in increasing significant performance and
reduces cpu utilization with GRO and LRO.

Eric Dumazet:
	"Its a bit strange you use dev_kfree_skb_any(skb) here."
	"We run in NAPI mode, so you can use dev_kfree_skb()."
Amit:
	Done. Using dev_kfree_skb();

Signed-off-by: default avatarAmit Kumar Salecha <amit.salecha@qlogic.com>
Acked-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0c796f91
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1013,6 +1013,7 @@ struct qlcnic_adapter {

	u64 dev_rst_time;

	struct vlan_group *vlgrp;
	struct qlcnic_npar_info *npars;
	struct qlcnic_eswitch *eswitch;
	struct qlcnic_nic_template *nic_ops;
+34 −25
Original line number Diff line number Diff line
@@ -1380,24 +1380,28 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
}

static int
qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb)
qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb,
			u16 *vlan_tag)
{
	u16 vlan_tag;
	struct ethhdr *eth_hdr;

	if (!__vlan_get_tag(skb, &vlan_tag)) {
		if (vlan_tag == adapter->pvid) {
			/* strip the tag from the packet and send it up */
	if (!__vlan_get_tag(skb, vlan_tag)) {
		eth_hdr = (struct ethhdr *) skb->data;
		memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
		skb_pull(skb, VLAN_HLEN);
			return 0;
	}
	if (!adapter->pvid)
		return 0;

	if (*vlan_tag == adapter->pvid) {
		/* Outer vlan tag. Packet should follow non-vlan path */
		*vlan_tag = 0xffff;
		return 0;
	}
	if (adapter->flags & QLCNIC_TAGGING_ENABLED)
		return 0;

	return -EIO;
	return -EINVAL;
}

static struct qlcnic_rx_buffer *
@@ -1411,6 +1415,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
	struct sk_buff *skb;
	struct qlcnic_host_rds_ring *rds_ring;
	int index, length, cksum, pkt_offset;
	u16 vid = 0xffff;

	if (unlikely(ring >= adapter->max_rds_rings))
		return NULL;
@@ -1441,16 +1446,17 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,

	skb->truesize = skb->len + sizeof(struct sk_buff);

	if (unlikely(adapter->pvid)) {
		if (qlcnic_check_rx_tagging(adapter, skb)) {
	if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
		adapter->stats.rxdropped++;
			dev_kfree_skb_any(skb);
		dev_kfree_skb(skb);
		return buffer;
	}
	}

	skb->protocol = eth_type_trans(skb, netdev);

	if ((vid != 0xffff) && adapter->vlgrp)
		vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vid);
	else
		napi_gro_receive(&sds_ring->napi, skb);

	adapter->stats.rx_pkts++;
@@ -1480,6 +1486,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
	int index;
	u16 lro_length, length, data_offset;
	u32 seq_number;
	u16 vid = 0xffff;

	if (unlikely(ring > adapter->max_rds_rings))
		return NULL;
@@ -1514,13 +1521,12 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,

	skb_pull(skb, l2_hdr_offset);

	if (unlikely(adapter->pvid)) {
		if (qlcnic_check_rx_tagging(adapter, skb)) {
	if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
		adapter->stats.rxdropped++;
			dev_kfree_skb_any(skb);
		dev_kfree_skb(skb);
		return buffer;
	}
	}

	skb->protocol = eth_type_trans(skb, netdev);

	iph = (struct iphdr *)skb->data;
@@ -1535,6 +1541,9 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,

	length = skb->len;

	if ((vid != 0xffff) && adapter->vlgrp)
		vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vid);
	else
		netif_receive_skb(skb);

	adapter->stats.lro_pkts++;
+9 −1
Original line number Diff line number Diff line
@@ -371,6 +371,13 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
	return 0;
}

static void qlcnic_vlan_rx_register(struct net_device *netdev,
		struct vlan_group *grp)
{
	struct qlcnic_adapter *adapter = netdev_priv(netdev);
	adapter->vlgrp = grp;
}

static const struct net_device_ops qlcnic_netdev_ops = {
	.ndo_open	   = qlcnic_open,
	.ndo_stop	   = qlcnic_close,
@@ -381,6 +388,7 @@ static const struct net_device_ops qlcnic_netdev_ops = {
	.ndo_set_mac_address    = qlcnic_set_mac,
	.ndo_change_mtu	   = qlcnic_change_mtu,
	.ndo_tx_timeout	   = qlcnic_tx_timeout,
	.ndo_vlan_rx_register = qlcnic_vlan_rx_register,
#ifdef CONFIG_NET_POLL_CONTROLLER
	.ndo_poll_controller = qlcnic_poll_controller,
#endif
@@ -1446,7 +1454,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
	SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);

	netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
		NETIF_F_IPV6_CSUM | NETIF_F_GRO);
		NETIF_F_IPV6_CSUM | NETIF_F_GRO | NETIF_F_HW_VLAN_RX);
	netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
		NETIF_F_IPV6_CSUM);