<commit_before>/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/radix-tree.h>
#include <mach/board.h>
#include <mach/socinfo.h>
#include "msm_bus_core.h"

enum {
	SLAVE_NODE,
	MASTER_NODE,
};

enum {
	DISABLE,
	ENABLE,
};

struct msm_bus_fabric {
	struct msm_bus_fabric_device fabdev;
	int ahb;
	void *cdata[NUM_CTX];
	bool arb_dirty;
	bool clk_dirty;
	struct radix_tree_root fab_tree;
	int num_nodes;
	struct list_head gateways;
	struct msm_bus_inode_info info;
	struct msm_bus_fabric_registration *pdata;
	void *hw_data;
};
#define to_msm_bus_fabric(d) container_of(d, \
	struct msm_bus_fabric, d)

/**
 * msm_bus_fabric_add_node() - Add a node to the fabric structure
 * @fabric: Fabric device to which the node should be added
 * @info: The node to be added
 */
static int msm_bus_fabric_add_node(struct msm_bus_fabric *fabric,
	struct msm_bus_inode_info *info)
{
	int status = -ENOMEM;
	MSM_BUS_DBG("msm_bus_fabric_add_node: ID %d Gw: %d\n",
		info->node_info->priv_id, info->node_info->gateway);
	status = radix_tree_preload(GFP_ATOMIC);
	if (status)
		goto out;

	status = radix_tree_insert(&fabric->fab_tree, info->node_info->priv_id,
			info);
	radix_tree_preload_end();
	if (IS_SLAVE(info->node_info->priv_id))
		radix_tree_tag_set(&fabric->fab_tree, info->node_info->priv_id,
			SLAVE_NODE);

	if (info->node_info->slaveclk[DUAL_CTX]) {
		info->nodeclk[DUAL_CTX].clk = clk_get_sys("msm_bus",
			info->node_info->slaveclk[DUAL_CTX]);
		if (IS_ERR(info->nodeclk[DUAL_CTX].clk)) {
			MSM_BUS_ERR("Could not get clock for %s\n",
				info->node_info->slaveclk[DUAL_CTX]);
			status = -EINVAL;
			goto out;
		}
		info->nodeclk[DUAL_CTX].enable = false;
		info->nodeclk[DUAL_CTX].dirty = false;
	}

out:
	return status;
}

/**
 * msm_bus_add_fab() - Add a fabric (gateway) to the current fabric
 * @fabric: Fabric device to which the gateway info should be added
 * @info: Gateway node to be added to the fabric
 */
static int msm_bus_fabric_add_fab(struct msm_bus_fabric *fabric,
	struct msm_bus_inode_info *info)
{
	struct msm_bus_fabnodeinfo *fabnodeinfo;
	MSM_BUS_DBG("msm_bus_fabric_add_fab: ID %d Gw: %d\n",
		info->node_info->priv_id, info->node_info->gateway);
	fabnodeinfo = kzalloc(sizeof(struct msm_bus_fabnodeinfo), GFP_KERNEL);
	if (fabnodeinfo == NULL) {
		MSM_FAB_ERR("msm_bus_fabric_add_fab: "
			"No Node Info\n");
		MSM_FAB_ERR("axi: Cannot register fabric!\n");
		return -ENOMEM;
	}

	fabnodeinfo->info = info;
	fabnodeinfo->info->num_pnodes = -1;
	list_add_tail(&fabnodeinfo->list, &fabric->gateways);
	return 0;
}

/**
 * register_fabric_info() - Create the internal fabric structure and
 * build the topology tree from platform specific data
 * @pdev: Platform device for getting base addresses
 * @fabric: Fabric to which the gateways, nodes should be added
 *
 * This function is called from probe. Iterates over the platform data,
 * and builds the topology
 */
static int register_fabric_info(struct platform_device *pdev,
	struct msm_bus_fabric *fabric)
{
	int i = 0, ret = 0, err = 0;

	MSM_BUS_DBG("id:%d pdata-id: %d len: %d\n", fabric->fabdev.id,
		fabric->pdata->id, fabric->pdata->len);
	fabric->hw_data = fabric->fabdev.hw_algo.allocate_hw_data(pdev,
		fabric->pdata);
	if (ZERO_OR_NULL_PTR(fabric->hw_data) && fabric->pdata->ahb == 0) {
		MSM_BUS_ERR("Couldn't allocate hw_data for fab: %d\n",
			fabric->fabdev.id);
		goto error;
	}

