Commit 7ab780f8 authored by Weili Qian's avatar Weili Qian Committed by JiangShui
Browse files

crypto: hisilicon/qm - modify interrupt resource application process

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


CVE: NA

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

Interrupt resources like wokrqueue are applied for in function
hisi_qm_memory_init(). During resource application, whether the
device supports this type of interrupt is not checked. As a result,
the applied resources may not be used. Therefore, the interrupt resource
application is moved to function qm_irqs_register(). When the interrupt
type is not supported, the interrupt resource is not applied, avoiding
resource waste.

Signed-off-by: default avatarWeili Qian <qianweili@huawei.com>
Signed-off-by: default avatarJiangShui Yang <yangjiangshui@h-partners.com>
parent cb2369cb
Loading
Loading
Loading
Loading
+3 −6
Original line number Diff line number Diff line
@@ -358,6 +358,8 @@ static struct dfx_diff_registers hpre_diff_regs[] = {
	},
};

static const struct hisi_qm_err_ini hpre_err_ini;

bool hpre_check_alg_support(struct hisi_qm *qm, u32 alg)
{
	u32 cap_val;
@@ -1162,6 +1164,7 @@ static int hpre_qm_init(struct hisi_qm *qm, struct pci_dev *pdev)
		qm->qp_num = pf_q_num;
		qm->debug.curr_qm_qp_num = pf_q_num;
		qm->qm_list = &hpre_devices;
		qm->err_ini = &hpre_err_ini;
		if (pf_q_num_flag)
			set_bit(QM_MODULE_PARAM, &qm->misc_ctl);
	}
@@ -1367,10 +1370,6 @@ static int hpre_pf_probe_init(struct hpre *hpre)
		return ret;

	hpre_open_sva_prefetch(qm);

	qm->err_ini = &hpre_err_ini;
	qm->err_ini->err_info_init(qm);
	hisi_qm_dev_err_init(qm);
	ret = hpre_show_last_regs_init(qm);
	if (ret)
		pci_err(qm->pdev, "Failed to init last word regs!\n");
@@ -1462,7 +1461,6 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id)

err_with_err_init:
	hpre_show_last_regs_uninit(qm);
	hisi_qm_dev_err_uninit(qm);

err_with_qm_init:
	hisi_qm_uninit(qm);
@@ -1488,7 +1486,6 @@ static void hpre_remove(struct pci_dev *pdev)
		hpre_cnt_regs_clear(qm);
		qm->debug.curr_qm_qp_num = 0;
		hpre_show_last_regs_uninit(qm);
		hisi_qm_dev_err_uninit(qm);
	}

	hisi_qm_uninit(qm);
+103 −78
Original line number Diff line number Diff line
@@ -2838,10 +2838,8 @@ static void hisi_qp_memory_uninit(struct hisi_qm *qm, int num)
	for (i = num - 1; i >= 0; i--) {
		qdma = &qm->qp_array[i].qdma;
		dma_free_coherent(dev, qdma->size, qdma->va, qdma->dma);
		kfree(qm->poll_data[i].qp_finish_id);
	}

	kfree(qm->poll_data);
	kfree(qm->qp_array);
}

@@ -2851,18 +2849,12 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id,
	struct device *dev = &qm->pdev->dev;
	size_t off = qm->sqe_size * sq_depth;
	struct hisi_qp *qp;
	int ret = -ENOMEM;

	qm->poll_data[id].qp_finish_id = kcalloc(qm->qp_num, sizeof(u16),
						 GFP_KERNEL);
	if (!qm->poll_data[id].qp_finish_id)
		return -ENOMEM;

	qp = &qm->qp_array[id];
	qp->qdma.va = dma_alloc_coherent(dev, dma_size, &qp->qdma.dma,
					 GFP_KERNEL);
	if (!qp->qdma.va)
		goto err_free_qp_finish_id;
		return -ENOMEM;

	qp->sqe = qp->qdma.va;
	qp->sqe_dma = qp->qdma.dma;
@@ -2875,10 +2867,6 @@ static int hisi_qp_memory_init(struct hisi_qm *qm, size_t dma_size, int id,
	qp->qp_id = id;

	return 0;

err_free_qp_finish_id:
	kfree(qm->poll_data[id].qp_finish_id);
	return ret;
}

static inline bool is_iommu_used(struct device *dev)
@@ -2984,11 +2972,6 @@ static void hisi_qm_set_state(struct hisi_qm *qm, u8 state)
		writel(state, qm->io_base + QM_VF_STATE);
}

