]> err.no Git - linux-2.6/blobdiff - drivers/net/ixgbe/ixgbe_main.c
Merge branch 'davem-next' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[linux-2.6] / drivers / net / ixgbe / ixgbe_main.c
index 1674b6a5b903ce83cd02c67b462e22fdc9262720..b37d618d8e2a90cc68a328d991caddfe1a1b3309 100644 (file)
@@ -389,24 +389,39 @@ static int __ixgbe_notify_dca(struct device *dev, void *data)
  * ixgbe_receive_skb - Send a completed packet up the stack
  * @adapter: board private structure
  * @skb: packet to send up
- * @is_vlan: packet has a VLAN tag
- * @tag: VLAN tag from descriptor
+ * @status: hardware indication of status of receive
+ * @rx_ring: rx descriptor ring (for a specific queue) to setup
+ * @rx_desc: rx descriptor
  **/
 static void ixgbe_receive_skb(struct ixgbe_adapter *adapter,
-                             struct sk_buff *skb, bool is_vlan,
-                             u16 tag)
+                             struct sk_buff *skb, u8 status,
+                             struct ixgbe_ring *ring,
+                              union ixgbe_adv_rx_desc *rx_desc)
 {
-       if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
-               if (adapter->vlgrp && is_vlan)
-                       vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag);
-               else
-                       netif_receive_skb(skb);
-       } else {
+       bool is_vlan = (status & IXGBE_RXD_STAT_VP);
+       u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan);
 
+       if (adapter->netdev->features & NETIF_F_LRO &&
+           skb->ip_summed == CHECKSUM_UNNECESSARY) {
                if (adapter->vlgrp && is_vlan)
-                       vlan_hwaccel_rx(skb, adapter->vlgrp, tag);
+                       lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb,
+                                                    adapter->vlgrp, tag,
+                                                    rx_desc);
                else
-                       netif_rx(skb);
+                       lro_receive_skb(&ring->lro_mgr, skb, rx_desc);
+               ring->lro_used = true;
+       } else {
+               if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
+                       if (adapter->vlgrp && is_vlan)
+                               vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag);
+                       else
+                               netif_receive_skb(skb);
+               } else {
+                       if (adapter->vlgrp && is_vlan)
+                               vlan_hwaccel_rx(skb, adapter->vlgrp, tag);
+                       else
+                               netif_rx(skb);
+               }
        }
 }
 
@@ -546,8 +561,8 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
        struct sk_buff *skb;
        unsigned int i;
        u32 upper_len, len, staterr;
-       u16 hdr_info, vlan_tag;
-       bool is_vlan, cleaned = false;
+       u16 hdr_info;
+       bool cleaned = false;
        int cleaned_count = 0;
        unsigned int total_rx_bytes = 0, total_rx_packets = 0;
 
@@ -556,8 +571,6 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
        rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
        staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
        rx_buffer_info = &rx_ring->rx_buffer_info[i];
-       is_vlan = (staterr & IXGBE_RXD_STAT_VP);
-       vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan);
 
        while (staterr & IXGBE_RXD_STAT_DD) {
                if (*work_done >= work_to_do)
@@ -635,7 +648,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
                total_rx_packets++;
 
                skb->protocol = eth_type_trans(skb, netdev);
-               ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag);
+               ixgbe_receive_skb(adapter, skb, staterr, rx_ring, rx_desc);
                netdev->last_rx = jiffies;
 
 next_desc:
@@ -652,8 +665,11 @@ next_desc:
                rx_buffer_info = next_buffer;
 
                staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
-               is_vlan = (staterr & IXGBE_RXD_STAT_VP);
-               vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan);
+       }
+
+       if (rx_ring->lro_used) {
+               lro_flush_all(&rx_ring->lro_mgr);
+               rx_ring->lro_used = false;
        }
 
        rx_ring->next_to_clean = i;
@@ -1381,6 +1397,33 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
                        (((S) & (PAGE_SIZE - 1)) ? 1 : 0))
 
 #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT                        2
