Commit 1e00d1ae authored by Weili Qian's avatar Weili Qian Committed by JiangShui
Browse files

crypto: hisilicon/qm - reset device before enabling it

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


CVE: NA

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

When the device is re-enabled, data that has not been cleared
may exist on the device. Therefore, reset the device to
the initial state before enabling the device. If an abnormal
interrupt event is reported when the device is enabled,
the device will not be reset.

Signed-off-by: default avatarWeili Qian <qianweili@huawei.com>
Signed-off-by: default avatarJiangShui Yang <yangjiangshui@h-partners.com>
parent 16a9377d
Loading
Loading
Loading
Loading
+18 −9
Original line number Diff line number Diff line
@@ -1350,6 +1350,17 @@ static const struct hisi_qm_err_ini hpre_err_ini = {
	.err_info_init		= hpre_err_info_init,
};

static void hpre_probe_uninit(struct hisi_qm *qm)
{
	if (qm->fun_type == QM_HW_VF)
		return;

	hpre_cnt_regs_clear(qm);
	qm->debug.curr_qm_qp_num = 0;
	hpre_show_last_regs_uninit(qm);
	hpre_close_sva_prefetch(qm);
}

static int hpre_pf_probe_init(struct hpre *hpre)
{
	struct hisi_qm *qm = &hpre->qm;
@@ -1398,6 +1409,7 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		return -ENOMEM;

	qm = &hpre->qm;
	set_bit(QM_DRIVER_DOWN, &qm->misc_ctl);
	ret = hpre_qm_init(qm, pdev);
	if (ret) {
		pci_err(pdev, "Failed to init HPRE QM (%d)!\n", ret);
@@ -1414,6 +1426,9 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	if (ret)
		goto err_with_err_init;

	/* Device is enabled, clear the flag. */
	clear_bit(QM_DRIVER_DOWN, &qm->misc_ctl);

	ret = hpre_debugfs_init(qm);
	if (ret)
		dev_warn(&pdev->dev, "init debugfs fail!\n");
@@ -1446,12 +1461,12 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id)

err_qm_del_list:
	hisi_qm_del_list(qm, &hpre_devices);
	hisi_qm_wait_task_finish(qm, &hpre_devices);
	hpre_debugfs_exit(qm);
	hisi_qm_stop(qm, QM_NORMAL);

err_with_err_init:
	hpre_show_last_regs_uninit(qm);

	hpre_probe_uninit(qm);
err_with_qm_init:
	hisi_qm_uninit(qm);

@@ -1471,13 +1486,7 @@ static void hpre_remove(struct pci_dev *pdev)

	hpre_debugfs_exit(qm);
	hisi_qm_stop(qm, QM_NORMAL);

	if (qm->fun_type == QM_HW_PF) {
		hpre_cnt_regs_clear(qm);
		qm->debug.curr_qm_qp_num = 0;
		hpre_show_last_regs_uninit(qm);
	}

	hpre_probe_uninit(qm);
	hisi_qm_uninit(qm);
}

+70 −9
Original line number Diff line number Diff line
@@ -445,6 +445,7 @@ static struct qm_typical_qos_table shaper_cbs_s[] = {
};

static void qm_irqs_unregister(struct hisi_qm *qm);
static int qm_reset_device(struct hisi_qm *qm);

static u32 qm_get_hw_error_status(struct hisi_qm *qm)
{
@@ -2198,6 +2199,7 @@ static int qm_drain_qp(struct hisi_qp *qp)

	return ret;
}

static int qm_stop_qp_nolock(struct hisi_qp *qp)
{
	struct hisi_qm *qm = qp->qm;
@@ -3004,6 +3006,44 @@ static void hisi_qm_memory_uninit(struct hisi_qm *qm)
		kfree(qm->factor);
}