static void hisi_qm_unint_work(struct hisi_qm *qm)
{
	destroy_workqueue(qm->wq);
}

static void hisi_qm_free_rsv_buf(struct hisi_qm *qm)
{
	struct qm_dma *xqc_dma = &qm->xqc_buf.qcdma;
@@ -3023,9 +3006,6 @@ static void hisi_qm_memory_uninit(struct hisi_qm *qm)
 */
void hisi_qm_uninit(struct hisi_qm *qm)
{
	qm_cmd_uninit(qm);
	hisi_qm_unint_work(qm);

	down_write(&qm->qps_lock);
	hisi_qm_memory_uninit(qm);
	hisi_qm_set_state(qm, QM_NOT_READY);
@@ -3374,12 +3354,12 @@ static enum acc_err_result qm_hw_error_handle(struct hisi_qm *qm, bool need_rese
}

/**
 * hisi_qm_dev_err_init() - Initialize device error configuration.
 * qm_dev_err_init() - Initialize device error configuration.
 * @qm: The qm for which we want to do error initialization.
 *
 * Initialize QM and device error related configuration.
 */
void hisi_qm_dev_err_init(struct hisi_qm *qm)
static void qm_dev_err_init(struct hisi_qm *qm)
{
	if (qm->fun_type == QM_HW_VF)
		return;
@@ -3392,15 +3372,14 @@ void hisi_qm_dev_err_init(struct hisi_qm *qm)
	}
	qm->err_ini->hw_err_enable(qm);
}
EXPORT_SYMBOL_GPL(hisi_qm_dev_err_init);

/**
 * hisi_qm_dev_err_uninit() - Uninitialize device error configuration.
 * qm_dev_err_uninit() - Uninitialize device error configuration.
 * @qm: The qm for which we want to do error uninitialization.
 *
 * Uninitialize QM and device error related configuration.
 */
void hisi_qm_dev_err_uninit(struct hisi_qm *qm)
static void qm_dev_err_uninit(struct hisi_qm *qm)
{
	if (qm->fun_type == QM_HW_VF)
		return;
@@ -3413,7 +3392,6 @@ void hisi_qm_dev_err_uninit(struct hisi_qm *qm)
	}
	qm->err_ini->hw_err_disable(qm);
}
EXPORT_SYMBOL_GPL(hisi_qm_dev_err_uninit);

/**
 * hisi_qm_free_qps() - free multiple queue pairs.
@@ -4507,7 +4485,7 @@ static int qm_controller_reset_done(struct hisi_qm *qm)
	}

	qm_restart_prepare(qm);
	hisi_qm_dev_err_init(qm);
	qm_dev_err_init(qm);
	if (qm->err_ini->open_axi_master_ooo)
		qm->err_ini->open_axi_master_ooo(qm);

@@ -4621,7 +4599,7 @@ void hisi_qm_reset_prepare(struct pci_dev *pdev)
			return;
		}

		hisi_qm_dev_err_uninit(pf_qm);
		qm_dev_err_uninit(pf_qm);
		/*
		 * Check whether there is an ECC mbit error,
		 * If it occurs, need to wait for soft reset
@@ -4693,7 +4671,7 @@ void hisi_qm_reset_done(struct pci_dev *pdev)
		}
	}

	hisi_qm_dev_err_init(pf_qm);
	qm_dev_err_init(pf_qm);

	ret = qm_restart(qm);
	if (ret) {
@@ -5018,10 +4996,15 @@ static void qm_unregister_abnormal_irq(struct hisi_qm *qm)
	if (qm->fun_type == QM_HW_VF)
		return;

	if (!qm->err_ini->err_info_init)
		return;

	val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val;
	if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK))
		return;

	qm_dev_err_uninit(qm);

	irq_vector = val & QM_IRQ_VECTOR_MASK;
	free_irq(pci_irq_vector(pdev, irq_vector), qm);
}
@@ -5035,18 +5018,29 @@ static int qm_register_abnormal_irq(struct hisi_qm *qm)
	if (qm->fun_type == QM_HW_VF)
		return 0;

	if (!qm->err_ini->err_info_init) {
		dev_info(&qm->pdev->dev, "Device doesnot support error init!\n");
		return 0;
	}

	val = qm->cap_tables.qm_cap_table[QM_ABN_IRQ_TYPE_CAP_IDX].cap_val;
	if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_ABN_IRQ_TYPE_MASK))
		return 0;

	irq_vector = val & QM_IRQ_VECTOR_MASK;
	ret = request_irq(pci_irq_vector(pdev, irq_vector), qm_abnormal_irq, 0, qm->dev_name, qm);
	if (ret)
	if (ret) {
		dev_err(&qm->pdev->dev, "failed to request abnormal irq, ret = %d", ret);

		return ret;
	}

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

	return 0;
}

static void qm_unregister_mb_cmd_irq(struct hisi_qm *qm)
{
	struct pci_dev *pdev = qm->pdev;
@@ -5056,6 +5050,8 @@ static void qm_unregister_mb_cmd_irq(struct hisi_qm *qm)
	if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK))
		return;

	qm_cmd_uninit(qm);

	irq_vector = val & QM_IRQ_VECTOR_MASK;
	free_irq(pci_irq_vector(pdev, irq_vector), qm);
}
@@ -5072,12 +5068,18 @@ static int qm_register_mb_cmd_irq(struct hisi_qm *qm)

	irq_vector = val & QM_IRQ_VECTOR_MASK;
	ret = request_irq(pci_irq_vector(pdev, irq_vector), qm_mb_cmd_irq, 0, qm->dev_name, qm);
	if (ret)
	if (ret) {
		dev_err(&pdev->dev, "failed to request function communication irq, ret = %d", ret);

		return ret;
	}

	INIT_WORK(&qm->cmd_process, qm_cmd_process);
	qm_cmd_init(qm);

	return 0;
}

/* Disable aeq interrupt by hisi_qm_stop(). */
static void qm_unregister_aeq_irq(struct hisi_qm *qm)
{
	struct pci_dev *pdev = qm->pdev;
@@ -5091,6 +5093,7 @@ static void qm_unregister_aeq_irq(struct hisi_qm *qm)
	free_irq(pci_irq_vector(pdev, irq_vector), qm);
}

