xref: /linux/arch/powerpc/platforms/pseries/papr-vpd.c (revision 746680ec6696585e30db3e18c93a63df9cbec39c)
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