diff options
author | Mallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com> | 2008-06-18 18:32:19 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-06-24 23:06:19 -0400 |
commit | 177db6ffd0599430a2ab63045e88fc4031f42420 (patch) | |
tree | 1c1e0b71a9589628e8b2abd82c213e1e7d1cc34b /drivers/net/ixgbe/ixgbe_main.c | |
parent | 8f85cd7fefa3d01c4e05aac1cb198733336cf44b (diff) |
ixgbe: add LRO support
Support for in-kernel LRO with the ability to enable/disable via ethtool
based on comments from Ben Hutchings.
Signed-off-by: Mallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: PJ Waskiewicz <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/ixgbe/ixgbe_main.c')
-rw-r--r-- | drivers/net/ixgbe/ixgbe_main.c | 111 |
1 files changed, 90 insertions, 21 deletions
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 0d37c9025be4..f429c9a4754f 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c | |||
@@ -389,24 +389,39 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) | |||
389 | * ixgbe_receive_skb - Send a completed packet up the stack | 389 | * ixgbe_receive_skb - Send a completed packet up the stack |
390 | * @adapter: board private structure | 390 | * @adapter: board private structure |
391 | * @skb: packet to send up | 391 | * @skb: packet to send up |
392 | * @is_vlan: packet has a VLAN tag | 392 | * @status: hardware indication of status of receive |
393 | * @tag: VLAN tag from descriptor | 393 | * @rx_ring: rx descriptor ring (for a specific queue) to setup |
394 | * @rx_desc: rx descriptor | ||
394 | **/ | 395 | **/ |
395 | static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, | 396 | static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, |
396 | struct sk_buff *skb, bool is_vlan, | 397 | struct sk_buff *skb, u8 status, |
397 | u16 tag) | 398 | struct ixgbe_ring *ring, |
399 | union ixgbe_adv_rx_desc *rx_desc) | ||
398 | { | 400 | { |
399 | if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { | 401 | bool is_vlan = (status & IXGBE_RXD_STAT_VP); |
400 | if (adapter->vlgrp && is_vlan) | 402 | u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan); |
401 | vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); | ||
402 | else | ||
403 | netif_receive_skb(skb); | ||
404 | } else { | ||
405 | 403 | ||
404 | if (adapter->netdev->features & NETIF_F_LRO && | ||
405 | skb->ip_summed == CHECKSUM_UNNECESSARY) { | ||
406 | if (adapter->vlgrp && is_vlan) | 406 | if (adapter->vlgrp && is_vlan) |
407 | vlan_hwaccel_rx(skb, adapter->vlgrp, tag); | 407 | lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb, |
408 | adapter->vlgrp, tag, | ||
409 | rx_desc); | ||
408 | else | 410 | else |
409 | netif_rx(skb); | 411 | lro_receive_skb(&ring->lro_mgr, skb, rx_desc); |
412 | ring->lro_used = true; | ||
413 | } else { | ||
414 | if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { | ||
415 | if (adapter->vlgrp && is_vlan) | ||
416 | vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); | ||
417 | else | ||
418 | netif_receive_skb(skb); | ||
419 | } else { | ||
420 | if (adapter->vlgrp && is_vlan) | ||
421 | vlan_hwaccel_rx(skb, adapter->vlgrp, tag); | ||
422 | else | ||
423 | netif_rx(skb); | ||
424 | } | ||
410 | } | 425 | } |
411 | } | 426 | } |
412 | 427 | ||
@@ -546,8 +561,8 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, | |||
546 | struct sk_buff *skb; | 561 | struct sk_buff *skb; |
547 | unsigned int i; | 562 | unsigned int i; |
548 | u32 upper_len, len, staterr; | 563 | u32 upper_len, len, staterr; |
549 | u16 hdr_info, vlan_tag; | 564 | u16 hdr_info; |
550 | bool is_vlan, cleaned = false; | 565 | bool cleaned = false; |
551 | int cleaned_count = 0; | 566 | int cleaned_count = 0; |
552 | unsigned int total_rx_bytes = 0, total_rx_packets = 0; | 567 | unsigned int total_rx_bytes = 0, total_rx_packets = 0; |
553 | 568 | ||
@@ -556,8 +571,6 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, | |||
556 | rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); | 571 | rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); |
557 | staterr = le32_to_cpu(rx_desc->wb.upper.status_error); | 572 | staterr = le32_to_cpu(rx_desc->wb.upper.status_error); |
558 | rx_buffer_info = &rx_ring->rx_buffer_info[i]; | 573 | rx_buffer_info = &rx_ring->rx_buffer_info[i]; |
559 | is_vlan = (staterr & IXGBE_RXD_STAT_VP); | ||
560 | vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan); | ||
561 | 574 | ||
562 | while (staterr & IXGBE_RXD_STAT_DD) { | 575 | while (staterr & IXGBE_RXD_STAT_DD) { |
563 | if (*work_done >= work_to_do) | 576 | if (*work_done >= work_to_do) |
@@ -635,7 +648,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, | |||
635 | total_rx_packets++; | 648 | total_rx_packets++; |
636 | 649 | ||
637 | skb->protocol = eth_type_trans(skb, netdev); | 650 | skb->protocol = eth_type_trans(skb, netdev); |
638 | ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag); | 651 | ixgbe_receive_skb(adapter, skb, staterr, rx_ring, rx_desc); |
639 | netdev->last_rx = jiffies; | 652 | netdev->last_rx = jiffies; |
640 | 653 | ||
641 | next_desc: | 654 | next_desc: |
@@ -652,8 +665,11 @@ next_desc: | |||
652 | rx_buffer_info = next_buffer; | 665 | rx_buffer_info = next_buffer; |
653 | 666 | ||
654 | staterr = le32_to_cpu(rx_desc->wb.upper.status_error); | 667 | staterr = le32_to_cpu(rx_desc->wb.upper.status_error); |
655 | is_vlan = (staterr & IXGBE_RXD_STAT_VP); | 668 | } |
656 | vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan); | 669 | |
670 | if (rx_ring->lro_used) { | ||
671 | lro_flush_all(&rx_ring->lro_mgr); | ||
672 | rx_ring->lro_used = false; | ||
657 | } | 673 | } |
658 | 674 | ||
659 | rx_ring->next_to_clean = i; | 675 | rx_ring->next_to_clean = i; |
@@ -1382,6 +1398,33 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) | |||
1382 | 1398 | ||
1383 | #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 | 1399 | #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 |
1384 | /** | 1400 | /** |
1401 | * ixgbe_get_skb_hdr - helper function for LRO header processing | ||
1402 | * @skb: pointer to sk_buff to be added to LRO packet | ||
1403 | * @iphdr: pointer to tcp header structure | ||
1404 | * @tcph: pointer to tcp header structure | ||
1405 | * @hdr_flags: pointer to header flags | ||
1406 | * @priv: private data | ||
1407 | **/ | ||
1408 | static int ixgbe_get_skb_hdr(struct sk_buff *skb, void **iphdr, void **tcph, | ||
1409 | u64 *hdr_flags, void *priv) | ||
1410 | { | ||
1411 | union ixgbe_adv_rx_desc *rx_desc = priv; | ||
1412 | |||
1413 | /* Verify that this is a valid IPv4 TCP packet */ | ||
1414 | if (!(rx_desc->wb.lower.lo_dword.pkt_info & | ||
1415 | (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_TCP))) | ||
1416 | return -1; | ||
1417 | |||
1418 | /* Set network headers */ | ||
1419 | skb_reset_network_header(skb); | ||
1420 | skb_set_transport_header(skb, ip_hdrlen(skb)); | ||
1421 | *iphdr = ip_hdr(skb); | ||
1422 | *tcph = tcp_hdr(skb); | ||
1423 | *hdr_flags = LRO_IPV4 | LRO_TCP; | ||
1424 | return 0; | ||
1425 | } | ||
1426 | |||
1427 | /** | ||
1385 | * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset | 1428 | * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset |
1386 | * @adapter: board private structure | 1429 | * @adapter: board private structure |
1387 | * | 1430 | * |
@@ -1470,6 +1513,17 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) | |||
1470 | adapter->rx_ring[i].tail = IXGBE_RDT(i); | 1513 | adapter->rx_ring[i].tail = IXGBE_RDT(i); |
1471 | } | 1514 | } |
1472 | 1515 | ||
1516 | /* Intitial LRO Settings */ | ||
1517 | adapter->rx_ring[i].lro_mgr.max_aggr = IXGBE_MAX_LRO_AGGREGATE; | ||
1518 | adapter->rx_ring[i].lro_mgr.max_desc = IXGBE_MAX_LRO_DESCRIPTORS; | ||
1519 | adapter->rx_ring[i].lro_mgr.get_skb_header = ixgbe_get_skb_hdr; | ||
1520 | adapter->rx_ring[i].lro_mgr.features = LRO_F_EXTRACT_VLAN_ID; | ||
1521 | if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) | ||
1522 | adapter->rx_ring[i].lro_mgr.features |= LRO_F_NAPI; | ||
1523 | adapter->rx_ring[i].lro_mgr.dev = adapter->netdev; | ||
1524 | adapter->rx_ring[i].lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; | ||
1525 | adapter->rx_ring[i].lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; | ||
1526 | |||
1473 | if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { | 1527 | if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { |
1474 | /* Fill out redirection table */ | 1528 | /* Fill out redirection table */ |
1475 | for (i = 0, j = 0; i < 128; i++, j++) { | 1529 | for (i = 0, j = 0; i < 128; i++, j++) { |
@@ -2489,12 +2543,18 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, | |||
2489 | struct pci_dev *pdev = adapter->pdev; | 2543 | struct pci_dev *pdev = adapter->pdev; |
2490 | int size; | 2544 | int size; |
2491 | 2545 | ||
2546 | size = sizeof(struct net_lro_desc) * IXGBE_MAX_LRO_DESCRIPTORS; | ||
2547 | rxdr->lro_mgr.lro_arr = vmalloc(size); | ||
2548 | if (!rxdr->lro_mgr.lro_arr) | ||
2549 | return -ENOMEM; | ||
2550 | memset(rxdr->lro_mgr.lro_arr, 0, size); | ||
2551 | |||
2492 | size = sizeof(struct ixgbe_rx_buffer) * rxdr->count; | 2552 | size = sizeof(struct ixgbe_rx_buffer) * rxdr->count; |
2493 | rxdr->rx_buffer_info = vmalloc(size); | 2553 | rxdr->rx_buffer_info = vmalloc(size); |
2494 | if (!rxdr->rx_buffer_info) { | 2554 | if (!rxdr->rx_buffer_info) { |
2495 | DPRINTK(PROBE, ERR, | 2555 | DPRINTK(PROBE, ERR, |
2496 | "vmalloc allocation failed for the rx desc ring\n"); | 2556 | "vmalloc allocation failed for the rx desc ring\n"); |
2497 | return -ENOMEM; | 2557 | goto alloc_failed; |
2498 | } | 2558 | } |
2499 | memset(rxdr->rx_buffer_info, 0, size); | 2559 | memset(rxdr->rx_buffer_info, 0, size); |
2500 | 2560 | ||
@@ -2508,13 +2568,18 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, | |||
2508 | DPRINTK(PROBE, ERR, | 2568 | DPRINTK(PROBE, ERR, |
2509 | "Memory allocation failed for the rx desc ring\n"); | 2569 | "Memory allocation failed for the rx desc ring\n"); |
2510 | vfree(rxdr->rx_buffer_info); | 2570 | vfree(rxdr->rx_buffer_info); |
2511 | return -ENOMEM; | 2571 | goto alloc_failed; |
2512 | } | 2572 | } |
2513 | 2573 | ||
2514 | rxdr->next_to_clean = 0; | 2574 | rxdr->next_to_clean = 0; |
2515 | rxdr->next_to_use = 0; | 2575 | rxdr->next_to_use = 0; |
2516 | 2576 | ||
2517 | return 0; | 2577 | return 0; |
2578 | |||
2579 | alloc_failed: | ||
2580 | vfree(rxdr->lro_mgr.lro_arr); | ||
2581 | rxdr->lro_mgr.lro_arr = NULL; | ||
2582 | return -ENOMEM; | ||
2518 | } | 2583 | } |
2519 | 2584 | ||
2520 | /** | 2585 | /** |
@@ -2565,6 +2630,9 @@ static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter, | |||
2565 | { | 2630 | { |
2566 | struct pci_dev *pdev = adapter->pdev; | 2631 | struct pci_dev *pdev = adapter->pdev; |
2567 | 2632 | ||
2633 | vfree(rx_ring->lro_mgr.lro_arr); | ||
2634 | rx_ring->lro_mgr.lro_arr = NULL; | ||
2635 | |||
2568 | ixgbe_clean_rx_ring(adapter, rx_ring); | 2636 | ixgbe_clean_rx_ring(adapter, rx_ring); |
2569 | 2637 | ||
2570 | vfree(rx_ring->rx_buffer_info); | 2638 | vfree(rx_ring->rx_buffer_info); |
@@ -3517,6 +3585,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, | |||
3517 | NETIF_F_HW_VLAN_RX | | 3585 | NETIF_F_HW_VLAN_RX | |
3518 | NETIF_F_HW_VLAN_FILTER; | 3586 | NETIF_F_HW_VLAN_FILTER; |
3519 | 3587 | ||
3588 | netdev->features |= NETIF_F_LRO; | ||
3520 | netdev->features |= NETIF_F_TSO; | 3589 | netdev->features |= NETIF_F_TSO; |
3521 | netdev->features |= NETIF_F_TSO6; | 3590 | netdev->features |= NETIF_F_TSO6; |
3522 | 3591 | ||