]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
IB/hfi1: Add a function to receive TID RDMA ACK packet
authorKaike Wan <kaike.wan@intel.com>
Thu, 24 Jan 2019 05:50:14 +0000 (21:50 -0800)
committerDoug Ledford <dledford@redhat.com>
Tue, 5 Feb 2019 23:07:43 +0000 (18:07 -0500)
This patch adds a function to receive TID RDMA ACK packet, which could
be an acknowledge to either a TID RDMA WRITE DATA packet or an TID
RDMA RESYNC packet. For an ACK to TID RDMA WRITE DATA packet, the
request segments are completed appropriately. For an ACK to a TID
RDMA RESYNC packet, any pending segment flow information is updated
accordingly.

Signed-off-by: Mitko Haralanov <mitko.haralanov@intel.com>
Signed-off-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
Signed-off-by: Ashutosh Dixit <ashutosh.dixit@intel.com>
Signed-off-by: Kaike Wan <kaike.wan@intel.com>
Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/hw/hfi1/opfn.c
drivers/infiniband/hw/hfi1/qp.h
drivers/infiniband/hw/hfi1/tid_rdma.c
drivers/infiniband/hw/hfi1/tid_rdma.h
drivers/infiniband/hw/hfi1/trace_tid.h
drivers/infiniband/hw/hfi1/verbs.h

index 2ca070690b2f7e07d87a2ecd8300af5fa911cb98..82e1889ca9690b75a345d5cb3e90354d3d7d6ea4 100644 (file)
@@ -245,6 +245,9 @@ void opfn_qp_init(struct rvt_qp *qp, struct ib_qp_attr *attr, int attr_mask)
        struct hfi1_qp_priv *priv = qp->priv;
        unsigned long flags;
 
