aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/rtlx.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/rtlx.c')
-rw-r--r--arch/mips/kernel/rtlx.c160
1 files changed, 57 insertions, 103 deletions
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index d92c48e0d7a6..e14ae09eda2b 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;
@@ -146,110 +146,80 @@ static void stopping(int vpe)
int rtlx_open(int index, int can_sleep)
{
- int ret;
- struct rtlx_channel *chan;
volatile struct rtlx_info **p;
+ struct rtlx_channel *chan;
+ enum rtlx_state state;
+ int ret = 0;
if (index >= RTLX_CHANNELS) {
printk(KERN_DEBUG "rtlx_open index out of range\n");
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) {
- DECLARE_WAITQUEUE(wait, current);
-
- /* go to sleep */
- add_wait_queue(&channel_wqs[index].lx_queue, &wait);
-
- set_current_state(TASK_INTERRUPTIBLE);
- while ((p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- }
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
-
- /* back running */
+ __wait_event_interruptible(channel_wqs[index].lx_queue,
+ (p = vpe_get_shared(RTLX_TARG_VPE)),
+ ret);
+ 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;
- return -ENOSYS;
+ ret = -ENOSYS;
+ goto out_fail;
}
}
if (*p == NULL) {
if (can_sleep) {
- DECLARE_WAITQUEUE(wait, current);
-
- /* go to sleep */
- add_wait_queue(&channel_wqs[index].lx_queue, &wait);
-
- set_current_state(TASK_INTERRUPTIBLE);
- while (*p == NULL) {
- schedule();
-
- /* reset task state to interruptable otherwise
- we'll whizz round here like a very fast loopy
- thing. schedule() appears to return with state
- set to TASK_RUNNING.
-
- If the loaded SP program, for whatever reason,
- doesn't set up the shared structure *p will never
- become true. So whoever connected to either /dev/rt?
- or if it was kspd, will then take up rather a lot of
- processor cycles.
- */
-
- set_current_state(TASK_INTERRUPTIBLE);
- }
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
-
- /* back running */
- }
- else {
+ __wait_event_interruptible(channel_wqs[index].lx_queue,
+ *p != NULL,
+ ret);
+ if (ret)
+ goto out_fail;
+ } else {
printk(" *vpe_get_shared is NULL. "
"Has an SP program been loaded?\n");
- channel_wqs[index].in_open = 0;
- return -ENOSYS;
+ ret = -ENOSYS;
+ goto out_fail;
}
}
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;
- return -ENOSYS;
+ 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;
- }
+ state = xchg(&chan->lx_state, RTLX_STATE_OPENED);
+ if (state == RTLX_STATE_OPENED) {
+ ret = -EBUSY;
+ goto out_fail;
+ }
- chan->lx_state = RTLX_STATE_OPENED;
- channel_wqs[index].in_open = 0;
- return 0;
+out_fail:
+ smp_mb();
+ atomic_dec(&channel_wqs[index].in_open);
+ smp_mb();
+
+out_ret:
+ return ret;
}
int rtlx_release(int index)
@@ -270,30 +240,17 @@ unsigned int rtlx_read_poll(int index, int can_sleep)
/* data available to read? */
if (chan->lx_read == chan->lx_write) {
if (can_sleep) {
- DECLARE_WAITQUEUE(wait, current);
-
- /* go to sleep */
- add_wait_queue(&channel_wqs[index].lx_queue, &wait);
-
- set_current_state(TASK_INTERRUPTIBLE);
- while (chan->lx_read == chan->lx_write) {
- schedule();
+ int ret = 0;
- set_current_state(TASK_INTERRUPTIBLE);
+ __wait_event_interruptible(channel_wqs[index].lx_queue,
+ chan->lx_read != chan->lx_write || sp_stopping,
+ ret);
+ if (ret)
+ return ret;
- if (sp_stopping) {
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
- return 0;
- }
- }
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
-
- /* back running */
- }
- else
+ if (sp_stopping)
+ return 0;
+ } else
return 0;
}
@@ -454,25 +411,22 @@ static ssize_t file_write(struct file *file, const char __user * buffer,
{
int minor;
struct rtlx_channel *rt;
- DECLARE_WAITQUEUE(wait, current);
minor = iminor(file->f_path.dentry->d_inode);
rt = &rtlx->channel[minor];
/* any space left... */
if (!rtlx_write_poll(minor)) {
+ int ret = 0;
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
- add_wait_queue(&channel_wqs[minor].rt_queue, &wait);
- set_current_state(TASK_INTERRUPTIBLE);
-
- while (!rtlx_write_poll(minor))
- schedule();
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&channel_wqs[minor].rt_queue, &wait);
+ __wait_event_interruptible(channel_wqs[minor].rt_queue,
+ rtlx_write_poll(minor),
+ ret);
+ if (ret)
+ return ret;
}
return rtlx_write(minor, (void *)buffer, count, 1);
@@ -513,7 +467,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);