162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2022, Microsoft Corporation. All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "mana_ib.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_ciint mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
962306a36Sopenharmony_ci		      struct ib_udata *udata)
1062306a36Sopenharmony_ci{
1162306a36Sopenharmony_ci	struct mana_ib_cq *cq = container_of(ibcq, struct mana_ib_cq, ibcq);
1262306a36Sopenharmony_ci	struct ib_device *ibdev = ibcq->device;
1362306a36Sopenharmony_ci	struct mana_ib_create_cq ucmd = {};
1462306a36Sopenharmony_ci	struct mana_ib_dev *mdev;
1562306a36Sopenharmony_ci	int err;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci	mdev = container_of(ibdev, struct mana_ib_dev, ib_dev);
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	if (udata->inlen < sizeof(ucmd))
2062306a36Sopenharmony_ci		return -EINVAL;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	err = ib_copy_from_udata(&ucmd, udata, min(sizeof(ucmd), udata->inlen));
2362306a36Sopenharmony_ci	if (err) {
2462306a36Sopenharmony_ci		ibdev_dbg(ibdev,
2562306a36Sopenharmony_ci			  "Failed to copy from udata for create cq, %d\n", err);
2662306a36Sopenharmony_ci		return err;
2762306a36Sopenharmony_ci	}
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	if (attr->cqe > MAX_SEND_BUFFERS_PER_QUEUE) {
3062306a36Sopenharmony_ci		ibdev_dbg(ibdev, "CQE %d exceeding limit\n", attr->cqe);
3162306a36Sopenharmony_ci		return -EINVAL;
3262306a36Sopenharmony_ci	}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	cq->cqe = attr->cqe;
3562306a36Sopenharmony_ci	cq->umem = ib_umem_get(ibdev, ucmd.buf_addr, cq->cqe * COMP_ENTRY_SIZE,
3662306a36Sopenharmony_ci			       IB_ACCESS_LOCAL_WRITE);
3762306a36Sopenharmony_ci	if (IS_ERR(cq->umem)) {
3862306a36Sopenharmony_ci		err = PTR_ERR(cq->umem);
3962306a36Sopenharmony_ci		ibdev_dbg(ibdev, "Failed to get umem for create cq, err %d\n",
4062306a36Sopenharmony_ci			  err);
4162306a36Sopenharmony_ci		return err;
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	err = mana_ib_gd_create_dma_region(mdev, cq->umem, &cq->gdma_region);
4562306a36Sopenharmony_ci	if (err) {
4662306a36Sopenharmony_ci		ibdev_dbg(ibdev,
4762306a36Sopenharmony_ci			  "Failed to create dma region for create cq, %d\n",
4862306a36Sopenharmony_ci			  err);
4962306a36Sopenharmony_ci		goto err_release_umem;
5062306a36Sopenharmony_ci	}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	ibdev_dbg(ibdev,
5362306a36Sopenharmony_ci		  "mana_ib_gd_create_dma_region ret %d gdma_region 0x%llx\n",
5462306a36Sopenharmony_ci		  err, cq->gdma_region);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	/*
5762306a36Sopenharmony_ci	 * The CQ ID is not known at this time. The ID is generated at create_qp
5862306a36Sopenharmony_ci	 */
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	return 0;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cierr_release_umem:
6362306a36Sopenharmony_ci	ib_umem_release(cq->umem);
6462306a36Sopenharmony_ci	return err;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ciint mana_ib_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct mana_ib_cq *cq = container_of(ibcq, struct mana_ib_cq, ibcq);
7062306a36Sopenharmony_ci	struct ib_device *ibdev = ibcq->device;
7162306a36Sopenharmony_ci	struct mana_ib_dev *mdev;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	mdev = container_of(ibdev, struct mana_ib_dev, ib_dev);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	mana_ib_gd_destroy_dma_region(mdev, cq->gdma_region);
7662306a36Sopenharmony_ci	ib_umem_release(cq->umem);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	return 0;
7962306a36Sopenharmony_ci}
80