]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/commitdiff
IB/{hfi1, qib, rdmavt}: Put qp in error state when cq is full
authorKamenee Arumugam <kamenee.arumugam@intel.com>
Fri, 28 Jun 2019 18:21:52 +0000 (14:21 -0400)
committerJason Gunthorpe <jgg@mellanox.com>
Sat, 29 Jun 2019 01:34:26 +0000 (22:34 -0300)
When a completion queue is full, the associated queue pairs are not put
into the error state. According to the IBTA specification, this is a
violation.

Quote from IBTA spec:
C9-218: A Requester Class F error occurs when the CQ is inaccessible or
full and an attempt is made to complete a WQE.  The Affected QP shall be
moved to the error state and affiliated asynchronous errors generated as
described in 11.6.3.1 Affiliated Asynchronous Events on page 678. The
current WQE and any subsequent WQEs are left in an unknown state.

C11-37: The CI shall generate a CQ Error when a CQ overrun is
detected. This condition will result in an Affiliated Asynchronous Error
for any associated Work Queues when they attempt to use that
CQ. Completions can no longer be added to the CQ. It is not guaranteed
that completions present in the CQ at the time the error occurred can be
retrieved. Possible causes include a CQ overrun or a CQ protection error.

Put the qp in error state when cq is full. Implement a state called full
to continue to put other associated QPs in error state.

Reviewed-by: Mike Marciniszyn <mike.marciniszyn@intel.com>
Reviewed-by: Michael J. Ruhl <michael.j.ruhl@intel.com>
Signed-off-by: Kamenee Arumugam <kamenee.arumugam@intel.com>
Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
drivers/infiniband/hw/hfi1/rc.c
drivers/infiniband/hw/hfi1/uc.c
drivers/infiniband/hw/hfi1/ud.c
drivers/infiniband/hw/qib/qib_rc.c
drivers/infiniband/hw/qib/qib_uc.c
drivers/infiniband/hw/qib/qib_ud.c
drivers/infiniband/sw/rdmavt/cq.c
drivers/infiniband/sw/rdmavt/qp.c
drivers/infiniband/sw/rdmavt/vt.h
include/rdma/rdmavt_cq.h
include/rdma/rdmavt_qp.h

index 235bdbc706acc01db8886c1da57f5fc0d83d8871..0477c14633ab8365849a8eecb24d2f0bcafb4feb 100644 (file)
@@ -3008,8 +3008,7 @@ send_last:
                wc.dlid_path_bits = 0;
                wc.port_num = 0;
                /* Signal completion event if the solicited bit is set. */
-               rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
-                            ib_bth_is_solicited(ohdr));
+               rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr));
                break;
 
        case OP(RDMA_WRITE_ONLY):
index 4ed4fcfabd6c67f3d85f6491f752258db432ca62..0c77f18120edb3d8f230eaee49e1f933dd5aa122 100644 (file)
@@ -476,8 +476,7 @@ last_imm:
                wc.dlid_path_bits = 0;
                wc.port_num = 0;
                /* Signal completion event if the solicited bit is set. */
-               rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
-                            ib_bth_is_solicited(ohdr));
+               rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr));
                break;
 
        case OP(RDMA_WRITE_FIRST):
index 4cb0fce5c096a6909fd05b2bb541c4bf37bf8157..e16d499cfd1ee2fb2b0c7abab5a1b32758f49f82 100644 (file)
@@ -255,8 +255,7 @@ static void ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
        wc.dlid_path_bits = rdma_ah_get_dlid(ah_attr) & ((1 << ppd->lmc) - 1);
        wc.port_num = qp->port_num;
        /* Signal completion event if the solicited bit is set. */
-       rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
-                    swqe->wr.send_flags & IB_SEND_SOLICITED);
+       rvt_recv_cq(qp, &wc, swqe->wr.send_flags & IB_SEND_SOLICITED);
        ibp->rvp.n_loop_pkts++;
 bail_unlock:
        spin_unlock_irqrestore(&qp->r_lock, flags);
@@ -1061,7 +1060,7 @@ void hfi1_ud_rcv(struct hfi1_packet *packet)
                dlid & ((1 << ppd_from_ibp(ibp)->lmc) - 1);
        wc.port_num = qp->port_num;
        /* Signal completion event if the solicited bit is set. */
-       rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc, solicited);
+       rvt_recv_cq(qp, &wc, solicited);
        return;
 
 drop:
index 8d9a94d6f68562d59f4a9b4f13389c3cc5acd99c..1d5e2d4ee257b3b0d2ccb49e8d2135d5722d722b 100644 (file)
@@ -1891,8 +1891,7 @@ send_last:
                wc.dlid_path_bits = 0;
                wc.port_num = 0;
                /* Signal completion event if the solicited bit is set. */
