Commit c796499d authored by Longfang Liu's avatar Longfang Liu Committed by openeuler-sync-bot
Browse files

vfio/migration: bugfix lost interruption after live migration

driver inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I7BTMW


CVE: NA

----------------------------------------------------------------------

During repeated live migration. There may be a problem with missing
interrupts. In this case, re-send the doorbell on the migration end.
Let QM report an interrupt again, and migrate the interrupt to the
destination together.
Thereby preventing the problem of interrupt loss.

fixec: a0464f0b ("vfio/hisilicon: add acc live migration driver")
Signed-off-by: default avatarLongfang Liu <liulongfang@huawei.com>
Signed-off-by: default avatarJiangShui Yang <yangjiangshui@h-partners.com>
(cherry picked from commit a60b29d3)
parent f325b4da
Loading
Loading
Loading
Loading
+41 −25
Original line number Diff line number Diff line
@@ -173,6 +173,27 @@ static int qm_config_get(struct hisi_qm *qm, u64 *base, u8 cmd, u16 queue)
	return 0;
}

static void qm_db(struct hisi_qm *qm, u16 qn, u8 cmd,
	u16 index, u8 priority)
{
	void __iomem *io_base = qm->io_base;
	u16 randata = 0;
	u64 doorbell;

	if (cmd == QM_DOORBELL_CMD_SQ || cmd == QM_DOORBELL_CMD_CQ)
		io_base = qm->db_io_base + (u64)qn * qm->db_interval +
			  QM_DOORBELL_SQ_CQ_BASE_V2;
	else
		io_base += QM_DOORBELL_EQ_AEQ_BASE_V2;

	doorbell = qn | ((u64)cmd << QM_DB_CMD_SHIFT_V2) |
		   ((u64)randata << QM_DB_RAND_SHIFT_V2) |
		   ((u64)index << QM_DB_INDEX_SHIFT_V2) |
		   ((u64)priority << QM_DB_PRIORITY_SHIFT_V2);

	writeq(doorbell, io_base);
}

/*
 * Each state Reg is checked 100 times,
 * with a delay of 100 microseconds after each check
@@ -438,6 +459,19 @@ static int qm_rw_regs_write(struct hisi_qm *qm, struct acc_vf_data *vf_data)
	return 0;
}

static void vf_qm_xeqc_save(struct hisi_qm *qm,
	struct acc_vf_migration *acc_vf_dev)
{
	struct acc_vf_data *vf_data = acc_vf_dev->vf_data;
	u16 eq_head, aeq_head;

	eq_head = vf_data->qm_eqc_dw[0] & 0xFFFF;
	qm_db(qm, 0, QM_DOORBELL_CMD_EQ, eq_head, 0);

	aeq_head = vf_data->qm_aeqc_dw[0] & 0xFFFF;
	qm_db(qm, 0, QM_DOORBELL_CMD_AEQ, aeq_head, 0);
}

/*
 * the vf QM have unbind from host, insmod in the VM
 * so, qm just have the addr from pci dev
@@ -461,12 +495,12 @@ static int vf_migration_data_store(struct hisi_qm *qm,
	 * every Reg is 32 bit, the dma address is 64 bit
	 * so, the dma address is store in the Reg2 and Reg1
	 */
	vf_data->eqe_dma = vf_data->qm_eqc_dw[2];
	vf_data->eqe_dma = vf_data->qm_eqc_dw[QM_XQC_ADDR_HIGH];
	vf_data->eqe_dma <<= QM_XQC_ADDR_OFFSET;
	vf_data->eqe_dma |= vf_data->qm_eqc_dw[1];
	vf_data->aeqe_dma = vf_data->qm_aeqc_dw[2];
	vf_data->eqe_dma |= vf_data->qm_eqc_dw[QM_XQC_ADDR_LOW];
	vf_data->aeqe_dma = vf_data->qm_aeqc_dw[QM_XQC_ADDR_HIGH];
	vf_data->aeqe_dma <<= QM_XQC_ADDR_OFFSET;
	vf_data->aeqe_dma |= vf_data->qm_aeqc_dw[1];
	vf_data->aeqe_dma |= vf_data->qm_aeqc_dw[QM_XQC_ADDR_LOW];

	/* Through SQC_BT/CQC_BT to get sqc and cqc address */
	ret = qm_config_get(qm, &vf_data->sqc_dma, QM_MB_CMD_SQC_BT, 0);
@@ -481,6 +515,9 @@ static int vf_migration_data_store(struct hisi_qm *qm,
		return -EINVAL;
	}

	/* Save eqc and aeqc interrupt information */
	vf_qm_xeqc_save(qm, acc_vf_dev);

	return 0;
}

@@ -493,27 +530,6 @@ static void qm_dev_cmd_init(struct hisi_qm *qm)
	writel(0x0, qm->io_base + QM_IFC_INT_MASK);
}

static void qm_db(struct hisi_qm *qm, u16 qn, u8 cmd,
	u16 index, u8 priority)
{
	void __iomem *io_base = qm->io_base;
	u16 randata = 0;
	u64 doorbell;

	if (cmd == QM_DOORBELL_CMD_SQ || cmd == QM_DOORBELL_CMD_CQ)
		io_base = qm->db_io_base + (u64)qn * qm->db_interval +
			  QM_DOORBELL_SQ_CQ_BASE_V2;
	else
		io_base += QM_DOORBELL_EQ_AEQ_BASE_V2;

	doorbell = qn | ((u64)cmd << QM_DB_CMD_SHIFT_V2) |
		   ((u64)randata << QM_DB_RAND_SHIFT_V2) |
		   ((u64)index << QM_DB_INDEX_SHIFT_V2) |
		   ((u64)priority << QM_DB_PRIORITY_SHIFT_V2);

	writeq(doorbell, io_base);
}

static void vf_qm_fun_restart(struct hisi_qm *qm,
	struct acc_vf_migration *acc_vf_dev)
{
+2 −0
Original line number Diff line number Diff line
@@ -79,6 +79,8 @@
#define QM_REG_ADDR_OFFSET		0x0004

#define QM_XQC_ADDR_OFFSET		32U
#define QM_XQC_ADDR_LOW		0x1
#define QM_XQC_ADDR_HIGH	0x2
#define QM_VF_AEQ_INT_MASK		0x0004
#define QM_VF_EQ_INT_MASK		0x000c
#define QM_IFC_INT_SOURCE_V		0x0020