OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [mips/] [kernel/] [rtlx.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
2
 * Copyright (C) 2005 MIPS Technologies, Inc.  All rights reserved.
3
 * Copyright (C) 2005, 06 Ralf Baechle (ralf@linux-mips.org)
4
 *
5
 *  This program is free software; you can distribute it and/or modify it
6
 *  under the terms of the GNU General Public License (Version 2) as
7
 *  published by the Free Software Foundation.
8
 *
9
 *  This program is distributed in the hope it will be useful, but WITHOUT
10
 *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
 *  for more details.
13
 *
14
 *  You should have received a copy of the GNU General Public License along
15
 *  with this program; if not, write to the Free Software Foundation, Inc.,
16
 *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
17
 *
18
 */
19
 
20
#include <linux/device.h>
21
#include <linux/kernel.h>
22
#include <linux/module.h>
23
#include <linux/fs.h>
24
#include <linux/init.h>
25
#include <asm/uaccess.h>
26
#include <linux/slab.h>
27
#include <linux/list.h>
28
#include <linux/vmalloc.h>
29
#include <linux/elf.h>
30
#include <linux/seq_file.h>
31
#include <linux/syscalls.h>
32
#include <linux/moduleloader.h>
33
#include <linux/interrupt.h>
34
#include <linux/poll.h>
35
#include <linux/sched.h>
36
#include <linux/wait.h>
37
#include <asm/mipsmtregs.h>
38
#include <asm/mips_mt.h>
39
#include <asm/cacheflush.h>
40
#include <asm/atomic.h>
41
#include <asm/cpu.h>
42
#include <asm/processor.h>
43
#include <asm/mips_mt.h>
44
#include <asm/system.h>
45
#include <asm/vpe.h>
46
#include <asm/rtlx.h>
47
 
48
static struct rtlx_info *rtlx;
49
static int major;
50
static char module_name[] = "rtlx";
51
 
52
static struct chan_waitqueues {
53
        wait_queue_head_t rt_queue;
54
        wait_queue_head_t lx_queue;
55
        atomic_t in_open;
56
        struct mutex mutex;
57
} channel_wqs[RTLX_CHANNELS];
58
 
59
static struct vpe_notifications notify;
60
static int sp_stopping = 0;
61
 
62
extern void *vpe_get_shared(int index);
63
 
64
static void rtlx_dispatch(void)
65
{
66
        do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ);
67
}
68
 
69
 
70
/* Interrupt handler may be called before rtlx_init has otherwise had
71
   a chance to run.
72
*/
73
static irqreturn_t rtlx_interrupt(int irq, void *dev_id)
74
{
75
        int i;
76
 
77
        for (i = 0; i < RTLX_CHANNELS; i++) {
78
                        wake_up(&channel_wqs[i].lx_queue);
79
                        wake_up(&channel_wqs[i].rt_queue);
80
        }
81
 
82
        return IRQ_HANDLED;
83
}
84
 
85
static void __used dump_rtlx(void)
86
{
87
        int i;
88
 
89
        printk("id 0x%lx state %d\n", rtlx->id, rtlx->state);
90
 
91
        for (i = 0; i < RTLX_CHANNELS; i++) {
92
                struct rtlx_channel *chan = &rtlx->channel[i];
93
 
94
                printk(" rt_state %d lx_state %d buffer_size %d\n",
95
                       chan->rt_state, chan->lx_state, chan->buffer_size);
96
 
97
                printk(" rt_read %d rt_write %d\n",
98
                       chan->rt_read, chan->rt_write);
99
 
100
                printk(" lx_read %d lx_write %d\n",
101
                       chan->lx_read, chan->lx_write);
102
 
103
                printk(" rt_buffer <%s>\n", chan->rt_buffer);
104
                printk(" lx_buffer <%s>\n", chan->lx_buffer);
105
        }
106
}
107
 
108
/* call when we have the address of the shared structure from the SP side. */
109
static int rtlx_init(struct rtlx_info *rtlxi)
110
{
111
        if (rtlxi->id != RTLX_ID) {
112
                printk(KERN_ERR "no valid RTLX id at 0x%p 0x%lx\n", rtlxi, rtlxi->id);
113
                return -ENOEXEC;
114
        }
115
 
116
        rtlx = rtlxi;
117
 
118
        return 0;
119
}
120
 
121
/* notifications */
122
static void starting(int vpe)
123
{
124
        int i;
125
        sp_stopping = 0;
126
 
127
        /* force a reload of rtlx */
128
        rtlx=NULL;
129
 
130
        /* wake up any sleeping rtlx_open's */
131
        for (i = 0; i < RTLX_CHANNELS; i++)
132
                wake_up_interruptible(&channel_wqs[i].lx_queue);
133
}
134
 
135
static void stopping(int vpe)
136
{
137
        int i;
138
 
139
        sp_stopping = 1;
140
        for (i = 0; i < RTLX_CHANNELS; i++)
141
                wake_up_interruptible(&channel_wqs[i].lx_queue);
142
}
143
 
144
 
145
int rtlx_open(int index, int can_sleep)
146
{
147
        struct rtlx_info **p;
148
        struct rtlx_channel *chan;
149
        enum rtlx_state state;
150
        int ret = 0;
151
 
152
        if (index >= RTLX_CHANNELS) {
153
                printk(KERN_DEBUG "rtlx_open index out of range\n");
154
                return -ENOSYS;
155
        }
156
 
157
        if (atomic_inc_return(&channel_wqs[index].in_open) > 1) {
158
                printk(KERN_DEBUG "rtlx_open channel %d already opened\n",
159
                       index);
160
                ret = -EBUSY;
161
                goto out_fail;
162
        }
163
 
164
        if (rtlx == NULL) {
165
                if( (p = vpe_get_shared(tclimit)) == NULL) {
166
                        if (can_sleep) {
167
                                __wait_event_interruptible(channel_wqs[index].lx_queue,
168
                                                           (p = vpe_get_shared(tclimit)),
169
                                                           ret);
170
                                if (ret)
171
                                        goto out_fail;
172
                        } else {
173
                                printk(KERN_DEBUG "No SP program loaded, and device "
174
                                        "opened with O_NONBLOCK\n");
175
                                ret = -ENOSYS;
176
                                goto out_fail;
177
                        }
178
                }
179
 
180
                smp_rmb();
181
                if (*p == NULL) {
182
                        if (can_sleep) {
183
                                DEFINE_WAIT(wait);
184
 
185
                                for (;;) {
186
                                        prepare_to_wait(&channel_wqs[index].lx_queue, &wait, TASK_INTERRUPTIBLE);
187
                                        smp_rmb();
188
                                        if (*p != NULL)
189
                                                break;
190
                                        if (!signal_pending(current)) {
191
                                                schedule();
192
                                                continue;
193
                                        }
194
                                        ret = -ERESTARTSYS;
195
                                        goto out_fail;
196
                                }
197
                                finish_wait(&channel_wqs[index].lx_queue, &wait);
198
                        } else {
199
                                printk(" *vpe_get_shared is NULL. "
200
                                       "Has an SP program been loaded?\n");
201
                                ret = -ENOSYS;
202
                                goto out_fail;
203
                        }
204
                }
205
 
206
                if ((unsigned int)*p < KSEG0) {
207
                        printk(KERN_WARNING "vpe_get_shared returned an invalid pointer "
208
                               "maybe an error code %d\n", (int)*p);
209
                        ret = -ENOSYS;
210
                        goto out_fail;
211
                }
212
 
213
                if ((ret = rtlx_init(*p)) < 0)
214
                        goto out_ret;
215
        }
216
 
217
        chan = &rtlx->channel[index];
218
 
219
        state = xchg(&chan->lx_state, RTLX_STATE_OPENED);
220
        if (state == RTLX_STATE_OPENED) {
221
                ret = -EBUSY;
222
                goto out_fail;
223
        }
224
 
225
out_fail:
226
        smp_mb();
227
        atomic_dec(&channel_wqs[index].in_open);
228
        smp_mb();
229
 
230
out_ret:
231
        return ret;
232
}
233
 
234
int rtlx_release(int index)
235
{
236
        rtlx->channel[index].lx_state = RTLX_STATE_UNUSED;
237
        return 0;
238
}
239
 
240
unsigned int rtlx_read_poll(int index, int can_sleep)
241
{
242
        struct rtlx_channel *chan;
243
 
244
        if (rtlx == NULL)
245
                return 0;
246
 
247
        chan = &rtlx->channel[index];
248
 
249
        /* data available to read? */
250
        if (chan->lx_read == chan->lx_write) {
251
                if (can_sleep) {
252
                        int ret = 0;
253
 
254
                        __wait_event_interruptible(channel_wqs[index].lx_queue,
255
                                                   chan->lx_read != chan->lx_write || sp_stopping,
256
                                                   ret);
257
                        if (ret)
258
                                return ret;
259
 
260
                        if (sp_stopping)
261
                                return 0;
262
                } else
263
                        return 0;
264
        }
265
 
266
        return (chan->lx_write + chan->buffer_size - chan->lx_read)
267
               % chan->buffer_size;
268
}
269
 
