/*
 * 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.
 */

#ifndef __IA_CSS_PSYS_PROCESS_GROUP_IMPL_H
#define __IA_CSS_PSYS_PROCESS_GROUP_IMPL_H

#include <ia_css_psysapi_fw_version.h>
#include <ia_css_psys_process_group.h>
#include "ia_css_psys_process_group_cmd_impl.h"
#include <ia_css_psys_terminal.h>
#include <ia_css_psys_transport.h>
#include <ia_css_psys_process.h>
#include <ia_css_psys_terminal_manifest.h>
#include <ia_css_psys_program_manifest.h>
#include <ia_css_psys_program_group_manifest.h>
#include "ia_css_terminal_manifest_types.h"

#include "ia_css_rbm.h"

#include <ia_css_kernel_bitmap.h>    /* ia_css_kernel_bitmap_t */

#include <vied_nci_psys_system_global.h>
#include <ia_css_program_group_data.h>
#include "ia_css_rbm_manifest_types.h"
#include <type_support.h>
#include <error_support.h>
#include <misc_support.h>
#include <math_support.h>

#include "ia_css_psys_dynamic_trace.h"
#include "ia_css_terminal_manifest.h"

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
bool ia_css_process_group_is_data_terminal_enabled(
    const ia_css_data_terminal_manifest_t    *data_term_manifest,
    ia_css_kernel_bitmap_t enable_bitmap)
{
    bool is_terminal_enabled = false;

    ia_css_kernel_bitmap_t term_bitmap =
        ia_css_data_terminal_manifest_get_kernel_bitmap(
                data_term_manifest);
    /*
     * Terminals depend on a kernel,
     * if the kernel is present the program it contains and
     * the terminal the program depends on are active
     */
    is_terminal_enabled  = !ia_css_is_kernel_bitmap_intersection_empty(
            enable_bitmap,
            term_bitmap);
    return is_terminal_enabled;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
bool ia_css_process_group_is_spatial_terminal_enabled(
    const ia_css_spatial_param_terminal_manifest_t *spatial_term_man,
    ia_css_kernel_bitmap_t enable_bitmap)
{
    bool is_terminal_enabled = false;
    ia_css_kernel_bitmap_t term_kernel_bitmap = ia_css_kernel_bitmap_clear();

    term_kernel_bitmap =
        ia_css_kernel_bitmap_set(
            term_kernel_bitmap,
            spatial_term_man->kernel_id);
    is_terminal_enabled = !ia_css_is_kernel_bitmap_intersection_empty(
            enable_bitmap, term_kernel_bitmap);
    return is_terminal_enabled;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
bool ia_css_process_group_is_terminal_enabled(
    const ia_css_terminal_manifest_t *terminal_manifest,
    ia_css_kernel_bitmap_t enable_bitmap)
{
    ia_css_terminal_type_t terminal_type;
    bool is_terminal_enabled = false;

    verifjmpexit(NULL != terminal_manifest);
    terminal_type = ia_css_terminal_manifest_get_type(terminal_manifest);

    if (ia_css_is_terminal_manifest_data_terminal(terminal_manifest)) {
        ia_css_data_terminal_manifest_t    *data_term_manifest =
                        (ia_css_data_terminal_manifest_t *)terminal_manifest;
        is_terminal_enabled =
                ia_css_process_group_is_data_terminal_enabled(data_term_manifest, enable_bitmap);
    } else if (ia_css_is_terminal_manifest_spatial_parameter_terminal(
                terminal_manifest)) {
        ia_css_spatial_param_terminal_manifest_t *spatial_term_man =
            (ia_css_spatial_param_terminal_manifest_t *)
            terminal_manifest;
         is_terminal_enabled = ia_css_process_group_is_spatial_terminal_enabled(spatial_term_man,
            enable_bitmap);
    } else if (ia_css_is_terminal_manifest_parameter_terminal(
            terminal_manifest) && terminal_type ==
            IA_CSS_TERMINAL_TYPE_PARAM_CACHED_IN) {
        /*
         * For parameter out and program control terminals, we
         * disable the terminals if ALL the corresponding kernels
         * are disabled, for parameter in terminals we cannot do this;
         * even if kernels are disabled, it may be required that
         * (HW) parameters must be supplied via the parameter
         * in terminal (e.g. bypass bits).
         */
        is_terminal_enabled = true;

    } else if (ia_css_is_terminal_manifest_parameter_terminal(
            terminal_manifest) && terminal_type ==
            IA_CSS_TERMINAL_TYPE_PARAM_CACHED_OUT) {
        ia_css_kernel_bitmap_t term_kernel_bitmap = ia_css_kernel_bitmap_clear();
        ia_css_param_terminal_manifest_t *param_term_man =
            (ia_css_param_terminal_manifest_t *)terminal_manifest;
        ia_css_param_manifest_section_desc_t *section_desc;
        unsigned int section = 0;
        uint8_t kernel_id;

        for (section = 0; section < param_term_man->
                param_manifest_section_desc_count; section++) {
            section_desc =
        ia_css_param_terminal_manifest_get_prm_sct_desc(
                        param_term_man, section);
            verifjmpexit(section_desc != NULL);
            kernel_id = ia_css_param_manifest_section_desc_get_kernel_id(section_desc);
            term_kernel_bitmap = ia_css_kernel_bitmap_set(
                    term_kernel_bitmap,
                    kernel_id);
        }

        is_terminal_enabled = !ia_css_is_kernel_bitmap_intersection_empty(
                    enable_bitmap, term_kernel_bitmap);
    } else if (ia_css_is_terminal_manifest_program_terminal(
                terminal_manifest)) {
        ia_css_kernel_bitmap_t term_kernel_bitmap = ia_css_kernel_bitmap_clear();
        ia_css_program_terminal_manifest_t *prog_term_man =
            (ia_css_program_terminal_manifest_t *)terminal_manifest;
        unsigned int section = 0;

        for (section = 0;
            section < prog_term_man->fragment_param_manifest_section_desc_count;
            section++) {
            ia_css_fragment_param_manifest_section_desc_t *desc =
                ia_css_program_terminal_manifest_get_frgmnt_prm_sct_desc(
                    prog_term_man,
                    section);
            verifjmpexit(desc != NULL);

            term_kernel_bitmap = ia_css_kernel_bitmap_set(
                    term_kernel_bitmap,
                    ia_css_fragment_param_manifest_section_desc_get_kernel_id(desc));
        }

        is_terminal_enabled = !ia_css_is_kernel_bitmap_intersection_empty(
                    enable_bitmap, term_kernel_bitmap);
    } else if (ia_css_is_terminal_manifest_program_control_init_terminal(
                terminal_manifest)) {
        is_terminal_enabled = true;
    }
    return is_terminal_enabled;
EXIT:
    return false;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint16_t ia_css_process_group_get_fragment_limit(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint16_t fragment_limit = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    fragment_limit = process_group->fragment_limit;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_fragment_limit invalid argument\n");
    }
    return fragment_limit;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_set_fragment_limit(
    ia_css_process_group_t *process_group,
    const uint16_t fragment_limit)
{
    DECLARE_ERRVAL
    int retval = -1;
    uint16_t fragment_state;

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

    verifexitval(process_group != NULL, EFAULT);

    retval = ia_css_process_group_get_fragment_state(process_group,
        &fragment_state);

    verifexitval(retval == 0, EINVAL);
    verifexitval(fragment_limit > fragment_state, EINVAL);
    verifexitval(fragment_limit <= ia_css_process_group_get_fragment_count(
                process_group), EINVAL);

    process_group->fragment_limit = fragment_limit;

    retval = 0;
EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_fragment_limit invalid argument process_group\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_fragment_limit failed (%i)\n",
            retval);
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_clear_fragment_limit(
    ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    int retval = -1;

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

    verifexitval(process_group != NULL, EFAULT);
    process_group->fragment_limit = 0;

    retval = 0;
EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_clear_fragment_limit invalid argument process_group\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_clear_fragment_limit failed (%i)\n",
            retval);
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_attach_buffer(
    ia_css_process_group_t *process_group,
    vied_vaddress_t buffer,
    const ia_css_buffer_state_t buffer_state,
    const unsigned int terminal_index)
{
    DECLARE_ERRVAL
    int retval = -1;
    ia_css_terminal_t *terminal = NULL;

    NOT_USED(buffer_state);

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_attach_buffer(): enter:\n");

    verifexitval(process_group != NULL, EFAULT);

    terminal = ia_css_process_group_get_terminal(
                process_group, terminal_index);

    verifexitval(terminal != NULL, EINVAL);
    verifexitval(ia_css_process_group_get_state(process_group) ==
        IA_CSS_PROCESS_GROUP_READY, EINVAL);
    verifexitval(process_group->protocol_version ==
        IA_CSS_PROCESS_GROUP_PROTOCOL_LEGACY ||
        process_group->protocol_version ==
        IA_CSS_PROCESS_GROUP_PROTOCOL_PPG, EINVAL);

    if (process_group->protocol_version ==
        IA_CSS_PROCESS_GROUP_PROTOCOL_LEGACY) {
        /*
         * Legacy flow:
         * Terminal address is part of the process group structure
         */
        retval = ia_css_terminal_set_buffer(
            terminal, buffer);
    } else if (process_group->protocol_version ==
        IA_CSS_PROCESS_GROUP_PROTOCOL_PPG) {
        /*
         * PPG flow:
         * Terminal address is part of external buffer set structure
         */
        retval = ia_css_terminal_set_terminal_index(
            terminal, terminal_index);
    }
    verifexitval(retval == 0, EFAULT);

    IA_CSS_TRACE_2(PSYSAPI_DYNAMIC, INFO,
        "\tTerminal 0x%lx has buffer 0x%x\n", (unsigned long int)terminal, buffer);

    if (ia_css_is_terminal_data_terminal(terminal) == true) {
        ia_css_frame_t *frame =
            ia_css_data_terminal_get_frame(
                (ia_css_data_terminal_t *)terminal);
        verifexitval(frame != NULL, EINVAL);

        retval = ia_css_frame_set_buffer_state(frame, buffer_state);
        verifexitval(retval == 0, EINVAL);
    }

    retval = 0;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_attach_buffer invalid argument process_group\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_attach_buffer failed (%i)\n",
            retval);
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
vied_vaddress_t ia_css_process_group_detach_buffer(
    ia_css_process_group_t *process_group,
    const unsigned int terminal_index)
{
    DECLARE_ERRVAL
    int retval = -1;
    vied_vaddress_t buffer = VIED_NULL;

    ia_css_terminal_t *terminal = NULL;
    ia_css_process_group_state_t state;

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_detach_buffer(): enter:\n");

    verifexitval(process_group != NULL, EFAULT);

    terminal =
        ia_css_process_group_get_terminal(
                process_group, terminal_index);
    state = ia_css_process_group_get_state(process_group);

    verifexitval(terminal != NULL, EINVAL);
    verifexitval(state == IA_CSS_PROCESS_GROUP_READY, EINVAL);

    buffer = ia_css_terminal_get_buffer(terminal);

    if (ia_css_is_terminal_data_terminal(terminal) == true) {
        ia_css_frame_t *frame =
            ia_css_data_terminal_get_frame(
                    (ia_css_data_terminal_t *)terminal);
        verifexitval(frame != NULL, EINVAL);

        retval = ia_css_frame_set_buffer_state(frame, IA_CSS_BUFFER_NULL);
        verifexitval(retval == 0, EINVAL);
    }
    ia_css_terminal_set_buffer(terminal, VIED_NULL);

    retval = 0;
EXIT:
    /*
     * buffer pointer will appear on output,
     * regardless of subsequent fails to avoid memory leaks
     */
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_detach_buffer invalid argument process_group\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_detach_buffer failed (%i)\n",
            retval);
    }
    return buffer;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_attach_stream(
    ia_css_process_group_t *process_group,
    uint32_t stream,
    const ia_css_buffer_state_t buffer_state,
    const unsigned int terminal_index)
{
    int retval = -1;

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_attach_stream(): enter:\n");

    NOT_USED(process_group);
    NOT_USED(stream);
    NOT_USED(buffer_state);
    NOT_USED(terminal_index);

    if (retval != 0) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_attach_stream failed (%i)\n",
            retval);
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint32_t ia_css_process_group_detach_stream(
    ia_css_process_group_t *process_group,
    const unsigned int terminal_index)
{
    int retval = -1;
    uint32_t stream = 0;

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_detach_stream(): enter:\n");

    NOT_USED(process_group);
    NOT_USED(terminal_index);

    if (retval != 0) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_detach_stream failed (%i)\n",
            retval);
    }
    return stream;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_set_barrier(
    ia_css_process_group_t *process_group,
    const vied_nci_barrier_ID_t barrier_index)
{
    DECLARE_ERRVAL
    int retval = -1;
    vied_nci_resource_bitmap_t bit_mask;
    vied_nci_resource_bitmap_t resource_bitmap;

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

    verifexitval(process_group != NULL, EFAULT);

    resource_bitmap =
        ia_css_process_group_get_resource_bitmap(process_group);

    bit_mask = vied_nci_barrier_bit_mask(barrier_index);

    verifexitval(bit_mask != 0, EINVAL);
    verifexitval(vied_nci_is_bitmap_clear(bit_mask, resource_bitmap), EINVAL);

    resource_bitmap = vied_nci_bitmap_set(resource_bitmap, bit_mask);

    retval =
        ia_css_process_group_set_resource_bitmap(
            process_group, resource_bitmap);
EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_barrier invalid argument process_group\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_barrier failed (%i)\n",
            retval);
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_clear_barrier(
    ia_css_process_group_t *process_group,
    const vied_nci_barrier_ID_t barrier_index)
{
    DECLARE_ERRVAL
    int retval = -1;
    vied_nci_resource_bitmap_t bit_mask, resource_bitmap;

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

    verifexitval(process_group != NULL, EFAULT);

    resource_bitmap =
        ia_css_process_group_get_resource_bitmap(process_group);

    bit_mask = vied_nci_barrier_bit_mask(barrier_index);

    verifexitval(bit_mask != 0, EINVAL);
    verifexitval(vied_nci_is_bitmap_set(bit_mask, resource_bitmap), EINVAL);

    resource_bitmap = vied_nci_bitmap_clear(resource_bitmap, bit_mask);

    retval =
        ia_css_process_group_set_resource_bitmap(
                process_group, resource_bitmap);
EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_clear_barrier invalid argument process_group\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_clear_barrier failed (%i)\n",
            retval);
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_print(
    const ia_css_process_group_t *process_group,
    void *fid)
{
    DECLARE_ERRVAL
    int retval = -1;
    int i;

    uint8_t    process_count;
    uint8_t terminal_count;
    vied_vaddress_t ipu_vaddress = VIED_NULL;
    ia_css_rbm_t routing_bitmap;

    NOT_USED(fid);

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

    verifexitval(process_group != NULL, EFAULT);
    retval = ia_css_process_group_get_ipu_vaddress(process_group, &ipu_vaddress);
    verifexitval(retval == 0, EINVAL);

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "=============== Process group print start ===============\n");
    IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, INFO,
        "\tprocess_group cpu address = 0x%lx\n", (unsigned long int)process_group);
    IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, INFO,
        "\tipu_virtual_address = %x\n", ipu_vaddress);
    IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, INFO,
        "\tsizeof(process_group) = %d\n",
        (int)ia_css_process_group_get_size(process_group));
    IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, INFO,
        "\tfragment_count = %d\n",
        (int)ia_css_process_group_get_fragment_count(process_group));

    routing_bitmap = *ia_css_process_group_get_routing_bitmap(process_group);
    for (i = 0; i < (int)IA_CSS_RBM_NOF_ELEMS; i++) {
        IA_CSS_TRACE_2(PSYSAPI_DYNAMIC, INFO,
            "\trouting_bitmap[index = %d] = 0x%X\n",
            i, (int)routing_bitmap.data[i]);
    }

    IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, INFO,
        "\tprogram_group(process_group) = %d\n",
        (int)ia_css_process_group_get_program_group_ID(process_group));
    process_count = ia_css_process_group_get_process_count(process_group);
    terminal_count =
        ia_css_process_group_get_terminal_count(process_group);

    IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, INFO,
        "\t%d processes\n", (int)process_count);
    for (i = 0; i < (int)process_count; i++) {
        ia_css_process_t *process =
            ia_css_process_group_get_process(process_group, i);

        retval = ia_css_process_print(process, fid);
        verifjmpexit(retval == 0);
    }
    IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, INFO,
        "\t%d terminals\n", (int)terminal_count);
    for (i = 0; i < (int)terminal_count; i++) {
        ia_css_terminal_t *terminal =
            ia_css_process_group_get_terminal(process_group, i);

        retval = ia_css_terminal_print(terminal, fid);
        verifjmpexit(retval == 0);
    }
    IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, INFO,
        "\terror_handling_enable = %u\n", process_group->error_handling_enable);
    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "=============== Process group print end ===============\n");
    retval = 0;
EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_print invalid argument\n");
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
bool ia_css_is_process_group_valid(
    const ia_css_process_group_t *process_group,
    const ia_css_program_group_manifest_t *pg_manifest,
    const ia_css_program_group_param_t *param)
{
    DECLARE_ERRVAL
    bool invalid_flag = false;
    uint8_t proc_idx;
    uint8_t proc_term_idx;
    uint8_t    process_count;
    uint8_t    program_count;
    uint8_t terminal_count;
    uint8_t man_terminal_count;

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

    verifexitval(process_group != NULL, EFAULT);
    verifexitval(pg_manifest != NULL, EFAULT);
    NOT_USED(param);

    process_count = process_group->process_count;
    terminal_count = process_group->terminal_count;
    program_count = ia_css_program_group_manifest_get_program_count(pg_manifest);
    man_terminal_count = ia_css_program_group_manifest_get_terminal_count(pg_manifest);

    /* Validate process group */
    invalid_flag = invalid_flag ||
        !(program_count >= process_count) ||
        !(man_terminal_count >= terminal_count) ||
        !(process_group->size > process_group->processes_offset) ||
        !(process_group->size > process_group->terminals_offset);

    /* Validate processes */
    for (proc_idx = 0; proc_idx < process_count; proc_idx++) {
        const ia_css_process_t *process;
        ia_css_program_manifest_t *p_manifest = NULL;
        ia_css_program_ID_t prog_id;
        bool no_match_found = true;

        process = ia_css_process_group_get_process(process_group, proc_idx);
        verifexitval(NULL != process, EFAULT);
        prog_id = ia_css_process_get_program_ID(process);
        p_manifest = ia_css_program_group_manifest_get_prgrm_mnfst(pg_manifest,
                                       ia_css_process_get_program_idx(process));
        verifexitval(NULL != p_manifest, EFAULT);

        if (prog_id == ia_css_program_manifest_get_program_ID(p_manifest)) {
            invalid_flag = invalid_flag || !ia_css_is_process_valid(process, p_manifest);
            no_match_found = false;
        }

        invalid_flag = invalid_flag || no_match_found;
    }

    /* Validate terminals */
    for (proc_term_idx = 0; proc_term_idx < terminal_count; proc_term_idx++) {
        int man_term_idx;
        const ia_css_terminal_t *terminal;
        const ia_css_terminal_manifest_t *terminal_manifest;

        terminal = ia_css_process_group_get_terminal(process_group, proc_term_idx);
        verifexitval(NULL != terminal, EFAULT);
        man_term_idx = ia_css_terminal_get_terminal_manifest_index(terminal);
        terminal_manifest = ia_css_program_group_manifest_get_term_mnfst(pg_manifest, man_term_idx);

        invalid_flag = invalid_flag || !ia_css_is_terminal_valid(terminal, terminal_manifest);
    }

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_is_process_group_valid() invalid argument\n");
        return false;
    } else {
        return (!invalid_flag);
    }
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
bool ia_css_can_process_group_submit(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    int i;
    bool can_submit = false;
    int retval = -1;
    uint8_t    terminal_count =
        ia_css_process_group_get_terminal_count(process_group);

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_can_process_group_submit(): enter:\n");

    verifexitval(process_group != NULL, EFAULT);

    for (i = 0; i < (int)terminal_count; i++) {
        ia_css_terminal_t *terminal =
            ia_css_process_group_get_terminal(process_group, i);
        vied_vaddress_t buffer;
        ia_css_buffer_state_t buffer_state;

        verifexitval(terminal != NULL, EINVAL);

        if (process_group->protocol_version ==
            IA_CSS_PROCESS_GROUP_PROTOCOL_LEGACY) {
            /*
             * For legacy pg flow, buffer addresses are contained inside
             * the process group structure, so these need to be validated
             * on process group submission.
             */
            buffer = ia_css_terminal_get_buffer(terminal);
            IA_CSS_TRACE_3(PSYSAPI_DYNAMIC, INFO,
                "\tH: Terminal number(%d) is 0x%lx having buffer 0x%x\n",
                i, (unsigned long int)terminal, buffer);
        }

        /* buffer_state is applicable only for data terminals*/
        if (ia_css_is_terminal_data_terminal(terminal) == true) {
            ia_css_frame_t *frame =
                ia_css_data_terminal_get_frame(
                    (ia_css_data_terminal_t *)terminal);

            verifexitval(frame != NULL, EINVAL);
            buffer_state = ia_css_frame_get_buffer_state(frame);
            if ((buffer_state == IA_CSS_BUFFER_NULL) ||
                (buffer_state == IA_CSS_N_BUFFER_STATES)) {
                break;
            }
        } else if (
            (ia_css_is_terminal_parameter_terminal(terminal)
                != true) &&
            (ia_css_is_terminal_program_terminal(terminal)
                != true) &&
            (ia_css_is_terminal_program_control_init_terminal(terminal)
                != true) &&
            (ia_css_is_terminal_spatial_parameter_terminal(
                terminal) != true)) {
            /* neither data nor parameter terminal, so error.*/
            break;
        }

    }
    /* Only true if no check failed */
    can_submit = (i == terminal_count);

    retval = 0;
EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_can_process_group_submit invalid argument process_group\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_can_process_group_submit failed (%i)\n",
            retval);
    }
    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_can_process_group_submit(): leave:\n");
    return can_submit;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
