drivers/misc/genwqe/card_utils.c

Source file repositories/reference/linux-study-clean/drivers/misc/genwqe/card_utils.c

File Facts

System
Linux kernel
Corpus path
drivers/misc/genwqe/card_utils.c
Extension
.c
Size
27792 bytes
Lines
1050
Domain
Driver Families
Bucket
drivers/misc
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 (dma_mapping_error(&pci_dev->dev, daddr)) {
			dev_err(&pci_dev->dev,
				"[%s] err: no dma addr daddr=%016llx!\n",
				__func__, (long long)daddr);
			goto err;
		}

		dma_list[i] = daddr;
	}
	return 0;

 err:
	genwqe_unmap_pages(cd, dma_list, num_pages);
	return -EIO;
}

static int genwqe_sgl_size(int num_pages)
{
	int len, num_tlb = num_pages / 7;

	len = sizeof(struct sg_entry) * (num_pages+num_tlb + 1);
	return roundup(len, PAGE_SIZE);
}

/*
 * genwqe_alloc_sync_sgl() - Allocate memory for sgl and overlapping pages
 *
 * Allocates memory for sgl and overlapping pages. Pages which might
 * overlap other user-space memory blocks are being cached for DMAs,
 * such that we do not run into syncronization issues. Data is copied
 * from user-space into the cached pages.
 */
int genwqe_alloc_sync_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
			  void __user *user_addr, size_t user_size, int write)
{
	int ret = -ENOMEM;
	struct pci_dev *pci_dev = cd->pci_dev;

	sgl->fpage_offs = offset_in_page((unsigned long)user_addr);
	sgl->fpage_size = min_t(size_t, PAGE_SIZE-sgl->fpage_offs, user_size);
	sgl->nr_pages = DIV_ROUND_UP(sgl->fpage_offs + user_size, PAGE_SIZE);
	sgl->lpage_size = (user_size - sgl->fpage_size) % PAGE_SIZE;

	dev_dbg(&pci_dev->dev, "[%s] uaddr=%p usize=%8ld nr_pages=%ld fpage_offs=%lx fpage_size=%ld lpage_size=%ld\n",
		__func__, user_addr, user_size, sgl->nr_pages,
		sgl->fpage_offs, sgl->fpage_size, sgl->lpage_size);

	sgl->user_addr = user_addr;
	sgl->user_size = user_size;
	sgl->write = write;
	sgl->sgl_size = genwqe_sgl_size(sgl->nr_pages);

	if (get_order(sgl->sgl_size) > MAX_PAGE_ORDER) {
		dev_err(&pci_dev->dev,
			"[%s] err: too much memory requested!\n", __func__);
		return ret;
	}

	sgl->sgl = __genwqe_alloc_consistent(cd, sgl->sgl_size,
					     &sgl->sgl_dma_addr);
	if (sgl->sgl == NULL) {
		dev_err(&pci_dev->dev,
			"[%s] err: no memory available!\n", __func__);
		return ret;
	}

	/* Only use buffering on incomplete pages */
	if ((sgl->fpage_size != 0) && (sgl->fpage_size != PAGE_SIZE)) {
		sgl->fpage = __genwqe_alloc_consistent(cd, PAGE_SIZE,
						       &sgl->fpage_dma_addr);
		if (sgl->fpage == NULL)
			goto err_out;

		/* Sync with user memory */
		if (copy_from_user(sgl->fpage + sgl->fpage_offs,
				   user_addr, sgl->fpage_size)) {
			ret = -EFAULT;
			goto err_out;
		}
	}
	if (sgl->lpage_size != 0) {
		sgl->lpage = __genwqe_alloc_consistent(cd, PAGE_SIZE,
						       &sgl->lpage_dma_addr);
		if (sgl->lpage == NULL)
			goto err_out1;

		/* Sync with user memory */
		if (copy_from_user(sgl->lpage, user_addr + user_size -
				   sgl->lpage_size, sgl->lpage_size)) {
			ret = -EFAULT;

Annotation

Implementation Notes