1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #define pr_fmt(fmt) "papr-vpd: " fmt 4 5 #include <linux/build_bug.h> 6 #include <linux/file.h> 7 #include <linux/fs.h> 8 #include <linux/init.h> 9 #include <linux/lockdep.h> 10 #include <linux/kernel.h> 11 #include <linux/miscdevice.h> 12 #include <linux/signal.h> 13 #include <linux/slab.h> 14 #include <linux/string.h> 15 #include <linux/string_helpers.h> 16 #include <linux/uaccess.h> 17 #include <asm/machdep.h> 18 #include <asm/papr-vpd.h> 19 #include <asm/rtas-work-area.h> 20 #include <asm/rtas.h> 21 #include <uapi/asm/papr-vpd.h> 22 #include "papr-rtas-common.h" 23 24 /** 25 * struct rtas_ibm_get_vpd_params - Parameters (in and out) for ibm,get-vpd. 26 * @loc_code: In: Caller-provided location code buffer. Must be RTAS-addressable. 27 * @work_area: In: Caller-provided work area buffer for results. 28 * @sequence: In: Sequence number. Out: Next sequence number. 29 * @written: Out: Bytes written by ibm,get-vpd to @work_area. 30 * @status: Out: RTAS call status. 31 */ 32 struct rtas_ibm_get_vpd_params { 33 const struct papr_location_code *loc_code; 34 struct rtas_work_area *work_area; 35 u32 sequence; 36 u32 written; 37 s32 status; 38 }; 39 40 /** 41 * rtas_ibm_get_vpd() - Call ibm,get-vpd to fill a work area buffer. 42 * @params: See &struct rtas_ibm_get_vpd_params. 43 * 44 * Calls ibm,get-vpd until it errors or successfully deposits data 45 * into the supplied work area. Handles RTAS retry statuses. Maps RTAS 46 * error statuses to reasonable errno values. 47 * 48 * The caller is expected to invoke rtas_ibm_get_vpd() multiple times 49 * to retrieve all the VPD for the provided location code. Only one 50 * sequence should be in progress at any time; starting a new sequence 51 * will disrupt any sequence already in progress. Serialization of VPD 52 * retrieval sequences is the responsibility of the caller. 53 * 54 * The caller should inspect @params.status to determine whether more 55 * calls are needed to complete the sequence. 56 * 57 * Context: May sleep. 58 * Return: -ve on error, 0 otherwise. 59 */ 60 static int rtas_ibm_get_vpd(struct rtas_ibm_get_vpd_params *params) 61 { 62 const struct papr_location_code *loc_code = params->loc_code; 63 struct rtas_work_area *work_area = params->work_area; 64 u32 rets[2]; 65 s32 fwrc; 66 int ret; 67 68 lockdep_assert_held(&rtas_ibm_get_vpd_lock); 69 70 do { 71 fwrc = rtas_call(rtas_function_token(RTAS_FN_IBM_GET_VPD), 4, 3, 72 rets, 73 __pa(loc_code), 74 rtas_work_area_phys(work_area), 75 rtas_work_area_size(work_area), 76 params->sequence); 77 } while (rtas_busy_delay(fwrc)); 78 79 switch (fwrc) { 80 case RTAS_HARDWARE_ERROR: 81 ret = -EIO; 82 break; 83 case RTAS_INVALID_PARAMETER: 84 ret = -EINVAL; 85 break; 86 case RTAS_SEQ_START_OVER: 87 ret = -EAGAIN; 88 pr_info_ratelimited("VPD changed during retrieval, retrying\n"); 89 break; 90 case RTAS_SEQ_MORE_DATA: 91 params->sequence = rets[0]; 92 fallthrough; 93 case RTAS_SEQ_COMPLETE: 94 params->written = rets[1]; 95 /* 96 * Kernel or firmware bug, do not continue. 97 */ 98 if (WARN(params->written > rtas_work_area_size(work_area), 99 "possible write beyond end of work area")) 100 ret = -EFAULT; 101 else 102 ret = 0; 103 break; 104 default: 105 ret = -EIO; 106 pr_err_ratelimited("unexpected ibm,get-vpd status %d\n", fwrc); 107 break; 108 } 109 110 params->status = fwrc; 111 return ret; 112 } 113 114 /* 115 * Internal VPD sequence APIs. A VPD sequence is a series of calls to 116 * ibm,get-vpd for a given location code. The sequence ends when an 117 * error is encountered or all VPD for the location code has been 118 * returned. 119 */ 120 121 /** 122 * vpd_sequence_begin() - Begin a VPD retrieval sequence. 123 * @seq: vpd call parameters from sequence struct 124 * 125 * Context: May sleep. 126 */ 127 static void vpd_sequence_begin(struct papr_rtas_sequence *seq) 128 { 129 struct rtas_ibm_get_vpd_params *vpd_params; 130 /* 131 * Use a static data structure for the location code passed to 132 * RTAS to ensure it's in the RMA and avoid a separate work 133 * area allocation. Guarded by the function lock. 134 */ 135 static struct papr_location_code static_loc_code; 136 137 vpd_params = (struct rtas_ibm_get_vpd_params *)seq->params; 138 /* 139 * We could allocate the work area before acquiring the 140 * function lock, but that would allow concurrent requests to 141 * exhaust the limited work area pool for no benefit. So 142 * allocate the work area under the lock. 143 */ 144 mutex_lock(&rtas_ibm_get_vpd_lock); 145 static_loc_code = *(struct papr_location_code *)vpd_params->loc_code; 146 vpd_params = (struct rtas_ibm_get_vpd_params *)seq->params; 147 vpd_params->work_area = rtas_work_area_alloc(SZ_4K); 148 vpd_params->loc_code = &static_loc_code; 149 vpd_params->sequence = 1; 150 vpd_params->status = 0; 151 } 152 153 /** 154 * vpd_sequence_end() - Finalize a VPD retrieval sequence. 155 * @seq: Sequence state. 156 * 157 * Releases resources obtained by vpd_sequence_begin(). 158 */ 159 static void vpd_sequence_end(struct papr_rtas_sequence *seq) 160 { 161 struct rtas_ibm_get_vpd_params *vpd_params; 162 163 vpd_params = (struct rtas_ibm_get_vpd_params *)seq->params; 164 rtas_work_area_free(vpd_params->work_area); 165 mutex_unlock(&rtas_ibm_get_vpd_lock); 166 } 167 168 /* 169 * Generator function to be passed to papr_rtas_blob_generate(). 170 */ 171 static const char *vpd_sequence_fill_work_area(struct papr_rtas_sequence *seq, 172 size_t *len) 173 { 174 struct rtas_ibm_get_vpd_params *p; 175 bool init_state; 176 177 p = (struct rtas_ibm_get_vpd_params *)seq->params; 178 init_state = (p->written == 0) ? true : false; 179 180 if (papr_rtas_sequence_should_stop(seq, p->status, init_state)) 181 return NULL; 182 if (papr_rtas_sequence_set_err(seq, rtas_ibm_get_vpd(p))) 183 return NULL; 184 *len = p->written; 185 return rtas_work_area_raw_buf(p->work_area); 186 } 187 188 static const struct file_operations papr_vpd_handle_ops = { 189 .read = papr_rtas_common_handle_read, 190 .llseek = papr_rtas_common_handle_seek, 191 .release = papr_rtas_common_handle_release, 192 }; 193 194 /** 195 * papr_vpd_create_handle() - Create a fd-based handle for reading VPD. 196 * @ulc: Location code in user memory; defines the scope of the VPD to 197 * retrieve. 198 * 199 * Handler for PAPR_VPD_IOC_CREATE_HANDLE ioctl command. Validates 200 * @ulc and instantiates an immutable VPD "blob" for it. The blob is 201 * attached to a file descriptor for reading by user space. The memory 202 * backing the blob is freed when the file is released. 203 * 204 * The entire requested VPD is retrieved by this call and all 205 * necessary RTAS interactions are performed before returning the fd 206 * to user space. This keeps the read handler simple and ensures that 207 * the kernel can prevent interleaving of ibm,get-vpd call sequences. 208 * 209 * Return: The installed fd number if successful, -ve errno otherwise. 210 */ 211 static long papr_vpd_create_handle(struct papr_location_code __user *ulc) 212 { 213 struct rtas_ibm_get_vpd_params vpd_params = {}; 214 struct papr_rtas_sequence seq = {}; 215 struct papr_location_code klc; 216 int fd; 217 218 if (copy_from_user(&klc, ulc, sizeof(klc))) 219 return -EFAULT; 220 221 if (!string_is_terminated(klc.str, ARRAY_SIZE(klc.str))) 222 return -EINVAL; 223 224 seq = (struct papr_rtas_sequence) { 225 .begin = vpd_sequence_begin, 226 .end = vpd_sequence_end, 227 .work = vpd_sequence_fill_work_area, 228 }; 229 230 vpd_params.loc_code = &klc; 231 seq.params = (void *)&vpd_params; 232 233 fd = papr_rtas_setup_file_interface(&seq, &papr_vpd_handle_ops, 234 "[papr-vpd]"); 235 236 return fd; 237 } 238 239 /* 240 * Top-level ioctl handler for /dev/papr-vpd. 241 */ 242 static long papr_vpd_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) 243 { 244 void __user *argp = (__force void __user *)arg; 245 long ret; 246 247 switch (ioctl) { 248 case PAPR_VPD_IOC_CREATE_HANDLE: 249 ret = papr_vpd_create_handle(argp); 250 break; 251 default: 252 ret = -ENOIOCTLCMD; 253 break; 254 } 255 return ret; 256 } 257 258 static const struct file_operations papr_vpd_ops = { 259 .unlocked_ioctl = papr_vpd_dev_ioctl, 260 }; 261 262 static struct miscdevice papr_vpd_dev = { 263 .minor = MISC_DYNAMIC_MINOR, 264 .name = "papr-vpd", 265 .fops = &papr_vpd_ops, 266 }; 267 268 static __init int papr_vpd_init(void) 269 { 270 if (!rtas_function_implemented(RTAS_FN_IBM_GET_VPD)) 271 return -ENODEV; 272 273 return misc_register(&papr_vpd_dev); 274 } 275 machine_device_initcall(pseries, papr_vpd_init); 276