/*
 * Copyright (C) 2020 Intel Corporation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "ia_css_psys_process_group.h"
#include "ia_css_psys_dynamic_storage_class.h"
#include "ia_css_psys_dynamic_trace.h"
#include "ia_css_program_group_param_private.h"

/*
 * Functions to possibly inline
 */

#ifndef __IA_CSS_PSYS_DYNAMIC_INLINE__
#include "ia_css_psys_process_group_impl.h"
#endif /* __IA_CSS_PSYS_DYNAMIC_INLINE__ */

/*
 * Functions not to inline
 */

/* This header is need for cpu memset to 0
* and process groups are not created in SP
*/
#if !defined(__VIED_CELL)
#include "cpu_mem_support.h"
#endif

/* This source file is created with the intention of sharing and
* compiled for host and firmware. Since there is no native 64bit
* data type support for firmware this wouldn't compile for SP
* tile. The part of the file that is not compilable are marked
* with the following __VIED_CELL marker and this comment. Once we
* come up with a solution to address this issue this will be
* removed.
*/
#if !defined(__VIED_CELL)

/*  FUNCTION IS PRIVATE TO THIS MODULE; other C files in this module need it */
bool ia_css_process_group_is_program_enabled(
    const ia_css_program_manifest_t *program_manifest,
    ia_css_kernel_bitmap_t enable_bitmap)
{
    ia_css_kernel_bitmap_t program_bitmap =
        ia_css_program_manifest_get_kernel_bitmap(program_manifest);
    ia_css_program_type_t program_type =
        ia_css_program_manifest_get_type(program_manifest);
    ia_css_kernel_bitmap_t program_enable_bitmap;

    if (!ia_css_is_kernel_bitmap_intersection_empty(enable_bitmap,
                program_bitmap)) {

        if (program_type == IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUB ||
            program_type == IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUPER ||
            program_type == IA_CSS_PROGRAM_TYPE_VIRTUAL_SUB) {
            /*
             * EXCLUSIVE_SUB programs are subsets of
             * EXCLUSIVE_SUPER so the bits of the enable_bitmap
             * that refer to those are those of their
             * EXCLUSIVE_SUPER program (on which the depend) and
             * not the subset that their own program_bitmap has
             */
            if (program_type ==
                    IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUB ||
                    program_type ==
                    IA_CSS_PROGRAM_TYPE_VIRTUAL_SUB) {
                ia_css_kernel_bitmap_t super_program_bitmap;

                const ia_css_program_group_manifest_t *
                    prog_group_manifest =
            ia_css_program_manifest_get_parent(program_manifest);
                uint8_t super_prog_idx =
                ia_css_program_manifest_get_program_dependency(
                        program_manifest, 0);
                const ia_css_program_manifest_t    *
                    super_program_manifest =
            ia_css_program_group_manifest_get_prgrm_mnfst(
                    prog_group_manifest, super_prog_idx);

                verifexit(super_program_manifest != NULL);
                if (((program_type ==
                    IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUB) &&
                    (ia_css_program_manifest_get_type(
                    super_program_manifest) !=
                    IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUPER))
                    || ((program_type ==
                    IA_CSS_PROGRAM_TYPE_VIRTUAL_SUB) &&
                    (ia_css_program_manifest_get_type(
                    super_program_manifest) !=
                    IA_CSS_PROGRAM_TYPE_VIRTUAL_SUPER))) {
                    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
                        "ia_css_process_group_is_program_enabled(): Error\n");
                    verifexit(0);
                }

                super_program_bitmap =
                ia_css_program_manifest_get_kernel_bitmap(
                        super_program_manifest);
                program_enable_bitmap =
                    ia_css_kernel_bitmap_intersection(
                        enable_bitmap,
                        super_program_bitmap);
            } else {
                program_enable_bitmap =
                    ia_css_kernel_bitmap_intersection(
                        enable_bitmap, program_bitmap);
            }

            if (ia_css_is_kernel_bitmap_equal(
                program_enable_bitmap, program_bitmap)) {
                return true;
            }
        } else if (program_type == IA_CSS_PROGRAM_TYPE_VIRTUAL_SUPER) {
            /*
             * Virtual super programs are not selectable
             * only the virtual sub programs
             */
            return false;
        } else {
            return true;
        }
    }

EXIT:
    return false;
}

