root/sys/dev/qat/qat_common/adf_cfg_section.c
/* SPDX-License-Identifier: BSD-3-Clause */
/* Copyright(c) 2007-2022 Intel Corporation */
#include "adf_cfg_instance.h"
#include "adf_cfg_device.h"
#include "adf_cfg_section.h"

static bool
adf_cfg_is_svc_enabled(struct adf_accel_dev *accel_dev, const u8 svc)
{
        int ring_pair_index = 0;
        u8 serv_type = NA;
        struct adf_hw_device_data *hw_data = GET_HW_DATA(accel_dev);

        for (ring_pair_index = 0; ring_pair_index < ADF_CFG_NUM_SERVICES;
             ring_pair_index++) {
                serv_type =
                    GET_SRV_TYPE(hw_data->ring_to_svc_map, ring_pair_index);
                if (serv_type == svc)
                        return true;
        }
        return false;
}

static int
adf_cfg_set_core_number_for_instance(struct adf_accel_dev *accel_dev,
                                     const char *sec_name,
                                     const char *inst_name,
                                     int process_num,
                                     unsigned long *core_number)
{
        char *core_val = NULL;
        char *pos = NULL;
        char **tokens = NULL;
        int token_index = 0;
        int core_arr_index = 0;
        int i = 0;
        int ret = EFAULT;
        unsigned long *core_num_arr = NULL;
        unsigned long core_num;
        unsigned long start, end;

        /* do memory allocation */
        core_val =
            malloc(ADF_CFG_MAX_VAL_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        tokens = malloc(sizeof(char *) * ADF_CFG_MAX_TOKENS,
                        M_QAT,
                        M_WAITOK | M_ZERO);

        for (i = 0; i < ADF_CFG_MAX_TOKENS; i++) {
                tokens[i] =
                    malloc(ADF_CFG_MAX_TOKEN_LEN, M_QAT, M_WAITOK | M_ZERO);
        }

        core_num_arr = malloc(sizeof(unsigned long) * ADF_CFG_MAX_CORE_NUM,
                              M_QAT,
                              M_WAITOK | M_ZERO);

        /* parse the core_val */
        ret = EFAULT;
        if (adf_cfg_get_param_value(accel_dev, sec_name, inst_name, core_val))
                goto failed;

        pos = strchr(core_val, ',');
        while (pos) {
                pos[0] = '\0';
                strlcpy(tokens[token_index++], core_val, ADF_CFG_MAX_TOKEN_LEN);
                strlcpy(core_val, pos + 1, ADF_CFG_MAX_VAL_LEN_IN_BYTES);
                pos = strchr(core_val, ',');
                if (!pos)
                        strlcpy(tokens[token_index++],
                                core_val,
                                ADF_CFG_MAX_VAL_LEN_IN_BYTES);
        }

        /* in case there is only N-M */
        if (token_index == 0)
                strlcpy(tokens[token_index++],
                        core_val,
                        ADF_CFG_MAX_VAL_LEN_IN_BYTES);

        /* parse the tokens such as N-M */
        for (i = 0; i < token_index; i++) {
                pos = strchr(tokens[i], '-');
                if (pos) {
                        pos[0] = '\0';
                        ret = compat_strtoul(tokens[i], 10, &start);
                        if (ret)
                                goto failed;
                        ret = compat_strtoul(pos + 1, 10, &end);
                        if (ret)
                                goto failed;
                        if (start > end) {
                                ret = EFAULT;
                                goto failed;
                        }
                        for (core_num = start; core_num < end + 1; core_num++)
                                core_num_arr[core_arr_index++] = core_num;
                } else {
                        ret = compat_strtoul(tokens[i], 10, &core_num);
                        if (ret)
                                goto failed;
                        core_num_arr[core_arr_index++] = core_num;
                }
        }

        if (core_arr_index == 0) {
                ret = compat_strtoul(core_val, 10, &core_num);
                if (ret)
                        goto failed;
                else
                        core_num_arr[core_arr_index++] = core_num;
        }

        *core_number = core_num_arr[process_num % core_arr_index];
        ret = 0;
failed:
        free(core_val, M_QAT);
        if (tokens) {
                for (i = 0; i < ADF_CFG_MAX_TOKENS; i++)
                        free(tokens[i], M_QAT);
                free(tokens, M_QAT);
        }
        free(core_num_arr, M_QAT);

        if (ret)
                device_printf(GET_DEV(accel_dev),
                              "Get core number failed with error %d\n",
                              ret);
        return ret;
}

static int
adf_cfg_set_value(struct adf_accel_dev *accel_dev,
                  const char *sec,
                  const char *key,
                  unsigned long *value)
{
        char *val = NULL;
        int ret = EFAULT;

        val = malloc(ADF_CFG_MAX_VAL_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        if (adf_cfg_get_param_value(accel_dev, sec, key, val))
                goto out;

        /* as the key type can be either ADF_DEC or ADF_HEX */
        if (compat_strtoul(val, 10, value) && compat_strtoul(val, 16, value))
                goto out;

        ret = 0;
out:
        free(val, M_QAT);
        return ret;
}

static void
adf_cfg_add_cy_inst_info(struct adf_accel_dev *accel_dev,
                         struct adf_cfg_instance *crypto_inst,
                         const char *derived_sec,
                         int inst_index)
{
        char *key = NULL;
        unsigned long bank_number = 0;
        unsigned long ring_number = 0;
        unsigned long asym_req = 0;
        unsigned long sym_req = 0;

        key = malloc(ADF_CFG_MAX_KEY_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        snprintf(key,
                 ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                 ADF_CY_BANK_NUM_FORMAT,
                 inst_index);
        bank_number = crypto_inst->bundle;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&bank_number, ADF_DEC);

        snprintf(key,
                 ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                 ADF_CY_ASYM_TX_FORMAT,
                 inst_index);
        ring_number = crypto_inst->asym_tx;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&ring_number, ADF_DEC);

        snprintf(key,
                 ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                 ADF_CY_SYM_TX_FORMAT,
                 inst_index);
        ring_number = crypto_inst->sym_tx;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&ring_number, ADF_DEC);

        snprintf(key,
                 ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                 ADF_CY_ASYM_RX_FORMAT,
                 inst_index);
        ring_number = crypto_inst->asym_rx;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&ring_number, ADF_DEC);

        snprintf(key,
                 ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                 ADF_CY_SYM_RX_FORMAT,
                 inst_index);
        ring_number = crypto_inst->sym_rx;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&ring_number, ADF_DEC);

        strlcpy(key, ADF_CY_RING_ASYM_SIZE, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_set_value(accel_dev, ADF_GENERAL_SEC, key, &asym_req))
                asym_req = ADF_CFG_DEF_CY_RING_ASYM_SIZE;

        snprintf(key,
                 ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                 ADF_CY_RING_ASYM_SIZE_FORMAT,
                 inst_index);
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&asym_req, ADF_DEC);

        strlcpy(key, ADF_CY_RING_SYM_SIZE, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_set_value(accel_dev, ADF_GENERAL_SEC, key, &sym_req))
                sym_req = ADF_CFG_DEF_CY_RING_SYM_SIZE;

        snprintf(key,
                 ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                 ADF_CY_RING_SYM_SIZE_FORMAT,
                 inst_index);
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&sym_req, ADF_DEC);

        free(key, M_QAT);
}

