/* Copyright 2014-2016 Freescale Semiconductor Inc.
 * Copyright 2017-2021 NXP
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * * Neither the name of the above-listed copyright holders nor the
 * names of any contributors may be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 *
 * ALTERNATIVELY, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") as published by the Free Software
 * Foundation, either version 2 of that License or (at your option) any
 * later version.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include <getopt.h>
#include <ctype.h>
#include "restool.h"
#include "utils.h"
#include "dprc_commands_generate_dpl.h"
#include "mc_v9/fsl_dpaiop.h"
#include "mc_v9/fsl_dpbp.h"
#include "mc_v9/fsl_dpci.h"
#include "mc_v9/fsl_dpcon.h"
#include "mc_v9/fsl_dpdbg.h"
#include "mc_v9/fsl_dpdcei.h"
#include "mc_v9/fsl_dpdmai.h"
#include "mc_v10/fsl_dpdmux.h"
#include "mc_v9/fsl_dpio.h"
#include "mc_v9/fsl_dpmac.h"
#include "mc_v9/fsl_dpmcp.h"
#include "mc_v10/fsl_dprc.h"
#include "mc_v9/fsl_dprtc.h"
#include "mc_v9/fsl_dpseci.h"
#include "mc_v9/fsl_dpni.h"
#include "mc_v9/fsl_dpsw.h"
#include "mc_v10/fsl_dpni.h"
#include "mc_v10/fsl_dpcon.h"
#include "mc_v10/fsl_dpio.h"
#include "mc_v10/fsl_dpci.h"
#include "mc_v10/fsl_dpdcei.h"
#include "mc_v10/fsl_dpdmai.h"
#include "mc_v10/fsl_dpseci.h"
#include "mc_v10/fsl_dpdmux.h"
#include "mc_v10/fsl_dpsw.h"

/* dprc stuff */
#define ALL_DPRC_OPTS_DPL (                     \
	DPRC_CFG_OPT_SPAWN_ALLOWED |            \
	DPRC_CFG_OPT_ALLOC_ALLOWED |            \
	DPRC_CFG_OPT_OBJ_CREATE_ALLOWED |       \
	DPRC_CFG_OPT_TOPOLOGY_CHANGES_ALLOWED | \
	DPRC_CFG_OPT_AIOP |                     \
	DPRC_CFG_OPT_IRQ_CFG_ALLOWED)

/* dpni stuff */
/**
 * max_dist: Maximum distribution size for Rx traffic class;
 * supported values: 1,2,3,4,6,7,8,12,14,16,24,28,32,48,56,64,96,
 * 112,128,192,224,256,384,448,512,768,896,1024;
 */
#define MAX_DIST_SIZE	1024
#define ALL_DPNI_OPTS (					\
	DPNI_OPT_ALLOW_DIST_KEY_PER_TC |		\
	DPNI_OPT_TX_CONF_DISABLED |			\
	DPNI_OPT_PRIVATE_TX_CONF_ERROR_DISABLED |	\
	DPNI_OPT_DIST_HASH |				\
	DPNI_OPT_DIST_FS |				\
	DPNI_OPT_UNICAST_FILTER	|			\
	DPNI_OPT_MULTICAST_FILTER |			\
	DPNI_OPT_VLAN_FILTER |				\
	DPNI_OPT_IPR |					\
	DPNI_OPT_IPF |					\
	DPNI_OPT_VLAN_MANIPULATION |			\
	DPNI_OPT_QOS_MASK_SUPPORT |			\
	DPNI_OPT_TX_FRM_RELEASE |			\
	DPNI_OPT_NO_MAC_FILTER |			\
	DPNI_OPT_HAS_POLICING |				\
	DPNI_OPT_SHARED_CONGESTION |			\
	DPNI_OPT_HAS_KEY_MASKING |			\
	DPNI_OPT_NO_FS |				\
	DPNI_OPT_HAS_OPR |				\
	DPNI_OPT_OPR_PER_TC |				\
	DPNI_OPT_SINGLE_SENDER |			\
	DPNI_OPT_CUSTOM_CG |				\
	DPNI_OPT_FS_MASK_SUPPORT |			\
	DPNI_OPT_SHARED_FS	|			\
	DPNI_OPT_SHARED_HASH_KEY |			\
	DPNI_OPT_CUSTOM_OPR)

struct dpni_config {
	struct dpni_extended_cfg dpni_extended_cfg;
	struct dpni_cfg dpni_cfg;
	struct dpni_attr dpni_attr;
	uint16_t dpni_handle;
};

#define RESTOOL_DPNI_CREATE \
	_IOWR(RESTOOL_IOCTL_TYPE, 0x5, struct dpni_config)

#define RESTOOL_DPNI_GET_ATTRIBUTES \
	_IOWR(RESTOOL_IOCTL_TYPE, 0x6, struct dpni_config)

/* dpdmux stuff */
#define ALL_DPDMUX_OPTS (		\
	DPDMUX_OPT_BRIDGE_EN |		\
	DPDMUX_OPT_CLS_MASK_SUPPORT |	\
	DPDMUX_OPT_AUTO_MAX_FRAME_LEN)

/* dpsw stuff */
#define ALL_DPSW_OPTS (			\
	DPSW_OPT_FLOODING_DIS |		\
	DPSW_OPT_MULTICAST_DIS |	\
	DPSW_OPT_CTRL_IF_DIS |	\
	DPSW_OPT_FLOODING_METERING_DIS |	\
	DPSW_OPT_METERING_EN |		\
	DPSW_OPT_LAG_DIS |		\
	DPSW_OPT_BP_PER_IF)


/* dpl stuff */
#define RESTOOL_DYNAMIC_DPL "./dynamic-dpl.dts"

/**
 * struct obj_list - linked list node of all objects
 * @next: tracks next objects, the objects are sorted
 * @type: object type
 * @id: object id
 * @label: object label
 */
struct obj_list {
	struct obj_list *next;
	char type[16];
	int id;
	char label[16];
};

/**
 * struct conn_list - linked list node of 2 connected endpoints
 * @next: tracks next connection, the connections are not sorted.
 * @type1: endpoint1's object type
 * @type2: endpoint2's object type
 * @id1: endpoint1's id
 * @id2: endpoint2's id
 * @if_id1: endpoint1's interface id, initialized as -1 if no interface
 * @if_id2: endpoint2's interface id, initialized as -1 if no interface
 */
struct conn_list {
	struct conn_list *next;
	char type1[16];
	char type2[16];
	int id1;
	int id2;
	int if_id1;
	int if_id2;
};

/**
 * struct container_list - linked list node of all containers
 * @next: tracks next container
 * @obj_list: tracks the objects in current container, sorted list
 * @id: current container's id
 * @parent_id: current container's parent id. 0 means no parent.
 * @options: configuration options of current container
 */
struct container_list {
	struct container_list *next;
	struct obj_list *obj;
	int id;
	int parent_id;
	uint64_t options;
};

static int container_count;
static struct container_list *container_head;
static struct obj_list *obj_head;
static struct conn_list *conn_head;

static enum mc_cmd_status mc_status;

/**
 * compare_insert_obj - compare the newly added object node with existing ones,
 *			insert in sorted order
 * @head: head of the object list
 * @target: the object node to be inserted
 *
 * Returns 0 on success, negative otherwise
 */
static int compare_insert_obj(struct obj_list **head, struct obj_list *target)
{
	int error;
	struct obj_list *prev;
	struct obj_list *curr;

	if (*head == NULL) {
		*head = target;
		target->next = NULL;
		return 0;
	}

	curr = prev = *head;
	while (curr) {
		error = strcmp(target->type, curr->type);

		if (error < 0) {
			if (curr == prev) {
				*head = target;
				target->next = curr;
				return 0;
			}

			prev->next = target;
			target->next = curr;
			return 0;
		}

		if (error == 0) {
			if (target->id < curr->id) {
				if (curr == prev) {
					*head = target;
					target->next = curr;
					return 0;
				}


				prev->next = target;
				target->next = curr;
				return 0;
			}

			if (target->id == curr->id) {
				ERROR_PRINTF("Two objects the same: %s.%d\n",
						curr->type, curr->id);
				return -EINVAL;
			}

			if (target->id > curr->id) {
				prev = curr;
				curr = curr->next;
			}
		}

		if (error > 0) {
			prev = curr;
			curr = curr->next;
		}
	}

	prev->next = target;
	target->next = NULL;
	return 0;
}