size_t ia_css_sizeof_process_group(
    const ia_css_program_group_manifest_t *manifest,
    const ia_css_program_group_param_t *param)
{
    size_t size = 0, tmp_size;
    int i, error_val = -1;
    uint8_t    process_count, process_num;
    uint8_t terminal_count;
    ia_css_kernel_bitmap_t enable_bitmap;

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, VERBOSE,
        "ia_css_sizeof_process_group(): enter:\n");

    verifexit(manifest != NULL);
    verifexit(param != NULL);

    COMPILATION_ERROR_IF(
        SIZE_OF_PROCESS_GROUP_STRUCT_BITS !=
            (CHAR_BIT * sizeof(ia_css_process_group_t)));

    COMPILATION_ERROR_IF(0 !=
            sizeof(ia_css_process_group_t) % sizeof(uint64_t));

    process_count =
        ia_css_process_group_compute_process_count(manifest, param);
    terminal_count =
        ia_css_process_group_compute_terminal_count(manifest, param);

    verifexit(process_count != 0);
    verifexit(terminal_count != 0);

    size += sizeof(ia_css_process_group_t);

    tmp_size = process_count * sizeof(uint16_t);
    size += tot_bytes_for_pow2_align(sizeof(uint64_t), tmp_size);

    tmp_size = terminal_count * sizeof(uint16_t);
    size += tot_bytes_for_pow2_align(sizeof(uint64_t), tmp_size);

    enable_bitmap =
        ia_css_program_group_param_get_kernel_enable_bitmap(param);
    process_num = 0;
    for (i = 0; i < (int)ia_css_program_group_manifest_get_program_count(
                manifest); i++) {
        ia_css_program_manifest_t *program_manifest =
        ia_css_program_group_manifest_get_prgrm_mnfst(manifest, i);
        ia_css_program_param_t *program_param =
            ia_css_program_group_param_get_program_param(param, i);

        if (ia_css_process_group_is_program_enabled(
                    program_manifest, enable_bitmap)) {
            verifexit(process_num < process_count);
            size += ia_css_sizeof_process(
                    program_manifest, program_param);
            process_num++;
        }
    }

    verifexit(process_num == process_count);

    for (i = 0; i < (int)ia_css_program_group_manifest_get_terminal_count(
                manifest); i++) {
        ia_css_terminal_manifest_t *terminal_manifest =
            ia_css_program_group_manifest_get_term_mnfst(
                    manifest, i);

        if (ia_css_process_group_is_terminal_enabled(
                    terminal_manifest, enable_bitmap)) {
            size += ia_css_sizeof_terminal(
                    terminal_manifest, param);
        }
    }

    error_val = 0;

EXIT:
    if (NULL == manifest || NULL == param) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, WARNING,
            "ia_css_sizeof_process_group invalid argument\n");
    }
    if (error_val != 0) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_sizeof_process_group ERROR(%d)\n", error_val);
    }
    return error_val ? 0 : size;
}

