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); |