/*
 * Copyright 2015 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 */
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include "hwmgr.h"

static int phm_run_table(struct pp_hwmgr *hwmgr,
			 struct phm_runtime_table_header *rt_table,
			 void *input,
			 void *output,
			 void *temp_storage)
{
	int result = 0;
	phm_table_function *function;

	if (rt_table->function_list == NULL) {
		pr_debug("[ powerplay ] this function not implement!\n");
		return 0;
	}

	for (function = rt_table->function_list; NULL != *function; function++) {
		int tmp = (*function)(hwmgr, input, output, temp_storage, result);

		if (tmp == PP_Result_TableImmediateExit)
			break;
		if (tmp) {
			if (0 == result)
				result = tmp;
			if (rt_table->exit_error)
				break;
		}
	}

	return result;
}

int phm_dispatch_table(struct pp_hwmgr *hwmgr,
		       struct phm_runtime_table_header *rt_table,
		       void *input, void *output)
{
	int result;
	void *temp_storage;

	if (hwmgr == NULL || rt_table == NULL) {
		printk(KERN_ERR "[ powerplay ] Invalid Parameter!\n");
		return -EINVAL;
	}

	if (0 != rt_table->storage_size) {
		temp_storage = kzalloc(rt_table->storage_size, GFP_KERNEL);
		if (temp_storage == NULL) {
			printk(KERN_ERR "[ powerplay ] Could not allocate table temporary storage\n");
			return -ENOMEM;
		}
	} else {
		temp_storage = NULL;
	}

	result = phm_run_table(hwmgr, rt_table, input, output, temp_storage);

	kfree(temp_storage);

	return result;
}

int phm_construct_table(struct pp_hwmgr *hwmgr,
			const struct phm_master_table_header *master_table,
			struct phm_runtime_table_header *rt_table)
{
	uint32_t function_count = 0;
	const struct phm_master_table_item *table_item;
	uint32_t size;
	phm_table_function *run_time_list;
	phm_table_function *rtf;

	if (hwmgr == NULL || master_table == NULL || rt_table == NULL) {
		printk(KERN_ERR "[ powerplay ] Invalid Parameter!\n");
		return -EINVAL;
	}

	for (table_item = master_table->master_list;
		NULL != table_item->tableFunction; table_item++) {
		if ((NULL == table_item->isFunctionNeededInRuntimeTable) ||
		    (table_item->isFunctionNeededInRuntimeTable(hwmgr)))
			function_count++;
	}

	size = (function_count + 1) * sizeof(phm_table_function);
	run_time_list = kzalloc(size, GFP_KERNEL);

	if (NULL == run_time_list)
		return -ENOMEM;

	rtf = run_time_list;
	for (table_item = master_table->master_list;
		NULL != table_item->tableFunction; table_item++) {
		if ((rtf - run_time_list) > function_count) {
			printk(KERN_ERR "[ powerplay ] Check function results have changed\n");
			kfree(run_time_list);
			return -EINVAL;
		}

		if ((NULL == table_item->isFunctionNeededInRuntimeTable) ||
		     (table_item->isFunctionNeededInRuntimeTable(hwmgr))) {
			*(rtf++) = table_item->tableFunction;
		}
	}

	if ((rtf - run_time_list) > function_count) {
		printk(KERN_ERR "[ powerplay ] Check function results have changed\n");
		kfree(run_time_list);
		return -EINVAL;
	}

	*rtf = NULL;
	rt_table->function_list = run_time_list;
	rt_table->exit_error = (0 != (master_table->flags & PHM_MasterTableFlag_ExitOnError));
	rt_table->storage_size = master_table->storage_size;
	return 0;
}

int phm_destroy_table(struct pp_hwmgr *hwmgr,
		      struct phm_runtime_table_header *rt_table)
{
	if (hwmgr == NULL || rt_table == NULL) {
		printk(KERN_ERR "[ powerplay ] Invalid Parameter\n");
		return -EINVAL;
	}

	if (NULL == rt_table->function_list)
		return 0;

	kfree(rt_table->function_list);

	rt_table->function_list = NULL;
	rt_table->storage_size = 0;
	rt_table->exit_error = false;

	return 0;
}