ia_css_process_group_t *ia_css_process_group_create(
    void *process_grp_mem,
    const ia_css_program_group_manifest_t *manifest,
    const ia_css_program_group_param_t *param)
{
    size_t size = ia_css_sizeof_process_group(manifest, param);
    int retval = -1;
    int ret;
    int i;
    ia_css_process_group_t *process_group = NULL;
    uint8_t process_count, process_num;
    uint8_t    terminal_count, terminal_num;
    uint16_t fragment_count;
    char *process_grp_raw_ptr;
    uint16_t *process_tab_ptr, *terminal_tab_ptr;
    ia_css_kernel_bitmap_t enable_bitmap;
    uint8_t manifest_terminal_count;

    IA_CSS_TRACE_3(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_create(process_grp_mem %p, manifest %p, group_param %p): enter:\n",
        process_grp_mem, manifest, param);

    verifexit(process_grp_mem != NULL);
    verifexit(manifest != NULL);
    verifexit(param != NULL);
    verifexit(ia_css_is_program_group_manifest_valid(manifest));
    verifexit(size != 0);

    process_group = (ia_css_process_group_t    *)process_grp_mem;
    ia_css_cpu_mem_set_zero(process_group, size);
    process_grp_raw_ptr = (char *) process_group;

    process_group->state = IA_CSS_PROCESS_GROUP_CREATED;

    process_group->protocol_version =
        ia_css_program_group_param_get_protocol_version(param);

    fragment_count = ia_css_program_group_param_get_fragment_count(param);
    process_count =
        ia_css_process_group_compute_process_count(manifest, param);
    terminal_count =
        ia_css_process_group_compute_terminal_count(manifest, param);
    enable_bitmap =
        ia_css_program_group_param_get_kernel_enable_bitmap(param);

    process_group->fragment_count = fragment_count;
    process_group->process_count = process_count;
    process_group->terminal_count = terminal_count;
    process_group->kernel_bitmap = enable_bitmap;

    process_grp_raw_ptr += sizeof(ia_css_process_group_t);
    process_tab_ptr = (uint16_t *) process_grp_raw_ptr;
    process_group->processes_offset =
        (uint16_t)(process_grp_raw_ptr - (char *)process_group);

    process_grp_raw_ptr += tot_bytes_for_pow2_align(
            sizeof(uint64_t), process_count * sizeof(uint16_t));
    terminal_tab_ptr = (uint16_t *) process_grp_raw_ptr;
    process_group->terminals_offset =
        (uint16_t)(process_grp_raw_ptr - (char *)process_group);

    /* Move raw pointer to the first process */
    process_grp_raw_ptr += tot_bytes_for_pow2_align(
            sizeof(uint64_t), terminal_count * sizeof(uint16_t));

    /* Set default */
    verifexit(ia_css_process_group_set_fragment_limit(
                process_group, fragment_count) == 0);

    /* Set process group terminal dependency list */
    /* This list is used during creating the process dependency list */
    manifest_terminal_count =
        ia_css_program_group_manifest_get_terminal_count(manifest);

    terminal_num = 0;
    for (i = 0; i < (int)manifest_terminal_count; i++) {
        ia_css_terminal_manifest_t *t_manifest =
            ia_css_program_group_manifest_get_term_mnfst(
                    manifest, i);

        verifexit(NULL != t_manifest);

        if (ia_css_process_group_is_terminal_enabled(
                    t_manifest, enable_bitmap)) {
            ia_css_terminal_t *terminal = NULL;
            ia_css_terminal_param_t *terminal_param =
                ia_css_program_group_param_get_terminal_param(
                        param, i);

            verifexit(NULL != terminal_param);
            terminal_tab_ptr[terminal_num] =
                (uint16_t)(process_grp_raw_ptr -
                        (char *)process_group);
            terminal = ia_css_terminal_create(
                    process_grp_raw_ptr, t_manifest,
                    terminal_param, enable_bitmap);
            verifexit(terminal != NULL);
            verifexit((ia_css_terminal_set_parent(
                    terminal, process_group) == 0));
            verifexit((ia_css_terminal_set_terminal_manifest_index(
                    terminal, i) == 0));
            IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, INFO,
                "ia_css_process_group_create: terminal_manifest_index %d\n",
                i);

            process_grp_raw_ptr += ia_css_terminal_get_size(
                            terminal);
            terminal_num++;
        } else {
            IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, INFO, "Skip terminal %d\n", i);
        }
    }
    verifexit(terminal_num == terminal_count);

    process_num = 0;
    for (i = 0; i < (int)ia_css_program_group_manifest_get_program_count(
                manifest); i++) {
        ia_css_process_t *process = NULL;
        ia_css_program_manifest_t *program_manifest =
            ia_css_program_group_manifest_get_prgrm_mnfst(
                    manifest, i);
        ia_css_program_param_t *program_param =
            ia_css_program_group_param_get_program_param(param, i);
        unsigned int prog_dep_index, proc_dep_index;
        unsigned int term_dep_index, term_index;

        verifexit(program_manifest != 0);
        verifexit(program_param    != NULL);

        if (ia_css_process_group_is_program_enabled(
                    program_manifest, enable_bitmap)) {

            verifexit(process_num < process_count);

            process_tab_ptr[process_num] =
                (uint16_t)(process_grp_raw_ptr -
                        (char *)process_group);

            /* instead of using program_param,
             * we can provide this directly to ia_css_process_create.
             * The corresponding public setter function is deprecated and will assert
             * upon use. */
            program_param->kernel_enable_bitmap =
                ia_css_kernel_bitmap_intersection(
                        ia_css_program_manifest_get_kernel_bitmap(program_manifest),
                        /*pg*/enable_bitmap);

            process = ia_css_process_create(
                    process_grp_raw_ptr,
                    program_manifest,
                    program_param,
                    i);
            verifexit(process != NULL);

            ia_css_process_set_parent(process, process_group);
            if (ia_css_has_program_manifest_fixed_cell(
                        program_manifest)) {
                vied_nci_cell_ID_t cell_id =
                    ia_css_program_manifest_get_cell_ID(
                            program_manifest);

                IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, INFO,
                    "ia_css_process_group_create: cell_id %d\n",
                    cell_id);
                ia_css_process_set_cell(process, cell_id);
            }

            process_grp_raw_ptr += ia_css_process_get_size(
                    process);
            /*
             * Set process dependencies of process derived
             * from program manifest
             */
            for (prog_dep_index = 0; prog_dep_index <
            ia_css_program_manifest_get_program_dependency_count(
                program_manifest); prog_dep_index++) {
                uint8_t dep_prog_idx =
                ia_css_program_manifest_get_program_dependency(
                    program_manifest, prog_dep_index);
                const ia_css_program_manifest_t *
                dep_prg_manifest =
            ia_css_program_group_manifest_get_prgrm_mnfst(
                    manifest, dep_prog_idx);
                ia_css_program_ID_t id =
                ia_css_program_manifest_get_program_ID(
                        dep_prg_manifest);

                verifexit(id != 0);
                for (proc_dep_index = 0;
                        proc_dep_index < process_num;
                        proc_dep_index++) {
                    ia_css_process_t *dep_process =
                    ia_css_process_group_get_process(
                            process_group,
                            proc_dep_index);

                    ia_css_process_set_cell_dependency(
                            process,
                            prog_dep_index, 0);

                if (ia_css_process_get_program_ID(
                        dep_process) == id) {
                    ia_css_process_set_cell_dependency(
                            process,
                            prog_dep_index,
                            proc_dep_index);
                        break;
                    }
                }
            }
            process_num++;

            /*
             * Set terminal dependencies of process derived
             * from program manifest
             */
            for (term_dep_index = 0; term_dep_index <
            ia_css_program_manifest_get_terminal_dependency_count(
                program_manifest); term_dep_index++) {
                uint8_t pm_term_index =
                ia_css_program_manifest_get_terminal_dependency
                    (program_manifest, term_dep_index);

                verifexit(pm_term_index < manifest_terminal_count);
                IA_CSS_TRACE_2(PSYSAPI_DYNAMIC, INFO,
                    "ia_css_process_group_create(): term_dep_index: %d, pm_term_index: %d\n",
                    term_dep_index, pm_term_index);
                for (term_index = 0;
                    term_index < terminal_count;
                    term_index++) {
                    ia_css_terminal_t *terminal =
                    ia_css_process_group_get_terminal(
                            process_group,
                            term_index);

                if (ia_css_terminal_get_terminal_manifest_index
                        (terminal) == pm_term_index) {
                    ia_css_process_set_terminal_dependency(
                            process,
                            term_dep_index,
                            term_index);
                    IA_CSS_TRACE_3(PSYSAPI_DYNAMIC, INFO,
                        "ia_css_process_group_create() set_terminal_dependency(process: %d, dep_idx: %d, term_idx: %d)\n",
                        i, term_dep_index, term_index);

                        break;
                    }
                }
            }
        }
    }
    verifexit(process_num == process_count);

    process_group->size =
        (uint32_t)ia_css_sizeof_process_group(manifest, param);
    process_group->ID =
        ia_css_program_group_manifest_get_program_group_ID(manifest);

    /* Initialize performance measurement fields to zero */
    process_group->pg_load_start_ts        = 0;
    process_group->pg_load_cycles        = 0;
    process_group->pg_init_cycles        = 0;
    process_group->pg_processing_cycles    = 0;
    process_group->pg_complete_cycles    = 0;

    process_group->error_handling_enable = 0;

    verifexit(process_group->size != 0);
    verifexit(process_group->ID != 0);

    ret = ia_css_process_group_on_create(process_group, manifest, param);
    verifexit(ret == 0);

    process_group->state = IA_CSS_PROCESS_GROUP_READY;
    retval = 0;

    IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_create(): Created successfully process group ID 0x%x\n",
        process_group->ID);