static void
adf_cfg_add_dc_inst_info(struct adf_accel_dev *accel_dev,
                         struct adf_cfg_instance *dc_inst,
                         const char *derived_sec,
                         int inst_index)
{
        char *key = NULL;
        unsigned long bank_number = 0;
        unsigned long ring_number = 0;
        unsigned long dc_req = 0;

        key = malloc(ADF_CFG_MAX_KEY_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        snprintf(key, ADF_CFG_MAX_STR_LEN, ADF_DC_BANK_NUM_FORMAT, inst_index);
        bank_number = dc_inst->bundle;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&bank_number, ADF_DEC);

        snprintf(key, ADF_CFG_MAX_STR_LEN, ADF_DC_TX_FORMAT, inst_index);
        ring_number = dc_inst->dc_tx;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&ring_number, ADF_DEC);

        snprintf(key, ADF_CFG_MAX_STR_LEN, ADF_DC_RX_FORMAT, inst_index);
        ring_number = dc_inst->dc_rx;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&ring_number, ADF_DEC);

        strlcpy(key, ADF_DC_RING_SIZE, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_set_value(accel_dev, ADF_GENERAL_SEC, key, &dc_req))
                dc_req = ADF_CFG_DEF_DC_RING_SIZE;

        snprintf(key, ADF_CFG_MAX_STR_LEN, ADF_DC_RING_SIZE_FORMAT, inst_index);
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&dc_req, ADF_DEC);

        free(key, M_QAT);
}

