aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/s2io.c
diff options
context:
space:
mode:
authorJeff Garzik <jeff@garzik.org>2006-03-02 14:26:30 -0500
committerJeff Garzik <jeff@garzik.org>2006-03-02 14:26:30 -0500
commit2ade43618b0aee83a50b344171d33d85c73d01b1 (patch)
tree0a49fe46159a6ef66098a4f37935412f4f226f4c /drivers/net/s2io.c
parent75e47b36004d136edff68295420424cba3a5ccd0 (diff)
parent79dc190147f8a87718fe72928d5ceb58e09acdb9 (diff)
Merge branch 'lro'
Diffstat (limited to 'drivers/net/s2io.c')
-rw-r--r--drivers/net/s2io.c589
1 files changed, 527 insertions, 62 deletions
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index da0d8a85acce..0db218c2dbeb 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -57,16 +57,20 @@
57#include <linux/ethtool.h> 57#include <linux/ethtool.h>
58#include <linux/workqueue.h> 58#include <linux/workqueue.h>
59#include <linux/if_vlan.h> 59#include <linux/if_vlan.h>
60#include <linux/ip.h>
61#include <linux/tcp.h>
62#include <net/tcp.h>
60 63
61#include <asm/system.h> 64#include <asm/system.h>
62#include <asm/uaccess.h> 65#include <asm/uaccess.h>
63#include <asm/io.h> 66#include <asm/io.h>
67#include <asm/div64.h>
64 68
65/* local include */ 69/* local include */
66#include "s2io.h" 70#include "s2io.h"
67#include "s2io-regs.h" 71#include "s2io-regs.h"
68 72
69#define DRV_VERSION "Version 2.0.9.4" 73#define DRV_VERSION "2.0.11.2"
70 74
71/* S2io Driver name & version. */ 75/* S2io Driver name & version. */
72static char s2io_driver_name[] = "Neterion"; 76static char s2io_driver_name[] = "Neterion";
@@ -168,6 +172,11 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
168 {"\n DRIVER STATISTICS"}, 172 {"\n DRIVER STATISTICS"},
169 {"single_bit_ecc_errs"}, 173 {"single_bit_ecc_errs"},
170 {"double_bit_ecc_errs"}, 174 {"double_bit_ecc_errs"},
175 ("lro_aggregated_pkts"),
176 ("lro_flush_both_count"),
177 ("lro_out_of_sequence_pkts"),
178 ("lro_flush_due_to_max_pkts"),
179 ("lro_avg_aggr_pkts"),
171}; 180};
172 181
173#define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN 182#define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN
@@ -317,6 +326,12 @@ static unsigned int indicate_max_pkts;
317static unsigned int rxsync_frequency = 3; 326static unsigned int rxsync_frequency = 3;
318/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */ 327/* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */
319static unsigned int intr_type = 0; 328static unsigned int intr_type = 0;
329/* Large receive offload feature */
330static unsigned int lro = 0;
331/* Max pkts to be aggregated by LRO at one time. If not specified,
332 * aggregation happens until we hit max IP pkt size(64K)
333 */
334static unsigned int lro_max_pkts = 0xFFFF;
320 335
321/* 336/*
322 * S2IO device table. 337 * S2IO device table.
@@ -1476,6 +1491,19 @@ static int init_nic(struct s2io_nic *nic)
1476 writel((u32) (val64 >> 32), (add + 4)); 1491 writel((u32) (val64 >> 32), (add + 4));
1477 val64 = readq(&bar0->mac_cfg); 1492 val64 = readq(&bar0->mac_cfg);
1478 1493
1494 /* Enable FCS stripping by adapter */
1495 add = &bar0->mac_cfg;
1496 val64 = readq(&bar0->mac_cfg);
1497 val64 |= MAC_CFG_RMAC_STRIP_FCS;
1498 if (nic->device_type == XFRAME_II_DEVICE)
1499 writeq(val64, &bar0->mac_cfg);
1500 else {
1501 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1502 writel((u32) (val64), add);
1503 writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key);
1504 writel((u32) (val64 >> 32), (add + 4));
1505 }
1506
1479 /* 1507 /*
1480 * Set the time value to be inserted in the pause frame 1508 * Set the time value to be inserted in the pause frame
1481 * generated by xena. 1509 * generated by xena.
@@ -2569,6 +2597,8 @@ static void rx_intr_handler(ring_info_t *ring_data)
2569#ifndef CONFIG_S2IO_NAPI 2597#ifndef CONFIG_S2IO_NAPI
2570 int pkt_cnt = 0; 2598 int pkt_cnt = 0;
2571#endif 2599#endif
2600 int i;
2601
2572 spin_lock(&nic->rx_lock); 2602 spin_lock(&nic->rx_lock);
2573 if (atomic_read(&nic->card_state) == CARD_DOWN) { 2603 if (atomic_read(&nic->card_state) == CARD_DOWN) {
2574 DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n", 2604 DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n",
@@ -2661,6 +2691,18 @@ static void rx_intr_handler(ring_info_t *ring_data)
2661 break; 2691 break;
2662#endif 2692#endif
2663 } 2693 }
2694 if (nic->lro) {
2695 /* Clear all LRO sessions before exiting */
2696 for (i=0; i<MAX_LRO_SESSIONS; i++) {
2697 lro_t *lro = &nic->lro0_n[i];
2698 if (lro->in_use) {
2699 update_L3L4_header(nic, lro);
2700 queue_rx_frame(lro->parent);
2701 clear_lro_session(lro);
2702 }
2703 }
2704 }
2705
2664 spin_unlock(&nic->rx_lock); 2706 spin_unlock(&nic->rx_lock);
2665} 2707}
2666 2708
@@ -3668,23 +3710,32 @@ s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs)
3668 * else schedule a tasklet to reallocate the buffers. 3710 * else schedule a tasklet to reallocate the buffers.
3669 */ 3711 */
3670 for (i = 0; i < config->rx_ring_num; i++) { 3712 for (i = 0; i < config->rx_ring_num; i++) {
3671 int rxb_size = atomic_read(&sp->rx_bufs_left[i]); 3713 if (!sp->lro) {
3672 int level = rx_buffer_level(sp, rxb_size, i); 3714 int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
3673 3715 int level = rx_buffer_level(sp, rxb_size, i);
3674 if ((level == PANIC) && (!TASKLET_IN_USE)) { 3716
3675 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name); 3717 if ((level == PANIC) && (!TASKLET_IN_USE)) {
3676 DBG_PRINT(INTR_DBG, "PANIC levels\n"); 3718 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ",
3677 if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) { 3719 dev->name);
3678 DBG_PRINT(ERR_DBG, "%s:Out of memory", 3720 DBG_PRINT(INTR_DBG, "PANIC levels\n");
3679 dev->name); 3721 if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
3680 DBG_PRINT(ERR_DBG, " in ISR!!\n"); 3722 DBG_PRINT(ERR_DBG, "%s:Out of memory",
3723 dev->name);
3724 DBG_PRINT(ERR_DBG, " in ISR!!\n");
3725 clear_bit(0, (&sp->tasklet_status));
3726 atomic_dec(&sp->isr_cnt);
3727 return IRQ_HANDLED;
3728 }
3681 clear_bit(0, (&sp->tasklet_status)); 3729 clear_bit(0, (&sp->tasklet_status));
3682 atomic_dec(&sp->isr_cnt); 3730 } else if (level == LOW) {
3683 return IRQ_HANDLED; 3731 tasklet_schedule(&sp->task);
3684 } 3732 }
3685 clear_bit(0, (&sp->tasklet_status)); 3733 }
3686 } else if (level == LOW) { 3734 else if (fill_rx_buffers(sp, i) == -ENOMEM) {
3687 tasklet_schedule(&sp->task); 3735 DBG_PRINT(ERR_DBG, "%s:Out of memory",
3736 dev->name);
3737 DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
3738 break;
3688 } 3739 }
3689 } 3740 }
3690 3741
@@ -3697,29 +3748,37 @@ s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs)
3697{ 3748{
3698 ring_info_t *ring = (ring_info_t *)dev_id; 3749 ring_info_t *ring = (ring_info_t *)dev_id;
3699 nic_t *sp = ring->nic; 3750 nic_t *sp = ring->nic;
3751 struct net_device *dev = (struct net_device *) dev_id;
3700 int rxb_size, level, rng_n; 3752 int rxb_size, level, rng_n;
3701 3753
3702 atomic_inc(&sp->isr_cnt); 3754 atomic_inc(&sp->isr_cnt);
3703 rx_intr_handler(ring); 3755 rx_intr_handler(ring);
3704 3756
3705 rng_n = ring->ring_no; 3757 rng_n = ring->ring_no;
3706 rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]); 3758 if (!sp->lro) {
3707 level = rx_buffer_level(sp, rxb_size, rng_n); 3759 rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]);
3708 3760 level = rx_buffer_level(sp, rxb_size, rng_n);
3709 if ((level == PANIC) && (!TASKLET_IN_USE)) { 3761
3710 int ret; 3762 if ((level == PANIC) && (!TASKLET_IN_USE)) {
3711 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__); 3763 int ret;
3712 DBG_PRINT(INTR_DBG, "PANIC levels\n"); 3764 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__);
3713 if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) { 3765 DBG_PRINT(INTR_DBG, "PANIC levels\n");
3714 DBG_PRINT(ERR_DBG, "Out of memory in %s", 3766 if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) {
3715 __FUNCTION__); 3767 DBG_PRINT(ERR_DBG, "Out of memory in %s",
3768 __FUNCTION__);
3769 clear_bit(0, (&sp->tasklet_status));
3770 return IRQ_HANDLED;
3771 }
3716 clear_bit(0, (&sp->tasklet_status)); 3772 clear_bit(0, (&sp->tasklet_status));
3717 return IRQ_HANDLED; 3773 } else if (level == LOW) {
3774 tasklet_schedule(&sp->task);
3718 } 3775 }
3719 clear_bit(0, (&sp->tasklet_status));
3720 } else if (level == LOW) {
3721 tasklet_schedule(&sp->task);
3722 } 3776 }
3777 else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
3778 DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name);
3779 DBG_PRINT(ERR_DBG, " in Rx Intr!!\n");
3780 }
3781
3723 atomic_dec(&sp->isr_cnt); 3782 atomic_dec(&sp->isr_cnt);
3724 3783
3725 return IRQ_HANDLED; 3784 return IRQ_HANDLED;
@@ -3875,24 +3934,33 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
3875 */ 3934 */
3876#ifndef CONFIG_S2IO_NAPI 3935#ifndef CONFIG_S2IO_NAPI
3877 for (i = 0; i < config->rx_ring_num; i++) { 3936 for (i = 0; i < config->rx_ring_num; i++) {
3878 int ret; 3937 if (!sp->lro) {
3879 int rxb_size = atomic_read(&sp->rx_bufs_left[i]); 3938 int ret;
3880 int level = rx_buffer_level(sp, rxb_size, i); 3939 int rxb_size = atomic_read(&sp->rx_bufs_left[i]);
3881 3940 int level = rx_buffer_level(sp, rxb_size, i);
3882 if ((level == PANIC) && (!TASKLET_IN_USE)) { 3941
3883 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name); 3942 if ((level == PANIC) && (!TASKLET_IN_USE)) {
3884 DBG_PRINT(INTR_DBG, "PANIC levels\n"); 3943 DBG_PRINT(INTR_DBG, "%s: Rx BD hit ",
3885 if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) { 3944 dev->name);
3886 DBG_PRINT(ERR_DBG, "%s:Out of memory", 3945 DBG_PRINT(INTR_DBG, "PANIC levels\n");
3887 dev->name); 3946 if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) {
3888 DBG_PRINT(ERR_DBG, " in ISR!!\n"); 3947 DBG_PRINT(ERR_DBG, "%s:Out of memory",
3948 dev->name);
3949 DBG_PRINT(ERR_DBG, " in ISR!!\n");
3950 clear_bit(0, (&sp->tasklet_status));
3951 atomic_dec(&sp->isr_cnt);
3952 return IRQ_HANDLED;
3953 }
3889 clear_bit(0, (&sp->tasklet_status)); 3954 clear_bit(0, (&sp->tasklet_status));
3890 atomic_dec(&sp->isr_cnt); 3955 } else if (level == LOW) {
3891 return IRQ_HANDLED; 3956 tasklet_schedule(&sp->task);
3892 } 3957 }
3893 clear_bit(0, (&sp->tasklet_status)); 3958 }
3894 } else if (level == LOW) { 3959 else if (fill_rx_buffers(sp, i) == -ENOMEM) {
3895 tasklet_schedule(&sp->task); 3960 DBG_PRINT(ERR_DBG, "%s:Out of memory",
3961 dev->name);
3962 DBG_PRINT(ERR_DBG, " in Rx intr!!\n");
3963 break;
3896 } 3964 }
3897 } 3965 }
3898#endif 3966#endif
@@ -5043,6 +5111,7 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
5043 int i = 0; 5111 int i = 0;
5044 nic_t *sp = dev->priv; 5112 nic_t *sp = dev->priv;
5045 StatInfo_t *stat_info = sp->mac_control.stats_info; 5113 StatInfo_t *stat_info = sp->mac_control.stats_info;
5114 u64 tmp;
5046 5115
5047 s2io_updt_stats(sp); 5116 s2io_updt_stats(sp);
5048 tmp_stats[i++] = 5117 tmp_stats[i++] =
@@ -5134,6 +5203,16 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
5134 tmp_stats[i++] = 0; 5203 tmp_stats[i++] = 0;
5135 tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs; 5204 tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs;
5136 tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs; 5205 tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs;
5206 tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt;
5207 tmp_stats[i++] = stat_info->sw_stat.sending_both;
5208 tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts;
5209 tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts;
5210 tmp = 0;
5211 if (stat_info->sw_stat.num_aggregations) {
5212 tmp = stat_info->sw_stat.sum_avg_pkts_aggregated;
5213 do_div(tmp, stat_info->sw_stat.num_aggregations);
5214 }
5215 tmp_stats[i++] = tmp;
5137} 5216}
5138 5217
5139static int s2io_ethtool_get_regs_len(struct net_device *dev) 5218static int s2io_ethtool_get_regs_len(struct net_device *dev)
@@ -5515,6 +5594,14 @@ static int s2io_card_up(nic_t * sp)
5515 /* Setting its receive mode */ 5594 /* Setting its receive mode */
5516 s2io_set_multicast(dev); 5595 s2io_set_multicast(dev);
5517 5596
5597 if (sp->lro) {
5598 /* Initialize max aggregatable pkts based on MTU */
5599 sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu;
5600 /* Check if we can use(if specified) user provided value */
5601 if (lro_max_pkts < sp->lro_max_aggr_per_sess)
5602 sp->lro_max_aggr_per_sess = lro_max_pkts;
5603 }
5604
5518 /* Enable tasklet for the device */ 5605 /* Enable tasklet for the device */
5519 tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev); 5606 tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);
5520 5607
@@ -5607,6 +5694,7 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
5607 ((unsigned long) rxdp->Host_Control); 5694 ((unsigned long) rxdp->Host_Control);
5608 int ring_no = ring_data->ring_no; 5695 int ring_no = ring_data->ring_no;
5609 u16 l3_csum, l4_csum; 5696 u16 l3_csum, l4_csum;
5697 lro_t *lro;
5610 5698
5611 skb->dev = dev; 5699 skb->dev = dev;
5612 if (rxdp->Control_1 & RXD_T_CODE) { 5700 if (rxdp->Control_1 & RXD_T_CODE) {
@@ -5655,7 +5743,8 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
5655 skb_put(skb, buf2_len); 5743 skb_put(skb, buf2_len);
5656 } 5744 }
5657 5745
5658 if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && 5746 if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
5747 (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
5659 (sp->rx_csum)) { 5748 (sp->rx_csum)) {
5660 l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); 5749 l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
5661 l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); 5750 l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
@@ -5666,6 +5755,54 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
5666 * a flag in the RxD. 5755 * a flag in the RxD.
5667 */ 5756 */
5668 skb->ip_summed = CHECKSUM_UNNECESSARY; 5757 skb->ip_summed = CHECKSUM_UNNECESSARY;
5758 if (sp->lro) {
5759 u32 tcp_len;
5760 u8 *tcp;
5761 int ret = 0;
5762
5763 ret = s2io_club_tcp_session(skb->data, &tcp,
5764 &tcp_len, &lro, rxdp, sp);
5765 switch (ret) {
5766 case 3: /* Begin anew */
5767 lro->parent = skb;
5768 goto aggregate;
5769 case 1: /* Aggregate */
5770 {
5771 lro_append_pkt(sp, lro,
5772 skb, tcp_len);
5773 goto aggregate;
5774 }
5775 case 4: /* Flush session */
5776 {
5777 lro_append_pkt(sp, lro,
5778 skb, tcp_len);
5779 queue_rx_frame(lro->parent);
5780 clear_lro_session(lro);
5781 sp->mac_control.stats_info->
5782 sw_stat.flush_max_pkts++;
5783 goto aggregate;
5784 }
5785 case 2: /* Flush both */
5786 lro->parent->data_len =
5787 lro->frags_len;
5788 sp->mac_control.stats_info->
5789 sw_stat.sending_both++;
5790 queue_rx_frame(lro->parent);
5791 clear_lro_session(lro);
5792 goto send_up;
5793 case 0: /* sessions exceeded */
5794 case 5: /*
5795 * First pkt in session not
5796 * L3/L4 aggregatable
5797 */
5798 break;
5799 default:
5800 DBG_PRINT(ERR_DBG,
5801 "%s: Samadhana!!\n",
5802 __FUNCTION__);
5803 BUG();
5804 }
5805 }
5669 } else { 5806 } else {
5670 /* 5807 /*
5671 * Packet with erroneous checksum, let the 5808 * Packet with erroneous checksum, let the
@@ -5677,25 +5814,31 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
5677 skb->ip_summed = CHECKSUM_NONE; 5814 skb->ip_summed = CHECKSUM_NONE;
5678 } 5815 }
5679 5816
5680 skb->protocol = eth_type_trans(skb, dev); 5817 if (!sp->lro) {
5818 skb->protocol = eth_type_trans(skb, dev);
5681#ifdef CONFIG_S2IO_NAPI 5819#ifdef CONFIG_S2IO_NAPI
5682 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { 5820 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
5683 /* Queueing the vlan frame to the upper layer */ 5821 /* Queueing the vlan frame to the upper layer */
5684 vlan_hwaccel_receive_skb(skb, sp->vlgrp, 5822 vlan_hwaccel_receive_skb(skb, sp->vlgrp,
5685 RXD_GET_VLAN_TAG(rxdp->Control_2)); 5823 RXD_GET_VLAN_TAG(rxdp->Control_2));
5686 } else { 5824 } else {
5687 netif_receive_skb(skb); 5825 netif_receive_skb(skb);
5688 } 5826 }
5689#else 5827#else
5690 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { 5828 if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
5691 /* Queueing the vlan frame to the upper layer */ 5829 /* Queueing the vlan frame to the upper layer */
5692 vlan_hwaccel_rx(skb, sp->vlgrp, 5830 vlan_hwaccel_rx(skb, sp->vlgrp,
5693 RXD_GET_VLAN_TAG(rxdp->Control_2)); 5831 RXD_GET_VLAN_TAG(rxdp->Control_2));
5694 } else { 5832 } else {
5695 netif_rx(skb); 5833 netif_rx(skb);
5696 } 5834 }
5697#endif 5835#endif
5836 } else {
5837send_up:
5838 queue_rx_frame(skb);
5839 }
5698 dev->last_rx = jiffies; 5840 dev->last_rx = jiffies;
5841aggregate:
5699 atomic_dec(&sp->rx_bufs_left[ring_no]); 5842 atomic_dec(&sp->rx_bufs_left[ring_no]);
5700 return SUCCESS; 5843 return SUCCESS;
5701} 5844}
@@ -5807,6 +5950,8 @@ module_param(indicate_max_pkts, int, 0);
5807#endif 5950#endif
5808module_param(rxsync_frequency, int, 0); 5951module_param(rxsync_frequency, int, 0);
5809module_param(intr_type, int, 0); 5952module_param(intr_type, int, 0);
5953module_param(lro, int, 0);
5954module_param(lro_max_pkts, int, 0);
5810 5955
5811/** 5956/**
5812 * s2io_init_nic - Initialization of the adapter . 5957 * s2io_init_nic - Initialization of the adapter .
@@ -5938,6 +6083,7 @@ Defaulting to INTA\n");
5938 else 6083 else
5939 sp->device_type = XFRAME_I_DEVICE; 6084 sp->device_type = XFRAME_I_DEVICE;
5940 6085
6086 sp->lro = lro;
5941 6087
5942 /* Initialize some PCI/PCI-X fields of the NIC. */ 6088 /* Initialize some PCI/PCI-X fields of the NIC. */
5943 s2io_init_pci(sp); 6089 s2io_init_pci(sp);
@@ -6241,6 +6387,10 @@ Defaulting to INTA\n");
6241 DBG_PRINT(ERR_DBG, "%s: 3-Buffer mode support has been " 6387 DBG_PRINT(ERR_DBG, "%s: 3-Buffer mode support has been "
6242 "enabled\n",dev->name); 6388 "enabled\n",dev->name);
6243 6389
6390 if (sp->lro)
6391 DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
6392 dev->name);
6393
6244 /* Initialize device name */ 6394 /* Initialize device name */
6245 strcpy(sp->name, dev->name); 6395 strcpy(sp->name, dev->name);
6246 if (sp->device_type & XFRAME_II_DEVICE) 6396 if (sp->device_type & XFRAME_II_DEVICE)
@@ -6351,3 +6501,318 @@ static void s2io_closer(void)
6351 6501
6352module_init(s2io_starter); 6502module_init(s2io_starter);
6353module_exit(s2io_closer); 6503module_exit(s2io_closer);
6504
6505static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
6506 struct tcphdr **tcp, RxD_t *rxdp)
6507{
6508 int ip_off;
6509 u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
6510
6511 if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) {
6512 DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n",
6513 __FUNCTION__);
6514 return -1;
6515 }
6516
6517 /* TODO:
6518 * By default the VLAN field in the MAC is stripped by the card, if this
6519 * feature is turned off in rx_pa_cfg register, then the ip_off field
6520 * has to be shifted by a further 2 bytes
6521 */
6522 switch (l2_type) {
6523 case 0: /* DIX type */
6524 case 4: /* DIX type with VLAN */
6525 ip_off = HEADER_ETHERNET_II_802_3_SIZE;
6526 break;
6527 /* LLC, SNAP etc are considered non-mergeable */
6528 default:
6529 return -1;
6530 }
6531
6532 *ip = (struct iphdr *)((u8 *)buffer + ip_off);
6533 ip_len = (u8)((*ip)->ihl);
6534 ip_len <<= 2;
6535 *tcp = (struct tcphdr *)((unsigned long)*ip + ip_len);
6536
6537 return 0;
6538}
6539
6540static int check_for_socket_match(lro_t *lro, struct iphdr *ip,
6541 struct tcphdr *tcp)
6542{
6543 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
6544 if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) ||
6545 (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest))
6546 return -1;
6547 return 0;
6548}
6549
6550static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
6551{
6552 return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
6553}
6554
6555static void initiate_new_session(lro_t *lro, u8 *l2h,
6556 struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
6557{
6558 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
6559 lro->l2h = l2h;
6560 lro->iph = ip;
6561 lro->tcph = tcp;
6562 lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq);
6563 lro->tcp_ack = ntohl(tcp->ack_seq);
6564 lro->sg_num = 1;
6565 lro->total_len = ntohs(ip->tot_len);
6566 lro->frags_len = 0;
6567 /*
6568 * check if we saw TCP timestamp. Other consistency checks have
6569 * already been done.
6570 */
6571 if (tcp->doff == 8) {
6572 u32 *ptr;
6573 ptr = (u32 *)(tcp+1);
6574 lro->saw_ts = 1;
6575 lro->cur_tsval = *(ptr+1);
6576 lro->cur_tsecr = *(ptr+2);
6577 }
6578 lro->in_use = 1;
6579}
6580
6581static void update_L3L4_header(nic_t *sp, lro_t *lro)
6582{
6583 struct iphdr *ip = lro->iph;
6584 struct tcphdr *tcp = lro->tcph;
6585 u16 nchk;
6586 StatInfo_t *statinfo = sp->mac_control.stats_info;
6587 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
6588
6589 /* Update L3 header */
6590 ip->tot_len = htons(lro->total_len);
6591 ip->check = 0;
6592 nchk = ip_fast_csum((u8 *)lro->iph, ip->ihl);
6593 ip->check = nchk;
6594
6595 /* Update L4 header */
6596 tcp->ack_seq = lro->tcp_ack;
6597 tcp->window = lro->window;
6598
6599 /* Update tsecr field if this session has timestamps enabled */
6600 if (lro->saw_ts) {
6601 u32 *ptr = (u32 *)(tcp + 1);
6602 *(ptr+2) = lro->cur_tsecr;
6603 }
6604
6605 /* Update counters required for calculation of
6606 * average no. of packets aggregated.
6607 */
6608 statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num;
6609 statinfo->sw_stat.num_aggregations++;
6610}
6611
6612static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
6613 struct tcphdr *tcp, u32 l4_pyld)
6614{
6615 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
6616 lro->total_len += l4_pyld;
6617 lro->frags_len += l4_pyld;
6618 lro->tcp_next_seq += l4_pyld;
6619 lro->sg_num++;
6620
6621 /* Update ack seq no. and window ad(from this pkt) in LRO object */
6622 lro->tcp_ack = tcp->ack_seq;
6623 lro->window = tcp->window;
6624
6625 if (lro->saw_ts) {
6626 u32 *ptr;
6627 /* Update tsecr and tsval from this packet */
6628 ptr = (u32 *) (tcp + 1);
6629 lro->cur_tsval = *(ptr + 1);
6630 lro->cur_tsecr = *(ptr + 2);
6631 }
6632}
6633
6634static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
6635 struct tcphdr *tcp, u32 tcp_pyld_len)
6636{
6637 u8 *ptr;
6638
6639 DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
6640
6641 if (!tcp_pyld_len) {
6642 /* Runt frame or a pure ack */
6643 return -1;
6644 }
6645
6646 if (ip->ihl != 5) /* IP has options */
6647 return -1;
6648
6649 if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin ||
6650 !tcp->ack) {
6651 /*
6652 * Currently recognize only the ack control word and
6653 * any other control field being set would result in
6654 * flushing the LRO session
6655 */
6656 return -1;
6657 }
6658
6659 /*
6660 * Allow only one TCP timestamp option. Don't aggregate if
6661 * any other options are detected.
6662 */
6663 if (tcp->doff != 5 && tcp->doff != 8)
6664 return -1;
6665
6666 if (tcp->doff == 8) {
6667 ptr = (u8 *)(tcp + 1);
6668 while (*ptr == TCPOPT_NOP)
6669 ptr++;
6670 if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP)
6671 return -1;
6672
6673 /* Ensure timestamp value increases monotonically */
6674 if (l_lro)
6675 if (l_lro->cur_tsval > *((u32 *)(ptr+2)))
6676 return -1;
6677
6678 /* timestamp echo reply should be non-zero */
6679 if (*((u32 *)(ptr+6)) == 0)
6680 return -1;
6681 }
6682
6683 return 0;
6684}
6685
6686static int
6687s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
6688 RxD_t *rxdp, nic_t *sp)
6689{
6690 struct iphdr *ip;
6691 struct tcphdr *tcph;
6692 int ret = 0, i;
6693
6694 if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp,
6695 rxdp))) {
6696 DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n",
6697 ip->saddr, ip->daddr);
6698 } else {
6699 return ret;
6700 }
6701
6702 tcph = (struct tcphdr *)*tcp;
6703 *tcp_len = get_l4_pyld_length(ip, tcph);
6704 for (i=0; i<MAX_LRO_SESSIONS; i++) {
6705 lro_t *l_lro = &sp->lro0_n[i];
6706 if (l_lro->in_use) {
6707 if (check_for_socket_match(l_lro, ip, tcph))
6708 continue;
6709 /* Sock pair matched */
6710 *lro = l_lro;
6711
6712 if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) {
6713 DBG_PRINT(INFO_DBG, "%s:Out of order. expected "
6714 "0x%x, actual 0x%x\n", __FUNCTION__,
6715 (*lro)->tcp_next_seq,
6716 ntohl(tcph->seq));
6717
6718 sp->mac_control.stats_info->
6719 sw_stat.outof_sequence_pkts++;
6720 ret = 2;
6721 break;
6722 }
6723
6724 if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len))
6725 ret = 1; /* Aggregate */
6726 else
6727 ret = 2; /* Flush both */
6728 break;
6729 }
6730 }
6731
6732 if (ret == 0) {
6733 /* Before searching for available LRO objects,
6734 * check if the pkt is L3/L4 aggregatable. If not
6735 * don't create new LRO session. Just send this
6736 * packet up.
6737 */
6738 if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) {
6739 return 5;
6740 }
6741
6742 for (i=0; i<MAX_LRO_SESSIONS; i++) {
6743 lro_t *l_lro = &sp->lro0_n[i];
6744 if (!(l_lro->in_use)) {
6745 *lro = l_lro;
6746 ret = 3; /* Begin anew */
6747 break;
6748 }
6749 }
6750 }
6751
6752 if (ret == 0) { /* sessions exceeded */
6753 DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n",
6754 __FUNCTION__);
6755 *lro = NULL;
6756 return ret;
6757 }
6758
6759 switch (ret) {
6760 case 3:
6761 initiate_new_session(*lro, buffer, ip, tcph, *tcp_len);
6762 break;
6763 case 2:
6764 update_L3L4_header(sp, *lro);
6765 break;
6766 case 1:
6767 aggregate_new_rx(*lro, ip, tcph, *tcp_len);
6768 if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) {
6769 update_L3L4_header(sp, *lro);
6770 ret = 4; /* Flush the LRO */
6771 }
6772 break;
6773 default:
6774 DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n",
6775 __FUNCTION__);
6776 break;
6777 }
6778
6779 return ret;
6780}
6781
6782static void clear_lro_session(lro_t *lro)
6783{
6784 static u16 lro_struct_size = sizeof(lro_t);
6785
6786 memset(lro, 0, lro_struct_size);
6787}
6788
6789static void queue_rx_frame(struct sk_buff *skb)
6790{
6791 struct net_device *dev = skb->dev;
6792
6793 skb->protocol = eth_type_trans(skb, dev);
6794#ifdef CONFIG_S2IO_NAPI
6795 netif_receive_skb(skb);
6796#else
6797 netif_rx(skb);
6798#endif
6799}
6800
6801static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
6802 u32 tcp_len)
6803{
6804 struct sk_buff *tmp, *first = lro->parent;
6805
6806 first->len += tcp_len;
6807 first->data_len = lro->frags_len;
6808 skb_pull(skb, (skb->len - tcp_len));
6809 if ((tmp = skb_shinfo(first)->frag_list)) {
6810 while (tmp->next)
6811 tmp = tmp->next;
6812 tmp->next = skb;
6813 }
6814 else
6815 skb_shinfo(first)->frag_list = skb;
6816 sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
6817 return;
6818}