Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b4dbe8d5 authored by Mitesh Ahuja's avatar Mitesh Ahuja Committed by Roland Dreier
Browse files

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: default avatarMitesh Ahuja <mitesh.ahuja@emulex.com>
Signed-off-by: default avatarDevesh Sharma <devesh.sharma@emulex.com>
Signed-off-by: default avatarSelvin Xavier <selvin.xavier@emulex.com>
Signed-off-by: default avatarRoland Dreier <roland@purestorage.com>
parent a601dc77
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -55,6 +55,12 @@
#define OCRDMA_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME)

#define convert_to_64bit(lo, hi) ((u64)hi << 32 | (u64)lo)
#define EQ_INTR_PER_SEC_THRSH_HI 150000
#define EQ_INTR_PER_SEC_THRSH_LOW 100000
#define EQ_AIC_MAX_EQD 20
#define EQ_AIC_MIN_EQD 0

void ocrdma_eqd_set_task(struct work_struct *work);

struct ocrdma_dev_attr {
	u8 fw_ver[32];
@@ -117,12 +123,19 @@ struct ocrdma_queue_info {
	bool created;
};

struct ocrdma_aic_obj {         /* Adaptive interrupt coalescing (AIC) info */
	u32 prev_eqd;
	u64 eq_intr_cnt;
	u64 prev_eq_intr_cnt;
};

struct ocrdma_eq {
	struct ocrdma_queue_info q;
	u32 vector;
	int cq_cnt;
	struct ocrdma_dev *dev;
	char irq_name[32];
	struct ocrdma_aic_obj aic_obj;
};

struct ocrdma_mq {
@@ -214,6 +227,7 @@ struct ocrdma_dev {

	struct ocrdma_eq *eq_tbl;
	int eq_cnt;
	struct delayed_work eqd_work;
	u16 base_eqid;
	u16 max_eq;

+77 −0
Original line number Diff line number Diff line
@@ -960,6 +960,7 @@ static irqreturn_t ocrdma_irq_handler(int irq, void *handle)

	} while (budget);

	eq->aic_obj.eq_intr_cnt++;
	ocrdma_ring_eq_db(dev, eq->q.id, true, true, 0);
	return IRQ_HANDLED;
}
@@ -3016,6 +3017,82 @@ static int ocrdma_create_eqs(struct ocrdma_dev *dev)
	return status;
}

static int ocrdma_mbx_modify_eqd(struct ocrdma_dev *dev, struct ocrdma_eq *eq,
				 int num)
{
	int i, status = -ENOMEM;
	struct ocrdma_modify_eqd_req *cmd;

	cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_MODIFY_EQ_DELAY, sizeof(*cmd));
	if (!cmd)
		return status;

	ocrdma_init_mch(&cmd->cmd.req, OCRDMA_CMD_MODIFY_EQ_DELAY,
			OCRDMA_SUBSYS_COMMON, sizeof(*cmd));

	cmd->cmd.num_eq = num;
	for (i = 0; i < num; i++) {
		cmd->cmd.set_eqd[i].eq_id = eq[i].q.id;
		cmd->cmd.set_eqd[i].phase = 0;
		cmd->cmd.set_eqd[i].delay_multiplier =
				(eq[i].aic_obj.prev_eqd * 65)/100;
	}
	status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
	if (status)
		goto mbx_err;
mbx_err:
	kfree(cmd);
	return status;
}

static int ocrdma_modify_eqd(struct ocrdma_dev *dev, struct ocrdma_eq *eq,
			     int num)
{
	int num_eqs, i = 0;
	if (num > 8) {
		while (num) {
			num_eqs = min(num, 8);
			ocrdma_mbx_modify_eqd(dev, &eq[i], num_eqs);
			i += num_eqs;
			num -= num_eqs;
		}
	} else {
		ocrdma_mbx_modify_eqd(dev, eq, num);
	}
	return 0;
}

