]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/infiniband/hw/cxgb4/cm.c
gpio: rcar: Add support for DT IRQ flags
[karo-tx-linux.git] / drivers / infiniband / hw / cxgb4 / cm.c
index 96d7131ab974bbb1baffcef9be2a4521890c82e9..5e153f6d4b48f2d36abcceec8dcee0996e5bf6d1 100644 (file)
@@ -234,12 +234,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);
 }
@@ -473,7 +477,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 +569,17 @@ static void c4iw_record_pm_msg(struct c4iw_ep *ep,
                sizeof(ep->com.mapped_remote_addr));
 }
 
+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;
@@ -591,6 +606,7 @@ static int send_connect(struct c4iw_ep *ep)
                                   &ep->com.mapped_local_addr;
        struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)
                                   &ep->com.mapped_remote_addr;
+       int win;
 
        wrlen = (ep->com.remote_addr.ss_family == AF_INET) ?
                        roundup(sizev4, 16) :
@@ -606,8 +622,18 @@ 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);
+
+       /*
+        * 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) |
@@ -618,7 +644,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);
@@ -674,6 +700,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);
@@ -690,6 +723,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 *)
@@ -713,6 +749,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);
                }
        }
@@ -1186,6 +1225,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);
@@ -1659,6 +1706,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));
@@ -1681,8 +1729,18 @@ 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);
+
+       /*
+        * 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) |
@@ -1694,7 +1752,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) |
@@ -1731,6 +1789,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,
@@ -1779,6 +1844,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);
@@ -1797,6 +1863,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;
@@ -2027,13 +2094,36 @@ 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;
+       int win;
 
        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);
+
+       /*
+        * 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) |
@@ -2044,7 +2134,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);
 
@@ -2064,14 +2154,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);
@@ -2136,6 +2230,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) {
@@ -2193,8 +2288,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;