-               rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
-                            ib_bth_is_solicited(ohdr));
+               rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr));
                break;
 
        case OP(RDMA_WRITE_FIRST):
index 30c70ad0f4bf9c04c1d39603523d1c5ef8e85adc..e17b91e2c22a91022930dc6cbbc896500bf6663a 100644 (file)
@@ -400,8 +400,7 @@ last_imm:
                wc.dlid_path_bits = 0;
                wc.port_num = 0;
                /* Signal completion event if the solicited bit is set. */
-               rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
-                            ib_bth_is_solicited(ohdr));
+               rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr));
                break;
 
        case OP(RDMA_WRITE_FIRST):
index 5cdedba2d164ee4ba8d1f37f3fb8aa6493f7bd83..32ad0b635fc6b817595e5442d39525860117fb84 100644 (file)
@@ -210,8 +210,7 @@ static void qib_ud_loopback(struct rvt_qp *sqp, struct rvt_swqe *swqe)
        wc.dlid_path_bits = rdma_ah_get_dlid(ah_attr) & ((1 << ppd->lmc) - 1);
        wc.port_num = qp->port_num;
        /* Signal completion event if the solicited bit is set. */
-       rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
-                    swqe->wr.send_flags & IB_SEND_SOLICITED);
+       rvt_recv_cq(qp, &wc, swqe->wr.send_flags & IB_SEND_SOLICITED);
        ibp->rvp.n_loop_pkts++;
 bail_unlock:
        spin_unlock_irqrestore(&qp->r_lock, flags);
@@ -573,8 +572,7 @@ void qib_ud_rcv(struct qib_ibport *ibp, struct ib_header *hdr,
                dlid & ((1 << ppd_from_ibp(ibp)->lmc) - 1);
        wc.port_num = qp->port_num;
        /* Signal completion event if the solicited bit is set. */
-       rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
-                    ib_bth_is_solicited(ohdr));
+       rvt_recv_cq(qp, &wc, ib_bth_is_solicited(ohdr));
        return;
 
 drop:
index 2602ad8b8cb04fac1c7e506d44cafec56357f09e..fac87b13329d0220bd6106f2f4d04284fbf1b1d1 100644 (file)
@@ -60,8 +60,11 @@ static struct workqueue_struct *comp_vector_wq;
  * @solicited: true if @entry is solicited
  *
  * This may be called with qp->s_lock held.
+ *
+ * Return: return true on success, else return
+ * false if cq is full.
  */
-void rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited)
+bool rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited)
 {
        struct ib_uverbs_wc *uqueue = NULL;
        struct ib_wc *kqueue = NULL;
@@ -97,7 +100,12 @@ void rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited)
                next = head + 1;
        }
 
-       if (unlikely(next == tail)) {
+       if (unlikely(next == tail || cq->cq_full)) {
+               struct rvt_dev_info *rdi = cq->rdi;
+
+               if (!cq->cq_full)
+                       rvt_pr_err_ratelimited(rdi, "CQ is full!\n");
+               cq->cq_full = true;
                spin_unlock_irqrestore(&cq->lock, flags);
                if (cq->ibcq.event_handler) {
                        struct ib_event ev;
@@ -107,7 +115,7 @@ void rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited)
                        ev.event = IB_EVENT_CQ_ERR;
                        cq->ibcq.event_handler(&ev, cq->ibcq.cq_context);
                }
-               return;
+               return false;
        }
        trace_rvt_cq_enter(cq, entry, head);
        if (uqueue) {
@@ -146,6 +154,7 @@ void rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited)
        }
 
        spin_unlock_irqrestore(&cq->lock, flags);
+       return true;
 }
 EXPORT_SYMBOL(rvt_cq_enter);
 
index 200b292be63ea0eceb045198f0bc13d5db4d4771..17e192a2c8b67914734f3797f0de96f9724be814 100644 (file)
@@ -3103,8 +3103,7 @@ do_write:
        wc.sl = rdma_ah_get_sl(&qp->remote_ah_attr);
        wc.port_num = 1;
        /* Signal completion event if the solicited bit is set. */
-       rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.recv_cq), &wc,
-                    wqe->wr.send_flags & IB_SEND_SOLICITED);
+       rvt_recv_cq(qp, &wc, wqe->wr.send_flags & IB_SEND_SOLICITED);
 
 send_comp:
        spin_unlock_irqrestore(&qp->r_lock, flags);
index 0675ea6c3872b702d30d677dbc9edcc6083c6d9f..d19ff817c2c716780521468c1a1832de18956e00 100644 (file)
                     fmt, \
                     ##__VA_ARGS__)
 
