drivers/infiniband/hw/vmw_pvrdma/pvrdma_misc.c

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

File Facts

System
Linux kernel
Corpus path
drivers/infiniband/hw/vmw_pvrdma/pvrdma_misc.c
Extension
.c
Size
8420 bytes
Lines
305
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

#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/bitmap.h>

#include "pvrdma.h"

int pvrdma_page_dir_init(struct pvrdma_dev *dev, struct pvrdma_page_dir *pdir,
			 u64 npages, bool alloc_pages)
{
	u64 i;

	if (npages > PVRDMA_PAGE_DIR_MAX_PAGES)
		return -EINVAL;

	memset(pdir, 0, sizeof(*pdir));

	pdir->dir = dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
				       &pdir->dir_dma, GFP_KERNEL);
	if (!pdir->dir)
		goto err;

	pdir->ntables = PVRDMA_PAGE_DIR_TABLE(npages - 1) + 1;
	pdir->tables = kzalloc_objs(*pdir->tables, pdir->ntables);
	if (!pdir->tables)
		goto err;

	for (i = 0; i < pdir->ntables; i++) {
		pdir->tables[i] = dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
						(dma_addr_t *)&pdir->dir[i],
						GFP_KERNEL);
		if (!pdir->tables[i])
			goto err;
	}

	pdir->npages = npages;

	if (alloc_pages) {
		pdir->pages = kzalloc_objs(*pdir->pages, npages);
		if (!pdir->pages)
			goto err;

		for (i = 0; i < pdir->npages; i++) {
			dma_addr_t page_dma;

			pdir->pages[i] = dma_alloc_coherent(&dev->pdev->dev,
							    PAGE_SIZE,
							    &page_dma,
							    GFP_KERNEL);
			if (!pdir->pages[i])
				goto err;

			pvrdma_page_dir_insert_dma(pdir, i, page_dma);
		}
	}

	return 0;

err:
	pvrdma_page_dir_cleanup(dev, pdir);

	return -ENOMEM;
}

static u64 *pvrdma_page_dir_table(struct pvrdma_page_dir *pdir, u64 idx)
{
	return pdir->tables[PVRDMA_PAGE_DIR_TABLE(idx)];
}

dma_addr_t pvrdma_page_dir_get_dma(struct pvrdma_page_dir *pdir, u64 idx)
{
	return pvrdma_page_dir_table(pdir, idx)[PVRDMA_PAGE_DIR_PAGE(idx)];
}

static void pvrdma_page_dir_cleanup_pages(struct pvrdma_dev *dev,
					  struct pvrdma_page_dir *pdir)
{
	if (pdir->pages) {
		u64 i;

		for (i = 0; i < pdir->npages && pdir->pages[i]; i++) {
			dma_addr_t page_dma = pvrdma_page_dir_get_dma(pdir, i);

			dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
					  pdir->pages[i], page_dma);
		}

		kfree(pdir->pages);
	}
}

Annotation

Implementation Notes