static int qm_clear_device(struct hisi_qm *qm)
{
	acpi_handle handle = ACPI_HANDLE(&qm->pdev->dev);
	u32 val;
	int ret;

	if (qm->fun_type == QM_HW_VF)
		return 0;

	/* Device does not support reset, return */
	if (!qm->err_ini->err_info_init)
		return 0;

	qm->err_ini->err_info_init(qm);

	if (!handle)
		return 0;

	/* No reset method, return */
	if (!acpi_has_method(handle, qm->err_info.acpi_rst))
		return 0;

	/* OOO register set and check */
	writel(ACC_MASTER_GLOBAL_CTRL_SHUTDOWN, qm->io_base + ACC_MASTER_GLOBAL_CTRL);

	ret = readl_relaxed_poll_timeout(qm->io_base + ACC_MASTER_TRANS_RETURN,
					 val,
					 (val == ACC_MASTER_TRANS_RETURN_RW),
					 POLL_PERIOD, POLL_TIMEOUT);
	if (ret) {
		pci_warn(qm->pdev, "Device is busy, not clear device.\n");
		writel(0x0, qm->io_base + ACC_MASTER_GLOBAL_CTRL);
		return ret;
	}

	return qm_reset_device(qm);
}

/**
 * hisi_qm_uninit() - Uninitialize qm.
 * @qm: The qm needed uninit.
@@ -4283,7 +4323,7 @@ static void qm_dev_ecc_mbit_handle(struct hisi_qm *qm)
	}
}

static int qm_soft_reset(struct hisi_qm *qm)
static int qm_soft_reset_prepare(struct hisi_qm *qm)
{
	struct pci_dev *pdev = qm->pdev;
	int ret;
@@ -4328,11 +4368,16 @@ static int qm_soft_reset(struct hisi_qm *qm)
		qm->err_ini->close_sva_prefetch(qm);

	ret = qm_set_pf_mse(qm, false);
	if (ret) {
	if (ret)
		pci_err(pdev, "Fails to disable pf MSE bit.\n");

	return ret;
}

static int qm_reset_device(struct hisi_qm *qm)
{
	struct pci_dev *pdev = qm->pdev;

	/* The reset related sub-control registers are not in PCI BAR */
	if (ACPI_HANDLE(&pdev->dev)) {
		unsigned long long value = 0;
@@ -4350,12 +4395,23 @@ static int qm_soft_reset(struct hisi_qm *qm)
			pci_err(pdev, "Reset step %llu failed!\n", value);
			return -EIO;
		}
	} else {

		return 0;
	}

	pci_err(pdev, "No reset method!\n");
	return -EINVAL;
}

	return 0;
static int qm_soft_reset(struct hisi_qm *qm)
{
	int ret;

	ret = qm_soft_reset_prepare(qm);
	if (ret)
		return ret;

	return qm_reset_device(qm);
}

static int qm_vf_reset_done(struct hisi_qm *qm)
@@ -5055,7 +5111,6 @@ static int qm_register_abnormal_irq(struct hisi_qm *qm)
	}

	INIT_WORK(&qm->rst_work, hisi_qm_controller_reset);
	qm->err_ini->err_info_init(qm);
	qm_dev_err_init(qm);

	return 0;
@@ -5442,8 +5497,14 @@ static int hisi_qm_pci_init(struct hisi_qm *qm)
		goto err_get_pci_res;
	}

	ret = qm_clear_device(qm);
	if (ret)
		goto err_free_vectors;

	return 0;

err_free_vectors:
	pci_free_irq_vectors(pdev);
err_get_pci_res:
	qm_put_pci_res(qm);
err_disable_pcidev:
+17 −5
Original line number Diff line number Diff line
@@ -1199,6 +1199,16 @@ static int sec_probe_init(struct sec_dev *sec)
	return 0;
}

static void sec_probe_uninit(struct hisi_qm *qm)
{
	if (qm->fun_type == QM_HW_VF)
		return;

	sec_debug_regs_clear(qm);
	sec_show_last_regs_uninit(qm);
	sec_close_sva_prefetch(qm);
}

