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>
This commit is contained in:
Родитель
0c796f91a5
Коммит
d57906633e
|
@ -1013,6 +1013,7 @@ struct qlcnic_adapter {
|
||||||
|
|
||||||
u64 dev_rst_time;
|
u64 dev_rst_time;
|
||||||
|
|
||||||
|
struct vlan_group *vlgrp;
|
||||||
struct qlcnic_npar_info *npars;
|
struct qlcnic_npar_info *npars;
|
||||||
struct qlcnic_eswitch *eswitch;
|
struct qlcnic_eswitch *eswitch;
|
||||||
struct qlcnic_nic_template *nic_ops;
|
struct qlcnic_nic_template *nic_ops;
|
||||||
|
|
|
@ -1380,24 +1380,28 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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;
|
struct ethhdr *eth_hdr;
|
||||||
|
|
||||||
if (!__vlan_get_tag(skb, &vlan_tag)) {
|
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;
|
eth_hdr = (struct ethhdr *) skb->data;
|
||||||
memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
|
memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
|
||||||
skb_pull(skb, VLAN_HLEN);
|
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)
|
if (adapter->flags & QLCNIC_TAGGING_ENABLED)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return -EIO;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct qlcnic_rx_buffer *
|
static struct qlcnic_rx_buffer *
|
||||||
|
@ -1411,6 +1415,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct qlcnic_host_rds_ring *rds_ring;
|
struct qlcnic_host_rds_ring *rds_ring;
|
||||||
int index, length, cksum, pkt_offset;
|
int index, length, cksum, pkt_offset;
|
||||||
|
u16 vid = 0xffff;
|
||||||
|
|
||||||
if (unlikely(ring >= adapter->max_rds_rings))
|
if (unlikely(ring >= adapter->max_rds_rings))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1441,16 +1446,17 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
|
||||||
|
|
||||||
skb->truesize = skb->len + sizeof(struct sk_buff);
|
skb->truesize = skb->len + sizeof(struct sk_buff);
|
||||||
|
|
||||||
if (unlikely(adapter->pvid)) {
|
if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
|
||||||
if (qlcnic_check_rx_tagging(adapter, skb)) {
|
|
||||||
adapter->stats.rxdropped++;
|
adapter->stats.rxdropped++;
|
||||||
dev_kfree_skb_any(skb);
|
dev_kfree_skb(skb);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
skb->protocol = eth_type_trans(skb, netdev);
|
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);
|
napi_gro_receive(&sds_ring->napi, skb);
|
||||||
|
|
||||||
adapter->stats.rx_pkts++;
|
adapter->stats.rx_pkts++;
|
||||||
|
@ -1480,6 +1486,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
|
||||||
int index;
|
int index;
|
||||||
u16 lro_length, length, data_offset;
|
u16 lro_length, length, data_offset;
|
||||||
u32 seq_number;
|
u32 seq_number;
|
||||||
|
u16 vid = 0xffff;
|
||||||
|
|
||||||
if (unlikely(ring > adapter->max_rds_rings))
|
if (unlikely(ring > adapter->max_rds_rings))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1514,13 +1521,12 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
|
||||||
|
|
||||||
skb_pull(skb, l2_hdr_offset);
|
skb_pull(skb, l2_hdr_offset);
|
||||||
|
|
||||||
if (unlikely(adapter->pvid)) {
|
if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
|
||||||
if (qlcnic_check_rx_tagging(adapter, skb)) {
|
|
||||||
adapter->stats.rxdropped++;
|
adapter->stats.rxdropped++;
|
||||||
dev_kfree_skb_any(skb);
|
dev_kfree_skb(skb);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
skb->protocol = eth_type_trans(skb, netdev);
|
skb->protocol = eth_type_trans(skb, netdev);
|
||||||
|
|
||||||
iph = (struct iphdr *)skb->data;
|
iph = (struct iphdr *)skb->data;
|
||||||
|
@ -1535,6 +1541,9 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
|
||||||
|
|
||||||
length = skb->len;
|
length = skb->len;
|
||||||
|
|
||||||
|
if ((vid != 0xffff) && adapter->vlgrp)
|
||||||
|
vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vid);
|
||||||
|
else
|
||||||
netif_receive_skb(skb);
|
netif_receive_skb(skb);
|
||||||
|
|
||||||
adapter->stats.lro_pkts++;
|
adapter->stats.lro_pkts++;
|
||||||
|
|
|
@ -371,6 +371,13 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
|
||||||
return 0;
|
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 = {
|
static const struct net_device_ops qlcnic_netdev_ops = {
|
||||||
.ndo_open = qlcnic_open,
|
.ndo_open = qlcnic_open,
|
||||||
.ndo_stop = qlcnic_close,
|
.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_set_mac_address = qlcnic_set_mac,
|
||||||
.ndo_change_mtu = qlcnic_change_mtu,
|
.ndo_change_mtu = qlcnic_change_mtu,
|
||||||
.ndo_tx_timeout = qlcnic_tx_timeout,
|
.ndo_tx_timeout = qlcnic_tx_timeout,
|
||||||
|
.ndo_vlan_rx_register = qlcnic_vlan_rx_register,
|
||||||
#ifdef CONFIG_NET_POLL_CONTROLLER
|
#ifdef CONFIG_NET_POLL_CONTROLLER
|
||||||
.ndo_poll_controller = qlcnic_poll_controller,
|
.ndo_poll_controller = qlcnic_poll_controller,
|
||||||
#endif
|
#endif
|
||||||
|
@ -1446,7 +1454,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter,
|
||||||
SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
|
SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops);
|
||||||
|
|
||||||
netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
|
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 |
|
netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM |
|
||||||
NETIF_F_IPV6_CSUM);
|
NETIF_F_IPV6_CSUM);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче