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

powerpc/pseries: Define common functions for RTAS sequence calls

The RTAS call can be normal where retrieves the data form the
hypervisor once or sequence based RTAS call which has to
issue multiple times until the complete data is obtained. For
some of these sequence RTAS calls, the OS should not interleave
calls with different input until the sequence is completed.
The data is collected for each call and copy to the buffer
for the entire sequence during ioctl() handle and then expose
this buffer to the user space with read() handle.

One such sequence RTAS call is ibm,get-vpd and its support is
already included in the current code. To add the similar support
for other sequence based calls, move the common functions in to
separate file and update papr_rtas_sequence struct with the
following callbacks so that RTAS call specific code will be
defined and executed to complete the sequence.

struct papr_rtas_sequence {
int error;
void params;
void (*begin) (struct papr_rtas_sequence *);
void (*end) (struct papr_rtas_sequence *);
const char * (*work) (struct papr_rtas_sequence *, size_t *);
};

params: Input parameters used to pass for RTAS call.
Begin: RTAS call specific function to initialize data
including work area allocation.
End: RTAS call specific function to free up resources
(free work area) after the sequence is completed.
Work: The actual RTAS call specific function which collects
the data from the hypervisor.

Signed-off-by: Haren Myneni <haren@linux.ibm.com>
Tested-by: Sathvika Vasireddy <sv@linux.ibm.com>
Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com>
Link: https://patch.msgid.link/20250416225743.596462-2-haren@linux.ibm.com

authored by

Haren Myneni and committed by
Madhavan Srinivasan
ecc45d4f 6ad77515

+418 -308
+1 -1
arch/powerpc/platforms/pseries/Makefile
··· 3 3 4 4 obj-y := lpar.o hvCall.o nvram.o reconfig.o \ 5 5 of_helpers.o rtas-work-area.o papr-sysparm.o \ 6 - papr-vpd.o \ 6 + papr-rtas-common.o papr-vpd.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 \
+311
arch/powerpc/platforms/pseries/papr-rtas-common.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + 3 + #define pr_fmt(fmt) "papr-common: " fmt 4 + 5 + #include <linux/types.h> 6 + #include <linux/kernel.h> 7 + #include <linux/signal.h> 8 + #include <linux/slab.h> 9 + #include <linux/file.h> 10 + #include <linux/fs.h> 11 + #include <linux/anon_inodes.h> 12 + #include <linux/sched/signal.h> 13 + #include "papr-rtas-common.h" 14 + 15 + /* 16 + * Sequence based RTAS HCALL has to issue multiple times to retrieve 17 + * complete data from the hypervisor. For some of these RTAS calls, 18 + * the OS should not interleave calls with different input until the 19 + * sequence is completed. So data is collected for these calls during 20 + * ioctl handle and export to user space with read() handle. 21 + * This file provides common functions needed for such sequence based 22 + * RTAS calls Ex: ibm,get-vpd and ibm,get-indices. 23 + */ 24 + 25 + bool papr_rtas_blob_has_data(const struct papr_rtas_blob *blob) 26 + { 27 + return blob->data && blob->len; 28 + } 29 + 30 + void papr_rtas_blob_free(const struct papr_rtas_blob *blob) 31 + { 32 + if (blob) { 33 + kvfree(blob->data); 34 + kfree(blob); 35 + } 36 + } 37 + 38 + /** 39 + * papr_rtas_blob_extend() - Append data to a &struct papr_rtas_blob. 40 + * @blob: The blob to extend. 41 + * @data: The new data to append to @blob. 42 + * @len: The length of @data. 43 + * 44 + * Context: May sleep. 45 + * Return: -ENOMEM on allocation failure, 0 otherwise. 46 + */ 47 + static int papr_rtas_blob_extend(struct papr_rtas_blob *blob, 48 + const char *data, size_t len) 49 + { 50 + const size_t new_len = blob->len + len; 51 + const size_t old_len = blob->len; 52 + const char *old_ptr = blob->data; 53 + char *new_ptr; 54 + 55 + new_ptr = kvrealloc(old_ptr, new_len, GFP_KERNEL_ACCOUNT); 56 + if (!new_ptr) 57 + return -ENOMEM; 58 + 59 + memcpy(&new_ptr[old_len], data, len); 60 + blob->data = new_ptr; 61 + blob->len = new_len; 62 + return 0; 63 + } 64 + 65 + /** 66 + * papr_rtas_blob_generate() - Construct a new &struct papr_rtas_blob. 67 + * @seq: work function of the caller that is called to obtain 68 + * data with the caller RTAS call. 69 + * 70 + * The @work callback is invoked until it returns NULL. @seq is 71 + * passed to @work in its first argument on each call. When 72 + * @work returns data, it should store the data length in its 73 + * second argument. 74 + * 75 + * Context: May sleep. 76 + * Return: A completely populated &struct papr_rtas_blob, or NULL on error. 77 + */ 78 + static const struct papr_rtas_blob * 79 + papr_rtas_blob_generate(struct papr_rtas_sequence *seq) 80 + { 81 + struct papr_rtas_blob *blob; 82 + const char *buf; 83 + size_t len; 84 + int err = 0; 85 + 86 + blob = kzalloc(sizeof(*blob), GFP_KERNEL_ACCOUNT); 87 + if (!blob) 88 + return NULL; 89 + 90 + if (!seq->work) 91 + return ERR_PTR(-EINVAL); 92 + 93 + 94 + while (err == 0 && (buf = seq->work(seq, &len))) 95 + err = papr_rtas_blob_extend(blob, buf, len); 96 + 97 + if (err != 0 || !papr_rtas_blob_has_data(blob)) 98 + goto free_blob; 99 + 100 + return blob; 101 + free_blob: 102 + papr_rtas_blob_free(blob); 103 + return NULL; 104 + } 105 + 106 + int papr_rtas_sequence_set_err(struct papr_rtas_sequence *seq, int err) 107 + { 108 + /* Preserve the first error recorded. */ 109 + if (seq->error == 0) 110 + seq->error = err; 111 + 112 + return seq->error; 113 + } 114 + 115 + /* 116 + * Higher-level retrieval code below. These functions use the 117 + * papr_rtas_blob_* and sequence_* APIs defined above to create fd-based 118 + * handles for consumption by user space. 119 + */ 120 + 121 + /** 122 + * papr_rtas_run_sequence() - Run a single retrieval sequence. 123 + * @seq: Functions of the caller to complete the sequence 124 + * 125 + * Context: May sleep. Holds a mutex and an RTAS work area for its 126 + * duration. Typically performs multiple sleepable slab 127 + * allocations. 128 + * 129 + * Return: A populated &struct papr_rtas_blob on success. Encoded error 130 + * pointer otherwise. 131 + */ 132 + static const struct papr_rtas_blob *papr_rtas_run_sequence(struct papr_rtas_sequence *seq) 133 + { 134 + const struct papr_rtas_blob *blob; 135 + 136 + if (seq->begin) 137 + seq->begin(seq); 138 + 139 + blob = papr_rtas_blob_generate(seq); 140 + if (!blob) 141 + papr_rtas_sequence_set_err(seq, -ENOMEM); 142 + 143 + if (seq->end) 144 + seq->end(seq); 145 + 146 + 147 + if (seq->error) { 148 + papr_rtas_blob_free(blob); 149 + return ERR_PTR(seq->error); 150 + } 151 + 152 + return blob; 153 + } 154 + 155 + /** 156 + * papr_rtas_retrieve() - Return the data blob that is exposed to 157 + * user space. 158 + * @seq: RTAS call specific functions to be invoked until the 159 + * sequence is completed. 160 + * 161 + * Run sequences against @param until a blob is successfully 162 + * instantiated, or a hard error is encountered, or a fatal signal is 163 + * pending. 164 + * 165 + * Context: May sleep. 166 + * Return: A fully populated data blob when successful. Encoded error 167 + * pointer otherwise. 168 + */ 169 + const struct papr_rtas_blob *papr_rtas_retrieve(struct papr_rtas_sequence *seq) 170 + { 171 + const struct papr_rtas_blob *blob; 172 + 173 + /* 174 + * EAGAIN means the sequence returns error with a -4 (data 175 + * changed and need to start the sequence) status from RTAS calls 176 + * and we should attempt a new sequence. PAPR+ (v2.13 R1–7.3.20–5 177 + * - ibm,get-vpd, R1–7.3.17–6 - ibm,get-indices) indicates that 178 + * this should be a transient condition, not something that 179 + * happens continuously. But we'll stop trying on a fatal signal. 180 + */ 181 + do { 182 + blob = papr_rtas_run_sequence(seq); 183 + if (!IS_ERR(blob)) /* Success. */ 184 + break; 185 + if (PTR_ERR(blob) != -EAGAIN) /* Hard error. */ 186 + break; 187 + cond_resched(); 188 + } while (!fatal_signal_pending(current)); 189 + 190 + return blob; 191 + } 192 + 193 + /** 194 + * papr_rtas_setup_file_interface - Complete the sequence and obtain 195 + * the data and export to user space with fd-based handles. Then the 196 + * user spave gets the data with read() handle. 197 + * @seq: RTAS call specific functions to get the data. 198 + * @fops: RTAS call specific file operations such as read(). 199 + * @name: RTAS call specific char device node. 200 + * 201 + * Return: FD handle for consumption by user space 202 + */ 203 + long papr_rtas_setup_file_interface(struct papr_rtas_sequence *seq, 204 + const struct file_operations *fops, 205 + char *name) 206 + { 207 + const struct papr_rtas_blob *blob; 208 + struct file *file; 209 + long ret; 210 + int fd; 211 + 212 + blob = papr_rtas_retrieve(seq); 213 + if (IS_ERR(blob)) 214 + return PTR_ERR(blob); 215 + 216 + fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC); 217 + if (fd < 0) { 218 + ret = fd; 219 + goto free_blob; 220 + } 221 + 222 + file = anon_inode_getfile_fmode(name, fops, (void *)blob, 223 + O_RDONLY, FMODE_LSEEK | FMODE_PREAD); 224 + if (IS_ERR(file)) { 225 + ret = PTR_ERR(file); 226 + goto put_fd; 227 + } 228 + 229 + fd_install(fd, file); 230 + return fd; 231 + 232 + put_fd: 233 + put_unused_fd(fd); 234 + free_blob: 235 + papr_rtas_blob_free(blob); 236 + return ret; 237 + } 238 + 239 + /* 240 + * papr_rtas_sequence_should_stop() - Determine whether RTAS retrieval 241 + * sequence should continue. 242 + * 243 + * Examines the sequence error state and outputs of the last call to 244 + * the specific RTAS to determine whether the sequence in progress 245 + * should continue or stop. 246 + * 247 + * Return: True if the sequence has encountered an error or if all data 248 + * for this sequence has been retrieved. False otherwise. 249 + */ 250 + bool papr_rtas_sequence_should_stop(const struct papr_rtas_sequence *seq, 251 + s32 status, bool init_state) 252 + { 253 + bool done; 254 + 255 + if (seq->error) 256 + return true; 257 + 258 + switch (status) { 259 + case RTAS_SEQ_COMPLETE: 260 + if (init_state) 261 + done = false; /* Initial state. */ 262 + else 263 + done = true; /* All data consumed. */ 264 + break; 265 + case RTAS_SEQ_MORE_DATA: 266 + done = false; /* More data available. */ 267 + break; 268 + default: 269 + done = true; /* Error encountered. */ 270 + break; 271 + } 272 + 273 + return done; 274 + } 275 + 276 + /* 277 + * User space read to retrieve data for the corresponding RTAS call. 278 + * papr_rtas_blob is filled with the data using the corresponding RTAS 279 + * call sequence API. 280 + */ 281 + ssize_t papr_rtas_common_handle_read(struct file *file, 282 + char __user *buf, size_t size, loff_t *off) 283 + { 284 + const struct papr_rtas_blob *blob = file->private_data; 285 + 286 + /* We should not instantiate a handle without any data attached. */ 287 + if (!papr_rtas_blob_has_data(blob)) { 288 + pr_err_once("handle without data\n"); 289 + return -EIO; 290 + } 291 + 292 + return simple_read_from_buffer(buf, size, off, blob->data, blob->len); 293 + } 294 + 295 + int papr_rtas_common_handle_release(struct inode *inode, 296 + struct file *file) 297 + { 298 + const struct papr_rtas_blob *blob = file->private_data; 299 + 300 + papr_rtas_blob_free(blob); 301 + 302 + return 0; 303 + } 304 + 305 + loff_t papr_rtas_common_handle_seek(struct file *file, loff_t off, 306 + int whence) 307 + { 308 + const struct papr_rtas_blob *blob = file->private_data; 309 + 310 + return fixed_size_llseek(file, off, whence, blob->len); 311 + }
+61
arch/powerpc/platforms/pseries/papr-rtas-common.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + #ifndef _ASM_POWERPC_PAPR_RTAS_COMMON_H 3 + #define _ASM_POWERPC_PAPR_RTAS_COMMON_H 4 + 5 + #include <linux/types.h> 6 + 7 + /* 8 + * Return codes for sequence based RTAS calls. 9 + * Not listed under PAPR+ v2.13 7.2.8: "Return Codes". 10 + * But defined in the specific section of each RTAS call. 11 + */ 12 + #define RTAS_SEQ_COMPLETE 0 /* All data has been retrieved. */ 13 + #define RTAS_SEQ_MORE_DATA 1 /* More data is available */ 14 + #define RTAS_SEQ_START_OVER -4 /* Data changed, restart call sequence. */ 15 + 16 + /* 17 + * Internal "blob" APIs for accumulating RTAS call results into 18 + * an immutable buffer to be attached to a file descriptor. 19 + */ 20 + struct papr_rtas_blob { 21 + const char *data; 22 + size_t len; 23 + }; 24 + 25 + /** 26 + * struct papr_sequence - State for managing a sequence of RTAS calls. 27 + * @error: Shall be zero as long as the sequence has not encountered an error, 28 + * -ve errno otherwise. Use papr_rtas_sequence_set_err() to update. 29 + * @params: Parameter block to pass to rtas_*() calls. 30 + * @begin: Work area allocation and initialize the needed parameter 31 + * values passed to RTAS call 32 + * @end: Free the allocated work area 33 + * @work: Obtain data with RTAS call and invoke it until the sequence is 34 + * completed. 35 + * 36 + */ 37 + struct papr_rtas_sequence { 38 + int error; 39 + void *params; 40 + void (*begin)(struct papr_rtas_sequence *seq); 41 + void (*end)(struct papr_rtas_sequence *seq); 42 + const char *(*work)(struct papr_rtas_sequence *seq, size_t *len); 43 + }; 44 + 45 + extern bool papr_rtas_blob_has_data(const struct papr_rtas_blob *blob); 46 + extern void papr_rtas_blob_free(const struct papr_rtas_blob *blob); 47 + extern int papr_rtas_sequence_set_err(struct papr_rtas_sequence *seq, 48 + int err); 49 + extern const struct papr_rtas_blob *papr_rtas_retrieve(struct papr_rtas_sequence *seq); 50 + extern long papr_rtas_setup_file_interface(struct papr_rtas_sequence *seq, 51 + const struct file_operations *fops, char *name); 52 + extern bool papr_rtas_sequence_should_stop(const struct papr_rtas_sequence *seq, 53 + s32 status, bool init_state); 54 + extern ssize_t papr_rtas_common_handle_read(struct file *file, 55 + char __user *buf, size_t size, loff_t *off); 56 + extern int papr_rtas_common_handle_release(struct inode *inode, 57 + struct file *file); 58 + extern loff_t papr_rtas_common_handle_seek(struct file *file, loff_t off, 59 + int whence); 60 + #endif /* _ASM_POWERPC_PAPR_RTAS_COMMON_H */ 61 +
+45 -307
arch/powerpc/platforms/pseries/papr-vpd.c
··· 2 2 3 3 #define pr_fmt(fmt) "papr-vpd: " fmt 4 4 5 - #include <linux/anon_inodes.h> 6 5 #include <linux/build_bug.h> 7 6 #include <linux/file.h> 8 7 #include <linux/fs.h> ··· 19 20 #include <asm/rtas-work-area.h> 20 21 #include <asm/rtas.h> 21 22 #include <uapi/asm/papr-vpd.h> 22 - 23 - /* 24 - * Function-specific return values for ibm,get-vpd, derived from PAPR+ 25 - * v2.13 7.3.20 "ibm,get-vpd RTAS Call". 26 - */ 27 - #define RTAS_IBM_GET_VPD_COMPLETE 0 /* All VPD has been retrieved. */ 28 - #define RTAS_IBM_GET_VPD_MORE_DATA 1 /* More VPD is available. */ 29 - #define RTAS_IBM_GET_VPD_START_OVER -4 /* VPD changed, restart call sequence. */ 23 + #include "papr-rtas-common.h" 30 24 31 25 /** 32 26 * struct rtas_ibm_get_vpd_params - Parameters (in and out) for ibm,get-vpd. ··· 83 91 case RTAS_INVALID_PARAMETER: 84 92 ret = -EINVAL; 85 93 break; 86 - case RTAS_IBM_GET_VPD_START_OVER: 94 + case RTAS_SEQ_START_OVER: 87 95 ret = -EAGAIN; 96 + pr_info_ratelimited("VPD changed during retrieval, retrying\n"); 88 97 break; 89 - case RTAS_IBM_GET_VPD_MORE_DATA: 98 + case RTAS_SEQ_MORE_DATA: 90 99 params->sequence = rets[0]; 91 100 fallthrough; 92 - case RTAS_IBM_GET_VPD_COMPLETE: 101 + case RTAS_SEQ_COMPLETE: 93 102 params->written = rets[1]; 94 103 /* 95 104 * Kernel or firmware bug, do not continue. ··· 112 119 } 113 120 114 121 /* 115 - * Internal VPD "blob" APIs for accumulating ibm,get-vpd results into 116 - * an immutable buffer to be attached to a file descriptor. 117 - */ 118 - struct vpd_blob { 119 - const char *data; 120 - size_t len; 121 - }; 122 - 123 - static bool vpd_blob_has_data(const struct vpd_blob *blob) 124 - { 125 - return blob->data && blob->len; 126 - } 127 - 128 - static void vpd_blob_free(const struct vpd_blob *blob) 129 - { 130 - if (blob) { 131 - kvfree(blob->data); 132 - kfree(blob); 133 - } 134 - } 135 - 136 - /** 137 - * vpd_blob_extend() - Append data to a &struct vpd_blob. 138 - * @blob: The blob to extend. 139 - * @data: The new data to append to @blob. 140 - * @len: The length of @data. 141 - * 142 - * Context: May sleep. 143 - * Return: -ENOMEM on allocation failure, 0 otherwise. 144 - */ 145 - static int vpd_blob_extend(struct vpd_blob *blob, const char *data, size_t len) 146 - { 147 - const size_t new_len = blob->len + len; 148 - const size_t old_len = blob->len; 149 - const char *old_ptr = blob->data; 150 - char *new_ptr; 151 - 152 - new_ptr = kvrealloc(old_ptr, new_len, GFP_KERNEL_ACCOUNT); 153 - if (!new_ptr) 154 - return -ENOMEM; 155 - 156 - memcpy(&new_ptr[old_len], data, len); 157 - blob->data = new_ptr; 158 - blob->len = new_len; 159 - return 0; 160 - } 161 - 162 - /** 163 - * vpd_blob_generate() - Construct a new &struct vpd_blob. 164 - * @generator: Function that supplies the blob data. 165 - * @arg: Context pointer supplied by caller, passed to @generator. 166 - * 167 - * The @generator callback is invoked until it returns NULL. @arg is 168 - * passed to @generator in its first argument on each call. When 169 - * @generator returns data, it should store the data length in its 170 - * second argument. 171 - * 172 - * Context: May sleep. 173 - * Return: A completely populated &struct vpd_blob, or NULL on error. 174 - */ 175 - static const struct vpd_blob * 176 - vpd_blob_generate(const char * (*generator)(void *, size_t *), void *arg) 177 - { 178 - struct vpd_blob *blob; 179 - const char *buf; 180 - size_t len; 181 - int err = 0; 182 - 183 - blob = kzalloc(sizeof(*blob), GFP_KERNEL_ACCOUNT); 184 - if (!blob) 185 - return NULL; 186 - 187 - while (err == 0 && (buf = generator(arg, &len))) 188 - err = vpd_blob_extend(blob, buf, len); 189 - 190 - if (err != 0 || !vpd_blob_has_data(blob)) 191 - goto free_blob; 192 - 193 - return blob; 194 - free_blob: 195 - vpd_blob_free(blob); 196 - return NULL; 197 - } 198 - 199 - /* 200 122 * Internal VPD sequence APIs. A VPD sequence is a series of calls to 201 123 * ibm,get-vpd for a given location code. The sequence ends when an 202 124 * error is encountered or all VPD for the location code has been ··· 119 211 */ 120 212 121 213 /** 122 - * struct vpd_sequence - State for managing a VPD sequence. 123 - * @error: Shall be zero as long as the sequence has not encountered an error, 124 - * -ve errno otherwise. Use vpd_sequence_set_err() to update this. 125 - * @params: Parameter block to pass to rtas_ibm_get_vpd(). 126 - */ 127 - struct vpd_sequence { 128 - int error; 129 - struct rtas_ibm_get_vpd_params params; 130 - }; 131 - 132 - /** 133 214 * vpd_sequence_begin() - Begin a VPD retrieval sequence. 134 - * @seq: Uninitialized sequence state. 135 - * @loc_code: Location code that defines the scope of the VPD to return. 136 - * 137 - * Initializes @seq with the resources necessary to carry out a VPD 138 - * sequence. Callers must pass @seq to vpd_sequence_end() regardless 139 - * of whether the sequence succeeds. 215 + * @seq: vpd call parameters from sequence struct 140 216 * 141 217 * Context: May sleep. 142 218 */ 143 - static void vpd_sequence_begin(struct vpd_sequence *seq, 144 - const struct papr_location_code *loc_code) 219 + static void vpd_sequence_begin(struct papr_rtas_sequence *seq) 145 220 { 221 + struct rtas_ibm_get_vpd_params *vpd_params; 146 222 /* 147 223 * Use a static data structure for the location code passed to 148 224 * RTAS to ensure it's in the RMA and avoid a separate work ··· 134 242 */ 135 243 static struct papr_location_code static_loc_code; 136 244 245 + vpd_params = (struct rtas_ibm_get_vpd_params *)seq->params; 137 246 /* 138 247 * We could allocate the work area before acquiring the 139 248 * function lock, but that would allow concurrent requests to ··· 142 249 * allocate the work area under the lock. 143 250 */ 144 251 mutex_lock(&rtas_ibm_get_vpd_lock); 145 - static_loc_code = *loc_code; 146 - *seq = (struct vpd_sequence) { 147 - .params = { 148 - .work_area = rtas_work_area_alloc(SZ_4K), 149 - .loc_code = &static_loc_code, 150 - .sequence = 1, 151 - }, 152 - }; 252 + static_loc_code = *(struct papr_location_code *)vpd_params->loc_code; 253 + vpd_params = (struct rtas_ibm_get_vpd_params *)seq->params; 254 + vpd_params->work_area = rtas_work_area_alloc(SZ_4K); 255 + vpd_params->loc_code = &static_loc_code; 256 + vpd_params->sequence = 1; 257 + vpd_params->status = 0; 153 258 } 154 259 155 260 /** ··· 156 265 * 157 266 * Releases resources obtained by vpd_sequence_begin(). 158 267 */ 159 - static void vpd_sequence_end(struct vpd_sequence *seq) 268 + static void vpd_sequence_end(struct papr_rtas_sequence *seq) 160 269 { 161 - rtas_work_area_free(seq->params.work_area); 270 + struct rtas_ibm_get_vpd_params *vpd_params; 271 + 272 + vpd_params = (struct rtas_ibm_get_vpd_params *)seq->params; 273 + rtas_work_area_free(vpd_params->work_area); 162 274 mutex_unlock(&rtas_ibm_get_vpd_lock); 163 275 } 164 276 165 - /** 166 - * vpd_sequence_should_stop() - Determine whether a VPD retrieval sequence 167 - * should continue. 168 - * @seq: VPD sequence state. 169 - * 170 - * Examines the sequence error state and outputs of the last call to 171 - * ibm,get-vpd to determine whether the sequence in progress should 172 - * continue or stop. 173 - * 174 - * Return: True if the sequence has encountered an error or if all VPD for 175 - * this sequence has been retrieved. False otherwise. 176 - */ 177 - static bool vpd_sequence_should_stop(const struct vpd_sequence *seq) 178 - { 179 - bool done; 180 - 181 - if (seq->error) 182 - return true; 183 - 184 - switch (seq->params.status) { 185 - case 0: 186 - if (seq->params.written == 0) 187 - done = false; /* Initial state. */ 188 - else 189 - done = true; /* All data consumed. */ 190 - break; 191 - case 1: 192 - done = false; /* More data available. */ 193 - break; 194 - default: 195 - done = true; /* Error encountered. */ 196 - break; 197 - } 198 - 199 - return done; 200 - } 201 - 202 - static int vpd_sequence_set_err(struct vpd_sequence *seq, int err) 203 - { 204 - /* Preserve the first error recorded. */ 205 - if (seq->error == 0) 206 - seq->error = err; 207 - 208 - return seq->error; 209 - } 210 - 211 277 /* 212 - * Generator function to be passed to vpd_blob_generate(). 278 + * Generator function to be passed to papr_rtas_blob_generate(). 213 279 */ 214 - static const char *vpd_sequence_fill_work_area(void *arg, size_t *len) 280 + static const char *vpd_sequence_fill_work_area(struct papr_rtas_sequence *seq, 281 + size_t *len) 215 282 { 216 - struct vpd_sequence *seq = arg; 217 - struct rtas_ibm_get_vpd_params *p = &seq->params; 283 + struct rtas_ibm_get_vpd_params *p; 284 + bool init_state; 218 285 219 - if (vpd_sequence_should_stop(seq)) 286 + p = (struct rtas_ibm_get_vpd_params *)seq->params; 287 + init_state = (p->written == 0) ? true : false; 288 + 289 + if (papr_rtas_sequence_should_stop(seq, p->status, init_state)) 220 290 return NULL; 221 - if (vpd_sequence_set_err(seq, rtas_ibm_get_vpd(p))) 291 + if (papr_rtas_sequence_set_err(seq, rtas_ibm_get_vpd(p))) 222 292 return NULL; 223 293 *len = p->written; 224 294 return rtas_work_area_raw_buf(p->work_area); 225 295 } 226 296 227 - /* 228 - * Higher-level VPD retrieval code below. These functions use the 229 - * vpd_blob_* and vpd_sequence_* APIs defined above to create fd-based 230 - * VPD handles for consumption by user space. 231 - */ 232 - 233 - /** 234 - * papr_vpd_run_sequence() - Run a single VPD retrieval sequence. 235 - * @loc_code: Location code that defines the scope of VPD to return. 236 - * 237 - * Context: May sleep. Holds a mutex and an RTAS work area for its 238 - * duration. Typically performs multiple sleepable slab 239 - * allocations. 240 - * 241 - * Return: A populated &struct vpd_blob on success. Encoded error 242 - * pointer otherwise. 243 - */ 244 - static const struct vpd_blob *papr_vpd_run_sequence(const struct papr_location_code *loc_code) 245 - { 246 - const struct vpd_blob *blob; 247 - struct vpd_sequence seq; 248 - 249 - vpd_sequence_begin(&seq, loc_code); 250 - blob = vpd_blob_generate(vpd_sequence_fill_work_area, &seq); 251 - if (!blob) 252 - vpd_sequence_set_err(&seq, -ENOMEM); 253 - vpd_sequence_end(&seq); 254 - 255 - if (seq.error) { 256 - vpd_blob_free(blob); 257 - return ERR_PTR(seq.error); 258 - } 259 - 260 - return blob; 261 - } 262 - 263 - /** 264 - * papr_vpd_retrieve() - Return the VPD for a location code. 265 - * @loc_code: Location code that defines the scope of VPD to return. 266 - * 267 - * Run VPD sequences against @loc_code until a blob is successfully 268 - * instantiated, or a hard error is encountered, or a fatal signal is 269 - * pending. 270 - * 271 - * Context: May sleep. 272 - * Return: A fully populated VPD blob when successful. Encoded error 273 - * pointer otherwise. 274 - */ 275 - static const struct vpd_blob *papr_vpd_retrieve(const struct papr_location_code *loc_code) 276 - { 277 - const struct vpd_blob *blob; 278 - 279 - /* 280 - * EAGAIN means the sequence errored with a -4 (VPD changed) 281 - * status from ibm,get-vpd, and we should attempt a new 282 - * sequence. PAPR+ v2.13 R1–7.3.20–5 indicates that this 283 - * should be a transient condition, not something that happens 284 - * continuously. But we'll stop trying on a fatal signal. 285 - */ 286 - do { 287 - blob = papr_vpd_run_sequence(loc_code); 288 - if (!IS_ERR(blob)) /* Success. */ 289 - break; 290 - if (PTR_ERR(blob) != -EAGAIN) /* Hard error. */ 291 - break; 292 - pr_info_ratelimited("VPD changed during retrieval, retrying\n"); 293 - cond_resched(); 294 - } while (!fatal_signal_pending(current)); 295 - 296 - return blob; 297 - } 298 - 299 - static ssize_t papr_vpd_handle_read(struct file *file, char __user *buf, size_t size, loff_t *off) 300 - { 301 - const struct vpd_blob *blob = file->private_data; 302 - 303 - /* bug: we should not instantiate a handle without any data attached. */ 304 - if (!vpd_blob_has_data(blob)) { 305 - pr_err_once("handle without data\n"); 306 - return -EIO; 307 - } 308 - 309 - return simple_read_from_buffer(buf, size, off, blob->data, blob->len); 310 - } 311 - 312 - static int papr_vpd_handle_release(struct inode *inode, struct file *file) 313 - { 314 - const struct vpd_blob *blob = file->private_data; 315 - 316 - vpd_blob_free(blob); 317 - 318 - return 0; 319 - } 320 - 321 - static loff_t papr_vpd_handle_seek(struct file *file, loff_t off, int whence) 322 - { 323 - const struct vpd_blob *blob = file->private_data; 324 - 325 - return fixed_size_llseek(file, off, whence, blob->len); 326 - } 327 - 328 - 329 297 static const struct file_operations papr_vpd_handle_ops = { 330 - .read = papr_vpd_handle_read, 331 - .llseek = papr_vpd_handle_seek, 332 - .release = papr_vpd_handle_release, 298 + .read = papr_rtas_common_handle_read, 299 + .llseek = papr_rtas_common_handle_seek, 300 + .release = papr_rtas_common_handle_release, 333 301 }; 334 302 335 303 /** ··· 210 460 */ 211 461 static long papr_vpd_create_handle(struct papr_location_code __user *ulc) 212 462 { 463 + struct rtas_ibm_get_vpd_params vpd_params = {}; 464 + struct papr_rtas_sequence seq = {}; 213 465 struct papr_location_code klc; 214 - const struct vpd_blob *blob; 215 - struct file *file; 216 - long err; 217 466 int fd; 218 467 219 468 if (copy_from_user(&klc, ulc, sizeof(klc))) ··· 221 472 if (!string_is_terminated(klc.str, ARRAY_SIZE(klc.str))) 222 473 return -EINVAL; 223 474 224 - blob = papr_vpd_retrieve(&klc); 225 - if (IS_ERR(blob)) 226 - return PTR_ERR(blob); 475 + seq = (struct papr_rtas_sequence) { 476 + .begin = vpd_sequence_begin, 477 + .end = vpd_sequence_end, 478 + .work = vpd_sequence_fill_work_area, 479 + }; 227 480 228 - fd = get_unused_fd_flags(O_RDONLY | O_CLOEXEC); 229 - if (fd < 0) { 230 - err = fd; 231 - goto free_blob; 232 - } 481 + vpd_params.loc_code = &klc; 482 + seq.params = (void *)&vpd_params; 233 483 234 - file = anon_inode_getfile_fmode("[papr-vpd]", &papr_vpd_handle_ops, 235 - (void *)blob, O_RDONLY, 236 - FMODE_LSEEK | FMODE_PREAD); 237 - if (IS_ERR(file)) { 238 - err = PTR_ERR(file); 239 - goto put_fd; 240 - } 241 - fd_install(fd, file); 484 + fd = papr_rtas_setup_file_interface(&seq, &papr_vpd_handle_ops, 485 + "[papr-vpd]"); 486 + 242 487 return fd; 243 - put_fd: 244 - put_unused_fd(fd); 245 - free_blob: 246 - vpd_blob_free(blob); 247 - return err; 248 488 } 249 489 250 490 /*