diff options
author | Mitesh Ahuja <mitesh.ahuja@emulex.com> | 2014-12-18 03:43:05 -0500 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2015-02-18 11:31:04 -0500 |
commit | b4dbe8d52d08e5ed60c9d01efbcd7b8694cf4b9f (patch) | |
tree | 0b76375dc4c59382a3b2126304f93bc24efe50d7 /drivers/infiniband/hw/ocrdma | |
parent | a601dc77f8bf71818d679cbd97e953becb2a085e (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.h | 14 | ||||
-rw-r--r-- | drivers/infiniband/hw/ocrdma/ocrdma_hw.c | 77 | ||||
-rw-r--r-- | drivers/infiniband/hw/ocrdma/ocrdma_main.c | 4 | ||||
-rw-r--r-- | drivers/infiniband/hw/ocrdma/ocrdma_sli.h | 24 |
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 | |||
63 | void ocrdma_eqd_set_task(struct work_struct *work); | ||
58 | 64 | ||
59 | struct ocrdma_dev_attr { | 65 | struct 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 | ||
126 | struct 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 | |||
120 | struct ocrdma_eq { | 132 | struct 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 | ||
128 | struct ocrdma_mq { | 141 | struct 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 | ||
3020 | static 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; | ||
3043 | mbx_err: | ||
3044 | kfree(cmd); | ||
3045 | return status; | ||
3046 | } | ||
3047 | |||
3048 | static 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 | |||
3065 | void 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 | |||
3019 | int ocrdma_init_hw(struct ocrdma_dev *dev) | 3096 | int 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 | ||
320 | struct ocrmda_set_eqd { | ||
321 | u32 eq_id; | ||
322 | u32 phase; | ||
323 | u32 delay_multiplier; | ||
324 | }; | ||
325 | |||
326 | struct 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 | |||
332 | struct ocrdma_modify_eqd_req { | ||
333 | struct ocrdma_mqe_hdr hdr; | ||
334 | struct ocrdma_modify_eqd_cmd cmd; | ||
335 | }; | ||
336 | |||
337 | |||
338 | struct ocrdma_modify_eq_delay_rsp { | ||
339 | struct ocrdma_mbx_rsp hdr; | ||
340 | u32 rsvd0; | ||
341 | } __packed; | ||
342 | |||
319 | enum { | 343 | enum { |
320 | OCRDMA_MCQE_STATUS_SHIFT = 0, | 344 | OCRDMA_MCQE_STATUS_SHIFT = 0, |
321 | OCRDMA_MCQE_STATUS_MASK = 0xFFFF, | 345 | OCRDMA_MCQE_STATUS_MASK = 0xFFFF, |