static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
	struct sec_dev *sec;
@@ -1210,6 +1220,7 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		return -ENOMEM;

	qm = &sec->qm;
	set_bit(QM_DRIVER_DOWN, &qm->misc_ctl);
	ret = sec_qm_init(qm, pdev);
	if (ret) {
		pci_err(pdev, "Failed to init SEC QM (%d)!\n", ret);
@@ -1230,6 +1241,9 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		goto err_probe_uninit;
	}

	/* Device is enabled, clear the flag. */
	clear_bit(QM_DRIVER_DOWN, &qm->misc_ctl);

	ret = sec_debugfs_init(qm);
	if (ret)
		pci_warn(pdev, "Failed to init debugfs!\n");
@@ -1263,10 +1277,11 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	hisi_qm_alg_unregister(qm, &sec_devices, ctx_q_num);
err_qm_del_list:
	hisi_qm_del_list(qm, &sec_devices);
	hisi_qm_wait_task_finish(qm, &sec_devices);
	sec_debugfs_exit(qm);
	hisi_qm_stop(qm, QM_NORMAL);
err_probe_uninit:
	sec_show_last_regs_uninit(qm);
	sec_probe_uninit(qm);
err_qm_uninit:
	sec_qm_uninit(qm);
	return ret;
@@ -1287,10 +1302,7 @@ static void sec_remove(struct pci_dev *pdev)
	sec_debugfs_exit(qm);

	(void)hisi_qm_stop(qm, QM_NORMAL);

	if (qm->fun_type == QM_HW_PF)
		sec_debug_regs_clear(qm);
	sec_show_last_regs_uninit(qm);
	sec_probe_uninit(qm);

	sec_qm_uninit(qm);
}
+16 −3
Original line number Diff line number Diff line
@@ -1294,6 +1294,15 @@ static int hisi_zip_probe_init(struct hisi_zip *hisi_zip)
	return 0;
}

static void hisi_zip_probe_uninit(struct hisi_qm *qm)
{
	if (qm->fun_type == QM_HW_VF)
		return;

	hisi_zip_show_last_regs_uninit(qm);
	hisi_zip_close_sva_prefetch(qm);
}

static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
	struct hisi_zip *hisi_zip;
@@ -1305,7 +1314,7 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		return -ENOMEM;

	qm = &hisi_zip->qm;

	set_bit(QM_DRIVER_DOWN, &qm->misc_ctl);
	ret = hisi_zip_qm_init(qm, pdev);
	if (ret) {
		pci_err(pdev, "Failed to init ZIP QM (%d)!\n", ret);
@@ -1322,6 +1331,9 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	if (ret)
		goto err_dev_err_uninit;

	/* Device is enabled, clear the flag. */
	clear_bit(QM_DRIVER_DOWN, &qm->misc_ctl);

	ret = hisi_zip_debugfs_init(qm);
	if (ret)
		pci_err(pdev, "failed to init debugfs (%d)!\n", ret);
@@ -1355,12 +1367,13 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	hisi_qm_alg_unregister(qm, &zip_devices, HZIP_CTX_Q_NUM_DEF);

err_qm_del_list:
	hisi_qm_wait_task_finish(qm, &zip_devices);
	hisi_qm_del_list(qm, &zip_devices);
	hisi_zip_debugfs_exit(qm);
	hisi_qm_stop(qm, QM_NORMAL);

err_dev_err_uninit:
	hisi_zip_show_last_regs_uninit(qm);
	hisi_zip_probe_uninit(qm);

err_qm_uninit:
	hisi_zip_qm_uninit(qm);
@@ -1382,7 +1395,7 @@ static void hisi_zip_remove(struct pci_dev *pdev)

	hisi_zip_debugfs_exit(qm);
	hisi_qm_stop(qm, QM_NORMAL);
	hisi_zip_show_last_regs_uninit(qm);
	hisi_zip_probe_uninit(qm);
	hisi_zip_qm_uninit(qm);
}