aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/kernel/rtlx.c197
1 files changed, 93 insertions, 104 deletions
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index 8c81f3cb4e2d..1d855112bac2 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -20,42 +20,42 @@
20#include <linux/module.h> 20#include <linux/module.h>
21#include <linux/fs.h> 21#include <linux/fs.h>
22#include <linux/init.h> 22#include <linux/init.h>
23#include <asm/uaccess.h>
24#include <linux/slab.h>
25#include <linux/list.h>
26#include <linux/vmalloc.h>
27#include <linux/elf.h>
28#include <linux/seq_file.h>
29#include <linux/syscalls.h>
30#include <linux/moduleloader.h>
31#include <linux/interrupt.h>
32#include <linux/poll.h> 23#include <linux/poll.h>
33#include <linux/sched.h> 24#include <linux/sched.h>
34#include <linux/wait.h> 25#include <linux/wait.h>
35#include <asm/mipsmtregs.h> 26#include <asm/mipsmtregs.h>
36#include <asm/cacheflush.h> 27#include <asm/bitops.h>
37#include <asm/atomic.h>
38#include <asm/cpu.h> 28#include <asm/cpu.h>
39#include <asm/processor.h> 29#include <asm/processor.h>
40#include <asm/system.h>
41#include <asm/rtlx.h> 30#include <asm/rtlx.h>
31#include <asm/uaccess.h>
42 32
43#define RTLX_MAJOR 64
44#define RTLX_TARG_VPE 1 33#define RTLX_TARG_VPE 1
45 34
46struct rtlx_info *rtlx; 35static struct rtlx_info *rtlx;
47static int major; 36static int major;
48static char module_name[] = "rtlx"; 37static char module_name[] = "rtlx";
49static inline int spacefree(int read, int write, int size); 38static struct irqaction irq;
39static int irq_num;
40
41static inline int spacefree(int read, int write, int size)
42{
43 if (read == write) {
44 /*
45 * never fill the buffer completely, so indexes are always
46 * equal if empty and only empty, or !equal if data available
47 */
48 return size - 1;
49 }
50
51 return ((read + size - write) % size) - 1;
52}
50 53
51static struct chan_waitqueues { 54static struct chan_waitqueues {
52 wait_queue_head_t rt_queue; 55 wait_queue_head_t rt_queue;
53 wait_queue_head_t lx_queue; 56 wait_queue_head_t lx_queue;
54} channel_wqs[RTLX_CHANNELS]; 57} channel_wqs[RTLX_CHANNELS];
55 58
56static struct irqaction irq;
57static int irq_num;
58
59extern void *vpe_get_shared(int index); 59extern void *vpe_get_shared(int index);
60 60
61static void rtlx_dispatch(struct pt_regs *regs) 61static void rtlx_dispatch(struct pt_regs *regs)
@@ -63,9 +63,8 @@ static void rtlx_dispatch(struct pt_regs *regs)
63 do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs); 63 do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs);
64} 64}
65 65
66irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs) 66static irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
67{ 67{
68 irqreturn_t r = IRQ_HANDLED;
69 int i; 68 int i;
70 69
71 for (i = 0; i < RTLX_CHANNELS; i++) { 70 for (i = 0; i < RTLX_CHANNELS; i++) {
@@ -75,30 +74,7 @@ irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
75 wake_up_interruptible(&channel_wqs[i].lx_queue); 74 wake_up_interruptible(&channel_wqs[i].lx_queue);
76 } 75 }
77 76
78 return r; 77 return IRQ_HANDLED;
79}
80
81void dump_rtlx(void)
82{
83 int i;
84
85 printk("id 0x%lx state %d\n", rtlx->id, rtlx->state);
86
87 for (i = 0; i < RTLX_CHANNELS; i++) {
88 struct rtlx_channel *chan = &rtlx->channel[i];
89
90 printk(" rt_state %d lx_state %d buffer_size %d\n",
91 chan->rt_state, chan->lx_state, chan->buffer_size);
92
93 printk(" rt_read %d rt_write %d\n",
94 chan->rt_read, chan->rt_write);
95
96 printk(" lx_read %d lx_write %d\n",
97 chan->lx_read, chan->lx_write);
98
99 printk(" rt_buffer <%s>\n", chan->rt_buffer);
100 printk(" lx_buffer <%s>\n", chan->lx_buffer);
101 }
102} 78}
103 79
104/* call when we have the address of the shared structure from the SP side. */ 80/* call when we have the address of the shared structure from the SP side. */
@@ -108,7 +84,7 @@ static int rtlx_init(struct rtlx_info *rtlxi)
108 84
109 if (rtlxi->id != RTLX_ID) { 85 if (rtlxi->id != RTLX_ID) {
110 printk(KERN_WARNING "no valid RTLX id at 0x%p\n", rtlxi); 86 printk(KERN_WARNING "no valid RTLX id at 0x%p\n", rtlxi);
111 return (-ENOEXEC); 87 return -ENOEXEC;
112 } 88 }
113 89
114 /* initialise the wait queues */ 90 /* initialise the wait queues */
@@ -120,9 +96,8 @@ static int rtlx_init(struct rtlx_info *rtlxi)
120 /* set up for interrupt handling */ 96 /* set up for interrupt handling */
121 memset(&irq, 0, sizeof(struct irqaction)); 97 memset(&irq, 0, sizeof(struct irqaction));
122 98
123 if (cpu_has_vint) { 99 if (cpu_has_vint)
124 set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch); 100 set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch);
125 }
126 101
127 irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ; 102 irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ;
128 irq.handler = rtlx_interrupt; 103 irq.handler = rtlx_interrupt;
@@ -132,7 +107,8 @@ static int rtlx_init(struct rtlx_info *rtlxi)
132 setup_irq(irq_num, &irq); 107 setup_irq(irq_num, &irq);
133 108
134 rtlx = rtlxi; 109 rtlx = rtlxi;
135 return (0); 110
111 return 0;
136} 112}
137 113
138/* only allow one open process at a time to open each channel */ 114/* only allow one open process at a time to open each channel */
@@ -147,36 +123,36 @@ static int rtlx_open(struct inode *inode, struct file *filp)
147 if (rtlx == NULL) { 123 if (rtlx == NULL) {
148 struct rtlx_info **p; 124 struct rtlx_info **p;
149 if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) { 125 if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
150 printk(" vpe_get_shared is NULL. Has an SP program been loaded?\n"); 126 printk(KERN_ERR "vpe_get_shared is NULL. "
151 return (-EFAULT); 127 "Has an SP program been loaded?\n");
128 return -EFAULT;
152 } 129 }
153 130
154 if (*p == NULL) { 131 if (*p == NULL) {
155 printk(" vpe_shared %p %p\n", p, *p); 132 printk(KERN_ERR "vpe_shared %p %p\n", p, *p);
156 return (-EFAULT); 133 return -EFAULT;
157 } 134 }
158 135
159 if ((ret = rtlx_init(*p)) < 0) 136 if ((ret = rtlx_init(*p)) < 0)
160 return (ret); 137 return ret;
161 } 138 }
162 139
163 chan = &rtlx->channel[minor]; 140 chan = &rtlx->channel[minor];
164 141
165 /* already open? */ 142 if (test_and_set_bit(RTLX_STATE_OPENED, &chan->lx_state))
166 if (chan->lx_state == RTLX_STATE_OPENED) 143 return -EBUSY;
167 return (-EBUSY);
168 144
169 chan->lx_state = RTLX_STATE_OPENED; 145 return 0;
170 return (0);
171} 146}
172 147
173static int rtlx_release(struct inode *inode, struct file *filp) 148static int rtlx_release(struct inode *inode, struct file *filp)
174{ 149{
175 int minor; 150 int minor = MINOR(inode->i_rdev);
176 151
177 minor = MINOR(inode->i_rdev); 152 clear_bit(RTLX_STATE_OPENED, &rtlx->channel[minor].lx_state);
178 rtlx->channel[minor].lx_state = RTLX_STATE_UNUSED; 153 smp_mb__after_clear_bit();
179 return (0); 154
155 return 0;
180} 156}
181 157
182static unsigned int rtlx_poll(struct file *file, poll_table * wait) 158static unsigned int rtlx_poll(struct file *file, poll_table * wait)
@@ -199,12 +175,13 @@ static unsigned int rtlx_poll(struct file *file, poll_table * wait)
199 if (spacefree(chan->rt_read, chan->rt_write, chan->buffer_size)) 175 if (spacefree(chan->rt_read, chan->rt_write, chan->buffer_size))
200 mask |= POLLOUT | POLLWRNORM; 176 mask |= POLLOUT | POLLWRNORM;
201 177
202 return (mask); 178 return mask;
203} 179}
204 180
205static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count, 181static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count,
206 loff_t * ppos) 182 loff_t * ppos)
207{ 183{
184 unsigned long failed;
208 size_t fl = 0L; 185 size_t fl = 0L;
209 int minor; 186 int minor;
210 struct rtlx_channel *lx; 187 struct rtlx_channel *lx;
@@ -216,7 +193,7 @@ static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count,
216 /* data available? */ 193 /* data available? */
217 if (lx->lx_write == lx->lx_read) { 194 if (lx->lx_write == lx->lx_read) {
218 if (file->f_flags & O_NONBLOCK) 195 if (file->f_flags & O_NONBLOCK)
219 return (0); // -EAGAIN makes cat whinge 196 return 0; /* -EAGAIN makes cat whinge */
220 197
221 /* go to sleep */ 198 /* go to sleep */
222 add_wait_queue(&channel_wqs[minor].lx_queue, &wait); 199 add_wait_queue(&channel_wqs[minor].lx_queue, &wait);
@@ -232,39 +209,39 @@ static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count,
232 } 209 }
233 210
234 /* find out how much in total */ 211 /* find out how much in total */
235 count = min( count, 212 count = min(count,
236 (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) % lx->buffer_size); 213 (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) % lx->buffer_size);
237 214
238 /* then how much from the read pointer onwards */ 215 /* then how much from the read pointer onwards */
239 fl = min( count, (size_t)lx->buffer_size - lx->lx_read); 216 fl = min(count, (size_t)lx->buffer_size - lx->lx_read);
240 217
241 copy_to_user (buffer, &lx->lx_buffer[lx->lx_read], fl); 218 failed = copy_to_user (buffer, &lx->lx_buffer[lx->lx_read], fl);
219 if (failed) {
220 count = fl - failed;
221 goto out;
222 }
242 223
243 /* and if there is anything left at the beginning of the buffer */ 224 /* and if there is anything left at the beginning of the buffer */
244 if ( count - fl ) 225 if (count - fl) {
245 copy_to_user (buffer + fl, lx->lx_buffer, count - fl); 226 failed = copy_to_user (buffer + fl, lx->lx_buffer, count - fl);
227 if (failed) {
228 count -= failed;
229 goto out;
230 }
231 }
246 232
233out:
247 /* update the index */ 234 /* update the index */
248 lx->lx_read += count; 235 lx->lx_read += count;
249 lx->lx_read %= lx->buffer_size; 236 lx->lx_read %= lx->buffer_size;
250 237
251 return (count); 238 return count;
252}
253
254static inline int spacefree(int read, int write, int size)
255{
256 if (read == write) {
257 /* never fill the buffer completely, so indexes are always equal if empty
258 and only empty, or !equal if data available */
259 return (size - 1);
260 }
261
262 return ((read + size - write) % size) - 1;
263} 239}
264 240
265static ssize_t rtlx_write(struct file *file, const char __user * buffer, 241static ssize_t rtlx_write(struct file *file, const char __user * buffer,
266 size_t count, loff_t * ppos) 242 size_t count, loff_t * ppos)
267{ 243{
244 unsigned long failed;
268 int minor; 245 int minor;
269 struct rtlx_channel *rt; 246 struct rtlx_channel *rt;
270 size_t fl; 247 size_t fl;
@@ -277,7 +254,7 @@ static ssize_t rtlx_write(struct file *file, const char __user * buffer,
277 if (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size)) { 254 if (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size)) {
278 255
279 if (file->f_flags & O_NONBLOCK) 256 if (file->f_flags & O_NONBLOCK)
280 return (-EAGAIN); 257 return -EAGAIN;
281 258
282 add_wait_queue(&channel_wqs[minor].rt_queue, &wait); 259 add_wait_queue(&channel_wqs[minor].rt_queue, &wait);
283 set_current_state(TASK_INTERRUPTIBLE); 260 set_current_state(TASK_INTERRUPTIBLE);
@@ -290,52 +267,64 @@ static ssize_t rtlx_write(struct file *file, const char __user * buffer,
290 } 267 }
291 268
292 /* total number of bytes to copy */ 269 /* total number of bytes to copy */
293 count = min( count, (size_t)spacefree(rt->rt_read, rt->rt_write, rt->buffer_size) ); 270 count = min(count, (size_t)spacefree(rt->rt_read, rt->rt_write, rt->buffer_size) );
294 271
295 /* first bit from write pointer to the end of the buffer, or count */ 272 /* first bit from write pointer to the end of the buffer, or count */
296 fl = min(count, (size_t) rt->buffer_size - rt->rt_write); 273 fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
297 274
298 copy_from_user(&rt->rt_buffer[rt->rt_write], buffer, fl); 275 failed = copy_from_user(&rt->rt_buffer[rt->rt_write], buffer, fl);
276 if (failed) {
277 count = fl - failed;
278 goto out;
279 }
299 280
300 /* if there's any left copy to the beginning of the buffer */ 281 /* if there's any left copy to the beginning of the buffer */
301 if( count - fl ) 282 if (count - fl) {
302 copy_from_user(rt->rt_buffer, buffer + fl, count - fl); 283 failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl);
284 if (failed) {
285 count -= failed;
286 goto out;
287 }
288 }
303 289
290out:
304 rt->rt_write += count; 291 rt->rt_write += count;
305 rt->rt_write %= rt->buffer_size; 292 rt->rt_write %= rt->buffer_size;
306 293
307 return(count); 294 return count;
308} 295}
309 296
310static struct file_operations rtlx_fops = { 297static struct file_operations rtlx_fops = {
311 .owner = THIS_MODULE, 298 .owner = THIS_MODULE,
312 .open = rtlx_open, 299 .open = rtlx_open,
313 .release = rtlx_release, 300 .release = rtlx_release,
314 .write = rtlx_write, 301 .write = rtlx_write,
315 .read = rtlx_read, 302 .read = rtlx_read,
316 .poll = rtlx_poll 303 .poll = rtlx_poll
317}; 304};
318 305
319static int rtlx_module_init(void) 306static char register_chrdev_failed[] __initdata =
307 KERN_ERR "rtlx_module_init: unable to register device\n";
308
309static int __init rtlx_module_init(void)
320{ 310{
321 if ((major = register_chrdev(RTLX_MAJOR, module_name, &rtlx_fops)) < 0) { 311 major = register_chrdev(0, module_name, &rtlx_fops);
322 printk("rtlx_module_init: unable to register device\n"); 312 if (major < 0) {
323 return (-EBUSY); 313 printk(register_chrdev_failed);
314 return major;
324 } 315 }
325 316
326 if (major == 0) 317 return 0;
327 major = RTLX_MAJOR;
328
329 return (0);
330} 318}
331 319
332static void rtlx_module_exit(void) 320static void __exit rtlx_module_exit(void)
333{ 321{
334 unregister_chrdev(major, module_name); 322 unregister_chrdev(major, module_name);
335} 323}
336 324
337module_init(rtlx_module_init); 325module_init(rtlx_module_init);
338module_exit(rtlx_module_exit); 326module_exit(rtlx_module_exit);
327
339MODULE_DESCRIPTION("MIPS RTLX"); 328MODULE_DESCRIPTION("MIPS RTLX");
340MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc"); 329MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc.");
341MODULE_LICENSE("GPL"); 330MODULE_LICENSE("GPL");