	for (i = 0; i < fabric->pdata->len; i++) {
		struct msm_bus_inode_info *info;
		int ctx, j;

		info = kzalloc(sizeof(struct msm_bus_inode_info), GFP_KERNEL);
		if (info == NULL) {
			MSM_BUS_ERR("Error allocating info\n");
			return -ENOMEM;
		}

		info->node_info = fabric->pdata->info + i;
		info->commit_index = -1;
		info->num_pnodes = -1;

		for (ctx = 0; ctx < NUM_CTX; ctx++) {
			if (info->node_info->slaveclk[ctx]) {
				info->nodeclk[ctx].clk = clk_get_sys("msm_bus",
					info->node_info->slaveclk[ctx]);
				if (IS_ERR(info->nodeclk[ctx].clk)) {
					MSM_BUS_ERR("Couldn't get clk %s\n",
						info->node_info->slaveclk[ctx]);
					err = -EINVAL;
				}
				info->nodeclk[ctx].enable = false;
				info->nodeclk[ctx].dirty = false;
			}

			if (info->node_info->memclk[ctx]) {
				info->memclk[ctx].clk = clk_get_sys("msm_bus",
						info->node_info->memclk[ctx]);
				if (IS_ERR(info->memclk[ctx].clk)) {
					MSM_BUS_ERR("Couldn't get clk %s\n",
						info->node_info->memclk[ctx]);
					err = -EINVAL;
				}
				info->memclk[ctx].enable = false;
				info->memclk[ctx].dirty = false;
			}
		}

		ret = info->node_info->gateway ?
			msm_bus_fabric_add_fab(fabric, info) :
			msm_bus_fabric_add_node(fabric, info);
		if (ret) {
			MSM_BUS_ERR("Unable to add node info, ret: %d\n", ret);
			kfree(info);
			goto error;
		}

		if (fabric->fabdev.hw_algo.node_init == NULL)
			continue;

		for (j = 0; j < NUM_CTX; j++)
			clk_prepare_enable(fabric->info.nodeclk[j].clk);

		fabric->fabdev.hw_algo.node_init(fabric->hw_data, info);
		if (ret) {
			MSM_BUS_ERR("Unable to init node info, ret: %d\n", ret);
			kfree(info);
		}

		for (j = 0; j < NUM_CTX; j++)
			clk_disable_unprepare(fabric->info.nodeclk[j].clk);
	}

	MSM_BUS_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
		" ntieredslaves: %d, rpm_enabled: %d\n",
		fabric->fabdev.id, fabric->pdata->nmasters,
		fabric->pdata->nslaves, fabric->pdata->ntieredslaves,
		fabric->pdata->rpm_enabled);
	MSM_BUS_DBG("msm_bus_register_fabric_info i: %d\n", i);
	fabric->num_nodes = fabric->pdata->len;
error:
	fabric->num_nodes = i;
	msm_bus_dbg_commit_data(fabric->fabdev.name, NULL, 0, 0, 0,
		MSM_BUS_DBG_REGISTER);
	return ret | err;
}

/**
 * msm_bus_fabric_update_clks() - Set the clocks for fabrics and slaves
 * @fabric: Fabric for which the clocks need to be updated
 * @slave: The node for which the clocks need to be updated
 * @index: The index for which the current clocks are set
 * @curr_clk_hz:Current clock value
 * @req_clk_hz: Requested clock value
 * @bwsum: Bandwidth Sum
 * @clk_flag: Flag determining whether fabric clock or the slave clock has to
 * be set. If clk_flag is set, fabric clock is set, else slave clock is set.
 */