+/**
+ * ixgbe_get_skb_hdr - helper function for LRO header processing
+ * @skb: pointer to sk_buff to be added to LRO packet
+ * @iphdr: pointer to tcp header structure
+ * @tcph: pointer to tcp header structure
+ * @hdr_flags: pointer to header flags
+ * @priv: private data
+ **/
+static int ixgbe_get_skb_hdr(struct sk_buff *skb, void **iphdr, void **tcph,
+                             u64 *hdr_flags, void *priv)
+{
+       union ixgbe_adv_rx_desc *rx_desc = priv;
+
+       /* Verify that this is a valid IPv4 TCP packet */
+       if (!(rx_desc->wb.lower.lo_dword.pkt_info &
+           (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_TCP)))
+               return -1;
+
+       /* Set network headers */
+       skb_reset_network_header(skb);
+       skb_set_transport_header(skb, ip_hdrlen(skb));
+       *iphdr = ip_hdr(skb);
+       *tcph = tcp_hdr(skb);
+       *hdr_flags = LRO_IPV4 | LRO_TCP;
+       return 0;
+}
+
 /**
  * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset
  * @adapter: board private structure
@@ -1470,6 +1513,17 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
                adapter->rx_ring[i].tail = IXGBE_RDT(i);
        }
 
+       /* Intitial LRO Settings */
+       adapter->rx_ring[i].lro_mgr.max_aggr = IXGBE_MAX_LRO_AGGREGATE;
+       adapter->rx_ring[i].lro_mgr.max_desc = IXGBE_MAX_LRO_DESCRIPTORS;
+       adapter->rx_ring[i].lro_mgr.get_skb_header = ixgbe_get_skb_hdr;
+       adapter->rx_ring[i].lro_mgr.features = LRO_F_EXTRACT_VLAN_ID;
+       if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL))
+               adapter->rx_ring[i].lro_mgr.features |= LRO_F_NAPI;
+       adapter->rx_ring[i].lro_mgr.dev = adapter->netdev;
+       adapter->rx_ring[i].lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
+       adapter->rx_ring[i].lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
+
        if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
                /* Fill out redirection table */
                for (i = 0, j = 0; i < 128; i++, j++) {
@@ -2490,12 +2544,18 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
        struct pci_dev *pdev = adapter->pdev;
        int size;
 
+       size = sizeof(struct net_lro_desc) * IXGBE_MAX_LRO_DESCRIPTORS;
+       rxdr->lro_mgr.lro_arr = vmalloc(size);
+       if (!rxdr->lro_mgr.lro_arr)
+               return -ENOMEM;
+       memset(rxdr->lro_mgr.lro_arr, 0, size);
+
        size = sizeof(struct ixgbe_rx_buffer) * rxdr->count;
        rxdr->rx_buffer_info = vmalloc(size);
        if (!rxdr->rx_buffer_info) {
                DPRINTK(PROBE, ERR,
                        "vmalloc allocation failed for the rx desc ring\n");
-               return -ENOMEM;
+               goto alloc_failed;
        }
        memset(rxdr->rx_buffer_info, 0, size);
 
@@ -2509,13 +2569,18 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
                DPRINTK(PROBE, ERR,
                        "Memory allocation failed for the rx desc ring\n");
                vfree(rxdr->rx_buffer_info);
-               return -ENOMEM;
+               goto alloc_failed;
        }
 
        rxdr->next_to_clean = 0;
        rxdr->next_to_use = 0;
 
        return 0;
+
+alloc_failed:
+       vfree(rxdr->lro_mgr.lro_arr);
+       rxdr->lro_mgr.lro_arr = NULL;
+       return -ENOMEM;
 }
 
 /**
@@ -2566,6 +2631,9 @@ static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter,
 {
        struct pci_dev *pdev = adapter->pdev;
 
+       vfree(rx_ring->lro_mgr.lro_arr);
+       rx_ring->lro_mgr.lro_arr = NULL;
+
        ixgbe_clean_rx_ring(adapter, rx_ring);
 
        vfree(rx_ring->rx_buffer_info);
@@ -3518,6 +3586,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
                           NETIF_F_HW_VLAN_RX |
                           NETIF_F_HW_VLAN_FILTER;
 
+       netdev->features |= NETIF_F_LRO;
        netdev->features |= NETIF_F_TSO;
        netdev->features |= NETIF_F_TSO6;