bool ia_css_can_enqueue_buffer_set(
    const ia_css_process_group_t *process_group,
    const ia_css_buffer_set_t *buffer_set)
{
    DECLARE_ERRVAL
    int i;
    bool can_enqueue = false;
    int retval = -1;
    uint8_t    terminal_count;

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_can_enqueue_buffer_set(): enter:\n");

    verifexitval(process_group != NULL, EFAULT);
    verifexitval(buffer_set != NULL, EFAULT);

    terminal_count =
        ia_css_process_group_get_terminal_count(process_group);

    /*
     * For ppg flow, buffer addresses are contained in the
     * external buffer set structure, so these need to be
     * validated before enqueueing.
     */
    verifexitval(process_group->protocol_version ==
        IA_CSS_PROCESS_GROUP_PROTOCOL_PPG, EFAULT);

    for (i = 0; i < (int)terminal_count; i++) {
        ia_css_terminal_t *terminal =
            ia_css_process_group_get_terminal(process_group, i);
        vied_vaddress_t buffer;
        ia_css_buffer_state_t buffer_state;

        verifexitval(terminal != NULL, EINVAL);

        buffer = ia_css_buffer_set_get_buffer(buffer_set, terminal);
        IA_CSS_TRACE_3(PSYSAPI_DYNAMIC, INFO,
            "\tH: Terminal number(%d) is 0x%lx having buffer 0x%x\n",
            i, (unsigned long int)terminal, buffer);

        /* buffer_state is applicable only for data terminals*/
        if (ia_css_is_terminal_data_terminal(terminal) == true) {
            ia_css_frame_t *frame =
                ia_css_data_terminal_get_frame(
                    (ia_css_data_terminal_t *)terminal);

            verifexitval(frame != NULL, EINVAL);
            buffer_state = ia_css_frame_get_buffer_state(frame);
            if ((buffer_state == IA_CSS_BUFFER_NULL) ||
                (buffer_state == IA_CSS_N_BUFFER_STATES)) {
                break;
            }
        } else if (
            (ia_css_is_terminal_parameter_terminal(terminal)
                != true) &&
            (ia_css_is_terminal_program_terminal(terminal)
                != true) &&
            (ia_css_is_terminal_program_control_init_terminal(terminal)
                != true) &&
            (ia_css_is_terminal_spatial_parameter_terminal(
                terminal) != true)) {
            /* neither data nor parameter terminal, so error.*/
            break;
        }
    }
    /* Only true if no check failed */
    can_enqueue = (i == terminal_count);

    retval = 0;
EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_can_enqueue_buffer_set invalid argument\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_can_enqueue_buffer_set failed (%i)\n",
            retval);
    }
    return can_enqueue;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
