summaryrefslogtreecommitdiffstats
path: root/drivers/net/qlcnic/qlcnic_init.c
diff options
context:
space:
mode:
authorAmit Kumar Salecha <amit.salecha@qlogic.com>2010-09-16 21:14:39 +0200
committerDavid S. Miller <davem@davemloft.net>2010-09-17 20:26:09 +0200
commitd57906633efd58ccd93f056ed436ffde5cb31aa8 (patch)
tree59a319066931683e8b9ed0feeef0c483fcb5b068 /drivers/net/qlcnic/qlcnic_init.c
parentdrivers/net/tulip/de4x5.c: fix union member name in DE4X5_GET_REG ioctl (diff)
downloadlinux-d57906633efd58ccd93f056ed436ffde5cb31aa8.tar.xz
linux-d57906633efd58ccd93f056ed436ffde5cb31aa8.zip
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: Amit Kumar Salecha <amit.salecha@qlogic.com> Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/qlcnic/qlcnic_init.c')
-rw-r--r--drivers/net/qlcnic/qlcnic_init.c59
1 files changed, 34 insertions, 25 deletions
diff --git a/drivers/net/qlcnic/qlcnic_init.c b/drivers/net/qlcnic/qlcnic_init.c
index 26a7d6bca5c7..10cebb15ccd4 100644
--- a/drivers/net/qlcnic/qlcnic_init.c
+++ b/drivers/net/qlcnic/qlcnic_init.c
@@ -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 */
- eth_hdr = (struct ethhdr *) skb->data;
- memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
- skb_pull(skb, VLAN_HLEN);
- return 0;
- }
+ 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);
+ }
+ 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,17 +1446,18 @@ 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)) {
- adapter->stats.rxdropped++;
- dev_kfree_skb_any(skb);
- return buffer;
- }
+ if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+ adapter->stats.rxdropped++;
+ dev_kfree_skb(skb);
+ return buffer;
}
skb->protocol = eth_type_trans(skb, netdev);
- napi_gro_receive(&sds_ring->napi, skb);
+ 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++;
adapter->stats.rxbytes += length;
@@ -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)) {
- adapter->stats.rxdropped++;
- dev_kfree_skb_any(skb);
- return buffer;
- }
+ if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+ adapter->stats.rxdropped++;
+ dev_kfree_skb(skb);
+ return buffer;
}
+
skb->protocol = eth_type_trans(skb, netdev);
iph = (struct iphdr *)skb->data;
@@ -1535,7 +1541,10 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
length = skb->len;
- netif_receive_skb(skb);
+ if ((vid != 0xffff) && adapter->vlgrp)
+ vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vid);
+ else
+ netif_receive_skb(skb);
adapter->stats.lro_pkts++;
adapter->stats.lrobytes += length;