drivers/accel/ivpu/ivpu_gem_userptr.c

Source file repositories/reference/linux-study-clean/drivers/accel/ivpu/ivpu_gem_userptr.c

File Facts

System
Linux kernel
Corpus path
drivers/accel/ivpu/ivpu_gem_userptr.c
Extension
.c
Size
5504 bytes
Lines
214
Domain
Driver Families
Bucket
drivers/accel
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

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (C) 2020-2025 Intel Corporation
 */

#include <linux/dma-buf.h>
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/capability.h>

#include <drm/drm_device.h>
#include <drm/drm_file.h>
#include <drm/drm_gem.h>

#include "ivpu_drv.h"
#include "ivpu_gem.h"

static struct sg_table *
ivpu_gem_userptr_dmabuf_map(struct dma_buf_attachment *attachment,
			    enum dma_data_direction direction)
{
	struct sg_table *sgt = attachment->dmabuf->priv;
	int ret;

	ret = dma_map_sgtable(attachment->dev, sgt, direction, DMA_ATTR_SKIP_CPU_SYNC);
	if (ret)
		return ERR_PTR(ret);

	return sgt;
}

static void ivpu_gem_userptr_dmabuf_unmap(struct dma_buf_attachment *attachment,
					  struct sg_table *sgt,
					  enum dma_data_direction direction)
{
	dma_unmap_sgtable(attachment->dev, sgt, direction, DMA_ATTR_SKIP_CPU_SYNC);
}

static void ivpu_gem_userptr_dmabuf_release(struct dma_buf *dma_buf)
{
	struct sg_table *sgt = dma_buf->priv;
	struct sg_page_iter page_iter;
	struct page *page;

	for_each_sgtable_page(sgt, &page_iter, 0) {
		page = sg_page_iter_page(&page_iter);
		unpin_user_page(page);
	}

	sg_free_table(sgt);
	kfree(sgt);
}

static const struct dma_buf_ops ivpu_gem_userptr_dmabuf_ops = {
	.map_dma_buf = ivpu_gem_userptr_dmabuf_map,
	.unmap_dma_buf = ivpu_gem_userptr_dmabuf_unmap,
	.release = ivpu_gem_userptr_dmabuf_release,
};

static struct dma_buf *
ivpu_create_userptr_dmabuf(struct ivpu_device *vdev, void __user *user_ptr,
			   size_t size, uint32_t flags)
{
	struct dma_buf_export_info exp_info = {};
	struct dma_buf *dma_buf;
	struct sg_table *sgt;
	struct page **pages;
	unsigned long nr_pages = size >> PAGE_SHIFT;
	unsigned int gup_flags = FOLL_LONGTERM;
	int ret, i, pinned;

	/* Add FOLL_WRITE only if the BO is not read-only */
	if (!(flags & DRM_IVPU_BO_READ_ONLY))
		gup_flags |= FOLL_WRITE;

	pages = kvmalloc_objs(*pages, nr_pages);
	if (!pages)
		return ERR_PTR(-ENOMEM);

	pinned = pin_user_pages_fast((unsigned long)user_ptr, nr_pages, gup_flags, pages);
	if (pinned < 0) {
		ret = pinned;
		ivpu_dbg(vdev, IOCTL, "Failed to pin user pages: %d\n", ret);
		goto free_pages_array;
	}

Annotation

Implementation Notes