diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2007-02-23 13:40:45 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-02-26 23:06:06 +0000 |
commit | c4c4018b04f9b7993e3800dc1f391ac8947764a5 (patch) | |
tree | 346c9a4aa9c46eee6df883f89553e43b9d7033fc /arch/mips/kernel/rtlx.c | |
parent | cbc841356702ccf4f16e760c84006ed3ddd4b1fd (diff) |
[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.c | 44 |
1 files changed, 20 insertions, 24 deletions
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 766db51ab69..7a8683ab6fd 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); |