EXIT:
    if (NULL == process_grp_mem || NULL == manifest || NULL == param) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, WARNING,
            "ia_css_process_group_create invalid argument\n");
    }
    if (retval != 0) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_create failed (%i)\n", retval);
        process_group = ia_css_process_group_destroy(process_group);
    }
    return process_group;
}

ia_css_process_group_t *ia_css_process_group_destroy(
    ia_css_process_group_t *process_group)
{
    if (process_group != NULL) {
        ia_css_process_group_on_destroy(process_group);
        process_group = NULL;
    } else {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, WARNING,
            "ia_css_process_group_destroy invalid argument\n");
    }
    return process_group;
}

int ia_css_process_group_submit(
    ia_css_process_group_t *process_group)
{
    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_submit(): enter:\n");

    return ia_css_process_group_exec_cmd(process_group,
        IA_CSS_PROCESS_GROUP_CMD_SUBMIT);
}

int ia_css_process_group_start(
    ia_css_process_group_t *process_group)
{
    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_start(): enter:\n");

    return ia_css_process_group_exec_cmd(process_group,
        IA_CSS_PROCESS_GROUP_CMD_START);
}

int ia_css_process_group_stop(
    ia_css_process_group_t *process_group)
{
    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_stop(): enter:\n");

    return ia_css_process_group_exec_cmd(process_group,
        IA_CSS_PROCESS_GROUP_CMD_STOP);
}