static void
adf_cfg_add_asym_inst_info(struct adf_accel_dev *accel_dev,
                           struct adf_cfg_instance *asym_inst,
                           const char *derived_sec,
                           int inst_index)
{
        char *key = NULL;
        unsigned long bank_number = 0;
        unsigned long ring_number = 0;
        unsigned long asym_req = 0;

        key = malloc(ADF_CFG_MAX_KEY_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        if (adf_cy_inst_cross_banks(accel_dev))
                snprintf(key,
                         ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                         ADF_CY_ASYM_BANK_NUM_FORMAT,
                         inst_index);
        else
                snprintf(key,
                         ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                         ADF_CY_BANK_NUM_FORMAT,
                         inst_index);
        bank_number = asym_inst->bundle;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&bank_number, ADF_DEC);

        snprintf(key,
                 ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                 ADF_CY_ASYM_TX_FORMAT,
                 inst_index);
        ring_number = asym_inst->asym_tx;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&ring_number, ADF_DEC);

        snprintf(key,
                 ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                 ADF_CY_ASYM_RX_FORMAT,
                 inst_index);
        ring_number = asym_inst->asym_rx;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&ring_number, ADF_DEC);

        strlcpy(key, ADF_CY_RING_ASYM_SIZE, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_set_value(accel_dev, ADF_GENERAL_SEC, key, &asym_req))
                asym_req = ADF_CFG_DEF_CY_RING_ASYM_SIZE;

        snprintf(key,
                 ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                 ADF_CY_RING_ASYM_SIZE_FORMAT,
                 inst_index);
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&asym_req, ADF_DEC);

        free(key, M_QAT);
}

static void
adf_cfg_add_sym_inst_info(struct adf_accel_dev *accel_dev,
                          struct adf_cfg_instance *sym_inst,
                          const char *derived_sec,
                          int inst_index)
{
        char *key = NULL;
        unsigned long bank_number = 0;
        unsigned long ring_number = 0;
        unsigned long sym_req = 0;

        key = malloc(ADF_CFG_MAX_KEY_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        if (adf_cy_inst_cross_banks(accel_dev))
                snprintf(key,
                         ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                         ADF_CY_SYM_BANK_NUM_FORMAT,
                         inst_index);
        else
                snprintf(key,
                         ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                         ADF_CY_BANK_NUM_FORMAT,
                         inst_index);

        bank_number = sym_inst->bundle;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&bank_number, ADF_DEC);

        snprintf(key,
                 ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                 ADF_CY_SYM_TX_FORMAT,
                 inst_index);
        ring_number = sym_inst->sym_tx;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&ring_number, ADF_DEC);

        snprintf(key,
                 ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                 ADF_CY_SYM_RX_FORMAT,
                 inst_index);
        ring_number = sym_inst->sym_rx;
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&ring_number, ADF_DEC);

        strlcpy(key, ADF_CY_RING_SYM_SIZE, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_set_value(accel_dev, ADF_GENERAL_SEC, key, &sym_req))
                sym_req = ADF_CFG_DEF_CY_RING_SYM_SIZE;

        snprintf(key,
                 ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                 ADF_CY_RING_SYM_SIZE_FORMAT,
                 inst_index);
        adf_cfg_add_key_value_param(
            accel_dev, derived_sec, key, (void *)&sym_req, ADF_DEC);

        free(key, M_QAT);
}

static int
adf_cfg_section_copy(struct adf_accel_dev *accel_dev,
                     const char *processed_sec,
                     const char *derived_sec)
{
        unsigned long val = 0;
        struct list_head *list;
        struct adf_cfg_section *sec_process =
            adf_cfg_sec_find(accel_dev, processed_sec);
        if (!sec_process)
                return EFAULT;

        list_for_each(list, &sec_process->param_head)
        {
                struct adf_cfg_key_val *ptr =
                    list_entry(list, struct adf_cfg_key_val, list);

                /*
                 * ignore CoreAffinity since it will be generated later, and
                 * there is no need to keep NumProcesses and LimitDevAccess.
                 */
                if (strstr(ptr->key, ADF_ETRMGR_CORE_AFFINITY) ||
                    strstr(ptr->key, ADF_NUM_PROCESSES) ||
                    strstr(ptr->key, ADF_LIMIT_DEV_ACCESS))
                        continue;

                if (ptr->type == ADF_DEC) {
                        if (!compat_strtoul(ptr->val, 10, &val))
                                adf_cfg_add_key_value_param(accel_dev,
                                                            derived_sec,
                                                            ptr->key,
                                                            (void *)&val,
                                                            ptr->type);
                } else if (ptr->type == ADF_STR) {
                        adf_cfg_add_key_value_param(accel_dev,
                                                    derived_sec,
                                                    ptr->key,
                                                    (void *)ptr->val,
                                                    ptr->type);
                } else if (ptr->type == ADF_HEX) {
                        if (!compat_strtoul(ptr->val, 16, &val))
                                adf_cfg_add_key_value_param(accel_dev,
                                                            derived_sec,
                                                            ptr->key,
                                                            (void *)val,
                                                            ptr->type);
                }
        }
        return 0;
}