270
static inline int write_spacefree(int read, int write, int size)
271
{
272
        if (read == write) {
273
                /*
274
                 * Never fill the buffer completely, so indexes are always
275
                 * equal if empty and only empty, or !equal if data available
276
                 */
277
                return size - 1;
278
        }
279
 
280
        return ((read + size - write) % size) - 1;
281
}
282
 
283
unsigned int rtlx_write_poll(int index)
284
{
285
        struct rtlx_channel *chan = &rtlx->channel[index];
286
        return write_spacefree(chan->rt_read, chan->rt_write, chan->buffer_size);
287
}
288
 
289
ssize_t rtlx_read(int index, void __user *buff, size_t count)
290
{
291
        size_t lx_write, fl = 0L;
292
        struct rtlx_channel *lx;
293
        unsigned long failed;
294
 
295
        if (rtlx == NULL)
296
                return -ENOSYS;
297
 
298
        lx = &rtlx->channel[index];
299
 
300
        mutex_lock(&channel_wqs[index].mutex);
301
        smp_rmb();
302
        lx_write = lx->lx_write;
303
 
304
        /* find out how much in total */
305
        count = min(count,
306
                     (size_t)(lx_write + lx->buffer_size - lx->lx_read)
307
                     % lx->buffer_size);
308
 
309
        /* then how much from the read pointer onwards */
310
        fl = min(count, (size_t)lx->buffer_size - lx->lx_read);
311
 
312
        failed = copy_to_user(buff, lx->lx_buffer + lx->lx_read, fl);
313
        if (failed)
314
                goto out;
315
 
316
        /* and if there is anything left at the beginning of the buffer */
317
        if (count - fl)
318
                failed = copy_to_user(buff + fl, lx->lx_buffer, count - fl);
319
 
320
out:
321
        count -= failed;
322
 
323
        smp_wmb();
324
        lx->lx_read = (lx->lx_read + count) % lx->buffer_size;
325
        smp_wmb();
326
        mutex_unlock(&channel_wqs[index].mutex);
327
 
328
        return count;
329
}
330
 
331
ssize_t rtlx_write(int index, const void __user *buffer, size_t count)
332
{
333
        struct rtlx_channel *rt;
334
        unsigned long failed;
335
        size_t rt_read;
336
        size_t fl;
337
 
338
        if (rtlx == NULL)
339
                return(-ENOSYS);
340
 
341
        rt = &rtlx->channel[index];
342
 
343
        mutex_lock(&channel_wqs[index].mutex);
344
        smp_rmb();
345
        rt_read = rt->rt_read;
346
 
347
        /* total number of bytes to copy */
348
        count = min(count,
349
                    (size_t)write_spacefree(rt_read, rt->rt_write, rt->buffer_size));
350
 
351
        /* first bit from write pointer to the end of the buffer, or count */
352
        fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
353
 
354
        failed = copy_from_user(rt->rt_buffer + rt->rt_write, buffer, fl);
355
        if (failed)
356
                goto out;
357
 
358
        /* if there's any left copy to the beginning of the buffer */
359
        if (count - fl) {
360
                failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl);
361
        }
362
 
363
out:
364
        count -= failed;
365
 
366
        smp_wmb();
367
        rt->rt_write = (rt->rt_write + count) % rt->buffer_size;
368
        smp_wmb();
369
        mutex_unlock(&channel_wqs[index].mutex);
370
 
371
        return count;
372
}
373
 
374
 
375
static int file_open(struct inode *inode, struct file *filp)
376
{
377
        int minor = iminor(inode);
378
 
379
        return rtlx_open(minor, (filp->f_flags & O_NONBLOCK) ? 0 : 1);
380
}
381
 
382
static int file_release(struct inode *inode, struct file *filp)
383
{
384
        int minor = iminor(inode);
385
 
386
        return rtlx_release(minor);
387
}
388
 
389
static unsigned int file_poll(struct file *file, poll_table * wait)
390
{
391
        int minor;
392
        unsigned int mask = 0;
393
 
394
        minor = iminor(file->f_path.dentry->d_inode);
395
 
396
        poll_wait(file, &channel_wqs[minor].rt_queue, wait);
397
        poll_wait(file, &channel_wqs[minor].lx_queue, wait);
398
 
399
        if (rtlx == NULL)
400
                return 0;
401
 
402
        /* data available to read? */
403
        if (rtlx_read_poll(minor, 0))
404
                mask |= POLLIN | POLLRDNORM;
405
 
406
        /* space to write */
407
        if (rtlx_write_poll(minor))
408
                mask |= POLLOUT | POLLWRNORM;
409
 
410
        return mask;
411
}
412
 