int ia_css_process_group_run(
    ia_css_process_group_t *process_group)
{
    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_run(): enter:\n");

    return ia_css_process_group_exec_cmd(process_group,
        IA_CSS_PROCESS_GROUP_CMD_RUN);
}

int ia_css_process_group_suspend(
    ia_css_process_group_t *process_group)
{
    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_suspend(): enter:\n");

    return ia_css_process_group_exec_cmd(process_group,
        IA_CSS_PROCESS_GROUP_CMD_SUSPEND);
}

int ia_css_process_group_resume(
    ia_css_process_group_t *process_group)
{
    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_resume(): enter:\n");

    return ia_css_process_group_exec_cmd(process_group,
        IA_CSS_PROCESS_GROUP_CMD_RESUME);
}

int ia_css_process_group_reset(
    ia_css_process_group_t *process_group)
{
    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_reset(): enter:\n");

    return ia_css_process_group_exec_cmd(process_group,
        IA_CSS_PROCESS_GROUP_CMD_RESET);
}

int ia_css_process_group_abort(
    ia_css_process_group_t *process_group)
{
    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_abort(): enter:\n");

    return ia_css_process_group_exec_cmd(process_group,
        IA_CSS_PROCESS_GROUP_CMD_ABORT);
}

int ia_css_process_group_disown(
    ia_css_process_group_t *process_group)
{
    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_disown(): enter:\n");

    return ia_css_process_group_exec_cmd(process_group,
        IA_CSS_PROCESS_GROUP_CMD_DISOWN);
}

uint64_t ia_css_process_group_get_token(
    ia_css_process_group_t *process_group)
{
    uint64_t token = 0;

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, VERBOSE,
        "ia_css_process_group_get_token(): enter:\n");

    verifexit(process_group != NULL);

    token = process_group->token;

EXIT:
    if (NULL == process_group) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, WARNING,
            "ia_css_process_group_get_token invalid argument\n");
    }
    return token;
}

int ia_css_process_group_set_token(
    ia_css_process_group_t *process_group,
    const uint64_t token)
{
    int retval = -1;

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, VERBOSE,
        "ia_css_process_group_set_token(): enter:\n");

    verifexit(process_group != NULL);
    verifexit(token != 0);

    process_group->token = token;

    retval = 0;
EXIT:
    if (NULL == process_group || 0 == token) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, WARNING,
            "ia_css_process_group_set_token invalid argument\n");
    }
    if (retval != 0) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_token failed (%i)\n",
            retval);
    }
    return retval;
}

uint64_t ia_css_process_group_get_private_token(
    ia_css_process_group_t *process_group)
{
    uint64_t token = 0;

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, VERBOSE,
        "ia_css_process_group_get_private_token(): enter:\n");

    verifexit(process_group != NULL);

    token = process_group->private_token;

EXIT:
    if (NULL == process_group) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, WARNING,
            "ia_css_process_group_get_private_token invalid argument\n");
    }
    return token;
}

