drivers/gpu/drm/i915/gem/i915_gem_phys.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/i915/gem/i915_gem_phys.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/i915/gem/i915_gem_phys.c
Extension
.c
Size
6145 bytes
Lines
267
Domain
Driver Families
Bucket
drivers/gpu
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: MIT
/*
 * Copyright © 2014-2016 Intel Corporation
 */

#include <linux/highmem.h>
#include <linux/shmem_fs.h>
#include <linux/swap.h>

#include <drm/drm_cache.h>
#include <drm/drm_print.h>

#include "gt/intel_gt.h"
#include "i915_drv.h"
#include "i915_gem_object.h"
#include "i915_gem_object_frontbuffer.h"
#include "i915_gem_region.h"
#include "i915_gem_tiling.h"
#include "i915_scatterlist.h"

/* Abuse scatterlist to store pointer instead of struct page. */
static inline void __set_phys_vaddr(struct scatterlist *sg, void *vaddr)
{
	sg_assign_page(sg, (struct page *)vaddr);
}

static inline void *__get_phys_vaddr(struct scatterlist *sg)
{
	return (void *)sg_page(sg);
}

static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj)
{
	struct address_space *mapping = obj->base.filp->f_mapping;
	struct drm_i915_private *i915 = to_i915(obj->base.dev);
	struct scatterlist *sg;
	struct sg_table *st;
	dma_addr_t dma;
	void *vaddr;
	void *dst;
	int i;

	/* Contiguous chunk, with a single scatterlist element */
	if (overflows_type(obj->base.size, sg->length))
		return -E2BIG;

	if (GEM_WARN_ON(i915_gem_object_needs_bit17_swizzle(obj)))
		return -EINVAL;

	/*
	 * Always aligning to the object size, allows a single allocation
	 * to handle all possible callers, and given typical object sizes,
	 * the alignment of the buddy allocation will naturally match.
	 */
	vaddr = dma_alloc_coherent(obj->base.dev->dev,
				   roundup_pow_of_two(obj->base.size),
				   &dma, GFP_KERNEL);
	if (!vaddr)
		return -ENOMEM;

	st = kmalloc_obj(*st);
	if (!st)
		goto err_pci;

	if (sg_alloc_table(st, 1, GFP_KERNEL))
		goto err_st;

	sg = st->sgl;
	sg->offset = 0;
	sg->length = obj->base.size;

	__set_phys_vaddr(sg, vaddr);
	sg_dma_address(sg) = dma;
	sg_dma_len(sg) = obj->base.size;

	dst = vaddr;
	for (i = 0; i < obj->base.size / PAGE_SIZE; i++) {
		struct page *page;

		page = shmem_read_mapping_page(mapping, i);
		if (IS_ERR(page))
			goto err_st;

		memcpy_from_page(dst, page, 0, PAGE_SIZE);
		drm_clflush_virt_range(dst, PAGE_SIZE);

		put_page(page);
		dst += PAGE_SIZE;
	}

Annotation

Implementation Notes