bool ia_css_can_process_group_start(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    int i;
    bool can_start = false;
    int retval = -1;
    uint8_t    terminal_count;

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_can_process_group_start(): enter:\n");

    verifexitval(process_group != NULL, EFAULT);

    terminal_count =
        ia_css_process_group_get_terminal_count(process_group);
    for (i = 0; i < (int)terminal_count; i++) {
        ia_css_terminal_t *terminal =
            ia_css_process_group_get_terminal(process_group, i);
        ia_css_buffer_state_t buffer_state;
        bool ok = false;

        verifexitval(terminal != NULL, EINVAL);
        if (ia_css_is_terminal_data_terminal(terminal) == true) {
            /*
             * buffer_state is applicable only for data terminals
             */
            ia_css_frame_t *frame =
                ia_css_data_terminal_get_frame(
                    (ia_css_data_terminal_t *)terminal);
            bool is_input = ia_css_is_terminal_input(terminal);
            /*
             * check for NULL here.
             * then invoke next 2 statements
             */
            verifexitval(frame != NULL, EINVAL);
            IA_CSS_TRACE_5(PSYSAPI_DYNAMIC, VERBOSE,
                "\tTerminal %d: buffer_state %u, access_type %u, data_bytes %u, data %u\n",
                i, frame->buffer_state, frame->access_type,
                frame->data_bytes, frame->data);
            buffer_state = ia_css_frame_get_buffer_state(frame);

            ok = ((is_input &&
                (buffer_state == IA_CSS_BUFFER_FULL)) ||
                    (!is_input && (buffer_state ==
                            IA_CSS_BUFFER_EMPTY)));

        } else if (ia_css_is_terminal_parameter_terminal(terminal) ==
                true) {
            /*
             * FIXME:
             * is there any pre-requisite for param_terminal?
             */
            ok = true;
        } else if (ia_css_is_terminal_program_terminal(terminal) ==
                true) {
            ok = true;
        } else if (ia_css_is_terminal_program_control_init_terminal(terminal) ==
                true) {
            ok = true;
        } else if (ia_css_is_terminal_spatial_parameter_terminal(
                    terminal) == true) {
            ok = true;
        } else {
            /* neither data nor parameter terminal, so error.*/
            break;
        }

        if (!ok)
            break;
    }
    /* Only true if no check failed */
    can_start = (i == terminal_count);

    retval = 0;
EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_can_process_group_submit invalid argument process_group\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_can_process_group_start failed (%i)\n",
            retval);
    }
    return can_start;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