int ia_css_process_group_set_private_token(
    ia_css_process_group_t *process_group,
    const uint64_t token)
{
    int retval = -1;

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, VERBOSE,
        "ia_css_process_group_set_private_token(): enter:\n");

    verifexit(process_group != NULL);
    verifexit(token != 0);

    process_group->private_token = token;

    retval = 0;
EXIT:
    if (NULL == process_group || 0 == token) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, WARNING,
            "ia_css_process_group_set_private_token invalid argument\n");
    }
    if (retval != 0) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_private_token failed (%i)\n",
            retval);
    }
    return retval;
}

uint8_t ia_css_process_group_compute_process_count(
    const ia_css_program_group_manifest_t *manifest,
    const ia_css_program_group_param_t *param)
{
    uint8_t process_count = 0;
    ia_css_kernel_bitmap_t total_bitmap;
    ia_css_kernel_bitmap_t enable_bitmap;
    int i;

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, VERBOSE,
        "ia_css_process_group_compute_process_count(): enter:\n");

    verifexit(manifest != NULL);
    verifexit(param != NULL);

    total_bitmap =
        ia_css_program_group_manifest_get_kernel_bitmap(manifest);
    enable_bitmap =
        ia_css_program_group_param_get_kernel_enable_bitmap(param);

    verifexit(ia_css_is_program_group_manifest_valid(manifest));
    verifexit(ia_css_is_kernel_bitmap_subset(total_bitmap, enable_bitmap));
    verifexit(!ia_css_is_kernel_bitmap_empty(enable_bitmap));

    for (i = 0; i <
        (int)ia_css_program_group_manifest_get_program_count(manifest);
            i++) {
        ia_css_program_manifest_t *program_manifest =
            ia_css_program_group_manifest_get_prgrm_mnfst(
                    manifest, i);
        ia_css_kernel_bitmap_t program_bitmap =
            ia_css_program_manifest_get_kernel_bitmap(
                    program_manifest);
        /*
         * Programs can be orthogonal,
         * a mutually exclusive subset,
         * or a concurrent subset
         */
        if (!ia_css_is_kernel_bitmap_intersection_empty(enable_bitmap,
                    program_bitmap)) {
            ia_css_program_type_t program_type =
                ia_css_program_manifest_get_type(
                        program_manifest);
            /*
             * An exclusive subnode < exclusive supernode,
             * so simply don't count it
             */
            if (program_type !=
                IA_CSS_PROGRAM_TYPE_EXCLUSIVE_SUB &&
                program_type !=
                IA_CSS_PROGRAM_TYPE_VIRTUAL_SUB) {
                process_count++;
            }
        }
    }

EXIT:
    if (NULL == manifest || NULL == param) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, WARNING,
            "ia_css_process_group_compute_process_count invalid argument\n");
    }
    return process_count;
}

uint8_t ia_css_process_group_compute_terminal_count(
    const ia_css_program_group_manifest_t *manifest,
    const ia_css_program_group_param_t *param)
{
    uint8_t terminal_count = 0;
    ia_css_kernel_bitmap_t total_bitmap, enable_bitmap;
    int i;

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, VERBOSE,
        "ia_css_process_group_compute_terminal_count(): enter:\n");

    verifexit(manifest != NULL);
    verifexit(param != NULL);

    total_bitmap =
        ia_css_program_group_manifest_get_kernel_bitmap(manifest);
    enable_bitmap =
        ia_css_program_group_param_get_kernel_enable_bitmap(param);

    verifexit(ia_css_is_program_group_manifest_valid(manifest));
    verifexit(ia_css_is_kernel_bitmap_subset(total_bitmap, enable_bitmap));
    verifexit(!ia_css_is_kernel_bitmap_empty(enable_bitmap));

    for (i = 0; i <
        (int)ia_css_program_group_manifest_get_terminal_count(
            manifest); i++) {
        ia_css_terminal_manifest_t *tmanifest =
            ia_css_program_group_manifest_get_term_mnfst(
                    manifest, i);

        if (ia_css_process_group_is_terminal_enabled(
                    tmanifest, enable_bitmap)) {
            terminal_count++;
        }
    }

EXIT:
    if (NULL == manifest || NULL == param) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, WARNING,
            "ia_css_process_group_compute_terminal_count invalid argument\n");
    }
    return terminal_count;
}
#endif /* !defined(__VIED_CELL) */
