1// SPDX-License-Identifier: GPL-2.0
2#include <linux/kernel.h>
3#include <linux/fs.h>
4#include <linux/semaphore.h>
5#include <linux/slab.h>
6#include <linux/uaccess.h>
7#include <linux/of.h>
8#include <asm/rtas.h>
9
10#include "cxl.h"
11#include "hcalls.h"
12
13#define DOWNLOAD_IMAGE 1
14#define VALIDATE_IMAGE 2
15
16struct ai_header {
17 u16 version;
18 u8 reserved0[6];
19 u16 vendor;
20 u16 device;
21 u16 subsystem_vendor;
22 u16 subsystem;
23 u64 image_offset;
24 u64 image_length;
25 u8 reserved1[96];
26};
27
28static struct semaphore sem;
29static unsigned long *buffer[CXL_AI_MAX_ENTRIES];
30static struct sg_list *le;
31static u64 continue_token;
32static unsigned int transfer;
33
34struct update_props_workarea {
35 __be32 phandle;
36 __be32 state;
37 __be64 reserved;
38 __be32 nprops;
39} __packed;
40
41struct update_nodes_workarea {
42 __be32 state;
43 __be64 unit_address;
44 __be32 reserved;
45} __packed;
46
47#define DEVICE_SCOPE 3
48#define NODE_ACTION_MASK 0xff000000
49#define NODE_COUNT_MASK 0x00ffffff
50#define OPCODE_DELETE 0x01000000
51#define OPCODE_UPDATE 0x02000000
52#define OPCODE_ADD 0x03000000
53
54static int rcall(int token, char *buf, s32 scope)
55{
56 int rc;
57
58 spin_lock(&rtas_data_buf_lock);
59
60 memcpy(rtas_data_buf, buf, RTAS_DATA_BUF_SIZE);
61 rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, scope);
62 memcpy(buf, rtas_data_buf, RTAS_DATA_BUF_SIZE);
63
64 spin_unlock(&rtas_data_buf_lock);
65 return rc;
66}
67
68static int update_property(struct device_node *dn, const char *name,
69 u32 vd, char *value)
70{
71 struct property *new_prop;
72 u32 *val;
73 int rc;
74
75 new_prop = kzalloc(size: sizeof(*new_prop), GFP_KERNEL);
76 if (!new_prop)
77 return -ENOMEM;
78
79 new_prop->name = kstrdup(s: name, GFP_KERNEL);
80 if (!new_prop->name) {
81 kfree(objp: new_prop);
82 return -ENOMEM;
83 }
84
85 new_prop->length = vd;
86 new_prop->value = kzalloc(size: new_prop->length, GFP_KERNEL);
87 if (!new_prop->value) {
88 kfree(objp: new_prop->name);
89 kfree(objp: new_prop);
90 return -ENOMEM;
91 }
92 memcpy(new_prop->value, value, vd);
93
94 val = (u32 *)new_prop->value;
95 rc = cxl_update_properties(dn, new_prop);
96 pr_devel("%pOFn: update property (%s, length: %i, value: %#x)\n",
97 dn, name, vd, be32_to_cpu(*val));
98
99 if (rc) {
100 kfree(objp: new_prop->name);
101 kfree(objp: new_prop->value);
102 kfree(objp: new_prop);
103 }
104 return rc;
105}
106
107static int update_node(__be32 phandle, s32 scope)
108{
109 struct update_props_workarea *upwa;
110 struct device_node *dn;
111 int i, rc, ret;
112 char *prop_data;
113 char *buf;
114 int token;
115 u32 nprops;
116 u32 vd;
117
118 token = rtas_token("ibm,update-properties");
119 if (token == RTAS_UNKNOWN_SERVICE)
120 return -EINVAL;
121
122 buf = kzalloc(size: RTAS_DATA_BUF_SIZE, GFP_KERNEL);
123 if (!buf)
124 return -ENOMEM;
125
126 dn = of_find_node_by_phandle(be32_to_cpu(phandle));
127 if (!dn) {
128 kfree(objp: buf);
129 return -ENOENT;
130 }
131
132 upwa = (struct update_props_workarea *)&buf[0];
133 upwa->phandle = phandle;
134 do {
135 rc = rcall(token, buf, scope);
136 if (rc < 0)
137 break;
138
139 prop_data = buf + sizeof(*upwa);
140 nprops = be32_to_cpu(upwa->nprops);
141
142 if (*prop_data == 0) {
143 prop_data++;
144 vd = be32_to_cpu(*(__be32 *)prop_data);
145 prop_data += vd + sizeof(vd);
146 nprops--;
147 }
148
149 for (i = 0; i < nprops; i++) {
150 char *prop_name;
151
152 prop_name = prop_data;
153 prop_data += strlen(prop_name) + 1;
154 vd = be32_to_cpu(*(__be32 *)prop_data);
155 prop_data += sizeof(vd);
156
157 if ((vd != 0x00000000) && (vd != 0x80000000)) {
158 ret = update_property(dn, name: prop_name, vd,
159 value: prop_data);
160 if (ret)
161 pr_err("cxl: Could not update property %s - %i\n",
162 prop_name, ret);
163
164 prop_data += vd;
165 }
166 }
167 } while (rc == 1);
168
169 of_node_put(node: dn);
170 kfree(objp: buf);
171 return rc;
172}
173
174static int update_devicetree(struct cxl *adapter, s32 scope)
175{
176 struct update_nodes_workarea *unwa;
177 u32 action, node_count;
178 int token, rc, i;
179 __be32 *data, phandle;
180 char *buf;
181
182 token = rtas_token("ibm,update-nodes");
183 if (token == RTAS_UNKNOWN_SERVICE)
184 return -EINVAL;
185
186 buf = kzalloc(size: RTAS_DATA_BUF_SIZE, GFP_KERNEL);
187 if (!buf)
188 return -ENOMEM;
189
190 unwa = (struct update_nodes_workarea *)&buf[0];
191 unwa->unit_address = cpu_to_be64(adapter->guest->handle);
192 do {
193 rc = rcall(token, buf, scope);
194 if (rc && rc != 1)
195 break;
196
197 data = (__be32 *)buf + 4;
198 while (be32_to_cpu(*data) & NODE_ACTION_MASK) {
199 action = be32_to_cpu(*data) & NODE_ACTION_MASK;
200 node_count = be32_to_cpu(*data) & NODE_COUNT_MASK;
201 pr_devel("device reconfiguration - action: %#x, nodes: %#x\n",
202 action, node_count);
203 data++;
204
205 for (i = 0; i < node_count; i++) {
206 phandle = *data++;
207
208 switch (action) {
209 case OPCODE_DELETE:
210 /* nothing to do */
211 break;
212 case OPCODE_UPDATE:
213 update_node(phandle, scope);
214 break;
215 case OPCODE_ADD:
216 /* nothing to do, just move pointer */
217 data++;
218 break;
219 }
220 }
221 }
222 } while (rc == 1);
223
224 kfree(objp: buf);
225 return 0;
226}
227
228static int handle_image(struct cxl *adapter, int operation,
229 long (*fct)(u64, u64, u64, u64 *),
230 struct cxl_adapter_image *ai)
231{
232 size_t mod, s_copy, len_chunk = 0;
233 struct ai_header *header = NULL;
234 unsigned int entries = 0, i;
235 void *dest, *from;
236 int rc = 0, need_header;
237
238 /* base adapter image header */
239 need_header = (ai->flags & CXL_AI_NEED_HEADER);
240 if (need_header) {
241 header = kzalloc(size: sizeof(struct ai_header), GFP_KERNEL);
242 if (!header)
243 return -ENOMEM;
244 header->version = cpu_to_be16(1);
245 header->vendor = cpu_to_be16(adapter->guest->vendor);
246 header->device = cpu_to_be16(adapter->guest->device);
247 header->subsystem_vendor = cpu_to_be16(adapter->guest->subsystem_vendor);
248 header->subsystem = cpu_to_be16(adapter->guest->subsystem);
249 header->image_offset = cpu_to_be64(CXL_AI_HEADER_SIZE);
250 header->image_length = cpu_to_be64(ai->len_image);
251 }
252
253 /* number of entries in the list */
254 len_chunk = ai->len_data;
255 if (need_header)
256 len_chunk += CXL_AI_HEADER_SIZE;
257
258 entries = len_chunk / CXL_AI_BUFFER_SIZE;
259 mod = len_chunk % CXL_AI_BUFFER_SIZE;
260 if (mod)
261 entries++;
262
263 if (entries > CXL_AI_MAX_ENTRIES) {
264 rc = -EINVAL;
265 goto err;
266 }
267
268 /* < -- MAX_CHUNK_SIZE = 4096 * 256 = 1048576 bytes -->
269 * chunk 0 ----------------------------------------------------
270 * | header | data |
271 * ----------------------------------------------------
272 * chunk 1 ----------------------------------------------------
273 * | data |
274 * ----------------------------------------------------
275 * ....
276 * chunk n ----------------------------------------------------
277 * | data |
278 * ----------------------------------------------------
279 */
280 from = (void *) ai->data;
281 for (i = 0; i < entries; i++) {
282 dest = buffer[i];
283 s_copy = CXL_AI_BUFFER_SIZE;
284
285 if ((need_header) && (i == 0)) {
286 /* add adapter image header */
287 memcpy(buffer[i], header, sizeof(struct ai_header));
288 s_copy = CXL_AI_BUFFER_SIZE - CXL_AI_HEADER_SIZE;
289 dest += CXL_AI_HEADER_SIZE; /* image offset */
290 }
291 if ((i == (entries - 1)) && mod)
292 s_copy = mod;
293
294 /* copy data */
295 if (copy_from_user(to: dest, from, n: s_copy))
296 goto err;
297
298 /* fill in the list */
299 le[i].phys_addr = cpu_to_be64(virt_to_phys(buffer[i]));
300 le[i].len = cpu_to_be64(CXL_AI_BUFFER_SIZE);
301 if ((i == (entries - 1)) && mod)
302 le[i].len = cpu_to_be64(mod);
303 from += s_copy;
304 }
305 pr_devel("%s (op: %i, need header: %i, entries: %i, token: %#llx)\n",
306 __func__, operation, need_header, entries, continue_token);
307
308 /*
309 * download/validate the adapter image to the coherent
310 * platform facility
311 */
312 rc = fct(adapter->guest->handle, virt_to_phys(address: le), entries,
313 &continue_token);
314 if (rc == 0) /* success of download/validation operation */
315 continue_token = 0;
316
317err:
318 kfree(objp: header);
319
320 return rc;
321}
322
323static int transfer_image(struct cxl *adapter, int operation,
324 struct cxl_adapter_image *ai)
325{
326 int rc = 0;
327 int afu;
328
329 switch (operation) {
330 case DOWNLOAD_IMAGE:
331 rc = handle_image(adapter, operation,
332 fct: &cxl_h_download_adapter_image, ai);
333 if (rc < 0) {
334 pr_devel("resetting adapter\n");
335 cxl_h_reset_adapter(unit_address: adapter->guest->handle);
336 }
337 return rc;
338
339 case VALIDATE_IMAGE:
340 rc = handle_image(adapter, operation,
341 fct: &cxl_h_validate_adapter_image, ai);
342 if (rc < 0) {
343 pr_devel("resetting adapter\n");
344 cxl_h_reset_adapter(unit_address: adapter->guest->handle);
345 return rc;
346 }
347 if (rc == 0) {
348 pr_devel("remove current afu\n");
349 for (afu = 0; afu < adapter->slices; afu++)
350 cxl_guest_remove_afu(afu: adapter->afu[afu]);
351
352 pr_devel("resetting adapter\n");
353 cxl_h_reset_adapter(unit_address: adapter->guest->handle);
354
355 /* The entire image has now been
356 * downloaded and the validation has
357 * been successfully performed.
358 * After that, the partition should call
359 * ibm,update-nodes and
360 * ibm,update-properties to receive the
361 * current configuration
362 */
363 rc = update_devicetree(adapter, DEVICE_SCOPE);
364 transfer = 1;
365 }
366 return rc;
367 }
368
369 return -EINVAL;
370}
371
372static long ioctl_transfer_image(struct cxl *adapter, int operation,
373 struct cxl_adapter_image __user *uai)
374{
375 struct cxl_adapter_image ai;
376
377 pr_devel("%s\n", __func__);
378
379 if (copy_from_user(to: &ai, from: uai, n: sizeof(struct cxl_adapter_image)))
380 return -EFAULT;
381
382 /*
383 * Make sure reserved fields and bits are set to 0
384 */
385 if (ai.reserved1 || ai.reserved2 || ai.reserved3 || ai.reserved4 ||
386 (ai.flags & ~CXL_AI_ALL))
387 return -EINVAL;
388
389 return transfer_image(adapter, operation, ai: &ai);
390}
391
392static int device_open(struct inode *inode, struct file *file)
393{
394 int adapter_num = CXL_DEVT_ADAPTER(inode->i_rdev);
395 struct cxl *adapter;
396 int rc = 0, i;
397
398 pr_devel("in %s\n", __func__);
399
400 BUG_ON(sizeof(struct ai_header) != CXL_AI_HEADER_SIZE);
401
402 /* Allows one process to open the device by using a semaphore */
403 if (down_interruptible(sem: &sem) != 0)
404 return -EPERM;
405
406 if (!(adapter = get_cxl_adapter(num: adapter_num))) {
407 rc = -ENODEV;
408 goto err_unlock;
409 }
410
411 file->private_data = adapter;
412 continue_token = 0;
413 transfer = 0;
414
415 for (i = 0; i < CXL_AI_MAX_ENTRIES; i++)
416 buffer[i] = NULL;
417
418 /* aligned buffer containing list entries which describes up to
419 * 1 megabyte of data (256 entries of 4096 bytes each)
420 * Logical real address of buffer 0 - Buffer 0 length in bytes
421 * Logical real address of buffer 1 - Buffer 1 length in bytes
422 * Logical real address of buffer 2 - Buffer 2 length in bytes
423 * ....
424 * ....
425 * Logical real address of buffer N - Buffer N length in bytes
426 */
427 le = (struct sg_list *)get_zeroed_page(GFP_KERNEL);
428 if (!le) {
429 rc = -ENOMEM;
430 goto err;
431 }
432
433 for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
434 buffer[i] = (unsigned long *)get_zeroed_page(GFP_KERNEL);
435 if (!buffer[i]) {
436 rc = -ENOMEM;
437 goto err1;
438 }
439 }
440
441 return 0;
442
443err1:
444 for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
445 if (buffer[i])
446 free_page((unsigned long) buffer[i]);
447 }
448
449 if (le)
450 free_page((unsigned long) le);
451err:
452 put_device(dev: &adapter->dev);
453err_unlock:
454 up(sem: &sem);
455
456 return rc;
457}
458
459static long device_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
460{
461 struct cxl *adapter = file->private_data;
462
463 pr_devel("in %s\n", __func__);
464
465 if (cmd == CXL_IOCTL_DOWNLOAD_IMAGE)
466 return ioctl_transfer_image(adapter,
467 DOWNLOAD_IMAGE,
468 uai: (struct cxl_adapter_image __user *)arg);
469 else if (cmd == CXL_IOCTL_VALIDATE_IMAGE)
470 return ioctl_transfer_image(adapter,
471 VALIDATE_IMAGE,
472 uai: (struct cxl_adapter_image __user *)arg);
473 else
474 return -EINVAL;
475}
476
477static int device_close(struct inode *inode, struct file *file)
478{
479 struct cxl *adapter = file->private_data;
480 int i;
481
482 pr_devel("in %s\n", __func__);
483
484 for (i = 0; i < CXL_AI_MAX_ENTRIES; i++) {
485 if (buffer[i])
486 free_page((unsigned long) buffer[i]);
487 }
488
489 if (le)
490 free_page((unsigned long) le);
491
492 up(sem: &sem);
493 put_device(dev: &adapter->dev);
494 continue_token = 0;
495
496 /* reload the module */
497 if (transfer)
498 cxl_guest_reload_module(adapter);
499 else {
500 pr_devel("resetting adapter\n");
501 cxl_h_reset_adapter(unit_address: adapter->guest->handle);
502 }
503
504 transfer = 0;
505 return 0;
506}
507
508static const struct file_operations fops = {
509 .owner = THIS_MODULE,
510 .open = device_open,
511 .unlocked_ioctl = device_ioctl,
512 .compat_ioctl = compat_ptr_ioctl,
513 .release = device_close,
514};
515
516void cxl_guest_remove_chardev(struct cxl *adapter)
517{
518 cdev_del(&adapter->guest->cdev);
519}
520
521int cxl_guest_add_chardev(struct cxl *adapter)
522{
523 dev_t devt;
524 int rc;
525
526 devt = MKDEV(MAJOR(cxl_get_dev()), CXL_CARD_MINOR(adapter));
527 cdev_init(&adapter->guest->cdev, &fops);
528 if ((rc = cdev_add(&adapter->guest->cdev, devt, 1))) {
529 dev_err(&adapter->dev,
530 "Unable to add chardev on adapter (card%i): %i\n",
531 adapter->adapter_num, rc);
532 goto err;
533 }
534 adapter->dev.devt = devt;
535 sema_init(sem: &sem, val: 1);
536err:
537 return rc;
538}
539

source code of linux/drivers/misc/cxl/flash.c