aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband/hw/ocrdma
diff options
context:
space:
mode:
authorMitesh Ahuja <mitesh.ahuja@emulex.com>2014-12-18 03:43:05 -0500
committerRoland Dreier <roland@purestorage.com>2015-02-18 11:31:04 -0500
commitb4dbe8d52d08e5ed60c9d01efbcd7b8694cf4b9f (patch)
tree0b76375dc4c59382a3b2126304f93bc24efe50d7 /drivers/infiniband/hw/ocrdma
parenta601dc77f8bf71818d679cbd97e953becb2a085e (diff)
RDMA/ocrdma: Add support for interrupt moderation
Add support for interrupt moderation for ocrdma device. Thresholds for high interrupt rates are static values derived based on experimental results. Signed-off-by: Mitesh Ahuja <mitesh.ahuja@emulex.com> Signed-off-by: Devesh Sharma <devesh.sharma@emulex.com> Signed-off-by: Selvin Xavier <selvin.xavier@emulex.com> Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband/hw/ocrdma')
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma.h14
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.c77
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_main.c4
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_sli.h24
4 files changed, 119 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma.h b/drivers/infiniband/hw/ocrdma/ocrdma.h
index 933b38af13f0..b9fee0ed32d2 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma.h
@@ -55,6 +55,12 @@
55#define OCRDMA_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME) 55#define OCRDMA_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME)
56 56
57#define convert_to_64bit(lo, hi) ((u64)hi << 32 | (u64)lo) 57#define convert_to_64bit(lo, hi) ((u64)hi << 32 | (u64)lo)
58#define EQ_INTR_PER_SEC_THRSH_HI 150000
59#define EQ_INTR_PER_SEC_THRSH_LOW 100000
60#define EQ_AIC_MAX_EQD 20
61#define EQ_AIC_MIN_EQD 0
62
63void ocrdma_eqd_set_task(struct work_struct *work);
58 64
59struct ocrdma_dev_attr { 65struct ocrdma_dev_attr {
60 u8 fw_ver[32]; 66 u8 fw_ver[32];
@@ -117,12 +123,19 @@ struct ocrdma_queue_info {
117 bool created; 123 bool created;
118}; 124};
119 125
126struct ocrdma_aic_obj { /* Adaptive interrupt coalescing (AIC) info */
127 u32 prev_eqd;
128 u64 eq_intr_cnt;
129 u64 prev_eq_intr_cnt;
130};
131
120struct ocrdma_eq { 132struct ocrdma_eq {
121 struct ocrdma_queue_info q; 133 struct ocrdma_queue_info q;
122 u32 vector; 134 u32 vector;
123 int cq_cnt; 135 int cq_cnt;
124 struct ocrdma_dev *dev; 136 struct ocrdma_dev *dev;
125 char irq_name[32]; 137 char irq_name[32];
138 struct ocrdma_aic_obj aic_obj;
126}; 139};
127 140
128struct ocrdma_mq { 141struct ocrdma_mq {
@@ -214,6 +227,7 @@ struct ocrdma_dev {
214 227
215 struct ocrdma_eq *eq_tbl; 228 struct ocrdma_eq *eq_tbl;
216 int eq_cnt; 229 int eq_cnt;
230 struct delayed_work eqd_work;
217 u16 base_eqid; 231 u16 base_eqid;
218 u16 max_eq; 232 u16 max_eq;
219 233
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
index 6e9680d18934..189ebc7c20af 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
@@ -960,6 +960,7 @@ static irqreturn_t ocrdma_irq_handler(int irq, void *handle)
960 960
961 } while (budget); 961 } while (budget);
962 962
963 eq->aic_obj.eq_intr_cnt++;
963 ocrdma_ring_eq_db(dev, eq->q.id, true, true, 0); 964 ocrdma_ring_eq_db(dev, eq->q.id, true, true, 0);
964 return IRQ_HANDLED; 965 return IRQ_HANDLED;
965} 966}
@@ -3016,6 +3017,82 @@ done:
3016 return status; 3017 return status;
3017} 3018}
3018 3019
3020static int ocrdma_mbx_modify_eqd(struct ocrdma_dev *dev, struct ocrdma_eq *eq,
3021 int num)
3022{
3023 int i, status = -ENOMEM;
3024 struct ocrdma_modify_eqd_req *cmd;
3025
3026 cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_MODIFY_EQ_DELAY, sizeof(*cmd));
3027 if (!cmd)
3028 return status;
3029
3030 ocrdma_init_mch(&cmd->cmd.req, OCRDMA_CMD_MODIFY_EQ_DELAY,
3031 OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
3032
3033 cmd->cmd.num_eq = num;
3034 for (i = 0; i < num; i++) {
3035 cmd->cmd.set_eqd[i].eq_id = eq[i].q.id;
3036 cmd->cmd.set_eqd[i].phase = 0;
3037 cmd->cmd.set_eqd[i].delay_multiplier =
3038 (eq[i].aic_obj.prev_eqd * 65)/100;
3039 }
3040 status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
3041 if (status)
3042 goto mbx_err;
3043mbx_err:
3044 kfree(cmd);
3045 return status;
3046}
3047
3048static int ocrdma_modify_eqd(struct ocrdma_dev *dev, struct ocrdma_eq *eq,
3049 int num)
3050{
3051 int num_eqs, i = 0;
3052 if (num > 8) {
3053 while (num) {
3054 num_eqs = min(num, 8);
3055 ocrdma_mbx_modify_eqd(dev, &eq[i], num_eqs);
3056 i += num_eqs;
3057 num -= num_eqs;
3058 }
3059 } else {
3060 ocrdma_mbx_modify_eqd(dev, eq, num);
3061 }
3062 return 0;
3063}
3064
3065void ocrdma_eqd_set_task(struct work_struct *work)
3066{
3067 struct ocrdma_dev *dev =
3068 container_of(work, struct ocrdma_dev, eqd_work.work);
3069 struct ocrdma_eq *eq = 0;
3070 int i, num = 0, status = -EINVAL;
3071 u64 eq_intr;
3072
3073 for (i = 0; i < dev->eq_cnt; i++) {
3074 eq = &dev->eq_tbl[i];
3075 if (eq->aic_obj.eq_intr_cnt > eq->aic_obj.prev_eq_intr_cnt) {
3076 eq_intr = eq->aic_obj.eq_intr_cnt -
3077 eq->aic_obj.prev_eq_intr_cnt;
3078 if ((eq_intr > EQ_INTR_PER_SEC_THRSH_HI) &&
3079 (eq->aic_obj.prev_eqd == EQ_AIC_MIN_EQD)) {
3080 eq->aic_obj.prev_eqd = EQ_AIC_MAX_EQD;
3081 num++;
3082 } else if ((eq_intr < EQ_INTR_PER_SEC_THRSH_LOW) &&
3083 (eq->aic_obj.prev_eqd == EQ_AIC_MAX_EQD)) {
3084 eq->aic_obj.prev_eqd = EQ_AIC_MIN_EQD;
3085 num++;
3086 }
3087 }
3088 eq->aic_obj.prev_eq_intr_cnt = eq->aic_obj.eq_intr_cnt;
3089 }
3090
3091 if (num)
3092 status = ocrdma_modify_eqd(dev, &dev->eq_tbl[0], num);
3093 schedule_delayed_work(&dev->eqd_work, msecs_to_jiffies(1000));
3094}
3095
3019int ocrdma_init_hw(struct ocrdma_dev *dev) 3096int ocrdma_init_hw(struct ocrdma_dev *dev)
3020{ 3097{
3021 int status; 3098 int status;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index 0083360d918e..7a2b59aca004 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -493,6 +493,9 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
493 spin_unlock(&ocrdma_devlist_lock); 493 spin_unlock(&ocrdma_devlist_lock);
494 /* Init stats */ 494 /* Init stats */
495 ocrdma_add_port_stats(dev); 495 ocrdma_add_port_stats(dev);
496 /* Interrupt Moderation */
497 INIT_DELAYED_WORK(&dev->eqd_work, ocrdma_eqd_set_task);
498 schedule_delayed_work(&dev->eqd_work, msecs_to_jiffies(1000));
496 499
497 pr_info("%s %s: %s \"%s\" port %d\n", 500 pr_info("%s %s: %s \"%s\" port %d\n",
498 dev_name(&dev->nic_info.pdev->dev), hca_name(dev), 501 dev_name(&dev->nic_info.pdev->dev), hca_name(dev),
@@ -530,6 +533,7 @@ static void ocrdma_remove(struct ocrdma_dev *dev)
530 /* first unregister with stack to stop all the active traffic 533 /* first unregister with stack to stop all the active traffic
531 * of the registered clients. 534 * of the registered clients.
532 */ 535 */
536 cancel_delayed_work_sync(&dev->eqd_work);
533 ocrdma_remove_sysfiles(dev); 537 ocrdma_remove_sysfiles(dev);
534 ib_unregister_device(&dev->ibdev); 538 ib_unregister_device(&dev->ibdev);
535 539
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
index 6ba9939868a3..801883aa4145 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
@@ -89,6 +89,7 @@ enum {
89 OCRDMA_CMD_CREATE_MQ = 21, 89 OCRDMA_CMD_CREATE_MQ = 21,
90 OCRDMA_CMD_GET_CTRL_ATTRIBUTES = 32, 90 OCRDMA_CMD_GET_CTRL_ATTRIBUTES = 32,
91 OCRDMA_CMD_GET_FW_VER = 35, 91 OCRDMA_CMD_GET_FW_VER = 35,
92 OCRDMA_CMD_MODIFY_EQ_DELAY = 41,
92 OCRDMA_CMD_DELETE_MQ = 53, 93 OCRDMA_CMD_DELETE_MQ = 53,
93 OCRDMA_CMD_DELETE_CQ = 54, 94 OCRDMA_CMD_DELETE_CQ = 54,
94 OCRDMA_CMD_DELETE_EQ = 55, 95 OCRDMA_CMD_DELETE_EQ = 55,
@@ -316,6 +317,29 @@ struct ocrdma_create_eq_rsp {
316 317
317#define OCRDMA_EQ_MINOR_OTHER 0x1 318#define OCRDMA_EQ_MINOR_OTHER 0x1
318 319
320struct ocrmda_set_eqd {
321 u32 eq_id;
322 u32 phase;
323 u32 delay_multiplier;
324};
325
326struct ocrdma_modify_eqd_cmd {
327 struct ocrdma_mbx_hdr req;
328 u32 num_eq;
329 struct ocrmda_set_eqd set_eqd[8];
330} __packed;
331
332struct ocrdma_modify_eqd_req {
333 struct ocrdma_mqe_hdr hdr;
334 struct ocrdma_modify_eqd_cmd cmd;
335};
336
337
338struct ocrdma_modify_eq_delay_rsp {
339 struct ocrdma_mbx_rsp hdr;
340 u32 rsvd0;
341} __packed;
342
319enum { 343enum {
320 OCRDMA_MCQE_STATUS_SHIFT = 0, 344 OCRDMA_MCQE_STATUS_SHIFT = 0,
321 OCRDMA_MCQE_STATUS_MASK = 0xFFFF, 345 OCRDMA_MCQE_STATUS_MASK = 0xFFFF,