size_t ia_css_process_group_get_size(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    size_t size = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    size = process_group->size;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_size invalid argument\n");
    }
    return size;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
ia_css_process_group_state_t ia_css_process_group_get_state(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    ia_css_process_group_state_t state = IA_CSS_N_PROCESS_GROUP_STATES;

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

    verifexitval(process_group != NULL, EFAULT);

    state = process_group->state;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_state invalid argument\n");
    }
    return state;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
ia_css_kernel_bitmap_t ia_css_process_group_get_kernel_bitmap(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    ia_css_kernel_bitmap_t bitmap = ia_css_kernel_bitmap_clear();

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

    verifexitval(process_group != NULL, EFAULT);

    bitmap = process_group->kernel_bitmap;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
         "ia_css_process_group_get_kernel_bitmap invalid argument process\n");
    }
    return bitmap;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
const ia_css_rbm_t *ia_css_process_group_get_routing_bitmap(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    const ia_css_rbm_t *rbm = NULL;

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

    verifexitval(process_group != NULL, EFAULT);

    rbm = &(process_group->routing_bitmap);
EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_routing_bitmap invalid argument\n");
    }
    return rbm;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint16_t ia_css_process_group_get_fragment_count(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint16_t fragment_count = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    fragment_count = process_group->fragment_count;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_fragment_count invalid argument\n");
    }
    return fragment_count;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint8_t ia_css_process_group_get_process_count(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint8_t process_count = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    process_count = process_group->process_count;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_process_count invalid argument\n");
    }
    return process_count;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint8_t ia_css_process_group_get_terminal_count(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint8_t terminal_count = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    terminal_count = process_group->terminal_count;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_terminal_count invalid argument\n");
    }
    return terminal_count;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint32_t ia_css_process_group_get_psys_server_init_cycles(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint32_t psys_server_init_cycles = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    psys_server_init_cycles = process_group->psys_server_init_cycles;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "uint32_t ia_css_process_group_get_psys_server_init_cycles invalid argument\n");
    }
    return psys_server_init_cycles;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint32_t ia_css_process_group_get_pg_load_start_ts(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint32_t pg_load_start_ts = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    pg_load_start_ts = process_group->pg_load_start_ts;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_pg_load_start_ts invalid argument\n");
    }
    return pg_load_start_ts;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint32_t ia_css_process_group_get_pg_load_cycles(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint32_t pg_load_cycles = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    pg_load_cycles = process_group->pg_load_cycles;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_pg_load_cycles invalid argument\n");
    }
    return pg_load_cycles;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint32_t ia_css_process_group_get_pg_init_cycles(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint32_t pg_init_cycles = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    pg_init_cycles = process_group->pg_init_cycles;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_pg_init_cycles invalid argument\n");
    }
    return pg_init_cycles;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint32_t ia_css_process_group_get_pg_processing_cycles(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint32_t pg_processing_cycles = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    pg_processing_cycles = process_group->pg_processing_cycles;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_pg_processing_cycles invalid argument\n");
    }
    return pg_processing_cycles;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint32_t ia_css_process_group_get_pg_next_frame_init_cycles(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint32_t pg_next_frame_init_cycles = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    pg_next_frame_init_cycles = process_group->pg_next_frame_init_cycles;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_pg_next_frame_init_cycles invalid argument\n");
    }
    return pg_next_frame_init_cycles;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint32_t ia_css_process_group_get_pg_complete_cycles(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint32_t pg_complete_cycles = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    pg_complete_cycles = process_group->pg_complete_cycles;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_pg_complete_cycles invalid argument\n");
    }
    return pg_complete_cycles;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