static int
adf_cfg_create_rings_entries_for_cy_inst(struct adf_accel_dev *accel_dev,
                                         const char *processed_sec,
                                         const char *derived_sec,
                                         int process_num,
                                         enum adf_cfg_service_type serv_type)
{
        int i = 0;
        int ret = EFAULT;
        unsigned long num_inst = 0, num_dc_inst = 0;
        unsigned long core_number = 0;
        unsigned long polling_mode = 0;
        struct adf_cfg_instance *crypto_inst = NULL;

        char *key = NULL;
        char *val = NULL;

        key = malloc(ADF_CFG_MAX_KEY_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        val = malloc(ADF_CFG_MAX_VAL_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        snprintf(key, ADF_CFG_MAX_KEY_LEN_IN_BYTES, ADF_SERVICES_ENABLED);
        if (adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, key, val))
                goto failed;
        if ((!strncmp(val, ADF_CFG_CY, ADF_CFG_MAX_VAL_LEN_IN_BYTES)) ||
            (!strncmp(val, ADF_CFG_ASYM, ADF_CFG_MAX_VAL_LEN_IN_BYTES)) ||
            (!strncmp(val, ADF_CFG_SYM, ADF_CFG_MAX_VAL_LEN_IN_BYTES))) {
                strlcpy(key, ADF_NUM_DC, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
                if (adf_cfg_set_value(
                        accel_dev, processed_sec, key, &num_dc_inst))
                        goto failed;
                if (num_dc_inst > 0) {
                        device_printf(
                            GET_DEV(accel_dev),
                            "NumDcInstances > 0,when CY only is enabled\n");
                        goto failed;
                }
        }
        ret = EFAULT;

        strlcpy(key, ADF_NUM_CY, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_set_value(accel_dev, processed_sec, key, &num_inst))
                goto failed;

        crypto_inst = malloc(sizeof(*crypto_inst), M_QAT, M_WAITOK | M_ZERO);

        for (i = 0; i < num_inst; i++) {
                memset(crypto_inst, 0, sizeof(*crypto_inst));
                crypto_inst->stype = serv_type;
                snprintf(key,
                         ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                         ADF_CY_CORE_AFFINITY_FORMAT,
                         i);
                if (adf_cfg_set_core_number_for_instance(accel_dev,
                                                         processed_sec,
                                                         key,
                                                         process_num,
                                                         &core_number))
                        goto failed;

                if (strcmp(processed_sec, ADF_KERNEL_SEC) &&
                    strcmp(processed_sec, ADF_KERNEL_SAL_SEC))
                        adf_cfg_add_key_value_param(accel_dev,
                                                    derived_sec,
                                                    key,
                                                    (void *)&core_number,
                                                    ADF_DEC);

                snprintf(key,
                         ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                         ADF_CY_NAME_FORMAT,
                         i);
                if (adf_cfg_get_param_value(accel_dev, processed_sec, key, val))
                        goto failed;

                strlcpy(crypto_inst->name, val, sizeof(crypto_inst->name));

                snprintf(key,
                         ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                         ADF_CY_POLL_MODE_FORMAT,
                         i);
                if (adf_cfg_set_value(
                        accel_dev, processed_sec, key, &polling_mode))
                        goto failed;

                crypto_inst->polling_mode = polling_mode;
                CPU_ZERO(&crypto_inst->affinity_mask);
                CPU_SET(core_number, &crypto_inst->affinity_mask);

                if (adf_cfg_get_ring_pairs(accel_dev->cfg->dev,
                                           crypto_inst,
                                           derived_sec,
                                           accel_dev))
                        goto failed;

                switch (serv_type) {
                case CRYPTO:
                        adf_cfg_add_cy_inst_info(accel_dev,
                                                 crypto_inst,
                                                 derived_sec,
                                                 i);
                        break;
                case ASYM:
                        adf_cfg_add_asym_inst_info(accel_dev,
                                                   crypto_inst,
                                                   derived_sec,
                                                   i);
                        break;
                case SYM:
                        adf_cfg_add_sym_inst_info(accel_dev,
                                                  crypto_inst,
                                                  derived_sec,
                                                  i);
                        break;
                default:
                        pr_err("unknown crypto instance type %d.\n", serv_type);
                        goto failed;
                }
        }

        ret = 0;
failed:
        free(crypto_inst, M_QAT);
        free(val, M_QAT);
        free(key, M_QAT);

        if (ret)
                device_printf(GET_DEV(accel_dev),
                              "Failed to create rings for cy\n");

        return ret;
}

static int
adf_cfg_create_rings_entries_for_dc_inst(struct adf_accel_dev *accel_dev,
                                         const char *processed_sec,
                                         const char *derived_sec,
                                         int process_num)
{
        int i = 0;
        int ret = EFAULT;
        unsigned long num_inst = 0, num_cy_inst = 0;
        unsigned long core_number = 0;
        unsigned long polling_mode = 0;
        struct adf_cfg_instance *dc_inst = NULL;

        char *key = NULL;
        char *val = NULL;

        key = malloc(ADF_CFG_MAX_KEY_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        val = malloc(ADF_CFG_MAX_VAL_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        ret = EFAULT;

        snprintf(key, ADF_CFG_MAX_STR_LEN, ADF_SERVICES_ENABLED);
        if (adf_cfg_get_param_value(accel_dev, ADF_GENERAL_SEC, key, val))
                goto failed;

        if (!strncmp(val, ADF_CFG_DC, ADF_CFG_MAX_VAL_LEN_IN_BYTES)) {
                strlcpy(key, ADF_NUM_CY, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
                if (adf_cfg_set_value(
                        accel_dev, processed_sec, key, &num_cy_inst))
                        goto failed;
                if (num_cy_inst > 0) {
                        device_printf(
                            GET_DEV(accel_dev),
                            "NumCyInstances > 0,when DC only is enabled\n");
                        goto failed;
                }
        }

        strlcpy(key, ADF_NUM_DC, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_set_value(accel_dev, processed_sec, key, &num_inst))
                goto failed;

        dc_inst = malloc(sizeof(*dc_inst), M_QAT, M_WAITOK | M_ZERO);

        for (i = 0; i < num_inst; i++) {
                memset(dc_inst, 0, sizeof(*dc_inst));
                dc_inst->stype = COMP;
                snprintf(key,
                         ADF_CFG_MAX_STR_LEN,
                         ADF_DC_CORE_AFFINITY_FORMAT,
                         i);

                if (adf_cfg_set_core_number_for_instance(accel_dev,
                                                         processed_sec,
                                                         key,
                                                         process_num,
                                                         &core_number))
                        goto failed;

                if (strcmp(processed_sec, ADF_KERNEL_SEC) &&
                    strcmp(processed_sec, ADF_KERNEL_SAL_SEC)) {
                        adf_cfg_add_key_value_param(accel_dev,
                                                    derived_sec,
                                                    key,
                                                    (void *)&core_number,
                                                    ADF_DEC);
                }

                snprintf(key,
                         ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                         ADF_DC_NAME_FORMAT,
                         i);
                if (adf_cfg_get_param_value(accel_dev, processed_sec, key, val))
                        goto failed;

                strlcpy(dc_inst->name, val, sizeof(dc_inst->name));

                snprintf(key,
                         ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                         ADF_DC_POLL_MODE_FORMAT,
                         i);
                if (adf_cfg_set_value(
                        accel_dev, processed_sec, key, &polling_mode))
                        goto failed;

                dc_inst->polling_mode = polling_mode;
                CPU_ZERO(&dc_inst->affinity_mask);
                CPU_SET(core_number, &dc_inst->affinity_mask);

                if (adf_cfg_get_ring_pairs(
                        accel_dev->cfg->dev, dc_inst, derived_sec, accel_dev))
                        goto failed;

                adf_cfg_add_dc_inst_info(accel_dev, dc_inst, derived_sec, i);
        }

        ret = 0;
failed:
        free(dc_inst, M_QAT);
        free(val, M_QAT);
        free(key, M_QAT);

        if (ret)
                device_printf(GET_DEV(accel_dev),
                              "Failed to create rings for dc\n");

        return ret;
}

static int
adf_cfg_process_user_section(struct adf_accel_dev *accel_dev,
                             const char *sec_name,
                             int dev)
{
        int i = 0;
        int ret = EFAULT;
        unsigned long num_processes = 0;
        unsigned long limit_dev_acc = 0;
        u8 serv_type = 0;

        char *key = NULL;
        char *val = NULL;
        char *derived_sec_name = NULL;

        key = malloc(ADF_CFG_MAX_KEY_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        val = malloc(ADF_CFG_MAX_VAL_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        derived_sec_name =
            malloc(ADF_CFG_MAX_STR_LEN, M_QAT, M_WAITOK | M_ZERO);

        strlcpy(key, ADF_NUM_PROCESSES, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_set_value(accel_dev, sec_name, key, &num_processes))
                num_processes = 0;

        strlcpy(key, ADF_LIMIT_DEV_ACCESS, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_set_value(accel_dev, sec_name, key, &limit_dev_acc))
                limit_dev_acc = 0;

        for (i = 0; i < num_processes; i++) {
                if (limit_dev_acc)
                        snprintf(derived_sec_name,
                                 ADF_CFG_MAX_STR_LEN,
                                 ADF_LIMITED_USER_SECTION_NAME_FORMAT,
                                 sec_name,
                                 dev,
                                 i);
                else
                        snprintf(derived_sec_name,
                                 ADF_CFG_MAX_STR_LEN,
                                 ADF_USER_SECTION_NAME_FORMAT,
                                 sec_name,
                                 i);

                if (adf_cfg_derived_section_add(accel_dev, derived_sec_name))
                        goto failed;

                /* copy items to the derived section */
                adf_cfg_section_copy(accel_dev, sec_name, derived_sec_name);

                for (serv_type = NA; serv_type <= USED; serv_type++) {
                        switch (serv_type) {
                        case NA:
                                break;
                        case CRYPTO:
                        case ASYM:
                        case SYM:
                                if (adf_cfg_is_svc_enabled(accel_dev,
                                                           serv_type))
                                        if (adf_cfg_create_rings_entries_for_cy_inst(
                                                accel_dev,
                                                sec_name,
                                                derived_sec_name,
                                                i,
                                                (enum adf_cfg_service_type)
                                                    serv_type))
                                                goto failed;
                                break;
                        case COMP:
                                if (adf_cfg_is_svc_enabled(accel_dev,
                                                           serv_type))
                                        if (adf_cfg_create_rings_entries_for_dc_inst(
                                                accel_dev,
                                                sec_name,
                                                derived_sec_name,
                                                i))
                                                goto failed;
                                break;
                        case USED:
                                break;
                        default:
                                pr_err("Unknown service type %d.\n", serv_type);
                        }
                }
        }

        ret = 0;
failed:

        free(val, M_QAT);
        free(key, M_QAT);
        free(derived_sec_name, M_QAT);

        if (ret)
                device_printf(GET_DEV(accel_dev),
                              "Failed to process user section %s\n",
                              sec_name);

        return ret;
}

static int
adf_cfg_cleanup_user_section(struct adf_accel_dev *accel_dev,
                             const char *sec_name)
{
        struct adf_cfg_section *sec = adf_cfg_sec_find(accel_dev, sec_name);
        struct list_head *head;
        struct list_head *list_ptr, *tmp;

        if (!sec)
                return EFAULT;

        if (sec->is_derived)
                return 0;

        head = &sec->param_head;
        list_for_each_prev_safe(list_ptr, tmp, head)
        {
                struct adf_cfg_key_val *ptr =
                    list_entry(list_ptr, struct adf_cfg_key_val, list);

                if (!strcmp(ptr->key, ADF_LIMIT_DEV_ACCESS))
                        continue;

                list_del(list_ptr);
                free(ptr, M_QAT);
        }
        return 0;
}

static int
adf_cfg_process_section_no_op(struct adf_accel_dev *accel_dev,
                              const char *sec_name)
{
        return 0;
}

static int
adf_cfg_cleanup_general_section(struct adf_accel_dev *accel_dev,
                                const char *sec_name)
{
        unsigned long first_used_bundle = 0;
        int ret = EFAULT;
        char *key = NULL;
        char *val = NULL;

        key = malloc(ADF_CFG_MAX_KEY_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        val = malloc(ADF_CFG_MAX_VAL_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        /* Remove sections that not needed after processing */
        strlcpy(key, ADF_CONFIG_VERSION, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_remove_key_param(accel_dev, sec_name, key))
                goto failed;

        strlcpy(key, ADF_CY ADF_RING_ASYM_SIZE, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_remove_key_param(accel_dev, sec_name, key))
                goto failed;

        strlcpy(key, ADF_CY ADF_RING_SYM_SIZE, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_remove_key_param(accel_dev, sec_name, key))
                goto failed;

        strlcpy(key, ADF_DC ADF_RING_DC_SIZE, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_remove_key_param(accel_dev, sec_name, key))
                goto failed;

        /* After all processing done, set the "FirstUserBundle" value */
        first_used_bundle = accel_dev->cfg->dev->max_kernel_bundle_nr + 1;
        strlcpy(key, ADF_FIRST_USER_BUNDLE, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_add_key_value_param(
                accel_dev, sec_name, key, (void *)&first_used_bundle, ADF_DEC))
                goto failed;

        ret = 0;
failed:
        free(key, M_QAT);
        free(val, M_QAT);

        if (ret)
                device_printf(GET_DEV(accel_dev),
                              "Failed to clean up general section\n");

        return ret;
}

static int
adf_cfg_process_kernel_section(struct adf_accel_dev *accel_dev,
                               const char *sec_name)
{
        u8 serv_type = 0;

        for (serv_type = NA; serv_type <= USED; serv_type++) {
                switch (serv_type) {
                case NA:
                        break;
                case CRYPTO:
                case ASYM:
                case SYM:
                        if (adf_cfg_is_svc_enabled(accel_dev, serv_type))
                                if (adf_cfg_create_rings_entries_for_cy_inst(
                                        accel_dev,
                                        sec_name,
                                        sec_name,
                                        0,
                                        (enum adf_cfg_service_type)serv_type))
                                        goto failed;
                        break;
                case COMP:
                        if (adf_cfg_is_svc_enabled(accel_dev, serv_type))
                                if (adf_cfg_create_rings_entries_for_dc_inst(
                                        accel_dev, sec_name, sec_name, 0))
                                        goto failed;
                        break;
                case USED:
                        break;
                default:
                        pr_err("Unknown service type of instance %d.\n",
                               serv_type);
                }
        }

        return 0;

failed:
        return EFAULT;
}

static int
adf_cfg_cleanup_kernel_section(struct adf_accel_dev *accel_dev,
                               const char *sec_name)
{
        return 0;
}

static int
adf_cfg_create_accel_section(struct adf_accel_dev *accel_dev,
                             const char *sec_name)
{
        /* Find global settings for coalescing. Use defaults if not found */
        unsigned long accel_coales = 0;
        unsigned long accel_coales_timer = 0;
        unsigned long accel_coales_num_msg = 0;
        unsigned long cpu;
        char *key = NULL;
        char *val = NULL;
        int ret = EFAULT;
        int index = 0;
        struct adf_hw_device_data *hw_device = accel_dev->hw_device;

        if (!hw_device)
                goto failed;

        key = malloc(ADF_CFG_MAX_KEY_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        val = malloc(ADF_CFG_MAX_VAL_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        strlcpy(key,
                ADF_ETRMGR_COALESCING_ENABLED,
                ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_set_value(accel_dev, ADF_GENERAL_SEC, key, &accel_coales))
                accel_coales = ADF_CFG_ACCEL_DEF_COALES;

        strlcpy(key, ADF_ETRMGR_COALESCE_TIMER, ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_set_value(
                accel_dev, ADF_GENERAL_SEC, key, &accel_coales_timer))
                accel_coales_timer = ADF_CFG_ACCEL_DEF_COALES_TIMER;

        strlcpy(key,
                ADF_ETRMGR_COALESCING_MSG_ENABLED,
                ADF_CFG_MAX_KEY_LEN_IN_BYTES);
        if (adf_cfg_set_value(
                accel_dev, ADF_GENERAL_SEC, key, &accel_coales_num_msg))
                accel_coales_num_msg = ADF_CFG_ACCEL_DEF_COALES_NUM_MSG;

        for (index = 0; index < hw_device->num_banks; index++) {
                snprintf(key,
                         ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                         ADF_ETRMGR_COALESCING_ENABLED_FORMAT,
                         index);
                ret = adf_cfg_add_key_value_param(
                    accel_dev, sec_name, key, &accel_coales, ADF_DEC);
                if (ret != 0)
                        goto failed;

                snprintf(key,
                         ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                         ADF_ETRMGR_COALESCE_TIMER_FORMAT,
                         index);
                ret = adf_cfg_add_key_value_param(
                    accel_dev, sec_name, key, &accel_coales_timer, ADF_DEC);
                if (ret != 0)
                        goto failed;

                snprintf(key,
                         ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                         ADF_ETRMGR_COALESCING_MSG_ENABLED_FORMAT,
                         index);
                ret = adf_cfg_add_key_value_param(
                    accel_dev, sec_name, key, &accel_coales_num_msg, ADF_DEC);
                if (ret != 0)
                        goto failed;

                cpu = ADF_CFG_AFFINITY_WHATEVER;

                snprintf(key,
                         ADF_CFG_MAX_KEY_LEN_IN_BYTES,
                         ADF_ETRMGR_CORE_AFFINITY_FORMAT,
                         index);
                ret = adf_cfg_add_key_value_param(
                    accel_dev, sec_name, key, &cpu, ADF_DEC);
                if (ret != 0)
                        goto failed;
        }

        ret = 0;

failed:
        free(key, M_QAT);
        free(val, M_QAT);

        if (ret)
                device_printf(GET_DEV(accel_dev),
                              "Failed to create accel section\n");

        return ret;
}

static int
adf_cfg_cleanup_accel_section(struct adf_accel_dev *accel_dev,
                              const char *sec_name)
{
        return 0;
}

static int
adf_cfg_process_accel_section(struct adf_accel_dev *accel_dev,
                              const char *sec_name)
{
        int accel_num = 0;
        struct adf_hw_device_data *hw_device = accel_dev->hw_device;
        char *derived_name = NULL;
        int ret = EFAULT;

        if (!hw_device)
                goto failed;

        if (hw_device->num_logical_accel == 0)
                goto failed;

        derived_name =
            malloc(ADF_CFG_MAX_SECTION_LEN_IN_BYTES, M_QAT, M_WAITOK | M_ZERO);

        for (accel_num = 0; accel_num < hw_device->num_logical_accel;
             accel_num++) {
                snprintf(derived_name,
                         ADF_CFG_MAX_SECTION_LEN_IN_BYTES,
                         ADF_ACCEL_STR,
                         accel_num);
                ret = adf_cfg_section_add(accel_dev, derived_name);
                if (ret != 0)
                        goto failed;

                ret = adf_cfg_create_accel_section(accel_dev, derived_name);
                if (ret != 0)
                        goto failed;
        }

        ret = 0;
failed:
        free(derived_name, M_QAT);

        if (ret)
                device_printf(GET_DEV(accel_dev),
                              "Failed to process accel section\n");

        return ret;
}

int
adf_cfg_process_section(struct adf_accel_dev *accel_dev,
                        const char *sec_name,
                        int dev)
{
        if (!strcmp(sec_name, ADF_GENERAL_SEC) ||
            !strcmp(sec_name, ADF_INLINE_SEC))
                return adf_cfg_process_section_no_op(accel_dev, sec_name);
        else if (!strcmp(sec_name, ADF_KERNEL_SEC) ||
                 !strcmp(sec_name, ADF_KERNEL_SAL_SEC))
                return adf_cfg_process_kernel_section(accel_dev, sec_name);
        else if (!strcmp(sec_name, ADF_ACCEL_SEC))
                return adf_cfg_process_accel_section(accel_dev, sec_name);
        else
                return adf_cfg_process_user_section(accel_dev, sec_name, dev);
}

int
adf_cfg_cleanup_section(struct adf_accel_dev *accel_dev,
                        const char *sec_name,
                        int dev)
{
        if (!strcmp(sec_name, ADF_GENERAL_SEC))
                return adf_cfg_cleanup_general_section(accel_dev, sec_name);
        else if (!strcmp(sec_name, ADF_INLINE_SEC))
                return adf_cfg_process_section_no_op(accel_dev, sec_name);
        else if (!strcmp(sec_name, ADF_KERNEL_SEC) ||
                 !strcmp(sec_name, ADF_KERNEL_SAL_SEC))
                return adf_cfg_cleanup_kernel_section(accel_dev, sec_name);
        else if (strstr(sec_name, ADF_ACCEL_SEC))
                return adf_cfg_cleanup_accel_section(accel_dev, sec_name);
        else
                return adf_cfg_cleanup_user_section(accel_dev, sec_name);
}

int
adf_cfg_setup_irq(struct adf_accel_dev *accel_dev)
{
        int ret = EFAULT;
        struct adf_accel_pci *info_pci_dev = &accel_dev->accel_pci_dev;
        struct adf_cfg_device *cfg_dev = NULL;
        struct msix_entry *msixe = NULL;
        u32 num_msix = 0;
        int index = 0;
        int computed_core = 0;

        if (!accel_dev || !accel_dev->cfg || !accel_dev->hw_device)
                goto failed;

        cfg_dev = accel_dev->cfg->dev;
        if (!cfg_dev)
                goto failed;

        msixe =
            (struct msix_entry *)accel_dev->accel_pci_dev.msix_entries.entries;
        num_msix = accel_dev->accel_pci_dev.msix_entries.num_entries;
        if (!msixe)
                goto cleanup_and_fail;

        /*
         * Here we want to set the affinity of kernel and epoll mode
         * bundle into user defined value.
         * Because in adf_isr.c we setup core affinity by round-robin
         * we need to reset it after device up done.
         */
        for (index = 0; index < accel_dev->hw_device->num_banks; index++) {
                struct adf_cfg_bundle *bundle = cfg_dev->bundles[index];

                if (!bundle)
                        continue;

                if (bundle->type != KERNEL &&
                    bundle->polling_mode != ADF_CFG_RESP_EPOLL)
                        continue;

                if (bundle->number >= num_msix)
                        goto cleanup_and_fail;

                computed_core = CPU_FFS(&bundle->affinity_mask) - 1;
                bus_bind_intr(info_pci_dev->pci_dev,
                              msixe[index].irq,
                              computed_core);
        }
        ret = 0;

cleanup_and_fail:
        adf_cfg_device_clear(cfg_dev, accel_dev);
        free(cfg_dev, M_QAT);
        accel_dev->cfg->dev = NULL;

failed:
        return ret;
}