]> git.openfabrics.org - ~emulex/compat-rdma.git/commitdiff
cxgb4/iw_cxgb4 fixes
authorSteve Wise <swise@opengridcomputing.com>
Tue, 17 Jun 2014 21:07:15 +0000 (16:07 -0500)
committerSteve Wise <swise@opengridcomputing.com>
Tue, 17 Jun 2014 21:07:15 +0000 (16:07 -0500)
Cherry pick these from linux-3.16-rc1:

c887ad0 cxgb4: Change default Interrupt Holdoff Packet Count Threshold
b408ff2 iw_cxgb4: don't truncate the recv window size
92e7ae7 iw_cxgb4: Choose appropriate hw mtu index and ISS for iWARP connections
cf38be6 iw_cxgb4: Allocate and use IQs specifically for indirect interrupts

Signed-off-by: Steve Wise <swise@opengridcomputing.com>
linux-next-cherry-picks/0097-0064-iw_cxgb4--Allocate-and-use-IQs-specifically-for-indirect-interrupts.patch [new file with mode: 0644]
linux-next-cherry-picks/0098-0065-iw_cxgb4--Choose-appropriate-hw-mtu-index-and-ISS-for-iWARP-connections.patch [new file with mode: 0644]
linux-next-cherry-picks/0099-0066-iw_cxgb4--don't-truncate-the-recv-window-size.patch [new file with mode: 0644]
linux-next-cherry-picks/0100-0067-cxgb4--Change-default-Interrupt-Holdoff-Packet-Count-Threshold.patch [new file with mode: 0644]

