Unverified Commit 719747ca authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!7204 udma: fix bugs of DCA and record db

Merge Pull Request from: @zhaoweibo3 
 
The patches fixes the following problems:
1. Fix a bug of record_db which may causing Null pointer exception.
2. Fix a bug of DCA in a concurrent scenario.

https://gitee.com/openeuler/kernel/issues/I8V1IQ 
 
Link:https://gitee.com/openeuler/kernel/pulls/7204

 

Reviewed-by: default avatarChunzhi Hu <huchunzhi@huawei.com>
Signed-off-by: default avatarJialin Zhang <zhangjialin11@huawei.com>
parents 1b5b5db6 7116ad82
Loading
Loading
Loading
Loading
+49 −25
Original line number Diff line number Diff line
@@ -604,7 +604,8 @@ int udma_register_udca(struct udma_dev *udma_dev,
	int ret;

	ret = copy_from_user(&ucmd, (void *)udrv_data->in_addr,
			     min_t(uint32_t, udrv_data->in_len, (uint32_t)sizeof(ucmd)));
			     min_t(uint32_t, udrv_data->in_len,
				   (uint32_t)sizeof(ucmd)));
	if (ret) {
		dev_err(udma_dev->dev, "Failed to copy udata, ret = %d.\n",
			ret);
@@ -781,6 +782,24 @@ static int query_dca_active_pages_proc(struct dca_mem *mem, uint32_t index,
	return DCA_MEM_STOP_ITERATE;
}

static struct udma_qp *udma_dca_get_qp(struct udma_dev *dev, uint32_t qpn)
{
	struct udma_qp *qp;

	xa_lock(&dev->qp_table.xa);
	qp = get_qp(dev, qpn);
	if (!qp) {
		dev_err(dev->dev, "failed to find qp, qpn = 0x%x\n", qpn);
		xa_unlock(&dev->qp_table.xa);
		return NULL;
	}
	refcount_inc(&qp->refcount);

	xa_unlock(&dev->qp_table.xa);

	return qp;
}

int udma_query_dca_mem(struct udma_dev *dev, struct udma_dca_query_attr *attr,
		       struct udma_dca_query_resp *resp)
{
@@ -789,11 +808,10 @@ int udma_query_dca_mem(struct udma_dev *dev, struct udma_dca_query_attr *attr,
	struct udma_dca_cfg *cfg;
	struct udma_qp *qp;

	qp = get_qp(dev, attr->qpn);
	if (qp == NULL) {
		dev_err(dev->dev, "failed to find qp, qpn = 0x%llx\n", attr->qpn);
	qp = udma_dca_get_qp(dev, attr->qpn);
	if (qp == NULL)
		return -EINVAL;
	}

	cfg = &qp->dca_cfg;
	ctx = qp->dca_ctx;

@@ -805,6 +823,9 @@ int udma_query_dca_mem(struct udma_dev *dev, struct udma_dca_query_attr *attr,
	resp->mem_ofs = a_attr.page_index << UDMA_HW_PAGE_SHIFT;
	resp->page_count = a_attr.page_count;

	if (refcount_dec_and_test(&qp->refcount))
		complete(&qp->free);

	return a_attr.page_count ? 0 : -ENOMEM;
}

@@ -1111,14 +1132,12 @@ int udma_dca_attach(struct udma_dev *dev, struct udma_dca_attach_attr *attr,
	struct udma_dca_cfg *cfg;
	struct udma_qp *qp;
	uint32_t buf_id;
	int ret;
	int ret = 0;

	qp = get_qp(dev, attr->qpn);
	if (qp == NULL) {
		dev_err(dev->dev, "failed to find attach qp, qpn = 0x%llx\n",
			attr->qpn);
	qp = udma_dca_get_qp(dev, attr->qpn);
	if (qp == NULL)
		return -EINVAL;
	}

	cfg = &qp->dca_cfg;
	ctx = qp->dca_ctx;

@@ -1131,7 +1150,7 @@ int udma_dca_attach(struct udma_dev *dev, struct udma_dca_attach_attr *attr,
	if (buf_id != UDMA_DCA_INVALID_BUF_ID) {
		resp->alloc_pages = cfg->npages;
		spin_unlock(&cfg->lock);
		return 0;
		goto refcount_dec;
	}

	/* Start to new attach */
@@ -1140,7 +1159,7 @@ int udma_dca_attach(struct udma_dev *dev, struct udma_dca_attach_attr *attr,
	if (buf_id == UDMA_DCA_INVALID_BUF_ID) {
		spin_unlock(&cfg->lock);
		/* No report fail, need try again after the pool increased */
		return 0;
		goto refcount_dec;
	}

	ret = active_alloced_buf(dev, ctx, qp, buf_id, attr);
@@ -1149,7 +1168,7 @@ int udma_dca_attach(struct udma_dev *dev, struct udma_dca_attach_attr *attr,
		dev_err(dev->dev,
			"failed to active DCA buf for QP-%llu, ret = %d.\n",
			qp->qpn, ret);
		return ret;
		goto refcount_dec;
	}

	/* Attach ok */
@@ -1162,7 +1181,10 @@ int udma_dca_attach(struct udma_dev *dev, struct udma_dca_attach_attr *attr,
	resp->dcan = cfg->dcan;
	update_dca_buf_status(ctx, cfg->dcan, true);

	return 0;
refcount_dec:
	if (refcount_dec_and_test(&qp->refcount))
		complete(&qp->free);
	return ret;
}

void udma_dca_disattach(struct udma_dev *dev, struct udma_dca_attach_attr *attr)
@@ -1171,12 +1193,10 @@ void udma_dca_disattach(struct udma_dev *dev, struct udma_dca_attach_attr *attr)
	struct udma_dca_cfg *cfg;
	struct udma_qp *qp;

	qp = get_qp(dev, attr->qpn);
	if (qp == NULL) {
		dev_err(dev->dev, "failed to find disattach qp, qpn = 0x%llx\n",
			attr->qpn);
	qp = udma_dca_get_qp(dev, attr->qpn);
	if (qp == NULL)
		return;
	}

	cfg = &qp->dca_cfg;
	ctx = qp->dca_ctx;

@@ -1185,6 +1205,9 @@ void udma_dca_disattach(struct udma_dev *dev, struct udma_dca_attach_attr *attr)
	cfg->buf_id = UDMA_DCA_INVALID_BUF_ID;

	update_dca_buf_status(ctx, cfg->dcan, false);

	if (refcount_dec_and_test(&qp->refcount))
		complete(&qp->free);
}

void udma_dca_detach(struct udma_dev *dev, struct udma_dca_detach_attr *attr)
@@ -1193,12 +1216,10 @@ void udma_dca_detach(struct udma_dev *dev, struct udma_dca_detach_attr *attr)
	struct udma_dca_cfg *cfg;
	struct udma_qp *qp;

	qp = get_qp(dev, attr->qpn);
	if (qp == NULL) {
		dev_err(dev->dev, "failed to find detach qp, qpn = 0x%llx\n",
			attr->qpn);
	qp = udma_dca_get_qp(dev, attr->qpn);
	if (qp == NULL)
		return;
	}

	cfg = &qp->dca_cfg;
	ctx = qp->dca_ctx;

@@ -1212,6 +1233,9 @@ void udma_dca_detach(struct udma_dev *dev, struct udma_dca_detach_attr *attr)
	spin_unlock(&ctx->aging_lock);

	restart_aging_dca_mem(dev, ctx);

	if (refcount_dec_and_test(&qp->refcount))
		complete(&qp->free);
}

static int enum_dca_pool_proc(struct dca_mem *mem, uint32_t index, void *param)
+2 −3
Original line number Diff line number Diff line
@@ -238,6 +238,7 @@ static int alloc_jfc_buf(struct udma_dev *udma_dev, struct udma_jfc *udma_jfc,

	refcount_set(&udma_jfc->refcount, 1);
	init_completion(&udma_jfc->free);
	udma_jfc->udma_uctx = udma_uctx;
	return ret;

err_copy:
@@ -501,15 +502,13 @@ static void free_jfc_cqc(struct udma_dev *udma_dev, struct udma_jfc *udma_jfc)

static void free_jfc_buf(struct udma_dev *udma_dev, struct udma_jfc *udma_jfc)
{
	struct udma_ucontext *udma_uctx = to_udma_ucontext(udma_jfc->ubcore_jfc.uctx);

	/* wait for all interrupt processed */
	if (refcount_dec_and_test(&udma_jfc->refcount))
		complete(&udma_jfc->free);
	wait_for_completion(&udma_jfc->free);

	if (udma_dev->caps.flags & UDMA_CAP_FLAG_CQ_RECORD_DB)
		udma_db_unmap_user(udma_uctx, &udma_jfc->db);
		udma_db_unmap_user(udma_jfc->udma_uctx, &udma_jfc->db);
	udma_mtr_destroy(udma_dev, &udma_jfc->mtr);
}

+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ struct udma_jfc {
	struct completion	free;
	struct list_head	sq_list;
	struct list_head	rq_list;
	struct udma_ucontext	*udma_uctx;
	struct hns3_udma_jfc_attr_ex	jfc_attr_ex;
};

+2 −3
Original line number Diff line number Diff line
@@ -226,6 +226,7 @@ static int alloc_jfr_buf(struct udma_dev *dev, struct udma_jfr *jfr,

	refcount_set(&jfr->refcount, 1);
	init_completion(&jfr->free);
	jfr->udma_uctx = udma_uctx;
	return 0;

err_db:
@@ -527,8 +528,6 @@ static void free_jfrc(struct udma_dev *dev, struct udma_jfr *jfr)

static void free_jfr_buf(struct udma_dev *dev, struct udma_jfr *jfr)
{
	struct udma_ucontext *udma_uctx = to_udma_ucontext(jfr->ubcore_jfr.uctx);

	if (refcount_dec_and_test(&jfr->refcount))
		complete(&jfr->free);

@@ -536,7 +535,7 @@ static void free_jfr_buf(struct udma_dev *dev, struct udma_jfr *jfr)

	if (dev->caps.flags & UDMA_CAP_FLAG_SRQ_RECORD_DB ||
	    jfr->jfr_caps & HNS3_UDMA_JFR_CAP_RECORD_DB)
		udma_db_unmap_user(udma_uctx, &jfr->db);
		udma_db_unmap_user(jfr->udma_uctx, &jfr->db);

	free_jfr_wqe_buf(dev, jfr);
	free_jfr_idx(dev, jfr);
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ struct udma_jfr {
	uint32_t		qpn;
	enum ubcore_transport_mode tp_mode;
	bool			share_jfr;
	struct udma_ucontext	*udma_uctx;
};

struct udma_jfr_context {
Loading