| /* SPDX-License-Identifier: GPL-2.0-only */ | |
| #ifndef _ASM_POWERPC_RTAS_WORK_AREA_H | |
| #define _ASM_POWERPC_RTAS_WORK_AREA_H | |
| #include <linux/build_bug.h> | |
| #include <linux/sizes.h> | |
| #include <linux/types.h> | |
| #include <asm/page.h> | |
| /** | |
| * struct rtas_work_area - RTAS work area descriptor. | |
| * | |
| * Descriptor for a "work area" in PAPR terminology that satisfies | |
| * RTAS addressing requirements. | |
| */ | |
| struct rtas_work_area { | |
| /* private: Use the APIs provided below. */ | |
| char *buf; | |
| size_t size; | |
| }; | |
| enum { | |
| /* Maximum allocation size, enforced at build time. */ | |
| RTAS_WORK_AREA_MAX_ALLOC_SZ = SZ_128K, | |
| }; | |
| /** | |
| * rtas_work_area_alloc() - Acquire a work area of the requested size. | |
| * @size_: Allocation size. Must be compile-time constant and not more | |
| * than %RTAS_WORK_AREA_MAX_ALLOC_SZ. | |
| * | |
| * Allocate a buffer suitable for passing to RTAS functions that have | |
| * a memory address parameter, often (but not always) referred to as a | |
| * "work area" in PAPR. Although callers are allowed to block while | |
| * holding a work area, the amount of memory reserved for this purpose | |
| * is limited, and allocations should be short-lived. A good guideline | |
| * is to release any allocated work area before returning from a | |
| * system call. | |
| * | |
| * This function does not fail. It blocks until the allocation | |
| * succeeds. To prevent deadlocks, callers are discouraged from | |
| * allocating more than one work area simultaneously in a single task | |
| * context. | |
| * | |
| * Context: This function may sleep. | |
| * Return: A &struct rtas_work_area descriptor for the allocated work area. | |
| */ | |
| #define rtas_work_area_alloc(size_) ({ \ | |
| static_assert(__builtin_constant_p(size_)); \ | |
| static_assert((size_) > 0); \ | |
| static_assert((size_) <= RTAS_WORK_AREA_MAX_ALLOC_SZ); \ | |
| __rtas_work_area_alloc(size_); \ | |
| }) | |
| /* | |
| * Do not call __rtas_work_area_alloc() directly. Use | |
| * rtas_work_area_alloc(). | |
| */ | |
| struct rtas_work_area *__rtas_work_area_alloc(size_t size); | |
| /** | |
| * rtas_work_area_free() - Release a work area. | |
| * @area: Work area descriptor as returned from rtas_work_area_alloc(). | |
| * | |
| * Return a work area buffer to the pool. | |
| */ | |
| void rtas_work_area_free(struct rtas_work_area *area); | |
| static inline char *rtas_work_area_raw_buf(const struct rtas_work_area *area) | |
| { | |
| return area->buf; | |
| } | |
| static inline size_t rtas_work_area_size(const struct rtas_work_area *area) | |
| { | |
| return area->size; | |
| } | |
| static inline phys_addr_t rtas_work_area_phys(const struct rtas_work_area *area) | |
| { | |
| return __pa(area->buf); | |
| } | |
| /* | |
| * Early setup for the work area allocator. Call from | |
| * rtas_initialize() only. | |
| */ | |
| #ifdef CONFIG_PPC_PSERIES | |
| void rtas_work_area_reserve_arena(phys_addr_t limit); | |
| #else /* CONFIG_PPC_PSERIES */ | |
| static inline void rtas_work_area_reserve_arena(phys_addr_t limit) {} | |
| #endif /* CONFIG_PPC_PSERIES */ | |
| #endif /* _ASM_POWERPC_RTAS_WORK_AREA_H */ |