static int find_all_obj_desc(uint32_t dprc_id,
			     uint16_t dprc_handle,
			     int nesting_level,
			     struct container_list **prev,
			     uint32_t parent_id)
{

	int num_child_devices;
	int error = 0;
	static enum mc_cmd_status mc_status;
	struct container_list *prev_cont;
	struct container_list *curr_cont;
	struct dprc_attributes dprc_attr;

	if (prev)
		prev_cont = *prev;
	curr_cont = malloc(sizeof(struct container_list));
	if (curr_cont == NULL) {
		ERROR_PRINTF("malloc failed\n");
		error = -errno;
		goto out;
	}

	assert(nesting_level <= MAX_DPRC_NESTING);
	if (parent_id == 0) {
		DEBUG_PRINTF("This is the main dprc.\n");
		container_head = curr_cont;
	} else {
		DEBUG_PRINTF("This is child dprc.\n");
		prev_cont->next = curr_cont;
	}

	curr_cont->id = dprc_id;
	curr_cont->parent_id = parent_id;
	curr_cont->obj = NULL;
	curr_cont->next = NULL;
	if (prev)
		*prev = curr_cont;
	prev_cont = curr_cont;

	memset(&dprc_attr, 0, sizeof(dprc_attr));
	error = dprc_get_attributes(&restool.mc_io, 0,
				dprc_handle, &dprc_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	curr_cont->options = dprc_attr.options;
	container_count++;
	error = dprc_get_obj_count(&restool.mc_io, 0,
				   dprc_handle,
				   &num_child_devices);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}

	for (int i = 0; i < num_child_devices; i++) {
		struct dprc_obj_desc obj_desc;
		uint16_t child_dprc_handle;
		int error2;

		error = dprc_get_obj(
				&restool.mc_io, 0,
				dprc_handle,
				i,
				&obj_desc);
		if (error < 0) {
			DEBUG_PRINTF(
				"dprc_get_object(%u) failed with error %d\n",
				i, error);
			goto out;
		}

		DEBUG_PRINTF("it is %s.%u\n", obj_desc.type, obj_desc.id);

		if (strcmp(obj_desc.type, "dprc") == 0) {

			error = open_dprc(obj_desc.id, &child_dprc_handle);
			if (error < 0)
				goto out;

			DEBUG_PRINTF("entering %s.%u\n", obj_desc.type,
					obj_desc.id);
			error = find_all_obj_desc(obj_desc.id,
					child_dprc_handle,
					nesting_level + 1,
					&prev_cont,
					dprc_id);
			if (prev)
				*prev = prev_cont;

			error2 = dprc_close(&restool.mc_io, 0,
						child_dprc_handle);
			if (error2 < 0) {
				mc_status = flib_error_to_mc_status(error2);
				ERROR_PRINTF("MC error: %s (status %#x)\n",
				mc_status_to_string(mc_status), mc_status);
				if (error == 0)
					error = error2;

				goto out;
			}

			DEBUG_PRINTF("exiting %s.%u\n", obj_desc.type,
					obj_desc.id);
		} else {
			struct obj_list *curr_obj =
				malloc(sizeof(struct obj_list));
			if (curr_obj == NULL) {
				ERROR_PRINTF("malloc failed\n");
				error = -errno;
				goto out;
			}

			curr_obj->next = NULL;
			strncpy(curr_obj->type, obj_desc.type, EP_OBJ_TYPE_MAX_LEN - 1);
			curr_obj->type[EP_OBJ_TYPE_MAX_LEN - 1] = '\0';
			curr_obj->id = obj_desc.id;
			strncpy(curr_obj->label, obj_desc.label, EP_OBJ_TYPE_MAX_LEN - 1);
			curr_obj->label[EP_OBJ_TYPE_MAX_LEN - 1] = '\0';

			struct obj_list *curr_obj2 =
				malloc(sizeof(struct obj_list));
			if (curr_obj2 == NULL) {
				ERROR_PRINTF("malloc failed\n");
				error = -errno;
				goto out;
			}

			curr_obj2->next = NULL;
			strncpy(curr_obj2->type, obj_desc.type, EP_OBJ_TYPE_MAX_LEN - 1);
			curr_obj2->type[EP_OBJ_TYPE_MAX_LEN - 1] = '\0';
			curr_obj2->id = obj_desc.id;
			strncpy(curr_obj2->label, obj_desc.label, EP_OBJ_TYPE_MAX_LEN - 1);
			curr_obj2->label[EP_OBJ_TYPE_MAX_LEN - 1] = '\0';

			error = compare_insert_obj(&obj_head, curr_obj);
			if (error)
				goto out;
			error = compare_insert_obj(&curr_cont->obj, curr_obj2);
			if (error)
				goto out;
		}
	}

out:
	return error;
}

static int parse_layout(uint32_t dprc_id)
{
	int error;

	bool opened = false;

	uint16_t dprc_handle;

	/* if no dprc specified, use root dprc */
	if (restool.obj_name == NULL || dprc_id == restool.root_dprc_id) {
		dprc_id = restool.root_dprc_id;
		dprc_handle = restool.root_dprc_handle;
	} else {
		error = dprc_open(&restool.mc_io, 0, dprc_id, &dprc_handle);
		if (error < 0) {
			mc_status = flib_error_to_mc_status(error);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			goto out;
		}
		opened = true;
	}

	error = find_all_obj_desc(dprc_id, dprc_handle, 0, NULL, 0);

	if (opened == true) {
		error = dprc_close(&restool.mc_io, 0, dprc_handle);
		if (error < 0) {
			mc_status = flib_error_to_mc_status(error);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			goto out;
		}

	}

	if (error) {
		ERROR_PRINTF("Parsing Data Path Layout failed\n");
		return error;
	}

out:
	return 0;
}

static void parse_dprc_options(FILE *fp, uint64_t options)
{
	char buf[300];
	int len;

	if ((options & ~ALL_DPRC_OPTS_DPL) != 0)
		fprintf(fp, "\t\t\t/* Unrecognized options found... */\n");


	snprintf(buf, 14, "\t\t\toptions = ");

	if (options & DPRC_CFG_OPT_SPAWN_ALLOWED) {
		len = strlen(buf);
		snprintf(buf+len, 31, "\"DPRC_CFG_OPT_SPAWN_ALLOWED\", ");
	}

	if (options & DPRC_CFG_OPT_ALLOC_ALLOWED) {
		len = strlen(buf);
		snprintf(buf+len, 31, "\"DPRC_CFG_OPT_ALLOC_ALLOWED\", ");
	}

	if (options & DPRC_CFG_OPT_OBJ_CREATE_ALLOWED) {
		len = strlen(buf);
		snprintf(buf+len, 36, "\"DPRC_CFG_OPT_OBJ_CREATE_ALLOWED\", ");
	}

	if (options & DPRC_CFG_OPT_TOPOLOGY_CHANGES_ALLOWED) {
		len = strlen(buf);
		snprintf(buf+len, 42,
			"\"DPRC_CFG_OPT_TOPOLOGY_CHANGES_ALLOWED\", ");
	}

	if (options & DPRC_CFG_OPT_AIOP) {
		len = strlen(buf);
		snprintf(buf+len, 22, "\"DPRC_CFG_OPT_AIOP\", ");
	}

	if (options & DPRC_CFG_OPT_IRQ_CFG_ALLOWED) {
		len = strlen(buf);
		snprintf(buf+len, 33, "\"DPRC_CFG_OPT_IRQ_CFG_ALLOWED\", ");
	}

	len = strlen(buf);
	if (13 == len)
		return;
	buf[len-2] = ';';
	buf[len-1] = '\0';

	fprintf(fp, "%s\n", buf);
}

static void parse_obj_label(FILE *fp, char *label)
{
	assert(strlen(label) <= MC_OBJ_LABEL_MAX_LENGTH);
	if (strlen(label) > 0)
		fprintf(fp, "\t\t\t\t\tlabel = \"%s\";\n", label);
}

static char *to_upper(char *string)
{
	int length, i;
	char *upper_string;

	length = strlen(string);
	upper_string = malloc(length * sizeof(char));
	if (!upper_string) {
		ERROR_PRINTF("Could not alloc memory!");
		return NULL;
	}

	for (i = 0; i < length; i++)
		upper_string[i] = toupper(string[i]);
	upper_string[i] = '\0';

	return upper_string;
}

static int start_obj_set(char *obj_type)
{
	char *obj_type_upper;
	FILE *fp = stdout;

	obj_type_upper = to_upper(obj_type);
	if (!obj_type_upper)
		return -ENOMEM;

	fprintf(fp, "\n");
	fprintf(fp, "\t\t\t\t/* -------------- %ss --------------*/\n", obj_type_upper);
	fprintf(fp, "\t\t\t\tobj_set@%s {\n", obj_type);
	fprintf(fp, "\t\t\t\t\ttype = \"%s\";\n", obj_type);
	fprintf(fp, "\t\t\t\t\tids = <");

	free(obj_type_upper);

	return 0;
}

static void add_to_obj_set(int index)
{
	FILE *fp = stdout;

	fprintf(fp, "%d ", index);
}

static void end_obj_set(void)
{
	FILE *fp = stdout;

	fprintf(fp, ">;\n");
	fprintf(fp, "\t\t\t\t};\n");
}