void ocrdma_eqd_set_task(struct work_struct *work)
{
	struct ocrdma_dev *dev =
		container_of(work, struct ocrdma_dev, eqd_work.work);
	struct ocrdma_eq *eq = 0;
	int i, num = 0, status = -EINVAL;
	u64 eq_intr;

	for (i = 0; i < dev->eq_cnt; i++) {
		eq = &dev->eq_tbl[i];
		if (eq->aic_obj.eq_intr_cnt > eq->aic_obj.prev_eq_intr_cnt) {
			eq_intr = eq->aic_obj.eq_intr_cnt -
				  eq->aic_obj.prev_eq_intr_cnt;
			if ((eq_intr > EQ_INTR_PER_SEC_THRSH_HI) &&
			    (eq->aic_obj.prev_eqd == EQ_AIC_MIN_EQD)) {
				eq->aic_obj.prev_eqd = EQ_AIC_MAX_EQD;
				num++;
			} else if ((eq_intr < EQ_INTR_PER_SEC_THRSH_LOW) &&
				   (eq->aic_obj.prev_eqd == EQ_AIC_MAX_EQD)) {
				eq->aic_obj.prev_eqd = EQ_AIC_MIN_EQD;
				num++;
			}
		}
		eq->aic_obj.prev_eq_intr_cnt = eq->aic_obj.eq_intr_cnt;
	}

	if (num)
		status = ocrdma_modify_eqd(dev, &dev->eq_tbl[0], num);
	schedule_delayed_work(&dev->eqd_work, msecs_to_jiffies(1000));
}

int ocrdma_init_hw(struct ocrdma_dev *dev)
{
	int status;
+4 −0
Original line number Diff line number Diff line
@@ -493,6 +493,9 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
	spin_unlock(&ocrdma_devlist_lock);
	/* Init stats */
	ocrdma_add_port_stats(dev);
	/* Interrupt Moderation */
	INIT_DELAYED_WORK(&dev->eqd_work, ocrdma_eqd_set_task);
	schedule_delayed_work(&dev->eqd_work, msecs_to_jiffies(1000));

	pr_info("%s %s: %s \"%s\" port %d\n",
		dev_name(&dev->nic_info.pdev->dev), hca_name(dev),
@@ -530,6 +533,7 @@ static void ocrdma_remove(struct ocrdma_dev *dev)
	/* first unregister with stack to stop all the active traffic
	 * of the registered clients.
	 */
	cancel_delayed_work_sync(&dev->eqd_work);
	ocrdma_remove_sysfiles(dev);
	ib_unregister_device(&dev->ibdev);

+24 −0
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ enum {
	OCRDMA_CMD_CREATE_MQ		= 21,
	OCRDMA_CMD_GET_CTRL_ATTRIBUTES  = 32,
	OCRDMA_CMD_GET_FW_VER		= 35,
	OCRDMA_CMD_MODIFY_EQ_DELAY      = 41,
	OCRDMA_CMD_DELETE_MQ		= 53,
	OCRDMA_CMD_DELETE_CQ		= 54,
	OCRDMA_CMD_DELETE_EQ		= 55,
@@ -316,6 +317,29 @@ struct ocrdma_create_eq_rsp {

#define OCRDMA_EQ_MINOR_OTHER	0x1

struct ocrmda_set_eqd {
	u32 eq_id;
	u32 phase;
	u32 delay_multiplier;
};

struct ocrdma_modify_eqd_cmd {
	struct ocrdma_mbx_hdr req;
	u32 num_eq;
	struct ocrmda_set_eqd set_eqd[8];
} __packed;

struct ocrdma_modify_eqd_req {
	struct ocrdma_mqe_hdr hdr;
	struct ocrdma_modify_eqd_cmd cmd;
};


struct ocrdma_modify_eq_delay_rsp {
	struct ocrdma_mbx_rsp hdr;
	u32 rsvd0;
} __packed;

enum {
	OCRDMA_MCQE_STATUS_SHIFT	= 0,
	OCRDMA_MCQE_STATUS_MASK		= 0xFFFF,