This source file includes following definitions.
- op_str
- cxl_h_attach_process
- cxl_h_detach_process
- cxl_h_control_function
- cxl_h_reset_afu
- cxl_h_suspend_process
- cxl_h_resume_process
- cxl_h_read_error_state
- cxl_h_get_afu_err
- cxl_h_get_config
- cxl_h_terminate_process
- cxl_h_collect_vpd
- cxl_h_get_fn_error_interrupt
- cxl_h_ack_fn_error_interrupt
- cxl_h_get_error_log
- cxl_h_collect_int_info
- cxl_h_control_faults
- cxl_h_control_facility
- cxl_h_reset_adapter
- cxl_h_collect_vpd_adapter
- cxl_h_download_facility
- cxl_h_download_adapter_image
- cxl_h_validate_adapter_image
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
88 static 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
105 static char *control_adapter_op_names[] = {
106 "UNKNOWN_OP",
107 "RESET",
108 "COLLECT_VPD",
109 };
110
111 static char *download_op_names[] = {
112 "UNKNOWN_OP",
113 "DOWNLOAD",
114 "VALIDATE",
115 };
116
117 static 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
131 long 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
174 long 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
205 static 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
244 long 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
257 long 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
270 long 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
283 long 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
298 long 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
318 long 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
332 long 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
349 long 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
361 long 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
373 long 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
385 long 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
397 long 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
438 long 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
478 static 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
515 long 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
530 long 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
558 static 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
623 long 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
636 long 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 }