static int write_containers(void)
{
	struct container_list *curr_cont;
	struct obj_list *curr_obj;
	struct obj_list *prev_obj;
	char curr_obj_type[OBJ_TYPE_MAX_LENGTH];
	int remain, error;
	int obj_num = 99;
	int base = 100;
	FILE *fp = stdout;

	fprintf(fp,
		"\t/*****************************************************************\n");
	fprintf(fp, "\t * Containers\n");
	fprintf(fp,
		"\t *****************************************************************/\n");

	fprintf(fp, "\tcontainers {\n");

	curr_cont = container_head;
	while (curr_cont) {
		obj_num = 99;
		prev_obj = NULL;
		curr_obj = curr_cont->obj;
		memset(curr_obj_type, 0, OBJ_TYPE_MAX_LENGTH);

		fprintf(fp, "\n");
		fprintf(fp, "\t\tdprc@%d {\n", curr_cont->id);
		fprintf(fp, "\t\t\tcompatible = \"fsl,dprc\";\n");
		if (curr_cont->parent_id == 0)
			fprintf(fp, "\t\t\tparent = \"none\";\n");
		else
			fprintf(fp, "\t\t\tparent = \"dprc@%d\";\n",
				curr_cont->parent_id);
		parse_dprc_options(fp, curr_cont->options);


		fprintf(fp, "\n");
		fprintf(fp, "\t\t\tobjects {\n");

		while (curr_obj) {
			if (strcmp(curr_obj->type, "dpmcp") == 0 &&
			    0 == curr_obj->id) {
				curr_obj = curr_obj->next;
				continue;
			}
			if (prev_obj == NULL ||
			    strcmp(curr_obj->type, prev_obj->type) > 0) {
				remain = obj_num % base;
				obj_num = obj_num + base - remain;
			}

			if (restool.mc_fw_version.major <= MC_FW_VERSION_9) {
				fprintf(fp, "\n");
				fprintf(fp, "\t\t\t\tobj@%d {\n", obj_num);
				fprintf(fp, "\t\t\t\t\tobj_name = \"%s@%d\";\n",
					curr_obj->type, curr_obj->id);
				parse_obj_label(fp, curr_obj->label);
				fprintf(fp, "\t\t\t\t};\n");
			} else if (restool.mc_fw_version.major == MC_FW_VERSION_10) {
				if (curr_obj_type[0] == '\0') {
					memcpy(curr_obj_type, curr_obj->type, OBJ_TYPE_MAX_LENGTH);
					error = start_obj_set(curr_obj->type);
					if (error) {
						ERROR_PRINTF("start_obj_set() failed with error = %d\n", error);
						return error;
					}

					add_to_obj_set(curr_obj->id);
				} else if (strcmp(curr_obj_type, curr_obj->type)) {
					end_obj_set();

					memcpy(curr_obj_type, curr_obj->type, OBJ_TYPE_MAX_LENGTH);
					error = start_obj_set(curr_obj->type);
					if (error) {
						ERROR_PRINTF("start_obj_set() failed with error = %d\n", error);
						return error;
					}
					add_to_obj_set(curr_obj->id);
				} else {
					add_to_obj_set(curr_obj->id);
				}
			}

			obj_num++;
			prev_obj = curr_obj;
			curr_obj = curr_obj->next;
		}

		end_obj_set();

		fprintf(fp, "\t\t\t};\n");
		fprintf(fp, "\t\t};\n");
		curr_cont = curr_cont->next;
	}

	fprintf(fp, "\t};\n");

	return 0;
}

/**
 * compare_insert_connection - Just insert target into conn_list.
 *				The conn_list is unsorted.
 *				Algorithm is used to avoid adding duplication
 *				connection node from 2 objects
 * @head: conn_list head
 * @target: the one to be inserted
 *
 * Return 0 on success, negative otherwise
 */
static int compare_insert_connection(struct conn_list **head,
				     struct conn_list *target)
{
	struct conn_list *prev;
	struct conn_list *curr;

	if (*head == NULL) {
		*head = target;
		target->next = NULL;
		return 0;
	}

	curr = prev = *head;
	while (curr) {
		if (strcmp(target->type1, curr->type1) == 0 &&
		    target->id1 == curr->id1 &&
		    target->if_id1 == curr->if_id1) {

			if (strcmp(target->type2, curr->type2) == 0 &&
			    target->id2 == curr->id2 &&
			    target->if_id2 == curr->if_id2)
				return 0;

			return -EINVAL;
		}

		if (strcmp(target->type1, curr->type2) == 0 &&
		    target->id1 == curr->id2 &&
		    target->if_id1 == curr->if_id2) {

			if (strcmp(target->type2, curr->type1) == 0 &&
			    target->id2 == curr->id1 &&
			    target->if_id2 == curr->if_id1)
				return 0;

			return -EINVAL;
		}

		prev = curr;
		curr = curr->next;
	}

	prev->next = target;
	target->next = NULL;

	return 0;
}

/* objects don't Need to be parse and get attributes for now */
static int parse_dpbp(FILE *fp, struct obj_list *curr)
{
	(void)fp;
	(void)curr;
	return 0;
}

static int parse_dpdbg(FILE *fp, struct obj_list *curr)
{
	(void)fp;
	(void)curr;
	return 0;
}

static int parse_dpmcp(FILE *fp, struct obj_list *curr)
{
	(void)fp;
	(void)curr;
	return 0;
}

static int parse_dprc(FILE *fp, struct obj_list *curr)
{
	(void)fp;
	(void)curr;
	return 0;
}

static int parse_dprtc(FILE *fp, struct obj_list *curr)
{
	(void)fp;
	(void)curr;
	return 0;
}

/* objects Need to be parsed and get attributes*/
static int parse_dpaiop(FILE *fp, struct obj_list *curr)
{
	/* dpaiop_attr{} does not have field called aiop_container_id */
	(void)fp;
	(void)curr;
	return 0;
}

