Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Copyright 2015 IBM Corp.
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 /* perform a reset */
0027 #define H_CONTROL_CA_FUNCTION_SUSPEND_PROCESS         2 /* suspend a process from being executed */
0028 #define H_CONTROL_CA_FUNCTION_RESUME_PROCESS          3 /* resume a process to be executed */
0029 #define H_CONTROL_CA_FUNCTION_READ_ERR_STATE          4 /* read the error state */
0030 #define H_CONTROL_CA_FUNCTION_GET_AFU_ERR             5 /* collect the AFU error buffer */
0031 #define H_CONTROL_CA_FUNCTION_GET_CONFIG              6 /* collect configuration record */
0032 #define H_CONTROL_CA_FUNCTION_GET_DOWNLOAD_STATE      7 /* query to return download status */
0033 #define H_CONTROL_CA_FUNCTION_TERMINATE_PROCESS       8 /* terminate the process before completion */
0034 #define H_CONTROL_CA_FUNCTION_COLLECT_VPD             9 /* collect VPD */
0035 #define H_CONTROL_CA_FUNCTION_GET_FUNCTION_ERR_INT   11 /* read the function-wide error data based on an interrupt */
0036 #define H_CONTROL_CA_FUNCTION_ACK_FUNCTION_ERR_INT   12 /* acknowledge function-wide error data based on an interrupt */
0037 #define H_CONTROL_CA_FUNCTION_GET_ERROR_LOG          13 /* retrieve the Platform Log ID (PLID) of an error log */
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 /* perform a reset */
0043 #define H_CONTROL_CA_FACILITY_COLLECT_VPD       2 /* collect VPD */
0044 
0045 #define H_DOWNLOAD_CA_FACILITY_DOWNLOAD         1 /* download adapter image */
0046 #define H_DOWNLOAD_CA_FACILITY_VALIDATE         2 /* validate adapter image */
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",       /* 0 undefined */
0090     "RESET",        /* 1 */
0091     "SUSPEND_PROCESS",  /* 2 */
0092     "RESUME_PROCESS",   /* 3 */
0093     "READ_ERR_STATE",   /* 4 */
0094     "GET_AFU_ERR",      /* 5 */
0095     "GET_CONFIG",       /* 6 */
0096     "GET_DOWNLOAD_STATE",   /* 7 */
0097     "TERMINATE_PROCESS",    /* 8 */
0098     "COLLECT_VPD",      /* 9 */
0099     "UNKNOWN_OP",       /* 10 undefined */
0100     "GET_FUNCTION_ERR_INT", /* 11 */
0101     "ACK_FUNCTION_ERR_INT", /* 12 */
0102     "GET_ERROR_LOG",    /* 13 */
0103 };
0104 
0105 static char *control_adapter_op_names[] = {
0106     "UNKNOWN_OP",       /* 0 undefined */
0107     "RESET",        /* 1 */
0108     "COLLECT_VPD",      /* 2 */
0109 };
0110 
0111 static char *download_op_names[] = {
0112     "UNKNOWN_OP",       /* 0 undefined */
0113     "DOWNLOAD",     /* 1 */
0114     "VALIDATE",     /* 2 */
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:       /* The process info is attached to the coherent platform function */
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:     /* An incorrect parameter was supplied. */
0156     case H_FUNCTION:      /* The function is not supported. */
0157         return -EINVAL;
0158     case H_AUTHORITY:     /* The partition does not have authority to perform this hcall */
0159     case H_RESOURCE:      /* The coherent platform function does not have enough additional resource to attach the process */
0160     case H_HARDWARE:      /* A hardware event prevented the attach operation */
0161     case H_STATE:         /* The coherent platform function is not in a valid 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  * cxl_h_detach_process - Detach a process element from a coherent
0172  *                        platform function.
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:       /* The process was detached from the coherent platform function */
0185         return 0;
0186     case H_PARAMETER:     /* An incorrect parameter was supplied. */
0187         return -EINVAL;
0188     case H_AUTHORITY:     /* The partition does not have authority to perform this hcall */
0189     case H_RESOURCE:      /* The function has page table mappings for MMIO */
0190     case H_HARDWARE:      /* A hardware event prevented the detach operation */
0191     case H_STATE:         /* The coherent platform function is not in a valid 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  * cxl_h_control_function - This H_CONTROL_CA_FUNCTION hypervisor call allows
0202  *                          the partition to manipulate or query
0203  *                          certain coherent platform function behaviors.
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:       /* The operation is completed for the coherent platform function */
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:     /* An incorrect parameter was supplied. */
0224     case H_FUNCTION:      /* The function is not supported. */
0225     case H_NOT_FOUND:     /* The operation supplied was not valid */
0226     case H_NOT_AVAILABLE: /* The operation cannot be performed because the AFU has not been downloaded */
0227     case H_SG_LIST:       /* An block list entry was invalid */
0228         return -EINVAL;
0229     case H_AUTHORITY:     /* The partition does not have authority to perform this hcall */
0230     case H_RESOURCE:      /* The function has page table mappings for MMIO */
0231     case H_HARDWARE:      /* A hardware event prevented the attach operation */
0232     case H_STATE:         /* The coherent platform function is not in a valid 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  * cxl_h_reset_afu - Perform a reset to the coherent platform function.
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  * cxl_h_suspend_process - Suspend a process from being executed
0254  * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
0255  *              process was attached.
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  * cxl_h_resume_process - Resume a process to be executed
0267  * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
0268  *              process was attached.
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  * cxl_h_read_error_state - Checks the error state of the coherent
0280  *                          platform function.
0281  * R4 contains the error state
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  * cxl_h_get_afu_err - collect the AFU error buffer
0293  * Parameter1 = byte offset into error buffer to retrieve, valid values
0294  *              are between 0 and (ibm,error-buffer-size - 1)
0295  * Parameter2 = 4K aligned real address of error buffer, to be filled in
0296  * Parameter3 = length of error buffer, valid values are 4K or less
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  * cxl_h_get_config - collect configuration record for the
0309  *                    coherent platform function
0310  * Parameter1 = # of configuration record to retrieve, valid values are
0311  *              between 0 and (ibm,#config-records - 1)
0312  * Parameter2 = byte offset into configuration record to retrieve,
0313  *              valid values are between 0 and (ibm,config-record-size - 1)
0314  * Parameter3 = 4K aligned real address of configuration record buffer,
0315  *              to be filled in
0316  * Parameter4 = length of configuration buffer, valid values are 4K or less
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  * cxl_h_terminate_process - Terminate the process before completion
0329  * Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
0330  *              process was attached.
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  * cxl_h_collect_vpd - Collect VPD for the coherent platform function.
0342  * Parameter1 = # of VPD record to retrieve, valid values are between 0
0343  *              and (ibm,#config-records - 1).
0344  * Parameter2 = 4K naturally aligned real buffer containing block
0345  *              list entries
0346  * Parameter3 = number of block list entries in the block list, valid
0347  *              values are between 0 and 256
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  * cxl_h_get_fn_error_interrupt - Read the function-wide error data based on an interrupt
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  * cxl_h_ack_fn_error_interrupt - Acknowledge function-wide error data
0370  *                                based on an interrupt
0371  * Parameter1 = value to write to the function-wide error interrupt register
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  * cxl_h_get_error_log - Retrieve the Platform Log ID (PLID) of
0383  *                       an error log
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  * cxl_h_collect_int_info - Collect interrupt info about a coherent
0395  *                          platform function after an interrupt occurred.
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:     /* The interrupt info is returned in return registers. */
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:   /* An incorrect parameter was supplied. */
0417         return -EINVAL;
0418     case H_AUTHORITY:   /* The partition does not have authority to perform this hcall. */
0419     case H_HARDWARE:    /* A hardware event prevented the collection of the interrupt info.*/
0420     case H_STATE:       /* The coherent platform function is not in a valid state to collect interrupt info. */
0421         return -EBUSY;
0422     default:
0423         WARN(1, "Unexpected return code: %lx", rc);
0424         return -EINVAL;
0425     }
0426 }
0427 
0428 /*
0429  * cxl_h_control_faults - Control the operation of a coherent platform
0430  *                        function after a fault occurs.
0431  *
0432  * Parameters
0433  *    control-mask: value to control the faults
0434  *                  looks like PSL_TFC_An shifted >> 32
0435  *    reset-mask: mask to control reset of function faults
0436  *                Set reset_mask = 1 to reset PSL errors
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:    /* Faults were successfully controlled for the function. */
0457         return 0;
0458     case H_PARAMETER:  /* An incorrect parameter was supplied. */
0459         return -EINVAL;
0460     case H_HARDWARE:   /* A hardware event prevented the control of faults. */
0461     case H_STATE:      /* The function was in an invalid state. */
0462     case H_AUTHORITY:  /* The partition does not have authority to perform this hcall; the coherent platform facilities may need to be licensed. */
0463         return -EBUSY;
0464     case H_FUNCTION:   /* The function is not supported */
0465     case H_NOT_FOUND:  /* The operation supplied was not valid */
0466         return -EINVAL;
0467     default:
0468         WARN(1, "Unexpected return code: %lx", rc);
0469         return -EINVAL;
0470     }
0471 }
0472 
0473 /*
0474  * cxl_h_control_facility - This H_CONTROL_CA_FACILITY hypervisor call
0475  *                          allows the partition to manipulate or query
0476  *                          certain coherent platform facility behaviors.
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:       /* The operation is completed for the coherent platform facility */
0491         if (op == H_CONTROL_CA_FACILITY_COLLECT_VPD)
0492             *out = retbuf[0];
0493         return 0;
0494     case H_PARAMETER:     /* An incorrect parameter was supplied. */
0495     case H_FUNCTION:      /* The function is not supported. */
0496     case H_NOT_FOUND:     /* The operation supplied was not valid */
0497     case H_NOT_AVAILABLE: /* The operation cannot be performed because the AFU has not been downloaded */
0498     case H_SG_LIST:       /* An block list entry was invalid */
0499         return -EINVAL;
0500     case H_AUTHORITY:     /* The partition does not have authority to perform this hcall */
0501     case H_RESOURCE:      /* The function has page table mappings for MMIO */
0502     case H_HARDWARE:      /* A hardware event prevented the attach operation */
0503     case H_STATE:         /* The coherent platform facility is not in a valid 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  * cxl_h_reset_adapter - Perform a reset to the coherent platform facility.
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  * cxl_h_collect_vpd - Collect VPD for the coherent platform function.
0525  * Parameter1 = 4K naturally aligned real buffer containing block
0526  *              list entries
0527  * Parameter2 = number of block list entries in the block list, valid
0528  *              values are between 0 and 256
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  * cxl_h_download_facility - This H_DOWNLOAD_CA_FACILITY
0541  *                    hypervisor call provide platform support for
0542  *                    downloading a base adapter image to the coherent
0543  *                    platform facility, and for validating the entire
0544  *                    image after the download.
0545  * Parameters
0546  *    op: operation to perform to the coherent platform function
0547  *      Download: operation = 1, the base image in the coherent platform
0548  *                               facility is first erased, and then
0549  *                               programmed using the image supplied
0550  *                               in the scatter/gather list.
0551  *      Validate: operation = 2, the base image in the coherent platform
0552  *                               facility is compared with the image
0553  *                               supplied in the scatter/gather list.
0554  *    list_address: 4K naturally aligned real buffer containing
0555  *                  scatter/gather list entries.
0556  *    num: number of block list entries in the scatter/gather list.
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:       /* The operation is completed for the coherent platform facility */
0598         return 0;
0599     case H_PARAMETER:     /* An incorrect parameter was supplied */
0600     case H_FUNCTION:      /* The function is not supported. */
0601     case H_SG_LIST:       /* An block list entry was invalid */
0602     case H_BAD_DATA:      /* Image verification failed */
0603         return -EINVAL;
0604     case H_AUTHORITY:     /* The partition does not have authority to perform this hcall */
0605     case H_RESOURCE:      /* The function has page table mappings for MMIO */
0606     case H_HARDWARE:      /* A hardware event prevented the attach operation */
0607     case H_STATE:         /* The coherent platform facility is not in a valid state */
0608     case H_BUSY:
0609         return -EBUSY;
0610     case H_CONTINUE:
0611         *out = retbuf[0];
0612         return 1;  /* More data is needed for the complete image */
0613     default:
0614         WARN(1, "Unexpected return code: %lx", rc);
0615         return -EINVAL;
0616     }
0617 }
0618 
0619 /*
0620  * cxl_h_download_adapter_image - Download the base image to the coherent
0621  *                                platform facility.
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  * cxl_h_validate_adapter_image - Validate the base image in the coherent
0634  *                                platform facility.
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 }