Skip to content

Commit

Permalink
qlcnic: support vlan rx accleration
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Amit Kumar Salecha authored and David S. Miller committed Sep 17, 2010
1 parent 0c796f9 commit d579066
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 26 deletions.
1 change: 1 addition & 0 deletions drivers/net/qlcnic/qlcnic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
59 changes: 34 additions & 25 deletions drivers/net/qlcnic/qlcnic_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
10 changes: 9 additions & 1 deletion drivers/net/qlcnic/qlcnic_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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);

Expand Down

0 comments on commit d579066

Please sign in to comment.