/* SPDX-License-Identifier: BSD-3-Clause */ /* Copyright(c) 2007-2022 Intel Corporation */ /** ***************************************************************************** * @file sal_ctrl_services.c * * @ingroup SalCtrl * * @description * This file contains the core of the service controller implementation. * *****************************************************************************/ /* QAT-API includes */ #include "cpa.h" #include "cpa_cy_key.h" #include "cpa_cy_ln.h" #include "cpa_cy_dh.h" #include "cpa_cy_dsa.h" #include "cpa_cy_rsa.h" #include "cpa_cy_ec.h" #include "cpa_cy_prime.h" #include "cpa_cy_sym.h" #include "cpa_dc.h" /* QAT utils includes */ #include "qat_utils.h" /* ADF includes */ #include "icp_adf_init.h" #include "icp_adf_transport.h" #include "icp_accel_devices.h" #include "icp_adf_cfg.h" #include "icp_adf_init.h" #include "icp_adf_accel_mgr.h" #include "icp_adf_debug.h" /* FW includes */ #include "icp_qat_fw_la.h" /* SAL includes */ #include "lac_mem.h" #include "lac_mem_pools.h" #include "lac_list.h" #include "lac_hooks.h" #include "sal_string_parse.h" #include "lac_common.h" #include "lac_sal_types.h" #include "lac_sal.h" #include "lac_sal_ctrl.h" #include "icp_sal_versions.h" #define MAX_SUBSYSTEM_RETRY 64 static char *subsystem_name = "SAL"; /**< Name used by ADF to identify this component. */ static char *cy_dir_name = "cy"; static char *asym_dir_name = "asym"; static char *sym_dir_name = "sym"; static char *dc_dir_name = "dc"; /**< Stats dir names. */ static char *ver_file_name = "version"; static subservice_registation_handle_t sal_service_reg_handle; /**< Data structure used by ADF to keep a reference to this component. */ /* * @ingroup SalCtrl * @description * This function is used to parse the results from ADF * in response to ServiceEnabled query.The results are * semi-colon separated. Internally, the bitmask represented * by the enabled_service is used to track which features are enabled. * * @context * This functions is called from the SalCtrl_ServiceEventInit function. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * @param[in] device pointer to icp_accel_dev_t structure * @param[in] pEnabledServices pointer to memory where enabled services will * be written. * @retval Status */ CpaStatus SalCtrl_GetEnabledServices(icp_accel_dev_t *device, Cpa32U *pEnabledServices) { CpaStatus status = CPA_STATUS_SUCCESS; char param_value[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 }; char *token = NULL; char *running = NULL; *pEnabledServices = 0; memset(param_value, 0, ADF_CFG_MAX_VAL_LEN_IN_BYTES); status = icp_adf_cfgGetParamValue(device, LAC_CFG_SECTION_GENERAL, "ServicesEnabled", param_value); if (CPA_STATUS_SUCCESS == status) { running = param_value; token = strsep(&running, ";"); while (NULL != token) { do { if (strncmp(token, "asym", strlen("asym")) == 0) { *pEnabledServices |= SAL_SERVICE_TYPE_CRYPTO_ASYM; break; } if (strncmp(token, "sym", strlen("sym")) == 0) { *pEnabledServices |= SAL_SERVICE_TYPE_CRYPTO_SYM; break; } if (strncmp(token, "cy", strlen("cy")) == 0) { *pEnabledServices |= SAL_SERVICE_TYPE_CRYPTO; break; } if (strncmp(token, "dc", strlen("dc")) == 0) { *pEnabledServices |= SAL_SERVICE_TYPE_COMPRESSION; break; } QAT_UTILS_LOG( "Error parsing enabled services from ADF.\n"); return CPA_STATUS_FAIL; } while (0); token = strsep(&running, ";"); } } else { QAT_UTILS_LOG("Failed to get enabled services from ADF.\n"); } return status; } /* * @ingroup SalCtrl * @description * This function is used to check whether a service is enabled * * @context * This functions is called from the SalCtrl_ServiceEventInit function. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * param[in] enabled_services It is the bitmask for the enabled services * param[in] service It is the service we want to check for */ CpaBoolean SalCtrl_IsServiceEnabled(Cpa32U enabled_services, sal_service_type_t service) { return (CpaBoolean)((enabled_services & (Cpa32U)(service)) != 0); } /* * @ingroup SalCtrl * @description * This function is used to check whether enabled services has associated * hardware capability support * * @context * This functions is called from the SalCtrl_ServiceEventInit function. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * param[in] device A pointer to an icp_accel_dev_t * param[in] enabled_services It is the bitmask for the enabled services */ CpaStatus SalCtrl_GetSupportedServices(icp_accel_dev_t *device, Cpa32U enabled_services) { CpaStatus status = CPA_STATUS_SUCCESS; Cpa32U capabilitiesMask = 0; status = icp_amgr_getAccelDevCapabilities(device, &capabilitiesMask); if (CPA_STATUS_SUCCESS == status) { if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO)) { if (!(capabilitiesMask & ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC) || !(capabilitiesMask & ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC)) { QAT_UTILS_LOG( "Device does not support Crypto service\n"); status = CPA_STATUS_FAIL; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO_ASYM)) { if (!(capabilitiesMask & ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC)) { QAT_UTILS_LOG( "Device does not support Asym service\n"); status = CPA_STATUS_FAIL; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO_SYM)) { if (!(capabilitiesMask & ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC)) { QAT_UTILS_LOG( "Device does not support Sym service\n"); status = CPA_STATUS_FAIL; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_COMPRESSION)) { if (!(capabilitiesMask & ICP_ACCEL_CAPABILITIES_COMPRESSION)) { QAT_UTILS_LOG( "Device does not support Compression service.\n"); status = CPA_STATUS_FAIL; } } } return status; } /************************************************************************* * @ingroup SalCtrl * @description * This function is used to check if a service is supported * on the device. The key difference between this and * SalCtrl_GetSupportedServices() is that the latter treats it as * an error if the service is unsupported. * * @context * This can be called anywhere. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * param[in] device * param[in] service service or services to check * *************************************************************************/ CpaBoolean SalCtrl_IsServiceSupported(icp_accel_dev_t *device, sal_service_type_t service_to_check) { CpaStatus status = CPA_STATUS_SUCCESS; Cpa32U capabilitiesMask = 0; CpaBoolean service_supported = CPA_TRUE; if (!(SalCtrl_IsServiceEnabled((Cpa32U)service_to_check, SAL_SERVICE_TYPE_CRYPTO)) && !(SalCtrl_IsServiceEnabled((Cpa32U)service_to_check, SAL_SERVICE_TYPE_CRYPTO_ASYM)) && !(SalCtrl_IsServiceEnabled((Cpa32U)service_to_check, SAL_SERVICE_TYPE_CRYPTO_SYM)) && !(SalCtrl_IsServiceEnabled((Cpa32U)service_to_check, SAL_SERVICE_TYPE_COMPRESSION))) { QAT_UTILS_LOG("Invalid service type\n"); service_supported = CPA_FALSE; } status = icp_amgr_getAccelDevCapabilities(device, &capabilitiesMask); if (CPA_STATUS_SUCCESS != status) { QAT_UTILS_LOG("Can not get device capabilities.\n"); return CPA_FALSE; } if (SalCtrl_IsServiceEnabled((Cpa32U)service_to_check, SAL_SERVICE_TYPE_CRYPTO)) { if (!(capabilitiesMask & ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC) || !(capabilitiesMask & ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC)) { QAT_UTILS_LOG( "Device does not support Crypto service\n"); service_supported = CPA_FALSE; } } if (SalCtrl_IsServiceEnabled((Cpa32U)service_to_check, SAL_SERVICE_TYPE_CRYPTO_ASYM)) { if (!(capabilitiesMask & ICP_ACCEL_CAPABILITIES_CRYPTO_ASYMMETRIC)) { QAT_UTILS_LOG("Device does not support Asym service\n"); service_supported = CPA_FALSE; } } if (SalCtrl_IsServiceEnabled((Cpa32U)service_to_check, SAL_SERVICE_TYPE_CRYPTO_SYM)) { if (!(capabilitiesMask & ICP_ACCEL_CAPABILITIES_CRYPTO_SYMMETRIC)) { QAT_UTILS_LOG("Device does not support Sym service\n"); service_supported = CPA_FALSE; } } if (SalCtrl_IsServiceEnabled((Cpa32U)service_to_check, SAL_SERVICE_TYPE_COMPRESSION)) { if (!(capabilitiesMask & ICP_ACCEL_CAPABILITIES_COMPRESSION)) { QAT_UTILS_LOG( "Device does not support Compression service.\n"); service_supported = CPA_FALSE; } } return service_supported; } /* * @ingroup SalCtrl * @description * This function is used to retrieve how many instances are * to be configured for process specific service. * * @context * This functions is called from the SalCtrl_ServiceEventInit function. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * @param[in] device A pointer to an icp_accel_dev_t * @param[in] key Represents the parameter's name we want to query * @param[out] pCount Pointer to memory where num instances will be stored * @retval status returned status from ADF or _FAIL if number of instances * is out of range for the device. */ static CpaStatus SalCtrl_GetInstanceCount(icp_accel_dev_t *device, char *key, Cpa32U *pCount) { CpaStatus status = CPA_STATUS_FAIL; char param_value[ADF_CFG_MAX_VAL_LEN_IN_BYTES]; memset(param_value, 0, ADF_CFG_MAX_VAL_LEN_IN_BYTES); status = icp_adf_cfgGetParamValue(device, icpGetProcessName(), key, param_value); if (CPA_STATUS_SUCCESS == status) { *pCount = (Cpa32U)(Sal_Strtoul(param_value, NULL, SAL_CFG_BASE_DEC)); if (*pCount > SAL_MAX_NUM_INSTANCES_PER_DEV) { QAT_UTILS_LOG("Number of instances is out of range.\n"); status = CPA_STATUS_FAIL; } } return status; } /************************************************************************** * @ingroup SalCtrl * @description * This function calls the shutdown function on all the * service instances. * It also frees all service instance memory allocated at Init. * * @context * This function is called from the SalCtrl_ServiceEventShutdown * function. * * @assumptions * params[in] should not be NULL * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * @param[in] device An icp_accel_dev_t* type * @param[in] services A pointer to the container of services * @param[in] dbg_dir A pointer to the debug directory * @param[in] svc_type The type of the service instance * ****************************************************************************/ static CpaStatus SalCtrl_ServiceShutdown(icp_accel_dev_t *device, sal_list_t **services, debug_dir_info_t **debug_dir, sal_service_type_t svc_type) { CpaStatus status = CPA_STATUS_SUCCESS; sal_list_t *dyn_service = NULL; sal_service_t *inst = NULL; /* Call Shutdown function for each service instance */ SAL_FOR_EACH(*services, sal_service_t, device, shutdown, status); if (*debug_dir) { icp_adf_debugRemoveDir(*debug_dir); LAC_OS_FREE(*debug_dir); *debug_dir = NULL; } if (!icp_adf_is_dev_in_reset(device)) { dyn_service = *services; while (dyn_service) { inst = (sal_service_t *)SalList_getObject(dyn_service); if (CPA_TRUE == inst->is_dyn) { icp_adf_putDynInstance(device, (adf_service_type_t) svc_type, inst->instance); } dyn_service = SalList_next(dyn_service); } /* Free Sal services controller memory */ SalList_free(services); } else { sal_list_t *curr_element = NULL; sal_service_t *service = NULL; curr_element = *services; while (NULL != curr_element) { service = (sal_service_t *)SalList_getObject(curr_element); service->state = SAL_SERVICE_STATE_RESTARTING; curr_element = SalList_next(curr_element); } } return status; } static CpaStatus selectGeneration(device_type_t deviceType, sal_service_t *pInst) { switch (deviceType) { case DEVICE_C62X: case DEVICE_C62XVF: case DEVICE_DH895XCC: case DEVICE_DH895XCCVF: case DEVICE_C3XXX: case DEVICE_C3XXXVF: case DEVICE_200XX: case DEVICE_200XXVF: pInst->gen = GEN2; break; case DEVICE_C4XXX: case DEVICE_C4XXXVF: pInst->gen = GEN3; break; case DEVICE_4XXX: case DEVICE_4XXXVF: pInst->gen = GEN4; break; default: QAT_UTILS_LOG("deviceType not initialised\n"); return CPA_STATUS_FAIL; } return CPA_STATUS_SUCCESS; } /************************************************************************* * @ingroup SalCtrl * @description * This function is used to initialise the service instances. * It allocates memory for service instances and invokes the * Init function on them. * * @context * This function is called from the SalCtrl_ServiceEventInit function. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * @param[in] device An icp_accel_dev_t* type * @param[in] services A pointer to the container of services * @param[in] dbg_dir A pointer to the debug directory * @param[in] dbg_dir_name Name of the debug directory * @param[in] tail_list SAL's list of services * @param[in] instance_count Number of instances * @param[in] svc_type The type of the service instance * *************************************************************************/ static CpaStatus SalCtrl_ServiceInit(icp_accel_dev_t *device, sal_list_t **services, debug_dir_info_t **dbg_dir, char *dbg_dir_name, sal_list_t *tail_list, Cpa32U instance_count, sal_service_type_t svc_type) { CpaStatus status = CPA_STATUS_SUCCESS; sal_service_t *pInst = NULL; Cpa32U i = 0; debug_dir_info_t *debug_dir = NULL; debug_dir = LAC_OS_MALLOC(sizeof(debug_dir_info_t)); if (NULL == debug_dir) { QAT_UTILS_LOG("Failed to allocate memory for debug dir.\n"); return CPA_STATUS_RESOURCE; } debug_dir->name = dbg_dir_name; debug_dir->parent = NULL; status = icp_adf_debugAddDir(device, debug_dir); if (CPA_STATUS_SUCCESS != status) { QAT_UTILS_LOG("Failed to add debug dir.\n"); LAC_OS_FREE(debug_dir); debug_dir = NULL; return status; } if (!icp_adf_is_dev_in_reset(device)) { for (i = 0; i < instance_count; i++) { status = SalCtrl_ServiceCreate(svc_type, i, &pInst); if (CPA_STATUS_SUCCESS != status) { break; } pInst->debug_parent_dir = debug_dir; pInst->capabilitiesMask = device->accelCapabilitiesMask; status = selectGeneration(device->deviceType, pInst); if (CPA_STATUS_SUCCESS == status) { status = SalList_add(services, &tail_list, pInst); } if (CPA_STATUS_SUCCESS != status) { free(pInst, M_QAT); } } } else { sal_list_t *curr_element = *services; sal_service_t *service = NULL; while (NULL != curr_element) { service = (sal_service_t *)SalList_getObject(curr_element); service->debug_parent_dir = debug_dir; if (CPA_TRUE == service->isInstanceStarted) { icp_qa_dev_get(device); } curr_element = SalList_next(curr_element); } } if (CPA_STATUS_SUCCESS != status) { QAT_UTILS_LOG("Failed to allocate all instances.\n"); icp_adf_debugRemoveDir(debug_dir); LAC_OS_FREE(debug_dir); debug_dir = NULL; SalList_free(services); return status; } /* Call init function for each service instance */ SAL_FOR_EACH(*services, sal_service_t, device, init, status); if (CPA_STATUS_SUCCESS != status) { QAT_UTILS_LOG("Failed to initialise all service instances.\n"); /* shutdown all instances initialised before error */ SAL_FOR_EACH_STATE(*services, sal_service_t, device, shutdown, SAL_SERVICE_STATE_INITIALIZED); icp_adf_debugRemoveDir(debug_dir); LAC_OS_FREE(debug_dir); debug_dir = NULL; SalList_free(services); return status; } /* initialize the debug directory for relevant service */ *dbg_dir = debug_dir; return status; } /************************************************************************** * @ingroup SalCtrl * @description * This function calls the start function on all the service instances. * * @context * This function is called from the SalCtrl_ServiceEventStart function. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * @param[in] device An icp_accel_dev_t* type * @param[in] services A pointer to the container of services * **************************************************************************/ static CpaStatus SalCtrl_ServiceStart(icp_accel_dev_t *device, sal_list_t *services) { CpaStatus status = CPA_STATUS_SUCCESS; /* Call Start function for each service instance */ SAL_FOR_EACH(services, sal_service_t, device, start, status); if (CPA_STATUS_SUCCESS != status) { QAT_UTILS_LOG("Failed to start all instances.\n"); /* stop all instances started before error */ SAL_FOR_EACH_STATE(services, sal_service_t, device, stop, SAL_SERVICE_STATE_RUNNING); return status; } if (icp_adf_is_dev_in_reset(device)) { sal_list_t *curr_element = services; sal_service_t *service = NULL; while (NULL != curr_element) { service = (sal_service_t *)SalList_getObject(curr_element); if (service->notification_cb) { service->notification_cb( service, service->cb_tag, CPA_INSTANCE_EVENT_RESTARTED); } curr_element = SalList_next(curr_element); } } return status; } /**************************************************************************** * @ingroup SalCtrl * @description * This function calls the stop function on all the * service instances. * * @context * This function is called from the SalCtrl_ServiceEventStop function. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * @param[in] device An icp_accel_dev_t* type * @param[in] services A pointer to the container of services * *************************************************************************/ static CpaStatus SalCtrl_ServiceStop(icp_accel_dev_t *device, sal_list_t *services) { CpaStatus status = CPA_STATUS_SUCCESS; /* Calling restarting functions */ if (icp_adf_is_dev_in_reset(device)) { sal_list_t *curr_element = services; sal_service_t *service = NULL; while (NULL != curr_element) { service = (sal_service_t *)SalList_getObject(curr_element); if (service->notification_cb) { service->notification_cb( service, service->cb_tag, CPA_INSTANCE_EVENT_RESTARTING); } curr_element = SalList_next(curr_element); } } /* Call Stop function for each service instance */ SAL_FOR_EACH(services, sal_service_t, device, stop, status); return status; } static CpaStatus SalCtrl_ServiceError(icp_accel_dev_t *device, sal_list_t *services) { CpaStatus status = CPA_STATUS_SUCCESS; /* Calling error handling functions */ sal_list_t *curr_element = services; sal_service_t *service = NULL; while (NULL != curr_element) { service = (sal_service_t *)SalList_getObject(curr_element); if (service->notification_cb) { service->notification_cb( service, service->cb_tag, CPA_INSTANCE_EVENT_FATAL_ERROR); } curr_element = SalList_next(curr_element); } return status; } /* * @ingroup SalCtrl * @description * This function is used to print hardware and software versions in proc * filesystem entry via ADF Debug interface * * @context * This functions is called from proc filesystem interface * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * @param[in] private_data A pointer to a private data passed to the * function while adding a debug file. * @param[out] data Pointer to a buffer where version information * needs to be printed to. * @param[in] size Size of a buffer pointed by data. * @param[in] offset Offset in a debug file * * @retval 0 This function always returns 0 */ static int SalCtrl_VersionDebug(void *private_data, char *data, int size, int offset) { CpaStatus status = CPA_STATUS_SUCCESS; Cpa32U len = 0; icp_accel_dev_t *device = (icp_accel_dev_t *)private_data; char param_value[ADF_CFG_MAX_VAL_LEN_IN_BYTES] = { 0 }; len += snprintf( data + len, size - len, SEPARATOR BORDER " Hardware and Software versions for device %d " BORDER "\n" SEPARATOR, device->accelId); memset(param_value, 0, ADF_CFG_MAX_VAL_LEN_IN_BYTES); status = icp_adf_cfgGetParamValue(device, LAC_CFG_SECTION_GENERAL, ICP_CFG_HW_REV_ID_KEY, param_value); LAC_CHECK_STATUS(status); len += snprintf(data + len, size - len, " Hardware Version: %s %s \n", param_value, get_sku_info(device->sku)); memset(param_value, 0, ADF_CFG_MAX_VAL_LEN_IN_BYTES); status = icp_adf_cfgGetParamValue(device, LAC_CFG_SECTION_GENERAL, ICP_CFG_UOF_VER_KEY, param_value); LAC_CHECK_STATUS(status); len += snprintf(data + len, size - len, " Firmware Version: %s \n", param_value); memset(param_value, 0, ADF_CFG_MAX_VAL_LEN_IN_BYTES); status = icp_adf_cfgGetParamValue(device, LAC_CFG_SECTION_GENERAL, ICP_CFG_MMP_VER_KEY, param_value); LAC_CHECK_STATUS(status); len += snprintf(data + len, size - len, " MMP Version: %s \n", param_value); len += snprintf(data + len, size - len, " Driver Version: %d.%d.%d \n", SAL_INFO2_DRIVER_SW_VERSION_MAJ_NUMBER, SAL_INFO2_DRIVER_SW_VERSION_MIN_NUMBER, SAL_INFO2_DRIVER_SW_VERSION_PATCH_NUMBER); memset(param_value, 0, ADF_CFG_MAX_VAL_LEN_IN_BYTES); status = icp_adf_cfgGetParamValue(device, LAC_CFG_SECTION_GENERAL, ICP_CFG_LO_COMPATIBLE_DRV_KEY, param_value); LAC_CHECK_STATUS(status); len += snprintf(data + len, size - len, " Lowest Compatible Driver: %s \n", param_value); len += snprintf(data + len, size - len, " QuickAssist API CY Version: %d.%d \n", CPA_CY_API_VERSION_NUM_MAJOR, CPA_CY_API_VERSION_NUM_MINOR); len += snprintf(data + len, size - len, " QuickAssist API DC Version: %d.%d \n", CPA_DC_API_VERSION_NUM_MAJOR, CPA_DC_API_VERSION_NUM_MINOR); len += snprintf(data + len, size - len, SEPARATOR); return 0; } /************************************************************************** * @ingroup SalCtrl * @description * This function calls the shutdown function on all the service * instances. It also frees all service instance memory * allocated at Init. * * @context * This function is called from the SalCtrl_ServiceEventHandler function. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * @param[in] device An icp_accel_dev_t* type * @param[in] enabled_services Services enabled by user * ****************************************************************************/ static CpaStatus SalCtrl_ServiceEventShutdown(icp_accel_dev_t *device, Cpa32U enabled_services) { CpaStatus status = CPA_STATUS_SUCCESS; CpaStatus ret_status = CPA_STATUS_SUCCESS; sal_t *service_container = (sal_t *)device->pSalHandle; if (NULL == service_container) { QAT_UTILS_LOG("Private data is NULL\n"); return CPA_STATUS_FATAL; } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO)) { status = SalCtrl_ServiceShutdown(device, &service_container->crypto_services, &service_container->cy_dir, SAL_SERVICE_TYPE_CRYPTO); if (CPA_STATUS_SUCCESS != status) { ret_status = status; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO_ASYM)) { status = SalCtrl_ServiceShutdown(device, &service_container->asym_services, &service_container->asym_dir, SAL_SERVICE_TYPE_CRYPTO_ASYM); if (CPA_STATUS_SUCCESS != status) { ret_status = status; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO_SYM)) { status = SalCtrl_ServiceShutdown(device, &service_container->sym_services, &service_container->sym_dir, SAL_SERVICE_TYPE_CRYPTO_SYM); if (CPA_STATUS_SUCCESS != status) { ret_status = status; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_COMPRESSION)) { status = SalCtrl_ServiceShutdown( device, &service_container->compression_services, &service_container->dc_dir, SAL_SERVICE_TYPE_COMPRESSION); if (CPA_STATUS_SUCCESS != status) { ret_status = status; } } if (service_container->ver_file) { icp_adf_debugRemoveFile(service_container->ver_file); LAC_OS_FREE(service_container->ver_file); service_container->ver_file = NULL; } if (!icp_adf_is_dev_in_reset(device)) { /* Free container also */ free(service_container, M_QAT); device->pSalHandle = NULL; } return ret_status; } /************************************************************************* * @ingroup SalCtrl * @description * This function is used to initialize the service instances. * It first checks (via ADF query) which services are enabled in the * system and the number of each services. * It then invokes the init function on them which creates the * instances and allocates memory for them. * * @context * This function is called from the SalCtrl_ServiceEventHandler function. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * @param[in] device An icp_accel_dev_t* type * @param[in] enabled_services Services enabled by user * *************************************************************************/ static CpaStatus SalCtrl_ServiceEventInit(icp_accel_dev_t *device, Cpa32U enabled_services) { sal_t *service_container = NULL; CpaStatus status = CPA_STATUS_SUCCESS; sal_list_t *tail_list = NULL; Cpa32U instance_count = 0; status = SalCtrl_GetSupportedServices(device, enabled_services); if (CPA_STATUS_SUCCESS != status) { QAT_UTILS_LOG("Failed to get supported services.\n"); return status; } if (!icp_adf_is_dev_in_reset(device)) { service_container = malloc(sizeof(sal_t), M_QAT, M_WAITOK); device->pSalHandle = service_container; service_container->asym_services = NULL; service_container->sym_services = NULL; service_container->crypto_services = NULL; service_container->compression_services = NULL; } else { service_container = device->pSalHandle; } service_container->asym_dir = NULL; service_container->sym_dir = NULL; service_container->cy_dir = NULL; service_container->dc_dir = NULL; service_container->ver_file = NULL; service_container->ver_file = LAC_OS_MALLOC(sizeof(debug_file_info_t)); if (NULL == service_container->ver_file) { free(service_container, M_QAT); return CPA_STATUS_RESOURCE; } memset(service_container->ver_file, 0, sizeof(debug_file_info_t)); service_container->ver_file->name = ver_file_name; service_container->ver_file->seq_read = SalCtrl_VersionDebug; service_container->ver_file->private_data = device; service_container->ver_file->parent = NULL; status = icp_adf_debugAddFile(device, service_container->ver_file); if (CPA_STATUS_SUCCESS != status) { LAC_OS_FREE(service_container->ver_file); free(service_container, M_QAT); return status; } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO_ASYM)) { status = SalCtrl_GetInstanceCount(device, "NumberCyInstances", &instance_count); if (CPA_STATUS_SUCCESS != status) { instance_count = 0; } status = SalCtrl_ServiceInit(device, &service_container->asym_services, &service_container->asym_dir, asym_dir_name, tail_list, instance_count, SAL_SERVICE_TYPE_CRYPTO_ASYM); if (CPA_STATUS_SUCCESS != status) { goto err_init; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO_SYM)) { status = SalCtrl_GetInstanceCount(device, "NumberCyInstances", &instance_count); if (CPA_STATUS_SUCCESS != status) { instance_count = 0; } status = SalCtrl_ServiceInit(device, &service_container->sym_services, &service_container->sym_dir, sym_dir_name, tail_list, instance_count, SAL_SERVICE_TYPE_CRYPTO_SYM); if (CPA_STATUS_SUCCESS != status) { goto err_init; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO)) { status = SalCtrl_GetInstanceCount(device, "NumberCyInstances", &instance_count); if (CPA_STATUS_SUCCESS != status) { instance_count = 0; } status = SalCtrl_ServiceInit(device, &service_container->crypto_services, &service_container->cy_dir, cy_dir_name, tail_list, instance_count, SAL_SERVICE_TYPE_CRYPTO); if (CPA_STATUS_SUCCESS != status) { goto err_init; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_COMPRESSION)) { status = SalCtrl_GetInstanceCount(device, "NumberDcInstances", &instance_count); if (CPA_STATUS_SUCCESS != status) { instance_count = 0; } status = SalCtrl_ServiceInit( device, &service_container->compression_services, &service_container->dc_dir, dc_dir_name, tail_list, instance_count, SAL_SERVICE_TYPE_COMPRESSION); if (CPA_STATUS_SUCCESS != status) { goto err_init; } } return status; err_init: SalCtrl_ServiceEventShutdown(device, enabled_services); return status; } /**************************************************************************** * @ingroup SalCtrl * @description * This function calls the stop function on all the service instances. * * @context * This function is called from the SalCtrl_ServiceEventHandler function. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * @param[in] device An icp_accel_dev_t* type * @param[in] enabled_services Enabled services by user * *************************************************************************/ static CpaStatus SalCtrl_ServiceEventStop(icp_accel_dev_t *device, Cpa32U enabled_services) { CpaStatus status = CPA_STATUS_SUCCESS; CpaStatus ret_status = CPA_STATUS_SUCCESS; sal_t *service_container = device->pSalHandle; if (service_container == NULL) { QAT_UTILS_LOG("Private data is NULL.\n"); return CPA_STATUS_FATAL; } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO_ASYM)) { status = SalCtrl_ServiceStop(device, service_container->asym_services); if (CPA_STATUS_SUCCESS != status) { ret_status = status; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO_SYM)) { status = SalCtrl_ServiceStop(device, service_container->sym_services); if (CPA_STATUS_SUCCESS != status) { ret_status = status; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO)) { status = SalCtrl_ServiceStop(device, service_container->crypto_services); if (CPA_STATUS_SUCCESS != status) { ret_status = status; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_COMPRESSION)) { status = SalCtrl_ServiceStop( device, service_container->compression_services); if (CPA_STATUS_SUCCESS != status) { ret_status = status; } } return ret_status; } /************************************************************************** * @ingroup SalCtrl * @description * This function calls the error function on all the service instances. * * @context * This function is called from the SalCtrl_ServiceEventHandler function. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * @param[in] device An icp_accel_dev_t* type * @param[in] enabled_services Enabled services by user * **************************************************************************/ static CpaStatus SalCtrl_ServiceEventError(icp_accel_dev_t *device, Cpa32U enabled_services) { CpaStatus status = CPA_STATUS_SUCCESS; CpaStatus ret_status = CPA_STATUS_SUCCESS; sal_t *service_container = device->pSalHandle; if (service_container == NULL) { QAT_UTILS_LOG("Private data is NULL\n"); return CPA_STATUS_FATAL; } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO_ASYM)) { status = SalCtrl_ServiceError(device, service_container->asym_services); if (CPA_STATUS_SUCCESS != status) { ret_status = status; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO_SYM)) { status = SalCtrl_ServiceError(device, service_container->sym_services); if (CPA_STATUS_SUCCESS != status) { ret_status = status; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO)) { status = SalCtrl_ServiceError(device, service_container->crypto_services); if (CPA_STATUS_SUCCESS != status) { ret_status = status; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_COMPRESSION)) { status = SalCtrl_ServiceError( device, service_container->compression_services); if (CPA_STATUS_SUCCESS != status) { ret_status = status; } } return ret_status; } /************************************************************************** * @ingroup SalCtrl * @description * This function calls the start function on all the service instances. * * @context * This function is called from the SalCtrl_ServiceEventHandler function. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * @param[in] device An icp_accel_dev_t* type * @param[in] enabled_services Enabled services by user * **************************************************************************/ static CpaStatus SalCtrl_ServiceEventStart(icp_accel_dev_t *device, Cpa32U enabled_services) { CpaStatus status = CPA_STATUS_SUCCESS; sal_t *service_container = device->pSalHandle; if (service_container == NULL) { QAT_UTILS_LOG("Private data is NULL.\n"); return CPA_STATUS_FATAL; } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO_ASYM)) { status = SalCtrl_ServiceStart(device, service_container->asym_services); if (CPA_STATUS_SUCCESS != status) { goto err_start; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO_SYM)) { status = SalCtrl_ServiceStart(device, service_container->sym_services); if (CPA_STATUS_SUCCESS != status) { goto err_start; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_CRYPTO)) { status = SalCtrl_ServiceStart(device, service_container->crypto_services); if (CPA_STATUS_SUCCESS != status) { goto err_start; } } if (SalCtrl_IsServiceEnabled(enabled_services, SAL_SERVICE_TYPE_COMPRESSION)) { status = SalCtrl_ServiceStart( device, service_container->compression_services); if (CPA_STATUS_SUCCESS != status) { goto err_start; } } return status; err_start: SalCtrl_ServiceEventStop(device, enabled_services); return status; } /************************************************************************* * @ingroup SalCtrl * @description * This function is the events handler registered with ADF * for the QA API services (cy, dc) - kernel and user * * @context * This function is called from an ADF context. * * @assumptions * None * @sideEffects * None * @reentrant * No * @threadSafe * Yes * * @param[in] device An icp_accel_dev_t* type * @param[in] event Event from ADF * @param[in] param Parameter used for back compatibility * ***********************************************************************/ static CpaStatus SalCtrl_ServiceEventHandler(icp_accel_dev_t *device, icp_adf_subsystemEvent_t event, void *param) { CpaStatus status = CPA_STATUS_SUCCESS; CpaStatus stats_status = CPA_STATUS_SUCCESS; Cpa32U enabled_services = 0; status = SalCtrl_GetEnabledServices(device, &enabled_services); if (CPA_STATUS_SUCCESS != status) { QAT_UTILS_LOG("Failed to get enabled services.\n"); return status; } switch (event) { case ICP_ADF_EVENT_INIT: { /* In case there is no QAT SAL needs to call InitStats */ if (NULL == device->pQatStats) { status = SalStatistics_InitStatisticsCollection(device); } if (CPA_STATUS_SUCCESS != status) { return status; } status = SalCtrl_ServiceEventInit(device, enabled_services); break; } case ICP_ADF_EVENT_START: { status = SalCtrl_ServiceEventStart(device, enabled_services); break; } case ICP_ADF_EVENT_STOP: { status = SalCtrl_ServiceEventStop(device, enabled_services); break; } case ICP_ADF_EVENT_SHUTDOWN: { status = SalCtrl_ServiceEventShutdown(device, enabled_services); stats_status = SalStatistics_CleanStatisticsCollection(device); if (CPA_STATUS_SUCCESS != status || CPA_STATUS_SUCCESS != stats_status) { return CPA_STATUS_FAIL; } break; } case ICP_ADF_EVENT_ERROR: { status = SalCtrl_ServiceEventError(device, enabled_services); break; } default: status = CPA_STATUS_SUCCESS; break; } return status; } CpaStatus SalCtrl_AdfServicesRegister(void) { /* Fill out the global sal_service_reg_handle structure */ sal_service_reg_handle.subserviceEventHandler = SalCtrl_ServiceEventHandler; /* Set subsystem name to globally defined name */ sal_service_reg_handle.subsystem_name = subsystem_name; return icp_adf_subsystemRegister(&sal_service_reg_handle); } CpaStatus SalCtrl_AdfServicesUnregister(void) { return icp_adf_subsystemUnregister(&sal_service_reg_handle); } CpaStatus SalCtrl_AdfServicesStartedCheck(void) { CpaStatus status = CPA_STATUS_SUCCESS; Cpa32U retry_num = 0; CpaBoolean state = CPA_FALSE; do { state = icp_adf_isSubsystemStarted(&sal_service_reg_handle); retry_num++; } while ((CPA_FALSE == state) && (retry_num < MAX_SUBSYSTEM_RETRY)); if (CPA_FALSE == state) { QAT_UTILS_LOG("Sal Ctrl failed to start in given time.\n"); status = CPA_STATUS_FAIL; } return status; } CpaStatus validateConcurrRequest(Cpa32U numConcurrRequests) { Cpa32U baseReq = SAL_64_CONCURR_REQUESTS; if (SAL_64_CONCURR_REQUESTS > numConcurrRequests) { QAT_UTILS_LOG( "Invalid numConcurrRequests, it is less than min value.\n"); return CPA_STATUS_FAIL; } while (SAL_MAX_CONCURR_REQUESTS >= baseReq) { if (baseReq != numConcurrRequests) { baseReq = baseReq << 1; } else { break; } } if (SAL_MAX_CONCURR_REQUESTS < baseReq) { QAT_UTILS_LOG( "Invalid baseReg, it is greater than max value.\n"); return CPA_STATUS_FAIL; } return CPA_STATUS_SUCCESS; }