i40iw: Improve CQP timeout logic
authorShiraz Saleem <shiraz.saleem@intel.com>
Wed, 9 Aug 2017 01:38:45 +0000 (20:38 -0500)
committerDoug Ledford <dledford@redhat.com>
Tue, 22 Aug 2017 19:38:27 +0000 (15:38 -0400)
The current timeout logic for Control Queue-Pair (CQP) OPs
does not take into account whether CQP makes progress but
rather blindly waits for a large timeout value, 100000 jiffies
for the completion event. Improve this by setting the timeout
based on whether the CQP is making progress or not. If the CQP
is hung, the timeout will happen sooner, in 5000 jiffies. Each
time the CQP progress is detetcted, the timeout extends by 5000
jiffies.

Signed-off-by: Shiraz Saleem <shiraz.saleem@intel.com>
Signed-off-by: Christopher N Bednarz <christopher.n.bednarz@intel.com>
Signed-off-by: Henry Orosco <henry.orosco@intel.com>
Signed-off-by: Doug Ledford <dledford@redhat.com>
drivers/infiniband/hw/i40iw/i40iw_ctrl.c
drivers/infiniband/hw/i40iw/i40iw_p.h
drivers/infiniband/hw/i40iw/i40iw_type.h
drivers/infiniband/hw/i40iw/i40iw_utils.c

index a49ff2eb6fb3bca54f40bc460238eeb4a5b4ba52..d1f5345f04f08eb916539162b024f7b59e9b9a94 100644 (file)
@@ -54,6 +54,17 @@ static inline void i40iw_insert_wqe_hdr(u64 *wqe, u64 header)
        set_64bit_val(wqe, 24, header);
 }
 
+void i40iw_check_cqp_progress(struct i40iw_cqp_timeout *cqp_timeout, struct i40iw_sc_dev *dev)
+{
+       if (cqp_timeout->compl_cqp_cmds != dev->cqp_cmd_stats[OP_COMPLETED_COMMANDS]) {
+               cqp_timeout->compl_cqp_cmds = dev->cqp_cmd_stats[OP_COMPLETED_COMMANDS];
+               cqp_timeout->count = 0;
+       } else {
+               if (dev->cqp_cmd_stats[OP_REQUESTED_COMMANDS] != cqp_timeout->compl_cqp_cmds)
+                       cqp_timeout->count++;
+       }
+}
+
 /**
  * i40iw_get_cqp_reg_info - get head and tail for cqp using registers
  * @cqp: struct for cqp hw
index 28a92fee082293304cb201134fab6aa34f9b058d..e217a1259f5703ac1ef1ac4d3ed70acd986e2336 100644 (file)
 #ifndef I40IW_P_H
 #define I40IW_P_H
 
-#define PAUSE_TIMER_VALUE  0xFFFF
-#define REFRESH_THRESHOLD  0x7FFF
-#define HIGH_THRESHOLD     0x800
-#define LOW_THRESHOLD      0x200
-#define ALL_TC2PFC         0xFF
+#define PAUSE_TIMER_VALUE       0xFFFF
+#define REFRESH_THRESHOLD       0x7FFF
+#define HIGH_THRESHOLD          0x800
+#define LOW_THRESHOLD           0x200
+#define ALL_TC2PFC              0xFF
+#define CQP_COMPL_WAIT_TIME     0x3E8
+#define CQP_TIMEOUT_THRESHOLD   5
 
 void i40iw_debug_buf(struct i40iw_sc_dev *dev, enum i40iw_debug_flag mask,
                     char *desc, u64 *buf, u32 size);
@@ -51,6 +53,8 @@ void i40iw_sc_cqp_post_sq(struct i40iw_sc_cqp *cqp);
 
 u64 *i40iw_sc_cqp_get_next_send_wqe(struct i40iw_sc_cqp *cqp, u64 scratch);
 
+void i40iw_check_cqp_progress(struct i40iw_cqp_timeout *cqp_timeout, struct i40iw_sc_dev *dev);
+
 enum i40iw_status_code i40iw_sc_mr_fast_register(struct i40iw_sc_qp *qp,
                                                 struct i40iw_fast_reg_stag_info *info,
                                                 bool post_sq);
index 959ec81fba99ca6499f2e8d7d68f0cb073c86646..63118f6d5ab4a6c349e0981544ef280d0b8a99ef 100644 (file)
@@ -1345,4 +1345,9 @@ struct i40iw_virtchnl_work_info {
        void *worker_vf_dev;
 };
 
+struct i40iw_cqp_timeout {
+       u64 compl_cqp_cmds;
+       u8 count;
+};
+
 #endif
index e311ec559f4eb79de0e94aaa0f58861aba2882b0..62f1f45b8737a4716d04d8a340ab5612ef4f1047 100644 (file)
@@ -445,23 +445,29 @@ static int i40iw_wait_event(struct i40iw_device *iwdev,
 {
        struct cqp_commands_info *info = &cqp_request->info;
        struct i40iw_cqp *iwcqp = &iwdev->cqp;
+       struct i40iw_cqp_timeout cqp_timeout;
        bool cqp_error = false;
        int err_code = 0;
-       int timeout_ret = 0;
+       memset(&cqp_timeout, 0, sizeof(cqp_timeout));
+       cqp_timeout.compl_cqp_cmds = iwdev->sc_dev.cqp_cmd_stats[OP_COMPLETED_COMMANDS];
+       do {
+               if (wait_event_timeout(cqp_request->waitq,
+                                      cqp_request->request_done, CQP_COMPL_WAIT_TIME))
+                       break;
 
-       timeout_ret = wait_event_timeout(cqp_request->waitq,
-                                        cqp_request->request_done,
-                                        I40IW_EVENT_TIMEOUT);
-       if (!timeout_ret) {
-               i40iw_pr_err("error cqp command 0x%x timed out ret = %d\n",
-                            info->cqp_cmd, timeout_ret);
+               i40iw_check_cqp_progress(&cqp_timeout, &iwdev->sc_dev);
+
+               if (cqp_timeout.count < CQP_TIMEOUT_THRESHOLD)
+                       continue;
+
+               i40iw_pr_err("error cqp command 0x%x timed out", info->cqp_cmd);
                err_code = -ETIME;
                if (!iwdev->reset) {
                        iwdev->reset = true;
                        i40iw_request_reset(iwdev);
                }
                goto done;
-       }
+       } while (1);
        cqp_error = cqp_request->compl_info.error;
        if (cqp_error) {
                i40iw_pr_err("error cqp command 0x%x completion maj = 0x%x min=0x%x\n",