pasemi_mac: Software-based LRO support
authorOlof Johansson <olof@lixom.net>
Thu, 29 Nov 2007 02:57:27 +0000 (20:57 -0600)
committerDavid S. Miller <davem@davemloft.net>
Mon, 28 Jan 2008 23:04:24 +0000 (15:04 -0800)
pasemi_mac: Software-based LRO support

Implement LRO for pasemi_mac. Pretty straightforward.

Signed-off-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
drivers/net/Kconfig
drivers/net/pasemi_mac.c
drivers/net/pasemi_mac.h

index b034410b7ab63e520143cdd527dcb9f17bb4f0d5..477c3e45974578e7de44cb7d6295e1464fe52c20 100644 (file)
@@ -2572,6 +2572,7 @@ config PASEMI_MAC
        tristate "PA Semi 1/10Gbit MAC"
        depends on PPC64 && PCI
        select PHYLIB
        tristate "PA Semi 1/10Gbit MAC"
        depends on PPC64 && PCI
        select PHYLIB
+       select INET_LRO
        help
          This driver supports the on-chip 1/10Gbit Ethernet controller on
          PA Semi's PWRficient line of chips.
        help
          This driver supports the on-chip 1/10Gbit Ethernet controller on
          PA Semi's PWRficient line of chips.
index e78aac488f3c589832d54c643dbd3f28de0e83d9..98b639742680cd90d3dcd988035be5e0b5f573ed 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <net/checksum.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <net/checksum.h>
+#include <linux/inet_lro.h>
 
 #include <asm/irq.h>
 #include <asm/firmware.h>
 
 #include <asm/irq.h>
 #include <asm/firmware.h>
 
 
 /* Must be a power of two */
 
 
 /* Must be a power of two */
-#define RX_RING_SIZE 1024
+#define RX_RING_SIZE 2048
 #define TX_RING_SIZE 4096
 
 #define TX_RING_SIZE 4096
 
+#define LRO_MAX_AGGR 64
+
 #define DEFAULT_MSG_ENABLE       \
        (NETIF_MSG_DRV          | \
         NETIF_MSG_PROBE        | \
 #define DEFAULT_MSG_ENABLE       \
        (NETIF_MSG_DRV          | \
         NETIF_MSG_PROBE        | \
@@ -206,7 +209,6 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac)
                return -ENOENT;
        }
 
                return -ENOENT;
        }
 
-
        if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0],
                   &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) {
                dev_warn(&pdev->dev,
        if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0],
                   &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) {
                dev_warn(&pdev->dev,
@@ -219,6 +221,37 @@ static int pasemi_get_mac_addr(struct pasemi_mac *mac)
        return 0;
 }
 
        return 0;
 }
 
+static int get_skb_hdr(struct sk_buff *skb, void **iphdr,
+                      void **tcph, u64 *hdr_flags, void *data)
+{
+       u64 macrx = (u64) data;
+       unsigned int ip_len;
+       struct iphdr *iph;
+
+       /* IPv4 header checksum failed */
+       if ((macrx & XCT_MACRX_HTY_M) != XCT_MACRX_HTY_IPV4_OK)
+               return -1;
+
+       /* non tcp packet */
+       skb_reset_network_header(skb);
+       iph = ip_hdr(skb);
+       if (iph->protocol != IPPROTO_TCP)
+               return -1;
+
+       ip_len = ip_hdrlen(skb);
+       skb_set_transport_header(skb, ip_len);
+       *tcph = tcp_hdr(skb);
+
+       /* check if ip header and tcp header are complete */
+       if (iph->tot_len < ip_len + tcp_hdrlen(skb))
+               return -1;
+
+       *hdr_flags = LRO_IPV4 | LRO_TCP;
+       *iphdr = iph;
+
+       return 0;
+}
+
 static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac,
                                    struct sk_buff *skb,
                                    const dma_addr_t *dmas)
 static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac,
                                    struct sk_buff *skb,
                                    const dma_addr_t *dmas)
