1
2
3
4
5
6
7
8
9
10
11#include <linux/compiler.h>
12#include <linux/types.h>
13#include <linux/delay.h>
14#include <asm/byteorder.h>
15#include "hcalls.h"
16#include "trace.h"
17
18#define CXL_HCALL_TIMEOUT 60000
19#define CXL_HCALL_TIMEOUT_DOWNLOAD 120000
20
21#define H_ATTACH_CA_PROCESS 0x344
22#define H_CONTROL_CA_FUNCTION 0x348
23#define H_DETACH_CA_PROCESS 0x34C
24#define H_COLLECT_CA_INT_INFO 0x350
25#define H_CONTROL_CA_FAULTS 0x354
26#define H_DOWNLOAD_CA_FUNCTION 0x35C
27#define H_DOWNLOAD_CA_FACILITY 0x364
28#define H_CONTROL_CA_FACILITY 0x368
29
30#define H_CONTROL_CA_FUNCTION_RESET 1
31#define H_CONTROL_CA_FUNCTION_SUSPEND_PROCESS 2
32#define H_CONTROL_CA_FUNCTION_RESUME_PROCESS 3
33#define H_CONTROL_CA_FUNCTION_READ_ERR_STATE 4
34#define H_CONTROL_CA_FUNCTION_GET_AFU_ERR 5
35#define H_CONTROL_CA_FUNCTION_GET_CONFIG 6
36#define H_CONTROL_CA_FUNCTION_GET_DOWNLOAD_STATE 7
37#define H_CONTROL_CA_FUNCTION_TERMINATE_PROCESS 8
38#define H_CONTROL_CA_FUNCTION_COLLECT_VPD 9
39#define H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT 11
40#define H_CONTROL_CA_FUNCTION_ACK_FUNCTION_ERR_INT 12
41#define H_CONTROL_CA_FUNCTION_GET_ERROR_LOG 13
42
43#define H_CONTROL_CA_FAULTS_RESPOND_PSL 1
44#define H_CONTROL_CA_FAULTS_RESPOND_AFU 2
45
46#define H_CONTROL_CA_FACILITY_RESET 1
47#define H_CONTROL_CA_FACILITY_COLLECT_VPD 2
48
49#define H_DOWNLOAD_CA_FACILITY_DOWNLOAD 1
50#define H_DOWNLOAD_CA_FACILITY_VALIDATE 2
51
52
53#define _CXL_LOOP_HCALL(call, rc, retbuf, fn, ...) \
54 { \
55 unsigned int delay, total_delay = 0; \
56 u64 token = 0; \
57 \
58 memset(retbuf, 0, sizeof(retbuf)); \
59 while (1) { \
60 rc = call(fn, retbuf, __VA_ARGS__, token); \
61 token = retbuf[0]; \
62 if (rc != H_BUSY && !H_IS_LONG_BUSY(rc)) \
63 break; \
64 \
65 if (rc == H_BUSY) \
66 delay = 10; \
67 else \
68 delay = get_longbusy_msecs(rc); \
69 \
70 total_delay += delay; \
71 if (total_delay > CXL_HCALL_TIMEOUT) { \
72 WARN(1, "Warning: Giving up waiting for CXL hcall " \
73 "%#x after %u msec\n", fn, total_delay); \
74 rc = H_BUSY; \
75 break; \
76 } \
77 msleep(delay); \
78 } \
79 }
80#define CXL_H_WAIT_UNTIL_DONE(...) _CXL_LOOP_HCALL(plpar_hcall, __VA_ARGS__)
81#define CXL_H9_WAIT_UNTIL_DONE(...) _CXL_LOOP_HCALL(plpar_hcall9, __VA_ARGS__)
82
83#define _PRINT_MSG(rc, format, ...) \
84 { \
85 if ((rc != H_SUCCESS) && (rc != H_CONTINUE)) \
86 pr_err(format, __VA_ARGS__); \
87 else \
88 pr_devel(format, __VA_ARGS__); \
89 } \
90
91
92static char *afu_op_names[] = {
93 "UNKNOWN_OP",
94 "RESET",
95 "SUSPEND_PROCESS",
96 "RESUME_PROCESS",
97 "READ_ERR_STATE",
98 "GET_AFU_ERR",
99 "GET_CONFIG",
100 "GET_DOWNLOAD_STATE",
101 "TERMINATE_PROCESS",
102 "COLLECT_VPD",
103 "UNKNOWN_OP",
104 "GET_FUNCTION_ERR_INT",
105 "ACK_FUNCTION_ERR_INT",
106 "GET_ERROR_LOG",
107};
108
109static char *control_adapter_op_names[] = {
110 "UNKNOWN_OP",
111 "RESET",
112 "COLLECT_VPD",
113};
114
115static char *download_op_names[] = {
116 "UNKNOWN_OP",
117 "DOWNLOAD",
118 "VALIDATE",
119};
120
121static char *op_str(unsigned int op, char *name_array[], int array_len)
122{
123 if (op >= array_len)
124 return "UNKNOWN_OP";
125 return name_array[op];
126}
127
128#define OP_STR(op, name_array) op_str(op, name_array, ARRAY_SIZE(name_array))
129
130#define OP_STR_AFU(op) OP_STR(op, afu_op_names)
131#define OP_STR_CONTROL_ADAPTER(op) OP_STR(op, control_adapter_op_names)
132#define OP_STR_DOWNLOAD_ADAPTER(op) OP_STR(op, download_op_names)
133
134
135long cxl_h_attach_process(u64 unit_address,
136 struct cxl_process_element_hcall *element,
137 u64 *process_token, u64 *mmio_addr, u64 *mmio_size)
138{
139 unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
140 long rc;
141
142 CXL_H_WAIT_UNTIL_DONE(rc, retbuf, H_ATTACH_CA_PROCESS, unit_address, virt_to_phys(element));
143 _PRINT_MSG(rc, "cxl_h_attach_process(%#.16llx, %#.16lx): %li\n",
144 unit_address, virt_to_phys(element), rc);
145 trace_cxl_hcall_attach(unit_address, virt_to_phys(element), retbuf[0], retbuf[1], retbuf[2], rc);
146
147 pr_devel("token: 0x%.8lx mmio_addr: 0x%lx mmio_size: 0x%lx\nProcess Element Structure:\n",
148 retbuf[0], retbuf[1], retbuf[2]);
149 cxl_dump_debug_buffer(element, sizeof(*element));
150
151 switch (rc) {
152 case H_SUCCESS:
153 *process_token = retbuf[0];
154 if (mmio_addr)
155 *mmio_addr = retbuf[1];
156 if (mmio_size)
157 *mmio_size = retbuf[2];
158 return 0;
159 case H_PARAMETER:
160 case H_FUNCTION:
161 return -EINVAL;
162 case H_AUTHORITY:
163 case H_RESOURCE:
164 case H_HARDWARE:
165 case H_STATE:
166 case H_BUSY:
167 return -EBUSY;
168 default:
169 WARN(1, "Unexpected return code: %lx", rc);
170 return -EINVAL;
171 }
172}
173
174
175
176
177
178long cxl_h_detach_process(u64 unit_address, u64 process_token)
179{
180 unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
181 long rc;
182
183 CXL_H_WAIT_UNTIL_DONE(rc, retbuf, H_DETACH_CA_PROCESS, unit_address, process_token);
184 _PRINT_MSG(rc, "cxl_h_detach_process(%#.16llx, 0x%.8llx): %li\n", unit_address, process_token, rc);
185 trace_cxl_hcall_detach(unit_address, process_token, rc);
186
187 switch (rc) {
188 case H_SUCCESS:
189 return 0;
190 case H_PARAMETER:
191 return -EINVAL;
192 case H_AUTHORITY:
193 case H_RESOURCE:
194 case H_HARDWARE:
195 case H_STATE:
196 case H_BUSY:
197 return -EBUSY;
198 default:
199 WARN(1, "Unexpected return code: %lx", rc);
200 return -EINVAL;
201 }
202}
203
204
205
206
207
208
209static long cxl_h_control_function(u64 unit_address, u64 op,
210 u64 p1, u64 p2, u64 p3, u64 p4, u64 *out)
211{
212 unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
213 long rc;
214
215 CXL_H9_WAIT_UNTIL_DONE(rc, retbuf, H_CONTROL_CA_FUNCTION, unit_address, op, p1, p2, p3, p4);
216 _PRINT_MSG(rc, "cxl_h_control_function(%#.16llx, %s(%#llx, %#llx, %#llx, %#llx, R4: %#lx)): %li\n",
217 unit_address, OP_STR_AFU(op), p1, p2, p3, p4, retbuf[0], rc);
218 trace_cxl_hcall_control_function(unit_address, OP_STR_AFU(op), p1, p2, p3, p4, retbuf[0], rc);
219
220 switch (rc) {
221 case H_SUCCESS:
222 if ((op == H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT ||
223 op == H_CONTROL_CA_FUNCTION_READ_ERR_STATE ||
224 op == H_CONTROL_CA_FUNCTION_COLLECT_VPD))
225 *out = retbuf[0];
226 return 0;
227 case H_PARAMETER:
228 case H_FUNCTION:
229 case H_NOT_FOUND:
230 case H_NOT_AVAILABLE:
231 case H_SG_LIST:
232 return -EINVAL;
233 case H_AUTHORITY:
234 case H_RESOURCE:
235 case H_HARDWARE:
236 case H_STATE:
237 case H_BUSY:
238 return -EBUSY;
239 default:
240 WARN(1, "Unexpected return code: %lx", rc);
241 return -EINVAL;
242 }
243}
244
245
246
247
248long cxl_h_reset_afu(u64 unit_address)
249{
250 return cxl_h_control_function(unit_address,
251 H_CONTROL_CA_FUNCTION_RESET,
252 0, 0, 0, 0,
253 NULL);
254}
255
256
257
258
259
260
261long cxl_h_suspend_process(u64 unit_address, u64 process_token)
262{
263 return cxl_h_control_function(unit_address,
264 H_CONTROL_CA_FUNCTION_SUSPEND_PROCESS,
265 process_token, 0, 0, 0,
266 NULL);
267}
268
269
270
271
272
273
274long cxl_h_resume_process(u64 unit_address, u64 process_token)
275{
276 return cxl_h_control_function(unit_address,
277 H_CONTROL_CA_FUNCTION_RESUME_PROCESS,
278 process_token, 0, 0, 0,
279 NULL);
280}
281
282
283
284
285
286
287long cxl_h_read_error_state(u64 unit_address, u64 *state)
288{
289 return cxl_h_control_function(unit_address,
290 H_CONTROL_CA_FUNCTION_READ_ERR_STATE,
291 0, 0, 0, 0,
292 state);
293}
294
295
296
297
298
299
300
301
302long cxl_h_get_afu_err(u64 unit_address, u64 offset,
303 u64 buf_address, u64 len)
304{
305 return cxl_h_control_function(unit_address,
306 H_CONTROL_CA_FUNCTION_GET_AFU_ERR,
307 offset, buf_address, len, 0,
308 NULL);
309}
310
311
312
313
314
315
316
317
318
319
320
321
322long cxl_h_get_config(u64 unit_address, u64 cr_num, u64 offset,
323 u64 buf_address, u64 len)
324{
325 return cxl_h_control_function(unit_address,
326 H_CONTROL_CA_FUNCTION_GET_CONFIG,
327 cr_num, offset, buf_address, len,
328 NULL);
329}
330
331
332
333
334
335
336long cxl_h_terminate_process(u64 unit_address, u64 process_token)
337{
338 return cxl_h_control_function(unit_address,
339 H_CONTROL_CA_FUNCTION_TERMINATE_PROCESS,
340 process_token, 0, 0, 0,
341 NULL);
342}
343
344
345
346
347
348
349
350
351
352
353long cxl_h_collect_vpd(u64 unit_address, u64 record, u64 list_address,
354 u64 num, u64 *out)
355{
356 return cxl_h_control_function(unit_address,
357 H_CONTROL_CA_FUNCTION_COLLECT_VPD,
358 record, list_address, num, 0,
359 out);
360}
361
362
363
364
365long cxl_h_get_fn_error_interrupt(u64 unit_address, u64 *reg)
366{
367 return cxl_h_control_function(unit_address,
368 H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT,
369 0, 0, 0, 0, reg);
370}
371
372
373
374
375
376
377long cxl_h_ack_fn_error_interrupt(u64 unit_address, u64 value)
378{
379 return cxl_h_control_function(unit_address,
380 H_CONTROL_CA_FUNCTION_ACK_FUNCTION_ERR_INT,
381 value, 0, 0, 0,
382 NULL);
383}
384
385
386
387
388
389long cxl_h_get_error_log(u64 unit_address, u64 value)
390{
391 return cxl_h_control_function(unit_address,
392 H_CONTROL_CA_FUNCTION_GET_ERROR_LOG,
393 0, 0, 0, 0,
394 NULL);
395}
396
397
398
399
400
401long cxl_h_collect_int_info(u64 unit_address, u64 process_token,
402 struct cxl_irq_info *info)
403{
404 long rc;
405
406 BUG_ON(sizeof(*info) != sizeof(unsigned long[PLPAR_HCALL9_BUFSIZE]));
407
408 rc = plpar_hcall9(H_COLLECT_CA_INT_INFO, (unsigned long *) info,
409 unit_address, process_token);
410 _PRINT_MSG(rc, "cxl_h_collect_int_info(%#.16llx, 0x%llx): %li\n",
411 unit_address, process_token, rc);
412 trace_cxl_hcall_collect_int_info(unit_address, process_token, rc);
413
414 switch (rc) {
415 case H_SUCCESS:
416 pr_devel("dsisr:%#llx, dar:%#llx, dsr:%#llx, pid:%u, tid:%u, afu_err:%#llx, errstat:%#llx\n",
417 info->dsisr, info->dar, info->dsr, info->pid,
418 info->tid, info->afu_err, info->errstat);
419 return 0;
420 case H_PARAMETER:
421 return -EINVAL;
422 case H_AUTHORITY:
423 case H_HARDWARE:
424 case H_STATE:
425 return -EBUSY;
426 default:
427 WARN(1, "Unexpected return code: %lx", rc);
428 return -EINVAL;
429 }
430}
431
432
433
434
435
436
437
438
439
440
441
442long cxl_h_control_faults(u64 unit_address, u64 process_token,
443 u64 control_mask, u64 reset_mask)
444{
445 unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
446 long rc;
447
448 memset(retbuf, 0, sizeof(retbuf));
449
450 rc = plpar_hcall(H_CONTROL_CA_FAULTS, retbuf, unit_address,
451 H_CONTROL_CA_FAULTS_RESPOND_PSL, process_token,
452 control_mask, reset_mask);
453 _PRINT_MSG(rc, "cxl_h_control_faults(%#.16llx, 0x%llx, %#llx, %#llx): %li (%#lx)\n",
454 unit_address, process_token, control_mask, reset_mask,
455 rc, retbuf[0]);
456 trace_cxl_hcall_control_faults(unit_address, process_token,
457 control_mask, reset_mask, retbuf[0], rc);
458
459 switch (rc) {
460 case H_SUCCESS:
461 return 0;
462 case H_PARAMETER:
463 return -EINVAL;
464 case H_HARDWARE:
465 case H_STATE:
466 case H_AUTHORITY:
467 return -EBUSY;
468 case H_FUNCTION:
469 case H_NOT_FOUND:
470 return -EINVAL;
471 default:
472 WARN(1, "Unexpected return code: %lx", rc);
473 return -EINVAL;
474 }
475}
476
477
478
479
480
481
482static long cxl_h_control_facility(u64 unit_address, u64 op,
483 u64 p1, u64 p2, u64 p3, u64 p4, u64 *out)
484{
485 unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
486 long rc;
487
488 CXL_H9_WAIT_UNTIL_DONE(rc, retbuf, H_CONTROL_CA_FACILITY, unit_address, op, p1, p2, p3, p4);
489 _PRINT_MSG(rc, "cxl_h_control_facility(%#.16llx, %s(%#llx, %#llx, %#llx, %#llx, R4: %#lx)): %li\n",
490 unit_address, OP_STR_CONTROL_ADAPTER(op), p1, p2, p3, p4, retbuf[0], rc);
491 trace_cxl_hcall_control_facility(unit_address, OP_STR_CONTROL_ADAPTER(op), p1, p2, p3, p4, retbuf[0], rc);
492
493 switch (rc) {
494 case H_SUCCESS:
495 if (op == H_CONTROL_CA_FACILITY_COLLECT_VPD)
496 *out = retbuf[0];
497 return 0;
498 case H_PARAMETER:
499 case H_FUNCTION:
500 case H_NOT_FOUND:
501 case H_NOT_AVAILABLE:
502 case H_SG_LIST:
503 return -EINVAL;
504 case H_AUTHORITY:
505 case H_RESOURCE:
506 case H_HARDWARE:
507 case H_STATE:
508 case H_BUSY:
509 return -EBUSY;
510 default:
511 WARN(1, "Unexpected return code: %lx", rc);
512 return -EINVAL;
513 }
514}
515
516
517
518
519long cxl_h_reset_adapter(u64 unit_address)
520{
521 return cxl_h_control_facility(unit_address,
522 H_CONTROL_CA_FACILITY_RESET,
523 0, 0, 0, 0,
524 NULL);
525}
526
527
528
529
530
531
532
533
534long cxl_h_collect_vpd_adapter(u64 unit_address, u64 list_address,
535 u64 num, u64 *out)
536{
537 return cxl_h_control_facility(unit_address,
538 H_CONTROL_CA_FACILITY_COLLECT_VPD,
539 list_address, num, 0, 0,
540 out);
541}
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562static long cxl_h_download_facility(u64 unit_address, u64 op,
563 u64 list_address, u64 num,
564 u64 *out)
565{
566 unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
567 unsigned int delay, total_delay = 0;
568 u64 token = 0;
569 long rc;
570
571 if (*out != 0)
572 token = *out;
573
574 memset(retbuf, 0, sizeof(retbuf));
575 while (1) {
576 rc = plpar_hcall(H_DOWNLOAD_CA_FACILITY, retbuf,
577 unit_address, op, list_address, num,
578 token);
579 token = retbuf[0];
580 if (rc != H_BUSY && !H_IS_LONG_BUSY(rc))
581 break;
582
583 if (rc != H_BUSY) {
584 delay = get_longbusy_msecs(rc);
585 total_delay += delay;
586 if (total_delay > CXL_HCALL_TIMEOUT_DOWNLOAD) {
587 WARN(1, "Warning: Giving up waiting for CXL hcall "
588 "%#x after %u msec\n",
589 H_DOWNLOAD_CA_FACILITY, total_delay);
590 rc = H_BUSY;
591 break;
592 }
593 msleep(delay);
594 }
595 }
596 _PRINT_MSG(rc, "cxl_h_download_facility(%#.16llx, %s(%#llx, %#llx), %#lx): %li\n",
597 unit_address, OP_STR_DOWNLOAD_ADAPTER(op), list_address, num, retbuf[0], rc);
598 trace_cxl_hcall_download_facility(unit_address, OP_STR_DOWNLOAD_ADAPTER(op), list_address, num, retbuf[0], rc);
599
600 switch (rc) {
601 case H_SUCCESS:
602 return 0;
603 case H_PARAMETER:
604 case H_FUNCTION:
605 case H_SG_LIST:
606 case H_BAD_DATA:
607 return -EINVAL;
608 case H_AUTHORITY:
609 case H_RESOURCE:
610 case H_HARDWARE:
611 case H_STATE:
612 case H_BUSY:
613 return -EBUSY;
614 case H_CONTINUE:
615 *out = retbuf[0];
616 return 1;
617 default:
618 WARN(1, "Unexpected return code: %lx", rc);
619 return -EINVAL;
620 }
621}
622
623
624
625
626
627long cxl_h_download_adapter_image(u64 unit_address,
628 u64 list_address, u64 num,
629 u64 *out)
630{
631 return cxl_h_download_facility(unit_address,
632 H_DOWNLOAD_CA_FACILITY_DOWNLOAD,
633 list_address, num, out);
634}
635
636
637
638
639
640long cxl_h_validate_adapter_image(u64 unit_address,
641 u64 list_address, u64 num,
642 u64 *out)
643{
644 return cxl_h_download_facility(unit_address,
645 H_DOWNLOAD_CA_FACILITY_VALIDATE,
646 list_address, num, out);
647}
648