iw_cxgb4: don't truncate the recv window size
authorHariprasad Shenai <hariprasad@chelsio.com>
Fri, 6 Jun 2014 16:10:44 +0000 (21:40 +0530)
committerDavid S. Miller <davem@davemloft.net>
Wed, 11 Jun 2014 05:49:54 +0000 (22:49 -0700)
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>
drivers/infiniband/hw/cxgb4/cm.c
drivers/infiniband/hw/cxgb4/iw_cxgb4.h
drivers/net/ethernet/chelsio/cxgb4/t4_msg.h

index d2e9f72..965eaaf 100644 (file)
@@ -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(n->dev) * 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);
 
index 7474b49..7493dfe 100644 (file)
@@ -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)
index a4d7bdb..973eb11 100644 (file)
@@ -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)