ia_css_terminal_t *ia_css_process_group_get_terminal_from_type(
        const ia_css_process_group_t *process_group,
        const ia_css_terminal_type_t terminal_type)
{
    unsigned int proc_cnt;
    ia_css_terminal_t *terminal = NULL;

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

    for (proc_cnt = 0; proc_cnt < (unsigned int)ia_css_process_group_get_terminal_count(process_group); proc_cnt++) {
        terminal = ia_css_process_group_get_terminal(process_group, proc_cnt);
        if (terminal == NULL) {
            IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
                    "ia_css_process_group_get_terminal_from_type() Failed to get terminal %d", proc_cnt);
            goto EXIT;
        }
        if (ia_css_terminal_get_type(terminal) == terminal_type) {
            return terminal;
        }
        terminal = NULL; /* If not the expected type, return NULL */
    }
EXIT:
    return terminal;
}

/* Returns the terminal or NULL if it was not found
   For some of those maybe valid to not exist at all in the process group */
IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
const ia_css_terminal_t *ia_css_process_group_get_single_instance_terminal(
    const ia_css_process_group_t     *process_group,
    ia_css_terminal_type_t        term_type)
{
    int i, term_count;

    assert(process_group != NULL);

    /* Those below have at most one instance per process group */
    assert(term_type == IA_CSS_TERMINAL_TYPE_PARAM_CACHED_IN ||
        term_type == IA_CSS_TERMINAL_TYPE_PARAM_CACHED_OUT ||
        term_type == IA_CSS_TERMINAL_TYPE_PROGRAM ||
        term_type == IA_CSS_TERMINAL_TYPE_PROGRAM_CONTROL_INIT);

    term_count = ia_css_process_group_get_terminal_count(process_group);

    for (i = 0; i < term_count; i++) {
        const ia_css_terminal_t    *terminal = ia_css_process_group_get_terminal(process_group, i);

        if (ia_css_terminal_get_type(terminal) == term_type) {
            /* Only one parameter terminal per process group */
            return terminal;
        }
    }

    return NULL;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
ia_css_terminal_t *ia_css_process_group_get_manifest_idx_terminal(
    const ia_css_process_group_t *process_grp,
    const unsigned int manifest_idx)
{
    DECLARE_ERRVAL
    uint8_t i = 0;
    uint8_t terminal_count;

    terminal_count =
        ia_css_process_group_get_terminal_count(process_grp);

    for ( i = 0; i < terminal_count;
            i++) {
        unsigned int man_term_idx;
        ia_css_terminal_t *terminal;

        terminal =
            ia_css_process_group_get_terminal(
                    process_grp, i);
        verifexitval(NULL != terminal, EFAULT);
        man_term_idx =
            ia_css_terminal_get_terminal_manifest_index(terminal);
        if (man_term_idx == manifest_idx)
            return terminal;
    }
EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_manifest_idx_terminal Error\n");
    }
    return NULL;

}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
ia_css_terminal_t *ia_css_process_group_get_terminal(
    const ia_css_process_group_t *process_grp,
    const unsigned int terminal_num)
{
    DECLARE_ERRVAL
    ia_css_terminal_t *terminal_ptr = NULL;
    uint16_t *terminal_offset_table;

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

    verifexitval(process_grp != NULL, EFAULT);
    verifexitval(terminal_num < process_grp->terminal_count, EINVAL);

    terminal_offset_table =
        (uint16_t *)((char *)process_grp +
                process_grp->terminals_offset);
    terminal_ptr =
        (ia_css_terminal_t *)((char *)process_grp +
                terminal_offset_table[terminal_num]);

    verifexitval(terminal_ptr != NULL, EFAULT);

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_terminal invalid argument\n");
    }
    return terminal_ptr;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
