PageRenderTime 131ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 1ms

/arch/arm/mach-fsm/npa.c

https://bitbucket.org/sammyz/iscream_thunderc-2.6.35-rebase
C | 1572 lines | 1166 code | 246 blank | 160 comment | 157 complexity | 08f28696f4476f1e8ac612cff21e3393 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
/* Copyright (c) 2009-2010, Code Aurora Forum. 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 *
 */

/*
 * Node Power Architecture (NPA) implementation.
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/string.h>
#include <linux/workqueue.h>
#include <linux/spinlock_types.h>

#include "npa.h"
#include "npa_resource.h"

#define NPA_STR_NPA_INTERNAL "NPA-Internal"
#define NPA_STR_USER_CALLBACK "User-Callback"

/* Resource lock could be called with NULL mutex, when only the container
 * is created and the node is not defined yet.
 */
#ifdef CONFIG_MSM_NPA_LOG
#define RESOURCE_LOCK(r) do { \
	BUG_ON(!r); \
	if ((r)->definition)\
		npa_log(NPA_LOG_MASK_LOCKS, r,\
			"NPA: Resource [%s] level [%u] locked [%p] at "\
			"line [%d] by process [%p]\n",\
			(r)->definition->name, (r)->level, (r)->resource_lock,\
			__LINE__, current);\
	if ((r)->resource_lock)\
		mutex_lock_nested((r)->resource_lock, (r)->level);\
	} \
	while (0)
#define RESOURCE_UNLOCK(r) do { \
	BUG_ON(!r); \
	if ((r)->definition)\
		npa_log(NPA_LOG_MASK_LOCKS, r,\
		"NPA: Resource [%s] level [%u] unlocked [%p] at "\
		"line [%d] by process [%p]\n",\
		(r)->definition->name, (r)->level, (r)->resource_lock,\
		__LINE__, current);\
	if ((r)->resource_lock)\
		mutex_unlock((r)->resource_lock);\
	} \
	while (0)
#else
#define RESOURCE_LOCK(r)  do { \
	BUG_ON(!r); \
	if ((r)->resource_lock) \
		mutex_lock_nested((r)->resource_lock, (r)->level) ;\
	} \
	while (0)
#define RESOURCE_UNLOCK(r) do { \
	BUG_ON(!r); \
	if ((r)->resource_lock) \
		mutex_unlock((r)->resource_lock); \
	} \
	while (0)
#endif

#ifdef CONFIG_MSM_NPA_LOG
int npa_log_mask;
EXPORT_SYMBOL(npa_log_mask);
char npa_log_resource_name[NPA_NAME_MAX] = {0};
EXPORT_SYMBOL(npa_log_resource_name);
int npa_log_reset;
EXPORT_SYMBOL(npa_log_reset);

