diff options
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 766db51ab69e..7a8683ab6fde 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c | |||
| @@ -53,7 +53,7 @@ static char module_name[] = "rtlx"; | |||
| 53 | static struct chan_waitqueues { | 53 | static struct chan_waitqueues { |
| 54 | wait_queue_head_t rt_queue; | 54 | wait_queue_head_t rt_queue; |
| 55 | wait_queue_head_t lx_queue; | 55 | wait_queue_head_t lx_queue; |
| 56 | int in_open; | 56 | atomic_t in_open; |
| 57 | } channel_wqs[RTLX_CHANNELS]; | 57 | } channel_wqs[RTLX_CHANNELS]; |
| 58 | 58 | ||
| 59 | static struct irqaction irq; | 59 | static struct irqaction irq; |
| @@ -148,6 +148,7 @@ int rtlx_open(int index, int can_sleep) | |||
| 148 | { | 148 | { |
| 149 | volatile struct rtlx_info **p; | 149 | volatile struct rtlx_info **p; |
| 150 | struct rtlx_channel *chan; | 150 | struct rtlx_channel *chan; |
| 151 | enum rtlx_state state; | ||
| 151 | int ret = 0; | 152 | int ret = 0; |
| 152 | 153 | ||
| 153 | if (index >= RTLX_CHANNELS) { | 154 | if (index >= RTLX_CHANNELS) { |
| @@ -155,13 +156,13 @@ int rtlx_open(int index, int can_sleep) | |||
| 155 | return -ENOSYS; | 156 | return -ENOSYS; |
| 156 | } | 157 | } |
| 157 | 158 | ||
| 158 | if (channel_wqs[index].in_open) { | 159 | if (atomic_inc_return(&channel_wqs[index].in_open) > 1) { |
| 159 | printk(KERN_DEBUG "rtlx_open channel %d already opened\n", index); | 160 | printk(KERN_DEBUG "rtlx_open channel %d already opened\n", |
| 160 | return -EBUSY; | 161 | index); |
| 162 | ret = -EBUSY; | ||
| 163 | goto out_fail; | ||
| 161 | } | 164 | } |
| 162 | 165 | ||
| 163 | channel_wqs[index].in_open++; | ||
| 164 | |||
| 165 | if (rtlx == NULL) { | 166 | if (rtlx == NULL) { |
| 166 | if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { | 167 | if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { |
| 167 | if (can_sleep) { | 168 | if (can_sleep) { |
| @@ -173,9 +174,8 @@ int rtlx_open(int index, int can_sleep) | |||
| 173 | if (ret) | 174 | if (ret) |
| 174 | goto out_fail; | 175 | goto out_fail; |
| 175 | } else { | 176 | } else { |
| 176 | printk( KERN_DEBUG "No SP program loaded, and device " | 177 | printk(KERN_DEBUG "No SP program loaded, and device " |
| 177 | "opened with O_NONBLOCK\n"); | 178 | "opened with O_NONBLOCK\n"); |
| 178 | channel_wqs[index].in_open = 0; | ||
| 179 | ret = -ENOSYS; | 179 | ret = -ENOSYS; |
| 180 | goto out_fail; | 180 | goto out_fail; |
| 181 | } | 181 | } |
| @@ -193,7 +193,6 @@ int rtlx_open(int index, int can_sleep) | |||
| 193 | } else { | 193 | } else { |
| 194 | printk(" *vpe_get_shared is NULL. " | 194 | printk(" *vpe_get_shared is NULL. " |
| 195 | "Has an SP program been loaded?\n"); | 195 | "Has an SP program been loaded?\n"); |
| 196 | channel_wqs[index].in_open = 0; | ||
| 197 | ret = -ENOSYS; | 196 | ret = -ENOSYS; |
| 198 | goto out_fail; | 197 | goto out_fail; |
| 199 | } | 198 | } |
| @@ -202,31 +201,28 @@ int rtlx_open(int index, int can_sleep) | |||
| 202 | if ((unsigned int)*p < KSEG0) { | 201 | if ((unsigned int)*p < KSEG0) { |
| 203 | printk(KERN_WARNING "vpe_get_shared returned an invalid pointer " | 202 | printk(KERN_WARNING "vpe_get_shared returned an invalid pointer " |
| 204 | "maybe an error code %d\n", (int)*p); | 203 | "maybe an error code %d\n", (int)*p); |
| 205 | channel_wqs[index].in_open = 0; | ||
| 206 | ret = -ENOSYS; | 204 | ret = -ENOSYS; |
| 207 | goto out_fail; | 205 | goto out_fail; |
| 208 | } | 206 | } |
| 209 | 207 | ||
| 210 | if ((ret = rtlx_init(*p)) < 0) { | 208 | if ((ret = rtlx_init(*p)) < 0) |
| 211 | channel_wqs[index].in_open = 0; | 209 | goto out_ret; |
| 212 | return ret; | ||
| 213 | } | ||
| 214 | } | 210 | } |
| 215 | 211 | ||
| 216 | chan = &rtlx->channel[index]; | 212 | chan = &rtlx->channel[index]; |
| 217 | 213 | ||
| 218 | if (chan->lx_state == RTLX_STATE_OPENED) { | 214 | state = xchg(&chan->lx_state, RTLX_STATE_OPENED); |
| 219 | channel_wqs[index].in_open = 0; | 215 | if (state == RTLX_STATE_OPENED) { |
| 220 | return -EBUSY; | 216 | ret = -EBUSY; |
| 221 | } | 217 | goto out_fail; |
| 222 | 218 | } | |
| 223 | chan->lx_state = RTLX_STATE_OPENED; | ||
| 224 | channel_wqs[index].in_open = 0; | ||
| 225 | return 0; | ||
| 226 | 219 | ||
| 227 | out_fail: | 220 | out_fail: |
| 228 | channel_wqs[index].in_open--; | 221 | smp_mb(); |
| 222 | atomic_dec(&channel_wqs[index].in_open); | ||
| 223 | smp_mb(); | ||
| 229 | 224 | ||
| 225 | out_ret: | ||
| 230 | return ret; | 226 | return ret; |
| 231 | } | 227 | } |
| 232 | 228 | ||
| @@ -475,7 +471,7 @@ static int rtlx_module_init(void) | |||
| 475 | for (i = 0; i < RTLX_CHANNELS; i++) { | 471 | for (i = 0; i < RTLX_CHANNELS; i++) { |
| 476 | init_waitqueue_head(&channel_wqs[i].rt_queue); | 472 | init_waitqueue_head(&channel_wqs[i].rt_queue); |
| 477 | init_waitqueue_head(&channel_wqs[i].lx_queue); | 473 | init_waitqueue_head(&channel_wqs[i].lx_queue); |
| 478 | channel_wqs[i].in_open = 0; | 474 | atomic_set(&channel_wqs[i].in_open, 0); |
| 479 | 475 | ||
| 480 | dev = device_create(mt_class, NULL, MKDEV(major, i), | 476 | dev = device_create(mt_class, NULL, MKDEV(major, i), |
| 481 | "%s%d", module_name, i); | 477 | "%s%d", module_name, i); |