static int msm_bus_fabric_update_clks(struct msm_bus_fabric_device *fabdev,
		struct msm_bus_inode_info *slave, int index,
		unsigned long curr_clk_hz, unsigned long req_clk_hz,
		unsigned long bwsum_hz, int clk_flag, int ctx,
		unsigned int cl_active_flag)
{
	int i, status = 0;
	unsigned long max_pclk = 0, rate;
	unsigned long *pclk = NULL;
	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
	struct nodeclk *nodeclk;

	/**
	 * Integration for clock rates is not required if context is not
	 * same as client's active-only flag
	 */
	if (ctx != cl_active_flag)
		goto skip_set_clks;

	/* Maximum for this gateway */
	for (i = 0; i <= slave->num_pnodes; i++) {
		if (i == index && (req_clk_hz < curr_clk_hz))
			continue;
		slave->pnode[i].sel_clk = &slave->pnode[i].clk[ctx];
		max_pclk = max(max_pclk, *slave->pnode[i].sel_clk);
	}

	*slave->link_info.sel_clk =
		max(max_pclk, max(bwsum_hz, req_clk_hz));
	/* Is this gateway or slave? */
	if (clk_flag && (!fabric->ahb)) {
		struct msm_bus_fabnodeinfo *fabgw = NULL;
		struct msm_bus_inode_info *info = NULL;
		/* Maximum of all gateways set at fabric */
		list_for_each_entry(fabgw, &fabric->gateways, list) {
			info = fabgw->info;
			if (!info)
				continue;
			info->link_info.sel_clk = &info->link_info.clk[ctx];
			max_pclk = max(max_pclk, *info->link_info.sel_clk);
		}
		MSM_BUS_DBG("max_pclk from gateways: %lu\n", max_pclk);

		/* Maximum of all slave clocks. */

		for (i = 0; i < fabric->pdata->len; i++) {
			if (fabric->pdata->info[i].gateway ||
				(fabric->pdata->info[i].id < SLAVE_ID_KEY))
				continue;
			info = radix_tree_lookup(&fabric->fab_tree,
				fabric->pdata->info[i].priv_id);
			if (!info)
				continue;
			info->link_info.sel_clk = &info->link_info.clk[ctx];
			max_pclk = max(max_pclk, *info->link_info.sel_clk);
		}


		MSM_BUS_DBG("max_pclk from slaves & gws: %lu\n", max_pclk);
		fabric->info.link_info.sel_clk =
			&fabric->info.link_info.clk[ctx];
		pclk = fabric->info.link_info.sel_clk;
	} else {
		slave->link_info.sel_clk = &slave->link_info.clk[ctx];
		pclk = slave->link_info.sel_clk;
	}


	*pclk = max(max_pclk, max(bwsum_hz, req_clk_hz));

	if (!fabric->pdata->rpm_enabled)
		goto skip_set_clks;

	if (clk_flag) {
		nodeclk = &fabric->info.nodeclk[ctx];
		if (nodeclk->clk) {
			MSM_BUS_DBG("clks: id: %d set-clk: %lu bwsum_hz:%lu\n",
			fabric->fabdev.id, *pclk, bwsum_hz);
			if (nodeclk->rate != *pclk) {
				nodeclk->dirty = true;
				nodeclk->rate = *pclk;
			}
			fabric->clk_dirty = true;
		}
	} else {
		nodeclk = &slave->nodeclk[ctx];
		if (nodeclk->clk) {
			rate = *pclk;
			MSM_BUS_DBG("AXI_clks: id: %d set-clk: %lu "
			"bwsum_hz: %lu\n" , slave->node_info->priv_id, rate,
			bwsum_hz);
			if (nodeclk->rate != rate) {
				nodeclk->dirty = true;
				nodeclk->rate = rate;
			}
		}
		if (!status && slave->memclk[ctx].clk) {
			rate = *slave->link_info.sel_clk;
			if (slave->memclk[ctx].rate != rate) {
				slave->memclk[ctx].rate = rate;
				slave->memclk[ctx].dirty = true;
			}
			slave->memclk[ctx].rate = rate;
			fabric->clk_dirty = true;
		}
	}
skip_set_clks:
	return status;
}

void msm_bus_fabric_update_bw(struct msm_bus_fabric_device *fabdev,
	struct msm_bus_inode_info *hop, struct msm_bus_inode_info *info,
	long int add_bw, int *master_tiers, int ctx)
{
	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
	void *sel_cdata;
	int i;

	/* Temporarily stub out arbitration settings for msm8974 */
	if (machine_is_msm8974())
		return;

	sel_cdata = fabric->cdata[ctx];

	/* If it's an ahb fabric, don't calculate arb values */
	if (fabric->ahb) {
		MSM_BUS_DBG("AHB fabric, skipping bw calculation\n");
		return;
	}
	if (!add_bw) {
		MSM_BUS_DBG("No bandwidth delta. Skipping commit\n");
		return;
	}

	for (i = 0; i < NUM_CTX; i++)
		clk_prepare_enable(fabric->info.nodeclk[i].clk);

	fabdev->hw_algo.update_bw(hop, info, fabric->pdata, sel_cdata,
		master_tiers, add_bw);
	for (i = 0; i < NUM_CTX; i++)
		clk_disable_unprepare(fabric->info.nodeclk[i].clk);

	fabric->arb_dirty = true;
}

