summaryrefslogtreecommitdiffstats
path: root/arch/frv/kernel/entry.S
AgeCommit message (Expand)Author
2012-06-01FRV: Optimise the system call exit path in entry.S [ver #2]David Howells
2012-06-01FRV: Shrink TIF_WORK_MASK [ver #2]David Howells
2012-06-01FRV: Prevent syscall exit tracing and notify_resume at end of kernel exceptionsDavid Howells
2011-08-26All Arch: remove linkage for sys_nfsservctl system callNeilBrown
2011-05-28ns: Wire up the setns system callEric W. Biederman
2010-03-03Rename special text sections in arch/frv from .text.XXX to .text..XXX.Denys Vlasenko
2009-09-21perf: Do the big rename: Performance Counters -> Performance EventsIngo Molnar
2009-06-30FRV: Wire up new syscallsDavid Howells
2009-06-11FRV: Implement new-style ptraceDavid Howells
2009-06-11FRV: Don't turn on TIF_SYSCALL_TRACE unconditionally in syscall prologueDavid Howells
2009-04-27FRV: Wire up new syscallsDavid Howells
2008-08-01FRV: Wire up new system callsDavid Howells
2008-04-10FRV: Add support for emulation of userspace atomic ops [try #2]David Howells
2008-02-20FRV: Change the timerfd syscalls to be the same as i386David Howells
2008-02-05timerfd: fix remaining architecturesAndrew Morton
2008-02-03move frv docs one level upAdrian Bunk
2007-11-29FRV: arrange things such that BRA can reach from the trap tableDavid Howells
2007-08-11FRV: connect up fallocateDavid Howells
2007-07-16FRV: Connect up new syscallsDavid Howells
2007-05-08FRV: Miscellaneous fixesDavid Howells
2006-07-10[PATCH] FRV: Introduce asm-offsets for FRV archDavid Howells
2006-06-30Remove obsolete #include <linux/config.h>Jörn Engel
2006-06-23[PATCH] frv: wrong syscallAl Viro
2006-04-11[PATCH] frv: define MMU mode specific syscalls as 'cond_syscall' and clean up...Hyok S. Choi
2006-02-14[PATCH] FRV: Use virtual interrupt disablementDavid Howells
2006-02-14[PATCH] FRV: Miscellaneous fixesDavid Howells
2006-01-06[PATCH] frv: fix signal handlingDavid Howells
2005-04-16Linux-2.6.12-rc2Linus Torvalds
30'>230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
/*
 *	klist.c - Routines for manipulating klists.
 *
 *
 *	This klist interface provides a couple of structures that wrap around 
 *	struct list_head to provide explicit list "head" (struct klist) and 
 *	list "node" (struct klist_node) objects. For struct klist, a spinlock
 *	is included that protects access to the actual list itself. struct 
 *	klist_node provides a pointer to the klist that owns it and a kref
 *	reference count that indicates the number of current users of that node
 *	in the list.
 *
 *	The entire point is to provide an interface for iterating over a list
 *	that is safe and allows for modification of the list during the
 *	iteration (e.g. insertion and removal), including modification of the
 *	current node on the list.
 *
 *	It works using a 3rd object type - struct klist_iter - that is declared
 *	and initialized before an iteration. klist_next() is used to acquire the
 *	next element in the list. It returns NULL if there are no more items.
 *	Internally, that routine takes the klist's lock, decrements the reference
 *	count of the previous klist_node and increments the count of the next
 *	klist_node. It then drops the lock and returns.
 *
 *	There are primitives for adding and removing nodes to/from a klist. 
 *	When deleting, klist_del() will simply decrement the reference count. 
 *	Only when the count goes to 0 is the node removed from the list. 
 *	klist_remove() will try to delete the node from the list and block
 *	until it is actually removed. This is useful for objects (like devices)
 *	that have been removed from the system and must be freed (but must wait
 *	until all accessors have finished).
 *
 *	Copyright (C) 2005 Patrick Mochel
 *
 *	This file is released under the GPL v2.
 */

#include <linux/klist.h>
#include <linux/module.h>


/**
 *	klist_init - Initialize a klist structure. 
 *	@k:	The klist we're initializing.
 *	@get:	The get function for the embedding object (NULL if none)
 *	@put:	The put function for the embedding object (NULL if none)
 *
 * Initialises the klist structure.  If the klist_node structures are
 * going to be embedded in refcounted objects (necessary for safe
 * deletion) then the get/put arguments are used to initialise
 * functions that take and release references on the embedding
 * objects.
 */

void klist_init(struct klist * k, void (*get)(struct klist_node *),
		void (*put)(struct klist_node *))
{
	INIT_LIST_HEAD(&k->k_list);
	spin_lock_init(&k->k_lock);
	k->get = get;
	k->put = put;
}

EXPORT_SYMBOL_GPL(klist_init);


static void add_head(struct klist * k, struct klist_node * n)
{
	spin_lock(&k->k_lock);
	list_add(&n->n_node, &k->k_list);
	spin_unlock(&k->k_lock);
}

static void add_tail(struct klist * k, struct klist_node * n)
{
	spin_lock(&k->k_lock);
	list_add_tail(&n->n_node, &k->k_list);
	spin_unlock(&k->k_lock);
}


static void klist_node_init(struct klist * k, struct klist_node * n)
{
	INIT_LIST_HEAD(&n->n_node);
	init_completion(&n->n_removed);
	kref_init(&n->n_ref);
	n->n_klist = k;
	if (k->get)
		k->get(n);
}


/**
 *	klist_add_head - Initialize a klist_node and add it to front.
 *	@n:	node we're adding.
 *	@k:	klist it's going on.
 */

void klist_add_head(struct klist_node * n, struct klist * k)
{
	klist_node_init(k, n);
	add_head(k, n);
}

EXPORT_SYMBOL_GPL(klist_add_head);


/**
 *	klist_add_tail - Initialize a klist_node and add it to back.
 *	@n:	node we're adding.
 *	@k:	klist it's going on.
 */

void klist_add_tail(struct klist_node * n, struct klist * k)
{
	klist_node_init(k, n);
	add_tail(k, n);
}

EXPORT_SYMBOL_GPL(klist_add_tail);


static void klist_release(struct kref * kref)
{
	struct klist_node * n = container_of(kref, struct klist_node, n_ref);

	list_del(&n->n_node);
	complete(&n->n_removed);
	n->n_klist = NULL;
}

static int klist_dec_and_del(struct klist_node * n)
{
	return kref_put(&n->n_ref, klist_release);
}


/**
 *	klist_del - Decrement the reference count of node and try to remove.
 *	@n:	node we're deleting.
 */

void klist_del(struct klist_node * n)
{
	struct klist * k = n->n_klist;
	void (*put)(struct klist_node *) = k->put;

	spin_lock(&k->k_lock);
	if (!klist_dec_and_del(n))
		put = NULL;
	spin_unlock(&k->k_lock);
	if (put)
		put(n);
}

EXPORT_SYMBOL_GPL(klist_del);


/**
 *	klist_remove - Decrement the refcount of node and wait for it to go away.
 *	@n:	node we're removing.
 */

void klist_remove(struct klist_node * n)
{
	klist_del(n);
	wait_for_completion(&n->n_removed);
}

EXPORT_SYMBOL_GPL(klist_remove);


/**
 *	klist_node_attached - Say whether a node is bound to a list or not.
 *	@n:	Node that we're testing.
 */

int klist_node_attached(struct klist_node * n)
{
	return (n->n_klist != NULL);
}

EXPORT_SYMBOL_GPL(klist_node_attached);


/**
 *	klist_iter_init_node - Initialize a klist_iter structure.
 *	@k:	klist we're iterating.
 *	@i:	klist_iter we're filling.
 *	@n:	node to start with.
 *
 *	Similar to klist_iter_init(), but starts the action off with @n, 
 *	instead of with the list head.
 */

void klist_iter_init_node(struct klist * k, struct klist_iter * i, struct klist_node * n)
{
	i->i_klist = k;
	i->i_head = &k->k_list;
	i->i_cur = n;
	if (n)
		kref_get(&n->n_ref);
}

EXPORT_SYMBOL_GPL(klist_iter_init_node);


/**
 *	klist_iter_init - Iniitalize a klist_iter structure.
 *	@k:	klist we're iterating.
 *	@i:	klist_iter structure we're filling.
 *
 *	Similar to klist_iter_init_node(), but start with the list head.
 */

void klist_iter_init(struct klist * k, struct klist_iter * i)
{
	klist_iter_init_node(k, i, NULL);
}

EXPORT_SYMBOL_GPL(klist_iter_init);


/**
 *	klist_iter_exit - Finish a list iteration.
 *	@i:	Iterator structure.
 *
 *	Must be called when done iterating over list, as it decrements the 
 *	refcount of the current node. Necessary in case iteration exited before
 *	the end of the list was reached, and always good form.
 */

void klist_iter_exit(struct klist_iter * i)
{
	if (i->i_cur) {
		klist_del(i->i_cur);
		i->i_cur = NULL;
	}
}

EXPORT_SYMBOL_GPL(klist_iter_exit);


static struct klist_node * to_klist_node(struct list_head * n)
{
	return container_of(n, struct klist_node, n_node);
}


/**
 *	klist_next - Ante up next node in list.
 *	@i:	Iterator structure.
 *
 *	First grab list lock. Decrement the reference count of the previous
 *	node, if there was one. Grab the next node, increment its reference 
 *	count, drop the lock, and return that next node.
 */

struct klist_node * klist_next(struct klist_iter * i)
{
	struct list_head * next;
	struct klist_node * lnode = i->i_cur;
	struct klist_node * knode = NULL;
	void (*put)(struct klist_node *) = i->i_klist->put;

	spin_lock(&i->i_klist->k_lock);
	if (lnode) {
		next = lnode->n_node.next;
		if (!klist_dec_and_del(lnode))
			put = NULL;
	} else
		next = i->i_head->next;

	if (next != i->i_head) {
		knode = to_klist_node(next);
		kref_get(&knode->n_ref);
	}
	i->i_cur = knode;
	spin_unlock(&i->i_klist->k_lock);
	if (put && lnode)
		put(lnode);
	return knode;
}

EXPORT_SYMBOL_GPL(klist_next);