[MIPS] RTLX, VPE: Make open actually atomic.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
This commit is contained in:
Ralf Baechle 2007-02-23 13:40:45 +00:00
parent cbc8413567
commit c4c4018b04
2 changed files with 23 additions and 28 deletions

View File

@ -53,7 +53,7 @@ static char module_name[] = "rtlx";
static struct chan_waitqueues { static struct chan_waitqueues {
wait_queue_head_t rt_queue; wait_queue_head_t rt_queue;
wait_queue_head_t lx_queue; wait_queue_head_t lx_queue;
int in_open; atomic_t in_open;
} channel_wqs[RTLX_CHANNELS]; } channel_wqs[RTLX_CHANNELS];
static struct irqaction irq; static struct irqaction irq;
@ -148,6 +148,7 @@ int rtlx_open(int index, int can_sleep)
{ {
volatile struct rtlx_info **p; volatile struct rtlx_info **p;
struct rtlx_channel *chan; struct rtlx_channel *chan;
enum rtlx_state state;
int ret = 0; int ret = 0;
if (index >= RTLX_CHANNELS) { if (index >= RTLX_CHANNELS) {
@ -155,13 +156,13 @@ int rtlx_open(int index, int can_sleep)
return -ENOSYS; return -ENOSYS;
} }
if (channel_wqs[index].in_open) { if (atomic_inc_return(&channel_wqs[index].in_open) > 1) {
printk(KERN_DEBUG "rtlx_open channel %d already opened\n", index); printk(KERN_DEBUG "rtlx_open channel %d already opened\n",
return -EBUSY; index);
ret = -EBUSY;
goto out_fail;
} }
channel_wqs[index].in_open++;
if (rtlx == NULL) { if (rtlx == NULL) {
if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
if (can_sleep) { if (can_sleep) {
@ -173,9 +174,8 @@ int rtlx_open(int index, int can_sleep)
if (ret) if (ret)
goto out_fail; goto out_fail;
} else { } else {
printk( KERN_DEBUG "No SP program loaded, and device " printk(KERN_DEBUG "No SP program loaded, and device "
"opened with O_NONBLOCK\n"); "opened with O_NONBLOCK\n");
channel_wqs[index].in_open = 0;
ret = -ENOSYS; ret = -ENOSYS;
goto out_fail; goto out_fail;
} }
@ -193,7 +193,6 @@ int rtlx_open(int index, int can_sleep)
} else { } else {
printk(" *vpe_get_shared is NULL. " printk(" *vpe_get_shared is NULL. "
"Has an SP program been loaded?\n"); "Has an SP program been loaded?\n");
channel_wqs[index].in_open = 0;
ret = -ENOSYS; ret = -ENOSYS;
goto out_fail; goto out_fail;
} }
@ -202,31 +201,28 @@ int rtlx_open(int index, int can_sleep)
if ((unsigned int)*p < KSEG0) { if ((unsigned int)*p < KSEG0) {
printk(KERN_WARNING "vpe_get_shared returned an invalid pointer " printk(KERN_WARNING "vpe_get_shared returned an invalid pointer "
"maybe an error code %d\n", (int)*p); "maybe an error code %d\n", (int)*p);
channel_wqs[index].in_open = 0;
ret = -ENOSYS; ret = -ENOSYS;
goto out_fail; goto out_fail;
} }
if ((ret = rtlx_init(*p)) < 0) { if ((ret = rtlx_init(*p)) < 0)
channel_wqs[index].in_open = 0; goto out_ret;
return ret;
}
} }
chan = &rtlx->channel[index]; chan = &rtlx->channel[index];
if (chan->lx_state == RTLX_STATE_OPENED) { state = xchg(&chan->lx_state, RTLX_STATE_OPENED);
channel_wqs[index].in_open = 0; if (state == RTLX_STATE_OPENED) {
return -EBUSY; ret = -EBUSY;
} goto out_fail;
}
chan->lx_state = RTLX_STATE_OPENED;
channel_wqs[index].in_open = 0;
return 0;
out_fail: out_fail:
channel_wqs[index].in_open--; smp_mb();
atomic_dec(&channel_wqs[index].in_open);
smp_mb();
out_ret:
return ret; return ret;
} }
@ -475,7 +471,7 @@ static int rtlx_module_init(void)
for (i = 0; i < RTLX_CHANNELS; i++) { for (i = 0; i < RTLX_CHANNELS; i++) {
init_waitqueue_head(&channel_wqs[i].rt_queue); init_waitqueue_head(&channel_wqs[i].rt_queue);
init_waitqueue_head(&channel_wqs[i].lx_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), dev = device_create(mt_class, NULL, MKDEV(major, i),
"%s%d", module_name, i); "%s%d", module_name, i);

View File

@ -1079,6 +1079,7 @@ static int getcwd(char *buff, int size)
static int vpe_open(struct inode *inode, struct file *filp) static int vpe_open(struct inode *inode, struct file *filp)
{ {
int minor, ret; int minor, ret;
enum vpe_state state;
struct vpe *v; struct vpe *v;
struct vpe_notifications *not; struct vpe_notifications *not;
@ -1093,7 +1094,8 @@ static int vpe_open(struct inode *inode, struct file *filp)
return -ENODEV; return -ENODEV;
} }
if (v->state != VPE_STATE_UNUSED) { state = xchg(&v->state, VPE_STATE_INUSE);
if (state != VPE_STATE_UNUSED) {
dvpe(); dvpe();
printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n"); printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n");
@ -1108,9 +1110,6 @@ static int vpe_open(struct inode *inode, struct file *filp)
cleanup_tc(get_tc(minor)); cleanup_tc(get_tc(minor));
} }
// allocate it so when we get write ops we know it's expected.
v->state = VPE_STATE_INUSE;
/* this of-course trashes what was there before... */ /* this of-course trashes what was there before... */
v->pbuffer = vmalloc(P_SIZE); v->pbuffer = vmalloc(P_SIZE);
v->plen = P_SIZE; v->plen = P_SIZE;