static int msm_bus_fabric_clk_set(int enable, struct msm_bus_inode_info *info)
{
	int i, status = 0;
	long rounded_rate;

	for (i = 0; i < NUM_CTX; i++) {
		if (info->nodeclk[i].dirty) {
			if (info->nodeclk[i].rate != 0) {
				rounded_rate = clk_round_rate(info->
					nodeclk[i].clk, info->nodeclk[i].rate);
				status = clk_set_rate(info->nodeclk[i].clk,
					rounded_rate);
				MSM_BUS_DBG("AXI: node: %d set_rate: %ld\n",
					info->node_info->id, rounded_rate);
			}

			if (enable && !(info->nodeclk[i].enable)) {
				clk_prepare_enable(info->nodeclk[i].clk);
				info->nodeclk[i].dirty = false;
				info->nodeclk[i].enable = true;
			} else if ((info->nodeclk[i].rate == 0) && (!enable)
				&& (info->nodeclk[i].enable)) {
				clk_disable_unprepare(info->nodeclk[i].clk);
				info->nodeclk[i].dirty = false;
				info->nodeclk[i].enable = false;
			}
		}

		if (info->memclk[i].dirty) {
			if (info->nodeclk[i].rate != 0) {
				rounded_rate = clk_round_rate(info->
					memclk[i].clk, info->memclk[i].rate);
				status = clk_set_rate(info->memclk[i].clk,
					rounded_rate);
				MSM_BUS_DBG("AXI: node: %d set_rate: %ld\n",
					info->node_info->id, rounded_rate);
			}

			if (enable && !(info->memclk[i].enable)) {
				clk_prepare_enable(info->memclk[i].clk);
				info->memclk[i].dirty = false;
				info->memclk[i].enable = true;
			} else if (info->memclk[i].rate == 0 && (!enable) &&
				(info->memclk[i].enable)) {
				clk_disable_unprepare(info->memclk[i].clk);
				info->memclk[i].dirty = false;
				info->memclk[i].enable = false;
			}
		}
	}

	return status;
}

/**
 * msm_bus_fabric_clk_commit() - Call clock enable and update clock
 * values.
*/
static int msm_bus_fabric_clk_commit(int enable, struct msm_bus_fabric *fabric)
{
	unsigned int i, nfound = 0, status = 0;
	struct msm_bus_inode_info *info[fabric->pdata->nslaves];

	if (fabric->clk_dirty == false) {
		MSM_BUS_DBG("No clocks have been touched for fabric: %d\n",
			fabric->fabdev.id);
		goto out;
	} else
		status = msm_bus_fabric_clk_set(enable, &fabric->info);

	if (status)
		MSM_BUS_WARN("Error setting clocks on fabric: %d\n",
			fabric->fabdev.id);

	nfound = radix_tree_gang_lookup_tag(&fabric->fab_tree, (void **)&info,
		fabric->fabdev.id, fabric->pdata->nslaves, SLAVE_NODE);
	if (nfound == 0) {
		MSM_BUS_DBG("No slaves found for fabric: %d\n",
			fabric->fabdev.id);
		goto out;
	}

	for (i = 0; i < nfound; i++) {
		status = msm_bus_fabric_clk_set(enable, info[i]);
		if (status)
			MSM_BUS_WARN("Error setting clocks for node: %d\n",
				info[i]->node_info->id);
	}

out:
	return status;
}

/**
 * msm_bus_fabric_hw_commit() - Commit the arbitration data to Hardware.
 * @fabric: Fabric for which the data should be committed
 * */
static int msm_bus_fabric_hw_commit(struct msm_bus_fabric_device *fabdev)
{
	int status = 0;
	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);

	/*
	 * For a non-zero bandwidth request, clocks should be enabled before
	 * sending the arbitration data to RPM, but should be disabled only
	 * after commiting the data.
	 */
	status = msm_bus_fabric_clk_commit(ENABLE, fabric);
	if (status)
		MSM_BUS_DBG("Error setting clocks on fabric: %d\n",
			fabric->fabdev.id);

	if (!fabric->arb_dirty) {
		MSM_BUS_DBG("Not committing as fabric not arb_dirty\n");
		goto skip_arb;
	}

	status = fabdev->hw_algo.commit(fabric->pdata, fabric->hw_data,
		(void **)fabric->cdata);
	if (status)
		MSM_BUS_DBG("Error committing arb data for fabric: %d\n",
			fabric->fabdev.id);

	fabric->arb_dirty = false;
skip_arb:
	/*
	 * If the bandwidth request is 0 for a fabric, the clocks
	 * should be disabled after arbitration data is committed.
	 */
	status = msm_bus_fabric_clk_commit(DISABLE, fabric);
	if (status)
		MSM_BUS_DBG("Error disabling clocks on fabric: %d\n",
			fabric->fabdev.id);
	fabric->clk_dirty = false;
	return status;
}
<commit_msg>msm: msm_bus: Fix scaling of ocmem core clock<commit_after>/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#define pr_fmt(fmt) "AXI: %s(): " fmt, __func__

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/radix-tree.h>
#include <mach/board.h>
#include <mach/socinfo.h>
#include "msm_bus_core.h"

