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.c253
1 files changed, 114 insertions, 139 deletions
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index d92c48e0d7a6..bfc8ca168f83 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -53,7 +53,8 @@ static char module_name[] = "rtlx";
53static struct chan_waitqueues { 53static 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 struct mutex mutex;
57} channel_wqs[RTLX_CHANNELS]; 58} channel_wqs[RTLX_CHANNELS];
58 59
59static struct irqaction irq; 60static struct irqaction irq;
@@ -146,110 +147,91 @@ static void stopping(int vpe)
146 147
147int rtlx_open(int index, int can_sleep) 148int rtlx_open(int index, int can_sleep)
148{ 149{
149 int ret; 150 struct rtlx_info **p;
150 struct rtlx_channel *chan; 151 struct rtlx_channel *chan;
151 volatile struct rtlx_info **p; 152 enum rtlx_state state;
153 int ret = 0;
152 154
153 if (index >= RTLX_CHANNELS) { 155 if (index >= RTLX_CHANNELS) {
154 printk(KERN_DEBUG "rtlx_open index out of range\n"); 156 printk(KERN_DEBUG "rtlx_open index out of range\n");
155 return -ENOSYS; 157 return -ENOSYS;
156 } 158 }
157 159
158 if (channel_wqs[index].in_open) { 160 if (atomic_inc_return(&channel_wqs[index].in_open) > 1) {
159 printk(KERN_DEBUG "rtlx_open channel %d already opened\n", index); 161 printk(KERN_DEBUG "rtlx_open channel %d already opened\n",
160 return -EBUSY; 162 index);
163 ret = -EBUSY;
164 goto out_fail;
161 } 165 }
162 166
163 channel_wqs[index].in_open++;
164
165 if (rtlx == NULL) { 167 if (rtlx == NULL) {
166 if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { 168 if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
167 if (can_sleep) { 169 if (can_sleep) {
168 DECLARE_WAITQUEUE(wait, current); 170 __wait_event_interruptible(channel_wqs[index].lx_queue,
169 171 (p = vpe_get_shared(RTLX_TARG_VPE)),
170 /* go to sleep */ 172 ret);
171 add_wait_queue(&channel_wqs[index].lx_queue, &wait); 173 if (ret)
172 174 goto out_fail;
173 set_current_state(TASK_INTERRUPTIBLE);
174 while ((p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
175 schedule();
176 set_current_state(TASK_INTERRUPTIBLE);
177 }
178
179 set_current_state(TASK_RUNNING);
180 remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
181
182 /* back running */
183 } else { 175 } else {
184 printk( KERN_DEBUG "No SP program loaded, and device " 176 printk(KERN_DEBUG "No SP program loaded, and device "
185 "opened with O_NONBLOCK\n"); 177 "opened with O_NONBLOCK\n");
186 channel_wqs[index].in_open = 0; 178 ret = -ENOSYS;
187 return -ENOSYS; 179 goto out_fail;
188 } 180 }
189 } 181 }
190 182
183 smp_rmb();
191 if (*p == NULL) { 184 if (*p == NULL) {
192 if (can_sleep) { 185 if (can_sleep) {
193 DECLARE_WAITQUEUE(wait, current); 186 DEFINE_WAIT(wait);
194 187
195 /* go to sleep */ 188 for (;;) {
196 add_wait_queue(&channel_wqs[index].lx_queue, &wait); 189 prepare_to_wait(&channel_wqs[index].lx_queue, &wait, TASK_INTERRUPTIBLE);
197 190 smp_rmb();
198 set_current_state(TASK_INTERRUPTIBLE); 191 if (*p != NULL)
199 while (*p == NULL) { 192 break;
200 schedule(); 193 if (!signal_pending(current)) {
201 194 schedule();
202 /* reset task state to interruptable otherwise 195 continue;
203 we'll whizz round here like a very fast loopy 196 }
204 thing. schedule() appears to return with state 197 ret = -ERESTARTSYS;
205 set to TASK_RUNNING. 198 goto out_fail;
206
207 If the loaded SP program, for whatever reason,
208 doesn't set up the shared structure *p will never
209 become true. So whoever connected to either /dev/rt?
210 or if it was kspd, will then take up rather a lot of
211 processor cycles.
212 */
213
214 set_current_state(TASK_INTERRUPTIBLE);
215 } 199 }
216 200 finish_wait(&channel_wqs[index].lx_queue, &wait);
217 set_current_state(TASK_RUNNING); 201 } else {
218 remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
219
220 /* back running */
221 }
222 else {
223 printk(" *vpe_get_shared is NULL. " 202 printk(" *vpe_get_shared is NULL. "
224 "Has an SP program been loaded?\n"); 203 "Has an SP program been loaded?\n");
225 channel_wqs[index].in_open = 0; 204 ret = -ENOSYS;
226 return -ENOSYS; 205 goto out_fail;
227 } 206 }
228 } 207 }
229 208
230 if ((unsigned int)*p < KSEG0) { 209 if ((unsigned int)*p < KSEG0) {
231 printk(KERN_WARNING "vpe_get_shared returned an invalid pointer " 210 printk(KERN_WARNING "vpe_get_shared returned an invalid pointer "
232 "maybe an error code %d\n", (int)*p); 211 "maybe an error code %d\n", (int)*p);
233 channel_wqs[index].in_open = 0; 212 ret = -ENOSYS;
234 return -ENOSYS; 213 goto out_fail;
235 } 214 }
236 215
237 if ((ret = rtlx_init(*p)) < 0) { 216 if ((ret = rtlx_init(*p)) < 0)
238 channel_wqs[index].in_open = 0; 217 goto out_ret;
239 return ret;
240 }
241 } 218 }
242 219
243 chan = &rtlx->channel[index]; 220 chan = &rtlx->channel[index];
244 221
245 if (chan->lx_state == RTLX_STATE_OPENED) { 222 state = xchg(&chan->lx_state, RTLX_STATE_OPENED);
246 channel_wqs[index].in_open = 0; 223 if (state == RTLX_STATE_OPENED) {
247 return -EBUSY; 224 ret = -EBUSY;
248 } 225 goto out_fail;
226 }
249 227
250 chan->lx_state = RTLX_STATE_OPENED; 228out_fail:
251 channel_wqs[index].in_open = 0; 229 smp_mb();
252 return 0; 230 atomic_dec(&channel_wqs[index].in_open);
231 smp_mb();
232
233out_ret:
234 return ret;
253} 235}
254 236
255int rtlx_release(int index) 237int rtlx_release(int index)
@@ -270,30 +252,17 @@ unsigned int rtlx_read_poll(int index, int can_sleep)
270 /* data available to read? */ 252 /* data available to read? */
271 if (chan->lx_read == chan->lx_write) { 253 if (chan->lx_read == chan->lx_write) {
272 if (can_sleep) { 254 if (can_sleep) {
273 DECLARE_WAITQUEUE(wait, current); 255 int ret = 0;
274
275 /* go to sleep */
276 add_wait_queue(&channel_wqs[index].lx_queue, &wait);
277
278 set_current_state(TASK_INTERRUPTIBLE);
279 while (chan->lx_read == chan->lx_write) {
280 schedule();
281 256
282 set_current_state(TASK_INTERRUPTIBLE); 257 __wait_event_interruptible(channel_wqs[index].lx_queue,
258 chan->lx_read != chan->lx_write || sp_stopping,
259 ret);
260 if (ret)
261 return ret;
283 262
284 if (sp_stopping) { 263 if (sp_stopping)
285 set_current_state(TASK_RUNNING); 264 return 0;
286 remove_wait_queue(&channel_wqs[index].lx_queue, &wait); 265 } else
287 return 0;
288 }
289 }
290
291 set_current_state(TASK_RUNNING);
292 remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
293
294 /* back running */
295 }
296 else
297 return 0; 266 return 0;
298 } 267 }
299 268
@@ -320,56 +289,53 @@ unsigned int rtlx_write_poll(int index)
320 return write_spacefree(chan->rt_read, chan->rt_write, chan->buffer_size); 289 return write_spacefree(chan->rt_read, chan->rt_write, chan->buffer_size);
321} 290}
322 291
323static inline void copy_to(void *dst, void *src, size_t count, int user) 292ssize_t rtlx_read(int index, void __user *buff, size_t count)
324{ 293{
325 if (user) 294 size_t lx_write, fl = 0L;
326 copy_to_user(dst, src, count);
327 else
328 memcpy(dst, src, count);
329}
330
331static inline void copy_from(void *dst, void *src, size_t count, int user)
332{
333 if (user)
334 copy_from_user(dst, src, count);
335 else
336 memcpy(dst, src, count);
337}
338
339ssize_t rtlx_read(int index, void *buff, size_t count, int user)
340{
341 size_t fl = 0L;
342 struct rtlx_channel *lx; 295 struct rtlx_channel *lx;
296 unsigned long failed;
343 297
344 if (rtlx == NULL) 298 if (rtlx == NULL)
345 return -ENOSYS; 299 return -ENOSYS;
346 300
347 lx = &rtlx->channel[index]; 301 lx = &rtlx->channel[index];
348 302
303 mutex_lock(&channel_wqs[index].mutex);
304 smp_rmb();
305 lx_write = lx->lx_write;
306
349 /* find out how much in total */ 307 /* find out how much in total */
350 count = min(count, 308 count = min(count,
351 (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) 309 (size_t)(lx_write + lx->buffer_size - lx->lx_read)
352 % lx->buffer_size); 310 % lx->buffer_size);
353 311
354 /* then how much from the read pointer onwards */ 312 /* then how much from the read pointer onwards */
355 fl = min( count, (size_t)lx->buffer_size - lx->lx_read); 313 fl = min(count, (size_t)lx->buffer_size - lx->lx_read);
356 314
357 copy_to(buff, &lx->lx_buffer[lx->lx_read], fl, user); 315 failed = copy_to_user(buff, lx->lx_buffer + lx->lx_read, fl);
316 if (failed)
317 goto out;
358 318
359 /* and if there is anything left at the beginning of the buffer */ 319 /* and if there is anything left at the beginning of the buffer */
360 if ( count - fl ) 320 if (count - fl)
361 copy_to (buff + fl, lx->lx_buffer, count - fl, user); 321 failed = copy_to_user(buff + fl, lx->lx_buffer, count - fl);
322
323out:
324 count -= failed;
362 325
363 /* update the index */ 326 smp_wmb();
364 lx->lx_read += count; 327 lx->lx_read = (lx->lx_read + count) % lx->buffer_size;
365 lx->lx_read %= lx->buffer_size; 328 smp_wmb();
329 mutex_unlock(&channel_wqs[index].mutex);
366 330
367 return count; 331 return count;
368} 332}
369 333
370ssize_t rtlx_write(int index, void *buffer, size_t count, int user) 334ssize_t rtlx_write(int index, const void __user *buffer, size_t count)
371{ 335{
372 struct rtlx_channel *rt; 336 struct rtlx_channel *rt;
337 unsigned long failed;
338 size_t rt_read;
373 size_t fl; 339 size_t fl;
374 340
375 if (rtlx == NULL) 341 if (rtlx == NULL)
@@ -377,24 +343,35 @@ ssize_t rtlx_write(int index, void *buffer, size_t count, int user)
377 343
378 rt = &rtlx->channel[index]; 344 rt = &rtlx->channel[index];
379 345
346 mutex_lock(&channel_wqs[index].mutex);
347 smp_rmb();
348 rt_read = rt->rt_read;
349
380 /* total number of bytes to copy */ 350 /* total number of bytes to copy */
381 count = min(count, 351 count = min(count,
382 (size_t)write_spacefree(rt->rt_read, rt->rt_write, 352 (size_t)write_spacefree(rt_read, rt->rt_write, rt->buffer_size));
383 rt->buffer_size));
384 353
385 /* first bit from write pointer to the end of the buffer, or count */ 354 /* first bit from write pointer to the end of the buffer, or count */
386 fl = min(count, (size_t) rt->buffer_size - rt->rt_write); 355 fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
387 356
388 copy_from (&rt->rt_buffer[rt->rt_write], buffer, fl, user); 357 failed = copy_from_user(rt->rt_buffer + rt->rt_write, buffer, fl);
358 if (failed)
359 goto out;
389 360
390 /* if there's any left copy to the beginning of the buffer */ 361 /* if there's any left copy to the beginning of the buffer */
391 if( count - fl ) 362 if (count - fl) {
392 copy_from (rt->rt_buffer, buffer + fl, count - fl, user); 363 failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl);
364 }
393 365
394 rt->rt_write += count; 366out:
395 rt->rt_write %= rt->buffer_size; 367 count -= failed;
396 368
397 return(count); 369 smp_wmb();
370 rt->rt_write = (rt->rt_write + count) % rt->buffer_size;
371 smp_wmb();
372 mutex_unlock(&channel_wqs[index].mutex);
373
374 return count;
398} 375}
399 376
400 377
@@ -446,7 +423,7 @@ static ssize_t file_read(struct file *file, char __user * buffer, size_t count,
446 return 0; // -EAGAIN makes cat whinge 423 return 0; // -EAGAIN makes cat whinge
447 } 424 }
448 425
449 return rtlx_read(minor, buffer, count, 1); 426 return rtlx_read(minor, buffer, count);
450} 427}
451 428
452static ssize_t file_write(struct file *file, const char __user * buffer, 429static ssize_t file_write(struct file *file, const char __user * buffer,
@@ -454,28 +431,25 @@ static ssize_t file_write(struct file *file, const char __user * buffer,
454{ 431{
455 int minor; 432 int minor;
456 struct rtlx_channel *rt; 433 struct rtlx_channel *rt;
457 DECLARE_WAITQUEUE(wait, current);
458 434
459 minor = iminor(file->f_path.dentry->d_inode); 435 minor = iminor(file->f_path.dentry->d_inode);
460 rt = &rtlx->channel[minor]; 436 rt = &rtlx->channel[minor];
461 437
462 /* any space left... */ 438 /* any space left... */
463 if (!rtlx_write_poll(minor)) { 439 if (!rtlx_write_poll(minor)) {
440 int ret = 0;
464 441
465 if (file->f_flags & O_NONBLOCK) 442 if (file->f_flags & O_NONBLOCK)
466 return -EAGAIN; 443 return -EAGAIN;
467 444
468 add_wait_queue(&channel_wqs[minor].rt_queue, &wait); 445 __wait_event_interruptible(channel_wqs[minor].rt_queue,
469 set_current_state(TASK_INTERRUPTIBLE); 446 rtlx_write_poll(minor),
470 447 ret);
471 while (!rtlx_write_poll(minor)) 448 if (ret)
472 schedule(); 449 return ret;
473
474 set_current_state(TASK_RUNNING);
475 remove_wait_queue(&channel_wqs[minor].rt_queue, &wait);
476 } 450 }
477 451
478 return rtlx_write(minor, (void *)buffer, count, 1); 452 return rtlx_write(minor, buffer, count);
479} 453}
480 454
481static const struct file_operations rtlx_fops = { 455static const struct file_operations rtlx_fops = {
@@ -513,7 +487,8 @@ static int rtlx_module_init(void)
513 for (i = 0; i < RTLX_CHANNELS; i++) { 487 for (i = 0; i < RTLX_CHANNELS; i++) {
514 init_waitqueue_head(&channel_wqs[i].rt_queue); 488 init_waitqueue_head(&channel_wqs[i].rt_queue);
515 init_waitqueue_head(&channel_wqs[i].lx_queue); 489 init_waitqueue_head(&channel_wqs[i].lx_queue);
516 channel_wqs[i].in_open = 0; 490 atomic_set(&channel_wqs[i].in_open, 0);
491 mutex_init(&channel_wqs[i].mutex);
517 492
518 dev = device_create(mt_class, NULL, MKDEV(major, i), 493 dev = device_create(mt_class, NULL, MKDEV(major, i),
519 "%s%d", module_name, i); 494 "%s%d", module_name, i);