/* Enable aeq interrupt by hisi_qm_start(). */
static int qm_register_aeq_irq(struct hisi_qm *qm)
{
	struct pci_dev *pdev = qm->pdev;
@@ -5105,11 +5108,62 @@ static int qm_register_aeq_irq(struct hisi_qm *qm)
	ret = request_threaded_irq(pci_irq_vector(pdev, irq_vector), NULL,
						   qm_aeq_thread, IRQF_ONESHOT, qm->dev_name, qm);
	if (ret)
		dev_err(&pdev->dev, "failed to request eq irq, ret = %d", ret);
		dev_err(&pdev->dev, "failed to request aeq irq, ret = %d", ret);

	return ret;
}

static void qm_uninit_eq_work(struct hisi_qm *qm)
{
	int i;

	for (i = qm->qp_num - 1; i >= 0; i--)
		kfree(qm->poll_data[i].qp_finish_id);

	kfree(qm->poll_data);
	destroy_workqueue(qm->wq);
}

static int qm_init_eq_work(struct hisi_qm *qm)
{
	int ret = -ENOMEM;
	u16 eq_depth;
	int i;

	qm->poll_data = kcalloc(qm->qp_num, sizeof(struct hisi_qm_poll_data), GFP_KERNEL);
	if (!qm->poll_data)
		return ret;

	qm_get_xqc_depth(qm, &qm->eq_depth, &qm->aeq_depth, QM_XEQ_DEPTH_CAP);
	eq_depth = qm->eq_depth >> 1;
	for (i = 0; i < qm->qp_num; i++) {
		qm->poll_data[i].qp_finish_id = kcalloc(eq_depth, sizeof(u16), GFP_KERNEL);
		if (!qm->poll_data[i].qp_finish_id)
			goto free_qp_finish_id;

		INIT_WORK(&qm->poll_data[i].work, qm_work_process);
		qm->poll_data[i].qm = qm;
	}

	qm->wq = alloc_workqueue("%s", WQ_HIGHPRI | WQ_MEM_RECLAIM |
				 WQ_UNBOUND, num_online_cpus(),
				 pci_name(qm->pdev));
	if (!qm->wq) {
		dev_err(&qm->pdev->dev, "failed to alloc workqueue!\n");
		goto free_qp_finish_id;
	}

	return 0;

free_qp_finish_id:
	for (i = i - 1; i >= 0; i--)
		kfree(qm->poll_data[i].qp_finish_id);

	kfree(qm->poll_data);
	return ret;
}

/* Disable eq interrupt by hisi_qm_stop(). */
static void qm_unregister_eq_irq(struct hisi_qm *qm)
{
	struct pci_dev *pdev = qm->pdev;
@@ -5119,10 +5173,13 @@ static void qm_unregister_eq_irq(struct hisi_qm *qm)
	if (!((val >> QM_IRQ_TYPE_SHIFT) & QM_IRQ_TYPE_MASK))
		return;

	qm_uninit_eq_work(qm);

	irq_vector = val & QM_IRQ_VECTOR_MASK;
	free_irq(pci_irq_vector(pdev, irq_vector), qm);
}