enum {
	SLAVE_NODE,
	MASTER_NODE,
	CLK_NODE,
};

enum {
	DISABLE,
	ENABLE,
};

struct msm_bus_fabric {
	struct msm_bus_fabric_device fabdev;
	int ahb;
	void *cdata[NUM_CTX];
	bool arb_dirty;
	bool clk_dirty;
	struct radix_tree_root fab_tree;
	int num_nodes;
	struct list_head gateways;
	struct msm_bus_inode_info info;
	struct msm_bus_fabric_registration *pdata;
	void *hw_data;
};
#define to_msm_bus_fabric(d) container_of(d, \
	struct msm_bus_fabric, d)

/**
 * msm_bus_fabric_add_node() - Add a node to the fabric structure
 * @fabric: Fabric device to which the node should be added
 * @info: The node to be added
 */
static int msm_bus_fabric_add_node(struct msm_bus_fabric *fabric,
	struct msm_bus_inode_info *info)
{
	int status = -ENOMEM, ctx;
	MSM_BUS_DBG("msm_bus_fabric_add_node: ID %d Gw: %d\n",
		info->node_info->priv_id, info->node_info->gateway);
	status = radix_tree_preload(GFP_ATOMIC);
	if (status)
		goto out;

	status = radix_tree_insert(&fabric->fab_tree, info->node_info->priv_id,
			info);
	radix_tree_preload_end();
	if (IS_SLAVE(info->node_info->priv_id))
		radix_tree_tag_set(&fabric->fab_tree, info->node_info->priv_id,
			SLAVE_NODE);

	for (ctx = 0; ctx < NUM_CTX; ctx++) {
		if (info->node_info->slaveclk[ctx]) {
			radix_tree_tag_set(&fabric->fab_tree,
				info->node_info->priv_id, CLK_NODE);
			break;
		}

		info->nodeclk[ctx].enable = false;
		info->nodeclk[ctx].dirty = false;
	}

out:
	return status;
}

/**
 * msm_bus_add_fab() - Add a fabric (gateway) to the current fabric
 * @fabric: Fabric device to which the gateway info should be added
 * @info: Gateway node to be added to the fabric
 */
static int msm_bus_fabric_add_fab(struct msm_bus_fabric *fabric,
	struct msm_bus_inode_info *info)
{
	struct msm_bus_fabnodeinfo *fabnodeinfo;
	MSM_BUS_DBG("msm_bus_fabric_add_fab: ID %d Gw: %d\n",
		info->node_info->priv_id, info->node_info->gateway);
	fabnodeinfo = kzalloc(sizeof(struct msm_bus_fabnodeinfo), GFP_KERNEL);
	if (fabnodeinfo == NULL) {
		MSM_FAB_ERR("msm_bus_fabric_add_fab: "
			"No Node Info\n");
		MSM_FAB_ERR("axi: Cannot register fabric!\n");
		return -ENOMEM;
	}

	fabnodeinfo->info = info;
	fabnodeinfo->info->num_pnodes = -1;
	list_add_tail(&fabnodeinfo->list, &fabric->gateways);
	return 0;
}

/**
 * register_fabric_info() - Create the internal fabric structure and
 * build the topology tree from platform specific data
 * @pdev: Platform device for getting base addresses
 * @fabric: Fabric to which the gateways, nodes should be added
 *
 * This function is called from probe. Iterates over the platform data,
 * and builds the topology
 */
static int register_fabric_info(struct platform_device *pdev,
	struct msm_bus_fabric *fabric)
{
	int i = 0, ret = 0, err = 0;

	MSM_BUS_DBG("id:%d pdata-id: %d len: %d\n", fabric->fabdev.id,
		fabric->pdata->id, fabric->pdata->len);
	fabric->hw_data = fabric->fabdev.hw_algo.allocate_hw_data(pdev,
		fabric->pdata);
	if (ZERO_OR_NULL_PTR(fabric->hw_data) && fabric->pdata->ahb == 0) {
		MSM_BUS_ERR("Couldn't allocate hw_data for fab: %d\n",
			fabric->fabdev.id);
		goto error;
	}

