0001
0002
0003
0004
0005
0006
0007 #include <linux/compiler.h>
0008 #include <linux/types.h>
0009 #include <linux/delay.h>
0010 #include <asm/byteorder.h>
0011 #include "hcalls.h"
0012 #include "trace.h"
0013
0014 #define CXL_HCALL_TIMEOUT 60000
0015 #define CXL_HCALL_TIMEOUT_DOWNLOAD 120000
0016
0017 #define H_ATTACH_CA_PROCESS 0x344
0018 #define H_CONTROL_CA_FUNCTION 0x348
0019 #define H_DETACH_CA_PROCESS 0x34C
0020 #define H_COLLECT_CA_INT_INFO 0x350
0021 #define H_CONTROL_CA_FAULTS 0x354
0022 #define H_DOWNLOAD_CA_FUNCTION 0x35C
0023 #define H_DOWNLOAD_CA_FACILITY 0x364
0024 #define H_CONTROL_CA_FACILITY 0x368
0025
0026 #define H_CONTROL_CA_FUNCTION_RESET 1
0027 #define H_CONTROL_CA_FUNCTION_SUSPEND_PROCESS 2
0028 #define H_CONTROL_CA_FUNCTION_RESUME_PROCESS 3
0029 #define H_CONTROL_CA_FUNCTION_READ_ERR_STATE 4
0030 #define H_CONTROL_CA_FUNCTION_GET_AFU_ERR 5
0031 #define H_CONTROL_CA_FUNCTION_GET_CONFIG 6
0032 #define H_CONTROL_CA_FUNCTION_GET_DOWNLOAD_STATE 7
0033 #define H_CONTROL_CA_FUNCTION_TERMINATE_PROCESS 8
0034 #define H_CONTROL_CA_FUNCTION_COLLECT_VPD 9
0035 #define H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT 11
0036 #define H_CONTROL_CA_FUNCTION_ACK_FUNCTION_ERR_INT 12
0037 #define H_CONTROL_CA_FUNCTION_GET_ERROR_LOG 13
0038
0039 #define H_CONTROL_CA_FAULTS_RESPOND_PSL 1
0040 #define H_CONTROL_CA_FAULTS_RESPOND_AFU 2
0041
0042 #define H_CONTROL_CA_FACILITY_RESET 1
0043 #define H_CONTROL_CA_FACILITY_COLLECT_VPD 2
0044
0045 #define H_DOWNLOAD_CA_FACILITY_DOWNLOAD 1
0046 #define H_DOWNLOAD_CA_FACILITY_VALIDATE 2
0047
0048
0049 #define _CXL_LOOP_HCALL(call, rc, retbuf, fn, ...) \
0050 { \
0051 unsigned int delay, total_delay = 0; \
0052 u64 token = 0; \
0053 \
0054 memset(retbuf, 0, sizeof(retbuf)); \
0055 while (1) { \
0056 rc = call(fn, retbuf, __VA_ARGS__, token); \
0057 token = retbuf[0]; \
0058 if (rc != H_BUSY && !H_IS_LONG_BUSY(rc)) \
0059 break; \
0060 \
0061 if (rc == H_BUSY) \
0062 delay = 10; \
0063 else \
0064 delay = get_longbusy_msecs(rc); \
0065 \
0066 total_delay += delay; \
0067 if (total_delay > CXL_HCALL_TIMEOUT) { \
0068 WARN(1, "Warning: Giving up waiting for CXL hcall " \
0069 "%#x after %u msec\n", fn, total_delay); \
0070 rc = H_BUSY; \
0071 break; \
0072 } \
0073 msleep(delay); \
0074 } \
0075 }
0076 #define CXL_H_WAIT_UNTIL_DONE(...) _CXL_LOOP_HCALL(plpar_hcall, __VA_ARGS__)
0077 #define CXL_H9_WAIT_UNTIL_DONE(...) _CXL_LOOP_HCALL(plpar_hcall9, __VA_ARGS__)
0078
0079 #define _PRINT_MSG(rc, format, ...) \
0080 { \
0081 if ((rc != H_SUCCESS) && (rc != H_CONTINUE)) \
0082 pr_err(format, __VA_ARGS__); \
0083 else \
0084 pr_devel(format, __VA_ARGS__); \
0085 } \
0086
0087
0088 static char *afu_op_names[] = {
0089 "UNKNOWN_OP",
0090 "RESET",
0091 "SUSPEND_PROCESS",
0092 "RESUME_PROCESS",
0093 "READ_ERR_STATE",
0094 "GET_AFU_ERR",
0095 "GET_CONFIG",
0096 "GET_DOWNLOAD_STATE",
0097 "TERMINATE_PROCESS",
0098 "COLLECT_VPD",
0099 "UNKNOWN_OP",
0100 "GET_FUNCTION_ERR_INT",
0101 "ACK_FUNCTION_ERR_INT",
0102 "GET_ERROR_LOG",
0103 };
0104
0105 static char *control_adapter_op_names[] = {
0106 "UNKNOWN_OP",
0107 "RESET",
0108 "COLLECT_VPD",
0109 };
0110
0111 static char *download_op_names[] = {
0112 "UNKNOWN_OP",
0113 "DOWNLOAD",
0114 "VALIDATE",
0115 };
0116
0117 static char *op_str(unsigned int op, char *name_array[], int array_len)
0118 {
0119 if (op >= array_len)
0120 return "UNKNOWN_OP";
0121 return name_array[op];
0122 }
0123
0124 #define OP_STR(op, name_array) op_str(op, name_array, ARRAY_SIZE(name_array))
0125
0126 #define OP_STR_AFU(op) OP_STR(op, afu_op_names)
0127 #define OP_STR_CONTROL_ADAPTER(op) OP_STR(op, control_adapter_op_names)
0128 #define OP_STR_DOWNLOAD_ADAPTER(op) OP_STR(op, download_op_names)
0129
0130
0131 long cxl_h_attach_process(u64 unit_address,
0132 struct cxl_process_element_hcall *element,
0133 u64 *process_token, u64 *mmio_addr, u64 *mmio_size)
0134 {
0135 unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
0136 long rc;
0137
0138 CXL_H_WAIT_UNTIL_DONE(rc, retbuf, H_ATTACH_CA_PROCESS, unit_address, virt_to_phys(element));
0139 _PRINT_MSG(rc, "cxl_h_attach_process(%#.16llx, %#.16lx): %li\n",
0140 unit_address, virt_to_phys(element), rc);
0141 trace_cxl_hcall_attach(unit_address, virt_to_phys(element), retbuf[0], retbuf[1], retbuf[2], rc);
0142
0143 pr_devel("token: 0x%.8lx mmio_addr: 0x%lx mmio_size: 0x%lx\nProcess Element Structure:\n",
0144 retbuf[0], retbuf[1], retbuf[2]);
0145 cxl_dump_debug_buffer(element, sizeof(*element));
0146
0147 switch (rc) {
0148 case H_SUCCESS:
0149 *process_token = retbuf[0];
0150 if (mmio_addr)
0151 *mmio_addr = retbuf[1];
0152 if (mmio_size)
0153 *mmio_size = retbuf[2];
0154 return 0;
0155 case H_PARAMETER:
0156 case H_FUNCTION:
0157 return -EINVAL;
0158 case H_AUTHORITY:
0159 case H_RESOURCE:
0160 case H_HARDWARE:
0161 case H_STATE:
0162 case H_BUSY:
0163 return -EBUSY;
0164 default:
0165 WARN(1, "Unexpected return code: %lx", rc);
0166 return -EINVAL;
0167 }
0168 }
0169
0170
0171
0172
0173
0174 long cxl_h_detach_process(u64 unit_address, u64 process_token)
0175 {
0176 unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
0177 long rc;
0178
0179 CXL_H_WAIT_UNTIL_DONE(rc, retbuf, H_DETACH_CA_PROCESS, unit_address, process_token);
0180 _PRINT_MSG(rc, "cxl_h_detach_process(%#.16llx, 0x%.8llx): %li\n", unit_address, process_token, rc);
0181 trace_cxl_hcall_detach(unit_address, process_token, rc);
0182
0183 switch (rc) {
0184 case H_SUCCESS:
0185 return 0;
0186 case H_PARAMETER:
0187 return -EINVAL;
0188 case H_AUTHORITY:
0189 case H_RESOURCE:
0190 case H_HARDWARE:
0191 case H_STATE:
0192 case H_BUSY:
0193 return -EBUSY;
0194 default:
0195 WARN(1, "Unexpected return code: %lx", rc);
0196 return -EINVAL;
0197 }
0198 }
0199
0200
0201
0202
0203
0204
0205 static long cxl_h_control_function(u64 unit_address, u64 op,
0206 u64 p1, u64 p2, u64 p3, u64 p4, u64 *out)
0207 {
0208 unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
0209 long rc;
0210
0211 CXL_H9_WAIT_UNTIL_DONE(rc, retbuf, H_CONTROL_CA_FUNCTION, unit_address, op, p1, p2, p3, p4);
0212 _PRINT_MSG(rc, "cxl_h_control_function(%#.16llx, %s(%#llx, %#llx, %#llx, %#llx, R4: %#lx)): %li\n",
0213 unit_address, OP_STR_AFU(op), p1, p2, p3, p4, retbuf[0], rc);
0214 trace_cxl_hcall_control_function(unit_address, OP_STR_AFU(op), p1, p2, p3, p4, retbuf[0], rc);
0215
0216 switch (rc) {
0217 case H_SUCCESS:
0218 if ((op == H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT ||
0219 op == H_CONTROL_CA_FUNCTION_READ_ERR_STATE ||
0220 op == H_CONTROL_CA_FUNCTION_COLLECT_VPD))
0221 *out = retbuf[0];
0222 return 0;
0223 case H_PARAMETER:
0224 case H_FUNCTION:
0225 case H_NOT_FOUND:
0226 case H_NOT_AVAILABLE:
0227 case H_SG_LIST:
0228 return -EINVAL;
0229 case H_AUTHORITY:
0230 case H_RESOURCE:
0231 case H_HARDWARE:
0232 case H_STATE:
0233 case H_BUSY:
0234 return -EBUSY;
0235 default:
0236 WARN(1, "Unexpected return code: %lx", rc);
0237 return -EINVAL;
0238 }
0239 }
0240
0241
0242
0243
0244 long cxl_h_reset_afu(u64 unit_address)
0245 {
0246 return cxl_h_control_function(unit_address,
0247 H_CONTROL_CA_FUNCTION_RESET,
0248 0, 0, 0, 0,
0249 NULL);
0250 }
0251
0252
0253
0254
0255
0256
0257 long cxl_h_suspend_process(u64 unit_address, u64 process_token)
0258 {
0259 return cxl_h_control_function(unit_address,
0260 H_CONTROL_CA_FUNCTION_SUSPEND_PROCESS,
0261 process_token, 0, 0, 0,
0262 NULL);
0263 }
0264
0265
0266
0267
0268
0269
0270 long cxl_h_resume_process(u64 unit_address, u64 process_token)
0271 {
0272 return cxl_h_control_function(unit_address,
0273 H_CONTROL_CA_FUNCTION_RESUME_PROCESS,
0274 process_token, 0, 0, 0,
0275 NULL);
0276 }
0277
0278
0279
0280
0281
0282
0283 long cxl_h_read_error_state(u64 unit_address, u64 *state)
0284 {
0285 return cxl_h_control_function(unit_address,
0286 H_CONTROL_CA_FUNCTION_READ_ERR_STATE,
0287 0, 0, 0, 0,
0288 state);
0289 }
0290
0291
0292
0293
0294
0295
0296
0297
0298 long cxl_h_get_afu_err(u64 unit_address, u64 offset,
0299 u64 buf_address, u64 len)
0300 {
0301 return cxl_h_control_function(unit_address,
0302 H_CONTROL_CA_FUNCTION_GET_AFU_ERR,
0303 offset, buf_address, len, 0,
0304 NULL);
0305 }
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318 long cxl_h_get_config(u64 unit_address, u64 cr_num, u64 offset,
0319 u64 buf_address, u64 len)
0320 {
0321 return cxl_h_control_function(unit_address,
0322 H_CONTROL_CA_FUNCTION_GET_CONFIG,
0323 cr_num, offset, buf_address, len,
0324 NULL);
0325 }
0326
0327
0328
0329
0330
0331
0332 long cxl_h_terminate_process(u64 unit_address, u64 process_token)
0333 {
0334 return cxl_h_control_function(unit_address,
0335 H_CONTROL_CA_FUNCTION_TERMINATE_PROCESS,
0336 process_token, 0, 0, 0,
0337 NULL);
0338 }
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349 long cxl_h_collect_vpd(u64 unit_address, u64 record, u64 list_address,
0350 u64 num, u64 *out)
0351 {
0352 return cxl_h_control_function(unit_address,
0353 H_CONTROL_CA_FUNCTION_COLLECT_VPD,
0354 record, list_address, num, 0,
0355 out);
0356 }
0357
0358
0359
0360
0361 long cxl_h_get_fn_error_interrupt(u64 unit_address, u64 *reg)
0362 {
0363 return cxl_h_control_function(unit_address,
0364 H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT,
0365 0, 0, 0, 0, reg);
0366 }
0367
0368
0369
0370
0371
0372
0373 long cxl_h_ack_fn_error_interrupt(u64 unit_address, u64 value)
0374 {
0375 return cxl_h_control_function(unit_address,
0376 H_CONTROL_CA_FUNCTION_ACK_FUNCTION_ERR_INT,
0377 value, 0, 0, 0,
0378 NULL);
0379 }
0380
0381
0382
0383
0384
0385 long cxl_h_get_error_log(u64 unit_address, u64 value)
0386 {
0387 return cxl_h_control_function(unit_address,
0388 H_CONTROL_CA_FUNCTION_GET_ERROR_LOG,
0389 0, 0, 0, 0,
0390 NULL);
0391 }
0392
0393
0394
0395
0396
0397 long cxl_h_collect_int_info(u64 unit_address, u64 process_token,
0398 struct cxl_irq_info *info)
0399 {
0400 long rc;
0401
0402 BUG_ON(sizeof(*info) != sizeof(unsigned long[PLPAR_HCALL9_BUFSIZE]));
0403
0404 rc = plpar_hcall9(H_COLLECT_CA_INT_INFO, (unsigned long *) info,
0405 unit_address, process_token);
0406 _PRINT_MSG(rc, "cxl_h_collect_int_info(%#.16llx, 0x%llx): %li\n",
0407 unit_address, process_token, rc);
0408 trace_cxl_hcall_collect_int_info(unit_address, process_token, rc);
0409
0410 switch (rc) {
0411 case H_SUCCESS:
0412 pr_devel("dsisr:%#llx, dar:%#llx, dsr:%#llx, pid_tid:%#llx, afu_err:%#llx, errstat:%#llx\n",
0413 info->dsisr, info->dar, info->dsr, info->reserved,
0414 info->afu_err, info->errstat);
0415 return 0;
0416 case H_PARAMETER:
0417 return -EINVAL;
0418 case H_AUTHORITY:
0419 case H_HARDWARE:
0420 case H_STATE:
0421 return -EBUSY;
0422 default:
0423 WARN(1, "Unexpected return code: %lx", rc);
0424 return -EINVAL;
0425 }
0426 }
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438 long cxl_h_control_faults(u64 unit_address, u64 process_token,
0439 u64 control_mask, u64 reset_mask)
0440 {
0441 unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
0442 long rc;
0443
0444 memset(retbuf, 0, sizeof(retbuf));
0445
0446 rc = plpar_hcall(H_CONTROL_CA_FAULTS, retbuf, unit_address,
0447 H_CONTROL_CA_FAULTS_RESPOND_PSL, process_token,
0448 control_mask, reset_mask);
0449 _PRINT_MSG(rc, "cxl_h_control_faults(%#.16llx, 0x%llx, %#llx, %#llx): %li (%#lx)\n",
0450 unit_address, process_token, control_mask, reset_mask,
0451 rc, retbuf[0]);
0452 trace_cxl_hcall_control_faults(unit_address, process_token,
0453 control_mask, reset_mask, retbuf[0], rc);
0454
0455 switch (rc) {
0456 case H_SUCCESS:
0457 return 0;
0458 case H_PARAMETER:
0459 return -EINVAL;
0460 case H_HARDWARE:
0461 case H_STATE:
0462 case H_AUTHORITY:
0463 return -EBUSY;
0464 case H_FUNCTION:
0465 case H_NOT_FOUND:
0466 return -EINVAL;
0467 default:
0468 WARN(1, "Unexpected return code: %lx", rc);
0469 return -EINVAL;
0470 }
0471 }
0472
0473
0474
0475
0476
0477
0478 static long cxl_h_control_facility(u64 unit_address, u64 op,
0479 u64 p1, u64 p2, u64 p3, u64 p4, u64 *out)
0480 {
0481 unsigned long retbuf[PLPAR_HCALL9_BUFSIZE];
0482 long rc;
0483
0484 CXL_H9_WAIT_UNTIL_DONE(rc, retbuf, H_CONTROL_CA_FACILITY, unit_address, op, p1, p2, p3, p4);
0485 _PRINT_MSG(rc, "cxl_h_control_facility(%#.16llx, %s(%#llx, %#llx, %#llx, %#llx, R4: %#lx)): %li\n",
0486 unit_address, OP_STR_CONTROL_ADAPTER(op), p1, p2, p3, p4, retbuf[0], rc);
0487 trace_cxl_hcall_control_facility(unit_address, OP_STR_CONTROL_ADAPTER(op), p1, p2, p3, p4, retbuf[0], rc);
0488
0489 switch (rc) {
0490 case H_SUCCESS:
0491 if (op == H_CONTROL_CA_FACILITY_COLLECT_VPD)
0492 *out = retbuf[0];
0493 return 0;
0494 case H_PARAMETER:
0495 case H_FUNCTION:
0496 case H_NOT_FOUND:
0497 case H_NOT_AVAILABLE:
0498 case H_SG_LIST:
0499 return -EINVAL;
0500 case H_AUTHORITY:
0501 case H_RESOURCE:
0502 case H_HARDWARE:
0503 case H_STATE:
0504 case H_BUSY:
0505 return -EBUSY;
0506 default:
0507 WARN(1, "Unexpected return code: %lx", rc);
0508 return -EINVAL;
0509 }
0510 }
0511
0512
0513
0514
0515 long cxl_h_reset_adapter(u64 unit_address)
0516 {
0517 return cxl_h_control_facility(unit_address,
0518 H_CONTROL_CA_FACILITY_RESET,
0519 0, 0, 0, 0,
0520 NULL);
0521 }
0522
0523
0524
0525
0526
0527
0528
0529
0530 long cxl_h_collect_vpd_adapter(u64 unit_address, u64 list_address,
0531 u64 num, u64 *out)
0532 {
0533 return cxl_h_control_facility(unit_address,
0534 H_CONTROL_CA_FACILITY_COLLECT_VPD,
0535 list_address, num, 0, 0,
0536 out);
0537 }
0538
0539
0540
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558 static long cxl_h_download_facility(u64 unit_address, u64 op,
0559 u64 list_address, u64 num,
0560 u64 *out)
0561 {
0562 unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
0563 unsigned int delay, total_delay = 0;
0564 u64 token = 0;
0565 long rc;
0566
0567 if (*out != 0)
0568 token = *out;
0569
0570 memset(retbuf, 0, sizeof(retbuf));
0571 while (1) {
0572 rc = plpar_hcall(H_DOWNLOAD_CA_FACILITY, retbuf,
0573 unit_address, op, list_address, num,
0574 token);
0575 token = retbuf[0];
0576 if (rc != H_BUSY && !H_IS_LONG_BUSY(rc))
0577 break;
0578
0579 if (rc != H_BUSY) {
0580 delay = get_longbusy_msecs(rc);
0581 total_delay += delay;
0582 if (total_delay > CXL_HCALL_TIMEOUT_DOWNLOAD) {
0583 WARN(1, "Warning: Giving up waiting for CXL hcall "
0584 "%#x after %u msec\n",
0585 H_DOWNLOAD_CA_FACILITY, total_delay);
0586 rc = H_BUSY;
0587 break;
0588 }
0589 msleep(delay);
0590 }
0591 }
0592 _PRINT_MSG(rc, "cxl_h_download_facility(%#.16llx, %s(%#llx, %#llx), %#lx): %li\n",
0593 unit_address, OP_STR_DOWNLOAD_ADAPTER(op), list_address, num, retbuf[0], rc);
0594 trace_cxl_hcall_download_facility(unit_address, OP_STR_DOWNLOAD_ADAPTER(op), list_address, num, retbuf[0], rc);
0595
0596 switch (rc) {
0597 case H_SUCCESS:
0598 return 0;
0599 case H_PARAMETER:
0600 case H_FUNCTION:
0601 case H_SG_LIST:
0602 case H_BAD_DATA:
0603 return -EINVAL;
0604 case H_AUTHORITY:
0605 case H_RESOURCE:
0606 case H_HARDWARE:
0607 case H_STATE:
0608 case H_BUSY:
0609 return -EBUSY;
0610 case H_CONTINUE:
0611 *out = retbuf[0];
0612 return 1;
0613 default:
0614 WARN(1, "Unexpected return code: %lx", rc);
0615 return -EINVAL;
0616 }
0617 }
0618
0619
0620
0621
0622
0623 long cxl_h_download_adapter_image(u64 unit_address,
0624 u64 list_address, u64 num,
0625 u64 *out)
0626 {
0627 return cxl_h_download_facility(unit_address,
0628 H_DOWNLOAD_CA_FACILITY_DOWNLOAD,
0629 list_address, num, out);
0630 }
0631
0632
0633
0634
0635
0636 long cxl_h_validate_adapter_image(u64 unit_address,
0637 u64 list_address, u64 num,
0638 u64 *out)
0639 {
0640 return cxl_h_download_facility(unit_address,
0641 H_DOWNLOAD_CA_FACILITY_VALIDATE,
0642 list_address, num, out);
0643 }