413
static ssize_t file_read(struct file *file, char __user * buffer, size_t count,
414
                         loff_t * ppos)
415
{
416
        int minor = iminor(file->f_path.dentry->d_inode);
417
 
418
        /* data available? */
419
        if (!rtlx_read_poll(minor, (file->f_flags & O_NONBLOCK) ? 0 : 1)) {
420
                return 0;        // -EAGAIN makes cat whinge
421
        }
422
 
423
        return rtlx_read(minor, buffer, count);
424
}
425
 
426
static ssize_t file_write(struct file *file, const char __user * buffer,
427
                          size_t count, loff_t * ppos)
428
{
429
        int minor;
430
        struct rtlx_channel *rt;
431
 
432
        minor = iminor(file->f_path.dentry->d_inode);
433
        rt = &rtlx->channel[minor];
434
 
435
        /* any space left... */
436
        if (!rtlx_write_poll(minor)) {
437
                int ret = 0;
438
 
439
                if (file->f_flags & O_NONBLOCK)
440
                        return -EAGAIN;
441
 
442
                __wait_event_interruptible(channel_wqs[minor].rt_queue,
443
                                           rtlx_write_poll(minor),
444
                                           ret);
445
                if (ret)
446
                        return ret;
447
        }
448
 
449
        return rtlx_write(minor, buffer, count);
450
}
451
 
452
static const struct file_operations rtlx_fops = {
453
        .owner =   THIS_MODULE,
454
        .open =    file_open,
455
        .release = file_release,
456
        .write =   file_write,
457
        .read =    file_read,
458
        .poll =    file_poll
459
};
460
 
461
static struct irqaction rtlx_irq = {
462
        .handler        = rtlx_interrupt,
463
        .flags          = IRQF_DISABLED,
464
        .name           = "RTLX",
465
};
466
 
467
static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ;
468
 
469
static char register_chrdev_failed[] __initdata =
470
        KERN_ERR "rtlx_module_init: unable to register device\n";
471
 
472
static int __init rtlx_module_init(void)
473
{
474
        struct device *dev;
475
        int i, err;
476
 
477
        if (!cpu_has_mipsmt) {
478
                printk("VPE loader: not a MIPS MT capable processor\n");
479
                return -ENODEV;
480
        }
481
 
482
        if (tclimit == 0) {
483
                printk(KERN_WARNING "No TCs reserved for AP/SP, not "
484
                       "initializing RTLX.\nPass maxtcs=<n> argument as kernel "
485
                       "argument\n");
486
 
487
                return -ENODEV;
488
        }
489
 
490
        major = register_chrdev(0, module_name, &rtlx_fops);
491
        if (major < 0) {
492
                printk(register_chrdev_failed);
493
                return major;
494
        }
495
 
496
        /* initialise the wait queues */
497
        for (i = 0; i < RTLX_CHANNELS; i++) {
498
                init_waitqueue_head(&channel_wqs[i].rt_queue);
499
                init_waitqueue_head(&channel_wqs[i].lx_queue);
500
                atomic_set(&channel_wqs[i].in_open, 0);
501
                mutex_init(&channel_wqs[i].mutex);
502
 
503
                dev = device_create(mt_class, NULL, MKDEV(major, i),
504
                                    "%s%d", module_name, i);
505
                if (IS_ERR(dev)) {
506
                        err = PTR_ERR(dev);
507
                        goto out_chrdev;
508
                }
509
        }
510
 
511
        /* set up notifiers */
512
        notify.start = starting;
513
        notify.stop = stopping;
514
        vpe_notify(tclimit, &notify);
515
 
516
        if (cpu_has_vint)
517
                set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch);
518
 
519
        rtlx_irq.dev_id = rtlx;
520
        setup_irq(rtlx_irq_num, &rtlx_irq);
521
 
522
        return 0;
523
 
524
out_chrdev:
525
        for (i = 0; i < RTLX_CHANNELS; i++)
526
                device_destroy(mt_class, MKDEV(major, i));
527
 
528
        return err;
529
}
530
 
531
static void __exit rtlx_module_exit(void)
532
{
533
        int i;
534
 
535
        for (i = 0; i < RTLX_CHANNELS; i++)
536
                device_destroy(mt_class, MKDEV(major, i));
537
 
538
        unregister_chrdev(major, module_name);
539
}
540
 
541
module_init(rtlx_module_init);
542
module_exit(rtlx_module_exit);
543
 
544
MODULE_DESCRIPTION("MIPS RTLX");
545
MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc.");
546
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.