	for (i = 0; i < fabric->pdata->len; i++) {
		struct msm_bus_inode_info *info;
		int ctx, j;

		info = kzalloc(sizeof(struct msm_bus_inode_info), GFP_KERNEL);
		if (info == NULL) {
			MSM_BUS_ERR("Error allocating info\n");
			return -ENOMEM;
		}

		info->node_info = fabric->pdata->info + i;
		info->commit_index = -1;
		info->num_pnodes = -1;

		for (ctx = 0; ctx < NUM_CTX; ctx++) {
			if (info->node_info->slaveclk[ctx]) {
				info->nodeclk[ctx].clk = clk_get_sys("msm_bus",
					info->node_info->slaveclk[ctx]);
				if (IS_ERR(info->nodeclk[ctx].clk)) {
					MSM_BUS_ERR("Couldn't get clk %s\n",
						info->node_info->slaveclk[ctx]);
					err = -EINVAL;
				}
				info->nodeclk[ctx].enable = false;
				info->nodeclk[ctx].dirty = false;
			}

			if (info->node_info->memclk[ctx]) {
				info->memclk[ctx].clk = clk_get_sys("msm_bus",
						info->node_info->memclk[ctx]);
				if (IS_ERR(info->memclk[ctx].clk)) {
					MSM_BUS_ERR("Couldn't get clk %s\n",
						info->node_info->memclk[ctx]);
					err = -EINVAL;
				}
				info->memclk[ctx].enable = false;
				info->memclk[ctx].dirty = false;
			}
		}

		ret = info->node_info->gateway ?
			msm_bus_fabric_add_fab(fabric, info) :
			msm_bus_fabric_add_node(fabric, info);
		if (ret) {
			MSM_BUS_ERR("Unable to add node info, ret: %d\n", ret);
			kfree(info);
			goto error;
		}

		if (fabric->fabdev.hw_algo.node_init == NULL)
			continue;

		for (j = 0; j < NUM_CTX; j++)
			clk_prepare_enable(fabric->info.nodeclk[j].clk);

		fabric->fabdev.hw_algo.node_init(fabric->hw_data, info);
		if (ret) {
			MSM_BUS_ERR("Unable to init node info, ret: %d\n", ret);
			kfree(info);
		}

		for (j = 0; j < NUM_CTX; j++)
			clk_disable_unprepare(fabric->info.nodeclk[j].clk);
	}

	MSM_BUS_DBG("Fabric: %d nmasters: %d nslaves: %d\n"
		" ntieredslaves: %d, rpm_enabled: %d\n",
		fabric->fabdev.id, fabric->pdata->nmasters,
		fabric->pdata->nslaves, fabric->pdata->ntieredslaves,
		fabric->pdata->rpm_enabled);
	MSM_BUS_DBG("msm_bus_register_fabric_info i: %d\n", i);
	fabric->num_nodes = fabric->pdata->len;
error:
	fabric->num_nodes = i;
	msm_bus_dbg_commit_data(fabric->fabdev.name, NULL, 0, 0, 0,
		MSM_BUS_DBG_REGISTER);
	return ret | err;
}

/**
 * msm_bus_fabric_update_clks() - Set the clocks for fabrics and slaves
 * @fabric: Fabric for which the clocks need to be updated
 * @slave: The node for which the clocks need to be updated
 * @index: The index for which the current clocks are set
 * @curr_clk_hz:Current clock value
 * @req_clk_hz: Requested clock value
 * @bwsum: Bandwidth Sum
 * @clk_flag: Flag determining whether fabric clock or the slave clock has to
 * be set. If clk_flag is set, fabric clock is set, else slave clock is set.
 */
