qlcnic: Fix estimation of recv MSS in case of LRO
authorRajesh Borundia <rajesh.borundia@qlogic.com>
Wed, 6 Jun 2012 07:35:06 +0000 (07:35 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 7 Jun 2012 20:18:53 +0000 (13:18 -0700)
o Linux stack estimates MSS from skb->len or skb_shinfo(skb)->gso_size.
In case of LRO skb->len is aggregate of len of number of packets hence MSS
obtained using skb->len would be incorrect. Incorrect estimation of recv MSS
would lead to delayed acks in some traffic patterns (which sends two or three
packets and wait for ack and only then send remaining packets). This leads to
drop in performance. Hence we need to set gso_size to MSS obtained from firmware.

o This is fixed recently in firmware hence the MSS is obtained based on
capability. If fw is capable of sending the MSS then only driver sets the gso_size.

Signed-off-by: Rajesh Borundia <rajesh.borundia@qlogic.com>
Signed-off-by: Anirban Chakraborty <anirban.chakraborty@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hdr.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c

index 8680a5dae4a2e175e18dc91cbe4f204f135915a6..520ff031cfaaf27c425a6a5aa3da6d3f4142dff7 100644 (file)
@@ -258,6 +258,8 @@ struct rcv_desc {
        (((sts_data) >> 52) & 0x1)
 #define qlcnic_get_lro_sts_seq_number(sts_data)                \
        ((sts_data) & 0x0FFFFFFFF)
+#define qlcnic_get_lro_sts_mss(sts_data1)              \
+       ((sts_data1 >> 32) & 0x0FFFF)
 
 
 struct status_desc {
@@ -623,6 +625,7 @@ struct qlcnic_recv_context {
 #define QLCNIC_CAP0_JUMBO_CONTIGUOUS   (1 << 7)
 #define QLCNIC_CAP0_LRO_CONTIGUOUS     (1 << 8)
 #define QLCNIC_CAP0_VALIDOFF           (1 << 11)
+#define QLCNIC_CAP0_LRO_MSS            (1 << 21)
 
 /*
  * Context state
@@ -829,6 +832,9 @@ struct qlcnic_mac_list_s {
 #define QLCNIC_FW_CAPABILITY_FVLANTX           BIT_9
 #define QLCNIC_FW_CAPABILITY_HW_LRO            BIT_10
 #define QLCNIC_FW_CAPABILITY_MULTI_LOOPBACK    BIT_27
+#define QLCNIC_FW_CAPABILITY_MORE_CAPS         BIT_31
+
+#define QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG BIT_2
 
 /* module types */
 #define LINKEVENT_MODULE_NOT_PRESENT                   1
@@ -918,6 +924,7 @@ struct qlcnic_ipaddr {
 #define QLCNIC_NEED_FLR                        0x1000
 #define QLCNIC_FW_RESET_OWNER          0x2000
 #define QLCNIC_FW_HANG                 0x4000
+#define QLCNIC_FW_LRO_MSS_CAP          0x8000
 #define QLCNIC_IS_MSI_FAMILY(adapter) \
        ((adapter)->flags & (QLCNIC_MSI_ENABLED | QLCNIC_MSIX_ENABLED))
 
index 8db85244e8adc553c0e3f99db6ade641998c9bc8..cfa174d3a3b1fa3e73cd05aaa3d9da92b8959153 100644 (file)
@@ -237,6 +237,9 @@ qlcnic_fw_cmd_create_rx_ctx(struct qlcnic_adapter *adapter)
                                                | QLCNIC_CAP0_VALIDOFF);
        cap |= (QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS);
 
+       if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+               cap |= QLCNIC_CAP0_LRO_MSS;
+
        prq->valid_field_offset = offsetof(struct qlcnic_hostrq_rx_ctx,
                                                         msix_handler);
        prq->txrx_sds_binding = nsds_rings - 1;
index 6ced3195aad3215c0a0033ac56a71aa6c78d3c54..28a6b28192e302227a9b02552c0acef56e6ea560 100644 (file)
@@ -588,6 +588,7 @@ enum {
 #define CRB_DRIVER_VERSION             (QLCNIC_REG(0x2a0))
 
 #define CRB_FW_CAPABILITIES_1          (QLCNIC_CAM_RAM(0x128))
+#define CRB_FW_CAPABILITIES_2          (QLCNIC_CAM_RAM(0x12c))
 #define CRB_MAC_BLOCK_START            (QLCNIC_CAM_RAM(0x1c0))
 
 /*
index 799fd40ed03ad3643cc7d28ed927c10e3bc80c7e..8620b696aca82b55f9b1c0232b8403620bb48056 100644 (file)
@@ -1653,6 +1653,9 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
 
        length = skb->len;
 
+       if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+               skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1);
+
        if (vid != 0xffff)
                __vlan_hwaccel_put_tag(skb, vid);
        netif_receive_skb(skb);
index 46e77a2c51219223909f40d6fb223c0981d37a26..707b5ca3dddef39fd2db34168efaeb84227e302e 100644 (file)
@@ -1136,6 +1136,8 @@ static int
 __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
 {
        int ring;
+       u32 capab2;
+
        struct qlcnic_host_rds_ring *rds_ring;
 
        if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
@@ -1146,6 +1148,12 @@ __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
        if (qlcnic_set_eswitch_port_config(adapter))
                return -EIO;
 
+       if (adapter->capabilities & QLCNIC_FW_CAPABILITY_MORE_CAPS) {
+               capab2 = QLCRD32(adapter, CRB_FW_CAPABILITIES_2);
+               if (capab2 & QLCNIC_FW_CAPABILITY_2_LRO_MAX_TCP_SEG)
+                       adapter->flags |= QLCNIC_FW_LRO_MSS_CAP;
+       }
+
        if (qlcnic_fw_create_ctx(adapter))
                return -EIO;
 
@@ -1215,6 +1223,7 @@ __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
        qlcnic_napi_disable(adapter);
 
        qlcnic_fw_destroy_ctx(adapter);
+       adapter->flags &= ~QLCNIC_FW_LRO_MSS_CAP;
 
        qlcnic_reset_rx_buffers_list(adapter);
        qlcnic_release_tx_buffers(adapter);