arch/powerpc/platforms/pseries/rtas-work-area.c

Source file repositories/reference/linux-study-clean/arch/powerpc/platforms/pseries/rtas-work-area.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/platforms/pseries/rtas-work-area.c
Extension
.c
Size
5915 bytes
Lines
211
Domain
Architecture Layer
Bucket
arch/powerpc
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0-only

#define pr_fmt(fmt)	"rtas-work-area: " fmt

#include <linux/genalloc.h>
#include <linux/log2.h>
#include <linux/kernel.h>
#include <linux/memblock.h>
#include <linux/mempool.h>
#include <linux/minmax.h>
#include <linux/mutex.h>
#include <linux/numa.h>
#include <linux/sizes.h>
#include <linux/wait.h>

#include <asm/machdep.h>
#include <asm/rtas-work-area.h>
#include <asm/rtas.h>

enum {
	/*
	 * Ensure the pool is page-aligned.
	 */
	RTAS_WORK_AREA_ARENA_ALIGN = PAGE_SIZE,
	/*
	 * Don't let a single allocation claim the whole arena.
	 */
	RTAS_WORK_AREA_ARENA_SZ = RTAS_WORK_AREA_MAX_ALLOC_SZ * 2,
	/*
	 * The smallest known work area size is for ibm,get-vpd's
	 * location code argument, which is limited to 79 characters
	 * plus 1 nul terminator.
	 *
	 * PAPR+ 7.3.20 ibm,get-vpd RTAS Call
	 * PAPR+ 12.3.2.4 Converged Location Code Rules - Length Restrictions
	 */
	RTAS_WORK_AREA_MIN_ALLOC_SZ = roundup_pow_of_two(80),
};

static struct {
	struct gen_pool *gen_pool;
	char *arena;
	struct mutex mutex; /* serializes allocations */
	struct wait_queue_head wqh;
	mempool_t descriptor_pool;
	bool available;
} rwa_state = {
	.mutex = __MUTEX_INITIALIZER(rwa_state.mutex),
	.wqh = __WAIT_QUEUE_HEAD_INITIALIZER(rwa_state.wqh),
};

/*
 * A single work area buffer and descriptor to serve requests early in
 * boot before the allocator is fully initialized. We know 4KB is the
 * most any boot time user needs (they all call ibm,get-system-parameter).
 */
static bool early_work_area_in_use __initdata;
static char early_work_area_buf[SZ_4K] __initdata __aligned(SZ_4K);
static struct rtas_work_area early_work_area __initdata = {
	.buf = early_work_area_buf,
	.size = sizeof(early_work_area_buf),
};


static struct rtas_work_area * __init rtas_work_area_alloc_early(size_t size)
{
	WARN_ON(size > early_work_area.size);
	WARN_ON(early_work_area_in_use);
	early_work_area_in_use = true;
	memset(early_work_area.buf, 0, early_work_area.size);
	return &early_work_area;
}

static void __init rtas_work_area_free_early(struct rtas_work_area *work_area)
{
	WARN_ON(work_area != &early_work_area);
	WARN_ON(!early_work_area_in_use);
	early_work_area_in_use = false;
}

struct rtas_work_area * __ref __rtas_work_area_alloc(size_t size)
{
	struct rtas_work_area *area;
	unsigned long addr;

	might_sleep();

	/*
	 * The rtas_work_area_alloc() wrapper enforces this at build
	 * time. Requests that exceed the arena size will block

Annotation

Implementation Notes