ia_css_process_t *ia_css_process_group_get_process(
    const ia_css_process_group_t *process_grp,
    const unsigned int process_num)
{
    DECLARE_ERRVAL
    ia_css_process_t *process_ptr = NULL;
    uint16_t *process_offset_table;

    verifexitval(process_grp != NULL, EFAULT);
    verifexitval(process_num < process_grp->process_count, EINVAL);

    process_offset_table =
        (uint16_t *)((char *)process_grp +
                process_grp->processes_offset);
    process_ptr =
        (ia_css_process_t *)((char *)process_grp +
                process_offset_table[process_num]);

    verifexitval(process_ptr != NULL, EFAULT);

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_process invalid argument\n");
    }
    return process_ptr;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
ia_css_program_group_ID_t ia_css_process_group_get_program_group_ID(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    ia_css_program_group_ID_t id = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    id = process_group->ID;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_program_group_ID invalid argument\n");
    }
    return id;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
vied_nci_resource_bitmap_t ia_css_process_group_get_resource_bitmap(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    vied_nci_resource_bitmap_t resource_bitmap = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    resource_bitmap = process_group->resource_bitmap;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_resource_bitmap invalid argument\n");
    }
    return resource_bitmap;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_set_resource_bitmap(
    ia_css_process_group_t *process_group,
    const vied_nci_resource_bitmap_t resource_bitmap)
{
    DECLARE_ERRVAL
    int retval = -1;

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

    verifexitval(process_group != NULL, EFAULT);

    process_group->resource_bitmap = resource_bitmap;

    retval = 0;
EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_resource_bitmap invalid argument process_group\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_resource_bitmap failed (%i)\n",
            retval);
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_set_routing_bitmap(
    ia_css_process_group_t *process_group,
    const ia_css_rbm_t rbm)
{
    DECLARE_ERRVAL
    int retval = -1;

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

    verifexitval(process_group != NULL, EFAULT);
    process_group->routing_bitmap = rbm;
    retval = 0;
EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_routing_bitmap invalid argument process_group\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_routing_bitmap failed (%i)\n",
            retval);
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint32_t ia_css_process_group_compute_cycle_count(
    const ia_css_program_group_manifest_t *manifest,
    const ia_css_program_group_param_t *param)
{
    DECLARE_ERRVAL
    uint32_t cycle_count = 0;

    NOT_USED(manifest);
    NOT_USED(param);

    verifexitval(manifest != NULL, EFAULT);
    verifexitval(param != NULL, EFAULT);

    cycle_count = 1;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_compute_cycle_count invalid argument\n");
    }
    return cycle_count;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_set_fragment_state(
    ia_css_process_group_t *process_group,
    uint16_t fragment_state)
{
    DECLARE_ERRVAL
    int retval = -1;

    IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, INFO,
        "ia_css_process_group_set_fragment_state(): enter:\n");

    verifexitval(process_group != NULL, EFAULT);
    verifexitval(fragment_state <= ia_css_process_group_get_fragment_count(
                process_group), EINVAL);

    process_group->fragment_state = fragment_state;
    retval = 0;
EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_fragment_state invalid argument process_group\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_fragment_state failed (%i)\n",
            retval);
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_get_fragment_state(
    const ia_css_process_group_t *process_group,
    uint16_t *fragment_state)
{
    DECLARE_ERRVAL
    int retval = -1;

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

    verifexitval(process_group != NULL, EFAULT);
    verifexitval(fragment_state != NULL, EFAULT);

    *fragment_state = process_group->fragment_state;
    retval = 0;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_fragment_state invalid argument\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_fragment_state failed (%i)\n",
            retval);
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_get_ipu_vaddress(
    const ia_css_process_group_t *process_group,
    vied_vaddress_t *ipu_vaddress)
{
    DECLARE_ERRVAL
    int retval = -1;

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

    verifexitval(process_group != NULL, EFAULT);
    verifexitval(ipu_vaddress != NULL, EFAULT);

    *ipu_vaddress = process_group->ipu_virtual_address;
    retval = 0;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_ipu_vaddress invalid argument\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_ipu_vaddress failed (%i)\n",
            retval);
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_set_ipu_vaddress(
    ia_css_process_group_t *process_group,
    vied_vaddress_t ipu_vaddress)
{
    DECLARE_ERRVAL
    int retval = -1;

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

    verifexitval(process_group != NULL, EFAULT);

    process_group->ipu_virtual_address = ipu_vaddress;
    retval = 0;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_ipu_vaddress invalid argument\n");
    }
    if (!noerror()) {
        IA_CSS_TRACE_1(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_ipu_vaddress failed (%i)\n",
            retval);
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint8_t ia_css_process_group_get_protocol_version(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint8_t protocol_version = IA_CSS_PROCESS_GROUP_N_PROTOCOLS;

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

    verifexitval(process_group != NULL, EFAULT);

    protocol_version = process_group->protocol_version;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_protocol_version invalid argument\n");
    }
    return protocol_version;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint8_t ia_css_process_group_get_base_queue_id(
    ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint8_t queue_id = IA_CSS_N_PSYS_CMD_QUEUE_ID;

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

    verifexitval(process_group != NULL, EFAULT);

    queue_id = process_group->base_queue_id;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_base_queue_id invalid argument\n");
    }
    return queue_id;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_set_base_queue_id(
    ia_css_process_group_t *process_group,
    uint8_t queue_id)
{
    DECLARE_ERRVAL
    int retval = -1;

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

    verifexitval(process_group != NULL, EFAULT);

    /* Make sure that Driver\host don't use the main command queue or device queue for the ppg queues*/
    if ((queue_id > IA_CSS_PSYS_CMD_QUEUE_DEVICE_ID) && ((queue_id + process_group->num_queues - 1) < IA_CSS_N_PSYS_CMD_QUEUE_ID)) {
        process_group->base_queue_id = queue_id;
        retval = 0;
    } else {
        IA_CSS_TRACE_2(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_base_queue_id: queue_id %u out of range for process_group 0x%lx\n",
                       queue_id, (unsigned long int)process_group);
    }

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_base_queue_id invalid argument\n");
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint8_t ia_css_process_group_get_num_queues(
    ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint8_t num_queues = 0;

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

    verifexitval(process_group != NULL, EFAULT);

    num_queues = process_group->num_queues;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_num_queues invalid argument\n");
    }
    return num_queues;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
int ia_css_process_group_set_num_queues(
    ia_css_process_group_t *process_group,
    uint8_t num_queues)
{
    DECLARE_ERRVAL
    int retval = -1;

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

    verifexitval(process_group != NULL, EFAULT);

    process_group->num_queues = num_queues;
    retval = 0;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_num_queues invalid argument\n");
    }
    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_H
int ia_css_process_group_set_error_handling_enable(
    ia_css_process_group_t *process_group,
    const bool error_handling_enable)
{
    DECLARE_ERRVAL
    int retval = -1;

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

    verifexitval(process_group != NULL, EFAULT);

    process_group->error_handling_enable = (uint8_t)((error_handling_enable == true) ? 1 : 0);
    retval = 0;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_set_error_handling_enable invalid argument\n");
    }

    return retval;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
uint8_t ia_css_process_group_get_error_handling_enable(
    const ia_css_process_group_t *process_group)
{
    DECLARE_ERRVAL
    uint8_t error_handling_enable = UINT8_MAX;

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

    verifexitval(process_group != NULL, EFAULT);

    /* Error handling enable flag should serve as boolean type, so it can be either 0 or 1 */
    assert(process_group->error_handling_enable <= (uint8_t)1);
    error_handling_enable = process_group->error_handling_enable;

EXIT:
    if (haserror(EFAULT)) {
        IA_CSS_TRACE_0(PSYSAPI_DYNAMIC, ERROR,
            "ia_css_process_group_get_error_handling_enable invalid argument\n");
    }

    return error_handling_enable;
}

IA_CSS_PSYS_DYNAMIC_STORAGE_CLASS_C
bool ia_css_process_group_has_vp(const ia_css_process_group_t *process_group)
{
#if NUM_OF_VP_CELLS > 0
    bool has_vp = false;
#ifdef HAS_VP
    uint32_t i;

    uint8_t process_count = ia_css_process_group_get_process_count(process_group);

    for (i = 0; i < process_count; i++) {
        ia_css_process_t *process;
        vied_nci_cell_ID_t cell_id;

        process = ia_css_process_group_get_process(process_group, i);
        cell_id = ia_css_process_get_cell(process);

        if (VIED_NCI_VP_TYPE_ID == vied_nci_cell_get_type(cell_id)) {
            has_vp = true;
            break;
        }
    }
#else /* not HAS_VP */
        NOT_USED(process_group);
#endif /* HAS_VP */

    return has_vp;
#else
    NOT_USED(process_group);
    return false;
#endif
}

#endif /* __IA_CSS_PSYS_PROCESS_GROUP_IMPL_H */
