linux/arch/frv/kernel/semaphore.c
David Howells 8080f23122 [PATCH] FRV: Make the FRV arch work again
The attached patch implements a bunch of small changes to the FRV arch to
make it work again.

It deals with the following problems:

 (1) SEM_DEBUG should be SEMAPHORE_DEBUG.

 (2) The argument list to pcibios_penalize_isa_irq() has changed.

 (3) CONFIG_HIGHMEM can't be used directly in #if as it may not be defined.

 (4) page->private is no longer directly accessible.

 (5) linux/hardirq.h assumes asm/hardirq.h will include linux/irq.h

 (6) The IDE MMIO access functions are given pointers, not integers, and so
     get type casting errors.

 (7) __pa() is passed an explicit u64 type in drivers/char/mem.c, but that
     can't be cast directly to a pointer on a 32-bit platform.

 (8) SEMAPHORE_DEBUG should not be contingent on WAITQUEUE_DEBUG as that no
     longer exists.

 (9) PREEMPT_ACTIVE is too low a value.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
2005-11-28 14:42:23 -08:00

157 lines
3.6 KiB
C

/* semaphore.c: FR-V semaphores
*
* Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
* - Derived from lib/rwsem-spinlock.c
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/config.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <asm/semaphore.h>
struct sem_waiter {
struct list_head list;
struct task_struct *task;
};
#if SEMAPHORE_DEBUG
void semtrace(struct semaphore *sem, const char *str)
{
if (sem->debug)
printk("[%d] %s({%d,%d})\n",
current->pid,
str,
sem->counter,
list_empty(&sem->wait_list) ? 0 : 1);
}
#else
#define semtrace(SEM,STR) do { } while(0)
#endif
/*
* wait for a token to be granted from a semaphore
* - entered with lock held and interrupts disabled
*/
void __down(struct semaphore *sem, unsigned long flags)
{
struct task_struct *tsk = current;
struct sem_waiter waiter;
semtrace(sem, "Entering __down");
/* set up my own style of waitqueue */
waiter.task = tsk;
get_task_struct(tsk);
list_add_tail(&waiter.list, &sem->wait_list);
/* we don't need to touch the semaphore struct anymore */
spin_unlock_irqrestore(&sem->wait_lock, flags);
/* wait to be given the semaphore */
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
for (;;) {
if (list_empty(&waiter.list))
break;
schedule();
set_task_state(tsk, TASK_UNINTERRUPTIBLE);
}
tsk->state = TASK_RUNNING;
semtrace(sem, "Leaving __down");
}
EXPORT_SYMBOL(__down);
/*
* interruptibly wait for a token to be granted from a semaphore
* - entered with lock held and interrupts disabled
*/
int __down_interruptible(struct semaphore *sem, unsigned long flags)
{
struct task_struct *tsk = current;
struct sem_waiter waiter;
int ret;
semtrace(sem,"Entering __down_interruptible");
/* set up my own style of waitqueue */
waiter.task = tsk;
get_task_struct(tsk);
list_add_tail(&waiter.list, &sem->wait_list);
/* we don't need to touch the semaphore struct anymore */
set_task_state(tsk, TASK_INTERRUPTIBLE);
spin_unlock_irqrestore(&sem->wait_lock, flags);
/* wait to be given the semaphore */
ret = 0;
for (;;) {
if (list_empty(&waiter.list))
break;
if (unlikely(signal_pending(current)))
goto interrupted;
schedule();
set_task_state(tsk, TASK_INTERRUPTIBLE);
}
out:
tsk->state = TASK_RUNNING;
semtrace(sem, "Leaving __down_interruptible");
return ret;
interrupted:
spin_lock_irqsave(&sem->wait_lock, flags);
if (!list_empty(&waiter.list)) {
list_del(&waiter.list);
ret = -EINTR;
}
spin_unlock_irqrestore(&sem->wait_lock, flags);
if (ret == -EINTR)
put_task_struct(current);
goto out;
}
EXPORT_SYMBOL(__down_interruptible);
/*
* release a single token back to a semaphore
* - entered with lock held and interrupts disabled
*/
void __up(struct semaphore *sem)
{
struct task_struct *tsk;
struct sem_waiter *waiter;
semtrace(sem,"Entering __up");
/* grant the token to the process at the front of the queue */
waiter = list_entry(sem->wait_list.next, struct sem_waiter, list);
/* We must be careful not to touch 'waiter' after we set ->task = NULL.
* It is an allocated on the waiter's stack and may become invalid at
* any time after that point (due to a wakeup from another source).
*/
list_del_init(&waiter->list);
tsk = waiter->task;
mb();
waiter->task = NULL;
wake_up_process(tsk);
put_task_struct(tsk);
semtrace(sem,"Leaving __up");
}
EXPORT_SYMBOL(__up);