+       if (attr_mask & IB_QP_RETRY_CNT)
+               priv->s_retry = attr->retry_cnt;
+
        spin_lock_irqsave(&priv->opfn.lock, flags);
        if (ibqp->qp_type == IB_QPT_RC && HFI1_CAP_IS_KSET(TID_RDMA)) {
                struct tid_rdma_params *local = &priv->tid_rdma.local;
index f74e2509e8b9f98b58d15f387b3f7c5bf5af6e10..d531b760ea93ff422dfa3211b6505bb8075743cb 100644 (file)
@@ -65,6 +65,7 @@ extern const struct rvt_operation_params hfi1_post_parms[];
  * HFI1_S_WAIT_PIO_DRAIN - qp waiting for PIOs to drain
  * HFI1_S_WAIT_TID_SPACE - a QP is waiting for TID resource
  * HFI1_S_WAIT_TID_RESP - waiting for a TID RDMA WRITE response
+ * HFI1_S_WAIT_HALT - halt the first leg send engine
  * HFI1_S_MIN_BIT_MASK - the lowest bit that can be used by hfi1
  */
 #define HFI1_S_AHG_VALID         0x80000000
@@ -72,6 +73,7 @@ extern const struct rvt_operation_params hfi1_post_parms[];
 #define HFI1_S_WAIT_PIO_DRAIN    0x20000000
 #define HFI1_S_WAIT_TID_SPACE    0x10000000
 #define HFI1_S_WAIT_TID_RESP     0x08000000
+#define HFI1_S_WAIT_HALT         0x04000000
 #define HFI1_S_MIN_BIT_MASK      0x01000000
 
 /*
index d8a7f07b028d000af0aae8a6d3b68c83fda55e86..5eb8453a719e2749dafc8a4ce25c86cc88fe9fcd 100644 (file)
@@ -319,6 +319,7 @@ int hfi1_qp_priv_init(struct rvt_dev_info *rdi, struct rvt_qp *qp,
        qpriv->flow_state.index = RXE_NUM_TID_FLOWS;
        qpriv->flow_state.last_index = RXE_NUM_TID_FLOWS;
        qpriv->flow_state.generation = KERN_GENERATION_RESERVED;
+       qpriv->s_state = TID_OP(WRITE_RESP);
        qpriv->s_tid_cur = HFI1_QP_WQE_INVALID;
        qpriv->s_tid_head = HFI1_QP_WQE_INVALID;
        qpriv->s_tid_tail = HFI1_QP_WQE_INVALID;
@@ -327,6 +328,7 @@ int hfi1_qp_priv_init(struct rvt_dev_info *rdi, struct rvt_qp *qp,
        qpriv->r_tid_tail = HFI1_QP_WQE_INVALID;
        qpriv->r_tid_ack = HFI1_QP_WQE_INVALID;
        qpriv->r_tid_alloc = HFI1_QP_WQE_INVALID;
+       atomic_set(&qpriv->n_tid_requests, 0);
        timer_setup(&qpriv->s_tid_timer, hfi1_tid_timeout, 0);
        INIT_LIST_HEAD(&qpriv->tid_wait);
 
@@ -4318,3 +4320,213 @@ u32 hfi1_build_tid_rdma_write_ack(struct rvt_qp *qp, struct rvt_ack_entry *e,
 
        return sizeof(ohdr->u.tid_rdma.ack) / sizeof(u32);
 }
+
+void hfi1_rc_rcv_tid_rdma_ack(struct hfi1_packet *packet)
+{
+       struct ib_other_headers *ohdr = packet->ohdr;
+       struct rvt_qp *qp = packet->qp;
+       struct hfi1_qp_priv *qpriv = qp->priv;
+       struct rvt_swqe *wqe;
+       struct tid_rdma_request *req;
+       struct tid_rdma_flow *flow;
+       u32 aeth, psn, req_psn, ack_psn, fspsn, resync_psn, ack_kpsn;
+       bool is_fecn;
+       unsigned long flags;
+       u16 fidx;
+
+       is_fecn = process_ecn(qp, packet);
+       psn = mask_psn(be32_to_cpu(ohdr->bth[2]));
+       aeth = be32_to_cpu(ohdr->u.tid_rdma.ack.aeth);
+       req_psn = mask_psn(be32_to_cpu(ohdr->u.tid_rdma.ack.verbs_psn));
+       resync_psn = mask_psn(be32_to_cpu(ohdr->u.tid_rdma.ack.tid_flow_psn));
+
+       spin_lock_irqsave(&qp->s_lock, flags);
+
+       /* If we are waiting for an ACK to RESYNC, drop any other packets */
+       if ((qp->s_flags & HFI1_S_WAIT_HALT) &&
+           cmp_psn(psn, qpriv->s_resync_psn))
+               goto ack_op_err;
+
+       ack_psn = req_psn;
+       if (hfi1_tid_rdma_is_resync_psn(psn))
+               ack_kpsn = resync_psn;
+       else
+               ack_kpsn = psn;
+       if (aeth >> 29) {
+               ack_psn--;
+               ack_kpsn--;
+       }
+
+       wqe = rvt_get_swqe_ptr(qp, qp->s_acked);
+
+       if (wqe->wr.opcode != IB_WR_TID_RDMA_WRITE)
+               goto ack_op_err;
+
+       req = wqe_to_tid_req(wqe);
+       flow = &req->flows[req->acked_tail];
+
+       /* Drop stale ACK/NAK */
+       if (cmp_psn(psn, full_flow_psn(flow, flow->flow_state.spsn)) < 0)
+               goto ack_op_err;
+
+       while (cmp_psn(ack_kpsn,
+                      full_flow_psn(flow, flow->flow_state.lpsn)) >= 0 &&
+              req->ack_seg < req->cur_seg) {
+               req->ack_seg++;
+               /* advance acked segment pointer */
+               req->acked_tail = CIRC_NEXT(req->acked_tail, MAX_FLOWS);
+               req->r_last_acked = flow->flow_state.resp_ib_psn;
+               if (req->ack_seg == req->total_segs) {
+                       req->state = TID_REQUEST_COMPLETE;
+                       wqe = do_rc_completion(qp, wqe,
+                                              to_iport(qp->ibqp.device,
+                                                       qp->port_num));
+                       atomic_dec(&qpriv->n_tid_requests);
+                       if (qp->s_acked == qp->s_tail)
+                               break;
+                       if (wqe->wr.opcode != IB_WR_TID_RDMA_WRITE)
+                               break;
+                       req = wqe_to_tid_req(wqe);
+               }
+               flow = &req->flows[req->acked_tail];
+       }
+
+       switch (aeth >> 29) {
+       case 0:         /* ACK */
+               if (qpriv->s_flags & RVT_S_WAIT_ACK)
+                       qpriv->s_flags &= ~RVT_S_WAIT_ACK;
+               if (!hfi1_tid_rdma_is_resync_psn(psn)) {
+                       hfi1_schedule_send(qp);
+               } else {
+                       u32 spsn, fpsn, last_acked, generation;
+                       struct tid_rdma_request *rptr;
+
+                       /* Allow new requests (see hfi1_make_tid_rdma_pkt) */
+                       qp->s_flags &= ~HFI1_S_WAIT_HALT;
+                       /*
+                        * Clear RVT_S_SEND_ONE flag in case that the TID RDMA
+                        * ACK is received after the TID retry timer is fired
+                        * again. In this case, do not send any more TID
+                        * RESYNC request or wait for any more TID ACK packet.
+                        */
+                       qpriv->s_flags &= ~RVT_S_SEND_ONE;
+                       hfi1_schedule_send(qp);
+
+                       if ((qp->s_acked == qpriv->s_tid_tail &&
+                            req->ack_seg == req->total_segs) ||
+                           qp->s_acked == qp->s_tail) {
+                               qpriv->s_state = TID_OP(WRITE_DATA_LAST);
+                               goto done;
+                       }
+
+                       if (req->ack_seg == req->comp_seg) {
+                               qpriv->s_state = TID_OP(WRITE_DATA);
+                               goto done;
+                       }
+
+                       /*
+                        * The PSN to start with is the next PSN after the
+                        * RESYNC PSN.
+                        */
+                       psn = mask_psn(psn + 1);
+                       generation = psn >> HFI1_KDETH_BTH_SEQ_SHIFT;
+                       spsn = 0;
+
+                       /*
+                        * Update to the correct WQE when we get an ACK(RESYNC)
+                        * in the middle of a request.
+                        */
+                       if (delta_psn(ack_psn, wqe->lpsn))
+                               wqe = rvt_get_swqe_ptr(qp, qp->s_acked);
+                       req = wqe_to_tid_req(wqe);
+                       flow = &req->flows[req->acked_tail];
+                       /*
+                        * RESYNC re-numbers the PSN ranges of all remaining
+                        * segments. Also, PSN's start from 0 in the middle of a
+                        * segment and the first segment size is less than the
+                        * default number of packets. flow->resync_npkts is used
+                        * to track the number of packets from the start of the
+                        * real segment to the point of 0 PSN after the RESYNC
+                        * in order to later correctly rewind the SGE.
+                        */
+                       fpsn = full_flow_psn(flow, flow->flow_state.spsn);
+                       req->r_ack_psn = psn;
+                       flow->resync_npkts +=
+                               delta_psn(mask_psn(resync_psn + 1), fpsn);
+                       /*
+                        * Renumber all packet sequence number ranges
+                        * based on the new generation.
+                        */
+                       last_acked = qp->s_acked;
+                       rptr = req;
+                       while (1) {
+                               /* start from last acked segment */
+                               for (fidx = rptr->acked_tail;
+                                    CIRC_CNT(rptr->setup_head, fidx,
+                                             MAX_FLOWS);
+                                    fidx = CIRC_NEXT(fidx, MAX_FLOWS)) {
+                                       u32 lpsn;
+                                       u32 gen;
+
+                                       flow = &rptr->flows[fidx];
+                                       gen = flow->flow_state.generation;
+                                       if (WARN_ON(gen == generation &&
+                                                   flow->flow_state.spsn !=
+                                                    spsn))
+                                               continue;
+                                       lpsn = flow->flow_state.lpsn;
+                                       lpsn = full_flow_psn(flow, lpsn);
+                                       flow->npkts =
+                                               delta_psn(lpsn,
+                                                         mask_psn(resync_psn)
+                                                         );
+                                       flow->flow_state.generation =
+                                               generation;
+                                       flow->flow_state.spsn = spsn;
+                                       flow->flow_state.lpsn =
+                                               flow->flow_state.spsn +
+                                               flow->npkts - 1;
+                                       flow->pkt = 0;
+                                       spsn += flow->npkts;
+                                       resync_psn += flow->npkts;
+                               }
+                               if (++last_acked == qpriv->s_tid_cur + 1)
+                                       break;
+                               if (last_acked == qp->s_size)
+                                       last_acked = 0;
+                               wqe = rvt_get_swqe_ptr(qp, last_acked);
+                               rptr = wqe_to_tid_req(wqe);
+                       }
+                       req->cur_seg = req->ack_seg;
+                       qpriv->s_tid_tail = qp->s_acked;
+                       qpriv->s_state = TID_OP(WRITE_REQ);
+               }
+done:
+               qpriv->s_retry = qp->s_retry_cnt;
+               break;
+
+       case 3:         /* NAK */
+               switch ((aeth >> IB_AETH_CREDIT_SHIFT) &
+                       IB_AETH_CREDIT_MASK) {
+               case 0: /* PSN sequence error */
+                       flow = &req->flows[req->acked_tail];
+                       fspsn = full_flow_psn(flow, flow->flow_state.spsn);
+                       req->r_ack_psn = mask_psn(be32_to_cpu(ohdr->bth[2]));
+                       req->cur_seg = req->ack_seg;
+                       qpriv->s_tid_tail = qp->s_acked;
+                       qpriv->s_state = TID_OP(WRITE_REQ);
+                       qpriv->s_retry = qp->s_retry_cnt;
+                       break;
+
+               default:
+                       break;
+               }
+               break;
+
+       default:
+               break;
+       }
+
+ack_op_err:
+       spin_unlock_irqrestore(&qp->s_lock, flags);
+}
index 89f5af627128c84bfe8c386fcf7afffd7540e8b0..499036e7a3e8cc14c12a1fe6cb4ae0bc4f73229b 100644 (file)
@@ -101,6 +101,7 @@ struct tid_rdma_request {
 
        u32 seg_len;
        u32 total_len;
+       u32 r_ack_psn;          /* next expected ack PSN */
        u32 r_flow_psn;         /* IB PSN of next segment start */
        u32 r_last_acked;       /* IB PSN of last ACK'ed packet */
        u32 s_next_psn;         /* IB PSN of next segment start for read */
@@ -285,4 +286,6 @@ u32 hfi1_build_tid_rdma_write_ack(struct rvt_qp *qp, struct rvt_ack_entry *e,
                                  struct ib_other_headers *ohdr, u16 iflow,
                                  u32 *bth1, u32 *bth2);
 
+void hfi1_rc_rcv_tid_rdma_ack(struct hfi1_packet *packet);
+
 #endif /* HFI1_TID_RDMA_H */
index 51f5b0e8da714f6e24fa0c8b475d79ddd6412f5a..a45b5257d6c43fcb1368a147860de4e53146ec1c 100644 (file)
@@ -52,7 +52,7 @@ u16 hfi1_trace_get_tid_idx(u32 ent);
 #define TID_READ_SENDER_PRN "[%s] qpn 0x%x newreq %u tid_r_reqs %u " \
                            "tid_r_comp %u pending_tid_r_segs %u " \
                            "s_flags 0x%x ps_flags 0x%x iow_flags 0x%lx " \
-                           "hw_flow_index %u generation 0x%x " \
+                           "s_state 0x%x hw_flow_index %u generation 0x%x " \
                            "fpsn 0x%x flow_flags 0x%x"
 
 #define TID_REQ_PRN "[%s] qpn 0x%x newreq %u opcode 0x%x psn 0x%x lpsn 0x%x " \
@@ -844,6 +844,7 @@ DECLARE_EVENT_CLASS(/* tid_read_sender */
                __field(u32, s_flags)
                __field(u32, ps_flags)
                __field(unsigned long, iow_flags)
+               __field(u8, s_state)
                __field(u32, hw_flow_index)
                __field(u32, generation)
                __field(u32, fpsn)
@@ -861,6 +862,7 @@ DECLARE_EVENT_CLASS(/* tid_read_sender */
                __entry->s_flags = qp->s_flags;
                __entry->ps_flags = priv->s_flags;
                __entry->iow_flags = priv->s_iowait.flags;
+               __entry->s_state = priv->s_state;
                __entry->hw_flow_index = priv->flow_state.index;
                __entry->generation = priv->flow_state.generation;
                __entry->fpsn = priv->flow_state.psn;
@@ -877,6 +879,7 @@ DECLARE_EVENT_CLASS(/* tid_read_sender */
                __entry->s_flags,
                __entry->ps_flags,
                __entry->iow_flags,
+               __entry->s_state,
                __entry->hw_flow_index,
                __entry->generation,
                __entry->fpsn,
index 3a97a39aeba443cba41836b2075cc51ff28c6970..30e3f5af5cf101e1873da6868784977b66261919 100644 (file)
@@ -170,9 +170,12 @@ struct hfi1_qp_priv {
        struct tid_rdma_qp_params tid_rdma;
        struct rvt_qp *owner;
        u8 hdr_type; /* 9B or 16B */
+       atomic_t n_tid_requests;            /* # of sent TID RDMA requests */
        unsigned long tid_timer_timeout_jiffies;
 
        /* variables for the TID RDMA SE state machine */
+       u8 s_state;
+       u8 s_retry;
        u8 rnr_nak_state;       /* RNR NAK state */
        u8 s_nak_state;
        u32 s_nak_psn;
@@ -197,6 +200,7 @@ struct hfi1_qp_priv {
 
        u32 r_next_psn_kdeth;
        u32 r_next_psn_kdeth_save;
+       u32 s_resync_psn;
        u8 sync_pt;           /* Set when QP reaches sync point */
        u8 resync;
 };