+#define rvt_pr_err_ratelimited(rdi, fmt, ...) \
+       __rvt_pr_err_ratelimited((rdi)->driver_f.get_pci_dev(rdi), \
+                                rvt_get_ibdev_name(rdi), \
+                                fmt, \
+                                ##__VA_ARGS__)
+
 #define __rvt_pr_info(pdev, name, fmt, ...) \
        dev_info(&pdev->dev, "%s: " fmt, name, ##__VA_ARGS__)
 
@@ -87,6 +93,9 @@
 #define __rvt_pr_err(pdev, name, fmt, ...) \
        dev_err(&pdev->dev, "%s: " fmt, name, ##__VA_ARGS__)
 
+#define __rvt_pr_err_ratelimited(pdev, name, fmt, ...) \
+       dev_err_ratelimited(&(pdev)->dev, "%s: " fmt, name, ##__VA_ARGS__)
+
 static inline int ibport_num_to_idx(struct ib_device *ibdev, u8 port_num)
 {
        struct rvt_dev_info *rdi = ib_to_rvt(ibdev);
index ab22860a63e2306252ed493b6a270b21675e2b50..04c519ef6d715b30adf603b2445180a9874325e2 100644 (file)
@@ -93,6 +93,7 @@ struct rvt_cq {
        spinlock_t lock; /* protect changes in this struct */
        u8 notify;
        u8 triggered;
+       u8 cq_full;
        int comp_vector_cpu;
        struct rvt_dev_info *rdi;
        struct rvt_cq_wc *queue;
@@ -105,6 +106,6 @@ static inline struct rvt_cq *ibcq_to_rvtcq(struct ib_cq *ibcq)
        return container_of(ibcq, struct rvt_cq, ibcq);
 }
 
-void rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited);
+bool rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited);
 
 #endif          /* DEF_RDMAVT_INCCQH */
index de5915b244bed09a814764888f16c7d4bb020d5f..e4be869c4f21c7803e6dbf8bc3a173dcf8efa907 100644 (file)
@@ -718,6 +718,48 @@ rvt_qp_swqe_incr(struct rvt_qp *qp, u32 val)
        return val;
 }
 
+int rvt_error_qp(struct rvt_qp *qp, enum ib_wc_status err);
+
+/**
+ * rvt_recv_cq - add a new entry to completion queue
+ *                     by receive queue
+ * @qp: receive queue
+ * @wc: work completion entry to add
+ * @solicited: true if @entry is solicited
+ *
+ * This is wrapper function for rvt_enter_cq function call by
+ * receive queue. If rvt_cq_enter return false, it means cq is
+ * full and the qp is put into error state.
+ */
+static inline void rvt_recv_cq(struct rvt_qp *qp, struct ib_wc *wc,
+                              bool solicited)
+{
+       struct rvt_cq *cq = ibcq_to_rvtcq(qp->ibqp.recv_cq);
+
+       if (unlikely(!rvt_cq_enter(cq, wc, solicited)))
+               rvt_error_qp(qp, IB_WC_LOC_QP_OP_ERR);
+}
+
+/**
+ * rvt_send_cq - add a new entry to completion queue
+ *                        by send queue
+ * @qp: send queue
+ * @wc: work completion entry to add
+ * @solicited: true if @entry is solicited
+ *
+ * This is wrapper function for rvt_enter_cq function call by
+ * send queue. If rvt_cq_enter return false, it means cq is
+ * full and the qp is put into error state.
+ */
+static inline void rvt_send_cq(struct rvt_qp *qp, struct ib_wc *wc,
+                              bool solicited)
+{
+       struct rvt_cq *cq = ibcq_to_rvtcq(qp->ibqp.send_cq);
+
+       if (unlikely(!rvt_cq_enter(cq, wc, solicited)))
+               rvt_error_qp(qp, IB_WC_LOC_QP_OP_ERR);
+}
+
 /**
  * rvt_qp_complete_swqe - insert send completion
  * @qp - the qp
@@ -768,9 +810,7 @@ rvt_qp_complete_swqe(struct rvt_qp *qp,
                        .qp = &qp->ibqp,
                        .byte_len = byte_len,
                };
-
-               rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.send_cq), &w,
-                            status != IB_WC_SUCCESS);
+               rvt_send_cq(qp, &w, status != IB_WC_SUCCESS);
        }
        return last;
 }
@@ -780,7 +820,6 @@ extern const int  ib_rvt_state_ops[];
 struct rvt_dev_info;
 int rvt_get_rwqe(struct rvt_qp *qp, bool wr_id_only);
 void rvt_comm_est(struct rvt_qp *qp);
-int rvt_error_qp(struct rvt_qp *qp, enum ib_wc_status err);
 void rvt_rc_error(struct rvt_qp *qp, enum ib_wc_status err);
 unsigned long rvt_rnr_tbl_to_usec(u32 index);
 enum hrtimer_restart rvt_rc_rnr_retry(struct hrtimer *t);