kernel/dma/pool.c

Source file repositories/reference/linux-study-clean/kernel/dma/pool.c

File Facts

System
Linux kernel
Corpus path
kernel/dma/pool.c
Extension
.c
Size
8164 bytes
Lines
310
Domain
Core OS
Bucket
Scheduler, Processes, Timers, Sync, And Syscalls
Inferred role
Core OS: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2012 ARM Ltd.
 * Copyright (C) 2020 Google LLC
 */
#include <linux/cma.h>
#include <linux/debugfs.h>
#include <linux/dma-map-ops.h>
#include <linux/dma-direct.h>
#include <linux/init.h>
#include <linux/genalloc.h>
#include <linux/set_memory.h>
#include <linux/slab.h>
#include <linux/workqueue.h>

static struct gen_pool *atomic_pool_dma __ro_after_init;
static unsigned long pool_size_dma;
static struct gen_pool *atomic_pool_dma32 __ro_after_init;
static unsigned long pool_size_dma32;
static struct gen_pool *atomic_pool_kernel __ro_after_init;
static unsigned long pool_size_kernel;

/* Size can be defined by the coherent_pool command line */
static size_t atomic_pool_size;

/* Dynamic background expansion when the atomic pool is near capacity */
static struct work_struct atomic_pool_work;

static int __init early_coherent_pool(char *p)
{
	atomic_pool_size = memparse(p, &p);
	return 0;
}
early_param("coherent_pool", early_coherent_pool);

static void __init dma_atomic_pool_debugfs_init(void)
{
	struct dentry *root;

	root = debugfs_create_dir("dma_pools", NULL);
	debugfs_create_ulong("pool_size_dma", 0400, root, &pool_size_dma);
	debugfs_create_ulong("pool_size_dma32", 0400, root, &pool_size_dma32);
	debugfs_create_ulong("pool_size_kernel", 0400, root, &pool_size_kernel);
}

static void dma_atomic_pool_size_add(gfp_t gfp, size_t size)
{
	if (gfp & __GFP_DMA)
		pool_size_dma += size;
	else if (gfp & __GFP_DMA32)
		pool_size_dma32 += size;
	else
		pool_size_kernel += size;
}

static bool cma_in_zone(gfp_t gfp)
{
	unsigned long size;
	phys_addr_t end;
	struct cma *cma;

	cma = dev_get_cma_area(NULL);
	if (!cma)
		return false;

	size = cma_get_size(cma);
	if (!size)
		return false;

	/* CMA can't cross zone boundaries, see cma_activate_area() */
	end = cma_get_base(cma) + size - 1;
	if (IS_ENABLED(CONFIG_ZONE_DMA) && (gfp & GFP_DMA))
		return end <= zone_dma_limit;
	if (IS_ENABLED(CONFIG_ZONE_DMA32) && (gfp & GFP_DMA32))
		return end <= max(DMA_BIT_MASK(32), zone_dma_limit);
	return true;
}

static int atomic_pool_expand(struct gen_pool *pool, size_t pool_size,
			      gfp_t gfp)
{
	unsigned int order;
	struct page *page = NULL;
	void *addr;
	int ret = -ENOMEM;

	/* Cannot allocate larger than MAX_PAGE_ORDER */
	order = min(get_order(pool_size), MAX_PAGE_ORDER);

	do {

Annotation

Implementation Notes