static int msm_bus_fabric_update_clks(struct msm_bus_fabric_device *fabdev,
		struct msm_bus_inode_info *slave, int index,
		unsigned long curr_clk_hz, unsigned long req_clk_hz,
		unsigned long bwsum_hz, int clk_flag, int ctx,
		unsigned int cl_active_flag)
{
	int i, status = 0;
	unsigned long max_pclk = 0, rate;
	unsigned long *pclk = NULL;
	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
	struct nodeclk *nodeclk;

	/**
	 * Integration for clock rates is not required if context is not
	 * same as client's active-only flag
	 */
	if (ctx != cl_active_flag)
		goto skip_set_clks;

	/* Maximum for this gateway */
	for (i = 0; i <= slave->num_pnodes; i++) {
		if (i == index && (req_clk_hz < curr_clk_hz))
			continue;
		slave->pnode[i].sel_clk = &slave->pnode[i].clk[ctx];
		max_pclk = max(max_pclk, *slave->pnode[i].sel_clk);
	}

	*slave->link_info.sel_clk =
		max(max_pclk, max(bwsum_hz, req_clk_hz));
	/* Is this gateway or slave? */
	if (clk_flag && (!fabric->ahb)) {
		struct msm_bus_fabnodeinfo *fabgw = NULL;
		struct msm_bus_inode_info *info = NULL;
		/* Maximum of all gateways set at fabric */
		list_for_each_entry(fabgw, &fabric->gateways, list) {
			info = fabgw->info;
			if (!info)
				continue;
			info->link_info.sel_clk = &info->link_info.clk[ctx];
			max_pclk = max(max_pclk, *info->link_info.sel_clk);
		}
		MSM_BUS_DBG("max_pclk from gateways: %lu\n", max_pclk);

		/* Maximum of all slave clocks. */

		for (i = 0; i < fabric->pdata->len; i++) {
			if (fabric->pdata->info[i].gateway ||
				(fabric->pdata->info[i].id < SLAVE_ID_KEY))
				continue;
			info = radix_tree_lookup(&fabric->fab_tree,
				fabric->pdata->info[i].priv_id);
			if (!info)
				continue;
			info->link_info.sel_clk = &info->link_info.clk[ctx];
			max_pclk = max(max_pclk, *info->link_info.sel_clk);
		}


		MSM_BUS_DBG("max_pclk from slaves & gws: %lu\n", max_pclk);
		fabric->info.link_info.sel_clk =
			&fabric->info.link_info.clk[ctx];
		pclk = fabric->info.link_info.sel_clk;
	} else {
		slave->link_info.sel_clk = &slave->link_info.clk[ctx];
		pclk = slave->link_info.sel_clk;
	}


	*pclk = max(max_pclk, max(bwsum_hz, req_clk_hz));

	if (!fabric->pdata->rpm_enabled)
		goto skip_set_clks;

	if (clk_flag) {
		nodeclk = &fabric->info.nodeclk[ctx];
		if (nodeclk->clk) {
			MSM_BUS_DBG("clks: id: %d set-clk: %lu bwsum_hz:%lu\n",
			fabric->fabdev.id, *pclk, bwsum_hz);
			if (nodeclk->rate != *pclk) {
				nodeclk->dirty = true;
				nodeclk->rate = *pclk;
			}
			fabric->clk_dirty = true;
		}
	} else {
		nodeclk = &slave->nodeclk[ctx];
		if (nodeclk->clk) {
			rate = *pclk;
			MSM_BUS_DBG("AXI_clks: id: %d set-clk: %lu "
			"bwsum_hz: %lu\n" , slave->node_info->priv_id, rate,
			bwsum_hz);
			if (nodeclk->rate != rate) {
				nodeclk->dirty = true;
				nodeclk->rate = rate;
			}
		}
		if (!status && slave->memclk[ctx].clk) {
			rate = *slave->link_info.sel_clk;
			if (slave->memclk[ctx].rate != rate) {
				slave->memclk[ctx].rate = rate;
				slave->memclk[ctx].dirty = true;
			}
			slave->memclk[ctx].rate = rate;
			fabric->clk_dirty = true;
		}
	}
skip_set_clks:
	return status;
}

void msm_bus_fabric_update_bw(struct msm_bus_fabric_device *fabdev,
	struct msm_bus_inode_info *hop, struct msm_bus_inode_info *info,
	long int add_bw, int *master_tiers, int ctx)
{
	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);
	void *sel_cdata;
	int i;

	/* Temporarily stub out arbitration settings for msm8974 */
	if (machine_is_msm8974())
		return;

	sel_cdata = fabric->cdata[ctx];

	/* If it's an ahb fabric, don't calculate arb values */
	if (fabric->ahb) {
		MSM_BUS_DBG("AHB fabric, skipping bw calculation\n");
		return;
	}
	if (!add_bw) {
		MSM_BUS_DBG("No bandwidth delta. Skipping commit\n");
		return;
	}

	for (i = 0; i < NUM_CTX; i++)
		clk_prepare_enable(fabric->info.nodeclk[i].clk);

	fabdev->hw_algo.update_bw(hop, info, fabric->pdata, sel_cdata,
		master_tiers, add_bw);
	for (i = 0; i < NUM_CTX; i++)
		clk_disable_unprepare(fabric->info.nodeclk[i].clk);

	fabric->arb_dirty = true;
}