/* Enable eq interrupt by hisi_qm_start(). */
static int qm_register_eq_irq(struct hisi_qm *qm)
{
	struct pci_dev *pdev = qm->pdev;
@@ -5135,12 +5192,20 @@ static int qm_register_eq_irq(struct hisi_qm *qm)

	irq_vector = val & QM_IRQ_VECTOR_MASK;
	ret = request_irq(pci_irq_vector(pdev, irq_vector), qm_eq_irq, 0, qm->dev_name, qm);
	if (ret)
	if (ret) {
		dev_err(&pdev->dev, "failed to request eq irq, ret = %d", ret);
		return ret;
	}

	ret = qm_init_eq_work(qm);
	if (ret) {
		free_irq(pci_irq_vector(pdev, irq_vector), qm);
		return ret;
	}

	return 0;
}

static void qm_irqs_unregister(struct hisi_qm *qm)
{
	qm_unregister_mb_cmd_irq(qm);
@@ -5366,30 +5431,6 @@ static int hisi_qm_pci_init(struct hisi_qm *qm)
	return ret;
}

static int hisi_qm_init_work(struct hisi_qm *qm)
{
	int i;

	for (i = 0; i < qm->qp_num; i++)
		INIT_WORK(&qm->poll_data[i].work, qm_work_process);

	if (qm->fun_type == QM_HW_PF)
		INIT_WORK(&qm->rst_work, hisi_qm_controller_reset);

	if (qm->ver > QM_HW_V2)
		INIT_WORK(&qm->cmd_process, qm_cmd_process);

	qm->wq = alloc_workqueue("%s", WQ_HIGHPRI | WQ_MEM_RECLAIM |
				 WQ_UNBOUND, num_online_cpus(),
				 pci_name(qm->pdev));
	if (!qm->wq) {
		pci_err(qm->pdev, "failed to alloc workqueue!\n");
		return -ENOMEM;
	}

	return 0;
}

static int hisi_qp_alloc_memory(struct hisi_qm *qm)
{
	struct device *dev = &qm->pdev->dev;
@@ -5401,19 +5442,12 @@ static int hisi_qp_alloc_memory(struct hisi_qm *qm)
	if (!qm->qp_array)
		return -ENOMEM;

	qm->poll_data = kcalloc(qm->qp_num, sizeof(struct hisi_qm_poll_data), GFP_KERNEL);
	if (!qm->poll_data) {
		kfree(qm->qp_array);
		return -ENOMEM;
	}

	qm_get_xqc_depth(qm, &sq_depth, &cq_depth, QM_QP_DEPTH_CAP);

	/* one more page for device or qp statuses */
	qp_dma_size = qm->sqe_size * sq_depth + sizeof(struct qm_cqe) * cq_depth;
	qp_dma_size = PAGE_ALIGN(qp_dma_size) + PAGE_SIZE;
	for (i = 0; i < qm->qp_num; i++) {
		qm->poll_data[i].qm = qm;
		ret = hisi_qp_memory_init(qm, qp_dma_size, i, sq_depth, cq_depth);
		if (ret)
			goto err_init_qp_mem;
@@ -5482,7 +5516,6 @@ static int hisi_qm_memory_init(struct hisi_qm *qm)
} while (0)

	idr_init(&qm->qp_idr);
	qm_get_xqc_depth(qm, &qm->eq_depth, &qm->aeq_depth, QM_XEQ_DEPTH_CAP);
	qm->qdma.size = QMC_ALIGN(sizeof(struct qm_eqe) * qm->eq_depth) +
			QMC_ALIGN(sizeof(struct qm_aeqe) * qm->aeq_depth) +
			QMC_ALIGN(sizeof(struct qm_sqc) * qm->qp_num) +
@@ -5567,16 +5600,8 @@ int hisi_qm_init(struct hisi_qm *qm)
	if (ret)
		goto err_alloc_uacce;

	ret = hisi_qm_init_work(qm);
	if (ret)
		goto err_free_qm_memory;

	qm_cmd_init(qm);

	return 0;

err_free_qm_memory:
	hisi_qm_memory_uninit(qm);
err_alloc_uacce:
	qm_remove_uacce(qm);
err_irq_register:
@@ -5714,7 +5739,7 @@ static int qm_rebuild_for_resume(struct hisi_qm *qm)
	}

	qm_cmd_init(qm);
	hisi_qm_dev_err_init(qm);
	qm_dev_err_init(qm);
	/* Set the doorbell timeout to QM_DB_TIMEOUT_CFG ns. */
	writel(QM_DB_TIMEOUT_SET, qm->io_base + QM_DB_TIMEOUT_CFG);
	qm_disable_clock_gate(qm);