static int parse_dpcon_v9(FILE *fp, struct obj_list *curr)
{
	uint16_t dpcon_handle;
	int error;
	struct dpcon_attr dpcon_attr;
	bool dpcon_opened = false;

	error = dpcon_open_v10(&restool.mc_io, 0, curr->id, &dpcon_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpcon_opened = true;
	if (0 == dpcon_handle) {
		DEBUG_PRINTF(
			"dpcon_open() returned invalid handle (auth 0) for dpcon.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpcon_attr, 0, sizeof(dpcon_attr));
	error = dpcon_get_attributes(&restool.mc_io, 0, dpcon_handle,
					&dpcon_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpcon_attr.id);

	fprintf(fp, "\t\t\tnum_priorities = <%#x>;\n",
		dpcon_attr.num_priorities);

	error = 0;

out:
	if (dpcon_opened) {
		int error2;

		error2 = dpcon_close(&restool.mc_io, 0, dpcon_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}


static int parse_dpcon_v10(FILE *fp, struct obj_list *curr)
{
	struct dpcon_attr_v10 dpcon_attr;
	bool dpcon_opened = false;
	uint16_t dpcon_handle;
	int error;

	error = dpcon_open_v10(&restool.mc_io, 0, curr->id, &dpcon_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpcon_opened = true;
	if (0 == dpcon_handle) {
		DEBUG_PRINTF(
			"dpcon_open() returned invalid handle (auth 0) for dpcon.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpcon_attr, 0, sizeof(dpcon_attr));
	error = dpcon_get_attributes_v10(&restool.mc_io, 0, dpcon_handle,
					 &dpcon_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpcon_attr.id);

	fprintf(fp, "\t\t\tnum_priorities = <%#x>;\n",
		dpcon_attr.num_priorities);

	error = 0;

out:
	if (dpcon_opened) {
		int error2;

		error2 = dpcon_close_v10(&restool.mc_io, 0, dpcon_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}

static int parse_dpdcei_v9(FILE *fp, struct obj_list *curr)
{
	/* dpdcei_attr{} does not have a field called priority */
	uint16_t dpdcei_handle;
	int error;
	struct dpdcei_attr dpdcei_attr;
	bool dpdcei_opened = false;

	error = dpdcei_open(&restool.mc_io, 0, curr->id, &dpdcei_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpdcei_opened = true;
	if (0 == dpdcei_handle) {
		DEBUG_PRINTF(
			"dpdcei_open() returned invalid handle (auth 0) for dpdcei.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpdcei_attr, 0, sizeof(dpdcei_attr));
	error = dpdcei_get_attributes(&restool.mc_io, 0, dpdcei_handle,
					&dpdcei_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpdcei_attr.id);

	switch (dpdcei_attr.engine) {
	case DPDCEI_ENGINE_COMPRESSION:
		fprintf(fp, "\t\t\tengine = \"DPDCEI_ENGINE_COMPRESSION\";\n");
		break;
	case DPDCEI_ENGINE_DECOMPRESSION:
		fprintf(fp, "\t\t\tengine = \"DPDCEI_ENGINE_DECOMPRESSION\";\n");
		break;
	default:
		assert(false);
		break;
	}

	error = 0;

out:
	if (dpdcei_opened) {
		int error2;

		error2 = dpdcei_close(&restool.mc_io, 0, dpdcei_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}

static int parse_dpdcei_v10(FILE *fp, struct obj_list *curr)
{
	struct dpdcei_attr_v10 dpdcei_attr;
	bool dpdcei_opened = false;
	uint16_t dpdcei_handle;
	int error;

	error = dpdcei_open_v10(&restool.mc_io, 0, curr->id, &dpdcei_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpdcei_opened = true;
	if (0 == dpdcei_handle) {
		DEBUG_PRINTF(
			"dpdcei_open() returned invalid handle (auth 0) for dpdcei.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpdcei_attr, 0, sizeof(dpdcei_attr));
	error = dpdcei_get_attributes_v10(&restool.mc_io, 0, dpdcei_handle,
					  &dpdcei_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpdcei_attr.id);

	switch (dpdcei_attr.engine) {
	case DPDCEI_ENGINE_COMPRESSION:
		fprintf(fp, "\t\t\tengine = \"DPDCEI_ENGINE_COMPRESSION\";\n");
		break;
	case DPDCEI_ENGINE_DECOMPRESSION:
		fprintf(fp, "\t\t\tengine = \"DPDCEI_ENGINE_DECOMPRESSION\";\n");
		break;
	default:
		assert(false);
		break;
	}

	error = 0;

out:
	if (dpdcei_opened) {
		int error2;

		error2 = dpdcei_close_v10(&restool.mc_io, 0, dpdcei_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}

static int parse_dpdmai_v9(FILE *fp, struct obj_list *curr)
{
	uint16_t dpdmai_handle;
	int error;
	struct dpdmai_attr dpdmai_attr;
	bool dpdmai_opened = false;

	error = dpdmai_open(&restool.mc_io, 0, curr->id, &dpdmai_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpdmai_opened = true;
	if (0 == dpdmai_handle) {
		DEBUG_PRINTF(
			"dpdmai_open() returned invalid handle (auth 0) for dpdmai.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpdmai_attr, 0, sizeof(dpdmai_attr));
	error = dpdmai_get_attributes(&restool.mc_io, 0, dpdmai_handle,
					&dpdmai_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpdmai_attr.id);

	fprintf(fp, "\t\t\tpriorities = <%#x>;\n",
		dpdmai_attr.num_of_priorities);

	error = 0;

out:
	if (dpdmai_opened) {
		int error2;

		error2 = dpdmai_close(&restool.mc_io, 0, dpdmai_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}

static int parse_dpdmai_v10(FILE *fp, struct obj_list *curr)
{
	struct dpdmai_attr_v10 dpdmai_attr;
	bool dpdmai_opened = false;
	uint16_t dpdmai_handle;
	int error;

	error = dpdmai_open_v10(&restool.mc_io, 0, curr->id, &dpdmai_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpdmai_opened = true;
	if (0 == dpdmai_handle) {
		DEBUG_PRINTF(
			"dpdmai_open() returned invalid handle (auth 0) for dpdmai.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpdmai_attr, 0, sizeof(dpdmai_attr));
	error = dpdmai_get_attributes_v10(&restool.mc_io, 0, dpdmai_handle,
					  &dpdmai_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpdmai_attr.id);

	fprintf(fp, "\t\t\tpriorities = <%#x>;\n",
		dpdmai_attr.num_of_priorities);

	error = 0;

out:
	if (dpdmai_opened) {
		int error2;

		error2 = dpdmai_close_v10(&restool.mc_io, 0, dpdmai_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}

static int parse_dpio_v9(FILE *fp, struct obj_list *curr)
{
	uint16_t dpio_handle;
	int error;
	struct dpio_attr dpio_attr;
	bool dpio_opened = false;

	error = dpio_open(&restool.mc_io, 0, curr->id, &dpio_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpio_opened = true;
	if (0 == dpio_handle) {
		DEBUG_PRINTF(
			"dpio_open() returned invalid handle (auth 0) for dpio.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpio_attr, 0, sizeof(dpio_attr));
	error = dpio_get_attributes(&restool.mc_io, 0, dpio_handle, &dpio_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpio_attr.id);

	fprintf(fp, "\t\t\tchannel_mode = ");
	dpio_attr.channel_mode == 0 ? fprintf(fp, "\"DPIO_NO_CHANNEL\";\n") :
	dpio_attr.channel_mode == 1 ? fprintf(fp, "\"DPIO_LOCAL_CHANNEL\";\n") :
	fprintf(fp, "\"wrong mode\"\n");
	fprintf(fp, "\t\t\tnum_priorities = <%#x>;\n",
	       (unsigned int)dpio_attr.num_priorities);

	error = 0;

out:
	if (dpio_opened) {
		int error2;

		error2 = dpio_close(&restool.mc_io, 0, dpio_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}

static int parse_dpio_v10(FILE *fp, struct obj_list *curr)
{
	struct dpio_attr_v10 dpio_attr;
	bool dpio_opened = false;
	uint16_t dpio_handle;
	int error;

	error = dpio_open_v10(&restool.mc_io, 0, curr->id, &dpio_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpio_opened = true;
	if (0 == dpio_handle) {
		DEBUG_PRINTF(
			"dpio_open() returned invalid handle (auth 0) for dpio.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpio_attr, 0, sizeof(dpio_attr));
	error = dpio_get_attributes_v10(&restool.mc_io, 0, dpio_handle, &dpio_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpio_attr.id);

	fprintf(fp, "\t\t\tchannel_mode = ");
	dpio_attr.channel_mode == 0 ? fprintf(fp, "\"DPIO_NO_CHANNEL\";\n") :
	dpio_attr.channel_mode == 1 ? fprintf(fp, "\"DPIO_LOCAL_CHANNEL\";\n") :
	fprintf(fp, "\"wrong mode\"\n");
	fprintf(fp, "\t\t\tnum_priorities = <%#x>;\n",
	       (unsigned int)dpio_attr.num_priorities);

	error = 0;

out:
	if (dpio_opened) {
		int error2;

		error2 = dpio_close_v10(&restool.mc_io, 0, dpio_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}

static int parse_dpseci_v9(FILE *fp, struct obj_list *curr)
{
	int error;
	uint16_t dpseci_handle;
	bool dpseci_opened = false;
	struct dpseci_attr dpseci_attr;
	struct dpseci_tx_queue_attr tx_attr;
	char *priorities;

	error = dpseci_open(&restool.mc_io, 0, curr->id, &dpseci_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpseci_opened = true;
	if (0 == dpseci_handle) {
		DEBUG_PRINTF(
			"dpseci_open() returned invalid handle (auth 0) for dpseci.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}
	memset(&tx_attr, 0, sizeof(tx_attr));
	memset(&dpseci_attr, 0, sizeof(dpseci_attr));

	error = dpseci_get_attributes(&restool.mc_io, 0, dpseci_handle,
					&dpseci_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}

	priorities = malloc(dpseci_attr.num_tx_queues * sizeof(*priorities));
	if (priorities == NULL) {
		ERROR_PRINTF("malloc failed\n");
		error = -errno;
		goto out;
	}

	for (int i = 0; i < dpseci_attr.num_tx_queues; i++) {
		error = dpseci_get_tx_queue(&restool.mc_io, 0, dpseci_handle,
					    i, &tx_attr);

		if (error < 0) {
			mc_status = flib_error_to_mc_status(error);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			free(priorities);
			goto out;
		}

		priorities[i] = tx_attr.priority;
	}
	fprintf(fp, "\t\t\tpriorities = <");
	for (int i = 0; i < dpseci_attr.num_tx_queues-1; i++)
		fprintf(fp, "%d ", priorities[i]);

	fprintf(fp, "%d>;\n", priorities[dpseci_attr.num_tx_queues-1]);

	free(priorities);


out:
	if (dpseci_opened) {
		int error2;

		error2 = dpseci_close(&restool.mc_io, 0, dpseci_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}
	return 0;
}

static int parse_dpseci_v10(FILE *fp, struct obj_list *curr)
{
	struct dpseci_tx_queue_attr_v10 tx_attr;
	struct dpseci_attr_v10 dpseci_attr;
	bool dpseci_opened = false;
	uint16_t dpseci_handle;
	char *priorities;
	int error;

	error = dpseci_open_v10(&restool.mc_io, 0, curr->id, &dpseci_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpseci_opened = true;
	if (0 == dpseci_handle) {
		DEBUG_PRINTF(
			"dpseci_open() returned invalid handle (auth 0) for dpseci.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}
	memset(&tx_attr, 0, sizeof(tx_attr));
	memset(&dpseci_attr, 0, sizeof(dpseci_attr));

	error = dpseci_get_attributes_v10(&restool.mc_io, 0, dpseci_handle,
					  &dpseci_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}

	priorities = malloc(dpseci_attr.num_tx_queues * sizeof(*priorities));
	if (priorities == NULL) {
		ERROR_PRINTF("malloc failed\n");
		error = -errno;
		goto out;
	}

	for (int i = 0; i < dpseci_attr.num_tx_queues; i++) {
		error = dpseci_get_tx_queue_v10(&restool.mc_io, 0, dpseci_handle,
						i, &tx_attr);

		if (error < 0) {
			mc_status = flib_error_to_mc_status(error);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			free(priorities);
			goto out;
		}

		priorities[i] = tx_attr.priority;
	}
	fprintf(fp, "\t\t\tpriorities = <");
	for (int i = 0; i < dpseci_attr.num_tx_queues-1; i++)
		fprintf(fp, "%d ", priorities[i]);

	fprintf(fp, "%d>;\n", priorities[dpseci_attr.num_tx_queues-1]);

	free(priorities);


out:
	if (dpseci_opened) {
		int error2;

		error2 = dpseci_close_v10(&restool.mc_io, 0, dpseci_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}
	return 0;
}

/* following objects have possible connections*/
static int parse_dpci_v9(FILE *fp, struct obj_list *curr)
{
	uint16_t dpci_handle;
	int error;
	struct dpci_attr dpci_attr;
	struct dpci_peer_attr dpci_peer_attr;
	bool dpci_opened = false;
	struct conn_list *curr_conn;


	error = dpci_open(&restool.mc_io, 0, curr->id, &dpci_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpci_opened = true;
	if (0 == dpci_handle) {
		DEBUG_PRINTF(
			"dpci_open() returned invalid handle (auth 0) for dpci.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpci_attr, 0, sizeof(dpci_attr));
	error = dpci_get_attributes(&restool.mc_io, 0, dpci_handle, &dpci_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpci_attr.id);

	error = dpci_get_peer_attributes(&restool.mc_io, 0, dpci_handle,
					 &dpci_peer_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}

	fprintf(fp, "\t\t\tnum_of_priorities = <%#x>;\n",
	       (unsigned int)dpci_attr.num_of_priorities);

	if (-1 == dpci_peer_attr.peer_id) {
		DEBUG_PRINTF("no peer\n");
	} else {
		/* dpci has connection */
		curr_conn = malloc(sizeof(struct conn_list));
		if (curr_conn == NULL) {
			ERROR_PRINTF("malloc failed\n");
			error = -errno;
			goto out;
		}
		curr_conn->next = NULL;
		strcpy(curr_conn->type1, "dpci");
		strcpy(curr_conn->type2, "dpci");
		curr_conn->id1 = dpci_attr.id;
		curr_conn->id2 = dpci_peer_attr.peer_id;
		curr_conn->if_id1 = -1;	/* -1 means no interface */
		curr_conn->if_id2 = -1;

		error = compare_insert_connection(&conn_head, curr_conn);
		if (error)
			goto out;
	}

	error = 0;

out:
	if (dpci_opened) {
		int error2;

		error2 = dpci_close(&restool.mc_io, 0, dpci_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}

static int parse_dpci_v10(FILE *fp, struct obj_list *curr)
{
	struct dpci_peer_attr_v10 dpci_peer_attr;
	struct dpci_attr_v10 dpci_attr;
	struct conn_list *curr_conn;
	bool dpci_opened = false;
	uint16_t dpci_handle;
	int error;

	error = dpci_open_v10(&restool.mc_io, 0, curr->id, &dpci_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpci_opened = true;
	if (0 == dpci_handle) {
		DEBUG_PRINTF(
			"dpci_open() returned invalid handle (auth 0) for dpci.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpci_attr, 0, sizeof(dpci_attr));
	error = dpci_get_attributes_v10(&restool.mc_io, 0, dpci_handle, &dpci_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpci_attr.id);

	error = dpci_get_peer_attributes_v10(&restool.mc_io, 0, dpci_handle,
					 &dpci_peer_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}

	fprintf(fp, "\t\t\tnum_of_priorities = <%#x>;\n",
	       (unsigned int)dpci_attr.num_of_priorities);

	if (-1 == dpci_peer_attr.peer_id) {
		DEBUG_PRINTF("no peer\n");
	} else {
		/* dpci has connection */
		curr_conn = malloc(sizeof(struct conn_list));
		if (curr_conn == NULL) {
			ERROR_PRINTF("malloc failed\n");
			error = -errno;
			goto out;
		}
		curr_conn->next = NULL;
		strcpy(curr_conn->type1, "dpci");
		strcpy(curr_conn->type2, "dpci");
		curr_conn->id1 = dpci_attr.id;
		curr_conn->id2 = dpci_peer_attr.peer_id;
		curr_conn->if_id1 = -1;	/* -1 means no interface */
		curr_conn->if_id2 = -1;

		error = compare_insert_connection(&conn_head, curr_conn);
		if (error)
			goto out;
	}

	error = 0;

out:
	if (dpci_opened) {
		int error2;

		error2 = dpci_close_v10(&restool.mc_io, 0, dpci_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}

static int parse_dpmac(FILE *fp, struct obj_list *curr)
{
	/* don't have anything in the dpl-example.dts */
	(void)fp;
	(void)curr;
	return 0;
}

static void parse_dpni_options(FILE *fp, uint32_t options)
{
	char buf[500];
	int len;

	if ((options & ~ALL_DPNI_OPTS) != 0)
		fprintf(fp, "\t\t\t/* Unrecognized options found... */\n");

	snprintf(buf, 14, "\t\t\toptions = ");

	if (options & DPNI_OPT_ALLOW_DIST_KEY_PER_TC) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_ALLOW_DIST_KEY_PER_TC\", ");
	}

	if (options & DPNI_OPT_TX_CONF_DISABLED) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_TX_CONF_DISABLED\", ");
	}

	if (options & DPNI_OPT_PRIVATE_TX_CONF_ERROR_DISABLED) {
		len = strlen(buf);
		snprintf(buf+len, 50,
			"\"DPNI_OPT_PRIVATE_TX_CONF_ERROR_DISABLED\", ");
	}

	if (options & DPNI_OPT_DIST_HASH) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_DIST_HASH\", ");
	}

	if (options & DPNI_OPT_DIST_FS) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_DIST_FS\", ");
	}

	if (options & DPNI_OPT_UNICAST_FILTER) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_UNICAST_FILTER\", ");
	}

	if (options & DPNI_OPT_MULTICAST_FILTER) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_MULTICAST_FILTER\", ");
	}

	if (options & DPNI_OPT_VLAN_FILTER) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_VLAN_FILTER\", ");
	}

	if (options & DPNI_OPT_IPR) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_IPR\", ");
	}

	if (options & DPNI_OPT_IPF) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_IPF\", ");
	}

	if (options & DPNI_OPT_VLAN_MANIPULATION) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_VLAN_MANIPULATION\", ");
	}

	if (options & DPNI_OPT_QOS_MASK_SUPPORT) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_QOS_MASK_SUPPORT\", ");
	}

	if (options & DPNI_OPT_FS_MASK_SUPPORT) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_FS_MASK_SUPPORT\", ");
	}

	if (options & DPNI_OPT_SHARED_FS) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_SHARED_FS\", ");
	}

	len = strlen(buf);
	if (13 == len)
		return;

	buf[len-2] = ';';
	buf[len-1] = '\0';

	fprintf(fp, "%s\n", buf);
}

static void parse_dpni_options_v10(FILE *fp, uint32_t options)
{
	char buf[500];
	int len;

	if ((options & ~ALL_DPNI_OPTS) != 0)
		fprintf(fp, "\t\t\t/* Unrecognized options found... */\n");

	snprintf(buf, 14, "\t\t\toptions = ");

	if (options & DPNI_OPT_TX_FRM_RELEASE) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_TX_FRM_RELEASE\", ");
	}

	if (options & DPNI_OPT_HAS_POLICING) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_HAS_POLICING\", ");
	}
	if (options & DPNI_OPT_SHARED_CONGESTION) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_SHARED_CONGESTION\", ");
	}

	if (options & DPNI_OPT_HAS_KEY_MASKING) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_HAS_KEY_MASKING\", ");
	}

	if (options & DPNI_OPT_NO_FS) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_NO_FS\", ");
	}

	if (options & DPNI_OPT_NO_MAC_FILTER) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_NO_MAC_FILTER\", ");
	}

	if (options & DPNI_OPT_SHARED_HASH_KEY) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_SHARED_HASH_KEY\", ");
	}

	if (options & DPNI_OPT_HAS_OPR) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_HAS_OPR\", ");
	}

	if (options & DPNI_OPT_OPR_PER_TC) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_OPR_PER_TC\", ");
	}

	if (options & DPNI_OPT_SINGLE_SENDER) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_SINGLE_SENDER\", ");
	}

	if (options & DPNI_OPT_CUSTOM_CG) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_CUSTOM_CG\", ");
	}

	if (options & DPNI_OPT_CUSTOM_OPR) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPNI_OPT_CUSTOM_OPR\", ");
	}

	len = strlen(buf);
	if (13 == len)
		return;

	buf[len-2] = ';';
	buf[len-1] = '\0';

	fprintf(fp, "%s\n", buf);
}

static int parse_endpoint_dpl(struct obj_list *curr_obj, uint16_t num_ifs)
{
	struct dprc_endpoint endpoint1;
	struct dprc_endpoint endpoint2;
	int state;
	int error = 0;
	int k;
	struct conn_list *curr_conn;

	/* dpni though not have interfaces,
	 * need to have num_ifs > 0,
	 * say 1000 to start the first loop,
	 * and exit at the end of first loop
	 */
	for (k = 0; k < num_ifs; ++k) {
		memset(&endpoint1, 0, sizeof(struct dprc_endpoint));
		memset(&endpoint2, 0, sizeof(struct dprc_endpoint));
		endpoint1.id = curr_obj->id;
		endpoint1.if_id = k;
		strcpy(endpoint1.type, curr_obj->type);
		endpoint1.type[EP_OBJ_TYPE_MAX_LEN - 1] = '\0';
		error = dprc_get_connection(&restool.mc_io, 0,
					restool.root_dprc_handle,
					&endpoint1,
					&endpoint2,
					&state);
		DEBUG_PRINTF("endpoint state: %d\n", state);

		if (error == 0 && state == -1) {
			DEBUG_PRINTF("\tinterface %d: No object associated\n",
					k);
		} else if (error == 0) {
			if (strcmp(endpoint2.type, "dpsw") == 0 ||
			    strcmp(endpoint2.type, "dpdmux") == 0) {
				DEBUG_PRINTF("\tinterface %d: %s.%d.%d",
					k, endpoint2.type, endpoint2.id,
					endpoint2.if_id);

				curr_conn = malloc(sizeof(struct conn_list));
				if (curr_conn == NULL) {
					ERROR_PRINTF("malloc failed\n");
					error = -errno;
					return error;
				}
				curr_conn->next = NULL;
				strncpy(curr_conn->type1, endpoint1.type,
					EP_OBJ_TYPE_MAX_LEN - 1);
				curr_conn->type1[EP_OBJ_TYPE_MAX_LEN - 1] = '\0';
				strncpy(curr_conn->type2, endpoint2.type,
					EP_OBJ_TYPE_MAX_LEN - 1);
				curr_conn->type2[EP_OBJ_TYPE_MAX_LEN - 1] = '\0';
				curr_conn->id1 = endpoint1.id;
				curr_conn->id2 = endpoint2.id;
				if (strcmp(curr_obj->type, "dpni") == 0)
					curr_conn->if_id1 = -1;
					/* -1 means no interface */
				else
					curr_conn->if_id1 = endpoint1.if_id;

				curr_conn->if_id2 = endpoint2.if_id;

				error = compare_insert_connection(&conn_head,
								  curr_conn);
				if (error)
					return error;
			} else if (endpoint2.if_id == 0) {
				DEBUG_PRINTF("\tinterface %d: %s.%d",
					k, endpoint2.type, endpoint2.id);

				curr_conn = malloc(sizeof(struct conn_list));
				if (curr_conn == NULL) {
					ERROR_PRINTF("malloc failed\n");
					error = -errno;
					return error;
				}
				curr_conn->next = NULL;
				strncpy(curr_conn->type1, endpoint1.type,
					EP_OBJ_TYPE_MAX_LEN - 1);
				curr_conn->type1[EP_OBJ_TYPE_MAX_LEN - 1] = '\0';
				strncpy(curr_conn->type2, endpoint2.type,
					EP_OBJ_TYPE_MAX_LEN - 1);
				curr_conn->type2[EP_OBJ_TYPE_MAX_LEN - 1] = '\0';
				curr_conn->id1 = endpoint1.id;
				curr_conn->id2 = endpoint2.id;
				if (strcmp(curr_obj->type, "dpni") == 0)
					curr_conn->if_id1 = -1;
					/* -1 means no interface */
				else
					curr_conn->if_id1 = endpoint1.if_id;

				curr_conn->if_id2 = -1;

				error = compare_insert_connection(&conn_head,
								  curr_conn);
				if (error)
					return error;
			}

			if (state == 1)
				DEBUG_PRINTF(", link is up\n");
			else if (state == 0)
				DEBUG_PRINTF(", link is down\n");
			else
				DEBUG_PRINTF(", link is in error state\n");

		} else {
			mc_status = flib_error_to_mc_status(error);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				mc_status_to_string(mc_status), mc_status);
			return error;
		}

		if (strcmp(curr_obj->type, "dpni") == 0)
			break;
	}

	return 0;
}

static int parse_dpni_v9(FILE *fp, struct obj_list *curr)
{
	uint16_t dpni_handle;
	int error;
	struct dpni_attr_v9 dpni_attr;
	uint8_t mac_addr[6];
	bool dpni_opened = false;
	struct dpni_extended_cfg dpni_extended_cfg;

	memset(&dpni_extended_cfg, 0, sizeof(dpni_extended_cfg));
	memset(&dpni_attr, 0, sizeof(dpni_attr));

	error = dpni_open(&restool.mc_io, 0, curr->id, &dpni_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpni_opened = true;
	if (0 == dpni_handle) {
		DEBUG_PRINTF(
			"dpni_open() returned invalid handle (auth 0) for dpni.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	error = dpni_get_attributes_v9(&restool.mc_io, 0, dpni_handle,
				       &dpni_attr, &dpni_extended_cfg);

	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}

	assert(curr->id == dpni_attr.id);
	assert(DPNI_MAX_TC >= dpni_attr.max_tcs);

	error = dpni_get_primary_mac_addr(&restool.mc_io, 0,
					dpni_handle, mac_addr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}

	parse_endpoint_dpl(curr, 1000);

	fprintf(fp, "\t\t\tmac_addr = <");
	for (int j = 0; j < 5; ++j)
		fprintf(fp, "%#02x ", mac_addr[j]);
	fprintf(fp, "%#02x>;\n", mac_addr[5]);

	fprintf(fp, "\t\t\tmax_senders = <%#x>;\n",
		(uint32_t)dpni_attr.max_senders);

	parse_dpni_options(fp, dpni_attr.options);

	fprintf(fp, "\t\t\tmax_tcs = <%#x>;\n", (uint32_t)dpni_attr.max_tcs);

	fprintf(fp, "\t\t\tmax_dist_per_tc = <");
	for (int k = 0; k < dpni_attr.max_tcs - 1; ++k)
		fprintf(fp, "%#x ",
			(uint32_t)dpni_extended_cfg.tc_cfg[k].max_dist);
	fprintf(fp, "%#x>;\n",
		(uint32_t)dpni_extended_cfg.
		tc_cfg[dpni_attr.max_tcs].max_dist);

	fprintf(fp, "\t\t\tmax_fs_entries = <");
	for (int m = 0; m < dpni_attr.max_tcs - 1; ++m)
		fprintf(fp, "%#x",
			(uint32_t)dpni_extended_cfg.tc_cfg[m].max_fs_entries);
	fprintf(fp, "%#x>;\n",
		(uint32_t)dpni_extended_cfg.
		tc_cfg[dpni_attr.max_tcs].max_fs_entries);

	fprintf(fp, "\t\t\tmax_unicast_filters = <%#x>;\n",
	       (uint32_t)dpni_attr.max_unicast_filters);

	fprintf(fp, "\t\t\tmax_multicast_filters = <%#x>;\n",
	       (uint32_t)dpni_attr.max_multicast_filters);

	fprintf(fp, "\t\t\tmax_vlan_filters = <%#x>;\n",
		(uint32_t)dpni_attr.max_vlan_filters);

	fprintf(fp, "\t\t\tmax_qos_entries = <%#x>;\n",
		(uint32_t)dpni_attr.max_qos_entries);

	fprintf(fp, "\t\t\tmax_qos_key_size = <%#x>;\n",
		(uint32_t)dpni_attr.max_qos_key_size);

	fprintf(fp, "\t\t\tmax_dist_key_size = <%#x>;\n",
	       (uint32_t)dpni_attr.max_dist_key_size);

	fprintf(fp, "\t\t\tmax_policers = <%#x>;\n",
		(uint32_t)dpni_attr.max_policers);

	fprintf(fp, "\t\t\tmax_congestion_ctrl = <%#x>;\n",
		(uint32_t)dpni_attr.max_congestion_ctrl);

	fprintf(fp, "\t\t\tmax_reass_frm_size = <%#x>;\n",
		(uint32_t)dpni_extended_cfg.ipr_cfg.max_reass_frm_size);

	fprintf(fp, "\t\t\tmin_frag_size_ipv4 = <%#x>;\n",
		(uint32_t)dpni_extended_cfg.ipr_cfg.min_frag_size_ipv4);

	fprintf(fp, "\t\t\tmin_frag_size_ipv6 = <%#x>;\n",
		(uint32_t)dpni_extended_cfg.ipr_cfg.min_frag_size_ipv6);

	fprintf(fp, "\t\t\tmax_open_frames_ipv4 = <%#x>;\n",
		(uint32_t)dpni_extended_cfg.ipr_cfg.max_open_frames_ipv4);

	fprintf(fp, "\t\t\tmax_open_frames_ipv6 = <%#x>;\n",
		(uint32_t)dpni_extended_cfg.ipr_cfg.max_open_frames_ipv6);

	error = 0;

out:
	if (dpni_opened) {
		int error2;

		error2 = dpni_close(&restool.mc_io, 0, dpni_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}

static int parse_dpni_v10(FILE *fp, struct obj_list *curr)
{
	struct dpni_attr_v10 dpni_attr;
	uint16_t dpni_handle;
	bool dpni_opened = false;
	int error = 0;
	int error2;

	error = dpni_open_v10(&restool.mc_io, 0, curr->id, &dpni_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpni_opened = true;
	if (0 == dpni_handle) {
		DEBUG_PRINTF(
			"dpni_open() returned invalid handle (auth 0) for dpni.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpni_attr, 0, sizeof(dpni_attr));
	error = dpni_get_attributes_v10(&restool.mc_io, 0,
					dpni_handle, &dpni_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}

	parse_endpoint_dpl(curr, 1000);

	fprintf(fp, "\t\t\ttype = \"DPNI_TYPE_NIC\";\n");

	parse_dpni_options_v10(fp, dpni_attr.options);

	fprintf(fp, "\t\t\tnum_queues = <%u>;\n", dpni_attr.num_queues);
	fprintf(fp, "\t\t\tnum_tcs = <%u>;\n", dpni_attr.num_rx_tcs);
	fprintf(fp, "\t\t\tnum_cgs = <%u>;\n", dpni_attr.num_cgs);
	fprintf(fp, "\t\t\tmac_filter_entries = <%u>;\n", dpni_attr.mac_filter_entries);
	fprintf(fp, "\t\t\tvlan_filter_entries = <%u>;\n", dpni_attr.vlan_filter_entries);
	fprintf(fp, "\t\t\tfs_entries = <%u>;\n", dpni_attr.fs_entries);
	fprintf(fp, "\t\t\tqos_entries = <%u>;\n", dpni_attr.qos_entries);
	fprintf(fp, "\t\t\tdist_key_size = <%u>;\n", dpni_attr.fs_key_size);
	fprintf(fp, "\t\t\tnum_channels= <%u>;\n", dpni_attr.num_ceetm_ch);
	fprintf(fp, "\t\t\tnum_opr = <%u>;\n", dpni_attr.num_opr);

out:
	if (dpni_opened) {

		error2 = dpni_close_v10(&restool.mc_io, 0, dpni_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}

static void parse_dpdmux_options(FILE *fp, uint64_t options)
{
	char buf[100];
	int len;

	if ((options & ~ALL_DPDMUX_OPTS) != 0)
		fprintf(fp, "\t\t\t/* Unrecognized options found... */\n");

	snprintf(buf, 14, "\t\t\toptions = ");

	if (options & DPDMUX_OPT_BRIDGE_EN) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPDMUX_OPT_BRIDGE_EN\", ");
	}

	if (options & DPDMUX_OPT_CLS_MASK_SUPPORT) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPDMUX_OPT_CLS_MASK_SUPPORT\", ");
	}

	if (options & DPDMUX_OPT_AUTO_MAX_FRAME_LEN) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPDMUX_OPT_AUTO_MAX_FRAME_LEN\", ");
	}

	len = strlen(buf);
	if (13 == len)
		return;
	buf[len-2] = ';';
	buf[len-1] = '\0';

	fprintf(fp, "%s\n", buf);
}

static void parse_dpdmux_method(FILE *fp, enum dpdmux_method method)
{
	fprintf(fp, "\t\t\tmethod = ");
	switch (method) {
	case DPDMUX_METHOD_NONE:
		fprintf(fp, "\"DPDMUX_METHOD_NONE\";\n");
		break;
	case DPDMUX_METHOD_C_VLAN_MAC:
		fprintf(fp, "\"DPDMUX_METHOD_C_VLAN_MAC\";\n");
		break;
	case DPDMUX_METHOD_MAC:
		fprintf(fp, "\"DPDMUX_METHOD_MAC\";\n");
		break;
	case DPDMUX_METHOD_C_VLAN:
		fprintf(fp, "\"DPDMUX_METHOD_C_VLAN\";\n");
		break;
	case DPDMUX_METHOD_CUSTOM:
		fprintf(fp, "\"DPDMUX_METHOD_CUSTOM\";\n");
		break;
#if 0 /* TODO: Enable when MC support added */
	case DPDMUX_METHOD_S_VLAN:
		fprintf(fp, "DPDMUX_METHOD_S_VLAN\n");
		break;
#endif
	default:
		assert(false);
		break;
	}
}

static void parse_dpdmux_manip(FILE *fp, enum dpdmux_manip manip)
{
	fprintf(fp, "\t\t\tmanip = ");
	switch (manip) {
	case DPDMUX_MANIP_NONE:
		fprintf(fp, "\"DPDMUX_MANIP_NONE\";\n");
		break;
#if 0 /* TODO: Enable when MC support added */
	case DPDMUX_MANIP_ADD_REMOVE_S_VLAN:
		fprintf(fp, "DPDMUX_MANIP_ADD_REMOVE_S_VLAN\n");
		break;
#endif
	default:
		assert(false);
		break;
	}
}

static int parse_dpdmux_v9(FILE *fp, struct obj_list *curr)
{
	uint16_t dpdmux_handle;
	int error;
	struct dpdmux_attr_v9 dpdmux_attr;
	bool dpdmux_opened = false;

	error = dpdmux_open(&restool.mc_io, 0, curr->id, &dpdmux_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpdmux_opened = true;
	if (0 == dpdmux_handle) {
		DEBUG_PRINTF(
			"dpdmux_open() returned invalid handle (auth 0) for dpdmux.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpdmux_attr, 0, sizeof(dpdmux_attr));
	error = dpdmux_get_attributes_v9(&restool.mc_io, 0, dpdmux_handle,
					&dpdmux_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpdmux_attr.id);

	parse_endpoint_dpl(curr, dpdmux_attr.num_ifs + 1);
	parse_dpdmux_options(fp, dpdmux_attr.options);
	parse_dpdmux_method(fp, dpdmux_attr.method);
	parse_dpdmux_manip(fp, dpdmux_attr.manip);
	fprintf(fp, "\t\t\tnum_ifs = <%#x>;\n",
		(uint32_t)dpdmux_attr.num_ifs);

	error = 0;

out:
	if (dpdmux_opened) {
		int error2;

		error2 = dpdmux_close(&restool.mc_io, 0, dpdmux_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;

}

static int parse_dpdmux_v10(FILE *fp, struct obj_list *curr)
{
	struct dpdmux_attr_v10 dpdmux_attr;
	bool dpdmux_opened = false;
	uint16_t dpdmux_handle;
	int error;

	error = dpdmux_open_v10(&restool.mc_io, 0, curr->id, &dpdmux_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpdmux_opened = true;
	if (0 == dpdmux_handle) {
		DEBUG_PRINTF(
			"dpdmux_open() returned invalid handle (auth 0) for dpdmux.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpdmux_attr, 0, sizeof(dpdmux_attr));
	error = dpdmux_get_attributes_v10(&restool.mc_io, 0, dpdmux_handle,
					&dpdmux_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpdmux_attr.id);

	parse_endpoint_dpl(curr, dpdmux_attr.num_ifs + 1);
	parse_dpdmux_options(fp, dpdmux_attr.options);
	parse_dpdmux_method(fp, dpdmux_attr.method);
	parse_dpdmux_manip(fp, dpdmux_attr.manip);
	fprintf(fp, "\t\t\tnum_ifs = <%#x>;\n",
		(uint32_t)dpdmux_attr.num_ifs);

	error = 0;

out:
	if (dpdmux_opened) {
		int error2;

		error2 = dpdmux_close_v10(&restool.mc_io, 0, dpdmux_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;

}

static void parse_dpsw_options(FILE *fp, uint64_t options)
{
	char buf[300];
	int len;

	if ((options & ~ALL_DPSW_OPTS) != 0)
		fprintf(fp, "\t\t\t/* Unrecognized options found... */\n");

	snprintf(buf, 14, "\t\t\toptions = ");

	if (options & DPSW_OPT_FLOODING_DIS) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPSW_OPT_FLOODING_DIS\", ");
	}

	if (options & DPSW_OPT_MULTICAST_DIS) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPSW_OPT_MULTICAST_DIS\", ");
	}

	if (options & DPSW_OPT_CTRL_IF_DIS) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPSW_OPT_CTRL_IF_DIS\", ");
	}

	if (options & DPSW_OPT_FLOODING_METERING_DIS) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPSW_OPT_FLOODING_METERING_DIS\", ");
	}

	if (options & DPSW_OPT_METERING_EN) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPSW_OPT_METERING_EN\", ");
	}

	if (options & DPSW_OPT_LAG_DIS) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPSW_OPT_LAG_DIS\", ");
	}

	if (options & DPSW_OPT_BP_PER_IF) {
		len = strlen(buf);
		snprintf(buf+len, 50, "\"DPSW_OPT_BP_PER_IF\", ");
	}

	len = strlen(buf);
	if (13 == len)
		return;
	buf[len-2] = ';';
	buf[len-1] = '\0';

	fprintf(fp, "%s\n", buf);

}

static int parse_dpsw_v9(FILE *fp, struct obj_list *curr)
{
	uint16_t dpsw_handle;
	int error;
	struct dpsw_attr_v9 dpsw_attr;
	bool dpsw_opened = false;

	error = dpsw_open(&restool.mc_io, 0, curr->id, &dpsw_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpsw_opened = true;
	if (0 == dpsw_handle) {
		DEBUG_PRINTF(
			"dpsw_open() returned invalid handle (auth 0) for dpsw.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpsw_attr, 0, sizeof(dpsw_attr));
	error = dpsw_get_attributes_v9(&restool.mc_io, 0, dpsw_handle,
				       &dpsw_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpsw_attr.id);

	parse_endpoint_dpl(curr, dpsw_attr.num_ifs);
	parse_dpsw_options(fp, dpsw_attr.options);
	fprintf(fp, "\t\t\tmax_vlans = <%#x>;\n",
		(uint32_t)dpsw_attr.max_vlans);
	fprintf(fp, "\t\t\tmax_fdbs = <%#x>;\n", (uint32_t)dpsw_attr.max_fdbs);
	/* it should be num_fdb_entries,
	 * but dpsw_attr {} call it max_fdb_entries (typo)
	 */
	fprintf(fp, "\t\t\tnum_fdb_entries = <%#x>;\n",
		(uint32_t)dpsw_attr.max_fdb_entries);
	fprintf(fp, "\t\t\tfdb_aging_time = <%#x>;\n",
		(uint32_t)dpsw_attr.fdb_aging_time);
	fprintf(fp, "\t\t\tnum_ifs = <%#x>;\n", (uint32_t)dpsw_attr.num_ifs);
	fprintf(fp, "\t\t\tmax_fdb_mc_groups = <%#x>;\n",
		(uint32_t)dpsw_attr.max_fdb_mc_groups);
	fprintf(fp, "\t\t\tmax_meters_per_if = <%#x>;\n",
		(uint32_t)dpsw_attr.max_meters_per_if);

	error = 0;

out:
	if (dpsw_opened) {
		int error2;

		error2 = dpsw_close(&restool.mc_io, 0, dpsw_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}

static int parse_dpsw_v10(FILE *fp, struct obj_list *curr)
{
	struct dpsw_attr_v10 dpsw_attr;
	bool dpsw_opened = false;
	uint16_t dpsw_handle;
	int error;

	error = dpsw_open_v10(&restool.mc_io, 0, curr->id, &dpsw_handle);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	dpsw_opened = true;
	if (0 == dpsw_handle) {
		DEBUG_PRINTF(
			"dpsw_open() returned invalid handle (auth 0) for dpsw.%u\n",
			curr->id);
		error = -ENOENT;
		goto out;
	}

	memset(&dpsw_attr, 0, sizeof(dpsw_attr));
	error = dpsw_get_attributes_v10(&restool.mc_io, 0, dpsw_handle,
				       &dpsw_attr);
	if (error < 0) {
		mc_status = flib_error_to_mc_status(error);
		ERROR_PRINTF("MC error: %s (status %#x)\n",
			     mc_status_to_string(mc_status), mc_status);
		goto out;
	}
	assert(curr->id == dpsw_attr.id);

	parse_endpoint_dpl(curr, dpsw_attr.num_ifs);
	parse_dpsw_options(fp, dpsw_attr.options);
	fprintf(fp, "\t\t\tmax_vlans = <%#x>;\n",
		(uint32_t)dpsw_attr.max_vlans);
	fprintf(fp, "\t\t\tmax_fdbs = <%#x>;\n", (uint32_t)dpsw_attr.max_fdbs);
	/* it should be num_fdb_entries,
	 * but dpsw_attr {} call it max_fdb_entries (typo)
	 */
	fprintf(fp, "\t\t\tnum_fdb_entries = <%#x>;\n",
		(uint32_t)dpsw_attr.max_fdb_entries);
	fprintf(fp, "\t\t\tfdb_aging_time = <%#x>;\n",
		(uint32_t)dpsw_attr.fdb_aging_time);
	fprintf(fp, "\t\t\tnum_ifs = <%#x>;\n", (uint32_t)dpsw_attr.num_ifs);
	fprintf(fp, "\t\t\tmax_fdb_mc_groups = <%#x>;\n",
		(uint32_t)dpsw_attr.max_fdb_mc_groups);
	fprintf(fp, "\t\t\tmax_meters_per_if = <%#x>;\n",
		(uint32_t)dpsw_attr.max_meters_per_if);
	fprintf(fp, "\t\t\tflooding_cfg = \"%s\";\n",
		dpsw_attr.flooding_cfg == DPSW_FLOODING_PER_VLAN ?
		"DPSW_FLOODING_PER_VLAN" : "DPSW_FLOODING_PER_FDB");
	fprintf(fp, "\t\t\tbroadcast_cfg = \"%s\";\n",
		dpsw_attr.broadcast_cfg == DPSW_BROADCAST_PER_OBJECT ?
		"DPSW_BROADCAST_PER_OBJECT" : "DPSW_BROADCAST_PER_FDB");

	error = 0;

out:
	if (dpsw_opened) {
		int error2;

		error2 = dpsw_close_v10(&restool.mc_io, 0, dpsw_handle);
		if (error2 < 0) {
			mc_status = flib_error_to_mc_status(error2);
			ERROR_PRINTF("MC error: %s (status %#x)\n",
				     mc_status_to_string(mc_status), mc_status);
			if (error == 0)
				error = error2;
		}
	}

	return error;
}

static int write_objects(void)
{
	struct obj_list *curr_obj;
	FILE *fp = stdout;

	fprintf(fp, "\n");
	fprintf(fp,
		"\t/*****************************************************************\n");
	fprintf(fp, "\t * Objects\n");
	fprintf(fp,
		"\t *****************************************************************/\n");


	fprintf(fp, "\tobjects {\n");
	curr_obj = obj_head;
	while (curr_obj) {
		if (strcmp(curr_obj->type, "dpmcp") == 0 && 0 == curr_obj->id) {
			curr_obj = curr_obj->next;
			continue;
		}

		fprintf(fp, "\n");
		fprintf(fp, "\t\t%s@%d {\n", curr_obj->type, curr_obj->id);
		fprintf(fp, "\t\t\tcompatible = \"fsl,%s\";\n", curr_obj->type);

		/* objects don't need to be parsed and get attributes for now */
		if (strcmp(curr_obj->type, "dpbp") == 0)
			parse_dpbp(fp, curr_obj);
		if (strcmp(curr_obj->type, "dpdbg") == 0)
			parse_dpdbg(fp, curr_obj);
		if (strcmp(curr_obj->type, "dpmcp") == 0)
			parse_dpmcp(fp, curr_obj);
		if (strcmp(curr_obj->type, "dprc") == 0)
			parse_dprc(fp, curr_obj);
		if (strcmp(curr_obj->type, "dprtc") == 0)
			parse_dprtc(fp, curr_obj);

		/* objects need to be parsed and get attributes */
		if (strcmp(curr_obj->type, "dpaiop") == 0)
			parse_dpaiop(fp, curr_obj);

		if (strcmp(curr_obj->type, "dpcon") == 0) {
			if (restool.mc_fw_version.major == 9)
				parse_dpcon_v9(fp, curr_obj);
			else if (restool.mc_fw_version.major == 10)
				parse_dpcon_v10(fp, curr_obj);
		}

		if (strcmp(curr_obj->type, "dpdcei") == 0) {
			if (restool.mc_fw_version.major == 9)
				parse_dpdcei_v9(fp, curr_obj);
			else if (restool.mc_fw_version.major == 10)
				parse_dpdcei_v10(fp, curr_obj);
		}

		if (strcmp(curr_obj->type, "dpdmai") == 0) {
			if (restool.mc_fw_version.major == 9)
				parse_dpdmai_v9(fp, curr_obj);
			else if (restool.mc_fw_version.major == 10)
				parse_dpdmai_v10(fp, curr_obj);
		}

		if (strcmp(curr_obj->type, "dpio") == 0) {
			if (restool.mc_fw_version.major == 9)
				parse_dpio_v9(fp, curr_obj);
			else if (restool.mc_fw_version.major == 10)
				parse_dpio_v10(fp, curr_obj);
		}

		if (strcmp(curr_obj->type, "dpseci") == 0) {
			if (restool.mc_fw_version.major == 9)
				parse_dpseci_v9(fp, curr_obj);
			else if (restool.mc_fw_version.major == 10)
				parse_dpseci_v10(fp, curr_obj);
		}

		/* following objects have possible connections */
		if (strcmp(curr_obj->type, "dpci") == 0) {
			if (restool.mc_fw_version.major == 9)
				parse_dpci_v9(fp, curr_obj);
			else if (restool.mc_fw_version.major == 10)
				parse_dpci_v10(fp, curr_obj);
		}

		if (strcmp(curr_obj->type, "dpmac") == 0)
			parse_dpmac(fp, curr_obj);
			/* dpmac do not need to be parsed now */

		if (strcmp(curr_obj->type, "dpni") == 0) {
			if (restool.mc_fw_version.major == 9)
				parse_dpni_v9(fp, curr_obj);
			else if (restool.mc_fw_version.major == 10)
				parse_dpni_v10(fp, curr_obj);
		}


		/* following objects have possible connections and interface*/
		if (strcmp(curr_obj->type, "dpdmux") == 0) {
			if (restool.mc_fw_version.major == 9)
				parse_dpdmux_v9(fp, curr_obj);
			else if (restool.mc_fw_version.major == 10)
				parse_dpdmux_v10(fp, curr_obj);
		}

		if (strcmp(curr_obj->type, "dpsw") == 0) {
			if (restool.mc_fw_version.major == 9)
				parse_dpsw_v9(fp, curr_obj);
			else if (restool.mc_fw_version.major == 10)
				parse_dpsw_v10(fp, curr_obj);
		}

		fprintf(fp, "\t\t};\n");
		curr_obj = curr_obj->next;
	}
	fprintf(fp, "\t};\n");

	return 0;
}

static int write_connections(void)
{
	struct conn_list *curr_conn;
	int conn_num = 1;
	FILE *fp = stdout;

	fprintf(fp, "\n");
	fprintf(fp,
		"\t/*****************************************************************\n");
	fprintf(fp, "\t * Connections\n");
	fprintf(fp,
		"\t *****************************************************************/\n");

	fprintf(fp, "\tconnections {\n");
	curr_conn = conn_head;
	while (curr_conn) {
		fprintf(fp, "\n");
		fprintf(fp, "\t\tconnection@%d{\n", conn_num);
		if (curr_conn->if_id1 < 0)
			fprintf(fp, "\t\t\tendpoint1 = \"%s@%d\";\n",
				curr_conn->type1, curr_conn->id1);
		else
			fprintf(fp, "\t\t\tendpoint1 = \"%s@%d/if@%d\";\n",
				curr_conn->type1, curr_conn->id1,
				curr_conn->if_id1);
		if (curr_conn->if_id2 < 0)
			fprintf(fp, "\t\t\tendpoint2 = \"%s@%d\";\n",
				curr_conn->type2, curr_conn->id2);
		else
			fprintf(fp, "\t\t\tendpoint2 = \"%s@%d/if@%d\";\n",
				curr_conn->type2, curr_conn->id2,
				curr_conn->if_id2);

		fprintf(fp, "\t\t};\n");
		curr_conn = curr_conn->next;
		conn_num++;
	}
	fprintf(fp, "\t};\n");

	return 0;
}

static void delete_all_list(void)
{
	struct container_list *curr_cont;
	struct container_list *tmp_cont;
	struct obj_list *curr_obj;
	struct obj_list *tmp_obj;
	struct conn_list *curr_conn;
	struct conn_list *tmp_conn;

	curr_cont = container_head;
	curr_obj = obj_head;
	curr_conn = conn_head;

	/* delete global object lists */
	while (curr_obj) {
		tmp_obj = curr_obj;
		curr_obj = curr_obj->next;
		free(tmp_obj);
	}
	obj_head = NULL;

	/* delete global connection lists */
	while (curr_conn) {
		tmp_conn = curr_conn;
		curr_conn = curr_conn->next;
		free(tmp_conn);
	}
	conn_head = NULL;

	/* delete global container lists */
	while (curr_cont) {
		tmp_cont = curr_cont;
		curr_cont = curr_cont->next;

		/* delete the associated object lists whithin each container */
		curr_obj = tmp_cont->obj;
		while (curr_obj) {
			tmp_obj = curr_obj;
			curr_obj = curr_obj->next;
			free(tmp_obj);
		}
		tmp_cont->obj = NULL;

		free(tmp_cont);
	}
	container_head = NULL;
}

int dpl_generate(void)
{
	int error;
	uint32_t dprc_id = 0;

	if (restool.obj_name != NULL) {
		error = parse_object_name(restool.obj_name, "dprc", &dprc_id);
		if (error < 0)
			return error;
	}

	FILE *fp = stdout;

	fprintf(fp, "/dts-v1/;\n");
	fprintf(fp, "/ {\n");
	fprintf(fp, "\tdpl-version = <%d>;\n", restool.mc_fw_version.major);

	error = parse_layout(dprc_id);
	if (error) {
		ERROR_PRINTF("parse_layout() failed, error=%d\n", error);
		return error;
	}

	error = write_containers();
	if (error) {
		ERROR_PRINTF("write_containers() failed, error=%d\n", error);
		return error;
	}

	error = write_objects();
	if (error) {
		ERROR_PRINTF("write_objects() failed, error=%d\n", error);
		return error;
	}

	error = write_connections();
	if (error) {
		ERROR_PRINTF("write_connections() failed, error=%d\n", error);
		return error;
	}

	fprintf(fp, "};\n");

	delete_all_list();

	return 0;
}
