aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/myri10ge
diff options
context:
space:
mode:
authorAndrew Gallatin <gallatin@myri.com>2007-09-17 14:37:42 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:47:47 -0400
commit1e6e9342d41ff80ced0ad5dfcf084926700cdfc5 (patch)
treef4890526db54f9c8821e2d3e366d116d44b1712a /drivers/net/myri10ge
parentd4dc4ec9d84e0578b9bfbe56a11fafdb7cbac771 (diff)
[MYRI10GE]: Use LRO.
Singed off by: Andrew Gallatin <gallatin@myri.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/myri10ge')
-rw-r--r--drivers/net/myri10ge/myri10ge.c109
1 files changed, 108 insertions, 1 deletions
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index a30146ea51f0..48b23c592406 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -48,6 +48,7 @@
48#include <linux/etherdevice.h> 48#include <linux/etherdevice.h>
49#include <linux/if_ether.h> 49#include <linux/if_ether.h>
50#include <linux/if_vlan.h> 50#include <linux/if_vlan.h>
51#include <linux/inet_lro.h>
51#include <linux/ip.h> 52#include <linux/ip.h>
52#include <linux/inet.h> 53#include <linux/inet.h>
53#include <linux/in.h> 54#include <linux/in.h>
@@ -62,6 +63,8 @@
62#include <linux/io.h> 63#include <linux/io.h>
63#include <linux/log2.h> 64#include <linux/log2.h>
64#include <net/checksum.h> 65#include <net/checksum.h>
66#include <net/ip.h>
67#include <net/tcp.h>
65#include <asm/byteorder.h> 68#include <asm/byteorder.h>
66#include <asm/io.h> 69#include <asm/io.h>
67#include <asm/processor.h> 70#include <asm/processor.h>
@@ -89,6 +92,8 @@ MODULE_LICENSE("Dual BSD/GPL");
89 92
90#define MYRI10GE_EEPROM_STRINGS_SIZE 256 93#define MYRI10GE_EEPROM_STRINGS_SIZE 256
91#define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2) 94#define MYRI10GE_MAX_SEND_DESC_TSO ((65536 / 2048) * 2)
95#define MYRI10GE_MAX_LRO_DESCRIPTORS 8
96#define MYRI10GE_LRO_MAX_PKTS 64
92 97
93#define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff) 98#define MYRI10GE_NO_CONFIRM_DATA htonl(0xffffffff)
94#define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff 99#define MYRI10GE_NO_RESPONSE_RESULT 0xffffffff
@@ -151,6 +156,8 @@ struct myri10ge_rx_done {
151 dma_addr_t bus; 156 dma_addr_t bus;
152 int cnt; 157 int cnt;
153 int idx; 158 int idx;
159 struct net_lro_mgr lro_mgr;
160 struct net_lro_desc lro_desc[MYRI10GE_MAX_LRO_DESCRIPTORS];
154}; 161};
155 162
156struct myri10ge_priv { 163struct myri10ge_priv {
@@ -278,6 +285,14 @@ static int myri10ge_debug = -1; /* defaults above */
278module_param(myri10ge_debug, int, 0); 285module_param(myri10ge_debug, int, 0);
279MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)"); 286MODULE_PARM_DESC(myri10ge_debug, "Debug level (0=none,...,16=all)");
280 287
288static int myri10ge_lro = 1;
289module_param(myri10ge_lro, int, S_IRUGO);
290MODULE_PARM_DESC(myri10ge_lro, "Enable large receive offload\n");
291
292static int myri10ge_lro_max_pkts = MYRI10GE_LRO_MAX_PKTS;
293module_param(myri10ge_lro_max_pkts, int, S_IRUGO);
294MODULE_PARM_DESC(myri10ge_lro, "Number of LRO packets to be aggregated\n");
295
281static int myri10ge_fill_thresh = 256; 296static int myri10ge_fill_thresh = 256;
282module_param(myri10ge_fill_thresh, int, S_IRUGO | S_IWUSR); 297module_param(myri10ge_fill_thresh, int, S_IRUGO | S_IWUSR);
283MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed\n"); 298MODULE_PARM_DESC(myri10ge_fill_thresh, "Number of empty rx slots allowed\n");
@@ -1021,6 +1036,15 @@ myri10ge_rx_done(struct myri10ge_priv *mgp, struct myri10ge_rx_buf *rx,
1021 remainder -= MYRI10GE_ALLOC_SIZE; 1036 remainder -= MYRI10GE_ALLOC_SIZE;
1022 } 1037 }
1023 1038
1039 if (mgp->csum_flag && myri10ge_lro) {
1040 rx_frags[0].page_offset += MXGEFW_PAD;
1041 rx_frags[0].size -= MXGEFW_PAD;
1042 len -= MXGEFW_PAD;
1043 lro_receive_frags(&mgp->rx_done.lro_mgr, rx_frags,
1044 len, len, (void *)(unsigned long)csum, csum);
1045 return 1;
1046 }
1047
1024 hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN; 1048 hlen = MYRI10GE_HLEN > len ? len : MYRI10GE_HLEN;
1025 1049
1026 /* allocate an skb to attach the page(s) to. */ 1050 /* allocate an skb to attach the page(s) to. */
@@ -1136,6 +1160,9 @@ static inline int myri10ge_clean_rx_done(struct myri10ge_priv *mgp, int budget)
1136 mgp->stats.rx_packets += rx_packets; 1160 mgp->stats.rx_packets += rx_packets;
1137 mgp->stats.rx_bytes += rx_bytes; 1161 mgp->stats.rx_bytes += rx_bytes;
1138 1162
1163 if (myri10ge_lro)
1164 lro_flush_all(&rx_done->lro_mgr);
1165
1139 /* restock receive rings if needed */ 1166 /* restock receive rings if needed */
1140 if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt < myri10ge_fill_thresh) 1167 if (mgp->rx_small.fill_cnt - mgp->rx_small.cnt < myri10ge_fill_thresh)
1141 myri10ge_alloc_rx_pages(mgp, &mgp->rx_small, 1168 myri10ge_alloc_rx_pages(mgp, &mgp->rx_small,
@@ -1373,7 +1400,8 @@ static const char myri10ge_gstrings_stats[][ETH_GSTRING_LEN] = {
1373 "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32", 1400 "dropped_pause", "dropped_bad_phy", "dropped_bad_crc32",
1374 "dropped_unicast_filtered", "dropped_multicast_filtered", 1401 "dropped_unicast_filtered", "dropped_multicast_filtered",
1375 "dropped_runt", "dropped_overrun", "dropped_no_small_buffer", 1402 "dropped_runt", "dropped_overrun", "dropped_no_small_buffer",
1376 "dropped_no_big_buffer" 1403 "dropped_no_big_buffer", "LRO aggregated", "LRO flushed",
1404 "LRO avg aggr", "LRO no_desc"
1377}; 1405};
1378 1406
1379#define MYRI10GE_NET_STATS_LEN 21 1407#define MYRI10GE_NET_STATS_LEN 21
@@ -1439,6 +1467,14 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
1439 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun); 1467 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_overrun);
1440 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer); 1468 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_small_buffer);
1441 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_big_buffer); 1469 data[i++] = (unsigned int)ntohl(mgp->fw_stats->dropped_no_big_buffer);
1470 data[i++] = mgp->rx_done.lro_mgr.stats.aggregated;
1471 data[i++] = mgp->rx_done.lro_mgr.stats.flushed;
1472 if (mgp->rx_done.lro_mgr.stats.flushed)
1473 data[i++] = mgp->rx_done.lro_mgr.stats.aggregated /
1474 mgp->rx_done.lro_mgr.stats.flushed;
1475 else
1476 data[i++] = 0;
1477 data[i++] = mgp->rx_done.lro_mgr.stats.no_desc;
1442} 1478}
1443 1479
1444static void myri10ge_set_msglevel(struct net_device *netdev, u32 value) 1480static void myri10ge_set_msglevel(struct net_device *netdev, u32 value)
@@ -1712,10 +1748,69 @@ static void myri10ge_free_irq(struct myri10ge_priv *mgp)
1712 pci_disable_msi(pdev); 1748 pci_disable_msi(pdev);
1713} 1749}
1714 1750
1751static int
1752myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
1753 void **ip_hdr, void **tcpudp_hdr,
1754 u64 * hdr_flags, void *priv)
1755{
1756 struct ethhdr *eh;
1757 struct vlan_ethhdr *veh;
1758 struct iphdr *iph;
1759 u8 *va = page_address(frag->page) + frag->page_offset;
1760 unsigned long ll_hlen;
1761 __wsum csum = (__wsum) (unsigned long)priv;
1762
1763 /* find the mac header, aborting if not IPv4 */
1764
1765 eh = (struct ethhdr *)va;
1766 *mac_hdr = eh;
1767 ll_hlen = ETH_HLEN;
1768 if (eh->h_proto != htons(ETH_P_IP)) {
1769 if (eh->h_proto == htons(ETH_P_8021Q)) {
1770 veh = (struct vlan_ethhdr *)va;
1771 if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
1772 return -1;
1773
1774 ll_hlen += VLAN_HLEN;
1775
1776 /*
1777 * HW checksum starts ETH_HLEN bytes into
1778 * frame, so we must subtract off the VLAN
1779 * header's checksum before csum can be used
1780 */
1781 csum = csum_sub(csum, csum_partial(va + ETH_HLEN,
1782 VLAN_HLEN, 0));
1783 } else {
1784 return -1;
1785 }
1786 }
1787 *hdr_flags = LRO_IPV4;
1788
1789 iph = (struct iphdr *)(va + ll_hlen);
1790 *ip_hdr = iph;
1791 if (iph->protocol != IPPROTO_TCP)
1792 return -1;
1793 *hdr_flags |= LRO_TCP;
1794 *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2);
1795
1796 /* verify the IP checksum */
1797 if (unlikely(ip_fast_csum((u8 *) iph, iph->ihl)))
1798 return -1;
1799
1800 /* verify the checksum */
1801 if (unlikely(csum_tcpudp_magic(iph->saddr, iph->daddr,
1802 ntohs(iph->tot_len) - (iph->ihl << 2),
1803 IPPROTO_TCP, csum)))
1804 return -1;
1805
1806 return 0;
1807}
1808
1715static int myri10ge_open(struct net_device *dev) 1809static int myri10ge_open(struct net_device *dev)
1716{ 1810{
1717 struct myri10ge_priv *mgp; 1811 struct myri10ge_priv *mgp;
1718 struct myri10ge_cmd cmd; 1812 struct myri10ge_cmd cmd;
1813 struct net_lro_mgr *lro_mgr;
1719 int status, big_pow2; 1814 int status, big_pow2;
1720 1815
1721 mgp = netdev_priv(dev); 1816 mgp = netdev_priv(dev);
@@ -1847,6 +1942,18 @@ static int myri10ge_open(struct net_device *dev)
1847 mgp->link_state = htonl(~0U); 1942 mgp->link_state = htonl(~0U);
1848 mgp->rdma_tags_available = 15; 1943 mgp->rdma_tags_available = 15;
1849 1944
1945 lro_mgr = &mgp->rx_done.lro_mgr;
1946 lro_mgr->dev = dev;
1947 lro_mgr->features = LRO_F_NAPI;
1948 lro_mgr->ip_summed = CHECKSUM_COMPLETE;
1949 lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
1950 lro_mgr->max_desc = MYRI10GE_MAX_LRO_DESCRIPTORS;
1951 lro_mgr->lro_arr = mgp->rx_done.lro_desc;
1952 lro_mgr->get_frag_header = myri10ge_get_frag_header;
1953 lro_mgr->max_aggr = myri10ge_lro_max_pkts;
1954 if (lro_mgr->max_aggr > MAX_SKB_FRAGS)
1955 lro_mgr->max_aggr = MAX_SKB_FRAGS;
1956
1850 napi_enable(&mgp->napi); /* must happen prior to any irq */ 1957 napi_enable(&mgp->napi); /* must happen prior to any irq */
1851 1958
1852 status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0); 1959 status = myri10ge_send_cmd(mgp, MXGEFW_CMD_ETHERNET_UP, &cmd, 0);