static int msm_bus_fabric_clk_set(int enable, struct msm_bus_inode_info *info)
{
	int i, status = 0;
	long rounded_rate;

	for (i = 0; i < NUM_CTX; i++) {
		if (info->nodeclk[i].dirty) {
			if (info->nodeclk[i].rate != 0) {
				rounded_rate = clk_round_rate(info->
					nodeclk[i].clk, info->nodeclk[i].rate);
				status = clk_set_rate(info->nodeclk[i].clk,
					rounded_rate);
				MSM_BUS_DBG("AXI: node: %d set_rate: %ld\n",
					info->node_info->id, rounded_rate);
			}

			if (enable && !(info->nodeclk[i].enable)) {
				clk_prepare_enable(info->nodeclk[i].clk);
				info->nodeclk[i].dirty = false;
				info->nodeclk[i].enable = true;
			} else if ((info->nodeclk[i].rate == 0) && (!enable)
				&& (info->nodeclk[i].enable)) {
				clk_disable_unprepare(info->nodeclk[i].clk);
				info->nodeclk[i].dirty = false;
				info->nodeclk[i].enable = false;
			}
		}

		if (info->memclk[i].dirty) {
			if (info->nodeclk[i].rate != 0) {
				rounded_rate = clk_round_rate(info->
					memclk[i].clk, info->memclk[i].rate);
				status = clk_set_rate(info->memclk[i].clk,
					rounded_rate);
				MSM_BUS_DBG("AXI: node: %d set_rate: %ld\n",
					info->node_info->id, rounded_rate);
			}

			if (enable && !(info->memclk[i].enable)) {
				clk_prepare_enable(info->memclk[i].clk);
				info->memclk[i].dirty = false;
				info->memclk[i].enable = true;
			} else if (info->memclk[i].rate == 0 && (!enable) &&
				(info->memclk[i].enable)) {
				clk_disable_unprepare(info->memclk[i].clk);
				info->memclk[i].dirty = false;
				info->memclk[i].enable = false;
			}
		}
	}

	return status;
}

/**
 * msm_bus_fabric_clk_commit() - Call clock enable and update clock
 * values.
*/
static int msm_bus_fabric_clk_commit(int enable, struct msm_bus_fabric *fabric)
{
	unsigned int i, nfound = 0, status = 0;
	struct msm_bus_inode_info *info[fabric->pdata->nslaves];

	if (fabric->clk_dirty == true)
		status = msm_bus_fabric_clk_set(enable, &fabric->info);

	if (status)
		MSM_BUS_WARN("Error setting clocks on fabric: %d\n",
			fabric->fabdev.id);

	nfound = radix_tree_gang_lookup_tag(&fabric->fab_tree, (void **)&info,
		fabric->fabdev.id, fabric->pdata->nslaves, CLK_NODE);
	if (nfound == 0) {
		MSM_BUS_DBG("No clock nodes found for fabric: %d\n",
			fabric->fabdev.id);
		goto out;
	}

	for (i = 0; i < nfound; i++) {
		status = msm_bus_fabric_clk_set(enable, info[i]);
		if (status)
			MSM_BUS_WARN("Error setting clocks for node: %d\n",
				info[i]->node_info->id);
	}

out:
	return status;
}

/**
 * msm_bus_fabric_hw_commit() - Commit the arbitration data to Hardware.
 * @fabric: Fabric for which the data should be committed
 * */
static int msm_bus_fabric_hw_commit(struct msm_bus_fabric_device *fabdev)
{
	int status = 0;
	struct msm_bus_fabric *fabric = to_msm_bus_fabric(fabdev);

	/*
	 * For a non-zero bandwidth request, clocks should be enabled before
	 * sending the arbitration data to RPM, but should be disabled only
	 * after commiting the data.
	 */
	status = msm_bus_fabric_clk_commit(ENABLE, fabric);
	if (status)
		MSM_BUS_DBG("Error setting clocks on fabric: %d\n",
			fabric->fabdev.id);

	if (!fabric->arb_dirty) {
		MSM_BUS_DBG("Not committing as fabric not arb_dirty\n");
		goto skip_arb;
	}

	status = fabdev->hw_algo.commit(fabric->pdata, fabric->hw_data,
		(void **)fabric->cdata);
	if (status)
		MSM_BUS_DBG("Error committing arb data for fabric: %d\n",
			fabric->fabdev.id);

	fabric->arb_dirty = false;
skip_arb:
	/*
	 * If the bandwidth request is 0 for a fabric, the clocks
	 * should be disabled after arbitration data is committed.
	 */
	status = msm_bus_fabric_clk_commit(DISABLE, fabric);
	if (status)
		MSM_BUS_WARN("Error disabling clocks on fabric: %d\n",
			fabric->fabdev.id);
	fabric->clk_dirty = false;
	return status;
}

{'fraction_non_alphanumeric': 0.14584191025113216, 'fraction_numerical': 0.0035336901331137643, 'mean_word_length': 4.024823306326495, 'pattern_counts': {'":': 0, '<': 46, '<?xml version=': 0, '>': 427, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4880587', 'n_tokens_mistral': 12343, 'n_tokens_neox': 11219, 'n_words': 2540}