+1 −12
Original line number Diff line number Diff line
@@ -1083,15 +1083,11 @@ static int sec_pf_probe_init(struct sec_dev *sec)
	struct hisi_qm *qm = &sec->qm;
	int ret;

	qm->err_ini = &sec_err_ini;
	qm->err_ini->err_info_init(qm);

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

	sec_open_sva_prefetch(qm);
	hisi_qm_dev_err_init(qm);
	sec_debug_regs_clear(qm);
	ret = sec_show_last_regs_init(qm);
	if (ret)
@@ -1140,6 +1136,7 @@ static int sec_qm_init(struct hisi_qm *qm, struct pci_dev *pdev)
		qm->qp_num = pf_q_num;
		qm->debug.curr_qm_qp_num = pf_q_num;
		qm->qm_list = &sec_devices;
		qm->err_ini = &sec_err_ini;
		if (pf_q_num_flag)
			set_bit(QM_MODULE_PARAM, &qm->misc_ctl);
	} else if (qm->fun_type == QM_HW_VF && qm->ver == QM_HW_V1) {
@@ -1202,11 +1199,6 @@ static int sec_probe_init(struct sec_dev *sec)
	return 0;
}

static void sec_probe_uninit(struct hisi_qm *qm)
{
	hisi_qm_dev_err_uninit(qm);
}

static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
	struct sec_dev *sec;
@@ -1275,7 +1267,6 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	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;
@@ -1301,8 +1292,6 @@ static void sec_remove(struct pci_dev *pdev)
		sec_debug_regs_clear(qm);
	sec_show_last_regs_uninit(qm);

	sec_probe_uninit(qm);

	sec_qm_uninit(qm);
}

+1 −5
Original line number Diff line number Diff line
@@ -1168,8 +1168,6 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip)

	hisi_zip->ctrl = ctrl;
	ctrl->hisi_zip = hisi_zip;
	qm->err_ini = &hisi_zip_err_ini;
	qm->err_ini->err_info_init(qm);

	ret = hisi_zip_set_user_domain_and_cache(qm);
	if (ret)
@@ -1180,7 +1178,6 @@ static int hisi_zip_pf_probe_init(struct hisi_zip *hisi_zip)
		return ret;

	hisi_zip_open_sva_prefetch(qm);
	hisi_qm_dev_err_init(qm);
	hisi_zip_debug_regs_clear(qm);

	ret = hisi_zip_show_last_regs_init(qm);
@@ -1230,6 +1227,7 @@ static int hisi_zip_qm_init(struct hisi_qm *qm, struct pci_dev *pdev)
		qm->qp_num = pf_q_num;
		qm->debug.curr_qm_qp_num = pf_q_num;
		qm->qm_list = &zip_devices;
		qm->err_ini = &hisi_zip_err_ini;
		if (pf_q_num_flag)
			set_bit(QM_MODULE_PARAM, &qm->misc_ctl);
	} else if (qm->fun_type == QM_HW_VF && qm->ver == QM_HW_V1) {
@@ -1363,7 +1361,6 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id)

err_dev_err_uninit:
	hisi_zip_show_last_regs_uninit(qm);
	hisi_qm_dev_err_uninit(qm);

err_qm_uninit:
	hisi_zip_qm_uninit(qm);
@@ -1386,7 +1383,6 @@ 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_qm_dev_err_uninit(qm);
	hisi_zip_qm_uninit(qm);
}

+0 −2
Original line number Diff line number Diff line
@@ -553,8 +553,6 @@ void hisi_qm_debug_regs_clear(struct hisi_qm *qm);
int hisi_qm_sriov_enable(struct pci_dev *pdev, int max_vfs);
int hisi_qm_sriov_disable(struct pci_dev *pdev, bool is_frozen);
int hisi_qm_sriov_configure(struct pci_dev *pdev, int num_vfs);
void hisi_qm_dev_err_init(struct hisi_qm *qm);
void hisi_qm_dev_err_uninit(struct hisi_qm *qm);
int hisi_qm_regs_debugfs_init(struct hisi_qm *qm,
			  struct dfx_diff_registers *dregs, u32 reg_len);
void hisi_qm_regs_debugfs_uninit(struct hisi_qm *qm, u32 reg_len);