summaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/rtlx.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2007-02-23 14:40:45 +0100
committerRalf Baechle <ralf@linux-mips.org>2007-02-27 00:06:06 +0100
commitc4c4018b04f9b7993e3800dc1f391ac8947764a5 (patch)
tree346c9a4aa9c46eee6df883f89553e43b9d7033fc /arch/mips/kernel/rtlx.c
parent[MIPS] excite: Set serial driver iotype to UPIO_RM9000 (diff)
downloadlinux-c4c4018b04f9b7993e3800dc1f391ac8947764a5.tar.xz
linux-c4c4018b04f9b7993e3800dc1f391ac8947764a5.zip
[MIPS] RTLX, VPE: Make open actually atomic.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/rtlx.c')
-rw-r--r--arch/mips/kernel/rtlx.c44
1 files changed, 20 insertions, 24 deletions
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index 766db51ab69e..7a8683ab6fde 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -53,7 +53,7 @@ static char module_name[] = "rtlx";
static struct chan_waitqueues {
wait_queue_head_t rt_queue;
wait_queue_head_t lx_queue;
- int in_open;
+ atomic_t in_open;
} channel_wqs[RTLX_CHANNELS];
static struct irqaction irq;
@@ -148,6 +148,7 @@ int rtlx_open(int index, int can_sleep)
{
volatile struct rtlx_info **p;
struct rtlx_channel *chan;
+ enum rtlx_state state;
int ret = 0;
if (index >= RTLX_CHANNELS) {
@@ -155,13 +156,13 @@ int rtlx_open(int index, int can_sleep)
return -ENOSYS;
}
- if (channel_wqs[index].in_open) {
- printk(KERN_DEBUG "rtlx_open channel %d already opened\n", index);
- return -EBUSY;
+ if (atomic_inc_return(&channel_wqs[index].in_open) > 1) {
+ printk(KERN_DEBUG "rtlx_open channel %d already opened\n",
+ index);
+ ret = -EBUSY;
+ goto out_fail;
}
- channel_wqs[index].in_open++;
-
if (rtlx == NULL) {
if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
if (can_sleep) {
@@ -173,9 +174,8 @@ int rtlx_open(int index, int can_sleep)
if (ret)
goto out_fail;
} else {
- printk( KERN_DEBUG "No SP program loaded, and device "
+ printk(KERN_DEBUG "No SP program loaded, and device "
"opened with O_NONBLOCK\n");
- channel_wqs[index].in_open = 0;
ret = -ENOSYS;
goto out_fail;
}
@@ -193,7 +193,6 @@ int rtlx_open(int index, int can_sleep)
} else {
printk(" *vpe_get_shared is NULL. "
"Has an SP program been loaded?\n");
- channel_wqs[index].in_open = 0;
ret = -ENOSYS;
goto out_fail;
}
@@ -202,31 +201,28 @@ int rtlx_open(int index, int can_sleep)
if ((unsigned int)*p < KSEG0) {
printk(KERN_WARNING "vpe_get_shared returned an invalid pointer "
"maybe an error code %d\n", (int)*p);
- channel_wqs[index].in_open = 0;
ret = -ENOSYS;
goto out_fail;
}
- if ((ret = rtlx_init(*p)) < 0) {
- channel_wqs[index].in_open = 0;
- return ret;
- }
+ if ((ret = rtlx_init(*p)) < 0)
+ goto out_ret;
}
chan = &rtlx->channel[index];
- if (chan->lx_state == RTLX_STATE_OPENED) {
- channel_wqs[index].in_open = 0;
- return -EBUSY;
- }
-
- chan->lx_state = RTLX_STATE_OPENED;
- channel_wqs[index].in_open = 0;
- return 0;
+ state = xchg(&chan->lx_state, RTLX_STATE_OPENED);
+ if (state == RTLX_STATE_OPENED) {
+ ret = -EBUSY;
+ goto out_fail;
+ }
out_fail:
- channel_wqs[index].in_open--;
+ smp_mb();
+ atomic_dec(&channel_wqs[index].in_open);
+ smp_mb();
+out_ret:
return ret;
}
@@ -475,7 +471,7 @@ static int rtlx_module_init(void)
for (i = 0; i < RTLX_CHANNELS; i++) {
init_waitqueue_head(&channel_wqs[i].rt_queue);
init_waitqueue_head(&channel_wqs[i].lx_queue);
- channel_wqs[i].in_open = 0;
+ atomic_set(&channel_wqs[i].in_open, 0);
dev = device_create(mt_class, NULL, MKDEV(major, i),
"%s%d", module_name, i);