Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/pseries: PAPR system parameter API

Introduce a set of APIs for retrieving and updating PAPR system
parameters. This encapsulates the toil of temporary RTAS work area
management, RTAS function call retries, and translation of RTAS call
statuses to conventional error values.

There are several places in the kernel that already retrieve system
parameters by calling the RTAS ibm,get-system-parameter function
directly. These will be converted to papr_sysparm_get() in changes to
follow.

As for updating system parameters, current practice is to use
sys_rtas() from user space; there are no in-kernel users of the RTAS
ibm,set-system-parameter function. However this will become deprecated
in time because it is not compatible with lockdown.

The papr_sysparm_* APIs will form the common basis for in-kernel
and user space access to system parameters. The code to expose the
set/get capabilities to user space will follow.

Signed-off-by: Nathan Lynch <nathanl@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20230125-b4-powerpc-rtas-queue-v3-14-26929c8cce78@linux.ibm.com

authored by

Nathan Lynch and committed by
Michael Ellerman
419e27f3 e27e1423

+190 -1
+38
arch/powerpc/include/asm/papr-sysparm.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + #ifndef _ASM_POWERPC_PAPR_SYSPARM_H 3 + #define _ASM_POWERPC_PAPR_SYSPARM_H 4 + 5 + typedef struct { 6 + const u32 token; 7 + } papr_sysparm_t; 8 + 9 + #define mk_papr_sysparm(x_) ((papr_sysparm_t){ .token = x_, }) 10 + 11 + /* 12 + * Derived from the "Defined Parameters" table in PAPR 7.3.16 System 13 + * Parameters Option. Where the spec says "characteristics", we use 14 + * "attrs" in the symbolic names to keep them from getting too 15 + * unwieldy. 16 + */ 17 + #define PAPR_SYSPARM_SHARED_PROC_LPAR_ATTRS mk_papr_sysparm(20) 18 + #define PAPR_SYSPARM_PROC_MODULE_INFO mk_papr_sysparm(43) 19 + #define PAPR_SYSPARM_COOP_MEM_OVERCOMMIT_ATTRS mk_papr_sysparm(44) 20 + #define PAPR_SYSPARM_TLB_BLOCK_INVALIDATE_ATTRS mk_papr_sysparm(50) 21 + #define PAPR_SYSPARM_LPAR_NAME mk_papr_sysparm(55) 22 + 23 + enum { 24 + PAPR_SYSPARM_MAX_INPUT = 1024, 25 + PAPR_SYSPARM_MAX_OUTPUT = 4000, 26 + }; 27 + 28 + struct papr_sysparm_buf { 29 + __be16 len; 30 + char val[PAPR_SYSPARM_MAX_OUTPUT]; 31 + }; 32 + 33 + struct papr_sysparm_buf *papr_sysparm_buf_alloc(void); 34 + void papr_sysparm_buf_free(struct papr_sysparm_buf *buf); 35 + int papr_sysparm_set(papr_sysparm_t param, const struct papr_sysparm_buf *buf); 36 + int papr_sysparm_get(papr_sysparm_t param, struct papr_sysparm_buf *buf); 37 + 38 + #endif /* _ASM_POWERPC_PAPR_SYSPARM_H */
+1 -1
arch/powerpc/platforms/pseries/Makefile
··· 3 3 ccflags-$(CONFIG_PPC_PSERIES_DEBUG) += -DDEBUG 4 4 5 5 obj-y := lpar.o hvCall.o nvram.o reconfig.o \ 6 - of_helpers.o rtas-work-area.o \ 6 + of_helpers.o rtas-work-area.o papr-sysparm.o \ 7 7 setup.o iommu.o event_sources.o ras.o \ 8 8 firmware.o power.o dlpar.o mobility.o rng.o \ 9 9 pci.o pci_dlpar.o eeh_pseries.o msi.o \
+151
arch/powerpc/platforms/pseries/papr-sysparm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #define pr_fmt(fmt) "papr-sysparm: " fmt 4 + 5 + #include <linux/bug.h> 6 + #include <linux/init.h> 7 + #include <linux/kernel.h> 8 + #include <linux/printk.h> 9 + #include <linux/slab.h> 10 + #include <asm/rtas.h> 11 + #include <asm/papr-sysparm.h> 12 + #include <asm/rtas-work-area.h> 13 + 14 + struct papr_sysparm_buf *papr_sysparm_buf_alloc(void) 15 + { 16 + struct papr_sysparm_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL); 17 + 18 + return buf; 19 + } 20 + 21 + void papr_sysparm_buf_free(struct papr_sysparm_buf *buf) 22 + { 23 + kfree(buf); 24 + } 25 + 26 + /** 27 + * papr_sysparm_get() - Retrieve the value of a PAPR system parameter. 28 + * @param: PAPR system parameter token as described in 29 + * 7.3.16 "System Parameters Option". 30 + * @buf: A &struct papr_sysparm_buf as returned from papr_sysparm_buf_alloc(). 31 + * 32 + * Place the result of querying the specified parameter, if available, 33 + * in @buf. The result includes a be16 length header followed by the 34 + * value, which may be a string or binary data. See &struct papr_sysparm_buf. 35 + * 36 + * Since there is at least one parameter (60, OS Service Entitlement 37 + * Status) where the results depend on the incoming contents of the 38 + * work area, the caller-supplied buffer is copied unmodified into the 39 + * work area before calling ibm,get-system-parameter. 40 + * 41 + * A defined parameter may not be implemented on a given system, and 42 + * some implemented parameters may not be available to all partitions 43 + * on a system. A parameter's disposition may change at any time due 44 + * to system configuration changes or partition migration. 45 + * 46 + * Context: This function may sleep. 47 + * 48 + * Return: 0 on success, -errno otherwise. @buf is unmodified on error. 49 + */ 50 + 51 + int papr_sysparm_get(papr_sysparm_t param, struct papr_sysparm_buf *buf) 52 + { 53 + const s32 token = rtas_token("ibm,get-system-parameter"); 54 + struct rtas_work_area *work_area; 55 + s32 fwrc; 56 + int ret; 57 + 58 + might_sleep(); 59 + 60 + if (WARN_ON(!buf)) 61 + return -EFAULT; 62 + 63 + if (token == RTAS_UNKNOWN_SERVICE) 64 + return -ENOENT; 65 + 66 + work_area = rtas_work_area_alloc(sizeof(*buf)); 67 + 68 + memcpy(rtas_work_area_raw_buf(work_area), buf, sizeof(*buf)); 69 + 70 + do { 71 + fwrc = rtas_call(token, 3, 1, NULL, param.token, 72 + rtas_work_area_phys(work_area), 73 + rtas_work_area_size(work_area)); 74 + } while (rtas_busy_delay(fwrc)); 75 + 76 + switch (fwrc) { 77 + case 0: 78 + ret = 0; 79 + memcpy(buf, rtas_work_area_raw_buf(work_area), sizeof(*buf)); 80 + break; 81 + case -3: /* parameter not implemented */ 82 + ret = -EOPNOTSUPP; 83 + break; 84 + case -9002: /* this partition not authorized to retrieve this parameter */ 85 + ret = -EPERM; 86 + break; 87 + case -9999: /* "parameter error" e.g. the buffer is too small */ 88 + ret = -EINVAL; 89 + break; 90 + default: 91 + pr_err("unexpected ibm,get-system-parameter result %d\n", fwrc); 92 + fallthrough; 93 + case -1: /* Hardware/platform error */ 94 + ret = -EIO; 95 + break; 96 + } 97 + 98 + rtas_work_area_free(work_area); 99 + 100 + return ret; 101 + } 102 + 103 + int papr_sysparm_set(papr_sysparm_t param, const struct papr_sysparm_buf *buf) 104 + { 105 + const s32 token = rtas_token("ibm,set-system-parameter"); 106 + struct rtas_work_area *work_area; 107 + s32 fwrc; 108 + int ret; 109 + 110 + might_sleep(); 111 + 112 + if (WARN_ON(!buf)) 113 + return -EFAULT; 114 + 115 + if (token == RTAS_UNKNOWN_SERVICE) 116 + return -ENOENT; 117 + 118 + work_area = rtas_work_area_alloc(sizeof(*buf)); 119 + 120 + memcpy(rtas_work_area_raw_buf(work_area), buf, sizeof(*buf)); 121 + 122 + do { 123 + fwrc = rtas_call(token, 2, 1, NULL, param.token, 124 + rtas_work_area_phys(work_area)); 125 + } while (rtas_busy_delay(fwrc)); 126 + 127 + switch (fwrc) { 128 + case 0: 129 + ret = 0; 130 + break; 131 + case -3: /* parameter not supported */ 132 + ret = -EOPNOTSUPP; 133 + break; 134 + case -9002: /* this partition not authorized to modify this parameter */ 135 + ret = -EPERM; 136 + break; 137 + case -9999: /* "parameter error" e.g. invalid input data */ 138 + ret = -EINVAL; 139 + break; 140 + default: 141 + pr_err("unexpected ibm,set-system-parameter result %d\n", fwrc); 142 + fallthrough; 143 + case -1: /* Hardware/platform error */ 144 + ret = -EIO; 145 + break; 146 + } 147 + 148 + rtas_work_area_free(work_area); 149 + 150 + return ret; 151 + }