drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c

Source file repositories/reference/linux-study-clean/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c

File Facts

System
Linux kernel
Corpus path
drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c
Extension
.c
Size
11213 bytes
Lines
406
Domain
Driver Families
Bucket
drivers/infiniband
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (IS_ERR(cq->umem)) {
			ret = PTR_ERR(cq->umem);
			goto err_cq;
		}

		npages = ib_umem_num_dma_blocks(cq->umem, PAGE_SIZE);
	} else {
		/* One extra page for shared ring state */
		npages = 1 + (entries * sizeof(struct pvrdma_cqe) +
			      PAGE_SIZE - 1) / PAGE_SIZE;

		/* Skip header page. */
		cq->offset = PAGE_SIZE;
	}

	if (npages < 0 || npages > PVRDMA_PAGE_DIR_MAX_PAGES) {
		dev_warn(&dev->pdev->dev,
			 "overflow pages in completion queue\n");
		ret = -EINVAL;
		goto err_umem;
	}

	ret = pvrdma_page_dir_init(dev, &cq->pdir, npages, cq->is_kernel);
	if (ret) {
		dev_warn(&dev->pdev->dev,
			 "could not allocate page directory\n");
		goto err_umem;
	}

	/* Ring state is always the first page. Set in library for user cq. */
	if (cq->is_kernel)
		cq->ring_state = cq->pdir.pages[0];
	else
		pvrdma_page_dir_insert_umem(&cq->pdir, cq->umem, 0);

	refcount_set(&cq->refcnt, 1);
	init_completion(&cq->free);
	spin_lock_init(&cq->cq_lock);

	memset(cmd, 0, sizeof(*cmd));
	cmd->hdr.cmd = PVRDMA_CMD_CREATE_CQ;
	cmd->nchunks = npages;
	cmd->ctx_handle = context ? context->ctx_handle : 0;
	cmd->cqe = entries;
	cmd->pdir_dma = cq->pdir.dir_dma;
	ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_CQ_RESP);
	if (ret < 0) {
		dev_warn(&dev->pdev->dev,
			 "could not create completion queue, error: %d\n", ret);
		goto err_page_dir;
	}

	cq->ibcq.cqe = resp->cqe;
	cq->cq_handle = resp->cq_handle;
	cq_resp.cqn = resp->cq_handle;
	spin_lock_irqsave(&dev->cq_tbl_lock, flags);
	dev->cq_tbl[cq->cq_handle % dev->dsr->caps.max_cq] = cq;
	spin_unlock_irqrestore(&dev->cq_tbl_lock, flags);

	if (!cq->is_kernel) {
		cq->uar = &context->uar;

		/* Copy udata back. */
		ret = ib_respond_udata(udata, cq_resp);
		if (ret) {
			pvrdma_destroy_cq(&cq->ibcq, udata);
			return ret;
		}
	}

	return 0;

err_page_dir:
	pvrdma_page_dir_cleanup(dev, &cq->pdir);
err_umem:
	ib_umem_release(cq->umem);
err_cq:
	atomic_dec(&dev->num_cqs);
	return ret;
}

static void pvrdma_free_cq(struct pvrdma_dev *dev, struct pvrdma_cq *cq)
{
	if (refcount_dec_and_test(&cq->refcnt))
		complete(&cq->free);
	wait_for_completion(&cq->free);

	ib_umem_release(cq->umem);

	pvrdma_page_dir_cleanup(dev, &cq->pdir);

Annotation

Implementation Notes