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