@@ -662,7 +695,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac_rxring *rx,
                skb_put(skb, len-4);
 
                skb->protocol = eth_type_trans(skb, mac->netdev);
                skb_put(skb, len-4);
 
                skb->protocol = eth_type_trans(skb, mac->netdev);
-               netif_receive_skb(skb);
+               lro_receive_skb(&mac->lro_mgr, skb, (void *)macrx);
 
 next:
                RX_DESC(rx, n) = 0;
 
 next:
                RX_DESC(rx, n) = 0;
@@ -684,6 +717,8 @@ next:
 
        rx_ring(mac)->next_to_clean = n;
 
 
        rx_ring(mac)->next_to_clean = n;
 
+       lro_flush_all(&mac->lro_mgr);
+
        /* Increase is in number of 16-byte entries, and since each descriptor
         * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with
         * count*2.
        /* Increase is in number of 16-byte entries, and since each descriptor
         * with an 8BRES takes up 3x8 bytes (padded to 4x8), increase with
         * count*2.
@@ -988,7 +1023,7 @@ static int pasemi_mac_open(struct net_device *dev)
                      PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0x3ff));
 
        write_iob_reg(PAS_IOB_DMA_RXCH_CFG(mac->rx->chan.chno),
                      PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0x3ff));
 
        write_iob_reg(PAS_IOB_DMA_RXCH_CFG(mac->rx->chan.chno),
-                     PAS_IOB_DMA_RXCH_CFG_CNTTH(128));
+                     PAS_IOB_DMA_RXCH_CFG_CNTTH(256));
 
        write_iob_reg(PAS_IOB_DMA_TXCH_CFG(mac->tx->chan.chno),
                      PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
 
        write_iob_reg(PAS_IOB_DMA_TXCH_CFG(mac->tx->chan.chno),
                      PAS_IOB_DMA_TXCH_CFG_CNTTH(32));
@@ -1368,6 +1403,16 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG |
                        NETIF_F_HIGHDMA;
 
        dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG |
                        NETIF_F_HIGHDMA;
 
+       mac->lro_mgr.max_aggr = LRO_MAX_AGGR;
+       mac->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS;
+       mac->lro_mgr.lro_arr = mac->lro_desc;
+       mac->lro_mgr.get_skb_header = get_skb_hdr;
+       mac->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
+       mac->lro_mgr.dev = mac->netdev;
+       mac->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
+       mac->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
+
+
        mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
        if (!mac->dma_pdev) {
                dev_err(&mac->pdev->dev, "Can't find DMA Controller\n");
        mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
        if (!mac->dma_pdev) {
                dev_err(&mac->pdev->dev, "Can't find DMA Controller\n");
index c6555edba55ddf043dc3cce1de1e81b46eef8a80..8bee2a664c83760d12a897eb4230331f6e99c229 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/spinlock.h>
 #include <linux/phy.h>
 
 #include <linux/spinlock.h>
 #include <linux/phy.h>
 
+#define MAX_LRO_DESCRIPTORS 8
+
 struct pasemi_mac_txring {
        struct pasemi_dmachan chan; /* Must be first */
        spinlock_t       lock;
 struct pasemi_mac_txring {
        struct pasemi_dmachan chan; /* Must be first */
        spinlock_t       lock;
@@ -64,7 +66,10 @@ struct pasemi_mac {
 
        u8              mac_addr[6];
 
 
        u8              mac_addr[6];
 
+       struct net_lro_mgr      lro_mgr;
+       struct net_lro_desc     lro_desc[MAX_LRO_DESCRIPTORS];
        struct timer_list       rxtimer;
        struct timer_list       rxtimer;
+       unsigned int            lro_max_aggr;
 
        struct pasemi_mac_txring *tx;
        struct pasemi_mac_rxring *rx;
 
        struct pasemi_mac_txring *tx;
        struct pasemi_mac_rxring *rx;