diff --git a/linux-next-cherry-picks/0097-0064-iw_cxgb4--Allocate-and-use-IQs-specifically-for-indirect-interrupts.patch b/linux-next-cherry-picks/0097-0064-iw_cxgb4--Allocate-and-use-IQs-specifically-for-indirect-interrupts.patch
new file mode 100644 (file)
index 0000000..7b18016
--- /dev/null
@@ -0,0 +1,337 @@
+commit cf38be6d61001b234d5b980d6e98702587638190
+Author: Hariprasad Shenai <hariprasad@chelsio.com>
+Date:   Fri Jun 6 21:40:42 2014 +0530
+
+    iw_cxgb4: Allocate and use IQs specifically for indirect interrupts
+    
+    Currently indirect interrupts for RDMA CQs funnel through the LLD's RDMA
+    RXQs, which also handle direct interrupts for offload CPLs during RDMA
+    connection setup/teardown.  The intended T4 usage model, however, is to
+    have indirect interrupts flow through dedicated IQs. IE not to mix
+    indirect interrupts with CPL messages in an IQ.  This patch adds the
+    concept of RDMA concentrator IQs, or CIQs, setup and maintained by the
+    LLD and exported to iw_cxgb4 for use when creating CQs. RDMA CPLs will
+    flow through the LLD's RDMA RXQs, and CQ interrupts flow through the
+    CIQs.
+    
+    Design:
+    
+    cxgb4 creates and exports an array of CIQs for the RDMA ULD.  These IQs
+    are sized according to the max available CQs available at adapter init.
+    In addition, these IQs don't need FL buffers since they only service
+    indirect interrupts.  One CIQ is setup per RX channel similar to the
+    RDMA RXQs.
+    
+    iw_cxgb4 will utilize these CIQs based on the vector value passed into
+    create_cq().  The num_comp_vectors advertised by iw_cxgb4 will be the
+    number of CIQs configured, and thus the vector value will be the index
+    into the array of CIQs.
+    
+    Based on original work by Steve Wise <swise@opengridcomputing.com>
+    
+    Signed-off-by: Steve Wise <swise@opengridcomputing.com>
+    Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
+index cfaa56a..71fc2ef 100644
+--- a/drivers/infiniband/hw/cxgb4/cq.c
++++ b/drivers/infiniband/hw/cxgb4/cq.c
+@@ -134,7 +134,8 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
+                       V_FW_RI_RES_WR_IQANUS(0) |
+                       V_FW_RI_RES_WR_IQANUD(1) |
+                       F_FW_RI_RES_WR_IQANDST |
+-                      V_FW_RI_RES_WR_IQANDSTINDEX(*rdev->lldi.rxq_ids));
++                      V_FW_RI_RES_WR_IQANDSTINDEX(
++                              rdev->lldi.ciq_ids[cq->vector]));
+       res->u.cq.iqdroprss_to_iqesize = cpu_to_be16(
+                       F_FW_RI_RES_WR_IQDROPRSS |
+                       V_FW_RI_RES_WR_IQPCIECH(2) |
+@@ -870,6 +871,9 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
+       rhp = to_c4iw_dev(ibdev);
++      if (vector >= rhp->rdev.lldi.nciq)
++              return ERR_PTR(-EINVAL);
++
+       chp = kzalloc(sizeof(*chp), GFP_KERNEL);
+       if (!chp)
+               return ERR_PTR(-ENOMEM);
+@@ -915,6 +919,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev, int entries,
+       }
+       chp->cq.size = hwentries;
+       chp->cq.memsize = memsize;
++      chp->cq.vector = vector;
+       ret = create_cq(&rhp->rdev, &chp->cq,
+                       ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
+diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
+index a94a3e1..31cd188 100644
+--- a/drivers/infiniband/hw/cxgb4/provider.c
++++ b/drivers/infiniband/hw/cxgb4/provider.c
+@@ -499,7 +499,7 @@ int c4iw_register_device(struct c4iw_dev *dev)
+       dev->ibdev.node_type = RDMA_NODE_RNIC;
+       memcpy(dev->ibdev.node_desc, C4IW_NODE_DESC, sizeof(C4IW_NODE_DESC));
+       dev->ibdev.phys_port_cnt = dev->rdev.lldi.nports;
+-      dev->ibdev.num_comp_vectors = 1;
++      dev->ibdev.num_comp_vectors =  dev->rdev.lldi.nciq;
+       dev->ibdev.dma_device = &(dev->rdev.lldi.pdev->dev);
+       dev->ibdev.query_device = c4iw_query_device;
+       dev->ibdev.query_port = c4iw_query_port;
+diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
+index 2178f31..68b0a6b 100644
+--- a/drivers/infiniband/hw/cxgb4/t4.h
++++ b/drivers/infiniband/hw/cxgb4/t4.h
+@@ -542,6 +542,7 @@ struct t4_cq {
+       size_t memsize;
+       __be64 bits_type_ts;
+       u32 cqid;
++      int vector;
+       u16 size; /* including status page */
+       u16 cidx;
+       u16 sw_pidx;
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+index 32db377..f503dce 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+@@ -357,11 +357,17 @@ enum {
+       MAX_OFLD_QSETS = 16,          /* # of offload Tx/Rx queue sets */
+       MAX_CTRL_QUEUES = NCHAN,      /* # of control Tx queues */
+       MAX_RDMA_QUEUES = NCHAN,      /* # of streaming RDMA Rx queues */
++      MAX_RDMA_CIQS = NCHAN,        /* # of  RDMA concentrator IQs */
++      MAX_ISCSI_QUEUES = NCHAN,     /* # of streaming iSCSI Rx queues */
+ };
+ enum {
+-      MAX_EGRQ = 128,         /* max # of egress queues, including FLs */
+-      MAX_INGQ = 64           /* max # of interrupt-capable ingress queues */
++      INGQ_EXTRAS = 2,        /* firmware event queue and */
++                              /*   forwarded interrupts */
++      MAX_EGRQ = MAX_ETH_QSETS*2 + MAX_OFLD_QSETS*2
++                 + MAX_CTRL_QUEUES + MAX_RDMA_QUEUES + MAX_ISCSI_QUEUES,
++      MAX_INGQ = MAX_ETH_QSETS + MAX_OFLD_QSETS + MAX_RDMA_QUEUES
++                 + MAX_RDMA_CIQS + MAX_ISCSI_QUEUES + INGQ_EXTRAS,
+ };
+ struct adapter;
+@@ -538,6 +544,7 @@ struct sge {
+       struct sge_eth_rxq ethrxq[MAX_ETH_QSETS];
+       struct sge_ofld_rxq ofldrxq[MAX_OFLD_QSETS];
+       struct sge_ofld_rxq rdmarxq[MAX_RDMA_QUEUES];
++      struct sge_ofld_rxq rdmaciq[MAX_RDMA_CIQS];
+       struct sge_rspq fw_evtq ____cacheline_aligned_in_smp;
+       struct sge_rspq intrq ____cacheline_aligned_in_smp;
+@@ -548,8 +555,10 @@ struct sge {
+       u16 ethtxq_rover;           /* Tx queue to clean up next */
+       u16 ofldqsets;              /* # of active offload queue sets */
+       u16 rdmaqs;                 /* # of available RDMA Rx queues */
++      u16 rdmaciqs;               /* # of available RDMA concentrator IQs */
+       u16 ofld_rxq[MAX_OFLD_QSETS];
+       u16 rdma_rxq[NCHAN];
++      u16 rdma_ciq[NCHAN];
+       u16 timer_val[SGE_NTIMERS];
+       u8 counter_val[SGE_NCOUNTERS];
+       u32 fl_pg_order;            /* large page allocation size */
+@@ -577,6 +586,7 @@ struct sge {
+ #define for_each_ethrxq(sge, i) for (i = 0; i < (sge)->ethqsets; i++)
+ #define for_each_ofldrxq(sge, i) for (i = 0; i < (sge)->ofldqsets; i++)
+ #define for_each_rdmarxq(sge, i) for (i = 0; i < (sge)->rdmaqs; i++)
++#define for_each_rdmaciq(sge, i) for (i = 0; i < (sge)->rdmaciqs; i++)
+ struct l2t_data;
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+index 8cf6be9..c26c3f8 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -818,12 +818,17 @@ static void name_msix_vecs(struct adapter *adap)
+       for_each_rdmarxq(&adap->sge, i)
+               snprintf(adap->msix_info[msi_idx++].desc, n, "%s-rdma%d",
+                        adap->port[0]->name, i);
++
++      for_each_rdmaciq(&adap->sge, i)
++              snprintf(adap->msix_info[msi_idx++].desc, n, "%s-rdma-ciq%d",
++                       adap->port[0]->name, i);
+ }
+ static int request_msix_queue_irqs(struct adapter *adap)
+ {
+       struct sge *s = &adap->sge;
+-      int err, ethqidx, ofldqidx = 0, rdmaqidx = 0, msi_index = 2;
++      int err, ethqidx, ofldqidx = 0, rdmaqidx = 0, rdmaciqqidx = 0;
++      int msi_index = 2;
+       err = request_irq(adap->msix_info[1].vec, t4_sge_intr_msix, 0,
+                         adap->msix_info[1].desc, &s->fw_evtq);
+@@ -857,9 +862,21 @@ static int request_msix_queue_irqs(struct adapter *adap)
+                       goto unwind;
+               msi_index++;
+       }
++      for_each_rdmaciq(s, rdmaciqqidx) {
++              err = request_irq(adap->msix_info[msi_index].vec,
++                                t4_sge_intr_msix, 0,
++                                adap->msix_info[msi_index].desc,
++                                &s->rdmaciq[rdmaciqqidx].rspq);
++              if (err)
++                      goto unwind;
++              msi_index++;
++      }
+       return 0;
+ unwind:
++      while (--rdmaciqqidx >= 0)
++              free_irq(adap->msix_info[--msi_index].vec,
++                       &s->rdmaciq[rdmaciqqidx].rspq);
+       while (--rdmaqidx >= 0)
+               free_irq(adap->msix_info[--msi_index].vec,
+                        &s->rdmarxq[rdmaqidx].rspq);
+@@ -885,6 +902,8 @@ static void free_msix_queue_irqs(struct adapter *adap)
+               free_irq(adap->msix_info[msi_index++].vec, &s->ofldrxq[i].rspq);
+       for_each_rdmarxq(s, i)
+               free_irq(adap->msix_info[msi_index++].vec, &s->rdmarxq[i].rspq);
++      for_each_rdmaciq(s, i)
++              free_irq(adap->msix_info[msi_index++].vec, &s->rdmaciq[i].rspq);
+ }
+ /**
+@@ -1047,7 +1066,8 @@ freeout: t4_free_sge_resources(adap);
+               if (msi_idx > 0)
+                       msi_idx++;
+               err = t4_sge_alloc_rxq(adap, &q->rspq, false, dev, msi_idx,
+-                                     &q->fl, uldrx_handler);
++                                     q->fl.size ? &q->fl : NULL,
++                                     uldrx_handler);
+               if (err)
+                       goto freeout;
+               memset(&q->stats, 0, sizeof(q->stats));
+@@ -1064,13 +1084,28 @@ freeout:       t4_free_sge_resources(adap);
+               if (msi_idx > 0)
+                       msi_idx++;
+               err = t4_sge_alloc_rxq(adap, &q->rspq, false, adap->port[i],
+-                                     msi_idx, &q->fl, uldrx_handler);
++                                     msi_idx, q->fl.size ? &q->fl : NULL,
++                                     uldrx_handler);
+               if (err)
+                       goto freeout;
+               memset(&q->stats, 0, sizeof(q->stats));
+               s->rdma_rxq[i] = q->rspq.abs_id;
+       }
++      for_each_rdmaciq(s, i) {
++              struct sge_ofld_rxq *q = &s->rdmaciq[i];
++
++              if (msi_idx > 0)
++                      msi_idx++;
++              err = t4_sge_alloc_rxq(adap, &q->rspq, false, adap->port[i],
++                                     msi_idx, q->fl.size ? &q->fl : NULL,
++                                     uldrx_handler);
++              if (err)
++                      goto freeout;
++              memset(&q->stats, 0, sizeof(q->stats));
++              s->rdma_ciq[i] = q->rspq.abs_id;
++      }
++
+       for_each_port(adap, i) {
+               /*
+                * Note that ->rdmarxq[i].rspq.cntxt_id below is 0 if we don't
+@@ -3789,7 +3824,9 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
+       lli.mtus = adap->params.mtus;
+       if (uld == CXGB4_ULD_RDMA) {
+               lli.rxq_ids = adap->sge.rdma_rxq;
++              lli.ciq_ids = adap->sge.rdma_ciq;
+               lli.nrxq = adap->sge.rdmaqs;
++              lli.nciq = adap->sge.rdmaciqs;
+       } else if (uld == CXGB4_ULD_ISCSI) {
+               lli.rxq_ids = adap->sge.ofld_rxq;
+               lli.nrxq = adap->sge.ofldqsets;
+@@ -5695,6 +5732,7 @@ static void cfg_queues(struct adapter *adap)
+ {
+       struct sge *s = &adap->sge;
+       int i, q10g = 0, n10g = 0, qidx = 0;
++      int ciq_size;
+       for_each_port(adap, i)
+               n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg);
+@@ -5733,6 +5771,7 @@ static void cfg_queues(struct adapter *adap)
+                       s->ofldqsets = adap->params.nports;
+               /* For RDMA one Rx queue per channel suffices */
+               s->rdmaqs = adap->params.nports;
++              s->rdmaciqs = adap->params.nports;
+       }
+       for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) {
+@@ -5767,6 +5806,19 @@ static void cfg_queues(struct adapter *adap)
+               r->fl.size = 72;
+       }
++      ciq_size = 64 + adap->vres.cq.size + adap->tids.nftids;
++      if (ciq_size > SGE_MAX_IQ_SIZE) {
++              CH_WARN(adap, "CIQ size too small for available IQs\n");
++              ciq_size = SGE_MAX_IQ_SIZE;
++      }
++
++      for (i = 0; i < ARRAY_SIZE(s->rdmaciq); i++) {
++              struct sge_ofld_rxq *r = &s->rdmaciq[i];
++
++              init_rspq(&r->rspq, 0, 0, ciq_size, 64);
++              r->rspq.uld = CXGB4_ULD_RDMA;
++      }
++
+       init_rspq(&s->fw_evtq, 6, 0, 512, 64);
+       init_rspq(&s->intrq, 6, 0, 2 * MAX_INGQ, 64);
+ }
+@@ -5815,9 +5867,9 @@ static int enable_msix(struct adapter *adap)
+       want = s->max_ethqsets + EXTRA_VECS;
+       if (is_offload(adap)) {
+-              want += s->rdmaqs + s->ofldqsets;
++              want += s->rdmaqs + s->rdmaciqs + s->ofldqsets;
+               /* need nchan for each possible ULD */
+-              ofld_need = 2 * nchan;
++              ofld_need = 3 * nchan;
+       }
+       need = adap->params.nports + EXTRA_VECS + ofld_need;
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+index e274a04..87af314 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+@@ -232,8 +232,10 @@ struct cxgb4_lld_info {
+       const struct cxgb4_virt_res *vr;     /* assorted HW resources */
+       const unsigned short *mtus;          /* MTU table */
+       const unsigned short *rxq_ids;       /* the ULD's Rx queue ids */
++      const unsigned short *ciq_ids;       /* the ULD's concentrator IQ ids */
+       unsigned short nrxq;                 /* # of Rx queues */
+       unsigned short ntxq;                 /* # of Tx queues */
++      unsigned short nciq;                 /* # of concentrator IQ */
+       unsigned char nchan:4;               /* # of channels */
+       unsigned char nports:4;              /* # of ports */
+       unsigned char wr_cred;               /* WR 16-byte credits */
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
+index cced1a3..bd82939 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
+@@ -2515,6 +2515,10 @@ void t4_free_sge_resources(struct adapter *adap)
+               if (oq->rspq.desc)
+                       free_rspq_fl(adap, &oq->rspq, &oq->fl);
+       }
++      for (i = 0, oq = adap->sge.rdmaciq; i < adap->sge.rdmaciqs; i++, oq++) {
++              if (oq->rspq.desc)
++                      free_rspq_fl(adap, &oq->rspq, &oq->fl);
++      }
+       /* clean up offload Tx queues */
+       for (i = 0; i < ARRAY_SIZE(adap->sge.ofldtxq); i++) {
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+index 1d1623b..71b799b 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+@@ -68,6 +68,7 @@ enum {
+       SGE_MAX_WR_LEN = 512,     /* max WR size in bytes */
+       SGE_NTIMERS = 6,          /* # of interrupt holdoff timer values */
+       SGE_NCOUNTERS = 4,        /* # of interrupt packet counter values */
++      SGE_MAX_IQ_SIZE = 65520,
+       SGE_TIMER_RSTRT_CNTR = 6, /* restart RX packet threshold counter */
+       SGE_TIMER_UPD_CIDX = 7,   /* update cidx only */
diff --git a/linux-next-cherry-picks/0098-0065-iw_cxgb4--Choose-appropriate-hw-mtu-index-and-ISS-for-iWARP-connections.patch b/linux-next-cherry-picks/0098-0065-iw_cxgb4--Choose-appropriate-hw-mtu-index-and-ISS-for-iWARP-connections.patch
new file mode 100644 (file)
index 0000000..9ea6701
--- /dev/null
@@ -0,0 +1,370 @@
+commit 92e7ae71726ca9e16a8a88ebeee14eb5177575a1
+Author: Hariprasad Shenai <hariprasad@chelsio.com>
+Date:   Fri Jun 6 21:40:43 2014 +0530
+
+    iw_cxgb4: Choose appropriate hw mtu index and ISS for iWARP connections
+    
+    Select the appropriate hw mtu index and initial sequence number to optimize
+    hw memory performance.
+    
+    Add new cxgb4_best_aligned_mtu() which allows callers to provide enough
+    information to be used to [possibly] select an MTU which will result in the
+    TCP Data Segment Size (AKA Maximum Segment Size) to be an aligned value.
+    
+    If an RTR message exhange is required, then align the ISS to 8B - 1 + 4, so
+    that after the SYN the send seqno will align on a 4B boundary. The RTR
+    message exchange will leave the send seqno aligned on an 8B boundary.
+    If an RTR is not required, then align the ISS to 8B - 1.  The goal is
+    to have the send seqno be 8B aligned when we send the first FPDU.
+    
+    Based on original work by Casey Leedom <leeedom@chelsio.com> and
+    Steve Wise <swise@opengridcomputing.com>
+    
+    Signed-off-by: Casey Leedom <leedom@chelsio.com>
+    Signed-off-by: Steve Wise <swise@opengridcomputing.com>
+    Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
+index 1f863a9..d2e9f72 100644
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -232,12 +232,16 @@ static void release_tid(struct c4iw_rdev *rdev, u32 hwtid, struct sk_buff *skb)
+ static void set_emss(struct c4iw_ep *ep, u16 opt)
+ {
+-      ep->emss = ep->com.dev->rdev.lldi.mtus[GET_TCPOPT_MSS(opt)] - 40;
++      ep->emss = ep->com.dev->rdev.lldi.mtus[GET_TCPOPT_MSS(opt)] -
++                 sizeof(struct iphdr) - sizeof(struct tcphdr);
+       ep->mss = ep->emss;
+       if (GET_TCPOPT_TSTAMP(opt))
+               ep->emss -= 12;
+       if (ep->emss < 128)
+               ep->emss = 128;
++      if (ep->emss & 7)
++              PDBG("Warning: misaligned mtu idx %u mss %u emss=%u\n",
++                   GET_TCPOPT_MSS(opt), ep->mss, ep->emss);
+       PDBG("%s mss_idx %u mss %u emss=%u\n", __func__, GET_TCPOPT_MSS(opt),
+            ep->mss, ep->emss);
+ }
+@@ -528,6 +532,17 @@ static int send_abort(struct c4iw_ep *ep, struct sk_buff *skb, gfp_t gfp)
+       return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t);
+ }
++static void best_mtu(const unsigned short *mtus, unsigned short mtu,
++                   unsigned int *idx, int use_ts)
++{
++      unsigned short hdr_size = sizeof(struct iphdr) +
++                                sizeof(struct tcphdr) +
++                                (use_ts ? 12 : 0);
++      unsigned short data_size = mtu - hdr_size;
++
++      cxgb4_best_aligned_mtu(mtus, hdr_size, data_size, 8, idx);
++}
++
+ static int send_connect(struct c4iw_ep *ep)
+ {
+       struct cpl_act_open_req *req;
+@@ -565,7 +580,8 @@ static int send_connect(struct c4iw_ep *ep)
+       }
+       set_wr_txq(skb, CPL_PRIORITY_SETUP, ep->ctrlq_idx);
+-      cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx);
++      best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx,
++               enable_tcp_timestamps);
+       wscale = compute_wscale(rcv_win);
+       opt0 = (nocong ? NO_CONG(1) : 0) |
+              KEEP_ALIVE(1) |
+@@ -633,6 +649,13 @@ static int send_connect(struct c4iw_ep *ep)
+                       req6->opt2 = cpu_to_be32(opt2);
+               }
+       } else {
++              u32 isn = (prandom_u32() & ~7UL) - 1;
++
++              opt2 |= T5_OPT_2_VALID;
++              opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */
++              if (peer2peer)
++                      isn += 4;
++
+               if (ep->com.remote_addr.ss_family == AF_INET) {
+                       t5_req = (struct cpl_t5_act_open_req *)
+                                skb_put(skb, wrlen);
+@@ -649,6 +672,9 @@ static int send_connect(struct c4iw_ep *ep)
+                                                    cxgb4_select_ntuple(
+                                            ep->com.dev->rdev.lldi.ports[0],
+                                            ep->l2t)));
++                      t5_req->rsvd = cpu_to_be32(isn);
++                      PDBG("%s snd_isn %u\n", __func__,
++                           be32_to_cpu(t5_req->rsvd));
+                       t5_req->opt2 = cpu_to_be32(opt2);
+               } else {
+                       t5_req6 = (struct cpl_t5_act_open_req6 *)
+@@ -672,6 +698,9 @@ static int send_connect(struct c4iw_ep *ep)
+                                                       cxgb4_select_ntuple(
+                                               ep->com.dev->rdev.lldi.ports[0],
+                                               ep->l2t));
++                      t5_req6->rsvd = cpu_to_be32(isn);
++                      PDBG("%s snd_isn %u\n", __func__,
++                           be32_to_cpu(t5_req6->rsvd));
+                       t5_req6->opt2 = cpu_to_be32(opt2);
+               }
+       }
+@@ -1640,7 +1669,8 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
+                       htons(F_FW_OFLD_CONNECTION_WR_CPLRXDATAACK);
+       req->tcb.tx_max = (__force __be32) jiffies;
+       req->tcb.rcv_adv = htons(1);
+-      cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx);
++      best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx,
++               enable_tcp_timestamps);
+       wscale = compute_wscale(rcv_win);
+       req->tcb.opt0 = (__force __be64) (TCAM_BYPASS(1) |
+               (nocong ? NO_CONG(1) : 0) |
+@@ -1986,12 +2016,26 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
+       u64 opt0;
+       u32 opt2;
+       int wscale;
++      struct cpl_t5_pass_accept_rpl *rpl5 = NULL;
+       PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
+       BUG_ON(skb_cloned(skb));
+-      skb_trim(skb, sizeof(*rpl));
++
+       skb_get(skb);
+-      cxgb4_best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx);
++      rpl = cplhdr(skb);
++      if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
++              skb_trim(skb, roundup(sizeof(*rpl5), 16));
++              rpl5 = (void *)rpl;
++              INIT_TP_WR(rpl5, ep->hwtid);
++      } else {
++              skb_trim(skb, sizeof(*rpl));
++              INIT_TP_WR(rpl, ep->hwtid);
++      }
++      OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL,
++                                                  ep->hwtid));
++
++      best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx,
++               enable_tcp_timestamps && req->tcpopt.tstamp);
+       wscale = compute_wscale(rcv_win);
+       opt0 = (nocong ? NO_CONG(1) : 0) |
+              KEEP_ALIVE(1) |
+@@ -2023,14 +2067,18 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
+                       opt2 |= CCTRL_ECN(1);
+       }
+       if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
++              u32 isn = (prandom_u32() & ~7UL) - 1;
+               opt2 |= T5_OPT_2_VALID;
+               opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE);
++              opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */
++              rpl5 = (void *)rpl;
++              memset(&rpl5->iss, 0, roundup(sizeof(*rpl5)-sizeof(*rpl), 16));
++              if (peer2peer)
++                      isn += 4;
++              rpl5->iss = cpu_to_be32(isn);
++              PDBG("%s iss %u\n", __func__, be32_to_cpu(rpl5->iss));
+       }
+-      rpl = cplhdr(skb);
+-      INIT_TP_WR(rpl, ep->hwtid);
+-      OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_PASS_ACCEPT_RPL,
+-                                    ep->hwtid));
+       rpl->opt0 = cpu_to_be64(opt0);
+       rpl->opt2 = cpu_to_be32(opt2);
+       set_wr_txq(skb, CPL_PRIORITY_SETUP, ep->ctrlq_idx);
+@@ -2095,6 +2143,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
+       int err;
+       u16 peer_mss = ntohs(req->tcpopt.mss);
+       int iptype;
++      unsigned short hdrs;
+       parent_ep = lookup_stid(t, stid);
+       if (!parent_ep) {
+@@ -2152,8 +2201,10 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
+               goto reject;
+       }
+-      if (peer_mss && child_ep->mtu > (peer_mss + 40))
+-              child_ep->mtu = peer_mss + 40;
++      hdrs = sizeof(struct iphdr) + sizeof(struct tcphdr) +
++             ((enable_tcp_timestamps && req->tcpopt.tstamp) ? 12 : 0);
++      if (peer_mss && child_ep->mtu > (peer_mss + hdrs))
++              child_ep->mtu = peer_mss + hdrs;
+       state_set(&child_ep->com, CONNECTING);
+       child_ep->com.dev = dev;
+diff --git a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
+index 6121ca0..91289a0 100644
+--- a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
++++ b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
+@@ -848,6 +848,7 @@ enum {                     /* TCP congestion control algorithms */
+ #define V_CONG_CNTRL(x) ((x) << S_CONG_CNTRL)
+ #define G_CONG_CNTRL(x) (((x) >> S_CONG_CNTRL) & M_CONG_CNTRL)
++#define CONG_CNTRL_VALID   (1 << 18)
+ #define T5_OPT_2_VALID       (1 << 31)
+ #endif /* _T4FW_RI_API_H_ */
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+index c26c3f8..5fa5f2a 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -3428,6 +3428,77 @@ unsigned int cxgb4_best_mtu(const unsigned short *mtus, unsigned short mtu,
+ EXPORT_SYMBOL(cxgb4_best_mtu);
+ /**
++ *     cxgb4_best_aligned_mtu - find best MTU, [hopefully] data size aligned
++ *     @mtus: the HW MTU table
++ *     @header_size: Header Size
++ *     @data_size_max: maximum Data Segment Size
++ *     @data_size_align: desired Data Segment Size Alignment (2^N)
++ *     @mtu_idxp: HW MTU Table Index return value pointer (possibly NULL)
++ *
++ *     Similar to cxgb4_best_mtu() but instead of searching the Hardware
++ *     MTU Table based solely on a Maximum MTU parameter, we break that
++ *     parameter up into a Header Size and Maximum Data Segment Size, and
++ *     provide a desired Data Segment Size Alignment.  If we find an MTU in
++ *     the Hardware MTU Table which will result in a Data Segment Size with
++ *     the requested alignment _and_ that MTU isn't "too far" from the
++ *     closest MTU, then we'll return that rather than the closest MTU.
++ */
++unsigned int cxgb4_best_aligned_mtu(const unsigned short *mtus,
++                                  unsigned short header_size,
++                                  unsigned short data_size_max,
++                                  unsigned short data_size_align,
++                                  unsigned int *mtu_idxp)
++{
++      unsigned short max_mtu = header_size + data_size_max;
++      unsigned short data_size_align_mask = data_size_align - 1;
++      int mtu_idx, aligned_mtu_idx;
++
++      /* Scan the MTU Table till we find an MTU which is larger than our
++       * Maximum MTU or we reach the end of the table.  Along the way,
++       * record the last MTU found, if any, which will result in a Data
++       * Segment Length matching the requested alignment.
++       */
++      for (mtu_idx = 0, aligned_mtu_idx = -1; mtu_idx < NMTUS; mtu_idx++) {
++              unsigned short data_size = mtus[mtu_idx] - header_size;
++
++              /* If this MTU minus the Header Size would result in a
++               * Data Segment Size of the desired alignment, remember it.
++               */
++              if ((data_size & data_size_align_mask) == 0)
++                      aligned_mtu_idx = mtu_idx;
++
++              /* If we're not at the end of the Hardware MTU Table and the
++               * next element is larger than our Maximum MTU, drop out of
++               * the loop.
++               */
++              if (mtu_idx+1 < NMTUS && mtus[mtu_idx+1] > max_mtu)
++                      break;
++      }
++
++      /* If we fell out of the loop because we ran to the end of the table,
++       * then we just have to use the last [largest] entry.
++       */
++      if (mtu_idx == NMTUS)
++              mtu_idx--;
++
++      /* If we found an MTU which resulted in the requested Data Segment
++       * Length alignment and that's "not far" from the largest MTU which is
++       * less than or equal to the maximum MTU, then use that.
++       */
++      if (aligned_mtu_idx >= 0 &&
++          mtu_idx - aligned_mtu_idx <= 1)
++              mtu_idx = aligned_mtu_idx;
++
++      /* If the caller has passed in an MTU Index pointer, pass the
++       * MTU Index back.  Return the MTU value.
++       */
++      if (mtu_idxp)
++              *mtu_idxp = mtu_idx;
++      return mtus[mtu_idx];
++}
++EXPORT_SYMBOL(cxgb4_best_aligned_mtu);
++
++/**
+  *    cxgb4_port_chan - get the HW channel of a port
+  *    @dev: the net device for the port
+  *
+@@ -5572,13 +5643,41 @@ static int adap_init0(struct adapter *adap)
+ #undef FW_PARAM_PFVF
+ #undef FW_PARAM_DEV
+-      /*
+-       * These are finalized by FW initialization, load their values now.
++      /* The MTU/MSS Table is initialized by now, so load their values.  If
++       * we're initializing the adapter, then we'll make any modifications
++       * we want to the MTU/MSS Table and also initialize the congestion
++       * parameters.
+        */
+       t4_read_mtu_tbl(adap, adap->params.mtus, NULL);
+-      t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd,
+-                   adap->params.b_wnd);
++      if (state != DEV_STATE_INIT) {
++              int i;
++
++              /* The default MTU Table contains values 1492 and 1500.
++               * However, for TCP, it's better to have two values which are
++               * a multiple of 8 +/- 4 bytes apart near this popular MTU.
++               * This allows us to have a TCP Data Payload which is a
++               * multiple of 8 regardless of what combination of TCP Options
++               * are in use (always a multiple of 4 bytes) which is
++               * important for performance reasons.  For instance, if no
++               * options are in use, then we have a 20-byte IP header and a
++               * 20-byte TCP header.  In this case, a 1500-byte MSS would
++               * result in a TCP Data Payload of 1500 - 40 == 1460 bytes
++               * which is not a multiple of 8.  So using an MSS of 1488 in
++               * this case results in a TCP Data Payload of 1448 bytes which
++               * is a multiple of 8.  On the other hand, if 12-byte TCP Time
++               * Stamps have been negotiated, then an MTU of 1500 bytes
++               * results in a TCP Data Payload of 1448 bytes which, as
++               * above, is a multiple of 8 bytes ...
++               */
++              for (i = 0; i < NMTUS; i++)
++                      if (adap->params.mtus[i] == 1492) {
++                              adap->params.mtus[i] = 1488;
++                              break;
++                      }
++              t4_load_mtus(adap, adap->params.mtus, adap->params.a_wnd,
++                           adap->params.b_wnd);
++      }
+       t4_init_tp_params(adap);
+       adap->flags |= FW_OK;
+       return 0;
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+index 87af314..55e9daf 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+@@ -276,6 +276,11 @@ unsigned int cxgb4_port_viid(const struct net_device *dev);
+ unsigned int cxgb4_port_idx(const struct net_device *dev);
+ unsigned int cxgb4_best_mtu(const unsigned short *mtus, unsigned short mtu,
+                           unsigned int *idx);
++unsigned int cxgb4_best_aligned_mtu(const unsigned short *mtus,
++                                  unsigned short header_size,
++                                  unsigned short data_size_max,
++                                  unsigned short data_size_align,
++                                  unsigned int *mtu_idxp);
+ void cxgb4_get_tcp_stats(struct pci_dev *pdev, struct tp_tcp_stats *v4,
+                        struct tp_tcp_stats *v6);
+ void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask,
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+index f2738c7..a4d7bdb 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+@@ -278,6 +278,15 @@ struct cpl_pass_accept_rpl {
+       __be64 opt0;
+ };
++struct cpl_t5_pass_accept_rpl {
++      WR_HDR;
++      union opcode_tid ot;
++      __be32 opt2;
++      __be64 opt0;
++      __be32 iss;
++      __be32 rsvd;
++};
++
+ struct cpl_act_open_req {
+       WR_HDR;
+       union opcode_tid ot;
diff --git a/linux-next-cherry-picks/0099-0066-iw_cxgb4--don't-truncate-the-recv-window-size.patch b/linux-next-cherry-picks/0099-0066-iw_cxgb4--don't-truncate-the-recv-window-size.patch
new file mode 100644 (file)
index 0000000..327c7c2
--- /dev/null
@@ -0,0 +1,196 @@
+commit b408ff282dda0ef7a3218dc2e5f1399c665d4c20
+Author: Hariprasad Shenai <hariprasad@chelsio.com>
+Date:   Fri Jun 6 21:40:44 2014 +0530
+
+    iw_cxgb4: don't truncate the recv window size
+    
+    Fixed a bug that shows up with recv window sizes that exceed the size of
+    the RCV_BUFSIZ field in opt0 (>= 1024K).  If the recv window exceeds
+    this, then we specify the max possible in opt0, add add the rest in via
+    a RX_DATA_ACK credits.
+    
+    Signed-off-by: Steve Wise <swise@opengridcomputing.com>
+    Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
+index d2e9f72..965eaaf 100644
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -472,7 +472,7 @@ static void send_flowc(struct c4iw_ep *ep, struct sk_buff *skb)
+       flowc->mnemval[5].mnemonic = FW_FLOWC_MNEM_RCVNXT;
+       flowc->mnemval[5].val = cpu_to_be32(ep->rcv_seq);
+       flowc->mnemval[6].mnemonic = FW_FLOWC_MNEM_SNDBUF;
+-      flowc->mnemval[6].val = cpu_to_be32(snd_win);
++      flowc->mnemval[6].val = cpu_to_be32(ep->snd_win);
+       flowc->mnemval[7].mnemonic = FW_FLOWC_MNEM_MSS;
+       flowc->mnemval[7].val = cpu_to_be32(ep->emss);
+       /* Pad WR to 16 byte boundary */
+@@ -565,6 +565,7 @@ static int send_connect(struct c4iw_ep *ep)
+       struct sockaddr_in *ra = (struct sockaddr_in *)&ep->com.remote_addr;
+       struct sockaddr_in6 *la6 = (struct sockaddr_in6 *)&ep->com.local_addr;
+       struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)&ep->com.remote_addr;
++      int win;
+       wrlen = (ep->com.remote_addr.ss_family == AF_INET) ?
+                       roundup(sizev4, 16) :
+@@ -583,6 +584,15 @@ static int send_connect(struct c4iw_ep *ep)
+       best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx,
+                enable_tcp_timestamps);
+       wscale = compute_wscale(rcv_win);
++
++      /*
++       * Specify the largest window that will fit in opt0. The
++       * remainder will be specified in the rx_data_ack.
++       */
++      win = ep->rcv_win >> 10;
++      if (win > RCV_BUFSIZ_MASK)
++              win = RCV_BUFSIZ_MASK;
++
+       opt0 = (nocong ? NO_CONG(1) : 0) |
+              KEEP_ALIVE(1) |
+              DELACK(1) |
+@@ -593,7 +603,7 @@ static int send_connect(struct c4iw_ep *ep)
+              SMAC_SEL(ep->smac_idx) |
+              DSCP(ep->tos) |
+              ULP_MODE(ULP_MODE_TCPDDP) |
+-             RCV_BUFSIZ(rcv_win>>10);
++             RCV_BUFSIZ(win);
+       opt2 = RX_CHANNEL(0) |
+              CCTRL_ECN(enable_ecn) |
+              RSS_QUEUE_VALID | RSS_QUEUE(ep->rss_qid);
+@@ -1174,6 +1184,14 @@ static int update_rx_credits(struct c4iw_ep *ep, u32 credits)
+               return 0;
+       }
++      /*
++       * If we couldn't specify the entire rcv window at connection setup
++       * due to the limit in the number of bits in the RCV_BUFSIZ field,
++       * then add the overage in to the credits returned.
++       */
++      if (ep->rcv_win > RCV_BUFSIZ_MASK * 1024)
++              credits += ep->rcv_win - RCV_BUFSIZ_MASK * 1024;
++
+       req = (struct cpl_rx_data_ack *) skb_put(skb, wrlen);
+       memset(req, 0, wrlen);
+       INIT_TP_WR(req, ep->hwtid);
+@@ -1647,6 +1665,7 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
+       unsigned int mtu_idx;
+       int wscale;
+       struct sockaddr_in *sin;
++      int win;
+       skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
+       req = (struct fw_ofld_connection_wr *)__skb_put(skb, sizeof(*req));
+@@ -1672,6 +1691,15 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
+       best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx,
+                enable_tcp_timestamps);
+       wscale = compute_wscale(rcv_win);
++
++      /*
++       * Specify the largest window that will fit in opt0. The
++       * remainder will be specified in the rx_data_ack.
++       */
++      win = ep->rcv_win >> 10;
++      if (win > RCV_BUFSIZ_MASK)
++              win = RCV_BUFSIZ_MASK;
++
+       req->tcb.opt0 = (__force __be64) (TCAM_BYPASS(1) |
+               (nocong ? NO_CONG(1) : 0) |
+               KEEP_ALIVE(1) |
+@@ -1683,7 +1711,7 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
+               SMAC_SEL(ep->smac_idx) |
+               DSCP(ep->tos) |
+               ULP_MODE(ULP_MODE_TCPDDP) |
+-              RCV_BUFSIZ(rcv_win >> 10));
++              RCV_BUFSIZ(win));
+       req->tcb.opt2 = (__force __be32) (PACE(1) |
+               TX_QUEUE(ep->com.dev->rdev.lldi.tx_modq[ep->tx_chan]) |
+               RX_CHANNEL(0) |
+@@ -1720,6 +1748,13 @@ static int is_neg_adv(unsigned int status)
+              status == CPL_ERR_KEEPALV_NEG_ADVICE;
+ }
++static void set_tcp_window(struct c4iw_ep *ep, struct port_info *pi)
++{
++      ep->snd_win = snd_win;
++      ep->rcv_win = rcv_win;
++      PDBG("%s snd_win %d rcv_win %d\n", __func__, ep->snd_win, ep->rcv_win);
++}
++
+ #define ACT_OPEN_RETRY_COUNT 2
+ static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
+@@ -1768,6 +1803,7 @@ static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
+               ep->ctrlq_idx = cxgb4_port_idx(pdev);
+               ep->rss_qid = cdev->rdev.lldi.rxq_ids[
+                       cxgb4_port_idx(pdev) * step];
++              set_tcp_window(ep, (struct port_info *)netdev_priv(pdev));
+               dev_put(pdev);
+       } else {
+               pdev = get_real_dev(n->dev);
+@@ -1786,6 +1822,7 @@ static int import_ep(struct c4iw_ep *ep, int iptype, __u8 *peer_ip,
+                       cdev->rdev.lldi.nchan;
+               ep->rss_qid = cdev->rdev.lldi.rxq_ids[
+                       cxgb4_port_idx(pdev) * step];
++              set_tcp_window(ep, (struct port_info *)netdev_priv(pdev));
+               if (clear_mpa_v1) {
+                       ep->retry_with_mpa_v1 = 0;
+@@ -2017,6 +2054,7 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
+       u32 opt2;
+       int wscale;
+       struct cpl_t5_pass_accept_rpl *rpl5 = NULL;
++      int win;
+       PDBG("%s ep %p tid %u\n", __func__, ep, ep->hwtid);
+       BUG_ON(skb_cloned(skb));
+@@ -2037,6 +2075,14 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
+       best_mtu(ep->com.dev->rdev.lldi.mtus, ep->mtu, &mtu_idx,
+                enable_tcp_timestamps && req->tcpopt.tstamp);
+       wscale = compute_wscale(rcv_win);
++
++      /*
++       * Specify the largest window that will fit in opt0. The
++       * remainder will be specified in the rx_data_ack.
++       */
++      win = ep->rcv_win >> 10;
++      if (win > RCV_BUFSIZ_MASK)
++              win = RCV_BUFSIZ_MASK;
+       opt0 = (nocong ? NO_CONG(1) : 0) |
+              KEEP_ALIVE(1) |
+              DELACK(1) |
+@@ -2047,7 +2093,7 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
+              SMAC_SEL(ep->smac_idx) |
+              DSCP(ep->tos >> 2) |
+              ULP_MODE(ULP_MODE_TCPDDP) |
+-             RCV_BUFSIZ(rcv_win>>10);
++             RCV_BUFSIZ(win);
+       opt2 = RX_CHANNEL(0) |
+              RSS_QUEUE_VALID | RSS_QUEUE(ep->rss_qid);
+diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+index 7474b49..7493dfe 100644
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -805,6 +805,8 @@ struct c4iw_ep {
+       u8 retry_with_mpa_v1;
+       u8 tried_with_mpa_v1;
+       unsigned int retry_count;
++      int snd_win;
++      int rcv_win;
+ };
+ static inline struct c4iw_ep *to_ep(struct iw_cm_id *cm_id)
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+index a4d7bdb..973eb11 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
++++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+@@ -227,6 +227,7 @@ struct cpl_pass_open_req {
+ #define DELACK(x)     ((x) << 5)
+ #define ULP_MODE(x)   ((x) << 8)
+ #define RCV_BUFSIZ(x) ((x) << 12)
++#define RCV_BUFSIZ_MASK 0x3FFU
+ #define DSCP(x)       ((x) << 22)
+ #define SMAC_SEL(x)   ((u64)(x) << 28)
+ #define L2T_IDX(x)    ((u64)(x) << 36)
diff --git a/linux-next-cherry-picks/0100-0067-cxgb4--Change-default-Interrupt-Holdoff-Packet-Count-Threshold.patch b/linux-next-cherry-picks/0100-0067-cxgb4--Change-default-Interrupt-Holdoff-Packet-Count-Threshold.patch
new file mode 100644 (file)
index 0000000..a6adde5
--- /dev/null
@@ -0,0 +1,162 @@
+commit c887ad0e226b54b33670e22b3bffb53c8d0e3d28
+Author: Hariprasad Shenai <hariprasad@chelsio.com>
+Date:   Fri Jun 6 21:40:45 2014 +0530
+
+    cxgb4: Change default Interrupt Holdoff Packet Count Threshold
+    
+    Based on original work by Casey Leedom <leedom@chelsio.com>
+    
+    Signed-off-by: Casey Leedom <leedom@chelsio.com>
+    Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com>
+    Signed-off-by: David S. Miller <davem@davemloft.net>
+
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+index 5fa5f2a..2f8d6b9 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+@@ -2503,8 +2503,7 @@ static unsigned int qtimer_val(const struct adapter *adap,
+ }
+ /**
+- *    set_rxq_intr_params - set a queue's interrupt holdoff parameters
+- *    @adap: the adapter
++ *    set_rspq_intr_params - set a queue's interrupt holdoff parameters
+  *    @q: the Rx queue
+  *    @us: the hold-off time in us, or 0 to disable timer
+  *    @cnt: the hold-off packet count, or 0 to disable counter
+@@ -2512,9 +2511,11 @@ static unsigned int qtimer_val(const struct adapter *adap,
+  *    Sets an Rx queue's interrupt hold-off time and packet count.  At least
+  *    one of the two needs to be enabled for the queue to generate interrupts.
+  */
+-static int set_rxq_intr_params(struct adapter *adap, struct sge_rspq *q,
+-                             unsigned int us, unsigned int cnt)
++static int set_rspq_intr_params(struct sge_rspq *q,
++                              unsigned int us, unsigned int cnt)
+ {
++      struct adapter *adap = q->adap;
++
+       if ((us | cnt) == 0)
+               cnt = 1;
+@@ -2541,24 +2542,34 @@ static int set_rxq_intr_params(struct adapter *adap, struct sge_rspq *q,
+       return 0;
+ }
+-static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
++/**
++ * set_rx_intr_params - set a net devices's RX interrupt holdoff paramete!
++ * @dev: the network device
++ * @us: the hold-off time in us, or 0 to disable timer
++ * @cnt: the hold-off packet count, or 0 to disable counter
++ *
++ * Set the RX interrupt hold-off parameters for a network device.
++ */
++static int set_rx_intr_params(struct net_device *dev,
++                            unsigned int us, unsigned int cnt)
+ {
+-      const struct port_info *pi = netdev_priv(dev);
++      int i, err;
++      struct port_info *pi = netdev_priv(dev);
+       struct adapter *adap = pi->adapter;
+-      struct sge_rspq *q;
+-      int i;
+-      int r = 0;
+-
+-      for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++) {
+-              q = &adap->sge.ethrxq[i].rspq;
+-              r = set_rxq_intr_params(adap, q, c->rx_coalesce_usecs,
+-                      c->rx_max_coalesced_frames);
+-              if (r) {
+-                      dev_err(&dev->dev, "failed to set coalesce %d\n", r);
+-                      break;
+-              }
++      struct sge_eth_rxq *q = &adap->sge.ethrxq[pi->first_qset];
++
++      for (i = 0; i < pi->nqsets; i++, q++) {
++              err = set_rspq_intr_params(&q->rspq, us, cnt);
++              if (err)
++                      return err;
+       }
+-      return r;
++      return 0;
++}
++
++static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
++{
++      return set_rx_intr_params(dev, c->rx_coalesce_usecs,
++                                c->rx_max_coalesced_frames);
+ }
+ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+@@ -5812,12 +5823,12 @@ static inline bool is_x_10g_port(const struct link_config *lc)
+              (lc->supported & FW_PORT_CAP_SPEED_40G) != 0;
+ }
+-static inline void init_rspq(struct sge_rspq *q, u8 timer_idx, u8 pkt_cnt_idx,
++static inline void init_rspq(struct adapter *adap, struct sge_rspq *q,
++                           unsigned int us, unsigned int cnt,
+                            unsigned int size, unsigned int iqe_size)
+ {
+-      q->intr_params = QINTR_TIMER_IDX(timer_idx) |
+-                       (pkt_cnt_idx < SGE_NCOUNTERS ? QINTR_CNT_EN : 0);
+-      q->pktcnt_idx = pkt_cnt_idx < SGE_NCOUNTERS ? pkt_cnt_idx : 0;
++      q->adap = adap;
++      set_rspq_intr_params(q, us, cnt);
+       q->iqe_len = iqe_size;
+       q->size = size;
+ }
+@@ -5876,7 +5887,7 @@ static void cfg_queues(struct adapter *adap)
+       for (i = 0; i < ARRAY_SIZE(s->ethrxq); i++) {
+               struct sge_eth_rxq *r = &s->ethrxq[i];
+-              init_rspq(&r->rspq, 0, 0, 1024, 64);
++              init_rspq(adap, &r->rspq, 5, 10, 1024, 64);
+               r->fl.size = 72;
+       }
+@@ -5892,7 +5903,7 @@ static void cfg_queues(struct adapter *adap)
+       for (i = 0; i < ARRAY_SIZE(s->ofldrxq); i++) {
+               struct sge_ofld_rxq *r = &s->ofldrxq[i];
+-              init_rspq(&r->rspq, 0, 0, 1024, 64);
++              init_rspq(adap, &r->rspq, 5, 1, 1024, 64);
+               r->rspq.uld = CXGB4_ULD_ISCSI;
+               r->fl.size = 72;
+       }
+@@ -5900,7 +5911,7 @@ static void cfg_queues(struct adapter *adap)
+       for (i = 0; i < ARRAY_SIZE(s->rdmarxq); i++) {
+               struct sge_ofld_rxq *r = &s->rdmarxq[i];
+-              init_rspq(&r->rspq, 0, 0, 511, 64);
++              init_rspq(adap, &r->rspq, 5, 1, 511, 64);
+               r->rspq.uld = CXGB4_ULD_RDMA;
+               r->fl.size = 72;
+       }
+@@ -5914,12 +5925,12 @@ static void cfg_queues(struct adapter *adap)
+       for (i = 0; i < ARRAY_SIZE(s->rdmaciq); i++) {
+               struct sge_ofld_rxq *r = &s->rdmaciq[i];
+-              init_rspq(&r->rspq, 0, 0, ciq_size, 64);
++              init_rspq(adap, &r->rspq, 5, 1, ciq_size, 64);
+               r->rspq.uld = CXGB4_ULD_RDMA;
+       }
+-      init_rspq(&s->fw_evtq, 6, 0, 512, 64);
+-      init_rspq(&s->intrq, 6, 0, 2 * MAX_INGQ, 64);
++      init_rspq(adap, &s->fw_evtq, 0, 1, 1024, 64);
++      init_rspq(adap, &s->intrq, 0, 1, 2 * MAX_INGQ, 64);
+ }
+ /*
+diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
+index bd82939..58bd213 100644
+--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
++++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
+@@ -2215,7 +2215,6 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
+       iq->cntxt_id = ntohs(c.iqid);
+       iq->abs_id = ntohs(c.physiqid);
+       iq->size--;                           /* subtract status entry */
+-      iq->adap = adap;
+       iq->netdev = dev;
+       iq->handler = hnd;