162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci#ifndef _ASM_POWERPC_RTAS_WORK_AREA_H 362306a36Sopenharmony_ci#define _ASM_POWERPC_RTAS_WORK_AREA_H 462306a36Sopenharmony_ci 562306a36Sopenharmony_ci#include <linux/build_bug.h> 662306a36Sopenharmony_ci#include <linux/sizes.h> 762306a36Sopenharmony_ci#include <linux/types.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/page.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/** 1262306a36Sopenharmony_ci * struct rtas_work_area - RTAS work area descriptor. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Descriptor for a "work area" in PAPR terminology that satisfies 1562306a36Sopenharmony_ci * RTAS addressing requirements. 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_cistruct rtas_work_area { 1862306a36Sopenharmony_ci /* private: Use the APIs provided below. */ 1962306a36Sopenharmony_ci char *buf; 2062306a36Sopenharmony_ci size_t size; 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cienum { 2462306a36Sopenharmony_ci /* Maximum allocation size, enforced at build time. */ 2562306a36Sopenharmony_ci RTAS_WORK_AREA_MAX_ALLOC_SZ = SZ_128K, 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/** 2962306a36Sopenharmony_ci * rtas_work_area_alloc() - Acquire a work area of the requested size. 3062306a36Sopenharmony_ci * @size_: Allocation size. Must be compile-time constant and not more 3162306a36Sopenharmony_ci * than %RTAS_WORK_AREA_MAX_ALLOC_SZ. 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * Allocate a buffer suitable for passing to RTAS functions that have 3462306a36Sopenharmony_ci * a memory address parameter, often (but not always) referred to as a 3562306a36Sopenharmony_ci * "work area" in PAPR. Although callers are allowed to block while 3662306a36Sopenharmony_ci * holding a work area, the amount of memory reserved for this purpose 3762306a36Sopenharmony_ci * is limited, and allocations should be short-lived. A good guideline 3862306a36Sopenharmony_ci * is to release any allocated work area before returning from a 3962306a36Sopenharmony_ci * system call. 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * This function does not fail. It blocks until the allocation 4262306a36Sopenharmony_ci * succeeds. To prevent deadlocks, callers are discouraged from 4362306a36Sopenharmony_ci * allocating more than one work area simultaneously in a single task 4462306a36Sopenharmony_ci * context. 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * Context: This function may sleep. 4762306a36Sopenharmony_ci * Return: A &struct rtas_work_area descriptor for the allocated work area. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci#define rtas_work_area_alloc(size_) ({ \ 5062306a36Sopenharmony_ci static_assert(__builtin_constant_p(size_)); \ 5162306a36Sopenharmony_ci static_assert((size_) > 0); \ 5262306a36Sopenharmony_ci static_assert((size_) <= RTAS_WORK_AREA_MAX_ALLOC_SZ); \ 5362306a36Sopenharmony_ci __rtas_work_area_alloc(size_); \ 5462306a36Sopenharmony_ci}) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * Do not call __rtas_work_area_alloc() directly. Use 5862306a36Sopenharmony_ci * rtas_work_area_alloc(). 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistruct rtas_work_area *__rtas_work_area_alloc(size_t size); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/** 6362306a36Sopenharmony_ci * rtas_work_area_free() - Release a work area. 6462306a36Sopenharmony_ci * @area: Work area descriptor as returned from rtas_work_area_alloc(). 6562306a36Sopenharmony_ci * 6662306a36Sopenharmony_ci * Return a work area buffer to the pool. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_civoid rtas_work_area_free(struct rtas_work_area *area); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic inline char *rtas_work_area_raw_buf(const struct rtas_work_area *area) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci return area->buf; 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic inline size_t rtas_work_area_size(const struct rtas_work_area *area) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci return area->size; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic inline phys_addr_t rtas_work_area_phys(const struct rtas_work_area *area) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci return __pa(area->buf); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * Early setup for the work area allocator. Call from 8762306a36Sopenharmony_ci * rtas_initialize() only. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#ifdef CONFIG_PPC_PSERIES 9162306a36Sopenharmony_civoid rtas_work_area_reserve_arena(phys_addr_t limit); 9262306a36Sopenharmony_ci#else /* CONFIG_PPC_PSERIES */ 9362306a36Sopenharmony_cistatic inline void rtas_work_area_reserve_arena(phys_addr_t limit) {} 9462306a36Sopenharmony_ci#endif /* CONFIG_PPC_PSERIES */ 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#endif /* _ASM_POWERPC_RTAS_WORK_AREA_H */ 97