diff options
author | Amit Kumar Salecha <amit.salecha@qlogic.com> | 2010-09-16 15:14:39 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-09-17 14:26:09 -0400 |
commit | d57906633efd58ccd93f056ed436ffde5cb31aa8 (patch) | |
tree | 59a319066931683e8b9ed0feeef0c483fcb5b068 /drivers/net/qlcnic | |
parent | 0c796f91a518480fd6696ba2affed1167e840823 (diff) |
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')
-rw-r--r-- | drivers/net/qlcnic/qlcnic.h | 1 | ||||
-rw-r--r-- | drivers/net/qlcnic/qlcnic_init.c | 59 | ||||
-rw-r--r-- | drivers/net/qlcnic/qlcnic_main.c | 10 |
3 files changed, 44 insertions, 26 deletions
diff --git a/drivers/net/qlcnic/qlcnic.h b/drivers/net/qlcnic/qlcnic.h index cc8385a6727e..c8caec90b31b 100644 --- a/drivers/net/qlcnic/qlcnic.h +++ b/drivers/net/qlcnic/qlcnic.h | |||
@@ -1013,6 +1013,7 @@ struct qlcnic_adapter { | |||
1013 | 1013 | ||
1014 | u64 dev_rst_time; | 1014 | u64 dev_rst_time; |
1015 | 1015 | ||
1016 | struct vlan_group *vlgrp; | ||
1016 | struct qlcnic_npar_info *npars; | 1017 | struct qlcnic_npar_info *npars; |
1017 | struct qlcnic_eswitch *eswitch; | 1018 | struct qlcnic_eswitch *eswitch; |
1018 | struct qlcnic_nic_template *nic_ops; | 1019 | struct qlcnic_nic_template *nic_ops; |
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, | |||
1380 | } | 1380 | } |
1381 | 1381 | ||
1382 | static int | 1382 | static int |
1383 | qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb) | 1383 | qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb, |
1384 | u16 *vlan_tag) | ||
1384 | { | 1385 | { |
1385 | u16 vlan_tag; | ||
1386 | struct ethhdr *eth_hdr; | 1386 | struct ethhdr *eth_hdr; |
1387 | 1387 | ||
1388 | if (!__vlan_get_tag(skb, &vlan_tag)) { | 1388 | if (!__vlan_get_tag(skb, vlan_tag)) { |
1389 | if (vlan_tag == adapter->pvid) { | 1389 | eth_hdr = (struct ethhdr *) skb->data; |
1390 | /* strip the tag from the packet and send it up */ | 1390 | memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2); |
1391 | eth_hdr = (struct ethhdr *) skb->data; | 1391 | skb_pull(skb, VLAN_HLEN); |
1392 | memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2); | 1392 | } |
1393 | skb_pull(skb, VLAN_HLEN); | 1393 | if (!adapter->pvid) |
1394 | return 0; | 1394 | return 0; |
1395 | } | 1395 | |
1396 | if (*vlan_tag == adapter->pvid) { | ||
1397 | /* Outer vlan tag. Packet should follow non-vlan path */ | ||
1398 | *vlan_tag = 0xffff; | ||
1399 | return 0; | ||
1396 | } | 1400 | } |
1397 | if (adapter->flags & QLCNIC_TAGGING_ENABLED) | 1401 | if (adapter->flags & QLCNIC_TAGGING_ENABLED) |
1398 | return 0; | 1402 | return 0; |
1399 | 1403 | ||
1400 | return -EIO; | 1404 | return -EINVAL; |
1401 | } | 1405 | } |
1402 | 1406 | ||
1403 | static struct qlcnic_rx_buffer * | 1407 | static struct qlcnic_rx_buffer * |
@@ -1411,6 +1415,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter, | |||
1411 | struct sk_buff *skb; | 1415 | struct sk_buff *skb; |
1412 | struct qlcnic_host_rds_ring *rds_ring; | 1416 | struct qlcnic_host_rds_ring *rds_ring; |
1413 | int index, length, cksum, pkt_offset; | 1417 | int index, length, cksum, pkt_offset; |
1418 | u16 vid = 0xffff; | ||
1414 | 1419 | ||
1415 | if (unlikely(ring >= adapter->max_rds_rings)) | 1420 | if (unlikely(ring >= adapter->max_rds_rings)) |
1416 | return NULL; | 1421 | return NULL; |
@@ -1441,17 +1446,18 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter, | |||
1441 | 1446 | ||
1442 | skb->truesize = skb->len + sizeof(struct sk_buff); | 1447 | skb->truesize = skb->len + sizeof(struct sk_buff); |
1443 | 1448 | ||
1444 | if (unlikely(adapter->pvid)) { | 1449 | if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { |
1445 | if (qlcnic_check_rx_tagging(adapter, skb)) { | 1450 | adapter->stats.rxdropped++; |
1446 | adapter->stats.rxdropped++; | 1451 | dev_kfree_skb(skb); |
1447 | dev_kfree_skb_any(skb); | 1452 | return buffer; |
1448 | return buffer; | ||
1449 | } | ||
1450 | } | 1453 | } |
1451 | 1454 | ||
1452 | skb->protocol = eth_type_trans(skb, netdev); | 1455 | skb->protocol = eth_type_trans(skb, netdev); |
1453 | 1456 | ||
1454 | napi_gro_receive(&sds_ring->napi, skb); | 1457 | if ((vid != 0xffff) && adapter->vlgrp) |
1458 | vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vid); | ||
1459 | else | ||
1460 | napi_gro_receive(&sds_ring->napi, skb); | ||
1455 | 1461 | ||
1456 | adapter->stats.rx_pkts++; | 1462 | adapter->stats.rx_pkts++; |
1457 | adapter->stats.rxbytes += length; | 1463 | adapter->stats.rxbytes += length; |
@@ -1480,6 +1486,7 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, | |||
1480 | int index; | 1486 | int index; |
1481 | u16 lro_length, length, data_offset; | 1487 | u16 lro_length, length, data_offset; |
1482 | u32 seq_number; | 1488 | u32 seq_number; |
1489 | u16 vid = 0xffff; | ||
1483 | 1490 | ||
1484 | if (unlikely(ring > adapter->max_rds_rings)) | 1491 | if (unlikely(ring > adapter->max_rds_rings)) |
1485 | return NULL; | 1492 | return NULL; |
@@ -1514,13 +1521,12 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, | |||
1514 | 1521 | ||
1515 | skb_pull(skb, l2_hdr_offset); | 1522 | skb_pull(skb, l2_hdr_offset); |
1516 | 1523 | ||
1517 | if (unlikely(adapter->pvid)) { | 1524 | if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { |
1518 | if (qlcnic_check_rx_tagging(adapter, skb)) { | 1525 | adapter->stats.rxdropped++; |
1519 | adapter->stats.rxdropped++; | 1526 | dev_kfree_skb(skb); |
1520 | dev_kfree_skb_any(skb); | 1527 | return buffer; |
1521 | return buffer; | ||
1522 | } | ||
1523 | } | 1528 | } |
1529 | |||
1524 | skb->protocol = eth_type_trans(skb, netdev); | 1530 | skb->protocol = eth_type_trans(skb, netdev); |
1525 | 1531 | ||
1526 | iph = (struct iphdr *)skb->data; | 1532 | iph = (struct iphdr *)skb->data; |
@@ -1535,7 +1541,10 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter, | |||
1535 | 1541 | ||
1536 | length = skb->len; | 1542 | length = skb->len; |
1537 | 1543 | ||
1538 | netif_receive_skb(skb); | 1544 | if ((vid != 0xffff) && adapter->vlgrp) |
1545 | vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vid); | ||
1546 | else | ||
1547 | netif_receive_skb(skb); | ||
1539 | 1548 | ||
1540 | adapter->stats.lro_pkts++; | 1549 | adapter->stats.lro_pkts++; |
1541 | adapter->stats.lrobytes += length; | 1550 | adapter->stats.lrobytes += length; |
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c index 5fd2abd1eb67..9eb0ced1ffab 100644 --- a/drivers/net/qlcnic/qlcnic_main.c +++ b/drivers/net/qlcnic/qlcnic_main.c | |||
@@ -371,6 +371,13 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p) | |||
371 | return 0; | 371 | return 0; |
372 | } | 372 | } |
373 | 373 | ||
374 | static void qlcnic_vlan_rx_register(struct net_device *netdev, | ||
375 | struct vlan_group *grp) | ||
376 | { | ||
377 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | ||
378 | adapter->vlgrp = grp; | ||
379 | } | ||
380 | |||
374 | static const struct net_device_ops qlcnic_netdev_ops = { | 381 | static const struct net_device_ops qlcnic_netdev_ops = { |
375 | .ndo_open = qlcnic_open, | 382 | .ndo_open = qlcnic_open, |
376 | .ndo_stop = qlcnic_close, | 383 | .ndo_stop = qlcnic_close, |
@@ -381,6 +388,7 @@ static const struct net_device_ops qlcnic_netdev_ops = { | |||
381 | .ndo_set_mac_address = qlcnic_set_mac, | 388 | .ndo_set_mac_address = qlcnic_set_mac, |
382 | .ndo_change_mtu = qlcnic_change_mtu, | 389 | .ndo_change_mtu = qlcnic_change_mtu, |
383 | .ndo_tx_timeout = qlcnic_tx_timeout, | 390 | .ndo_tx_timeout = qlcnic_tx_timeout, |
391 | .ndo_vlan_rx_register = qlcnic_vlan_rx_register, | ||
384 | #ifdef CONFIG_NET_POLL_CONTROLLER | 392 | #ifdef CONFIG_NET_POLL_CONTROLLER |
385 | .ndo_poll_controller = qlcnic_poll_controller, | 393 | .ndo_poll_controller = qlcnic_poll_controller, |
386 | #endif | 394 | #endif |
@@ -1446,7 +1454,7 @@ qlcnic_setup_netdev(struct qlcnic_adapter *adapter, | |||
1446 | SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops); | 1454 | SET_ETHTOOL_OPS(netdev, &qlcnic_ethtool_ops); |
1447 | 1455 | ||
1448 | netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | | 1456 | netdev->features |= (NETIF_F_SG | NETIF_F_IP_CSUM | |
1449 | NETIF_F_IPV6_CSUM | NETIF_F_GRO); | 1457 | NETIF_F_IPV6_CSUM | NETIF_F_GRO | NETIF_F_HW_VLAN_RX); |
1450 | netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | | 1458 | netdev->vlan_features |= (NETIF_F_SG | NETIF_F_IP_CSUM | |
1451 | NETIF_F_IPV6_CSUM); | 1459 | NETIF_F_IPV6_CSUM); |
1452 | 1460 | ||