module_param_named(log_mask, npa_log_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_PARM_DESC(npa_log_mask,
	"Specify NPA logging for any or all of "
	"resource, client states, events, lists, plugin or locks.");
module_param_string(log_resource_name, npa_log_resource_name,
		sizeof(npa_log_resource_name), S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_PARM_DESC(npa_log_resource_name,
	"Specify logging for a specific NPA resource.");
module_param_named(log_reset, npa_log_reset, int, S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_PARM_DESC(npa_log_reset, "Reset NPA module parameters.");
struct npa_resource *npa_log_resource;
#endif

/* Maps resource name to alias name.*/
struct npa_alias_list {
	struct list_head 	list;
	const char 		*alias;
	struct npa_resource 	*resource;
};

static LIST_HEAD(alias_list); 	/* List of aliases */
static LIST_HEAD(active_list); 	/* Resources defined and active */
static LIST_HEAD(waiting_list);	/* Resources pending definition or waiting
				   on dependencies. */
static DEFINE_RWLOCK(list_lock);/* RW lock for locking active and waiting
				   lists */
static struct workqueue_struct *npa_wq;

static struct npa_resource *__get_resource(const char *resource_name);
static void resource_creation_handler(void *data, unsigned int state,
		void *called_data, unsigned int value);
static void send_single_event(struct work_struct *work);
static void send_update_events(struct work_struct *work);

#ifdef CONFIG_MSM_NPA_LOG
void _npa_log(int log_mask, struct npa_resource *res, const char *fmt, ...)
{
	if (npa_log_reset) {
		npa_log_mask = 0;
		npa_log_resource = NULL;
		npa_log_resource_name[0] = 0;
		npa_log_reset = 0;
	}

	if (npa_log_resource_name[0] && !npa_log_resource) {
		npa_log_resource = __get_resource(npa_log_resource_name);
		if (npa_log_resource)
			pr_info("NPA: Logging for resource [%s]\n",
					npa_log_resource_name);
	}

	if (!npa_log_resource ||
			(npa_log_resource && (res == npa_log_resource)))
		if (log_mask & npa_log_mask) {
			va_list ap;
			va_start(ap, fmt);
			vprintk(fmt, ap);
			va_end(ap);
		}
}

void __print_resource(struct npa_resource *r)
{
	struct npa_client *client = NULL;
	struct npa_event *e = NULL;
	struct npa_alias_list *a = NULL;
	const char *rname = r->definition->name;

	if (!(npa_log_mask & NPA_LOG_MASK_RESOURCE))
		return;

	list_for_each_entry(a, &alias_list, list) {
		if (!strncmp(a->resource->definition->name,
			r->definition->name, NPA_NAME_MAX)) {
			pr_info("NPA: Resource [%s] Alias: [%s]\n",
					rname, a->alias);
		}
	}

	pr_info("NPA: Resource [%s] Units: [%s]\n",
			rname, r->definition->units);
	pr_info("NPA: Resource [%s] Node name: [%s]\n",
			rname, r->node->name);
	pr_info("NPA: Resource [%s] Level: [%u]\n",
			rname, r->level);

	list_for_each_entry(client, &r->clients, list) {
		pr_info("NPA: Resource [%s] client [%s: %u]\n",
				rname, client->name, ACTIVE_STATE(client));
	}

	list_for_each_entry(e, &r->events, list) {
		pr_info("NPA: Reource [%s] event [%s, %d]\n",
				rname, e->handler_name, e->type);
	}

	pr_info("NPA: Resource [%s] Active state: [%u]\n",
			rname, r->active_state);
	pr_info("NPA: Resource [%s] Active max: [%u]\n",
			rname, r->active_max);
	pr_info("NPA: Resource [%s] Active headroom: [%u]\n",
			rname, r->active_headroom);
}
EXPORT_SYMBOL(__print_resource);

void __print_resources(void)
{
	struct npa_resource *resource = NULL;

	if (!(npa_log_mask & NPA_LOG_MASK_RESOURCE))
		return;

	list_for_each_entry(resource, &active_list, list)
		__print_resource(resource);

	list_for_each_entry(resource, &waiting_list, list)
		__print_resource(resource);
}
EXPORT_SYMBOL(__print_resources);

void __print_client_states(struct npa_resource *resource)
{
	struct npa_client *client = NULL;

	if (!(npa_log_mask & NPA_LOG_MASK_LIST))
		return;

	list_for_each_entry(client, &resource->clients, list) {
		pr_info("NPA: Resource [%s] client [%s: %u]\n",
				resource->definition->name,
				client->name, ACTIVE_STATE(client));
	}
}
EXPORT_SYMBOL(__print_client_states);

void __print_aliases(void)
{
	struct npa_alias_list *a = NULL;

	if (npa_log_mask & NPA_LOG_MASK_LIST)
		return;

	list_for_each_entry(a, &alias_list, list) {
		pr_info("NPA: Alias[%s --> %s]\n",
				a->alias, a->resource->definition->name);
	}
}
EXPORT_SYMBOL(__print_aliases);
#endif

/* Returns the resource, if the name matches any element in the list.
 * NULL if not found.
 * @resource_name can be original resource name or an alias.
 */
static struct npa_resource *__get_resource(const char *resource_name)
{
	struct npa_alias_list *alias = NULL;
	struct npa_alias_list *temp = NULL;

	list_for_each_entry_safe(alias, temp, &alias_list, list) {
		if (!strncmp(resource_name, alias->alias, NPA_NAME_MAX))
			return alias->resource;
	}

	return NULL;
}

static int __is_active_resource(struct npa_resource *resource)
{
	struct npa_resource *res_itr = NULL;

	if (resource && !list_empty(&active_list)) {
		list_for_each_entry(res_itr, &active_list, list) {
			if (resource == res_itr)
				return 1;
		}
	}

	return 0;
}

static struct npa_resource *active_resource(const char *resource_name)
{
	struct npa_resource *resource = NULL;

	read_lock(&list_lock);
	resource = __get_resource(resource_name);
	if (resource)
		resource = __is_active_resource(resource) ? resource : NULL;
	read_unlock(&list_lock);

	return resource;
}

/* Creates a resource object with the definition provided. The created
 * resource is automatically added to the waiting list. create_resource can be
 * called with an node pointer or NULL, indicating the node has to be created.
 * If the node already exists, then the resource definition and the resource
 * objects will be replaced with the ones provided.
 * Node = NULL, resource_defn = valid, name = valid:
 * 	Create a new resource for the first time and create a node for it.
 * Node = valid, resource_defn = valid, name = valid:
 * 	Link a new node to an existing resource.
 */
static struct npa_resource *create_resource(struct npa_node_definition *node,
		struct npa_resource_definition *resource_defn,
		const char *name)
{
	struct npa_alias_list *new_alias = NULL;
	struct npa_resource *new_resource = NULL;
	struct npa_resource *resource = NULL;
	struct npa_node_definition *old_node = NULL;
	struct npa_node_definition *new_node = NULL;
	struct npa_resource_definition *old_defn = NULL;
	struct npa_resource_definition *new_defn = NULL;

	if (!node) {
		new_node = kzalloc(sizeof(struct npa_node_definition),
				GFP_KERNEL);
		new_defn = kzalloc(sizeof(struct npa_resource_definition),
				GFP_KERNEL);
		new_defn->name = name;
		new_node->resources = new_defn;
		new_node->resource_count = 1;
		new_node->dependencies = NULL;
		new_node->dependency_count = 0;
	} else {
		new_node = node;
		new_defn = resource_defn;
	}

	write_lock(&list_lock);
	resource = __get_resource(name);
	if (resource && !node)
		goto done;
	if (!resource) {
		new_resource = kzalloc(sizeof(struct npa_resource), GFP_ATOMIC);
		new_alias = kzalloc(sizeof(struct npa_alias_list), GFP_ATOMIC);
		new_alias->alias = name;
		new_alias->resource = new_resource;
		INIT_LIST_HEAD(&new_alias->list);

		new_resource->node = new_node;
		new_resource->definition = new_defn;
		INIT_LIST_HEAD(&new_resource->list);
		INIT_LIST_HEAD(&new_resource->clients);
		INIT_LIST_HEAD(&new_resource->events);
		INIT_LIST_HEAD(&new_resource->watermarks);
		INIT_WORK(&new_resource->work, send_update_events);

		list_add(&new_alias->list, &alias_list);
		list_add(&new_resource->list, &waiting_list);
		resource = new_resource;
	} else {
		/* Resource exists */
		old_node = resource->node;
		old_defn = resource->definition;
		/* Replace the alias name pointer to use new defn. */
		if (old_defn) {
			struct npa_alias_list *a = NULL;
			list_for_each_entry(a, &alias_list, list) {
				if (a->alias == old_defn->name)
					a->alias = new_defn->name;
			}
		}
		/* Replace the node and resource defn. */
		resource->node = new_node;
		resource->definition = new_defn;
	}
done:
	write_unlock(&list_lock);

	npa_log(NPA_LOG_MASK_RESOURCE, resource,
		"NPA: Resource [%s] definition created\n",
		resource->definition->name);

	if (resource != new_resource) {
		kfree(old_defn);
		kfree(old_node);
		if (!node) {
			kfree(new_node);
			kfree(new_defn);
		}
		kfree(new_resource);
		kfree(new_alias);
	}

	return resource;
}

/* Register callback function for a resource creation event
 * (NPA_EVENT_RESERVED1). The event object malloc'd in this function is
 * released is to be released in the handler. NPA_EVENT_RESERVED1 events
 * are use and throw events and should be removed from the list once notified.
 */
static int register_resource_event(struct npa_resource *resource,
		npa_cb_fn callback, void *data)
{
	struct npa_event *event = NULL;

	if (!callback)
		return 0; /* Nothing to wait for */

	event = kzalloc(sizeof(struct npa_event), GFP_KERNEL);

	INIT_LIST_HEAD(&event->list);
	INIT_WORK(&event->work, send_single_event);
	event->type = NPA_EVENT_RESERVED1;
	event->resource = resource;
	/* Helpful identification string to distinguish user callbacks
	 * from NPA internal resource completion events.
	 */
	if (callback == resource_creation_handler)
		event->handler_name = NPA_STR_NPA_INTERNAL;
	else
		event->handler_name = NPA_STR_USER_CALLBACK;
	event->callback = callback;
	event->user_data = data;

	RESOURCE_LOCK(resource);
	list_add(&event->list, &resource->events);
	RESOURCE_UNLOCK(resource);

	npa_log(NPA_LOG_MASK_RESOURCE, resource,
		"NPA: Registered for NPA_EVENT_RESERVED1 from resource [%s]\n",
		resource->definition->name);

	return 0;
}

/* Sends notification to this particular event object. This is mostly used
 * when the event is added to the resource.
 */
static void send_single_event(struct work_struct *work)
{
	struct npa_event *event = container_of(work, struct npa_event, work);
	struct npa_resource *resource = event->resource;
	struct npa_event_data event_data;

	/* Read the state when it is not being modified. */
	RESOURCE_LOCK(resource);
	event_data.resource_name = resource->definition->name;
	event_data.state = resource->active_state;
	event_data.headroom = resource->active_headroom;
	RESOURCE_UNLOCK(resource);

	npa_log(NPA_LOG_MASK_EVENT, resource,
		"NPA: Sending single event [%s] for resource [%s]\n",
		event->handler_name, resource->definition->name);

	event->callback(event->user_data, event->type, &event_data, 0);
}

/* Executes callbacks on all event objects. Callbacks are called in the
 * sequence of the event objects. This function does not entertain any
 * priority. If a callback blocks, it will affect all others that are
 * pending in the event list, as well as blocking the NPA work queue.
 */
static void send_update_events(struct work_struct *work)
{
	int expired = 0;
	struct npa_event *event = NULL;
	struct npa_event *temp = NULL;
	struct npa_resource *resource =
		container_of(work, struct npa_resource, work);
	struct npa_event_data event_data;

	npa_log(NPA_LOG_MASK_EVENT, resource,
		"NPA: Resource [%s] sending change events\n",
		resource->definition->name);

	/* Read the state when it is not being modified. */
	RESOURCE_LOCK(resource);
	event_data.resource_name = resource->definition->name;
	event_data.state = resource->active_state;
	event_data.headroom = resource->active_headroom;
	RESOURCE_UNLOCK(resource);

	list_for_each_entry_safe(event, temp, &resource->events, list) {
		expired = 0;
		switch (event->type) {
		case NPA_EVENT_RESERVED1:
			 /* Destroy after execution. */
			list_del(&event->list);
			expired = 1;
			break;
		case NPA_EVENT_CHANGE:
			break;
		default:
			BUG();
			break;
		}

		npa_log(NPA_LOG_MASK_EVENT, resource,
			"NPA: Resource [%s] sending event [%d] to [%s] "
			"with state [%u] headroom [%d] \n",
			resource->definition->name, event->type,
			event->handler_name, event_data.state,
			event_data.headroom);

		event->callback(event->user_data, event->type, &event_data, 0);
		if (expired)
			kfree(event);
	}

	npa_log(NPA_LOG_MASK_EVENT, resource,
		"NPA: Resource [%s] sending watermark events\n",
		resource->definition->name);

	/* Send the watermark events */
	list_for_each_entry_safe(event, temp, &resource->watermarks, list) {
		if (event_data.state <= event->lo_watermark) {

			npa_log(NPA_LOG_MASK_EVENT, resource,
				"NPA: Resource [%s] sending "
				"low watermark event to [%s] "
				"with state [%u] headroom [%d]\n",
				resource->definition->name,
				event->handler_name,
				event_data.state,
				event_data.headroom);

			event->callback(event->user_data,
					NPA_EVENT_LO_WATERMARK,
					&event_data, 0);
		}
		if (event_data.state >= event->hi_watermark) {

			npa_log(NPA_LOG_MASK_EVENT, resource,
				"NPA: Resource [%s] sending "
				"high watermark event to [%s] "
				"with state [%u] headroom [%d]\n",
				resource->definition->name,
				event->handler_name,
				event_data.state,
				event_data.headroom);

			event->callback(event->user_data,
					NPA_EVENT_HI_WATERMARK,
					&event_data, 0);
		}
	}
}

/* Schedules a work to notify all those registered for events of the change
 * in resource state.
 */
static void publish_resource_state(struct npa_resource *resource)
{
	npa_log(NPA_LOG_MASK_EVENT, resource,
		"NPA: Queueing work for resource [%s]\n",
		resource->definition->name);

	queue_work(npa_wq, &resource->work);
}

/* Activate this resource and all other resources that are part of this node.
 * Resources when created by default are put in waiting lists.
 * This function is to be called, when all the dependencies of this
 * resources are available and the resource is ready to be used.
 */
static int activate_node(struct npa_resource *resource)
{
	struct npa_resource_definition *def = NULL;
	struct npa_node_dependency *node_dep = NULL;
	struct npa_client dummy = {
		.type = NPA_CLIENT_REQUIRED,
		.name = NPA_STR_NPA_INTERNAL,
		.resource_name = resource->definition->name,
	};
	unsigned int count = 0;
	unsigned int node_level = 0;

	npa_log(NPA_LOG_MASK_RESOURCE, resource,
		"NPA: Resource [%s] being activated\n",
		resource->definition->name);


	/* Create clients for all the dependencies, so that the driver
	 * function can send the requests to these resources as well.
	 */
	RESOURCE_LOCK(resource);
	node_dep = resource->node->dependencies;
	count = resource->node->dependency_count;
	while (count) {
		struct npa_client *client =
			npa_create_sync_client(node_dep->name,
					resource->node->name,
					node_dep->client_type);
		BUG_ON((client == NULL) || IS_ERR(client));
		node_dep->handle = client;
		if (client->resource->level > node_level)
			node_level = client->resource->level;
		count--;
		node_dep++;
	}

	def = resource->node->resources;
	count = resource->node->resource_count;
	while (count) {
		write_lock(&list_lock);
		list_del(&def->resource->list); /* Remove from waiting list */
		list_add(&def->resource->list, &active_list);
		write_unlock(&list_lock);
		def->resource->active_state =
			def->resource->node->driver_fn(def->resource, &dummy,
					def->resource->requested_state);
		def->resource->active_headroom = def->resource->active_max -
					def->resource->active_state;
		def->resource->level = node_level + 1;
		count--;
		def++;
	}
	RESOURCE_UNLOCK(resource);

	/* Schedule a work to signal all dependencies that may depend
	 * on this resource.
	 */
	def = resource->node->resources;
	count = resource->node->resource_count;
	while (count) {
		publish_resource_state(def->resource);
		def++;
		count--;
	}
	return 0;
}

static void request_state(struct npa_resource *resource,
		struct npa_client *client, unsigned int state)
{
	unsigned int new_state;

	npa_log(NPA_LOG_MASK_CLIENT, resource,
		"NPA: Resource [%s] client [%s] requested state [%u]\n",
		resource->definition->name, client->name, state);

	RESOURCE_LOCK(resource);
	PENDING_STATE(client) = state;
	new_state = resource->active_plugin->update_fn(resource, client);
	ACTIVE_STATE(client) = PENDING_STATE(client);
	resource->requested_state = new_state;

	if (new_state > resource->active_max)
		new_state = resource->active_max;

	if ((resource->definition->attributes &
				NPA_RESOURCE_REPORT_ALL_REQS) ||
				new_state != resource->active_state) {
		resource->active_state =
			resource->node->driver_fn(resource, client,
					new_state);
		resource->active_headroom = resource->active_max -
						resource->active_state;
	}
	RESOURCE_UNLOCK(resource);

	npa_log(NPA_LOG_MASK_CLIENT, resource,
		"NPA: Resource [%s] state set to [%u]\n",
		resource->definition->name, resource->active_state);

	publish_resource_state(resource);
}

/* Return if any dependency of this resource is still not active.
 * Returns NULL if there are no pending dependencies.
 */
static struct npa_node_dependency *get_first_pending_dependency(
		struct npa_resource *resource)
{
	struct npa_node_dependency *dep = NULL;
	unsigned int count = 0;

	dep = resource->node->dependencies;
	count = resource->node->dependency_count;
	while (count) {
		if (!active_resource(dep->name))
			return dep;
		count--;
		dep++;
	}

	return NULL;
}

/* Callback function for NPA_EVENT_RESERVED1. This function registers
 * itself with the event queue for the first pending dependency of the
 * resource. If there are no dependency, then this activates the resource
 * as well.
 */
static void resource_creation_handler(void *data, unsigned int type,
		void *event_data, unsigned int value)
{
	struct npa_resource *resource = (struct npa_resource *)data;
	struct npa_node_dependency *dep = NULL;

	npa_log(NPA_LOG_MASK_RESOURCE, resource,
		"NPA: Resource [%s] creation handler called\n",
		resource->definition->name);

	dep = get_first_pending_dependency(resource);
	if (dep) {
		npa_log(NPA_LOG_MASK_RESOURCE, resource,
			"NPA: Resource [%s] has dependency on resource [%s]\n",
			resource->definition->name, dep->name);

		npa_resource_available(dep->name,
				resource_creation_handler, resource);
		return;
	}

	/* All dependencies are complete. Finish the resource completion. */
	activate_node(resource);
}

static void resource_destruction_handler(void *data, unsigned int value,
		void *event_data, unsigned int type)
{
	struct npa_resource *resource = data;

	BUG_ON(!list_empty(&resource->clients));

	if (!list_empty(&resource->events)) {
		struct npa_event *event = NULL;
		struct npa_event *temp = NULL;
		list_for_each_entry_safe(event, temp, &resource->events, list) {
			list_del(&event->list);

			npa_log(NPA_LOG_MASK_EVENT, resource,
				"NPA: Resource [%s] sending "
				"event [%d] to [%s]\n",
				resource->definition->name,
				event->type, event->handler_name);

			event->callback(event->user_data, value, NULL, 0);
			kfree(event);
		}
	}

	BUG_ON(!list_empty(&resource->watermarks));

	kfree(resource->definition);
	kfree(resource->node);
	kfree(resource);
}

/* Defines the node and individual resources.
 * All resources need to be defined by an external entity before the resource
 * can be used. This function checks for any pending dependency. This function
 * adds the callback to its event queue and when the resource is completely
 * defined, the callback is invoked.
 */
int npa_define_node(struct npa_node_definition *node,
			unsigned int initial_state[],
			npa_cb_fn callback, void *user_data)
{
	struct npa_resource *resource = NULL;
	struct npa_resource_definition *res_def = NULL;
	struct npa_node_dependency *node_dep = NULL;
	struct mutex *common_lock = NULL;
	unsigned int count = 0;
	int ret = 0;
	int idx = 0;

	if (!node || !node->name[0] || !node->resources || !node->driver_fn)
		return -EINVAL;

	npa_log(NPA_LOG_MASK_RESOURCE, NULL,
		"NPA: Defining node: [%s]\n", node->name);

	common_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
	mutex_init(common_lock);

	/* For each resource definition in this node definition, see if a
	 * npa_resource object already exists, if not create and add to the
	 * waiting list. We then check for dependencies and wait on those
	 * using the first resource object that we have. Once the dependencies
	 * are satisfied for this resource, we go ahead and activate all
	 * the resources of this node.
	 */
	res_def = node->resources;
	count = node->resource_count;
	while (count) {
		BUG_ON(!res_def->plugin);
		resource = create_resource(node, res_def, res_def->name);
		BUG_ON(__is_active_resource(resource));
		resource->definition = res_def;
		resource->node = node;
		resource->requested_state = initial_state[idx++];
		resource->active_max = res_def->max;
		resource->active_plugin = res_def->plugin;
		resource->resource_lock = common_lock;
		res_def->resource = resource;

		npa_log(NPA_LOG_MASK_RESOURCE, resource,
			"NPA: Defining resource: [%s]\n", res_def->name);

		count--;
		res_def++;
	}

	/* Get the first resource in the node definition */
	resource = node->resources[0].resource;

	/* Save the callback function to be called if the resource is ready.*/
	ret = register_resource_event(resource, callback, user_data);
	if (ret)
		return ret;

	node_dep = get_first_pending_dependency(resource);
	if (node_dep) {
		npa_log(NPA_LOG_MASK_RESOURCE, resource,
			"NPA: Resource [%s] has dependency on resource [%s]\n",
			resource->definition->name, node_dep->name);

		return npa_resource_available(node_dep->name,
				resource_creation_handler,
				(void *)resource);
	}

	/* Only executed when there are no pending dependencies of this node.*/
	activate_node(resource);

	return ret;
}
EXPORT_SYMBOL(npa_define_node);

/* Checks if the resource is available in the NPA active or waiting lists.
 * If not, then creates a dummy resource and adds it to the waiting list.
 * When the resource is available, the callback function is executed when
 * the events are fired.
 */
int npa_resource_available(const char *resource_name,
			npa_cb_fn callback, void *user_data)
{
	struct npa_resource *resource = NULL;

	if (!resource_name || !resource_name[0] || !callback)
		return -EINVAL;

	npa_log(NPA_LOG_MASK_RESOURCE, resource,
		"NPA: Checking if resource [%s] is available\n", resource_name);

	resource = create_resource(NULL, NULL, resource_name);
	read_lock(&list_lock);
	if (!__is_active_resource(resource)) {
		read_unlock(&list_lock);
		/* Register for NPA_EVENT_RESERVED1 event callback and exit */
		return register_resource_event(resource, callback, user_data);
	}
	read_unlock(&list_lock);

	npa_log(NPA_LOG_MASK_RESOURCE, resource,
		"NPA: Resource [%s] is available\n", resource_name);

	/* Resource is active. Call in the current context. */
	callback(user_data, resource->active_state, NULL, 0);

	return 0;
}
EXPORT_SYMBOL(npa_resource_available);

/* Define an alias name for a resource. */
int npa_alias_resource(const char *resource_name, const char *alias_name,
			npa_cb_fn callback, void *user_data)
{
	struct npa_resource *parent = NULL;
	struct npa_resource *resource = NULL;
	struct npa_alias_list *ralias = NULL;

	if (!resource_name || !resource_name[0] ||
			!alias_name || !alias_name[0] || !callback)
		return -EINVAL;

	npa_log(NPA_LOG_MASK_RESOURCE, NULL,
		"NPA: Creating alias [%s] for resource [%s]\n",
		alias_name, resource_name);

	ralias = kzalloc(sizeof(struct npa_alias_list), GFP_KERNEL);

	parent = create_resource(NULL, NULL, resource_name);

	write_lock(&list_lock);
	resource = __get_resource(alias_name);
	if (resource) {
		struct npa_alias_list *alias = NULL;
		list_for_each_entry(alias, &alias_list, list) {
			if (alias->resource == resource)
				alias->resource = parent;
		}
		list_del(&resource->list);
	} else {
		INIT_LIST_HEAD(&ralias->list);
		ralias->alias = alias_name;
		ralias->resource = parent;
		list_add(&ralias->list, &alias_list);
	}
	write_unlock(&list_lock);

	read_lock(&list_lock);
	if (__is_active_resource(parent)) {
		read_unlock(&list_lock);
		if (resource)
			resource_destruction_handler(resource,
				parent->active_state, NULL, 0);
		callback(user_data, 0, NULL, 0);
	} else {
		read_unlock(&list_lock);
		register_resource_event(parent, callback, user_data);
		if (resource)
			register_resource_event(parent,
				resource_destruction_handler, resource);
	}

#ifdef CONFIG_MSM_NPA_LOG
	/* If we were looking to log an alias, then re-acquire the resource* */
	npa_log_resource = __get_resource(npa_log_resource_name);
#endif

	npa_log(NPA_LOG_MASK_RESOURCE, parent,
		"NPA: Alias [%s] created for resource [%s]\n",
		alias_name, parent->definition->name);

	return 0;
}
EXPORT_SYMBOL(npa_alias_resource);

/* Update the resource state with this state. The driver function is expected
 * to update the underlying h/w state or whatever this resource represents.
 * This function sends update events to the listeners.
 */
int npa_assign_resource_state(struct npa_resource *resource,
				unsigned int state)
{
	npa_log(NPA_LOG_MASK_RESOURCE, resource,
		"NPA: Resource [%s] is assigned state [%u]\n",
		resource->definition->name, state);

	resource->active_state = state;
	resource->active_headroom = resource->active_max - state;
	publish_resource_state(resource);

	return 0;
}
EXPORT_SYMBOL(npa_assign_resource_state);

/* Create a sync client for this resource.
 * Returns an handle to the NPA client object if the resource is active,
 * error condition otherwise.
 */
struct npa_client *npa_create_sync_client(const char *resource_name,
			const char *client_name, enum npa_client_type type)
{
	struct npa_client *client = NULL;
	struct npa_resource *resource = NULL;
	int flag = 0;

	if (!resource_name || !resource_name[0] ||
			!client_name || !client_name[0])
		return ERR_PTR(-EINVAL);

	resource = active_resource(resource_name);
	if (!resource) {
		/* Clients for pending resources are not allowed. */
		npa_log(NPA_LOG_MASK_CLIENT, resource,
			"NPA: Resource [%s] requested by "
			"client [%s] not active\n",
			resource_name, client_name);
		return ERR_PTR(-ENODEV);
	}

	RESOURCE_LOCK(resource);
	if (!(type & resource->active_plugin->supported_clients))
		flag = -1;
	if ((resource->definition->attributes &
				NPA_RESOURCE_SINGLE_CLIENT) &&
			!list_empty(&resource->clients))
		flag = -2;
	RESOURCE_UNLOCK(resource);

	if (flag == -1) {
		npa_log(NPA_LOG_MASK_CLIENT, resource,
			"NPA: Client [%s, %d] is not "
			"supported by resource [%s]\n",
			client_name, type, resource_name);
		return ERR_PTR(-EINVAL);
	}

	if (flag == -2) {
		npa_log(NPA_LOG_MASK_CLIENT, resource,
			"NPA: Resource [%s] supports only a single"
			"client. Client [%s] create failed\n",
			resource_name, client_name);
		return ERR_PTR(-EBUSY);
	}

	npa_log(NPA_LOG_MASK_CLIENT, resource,
		"NPA: Creating sync client [%s] for "
		"resource [%s]\n", client_name, resource_name);

	client = kzalloc(sizeof(struct npa_client), GFP_KERNEL);
	INIT_LIST_HEAD(&client->list);
	client->name = client_name;
	client->resource_name = resource_name;
	client->resource = resource;
	client->type = type;
	RESOURCE_LOCK(resource);
	list_add(&client->list, &resource->clients);
	if (resource->active_plugin->create_client_fn)
		resource->active_plugin->create_client_fn(client);
	RESOURCE_UNLOCK(resource);

	npa_log(NPA_LOG_MASK_CLIENT, resource,
		"NPA: Client [%s, %d] for resource [%s] created\n",
		client_name, type, resource_name);

	return client;
}
EXPORT_SYMBOL(npa_create_sync_client);

/* Removes a client from a resource. */
void npa_destroy_client(struct npa_client *client)
{
	struct npa_resource *resource = NULL;

	if (client) {
		npa_log(NPA_LOG_MASK_CLIENT, client->resource,
			"NPA: Resource [%s] client [%s, %d] destroyed\n",
			client->resource->definition->name,
			client->name, client->type);

		resource = client->resource;
		RESOURCE_LOCK(resource);
		if (resource->active_plugin->destroy_client_fn)
			resource->active_plugin->destroy_client_fn(client);
		list_del(&client->list);
		RESOURCE_UNLOCK(resource);
		kfree(client);
	}
}
EXPORT_SYMBOL(npa_destroy_client);

/* Issues a required workflow request call to the client. If the update function
 * returns a state different from the current resource state, then the resource
 * driver function is called in the same context to update the resource and the
 * update events will be scheduled to fire.
 */
int npa_issue_required_request(struct npa_client *client, unsigned int state)
{
	if (client->type != NPA_CLIENT_REQUIRED)
		return -EINVAL;

	npa_log(NPA_LOG_MASK_CLIENT, client->resource,
		"NPA: Resource [%s] received request from client [%s, %u]\n",
		client->resource->definition->name,
		client->name, state);

	request_state(client->resource, client, state);

	return 0;
}
EXPORT_SYMBOL(npa_issue_required_request);

int npa_modify_required_request(struct npa_client *client, int delta)
{
	if (client->type != NPA_CLIENT_REQUIRED)
		return -EINVAL;

	/* Check if the active state of the client is non-zero. */
	if (!ACTIVE_STATE(client))
		return -EINVAL;

	npa_log(NPA_LOG_MASK_CLIENT, client->resource,
		"NPA: Resource [%s] modify request by client [%s, %d]\n",
		client->resource->definition->name, client->name, delta);

	request_state(client->resource, client, ACTIVE_STATE(client) + delta);

	return 0;
}
EXPORT_SYMBOL(npa_modify_required_request);

int npa_issue_impulse_request(struct npa_client *client)
{
	if (client->type != NPA_CLIENT_IMPULSE)
		return -EINVAL;

	npa_log(NPA_LOG_MASK_CLIENT, client->resource,
		"NPA: Resource [%s] impulse request by client [%s]\n",
		client->resource->definition->name, client->name);

	request_state(client->resource, client,
			client->resource->definition->max);

	return 0;
}
EXPORT_SYMBOL(npa_issue_impulse_request);

int npa_issue_isoc_request(struct npa_client *client, unsigned int duration,
		unsigned int level)
{
	if (client->type != NPA_CLIENT_ISOCHRONOUS)
		return -EINVAL;

	npa_log(NPA_LOG_MASK_CLIENT, client->resource,
		"NPA: Resource [%s] isoc request by "
		"client [%s] with duration [%u], level [%u]\n",
		client->resource->definition->name,
		client->name, duration, level);

	/* TODO: Update work struct with time values */
	client->work[PENDING_REQUEST].state = level;
	request_state(client->resource, client, PENDING_STATE(client));

	return 0;
}
EXPORT_SYMBOL(npa_issue_isoc_request);

int npa_issue_limit_max_request(struct npa_client *client, unsigned int max)
{
	int val = max;
	struct npa_resource *resource = client->resource;
	struct npa_client *cl_itr = NULL;

	if (client->type != NPA_CLIENT_LIMIT_MAX)
		return -EINVAL;

	npa_log(NPA_LOG_MASK_CLIENT, client->resource,
		"NPA: Resource [%s] limit max [%u] request by client [%s] \n",
		client->resource->definition->name, max, client->name);

	RESOURCE_LOCK(resource);
	list_for_each_entry(cl_itr, &resource->clients, list) {
		if ((cl_itr->type & NPA_CLIENT_LIMIT_MAX))
			if (ACTIVE_STATE(cl_itr) &&
					(ACTIVE_STATE(cl_itr) < val))
				val = ACTIVE_STATE(cl_itr);
	}
	resource->active_max = val;
	RESOURCE_UNLOCK(resource);

	/* Issue the request to the update_fn and limit the current state if
	 * needed and call the driver fn. Send events if resource state is
	 * changed.
	 */
	request_state(client->resource, client, max);

	return 0;
}
EXPORT_SYMBOL(npa_issue_limit_max_request);

void npa_complete_request(struct npa_client *client)
{
	npa_log(NPA_LOG_MASK_CLIENT, client->resource,
		"NPA: Client [%s] completed request\n", client->name);

	/* Complete this request. */
	request_state(client->resource, client, 0);
}
EXPORT_SYMBOL(npa_complete_request);

void npa_cancel_request(struct npa_client *client)
{
	npa_log(NPA_LOG_MASK_CLIENT, client->resource,
		"NPA: Client [%s] cancelled request\n", client->name);

	/* TODO: In future flush any history for this client that may have
	 * been captured. And complete this request.
	 */
	request_state(client->resource, client, 0);
}
EXPORT_SYMBOL(npa_cancel_request);

unsigned int npa_get_state(struct npa_client *client)
{
	return client->resource->active_state;
}
EXPORT_SYMBOL(npa_get_state);

/* Create an event object and attach to the resource event list.
 * This function expects that the resource be active for the event to
 * be registered with the resource.
 */
struct npa_event *npa_create_change_event(const char *resource_name,
		const char *handler_name, npa_cb_fn event_cb, void *user_data)
{
	struct npa_event *event = NULL;
	struct npa_resource *resource = NULL;

	if (!resource_name || !resource_name[0] ||
			!handler_name || !event_cb)
		return ERR_PTR(-EINVAL);

	resource = active_resource(resource_name);
	if (!resource)
		return ERR_PTR(-ENODEV);

	event = kzalloc(sizeof(struct npa_event), GFP_KERNEL);
	INIT_LIST_HEAD(&event->list);
	INIT_WORK(&event->work, send_single_event);
	event->type = NPA_EVENT_CHANGE;
	event->handler_name = handler_name;
	event->resource = resource;
	event->callback = event_cb;
	event->user_data = user_data;

	RESOURCE_LOCK(resource);
	list_add(&event->list, &resource->events);
	RESOURCE_UNLOCK(resource);

	npa_log(NPA_LOG_MASK_EVENT, resource,
		"NPA: Resource [%s] adding change event for [%s]\n",
		resource->definition->name, handler_name);

	/* Callback with the current resource state only for this event */
	queue_work(npa_wq, &event->work);

	return event;
}
EXPORT_SYMBOL(npa_create_change_event);

struct npa_event *npa_create_watermark_event(const char *resource_name,
		const char *handler_name, npa_cb_fn event_cb, void *user_data)
{
	struct npa_event *event = NULL;
	struct npa_resource *resource = NULL;

	if (!resource_name || !resource_name[0] ||
			!handler_name || !event_cb)
		return ERR_PTR(-EINVAL);

	resource = active_resource(resource_name);
	if (!resource)
		return ERR_PTR(-ENODEV);

	event = kzalloc(sizeof(struct npa_event), GFP_KERNEL);
	INIT_LIST_HEAD(&event->list);
	INIT_WORK(&event->work, send_single_event);
	event->type = NPA_EVENT_LO_WATERMARK;
	event->handler_name = handler_name;
	event->resource = resource;
	event->callback = event_cb;
	event->user_data = user_data;

	RESOURCE_LOCK(resource);
	list_add(&event->list, &resource->watermarks);
	RESOURCE_UNLOCK(resource);

	npa_log(NPA_LOG_MASK_EVENT, resource,
		"NPA: Resource [%s] adding watermark events for [%s]\n",
		resource->definition->name, handler_name);

	return event;
}
EXPORT_SYMBOL(npa_create_watermark_event);

/* Removes an event from the event queue of this resource. */
void npa_destroy_event(struct npa_event *event)
{
	/* TODO BUG: Possible race condition with send-events(), event
	 * list being modified outside.
	 */
	RESOURCE_LOCK(event->resource);
	list_del(&event->list);
	RESOURCE_UNLOCK(event->resource);

	npa_log(NPA_LOG_MASK_EVENT, event->resource,
		"NPA: Resource [%s] event [%s] destroyed\n",
		event->resource->definition->name, event->handler_name);

	kfree(event);

}
EXPORT_SYMBOL(npa_destroy_event);

/* Set watermarks for this event. The events are fired only if the resource
 * state lie outside the watermarks.
 */
int npa_set_event_watermarks(struct npa_event *event,
				int lo_watermark, int hi_watermark)
{
	unsigned int state;
	int publish_event = 0;

	if (!event)
		return -EINVAL;

	RESOURCE_LOCK(event->resource);
	state = event->resource->active_state;
	event->lo_watermark = lo_watermark;
	event->hi_watermark = hi_watermark;
	if (state <= event->lo_watermark) {
		event->type = NPA_EVENT_LO_WATERMARK;
		publish_event = 1;
	}
	if (state >= event->hi_watermark) {
		event->type = NPA_EVENT_HI_WATERMARK;
		publish_event = 1;
	}
	RESOURCE_UNLOCK(event->resource);

	npa_log(NPA_LOG_MASK_EVENT, event->resource,
		"NPA: Resource [%s] event [%s] watermarks [%d, %d] set\n",
		event->resource->definition->name, event->handler_name,
		lo_watermark, hi_watermark);

	if (publish_event)
		queue_work(npa_wq, &event->work);

	return 0;
}
EXPORT_SYMBOL(npa_set_event_watermarks);

/* Pre-defined NPA update functions.
 * Currently we only consider "required" client requests.
 */
static unsigned int binary_update(struct npa_resource *resource,
					struct npa_client *client)
{
	struct npa_client *cl_itr = NULL;
	unsigned int val = PENDING_STATE(client);

	__print_client_states(resource);

	if (!(client->type & NPA_CLIENT_REQUIRED))
		return resource->active_state;

	if ((resource->active_state == ACTIVE_STATE(client)) &&
		(ACTIVE_STATE(client) != val))
		return val;

	list_for_each_entry(cl_itr, &resource->clients, list) {
		if ((cl_itr->type & NPA_CLIENT_REQUIRED) && (cl_itr != client))
				val |= ACTIVE_STATE(cl_itr);
	}

	npa_log(NPA_LOG_MASK_PLUGIN, resource,
		"NPA: Binary plugin: Calculated [%u] for resource [%s] "
		"client [%s]\n",
		val, resource->definition->name, client->name);

	return val;
}

static unsigned int min_update(struct npa_resource *resource,
					struct npa_client *client)
{
	struct npa_client *cl_itr = NULL;
	unsigned int val = PENDING_STATE(client);

	__print_client_states(resource);

	if (!(client->type & NPA_CLIENT_REQUIRED))
		return resource->active_state;

	if (val && (resource->active_state == ACTIVE_STATE(client)) &&
		(val <= ACTIVE_STATE(client))) {

		npa_log(NPA_LOG_MASK_PLUGIN, resource,
			"NPA: Min plugin: Current request [%u] is min for "
			"resource [%s]\n",
			val, resource->definition->name);

		return val;
	}

	list_for_each_entry(cl_itr, &resource->clients, list) {
		if (!(cl_itr->type & NPA_CLIENT_REQUIRED))
			continue;
		if ((cl_itr != client) && ACTIVE_STATE(cl_itr)) {
			if (!val)
				val = ACTIVE_STATE(cl_itr);
			if (ACTIVE_STATE(cl_itr) < val)
				val = ACTIVE_STATE(cl_itr);
		}
	}

	npa_log(NPA_LOG_MASK_PLUGIN, resource,
		"NPA: Min plugin: Calculated [%u] for resource [%s] "
		"client [%s]\n",
		val, resource->definition->name, client->name);

	return val;
}

static unsigned int max_update(struct npa_resource *resource,
					struct npa_client *client)
{
	struct npa_client *cl_itr = NULL;
	unsigned int val = PENDING_STATE(client);

	__print_client_states(resource);

	if (!(client->type & NPA_CLIENT_REQUIRED))
		return resource->active_state;

	if ((val != 0) &&
		(resource->active_state == ACTIVE_STATE(client)) &&
		(val >= ACTIVE_STATE(client))) {

		npa_log(NPA_LOG_MASK_PLUGIN, resource,
			"NPA: Max plugin: Current request [%u] is max for "
			"resource [%s]\n",
			val, resource->definition->name);

		return val;
	}

	list_for_each_entry(cl_itr, &resource->clients, list) {
		if (!(cl_itr->type & NPA_CLIENT_REQUIRED))
			continue;
		if ((cl_itr != client) && ACTIVE_STATE(cl_itr)) {
			if (!val)
				val = ACTIVE_STATE(cl_itr);
			if (ACTIVE_STATE(cl_itr) > val)
				val = ACTIVE_STATE(cl_itr);
		}
	}

	npa_log(NPA_LOG_MASK_PLUGIN, resource,
		"NPA: Max plugin: Calculated [%u] for resource [%s] "
		"client [%s]\n",
		val, resource->definition->name, client->name);

	return val;
}

static unsigned int sum_update(struct npa_resource *resource,
					struct npa_client *client)
{
	unsigned int val = resource->active_state;

	__print_client_states(resource);

	if (!(client->type & NPA_CLIENT_REQUIRED))
		return resource->active_state;

	val -= ACTIVE_STATE(client);
	val += PENDING_STATE(client);

	npa_log(NPA_LOG_MASK_PLUGIN, resource,
		"NPA: Sum plugin: Calculated [%u] for resource [%s] "
		"client [%s]\n",
		val, resource->definition->name, client->name);

	return val;
}

static unsigned int always_update(struct npa_resource *resource,
					struct npa_client *client)
{
	unsigned int val = 1;

	__print_client_states(resource);

	if (!(client->type & NPA_CLIENT_REQUIRED))
		return resource->active_state;

	npa_log(NPA_LOG_MASK_PLUGIN, resource,
		"NPA: Always on plugin: Calculated [%u] for resource [%s] "
		"client [%s]\n",
		val, resource->definition->name, client->name);

	return val;
}

const struct npa_resource_plugin_ops npa_binary_plugin = {
	.update_fn 		= binary_update,
	.supported_clients 	= NPA_CLIENT_REQUIRED,
	.create_client_fn 	= NULL,
	.destroy_client_fn	= NULL,
};
EXPORT_SYMBOL(npa_binary_plugin);

const struct npa_resource_plugin_ops npa_min_plugin = {
	.update_fn 		= min_update,
	.supported_clients 	= NPA_CLIENT_REQUIRED,
	.create_client_fn 	= NULL,
	.destroy_client_fn	= NULL,
};
EXPORT_SYMBOL(npa_min_plugin);

const struct npa_resource_plugin_ops npa_max_plugin = {
	.update_fn 		= max_update,
	.supported_clients 	= NPA_CLIENT_REQUIRED,
	.create_client_fn 	= NULL,
	.destroy_client_fn	= NULL,
};
EXPORT_SYMBOL(npa_max_plugin);

const struct npa_resource_plugin_ops npa_sum_plugin = {
	.update_fn 		= sum_update,
	.supported_clients 	= NPA_CLIENT_REQUIRED,
	.create_client_fn 	= NULL,
	.destroy_client_fn	= NULL,
};
EXPORT_SYMBOL(npa_sum_plugin);

const struct npa_resource_plugin_ops npa_always_on_plugin = {
	.update_fn 		= always_update,
	.supported_clients 	= NPA_CLIENT_REQUIRED,
	.create_client_fn 	= NULL,
	.destroy_client_fn	= NULL,
};
EXPORT_SYMBOL(npa_always_on_plugin);

/* NPA Init function. */
static int npa_init(void)
{
	npa_wq = create_workqueue("npa");
	BUG_ON(!npa_wq);

	pr_info("NPA: Init done.\n");

	return 0;
}

#ifdef CONFIG_MSM_NPA_DEBUG
/* ** DEBUG use only **
 * NPA reset function. Releases all resources and resource states.
 * This function should be called only when there all the clients and events
 * are destroyed. No request should be made during this call.
 */
void npa_reset(void)
{
	struct npa_alias_list *a = NULL;
	struct npa_alias_list *b = NULL;
	struct npa_alias_list *temp_a = NULL;
	struct npa_event *e = NULL;
	struct npa_event *temp_e = NULL;
	struct npa_client *c = NULL;
	struct npa_client *temp_c = NULL;
	struct npa_resource *resource = NULL;
	struct npa_resource_definition *def = NULL;
	unsigned int count = 0;

	write_lock(&list_lock);
	list_for_each_entry_safe(a, temp_a, &alias_list, list) {
		list_del(&a->list);
		kfree(a);
		if (!resource)
			continue;
		resource = a->resource;
		list_for_each_entry_safe(e, temp_e, &resource->events, list) {
			list_del(&e->list);
			kfree(e);
		}
		list_for_each_entry_safe(e, temp_e, &resource->watermarks,
				list){
			list_del(&e->list);
			kfree(e);
		}
		list_for_each_entry_safe(c, temp_c, &resource->clients, list) {
			list_del(&c->list);
			kfree(c);
		}
		if (!__is_active_resource(resource)) {
			kfree(resource->definition);
			kfree(resource->node);
		}
		list_for_each_entry(b, &alias_list, list) {
			if (b->resource == resource)
				b->resource = NULL;
		}
		resource->definition->resource = NULL;
		kfree(resource->resource_lock);
		def = resource->node->resources;
		count = resource->node->resource_count;
		while (count) {
			if (def->resource)
				def->resource->resource_lock = NULL;
			count--;
			def++;
		}
		kfree(resource);
	}
	write_unlock(&list_lock);
}
EXPORT_SYMBOL(npa_reset);
#endif

/* NPA needs to be made available before the resources. Should be way up in the
 * initialization list of the kernel.
 */
postcore_initcall(npa_init);