diff options
Diffstat (limited to 'drivers/net/s2io.c')
-rw-r--r-- | drivers/net/s2io.c | 619 |
1 files changed, 542 insertions, 77 deletions
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index b7f00d6eb6a6..79208f434ac1 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c | |||
@@ -57,23 +57,27 @@ | |||
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. */ |
72 | static char s2io_driver_name[] = "Neterion"; | 76 | static char s2io_driver_name[] = "Neterion"; |
73 | static char s2io_driver_version[] = DRV_VERSION; | 77 | static char s2io_driver_version[] = DRV_VERSION; |
74 | 78 | ||
75 | int rxd_size[4] = {32,48,48,64}; | 79 | static int rxd_size[4] = {32,48,48,64}; |
76 | int rxd_count[4] = {127,85,85,63}; | 80 | static int rxd_count[4] = {127,85,85,63}; |
77 | 81 | ||
78 | static inline int RXD_IS_UP2DT(RxD_t *rxdp) | 82 | static inline int RXD_IS_UP2DT(RxD_t *rxdp) |
79 | { | 83 | { |
@@ -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 |
@@ -214,7 +223,7 @@ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) | |||
214 | #define SWITCH_SIGN 0xA5A5A5A5A5A5A5A5ULL | 223 | #define SWITCH_SIGN 0xA5A5A5A5A5A5A5A5ULL |
215 | #define END_SIGN 0x0 | 224 | #define END_SIGN 0x0 |
216 | 225 | ||
217 | static u64 herc_act_dtx_cfg[] = { | 226 | static const u64 herc_act_dtx_cfg[] = { |
218 | /* Set address */ | 227 | /* Set address */ |
219 | 0x8000051536750000ULL, 0x80000515367500E0ULL, | 228 | 0x8000051536750000ULL, 0x80000515367500E0ULL, |
220 | /* Write data */ | 229 | /* Write data */ |
@@ -235,7 +244,7 @@ static u64 herc_act_dtx_cfg[] = { | |||
235 | END_SIGN | 244 | END_SIGN |
236 | }; | 245 | }; |
237 | 246 | ||
238 | static u64 xena_mdio_cfg[] = { | 247 | static const u64 xena_mdio_cfg[] = { |
239 | /* Reset PMA PLL */ | 248 | /* Reset PMA PLL */ |
240 | 0xC001010000000000ULL, 0xC0010100000000E0ULL, | 249 | 0xC001010000000000ULL, 0xC0010100000000E0ULL, |
241 | 0xC0010100008000E4ULL, | 250 | 0xC0010100008000E4ULL, |
@@ -245,7 +254,7 @@ static u64 xena_mdio_cfg[] = { | |||
245 | END_SIGN | 254 | END_SIGN |
246 | }; | 255 | }; |
247 | 256 | ||
248 | static u64 xena_dtx_cfg[] = { | 257 | static const u64 xena_dtx_cfg[] = { |
249 | 0x8000051500000000ULL, 0x80000515000000E0ULL, | 258 | 0x8000051500000000ULL, 0x80000515000000E0ULL, |
250 | 0x80000515D93500E4ULL, 0x8001051500000000ULL, | 259 | 0x80000515D93500E4ULL, 0x8001051500000000ULL, |
251 | 0x80010515000000E0ULL, 0x80010515001E00E4ULL, | 260 | 0x80010515000000E0ULL, 0x80010515001E00E4ULL, |
@@ -273,7 +282,7 @@ static u64 xena_dtx_cfg[] = { | |||
273 | * Constants for Fixing the MacAddress problem seen mostly on | 282 | * Constants for Fixing the MacAddress problem seen mostly on |
274 | * Alpha machines. | 283 | * Alpha machines. |
275 | */ | 284 | */ |
276 | static u64 fix_mac[] = { | 285 | static const u64 fix_mac[] = { |
277 | 0x0060000000000000ULL, 0x0060600000000000ULL, | 286 | 0x0060000000000000ULL, 0x0060600000000000ULL, |
278 | 0x0040600000000000ULL, 0x0000600000000000ULL, | 287 | 0x0040600000000000ULL, 0x0000600000000000ULL, |
279 | 0x0020600000000000ULL, 0x0060600000000000ULL, | 288 | 0x0020600000000000ULL, 0x0060600000000000ULL, |
@@ -317,6 +326,12 @@ static unsigned int indicate_max_pkts; | |||
317 | static unsigned int rxsync_frequency = 3; | 326 | static 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) */ |
319 | static unsigned int intr_type = 0; | 328 | static unsigned int intr_type = 0; |
329 | /* Large receive offload feature */ | ||
330 | static 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 | */ | ||
334 | static 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. |
@@ -2127,7 +2155,7 @@ static void stop_nic(struct s2io_nic *nic) | |||
2127 | } | 2155 | } |
2128 | } | 2156 | } |
2129 | 2157 | ||
2130 | int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb) | 2158 | static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb) |
2131 | { | 2159 | { |
2132 | struct net_device *dev = nic->dev; | 2160 | struct net_device *dev = nic->dev; |
2133 | struct sk_buff *frag_list; | 2161 | struct sk_buff *frag_list; |
@@ -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 | ||
@@ -2852,7 +2894,7 @@ static int wait_for_cmd_complete(nic_t * sp) | |||
2852 | * void. | 2894 | * void. |
2853 | */ | 2895 | */ |
2854 | 2896 | ||
2855 | void s2io_reset(nic_t * sp) | 2897 | static void s2io_reset(nic_t * sp) |
2856 | { | 2898 | { |
2857 | XENA_dev_config_t __iomem *bar0 = sp->bar0; | 2899 | XENA_dev_config_t __iomem *bar0 = sp->bar0; |
2858 | u64 val64; | 2900 | u64 val64; |
@@ -2940,7 +2982,7 @@ void s2io_reset(nic_t * sp) | |||
2940 | * SUCCESS on success and FAILURE on failure. | 2982 | * SUCCESS on success and FAILURE on failure. |
2941 | */ | 2983 | */ |
2942 | 2984 | ||
2943 | int s2io_set_swapper(nic_t * sp) | 2985 | static int s2io_set_swapper(nic_t * sp) |
2944 | { | 2986 | { |
2945 | struct net_device *dev = sp->dev; | 2987 | struct net_device *dev = sp->dev; |
2946 | XENA_dev_config_t __iomem *bar0 = sp->bar0; | 2988 | XENA_dev_config_t __iomem *bar0 = sp->bar0; |
@@ -3089,7 +3131,7 @@ static int wait_for_msix_trans(nic_t *nic, int i) | |||
3089 | return ret; | 3131 | return ret; |
3090 | } | 3132 | } |
3091 | 3133 | ||
3092 | void restore_xmsi_data(nic_t *nic) | 3134 | static void restore_xmsi_data(nic_t *nic) |
3093 | { | 3135 | { |
3094 | XENA_dev_config_t __iomem *bar0 = nic->bar0; | 3136 | XENA_dev_config_t __iomem *bar0 = nic->bar0; |
3095 | u64 val64; | 3137 | u64 val64; |
@@ -3180,7 +3222,7 @@ int s2io_enable_msi(nic_t *nic) | |||
3180 | return 0; | 3222 | return 0; |
3181 | } | 3223 | } |
3182 | 3224 | ||
3183 | int s2io_enable_msi_x(nic_t *nic) | 3225 | static int s2io_enable_msi_x(nic_t *nic) |
3184 | { | 3226 | { |
3185 | XENA_dev_config_t __iomem *bar0 = nic->bar0; | 3227 | XENA_dev_config_t __iomem *bar0 = nic->bar0; |
3186 | u64 tx_mat, rx_mat; | 3228 | u64 tx_mat, rx_mat; |
@@ -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 |
@@ -4129,7 +4197,7 @@ static void s2io_set_multicast(struct net_device *dev) | |||
4129 | * as defined in errno.h file on failure. | 4197 | * as defined in errno.h file on failure. |
4130 | */ | 4198 | */ |
4131 | 4199 | ||
4132 | int s2io_set_mac_addr(struct net_device *dev, u8 * addr) | 4200 | static int s2io_set_mac_addr(struct net_device *dev, u8 * addr) |
4133 | { | 4201 | { |
4134 | nic_t *sp = dev->priv; | 4202 | nic_t *sp = dev->priv; |
4135 | XENA_dev_config_t __iomem *bar0 = sp->bar0; | 4203 | XENA_dev_config_t __iomem *bar0 = sp->bar0; |
@@ -5044,6 +5112,7 @@ static void s2io_get_ethtool_stats(struct net_device *dev, | |||
5044 | int i = 0; | 5112 | int i = 0; |
5045 | nic_t *sp = dev->priv; | 5113 | nic_t *sp = dev->priv; |
5046 | StatInfo_t *stat_info = sp->mac_control.stats_info; | 5114 | StatInfo_t *stat_info = sp->mac_control.stats_info; |
5115 | u64 tmp; | ||
5047 | 5116 | ||
5048 | s2io_updt_stats(sp); | 5117 | s2io_updt_stats(sp); |
5049 | tmp_stats[i++] = | 5118 | tmp_stats[i++] = |
@@ -5135,6 +5204,16 @@ static void s2io_get_ethtool_stats(struct net_device *dev, | |||
5135 | tmp_stats[i++] = 0; | 5204 | tmp_stats[i++] = 0; |
5136 | tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs; | 5205 | tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs; |
5137 | tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs; | 5206 | tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs; |
5207 | tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt; | ||
5208 | tmp_stats[i++] = stat_info->sw_stat.sending_both; | ||
5209 | tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts; | ||
5210 | tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts; | ||
5211 | tmp = 0; | ||
5212 | if (stat_info->sw_stat.num_aggregations) { | ||
5213 | tmp = stat_info->sw_stat.sum_avg_pkts_aggregated; | ||
5214 | do_div(tmp, stat_info->sw_stat.num_aggregations); | ||
5215 | } | ||
5216 | tmp_stats[i++] = tmp; | ||
5138 | } | 5217 | } |
5139 | 5218 | ||
5140 | static int s2io_ethtool_get_regs_len(struct net_device *dev) | 5219 | static int s2io_ethtool_get_regs_len(struct net_device *dev) |
@@ -5516,6 +5595,14 @@ static int s2io_card_up(nic_t * sp) | |||
5516 | /* Setting its receive mode */ | 5595 | /* Setting its receive mode */ |
5517 | s2io_set_multicast(dev); | 5596 | s2io_set_multicast(dev); |
5518 | 5597 | ||
5598 | if (sp->lro) { | ||
5599 | /* Initialize max aggregatable pkts based on MTU */ | ||
5600 | sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu; | ||
5601 | /* Check if we can use(if specified) user provided value */ | ||
5602 | if (lro_max_pkts < sp->lro_max_aggr_per_sess) | ||
5603 | sp->lro_max_aggr_per_sess = lro_max_pkts; | ||
5604 | } | ||
5605 | |||
5519 | /* Enable tasklet for the device */ | 5606 | /* Enable tasklet for the device */ |
5520 | tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev); | 5607 | tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev); |
5521 | 5608 | ||
@@ -5608,6 +5695,7 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) | |||
5608 | ((unsigned long) rxdp->Host_Control); | 5695 | ((unsigned long) rxdp->Host_Control); |
5609 | int ring_no = ring_data->ring_no; | 5696 | int ring_no = ring_data->ring_no; |
5610 | u16 l3_csum, l4_csum; | 5697 | u16 l3_csum, l4_csum; |
5698 | lro_t *lro; | ||
5611 | 5699 | ||
5612 | skb->dev = dev; | 5700 | skb->dev = dev; |
5613 | if (rxdp->Control_1 & RXD_T_CODE) { | 5701 | if (rxdp->Control_1 & RXD_T_CODE) { |
@@ -5656,7 +5744,8 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) | |||
5656 | skb_put(skb, buf2_len); | 5744 | skb_put(skb, buf2_len); |
5657 | } | 5745 | } |
5658 | 5746 | ||
5659 | if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && | 5747 | if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) || |
5748 | (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) && | ||
5660 | (sp->rx_csum)) { | 5749 | (sp->rx_csum)) { |
5661 | l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); | 5750 | l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); |
5662 | l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); | 5751 | l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); |
@@ -5667,6 +5756,54 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) | |||
5667 | * a flag in the RxD. | 5756 | * a flag in the RxD. |
5668 | */ | 5757 | */ |
5669 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 5758 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
5759 | if (sp->lro) { | ||
5760 | u32 tcp_len; | ||
5761 | u8 *tcp; | ||
5762 | int ret = 0; | ||
5763 | |||
5764 | ret = s2io_club_tcp_session(skb->data, &tcp, | ||
5765 | &tcp_len, &lro, rxdp, sp); | ||
5766 | switch (ret) { | ||
5767 | case 3: /* Begin anew */ | ||
5768 | lro->parent = skb; | ||
5769 | goto aggregate; | ||
5770 | case 1: /* Aggregate */ | ||
5771 | { | ||
5772 | lro_append_pkt(sp, lro, | ||
5773 | skb, tcp_len); | ||
5774 | goto aggregate; | ||
5775 | } | ||
5776 | case 4: /* Flush session */ | ||
5777 | { | ||
5778 | lro_append_pkt(sp, lro, | ||
5779 | skb, tcp_len); | ||
5780 | queue_rx_frame(lro->parent); | ||
5781 | clear_lro_session(lro); | ||
5782 | sp->mac_control.stats_info-> | ||
5783 | sw_stat.flush_max_pkts++; | ||
5784 | goto aggregate; | ||
5785 | } | ||
5786 | case 2: /* Flush both */ | ||
5787 | lro->parent->data_len = | ||
5788 | lro->frags_len; | ||
5789 | sp->mac_control.stats_info-> | ||
5790 | sw_stat.sending_both++; | ||
5791 | queue_rx_frame(lro->parent); | ||
5792 | clear_lro_session(lro); | ||
5793 | goto send_up; | ||
5794 | case 0: /* sessions exceeded */ | ||
5795 | case 5: /* | ||
5796 | * First pkt in session not | ||
5797 | * L3/L4 aggregatable | ||
5798 | */ | ||
5799 | break; | ||
5800 | default: | ||
5801 | DBG_PRINT(ERR_DBG, | ||
5802 | "%s: Samadhana!!\n", | ||
5803 | __FUNCTION__); | ||
5804 | BUG(); | ||
5805 | } | ||
5806 | } | ||
5670 | } else { | 5807 | } else { |
5671 | /* | 5808 | /* |
5672 | * Packet with erroneous checksum, let the | 5809 | * Packet with erroneous checksum, let the |
@@ -5678,25 +5815,31 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) | |||
5678 | skb->ip_summed = CHECKSUM_NONE; | 5815 | skb->ip_summed = CHECKSUM_NONE; |
5679 | } | 5816 | } |
5680 | 5817 | ||
5681 | skb->protocol = eth_type_trans(skb, dev); | 5818 | if (!sp->lro) { |
5819 | skb->protocol = eth_type_trans(skb, dev); | ||
5682 | #ifdef CONFIG_S2IO_NAPI | 5820 | #ifdef CONFIG_S2IO_NAPI |
5683 | if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { | 5821 | if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { |
5684 | /* Queueing the vlan frame to the upper layer */ | 5822 | /* Queueing the vlan frame to the upper layer */ |
5685 | vlan_hwaccel_receive_skb(skb, sp->vlgrp, | 5823 | vlan_hwaccel_receive_skb(skb, sp->vlgrp, |
5686 | RXD_GET_VLAN_TAG(rxdp->Control_2)); | 5824 | RXD_GET_VLAN_TAG(rxdp->Control_2)); |
5687 | } else { | 5825 | } else { |
5688 | netif_receive_skb(skb); | 5826 | netif_receive_skb(skb); |
5689 | } | 5827 | } |
5690 | #else | 5828 | #else |
5691 | if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { | 5829 | if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { |
5692 | /* Queueing the vlan frame to the upper layer */ | 5830 | /* Queueing the vlan frame to the upper layer */ |
5693 | vlan_hwaccel_rx(skb, sp->vlgrp, | 5831 | vlan_hwaccel_rx(skb, sp->vlgrp, |
5694 | RXD_GET_VLAN_TAG(rxdp->Control_2)); | 5832 | RXD_GET_VLAN_TAG(rxdp->Control_2)); |
5695 | } else { | 5833 | } else { |
5696 | netif_rx(skb); | 5834 | netif_rx(skb); |
5697 | } | 5835 | } |
5698 | #endif | 5836 | #endif |
5837 | } else { | ||
5838 | send_up: | ||
5839 | queue_rx_frame(skb); | ||
5840 | } | ||
5699 | dev->last_rx = jiffies; | 5841 | dev->last_rx = jiffies; |
5842 | aggregate: | ||
5700 | atomic_dec(&sp->rx_bufs_left[ring_no]); | 5843 | atomic_dec(&sp->rx_bufs_left[ring_no]); |
5701 | return SUCCESS; | 5844 | return SUCCESS; |
5702 | } | 5845 | } |
@@ -5714,7 +5857,7 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) | |||
5714 | * void. | 5857 | * void. |
5715 | */ | 5858 | */ |
5716 | 5859 | ||
5717 | void s2io_link(nic_t * sp, int link) | 5860 | static void s2io_link(nic_t * sp, int link) |
5718 | { | 5861 | { |
5719 | struct net_device *dev = (struct net_device *) sp->dev; | 5862 | struct net_device *dev = (struct net_device *) sp->dev; |
5720 | 5863 | ||
@@ -5739,7 +5882,7 @@ void s2io_link(nic_t * sp, int link) | |||
5739 | * returns the revision ID of the device. | 5882 | * returns the revision ID of the device. |
5740 | */ | 5883 | */ |
5741 | 5884 | ||
5742 | int get_xena_rev_id(struct pci_dev *pdev) | 5885 | static int get_xena_rev_id(struct pci_dev *pdev) |
5743 | { | 5886 | { |
5744 | u8 id = 0; | 5887 | u8 id = 0; |
5745 | int ret; | 5888 | int ret; |
@@ -5808,6 +5951,8 @@ module_param(indicate_max_pkts, int, 0); | |||
5808 | #endif | 5951 | #endif |
5809 | module_param(rxsync_frequency, int, 0); | 5952 | module_param(rxsync_frequency, int, 0); |
5810 | module_param(intr_type, int, 0); | 5953 | module_param(intr_type, int, 0); |
5954 | module_param(lro, int, 0); | ||
5955 | module_param(lro_max_pkts, int, 0); | ||
5811 | 5956 | ||
5812 | /** | 5957 | /** |
5813 | * s2io_init_nic - Initialization of the adapter . | 5958 | * s2io_init_nic - Initialization of the adapter . |
@@ -5939,6 +6084,7 @@ Defaulting to INTA\n"); | |||
5939 | else | 6084 | else |
5940 | sp->device_type = XFRAME_I_DEVICE; | 6085 | sp->device_type = XFRAME_I_DEVICE; |
5941 | 6086 | ||
6087 | sp->lro = lro; | ||
5942 | 6088 | ||
5943 | /* Initialize some PCI/PCI-X fields of the NIC. */ | 6089 | /* Initialize some PCI/PCI-X fields of the NIC. */ |
5944 | s2io_init_pci(sp); | 6090 | s2io_init_pci(sp); |
@@ -6242,6 +6388,10 @@ Defaulting to INTA\n"); | |||
6242 | DBG_PRINT(ERR_DBG, "%s: 3-Buffer mode support has been " | 6388 | DBG_PRINT(ERR_DBG, "%s: 3-Buffer mode support has been " |
6243 | "enabled\n",dev->name); | 6389 | "enabled\n",dev->name); |
6244 | 6390 | ||
6391 | if (sp->lro) | ||
6392 | DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n", | ||
6393 | dev->name); | ||
6394 | |||
6245 | /* Initialize device name */ | 6395 | /* Initialize device name */ |
6246 | strcpy(sp->name, dev->name); | 6396 | strcpy(sp->name, dev->name); |
6247 | if (sp->device_type & XFRAME_II_DEVICE) | 6397 | if (sp->device_type & XFRAME_II_DEVICE) |
@@ -6344,7 +6494,7 @@ int __init s2io_starter(void) | |||
6344 | * Description: This function is the cleanup routine for the driver. It unregist * ers the driver. | 6494 | * Description: This function is the cleanup routine for the driver. It unregist * ers the driver. |
6345 | */ | 6495 | */ |
6346 | 6496 | ||
6347 | void s2io_closer(void) | 6497 | static void s2io_closer(void) |
6348 | { | 6498 | { |
6349 | pci_unregister_driver(&s2io_driver); | 6499 | pci_unregister_driver(&s2io_driver); |
6350 | DBG_PRINT(INIT_DBG, "cleanup done\n"); | 6500 | DBG_PRINT(INIT_DBG, "cleanup done\n"); |
@@ -6352,3 +6502,318 @@ void s2io_closer(void) | |||
6352 | 6502 | ||
6353 | module_init(s2io_starter); | 6503 | module_init(s2io_starter); |
6354 | module_exit(s2io_closer); | 6504 | module_exit(s2io_closer); |
6505 | |||
6506 | static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, | ||
6507 | struct tcphdr **tcp, RxD_t *rxdp) | ||
6508 | { | ||
6509 | int ip_off; | ||
6510 | u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len; | ||
6511 | |||
6512 | if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) { | ||
6513 | DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n", | ||
6514 | __FUNCTION__); | ||
6515 | return -1; | ||
6516 | } | ||
6517 | |||
6518 | /* TODO: | ||
6519 | * By default the VLAN field in the MAC is stripped by the card, if this | ||
6520 | * feature is turned off in rx_pa_cfg register, then the ip_off field | ||
6521 | * has to be shifted by a further 2 bytes | ||
6522 | */ | ||
6523 | switch (l2_type) { | ||
6524 | case 0: /* DIX type */ | ||
6525 | case 4: /* DIX type with VLAN */ | ||
6526 | ip_off = HEADER_ETHERNET_II_802_3_SIZE; | ||
6527 | break; | ||
6528 | /* LLC, SNAP etc are considered non-mergeable */ | ||
6529 | default: | ||
6530 | return -1; | ||
6531 | } | ||
6532 | |||
6533 | *ip = (struct iphdr *)((u8 *)buffer + ip_off); | ||
6534 | ip_len = (u8)((*ip)->ihl); | ||
6535 | ip_len <<= 2; | ||
6536 | *tcp = (struct tcphdr *)((unsigned long)*ip + ip_len); | ||
6537 | |||
6538 | return 0; | ||
6539 | } | ||
6540 | |||
6541 | static int check_for_socket_match(lro_t *lro, struct iphdr *ip, | ||
6542 | struct tcphdr *tcp) | ||
6543 | { | ||
6544 | DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); | ||
6545 | if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) || | ||
6546 | (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest)) | ||
6547 | return -1; | ||
6548 | return 0; | ||
6549 | } | ||
6550 | |||
6551 | static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp) | ||
6552 | { | ||
6553 | return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2)); | ||
6554 | } | ||
6555 | |||
6556 | static void initiate_new_session(lro_t *lro, u8 *l2h, | ||
6557 | struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len) | ||
6558 | { | ||
6559 | DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); | ||
6560 | lro->l2h = l2h; | ||
6561 | lro->iph = ip; | ||
6562 | lro->tcph = tcp; | ||
6563 | lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq); | ||
6564 | lro->tcp_ack = ntohl(tcp->ack_seq); | ||
6565 | lro->sg_num = 1; | ||
6566 | lro->total_len = ntohs(ip->tot_len); | ||
6567 | lro->frags_len = 0; | ||
6568 | /* | ||
6569 | * check if we saw TCP timestamp. Other consistency checks have | ||
6570 | * already been done. | ||
6571 | */ | ||
6572 | if (tcp->doff == 8) { | ||
6573 | u32 *ptr; | ||
6574 | ptr = (u32 *)(tcp+1); | ||
6575 | lro->saw_ts = 1; | ||
6576 | lro->cur_tsval = *(ptr+1); | ||
6577 | lro->cur_tsecr = *(ptr+2); | ||
6578 | } | ||
6579 | lro->in_use = 1; | ||
6580 | } | ||
6581 | |||
6582 | static void update_L3L4_header(nic_t *sp, lro_t *lro) | ||
6583 | { | ||
6584 | struct iphdr *ip = lro->iph; | ||
6585 | struct tcphdr *tcp = lro->tcph; | ||
6586 | u16 nchk; | ||
6587 | StatInfo_t *statinfo = sp->mac_control.stats_info; | ||
6588 | DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); | ||
6589 | |||
6590 | /* Update L3 header */ | ||
6591 | ip->tot_len = htons(lro->total_len); | ||
6592 | ip->check = 0; | ||
6593 | nchk = ip_fast_csum((u8 *)lro->iph, ip->ihl); | ||
6594 | ip->check = nchk; | ||
6595 | |||
6596 | /* Update L4 header */ | ||
6597 | tcp->ack_seq = lro->tcp_ack; | ||
6598 | tcp->window = lro->window; | ||
6599 | |||
6600 | /* Update tsecr field if this session has timestamps enabled */ | ||
6601 | if (lro->saw_ts) { | ||
6602 | u32 *ptr = (u32 *)(tcp + 1); | ||
6603 | *(ptr+2) = lro->cur_tsecr; | ||
6604 | } | ||
6605 | |||
6606 | /* Update counters required for calculation of | ||
6607 | * average no. of packets aggregated. | ||
6608 | */ | ||
6609 | statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num; | ||
6610 | statinfo->sw_stat.num_aggregations++; | ||
6611 | } | ||
6612 | |||
6613 | static void aggregate_new_rx(lro_t *lro, struct iphdr *ip, | ||
6614 | struct tcphdr *tcp, u32 l4_pyld) | ||
6615 | { | ||
6616 | DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); | ||
6617 | lro->total_len += l4_pyld; | ||
6618 | lro->frags_len += l4_pyld; | ||
6619 | lro->tcp_next_seq += l4_pyld; | ||
6620 | lro->sg_num++; | ||
6621 | |||
6622 | /* Update ack seq no. and window ad(from this pkt) in LRO object */ | ||
6623 | lro->tcp_ack = tcp->ack_seq; | ||
6624 | lro->window = tcp->window; | ||
6625 | |||
6626 | if (lro->saw_ts) { | ||
6627 | u32 *ptr; | ||
6628 | /* Update tsecr and tsval from this packet */ | ||
6629 | ptr = (u32 *) (tcp + 1); | ||
6630 | lro->cur_tsval = *(ptr + 1); | ||
6631 | lro->cur_tsecr = *(ptr + 2); | ||
6632 | } | ||
6633 | } | ||
6634 | |||
6635 | static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip, | ||
6636 | struct tcphdr *tcp, u32 tcp_pyld_len) | ||
6637 | { | ||
6638 | u8 *ptr; | ||
6639 | |||
6640 | DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); | ||
6641 | |||
6642 | if (!tcp_pyld_len) { | ||
6643 | /* Runt frame or a pure ack */ | ||
6644 | return -1; | ||
6645 | } | ||
6646 | |||
6647 | if (ip->ihl != 5) /* IP has options */ | ||
6648 | return -1; | ||
6649 | |||
6650 | if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin || | ||
6651 | !tcp->ack) { | ||
6652 | /* | ||
6653 | * Currently recognize only the ack control word and | ||
6654 | * any other control field being set would result in | ||
6655 | * flushing the LRO session | ||
6656 | */ | ||
6657 | return -1; | ||
6658 | } | ||
6659 | |||
6660 | /* | ||
6661 | * Allow only one TCP timestamp option. Don't aggregate if | ||
6662 | * any other options are detected. | ||
6663 | */ | ||
6664 | if (tcp->doff != 5 && tcp->doff != 8) | ||
6665 | return -1; | ||
6666 | |||
6667 | if (tcp->doff == 8) { | ||
6668 | ptr = (u8 *)(tcp + 1); | ||
6669 | while (*ptr == TCPOPT_NOP) | ||
6670 | ptr++; | ||
6671 | if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP) | ||
6672 | return -1; | ||
6673 | |||
6674 | /* Ensure timestamp value increases monotonically */ | ||
6675 | if (l_lro) | ||
6676 | if (l_lro->cur_tsval > *((u32 *)(ptr+2))) | ||
6677 | return -1; | ||
6678 | |||
6679 | /* timestamp echo reply should be non-zero */ | ||
6680 | if (*((u32 *)(ptr+6)) == 0) | ||
6681 | return -1; | ||
6682 | } | ||
6683 | |||
6684 | return 0; | ||
6685 | } | ||
6686 | |||
6687 | static int | ||
6688 | s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, | ||
6689 | RxD_t *rxdp, nic_t *sp) | ||
6690 | { | ||
6691 | struct iphdr *ip; | ||
6692 | struct tcphdr *tcph; | ||
6693 | int ret = 0, i; | ||
6694 | |||
6695 | if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp, | ||
6696 | rxdp))) { | ||
6697 | DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n", | ||
6698 | ip->saddr, ip->daddr); | ||
6699 | } else { | ||
6700 | return ret; | ||
6701 | } | ||
6702 | |||
6703 | tcph = (struct tcphdr *)*tcp; | ||
6704 | *tcp_len = get_l4_pyld_length(ip, tcph); | ||
6705 | for (i=0; i<MAX_LRO_SESSIONS; i++) { | ||
6706 | lro_t *l_lro = &sp->lro0_n[i]; | ||
6707 | if (l_lro->in_use) { | ||
6708 | if (check_for_socket_match(l_lro, ip, tcph)) | ||
6709 | continue; | ||
6710 | /* Sock pair matched */ | ||
6711 | *lro = l_lro; | ||
6712 | |||
6713 | if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) { | ||
6714 | DBG_PRINT(INFO_DBG, "%s:Out of order. expected " | ||
6715 | "0x%x, actual 0x%x\n", __FUNCTION__, | ||
6716 | (*lro)->tcp_next_seq, | ||
6717 | ntohl(tcph->seq)); | ||
6718 | |||
6719 | sp->mac_control.stats_info-> | ||
6720 | sw_stat.outof_sequence_pkts++; | ||
6721 | ret = 2; | ||
6722 | break; | ||
6723 | } | ||
6724 | |||
6725 | if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len)) | ||
6726 | ret = 1; /* Aggregate */ | ||
6727 | else | ||
6728 | ret = 2; /* Flush both */ | ||
6729 | break; | ||
6730 | } | ||
6731 | } | ||
6732 | |||
6733 | if (ret == 0) { | ||
6734 | /* Before searching for available LRO objects, | ||
6735 | * check if the pkt is L3/L4 aggregatable. If not | ||
6736 | * don't create new LRO session. Just send this | ||
6737 | * packet up. | ||
6738 | */ | ||
6739 | if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) { | ||
6740 | return 5; | ||
6741 | } | ||
6742 | |||
6743 | for (i=0; i<MAX_LRO_SESSIONS; i++) { | ||
6744 | lro_t *l_lro = &sp->lro0_n[i]; | ||
6745 | if (!(l_lro->in_use)) { | ||
6746 | *lro = l_lro; | ||
6747 | ret = 3; /* Begin anew */ | ||
6748 | break; | ||
6749 | } | ||
6750 | } | ||
6751 | } | ||
6752 | |||
6753 | if (ret == 0) { /* sessions exceeded */ | ||
6754 | DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n", | ||
6755 | __FUNCTION__); | ||
6756 | *lro = NULL; | ||
6757 | return ret; | ||
6758 | } | ||
6759 | |||
6760 | switch (ret) { | ||
6761 | case 3: | ||
6762 | initiate_new_session(*lro, buffer, ip, tcph, *tcp_len); | ||
6763 | break; | ||
6764 | case 2: | ||
6765 | update_L3L4_header(sp, *lro); | ||
6766 | break; | ||
6767 | case 1: | ||
6768 | aggregate_new_rx(*lro, ip, tcph, *tcp_len); | ||
6769 | if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) { | ||
6770 | update_L3L4_header(sp, *lro); | ||
6771 | ret = 4; /* Flush the LRO */ | ||
6772 | } | ||
6773 | break; | ||
6774 | default: | ||
6775 | DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n", | ||
6776 | __FUNCTION__); | ||
6777 | break; | ||
6778 | } | ||
6779 | |||
6780 | return ret; | ||
6781 | } | ||
6782 | |||
6783 | static void clear_lro_session(lro_t *lro) | ||
6784 | { | ||
6785 | static u16 lro_struct_size = sizeof(lro_t); | ||
6786 | |||
6787 | memset(lro, 0, lro_struct_size); | ||
6788 | } | ||
6789 | |||
6790 | static void queue_rx_frame(struct sk_buff *skb) | ||
6791 | { | ||
6792 | struct net_device *dev = skb->dev; | ||
6793 | |||
6794 | skb->protocol = eth_type_trans(skb, dev); | ||
6795 | #ifdef CONFIG_S2IO_NAPI | ||
6796 | netif_receive_skb(skb); | ||
6797 | #else | ||
6798 | netif_rx(skb); | ||
6799 | #endif | ||
6800 | } | ||
6801 | |||
6802 | static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, | ||
6803 | u32 tcp_len) | ||
6804 | { | ||
6805 | struct sk_buff *tmp, *first = lro->parent; | ||
6806 | |||
6807 | first->len += tcp_len; | ||
6808 | first->data_len = lro->frags_len; | ||
6809 | skb_pull(skb, (skb->len - tcp_len)); | ||
6810 | if ((tmp = skb_shinfo(first)->frag_list)) { | ||
6811 | while (tmp->next) | ||
6812 | tmp = tmp->next; | ||
6813 | tmp->next = skb; | ||
6814 | } | ||
6815 | else | ||
6816 | skb_shinfo(first)->frag_list = skb; | ||
6817 | sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++; | ||
6818 | return; | ||
6819 | } | ||