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.c104
1 files changed, 62 insertions, 42 deletions
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index e14ae09eda2b..e6e3047151a6 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -54,6 +54,7 @@ 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 atomic_t 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,7 +147,7 @@ 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 volatile struct rtlx_info **p; 150 struct rtlx_info **p;
150 struct rtlx_channel *chan; 151 struct rtlx_channel *chan;
151 enum rtlx_state state; 152 enum rtlx_state state;
152 int ret = 0; 153 int ret = 0;
@@ -179,13 +180,24 @@ int rtlx_open(int index, int can_sleep)
179 } 180 }
180 } 181 }
181 182
183 smp_rmb();
182 if (*p == NULL) { 184 if (*p == NULL) {
183 if (can_sleep) { 185 if (can_sleep) {
184 __wait_event_interruptible(channel_wqs[index].lx_queue, 186 DEFINE_WAIT(wait);
185 *p != NULL, 187
186 ret); 188 for (;;) {
187 if (ret) 189 prepare_to_wait(&channel_wqs[index].lx_queue, &wait, TASK_INTERRUPTIBLE);
190 smp_rmb();
191 if (*p != NULL)
192 break;
193 if (!signal_pending(current)) {
194 schedule();
195 continue;
196 }
197 ret = -ERESTARTSYS;
188 goto out_fail; 198 goto out_fail;
199 }
200 finish_wait(&channel_wqs[index].lx_queue, &wait);
189 } else { 201 } else {
190 printk(" *vpe_get_shared is NULL. " 202 printk(" *vpe_get_shared is NULL. "
191 "Has an SP program been loaded?\n"); 203 "Has an SP program been loaded?\n");
@@ -277,56 +289,52 @@ unsigned int rtlx_write_poll(int index)
277 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);
278} 290}
279 291
280static 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, int user)
281{
282 if (user)
283 copy_to_user(dst, src, count);
284 else
285 memcpy(dst, src, count);
286}
287
288static inline void copy_from(void *dst, void *src, size_t count, int user)
289{ 293{
290 if (user) 294 size_t lx_write, fl = 0L;
291 copy_from_user(dst, src, count);
292 else
293 memcpy(dst, src, count);
294}
295
296ssize_t rtlx_read(int index, void *buff, size_t count, int user)
297{
298 size_t fl = 0L;
299 struct rtlx_channel *lx; 295 struct rtlx_channel *lx;
296 unsigned long failed;
300 297
301 if (rtlx == NULL) 298 if (rtlx == NULL)
302 return -ENOSYS; 299 return -ENOSYS;
303 300
304 lx = &rtlx->channel[index]; 301 lx = &rtlx->channel[index];
305 302
303 mutex_lock(&channel_wqs[index].mutex);
304 smp_rmb();
305 lx_write = lx->lx_write;
306
306 /* find out how much in total */ 307 /* find out how much in total */
307 count = min(count, 308 count = min(count,
308 (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) 309 (size_t)(lx_write + lx->buffer_size - lx->lx_read)
309 % lx->buffer_size); 310 % lx->buffer_size);
310 311
311 /* then how much from the read pointer onwards */ 312 /* then how much from the read pointer onwards */
312 fl = min( count, (size_t)lx->buffer_size - lx->lx_read); 313 fl = min(count, (size_t)lx->buffer_size - lx->lx_read);
313 314
314 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;
315 318
316 /* 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 */
317 if ( count - fl ) 320 if (count - fl)
318 copy_to (buff + fl, lx->lx_buffer, count - fl, user); 321 failed = copy_to_user(buff + fl, lx->lx_buffer, count - fl);
319 322
320 /* update the index */ 323out:
321 lx->lx_read += count; 324 count -= failed;
322 lx->lx_read %= lx->buffer_size; 325
326 smp_wmb();
327 lx->lx_read = (lx->lx_read + count) % lx->buffer_size;
328 smp_wmb();
329 mutex_unlock(&channel_wqs[index].mutex);
323 330
324 return count; 331 return count;
325} 332}
326 333
327ssize_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, int user)
328{ 335{
329 struct rtlx_channel *rt; 336 struct rtlx_channel *rt;
337 size_t rt_read;
330 size_t fl; 338 size_t fl;
331 339
332 if (rtlx == NULL) 340 if (rtlx == NULL)
@@ -334,24 +342,35 @@ ssize_t rtlx_write(int index, void *buffer, size_t count, int user)
334 342
335 rt = &rtlx->channel[index]; 343 rt = &rtlx->channel[index];
336 344
345 mutex_lock(&channel_wqs[index].mutex);
346 smp_rmb();
347 rt_read = rt->rt_read;
348
337 /* total number of bytes to copy */ 349 /* total number of bytes to copy */
338 count = min(count, 350 count = min(count,
339 (size_t)write_spacefree(rt->rt_read, rt->rt_write, 351 (size_t)write_spacefree(rt_read, rt->rt_write, rt->buffer_size));
340 rt->buffer_size));
341 352
342 /* first bit from write pointer to the end of the buffer, or count */ 353 /* first bit from write pointer to the end of the buffer, or count */
343 fl = min(count, (size_t) rt->buffer_size - rt->rt_write); 354 fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
344 355
345 copy_from (&rt->rt_buffer[rt->rt_write], buffer, fl, user); 356 failed = copy_from_user(rt->rt_buffer + rt->rt_write, buffer, fl);
357 if (failed)
358 goto out;
346 359
347 /* if there's any left copy to the beginning of the buffer */ 360 /* if there's any left copy to the beginning of the buffer */
348 if( count - fl ) 361 if (count - fl) {
349 copy_from (rt->rt_buffer, buffer + fl, count - fl, user); 362 failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl);
363 }
364
365out:
366 count -= cailed;
350 367
351 rt->rt_write += count; 368 smp_wmb();
352 rt->rt_write %= rt->buffer_size; 369 rt->rt_write = (rt->rt_write + count) % rt->buffer_size;
370 smp_wmb();
371 mutex_unlock(&channel_wqs[index].mutex);
353 372
354 return(count); 373 return count;
355} 374}
356 375
357 376
@@ -403,7 +422,7 @@ static ssize_t file_read(struct file *file, char __user * buffer, size_t count,
403 return 0; // -EAGAIN makes cat whinge 422 return 0; // -EAGAIN makes cat whinge
404 } 423 }
405 424
406 return rtlx_read(minor, buffer, count, 1); 425 return rtlx_read(minor, buffer, count);
407} 426}
408 427
409static ssize_t file_write(struct file *file, const char __user * buffer, 428static ssize_t file_write(struct file *file, const char __user * buffer,
@@ -429,7 +448,7 @@ static ssize_t file_write(struct file *file, const char __user * buffer,
429 return ret; 448 return ret;
430 } 449 }
431 450
432 return rtlx_write(minor, (void *)buffer, count, 1); 451 return rtlx_write(minor, buffer, count);
433} 452}
434 453
435static const struct file_operations rtlx_fops = { 454static const struct file_operations rtlx_fops = {
@@ -468,6 +487,7 @@ static int rtlx_module_init(void)
468 init_waitqueue_head(&channel_wqs[i].rt_queue); 487 init_waitqueue_head(&channel_wqs[i].rt_queue);
469 init_waitqueue_head(&channel_wqs[i].lx_queue); 488 init_waitqueue_head(&channel_wqs[i].lx_queue);
470 atomic_set(&channel_wqs[i].in_open, 0); 489 atomic_set(&channel_wqs[i].in_open, 0);
490 mutex_init(&channel_wqs[i].mutex);
471 491
472 dev = device_create(mt_class, NULL, MKDEV(major, i), 492 dev = device_create(mt_class, NULL, MKDEV(major, i),
473 "%s%d", module_name, i); 493 "%s%d", module_name, i);