maltalinux-cvs-patches
[Top] [All Lists]

CVS Update@linux-mips.org: malta

To: maltalinux-cvs-patches@linux-mips.org
Subject: CVS Update@linux-mips.org: malta
From: beth@linux-mips.org
Date: Wed, 27 Jul 2005 14:38:10 +0100
Reply-to: linux-mips@linux-mips.org
Sender: maltalinux-cvs-patches-bounce@linux-mips.org
CVSROOT:        /home/cvs
Module name:    malta
Changes by:     beth@ftp.linux-mips.org 05/07/27 14:38:04

Modified files:
        linux/arch/mips: Tag: MaltaRef_2_6 Kconfig 
        linux/arch/mips/kernel: Tag: MaltaRef_2_6 Makefile rtlx.c vpe.c 
        linux/include/asm-mips: Tag: MaltaRef_2_6 rtlx.h 
Added files:
        linux/arch/mips/kernel: Tag: MaltaRef_2_6 kspd.c 
        linux/include/asm-mips: Tag: MaltaRef_2_6 kspd.h vpe.h 

Log message:
        Add support for APSP file IO.

diff -urN malta/linux/arch/mips/Kconfig malta/linux/arch/mips/Kconfig
--- malta/linux/arch/mips/Kconfig       2005/06/21 13:23:39     1.73.1000.6
+++ malta/linux/arch/mips/Kconfig       2005/07/27 13:37:39     1.73.1000.7
@@ -1163,7 +1163,7 @@
        default y  
        help
          The loader can use memory that is present but has been hidden from
-         Linux using the kernel command line option "mem=xxMB". It's up to
+         Linux using the kernel command line option "memsize=xxM". It's up to
          you to ensure the amount you put in the option and the space your
          program requires is less or equal to the amount physically present.
 
@@ -1173,6 +1173,15 @@
        depends on MIPS_VPE_LOADER      
        help
 
+config MIPS_APSP_KSPD
+       bool "Enable KSPD"
+       depends on MIPS_VPE_APSP_API
+       help
+         KSPD is a kernel daemon that accepts syscall requests from the SP 
side,
+         actions them and returns the results. It also handles the "exit" 
syscall
+         notifying other kernel modules the SP program is exiting. 
+         You probably want to say yes here.
+
 config SB1_PASS_1_WORKAROUNDS
        bool
        depends on CPU_SB1_PASS_1
diff -urN malta/linux/arch/mips/kernel/kspd.c 
malta/linux/arch/mips/kernel/kspd.c
--- malta/linux/arch/mips/kernel/Attic/kspd.c   1970/01/01 00:00:00
+++ malta/linux/arch/mips/kernel/Attic/kspd.c   2005-07-27 14:37:54.201261000 
+0100     1.1.1000.1
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2005 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/unistd.h>
+#include <linux/fs.h>
+#include <linux/syscalls.h>
+#include <linux/workqueue.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+
+#include <asm/vpe.h>
+#include <asm/rtlx.h>
+#include <asm/kspd.h>
+
+static struct workqueue_struct *workqueue = NULL;
+static struct work_struct work;
+
+struct sp_request {
+       int cmd;
+       int arg0;
+       int arg1;
+       int arg2;
+       int ret;
+};
+
+static struct list_head kspd_notifylist;
+static int sp_stopping = 0;
+
+/* these should match with those in the SDE kit */
+#define MTSP_SYSCALL_BASE      0
+#define MTSP_SYSCALL_EXIT    (MTSP_SYSCALL_BASE + 0)
+#define MTSP_SYSCALL_OPEN    (MTSP_SYSCALL_BASE + 5)
+
+#define        MTSP_O_RDONLY   0x0000  
+#define        MTSP_O_WRONLY   0x0001  
+#define        MTSP_O_RDWR     0x0002  
+#define        MTSP_O_NONBLOCK 0x0004  
+#define        MTSP_O_APPEND   0x0008
+#define        MTSP_O_SHLOCK   0x0010
+#define        MTSP_O_EXLOCK   0x0020
+#define        MTSP_O_ASYNC            0x0040
+#define        MTSP_O_FSYNC            O_SYNC
+#define MTSP_O_NOFOLLOW      0x0100
+#define        MTSP_O_SYNC             0x0080
+#define        MTSP_O_CREAT            0x0200
+#define        MTSP_O_TRUNC            0x0400
+#define        MTSP_O_EXCL             0x0800
+#define        MTSP_O_BINARY   0x8000  
+
+#define SP_VPE 1
+
+struct apsp_table  {
+       int sp;
+       int ap;
+};
+
+/* we might want to do the mode flags too */
+struct apsp_table open_flags_table[] = {
+       {MTSP_O_RDWR, O_RDWR},
+       {MTSP_O_WRONLY, O_WRONLY},
+       {MTSP_O_CREAT, O_CREAT},
+       {MTSP_O_TRUNC, O_TRUNC},
+       {MTSP_O_NONBLOCK, O_NONBLOCK},
+       {MTSP_O_APPEND, O_APPEND},
+       {MTSP_O_NOFOLLOW, O_NOFOLLOW}
+};
+
+static int sp_syscall(int num, int arg0, int arg1, int arg2)
+{
+       register long int _num  __asm__ ("$2") = num;
+       register long int _arg0  __asm__ ("$4") = arg0;
+       register long int _arg1  __asm__ ("$5") = arg1;
+       register long int _arg2  __asm__ ("$6") = arg2;
+       register long int eflag  __asm__ ("$7") = 1;
+
+       mm_segment_t old_fs;
+
+       old_fs = get_fs();
+       set_fs (KERNEL_DS); 
+
+       __asm__ __volatile__ (
+               "syscall\n\t"
+               : "=r" (_num), "=r" (eflag)
+               : "r" (_num), "r" (_arg0), "r" (_arg1), "r" (_arg2)
+               );
+
+       set_fs (old_fs); 
+
+       if (eflag)
+               return -_num;
+
+       return _num;
+}
+
+static int translate_open_flags(int flags)
+{
+       int i;
+       unsigned int ret = 0;
+
+       for (i = 0; i < (sizeof(open_flags_table) / sizeof(struct apsp_table));
+            i++) {
+               if( (flags & open_flags_table[i].sp) ) {
+                       ret |= open_flags_table[i].ap;
+               }
+       }
+
+       return ret;
+}
+
+static void sp_setfsuidgid( uid_t uid, gid_t gid)
+{
+       current->fsuid = uid;
+       current->fsgid = gid;
+       
+       key_fsuid_changed(current);
+       key_fsgid_changed(current);
+}
+
+/* Expects a request to be on the sysio channel. Reads it. 
+   Decides whether its a linux syscall and runs it, or whatever. 
+   Puts the return code back into the request and sends the 
+   whole thing back.
+*/
+void sp_work_handle_request(void)
+{
+       struct sp_request spreq;
+       struct kspd_notifications *n;
+       char *vcwd;
+       mm_segment_t old_fs;
+
+       spreq.ret = -1;
+
+       if (!rtlx_read(RTLX_CHANNEL_SYSIO, &spreq, sizeof(struct sp_request), 
0)) {
+               printk(KERN_ERR "Expected request but nothing to read\n");
+               return;
+       }
+
+       /* run the syscall at the priviledge of the user who loaded the 
+          SP program */
+
+       if (vpe_getuid(SP_VPE))
+               sp_setfsuidgid( vpe_getuid(SP_VPE), vpe_getgid(SP_VPE));
+
+       /* Linux compatible syscalls can be actioned directly */
+       if ((spreq.cmd >=  __NR_Linux) && 
+           (spreq.cmd <= (__NR_Linux + __NR_Linux_syscalls))) {
+               /* its a linux syscall */
+
+               spreq.ret = sp_syscall(spreq.cmd, spreq.arg0, spreq.arg1, 
+                                         spreq.arg2);
+
+       }
+       else {
+               switch (spreq.cmd) {
+                       
+                       /* needs the flags argument translating from SDE kit to
+                          linux */
+               case MTSP_SYSCALL_OPEN:
+                       spreq.arg1 = translate_open_flags(spreq.arg1);
+
+                       vcwd = vpe_getcwd(SP_VPE);
+               
+                       /* change to the cwd of the process that loaded the SP 
program */
+                       old_fs = get_fs();
+                       set_fs (KERNEL_DS); 
+                       sys_chdir(vcwd);
+                       set_fs (old_fs); 
+
+                       spreq.ret = sp_syscall(__NR_open, spreq.arg0, 
spreq.arg1, 
+                                         spreq.arg2);
+
+                       break;
+
+               case MTSP_SYSCALL_EXIT:
+                       list_for_each_entry(n, &kspd_notifylist, list) {
+                               n->kspd_sp_exit(SP_VPE);
+                       }
+                       sp_stopping = 1;
+                       break;
+
+               default:
+                       printk(KERN_WARNING "KSPD: Invalid SP syscall number 
%d\n", 
+                              spreq.cmd);
+                       break;
+               }
+       }
+
+       if (vpe_getuid(SP_VPE))
+               sp_setfsuidgid( 0, 0);
+
+       if ((rtlx_write(RTLX_CHANNEL_SYSIO, &spreq, sizeof(struct sp_request), 
0))
+           < sizeof(struct sp_request))
+               printk("KSPD: sp_work_handle_request failed to send to SP\n");
+}
+
+static int channel_open = 0;
+
+/* the work handler */
+static void sp_work( void *data)
+{
+       if (!channel_open) {
+               if( rtlx_open(RTLX_CHANNEL_SYSIO, 1) != 0)
+                       printk("KSPD: unable to open sp channel\n");
+               else {
+                       channel_open++;
+                       printk(KERN_DEBUG "KSPD: SP channel opened\n");
+               }
+       } else {
+               /* wait for some data, allow it to sleep */
+               rtlx_read_poll(RTLX_CHANNEL_SYSIO, 1);
+
+               sp_work_handle_request();
+       }
+
+       if (!sp_stopping)
+               queue_work(workqueue, &work);
+}
+
+static void startwork(int vpe)
+{
+       sp_stopping = channel_open = 0;
+
+       if (workqueue == NULL) {
+               if ((workqueue = create_singlethread_workqueue("kspd")) == 
NULL) {
+                       printk(KERN_ERR "unable to start kspd\n");
+                       return;
+               }
+               
+               INIT_WORK(&work, sp_work, NULL);
+               queue_work(workqueue, &work);
+       }
+       else
+               queue_work(workqueue, &work);
+
+}
+
+static void stopwork(int vpe)
+{
+       sp_stopping = 1;
+
+       printk(KERN_DEBUG "KSPD: SP stopping\n");
+}
+
+void kspd_notify(struct kspd_notifications *notify)
+{
+       list_add(&notify->list, &kspd_notifylist);
+}
+
+static struct vpe_notifications notify;
+static int kspd_module_init(void)
+{
+       INIT_LIST_HEAD(&kspd_notifylist);
+
+       notify.start = startwork;
+       notify.stop = stopwork;
+       vpe_notify(SP_VPE, &notify);
+
+       return 0;
+}
+
+static void kspd_module_exit(void)
+{
+
+}
+
+module_init(kspd_module_init);
+module_exit(kspd_module_exit);
+MODULE_DESCRIPTION("MIPS KSPD");
+MODULE_AUTHOR("Elizabeth Clarke, MIPS Technologies, Inc");
+MODULE_LICENSE("GPL");
diff -urN malta/linux/arch/mips/kernel/Makefile 
malta/linux/arch/mips/kernel/Makefile
--- malta/linux/arch/mips/kernel/Makefile       2005/06/21 13:24:02     
1.80.1000.4
+++ malta/linux/arch/mips/kernel/Makefile       2005/07/27 13:37:54     
1.80.1000.5
@@ -36,6 +36,7 @@
 
 obj-$(CONFIG_MIPS_VPE_LOADER)  += vpe.o
 obj-$(CONFIG_MIPS_VPE_APSP_API)        += rtlx.o
+obj-$(CONFIG_MIPS_APSP_KSPD)   += kspd.o
 
 obj-$(CONFIG_NO_ISA)           += dma-no-isa.o
 obj-$(CONFIG_I8259)            += i8259.o
diff -urN malta/linux/arch/mips/kernel/rtlx.c 
malta/linux/arch/mips/kernel/rtlx.c
--- malta/linux/arch/mips/kernel/rtlx.c 2005/07/14 15:57:16     1.1
+++ malta/linux/arch/mips/kernel/rtlx.c 2005/07/27 13:37:54     1.1.1000.1
@@ -38,6 +38,7 @@
 #include <asm/cpu.h>
 #include <asm/processor.h>
 #include <asm/system.h>
+#include <asm/vpe.h>
 #include <asm/rtlx.h>
 
 #define RTLX_MAJOR 64
@@ -46,7 +47,7 @@
 struct rtlx_info *rtlx;
 static int major;
 static char module_name[] = "rtlx";
-static inline int spacefree(int read, int write, int size);
+static inline int write_spacefree(int read, int write, int size);
 
 static struct chan_waitqueues {
        wait_queue_head_t rt_queue;
@@ -55,23 +56,27 @@
 
 static struct irqaction irq;
 static int irq_num;
+static struct vpe_notifications notify;
+static int sp_stopping = 0;
 
 extern void *vpe_get_shared(int index);
+static int rtlx_init(struct rtlx_info *rtlxi);
 
 static void rtlx_dispatch(struct pt_regs *regs)
 {
        do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs);
 }
 
+
+/* Interrupt handler may be called before rtlx_init has otherwise had 
+   a chance to run. 
+*/
 irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
        irqreturn_t r = IRQ_HANDLED;
        int i;
 
        for (i = 0; i < RTLX_CHANNELS; i++) {
-               struct rtlx_channel *chan = &rtlx->channel[i];
-
-               if (chan->lx_read != chan->lx_write)
                        wake_up_interruptible(&channel_wqs[i].lx_queue);
        }
 
@@ -104,82 +109,247 @@
 /* call when we have the address of the shared structure from the SP side. */
 static int rtlx_init(struct rtlx_info *rtlxi)
 {
-       int i;
-
        if (rtlxi->id != RTLX_ID) {
-               printk(KERN_WARNING "no valid RTLX id at 0x%p\n", rtlxi);
-               return (-ENOEXEC);
+               printk(KERN_ERR "no valid RTLX id at 0x%p\n", rtlxi);
+               return -ENOEXEC;
        }
 
-       /* initialise the wait queues */
-       for (i = 0; i < RTLX_CHANNELS; i++) {
-               init_waitqueue_head(&channel_wqs[i].rt_queue);
-               init_waitqueue_head(&channel_wqs[i].lx_queue);
-       }
+       rtlx = rtlxi;
+       return 0;
+}
 
-       /* set up for interrupt handling */
-       memset(&irq, 0, sizeof(struct irqaction));
+/* notifications */
+static void starting(int vpe)
+{
+       int i;
+       sp_stopping = 0;
 
-       if (cpu_has_vint) {
-               set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch);
-       }
+       /* force a reload of rtlx */
+       rtlx=NULL;
 
-       irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ;
-       irq.handler = rtlx_interrupt;
-       irq.flags = SA_INTERRUPT;
-       irq.name = "RTLX";
-       irq.dev_id = rtlx;
-       setup_irq(irq_num, &irq);
+       /* wake up any sleeping rtlx_open's */
+       for (i = 0; i < RTLX_CHANNELS; i++)
+               wake_up_interruptible(&channel_wqs[i].lx_queue);
+}
+static void stopping(int vpe)
+{
+       int i;
 
-       rtlx = rtlxi;
-       return (0);
+       sp_stopping = 1;
+       for (i = 0; i < RTLX_CHANNELS; i++)
+               wake_up_interruptible(&channel_wqs[i].lx_queue);
 }
 
-/* only allow one open process at a time to open each channel */
-static int rtlx_open(struct inode *inode, struct file *filp)
+
+int rtlx_open(int index, int can_sleep)
 {
-       int minor, ret;
+       int ret;
        struct rtlx_channel *chan;
-
-       /* assume only 1 device at the mo. */
-       minor = MINOR(inode->i_rdev);
+       volatile struct rtlx_info **p;
 
        if (rtlx == NULL) {
-               struct rtlx_info **p;
                if( (p = vpe_get_shared(RTLX_TARG_VPE)) == NULL) {
-                       printk(" vpe_get_shared is NULL. Has an SP program been 
loaded?\n");
-                       return (-EFAULT);
+                       if (can_sleep) {
+                               DECLARE_WAITQUEUE(wait, current);
+                               
+                               /* go to sleep */
+                               add_wait_queue(&channel_wqs[index].lx_queue, 
&wait);
+                               
+                               set_current_state(TASK_INTERRUPTIBLE);
+                               while ((p = vpe_get_shared(RTLX_TARG_VPE)) == 
NULL) {
+                                       schedule();
+                               }
+
+                               set_current_state(TASK_RUNNING);
+                               remove_wait_queue(&channel_wqs[index].lx_queue, 
&wait);
+
+                               /* back running */
+                       }
                }
 
                if (*p == NULL) {
-                       printk(" vpe_shared %p %p\n", p, *p);
-                       return (-EFAULT);
+                       if (can_sleep) {
+                               DECLARE_WAITQUEUE(wait, current);
+                       
+
+                               /* go to sleep */
+                               add_wait_queue(&channel_wqs[index].lx_queue, 
&wait);
+                               
+                               set_current_state(TASK_INTERRUPTIBLE);
+                               while (*p == NULL) {
+                                       schedule();
+                               }
+                               
+                               set_current_state(TASK_RUNNING);
+                               remove_wait_queue(&channel_wqs[index].lx_queue, 
&wait);
+                               
+                               /* back running */
+                       }
+                       else {
+                               printk(" *vpe_get_shared is NULL. "
+                                      "Has an SP program been loaded?\n");
+                               return -ENOSYS;
+                       }
                }
-
+               
                if ((ret = rtlx_init(*p)) < 0)
-                       return (ret);
+                       return ret;
        }
-
-       chan = &rtlx->channel[minor];
-
+       
+       chan = &rtlx->channel[index];
+       
        /* already open? */
        if (chan->lx_state == RTLX_STATE_OPENED)
-               return (-EBUSY);
+               return -EBUSY;
 
        chan->lx_state = RTLX_STATE_OPENED;
-       return (0);
+       return 0;
+}      
+
+int rtlx_release(int index)
+{
+       rtlx->channel[index].lx_state = RTLX_STATE_UNUSED;
+       return 0;
 }
 
-static int rtlx_release(struct inode *inode, struct file *filp)
+unsigned int rtlx_read_poll(int index, int can_sleep)
 {
-       int minor;
+       struct rtlx_channel *chan = &rtlx->channel[index];
+       
+       /* data available to read? */
+       if (chan->lx_read == chan->lx_write) {
+               if (can_sleep) {
+                       DECLARE_WAITQUEUE(wait, current);
+                       
+                       /* go to sleep */
+                       add_wait_queue(&channel_wqs[index].lx_queue, &wait);
+
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       while (chan->lx_read == chan->lx_write) {
+                               schedule();
+
+                               set_current_state(TASK_INTERRUPTIBLE);
+
+                               if (sp_stopping) {
+                                       set_current_state(TASK_RUNNING);
+                                       
remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
+                                       return 0;
+                               }
+                       }
+                       
+                       set_current_state(TASK_RUNNING);
+                       remove_wait_queue(&channel_wqs[index].lx_queue, &wait);
+                       
+                       /* back running */
+               }
+               else
+                       return 0;
+       }
+       
+       return (chan->lx_write + chan->buffer_size - chan->lx_read)
+              % chan->buffer_size;
+}
+
+unsigned int rtlx_write_poll(int index)
+{
+       struct rtlx_channel *chan = &rtlx->channel[index];
+       return(write_spacefree(chan->rt_read, chan->rt_write, 
chan->buffer_size));
+}
+
+static inline void copy_to(void *dst, void *src, size_t count, int user)
+{
+       if (user)
+               copy_to_user (dst, src, count);
+       else
+               memcpy(dst,src,count);
+}
+
+static inline void copy_from(void *dst, void *src, size_t count, int user)
+{
+       if (user)
+               copy_from_user (dst, src, count);
+       else
+               memcpy (dst, src, count);
+}
+
+ssize_t rtlx_read(int index, void *buff, size_t count, int user)
+{
+       size_t fl = 0L;
+       struct rtlx_channel *lx;
+
+       if (rtlx == NULL)
+               return(-ENOSYS);
+
+       lx = &rtlx->channel[index];
+
+       /* find out how much in total */
+       count = min( count,
+                    (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read)
+                    % lx->buffer_size);
+
+       /* then how much from the read pointer onwards */
+       fl = min( count, (size_t)lx->buffer_size - lx->lx_read);
+
+       copy_to (buff, &lx->lx_buffer[lx->lx_read], fl, user);
+
+       /* and if there is anything left at the beginning of the buffer */
+       if ( count - fl )
+               copy_to (buff + fl, lx->lx_buffer, count - fl, user);
 
+       /* update the index */
+       lx->lx_read += count;
+       lx->lx_read %= lx->buffer_size;
+
+       return count;
+}
+
+ssize_t rtlx_write(int index, void *buffer, size_t count, int user)
+{
+       struct rtlx_channel *rt;
+       size_t fl;
+
+       if (rtlx == NULL)
+               return(-ENOSYS);
+
+       rt = &rtlx->channel[index];
+
+       /* total number of bytes to copy */
+       count = min( count, 
+                    (size_t)write_spacefree(rt->rt_read, rt->rt_write, 
+                                            rt->buffer_size));
+
+       /* first bit from write pointer to the end of the buffer, or count */
+       fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
+       
+       copy_from (&rt->rt_buffer[rt->rt_write], buffer, fl, user);
+
+       /* if there's any left copy to the beginning of the buffer */
+       if( count - fl )
+               copy_from (rt->rt_buffer, buffer + fl, count - fl, user);
+
+       rt->rt_write += count;
+       rt->rt_write %= rt->buffer_size;
+
+       return(count);
+}
+
+
+static int file_open(struct inode *inode, struct file *filp)
+{
+       int minor = MINOR(inode->i_rdev);
+
+       return rtlx_open(minor, 0);
+}
+
+static int file_release(struct inode *inode, struct file *filp)
+{
+       int minor;
        minor = MINOR(inode->i_rdev);
-       rtlx->channel[minor].lx_state = RTLX_STATE_UNUSED;
-       return (0);
+       
+       return rtlx_release(minor);
 }
 
-static unsigned int rtlx_poll(struct file *file, poll_table * wait)
+static unsigned int file_poll(struct file *file, poll_table * wait)
 {
        int minor;
        unsigned int mask = 0;
@@ -192,141 +362,117 @@
        poll_wait(file, &channel_wqs[minor].lx_queue, wait);
 
        /* data available to read? */
-       if (chan->lx_read != chan->lx_write)
+       if (rtlx_read_poll(minor, 0))
                mask |= POLLIN | POLLRDNORM;
 
        /* space to write */
-       if (spacefree(chan->rt_read, chan->rt_write, chan->buffer_size))
+       if (rtlx_write_poll(minor))
                mask |= POLLOUT | POLLWRNORM;
 
-       return (mask);
+       return mask;
 }
 
-static ssize_t rtlx_read(struct file *file, char __user * buffer, size_t count,
+static ssize_t file_read(struct file *file, char __user * buffer, size_t count,
                         loff_t * ppos)
 {
-       size_t fl = 0L;
-       int minor;
-       struct rtlx_channel *lx;
-       DECLARE_WAITQUEUE(wait, current);
-
-       minor = MINOR(file->f_dentry->d_inode->i_rdev);
-       lx = &rtlx->channel[minor];
+       int minor = MINOR(file->f_dentry->d_inode->i_rdev);
 
        /* data available? */
-       if (lx->lx_write == lx->lx_read) {
-               if (file->f_flags & O_NONBLOCK)
-                       return (0);     // -EAGAIN makes cat whinge
-
-               /* go to sleep */
-               add_wait_queue(&channel_wqs[minor].lx_queue, &wait);
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               while (lx->lx_write == lx->lx_read)
-                       schedule();
-
-               set_current_state(TASK_RUNNING);
-               remove_wait_queue(&channel_wqs[minor].lx_queue, &wait);
-
-               /* back running */
+       if (!rtlx_read_poll(minor, (file->f_flags & O_NONBLOCK))) {
+               return 0;       // -EAGAIN makes cat whinge
        }
-
-       /* find out how much in total */
-       count = min( count,
-                    (size_t)(lx->lx_write + lx->buffer_size - lx->lx_read) % 
lx->buffer_size);
-
-       /* then how much from the read pointer onwards */
-       fl = min( count, (size_t)lx->buffer_size - lx->lx_read);
-
-       copy_to_user (buffer, &lx->lx_buffer[lx->lx_read], fl);
-
-       /* and if there is anything left at the beginning of the buffer */
-       if ( count - fl )
-               copy_to_user (buffer + fl, lx->lx_buffer, count - fl);
-
-       /* update the index */
-       lx->lx_read += count;
-       lx->lx_read %= lx->buffer_size;
-
-       return (count);
+       
+       return rtlx_read(minor, buffer, count, 1);
 }
 
-static inline int spacefree(int read, int write, int size)
+static inline int write_spacefree(int read, int write, int size)
 {
        if (read == write) {
-               /* never fill the buffer completely, so indexes are always 
equal if empty
-                  and only empty, or !equal if data available */
-               return (size - 1);
+               /* never fill the buffer completely, so indexes are 
+                  always equal if empty and only empty, or !equal 
+                  if data available */
+               return size - 1;
        }
 
        return ((read + size - write) % size) - 1;
 }
 
-static ssize_t rtlx_write(struct file *file, const char __user * buffer,
+static ssize_t file_write(struct file *file, const char __user * buffer,
                          size_t count, loff_t * ppos)
 {
        int minor;
        struct rtlx_channel *rt;
-       size_t fl;
        DECLARE_WAITQUEUE(wait, current);
 
        minor = MINOR(file->f_dentry->d_inode->i_rdev);
        rt = &rtlx->channel[minor];
 
        /* any space left... */
-       if (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size)) {
+       if (!rtlx_write_poll(minor)) {
 
                if (file->f_flags & O_NONBLOCK)
-                       return (-EAGAIN);
+                       return -EAGAIN;
 
                add_wait_queue(&channel_wqs[minor].rt_queue, &wait);
                set_current_state(TASK_INTERRUPTIBLE);
 
-               while (!spacefree(rt->rt_read, rt->rt_write, rt->buffer_size))
+               while (!rtlx_write_poll(minor))
                        schedule();
 
                set_current_state(TASK_RUNNING);
                remove_wait_queue(&channel_wqs[minor].rt_queue, &wait);
        }
 
-       /* total number of bytes to copy */
-       count = min( count, (size_t)spacefree(rt->rt_read, rt->rt_write, 
rt->buffer_size) );
-
-       /* first bit from write pointer to the end of the buffer, or count */
-       fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
-
-       copy_from_user(&rt->rt_buffer[rt->rt_write], buffer, fl);
-
-       /* if there's any left copy to the beginning of the buffer */
-       if( count - fl )
-               copy_from_user(rt->rt_buffer, buffer + fl, count - fl);
-
-       rt->rt_write += count;
-       rt->rt_write %= rt->buffer_size;
-
-       return(count);
+       return rtlx_write(minor, (void *)buffer, count, 1);
 }
 
 static struct file_operations rtlx_fops = {
-       .owner = THIS_MODULE,
-       .open = rtlx_open,
-       .release = rtlx_release,
-       .write = rtlx_write,
-       .read = rtlx_read,
-       .poll = rtlx_poll
+       .owner =   THIS_MODULE,
+       .open =    file_open,
+       .release = file_release,
+       .write =   file_write,
+       .read =    file_read,
+       .poll =    file_poll
 };
 
 static int rtlx_module_init(void)
 {
+       int i;
+
        if ((major = register_chrdev(RTLX_MAJOR, module_name, &rtlx_fops)) < 0) 
{
                printk("rtlx_module_init: unable to register device\n");
-               return (-EBUSY);
+               return -EBUSY;
        }
 
        if (major == 0)
                major = RTLX_MAJOR;
 
-       return (0);
+       /* initialise the wait queues */
+       for (i = 0; i < RTLX_CHANNELS; i++) {
+               init_waitqueue_head(&channel_wqs[i].rt_queue);
+               init_waitqueue_head(&channel_wqs[i].lx_queue);
+       }
+
+       /* set up notifiers */
+       notify.start = starting;
+       notify.stop = stopping;
+       vpe_notify(RTLX_TARG_VPE, &notify);
+
+       /* set up for interrupt handling */
+       memset(&irq, 0, sizeof(struct irqaction));
+
+       if (cpu_has_vint) {
+               set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch);
+       }
+
+       irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ;
+       irq.handler = rtlx_interrupt;
+       irq.flags = SA_INTERRUPT;
+       irq.name = "RTLX";
+       irq.dev_id = rtlx;
+       setup_irq(irq_num, &irq);
+
+       return 0;
 }
 
 static void rtlx_module_exit(void)
diff -urN malta/linux/arch/mips/kernel/vpe.c malta/linux/arch/mips/kernel/vpe.c
--- malta/linux/arch/mips/kernel/vpe.c  2005/07/14 15:57:16     1.1
+++ malta/linux/arch/mips/kernel/vpe.c  2005/07/27 13:37:54     1.1.1000.1
@@ -31,6 +31,7 @@
  * You'll need to have the following device files.
  * mknod /dev/vpe0 c 63 0
  * mknod /dev/vpe1 c 63 1
+ *
  */
 
 #include <linux/kernel.h>
@@ -54,9 +55,17 @@
 #include <asm/cpu.h>
 #include <asm/processor.h>
 #include <asm/system.h>
+#include <asm/vpe.h>
+#include <asm/kspd.h>
 
 typedef void *vpe_handle;
 
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(fmt , a...)
+#endif
+
 // defined here because the kernel module loader doesn't have
 // anything to do with it.
 #define SHN_MIPS_SCOMMON 0xff03
@@ -68,12 +77,15 @@
 /* If this is set, the section belongs in the init part of the module */
 #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
 
-// temp number,
+// temp number, 
 #define VPE_MAJOR 63
 
 static char module_name[] = "vpe";
 static int major = 0;
 
+static struct kspd_notifications kspd_events;
+static int kspd_events_reqd = 0;
+
 /* grab the likely amount of memory we will need. */
 #ifdef CONFIG_MIPS_VPE_LOADER_TOM
 #define P_SIZE (2 * 1024 * 1024)
@@ -84,13 +96,15 @@
 
 #define MAX_VPES 16
 
+#define VPE_PATH_MAX 256
+
 enum vpe_state {
        VPE_STATE_UNUSED = 0,
        VPE_STATE_INUSE,
        VPE_STATE_RUNNING
 };
 
-enum tc_state {
+enum tc_state { 
        TC_STATE_UNUSED = 0,
        TC_STATE_INUSE,
        TC_STATE_RUNNING,
@@ -104,7 +118,7 @@
 
        /* parent VPE */
        struct vpe *pvpe;
-
+       
        /* The list of TC's with this VPE */
        struct list_head tc;
 
@@ -123,6 +137,8 @@
        u32 len;
        char *pbuffer;
        u32 plen;
+       unsigned int uid, gid;
+       char cwd[VPE_PATH_MAX];
 
        unsigned long __start;
 
@@ -134,6 +150,9 @@
 
        /* shared symbol address */
        void *shared_ptr;
+
+       /* the list of who wants to know when something major happens */
+       struct list_head notify;
 } vpe_t;
 
 struct vpecontrol_ {
@@ -206,6 +225,7 @@
        INIT_LIST_HEAD(&v->tc);
        list_add_tail(&v->list, &vpecontrol.vpe_list);
 
+       INIT_LIST_HEAD(&v->notify);
        v->minor = minor;
        return v;
 }
@@ -361,10 +381,11 @@
        else {
                /* .sbss + gp(relative) + offset */
                /* kludge! */
+
                rel =  (int)(short)((int)v + gp_offs +
                                    (int)(short)(*location & 0xffff) - gp_addr);
        }
-
+       
        if( (rel > 32768) || (rel < -32768) ) {
                printk(KERN_ERR
                       "apply_r_mips_gprel16: relative address out of range 
0x%x %d\n",
@@ -373,7 +394,7 @@
        }
 
        *location = (*location & 0xffff0000) | (rel & 0xffff);
-
+       
        return 0;
 }
 
@@ -384,15 +405,14 @@
        rel = (((unsigned int)v - (unsigned int)location));
        rel >>= 2;              // because the offset is in _instructions_ not 
bytes.
        rel -= 1;               // and one instruction less due to the branch 
delay slot.
-
+       
        if( (rel > 32768) || (rel < -32768) ) {
                printk(KERN_ERR
                       "apply_r_mips_pc16: relative address out of range 
0x%x\n", rel);
                return -ENOEXEC;
        }
-
+       
        *location = (*location & 0xffff0000) | (rel & 0xffff);
-
        return 0;
 }
 
@@ -474,7 +494,7 @@
                                printk("%d != %d\n", v, l->value);
                                goto out_danger;
                        }
-
+                       
 
                        /*
                         * Do the HI16 relocation.  Note that we actually don't
@@ -552,7 +572,7 @@
                /* This is the symbol it is referring to */
                sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
                        + ELF32_R_SYM(r_info);
-
+               
                if (!sym->st_value) {
                        printk(KERN_DEBUG "%s: undefined weak symbol %s\n",
                               me->name, strtab + sym->st_name);
@@ -561,6 +581,7 @@
 
                v = sym->st_value;
 
+
                res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v);
                if( res ) {
                        printk(KERN_DEBUG
@@ -581,6 +602,9 @@
 {
        gp_addr = secbase + rel;
        gp_offs = gp_addr - (secbase & 0xffff0000);
+
+       printk(KERN_DEBUG "save_gp_address gp_addr 0x%x gp_offs 0x%x secbase 
0x%x rel 0x%x\n",
+              gp_addr, gp_offs, secbase, rel);
 }
 /* end module-elf32.c */
 
@@ -600,14 +624,19 @@
 
        /* find the .bss section for COMMON symbols */
        for (i = 0; i < nsecs; i++) {
-               if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0)
+               if (strncmp(secstrings + sechdrs[i].sh_name, ".bss", 4) == 0) {
                        bssbase = sechdrs[i].sh_addr;
+                       break;
+               }
        }
 
        for (i = 1; i < n; i++) {
+
                switch (sym[i].st_shndx) {
+
                case SHN_COMMON:
-                       /* Allocate space for the symbol in the .bss section. 
st_value is currently size.
+                       /* Allocate space for the symbol in the .bss section. 
+                          st_value is currently size.
                           We want it to have the address of the symbol. */
 
                        size = sym[i].st_value;
@@ -626,11 +655,11 @@
 
                case SHN_MIPS_SCOMMON:
 
-                       printk(KERN_DEBUG
-                              "simplify_symbols: ignoring SHN_MIPS_SCOMMON 
symbol <%s> st_shndx %d\n",
-                              strtab + sym[i].st_name, sym[i].st_shndx);
+                       printk(KERN_DEBUG "simplify_symbols: ignoring 
SHN_MIPS_SCOMMON"
+                              "symbol <%s> st_shndx %d\n", strtab + 
sym[i].st_name,
+                              sym[i].st_shndx);
 
-                       // .sbss section
+                       // .sbss section 
                        break;
 
                default:
@@ -643,7 +672,7 @@
                        sym[i].st_value += secbase;
                        break;
                }
-
+               
        }
 
        return ret;
@@ -669,6 +698,7 @@
        printk(KERN_WARNING "VPE: TC index %d TCStatus 0x%lx halt 0x%lx\n",
               t->index, read_tc_c0_tcstatus(), read_tc_c0_tchalt());
        printk(KERN_WARNING "VPE: tcrestart 0x%lx\n", read_tc_c0_tcrestart());
+       printk(KERN_WARNING "VPE: tcbind 0x%lx\n", read_tc_c0_tcbind());
 }
 
 static void dump_tclist(void)
@@ -685,6 +715,7 @@
 {
        unsigned long val;
        struct tc *t;
+       struct vpe_notifications *n;
 
        /* check we are the Master VPE */
        val = read_c0_vpeconf0();
@@ -725,47 +756,52 @@
                return -ENOEXEC;
        }
 
+
        /* Write the address we want it to start running from in the TCPC 
register. */
        write_tc_c0_tcrestart((unsigned long)v->__start);
 
        /* write the sivc_info address to tccontext */
        write_tc_c0_tccontext((unsigned long)0);
 
-       /* Set up the XTC bit in vpeconf0 to point at our tc */
-       write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (t->index << 
VPECONF0_XTC_SHIFT));
-
-       /* mark the TC as activated, not interrupt exempt and not dynamically 
allocatable */
+       /* mark the TC as activated, not interrupt exempt and not dynamically 
+          allocatable */
        val = read_tc_c0_tcstatus();
        val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A;
        write_tc_c0_tcstatus(val);
-
+       
        write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
 
-       /* set up VPE1 */
-       write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);     
// no multiple TC's
-       write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);   // 
enable this VPE
-
        /* The sde-kit passes 'memsize' to __start in $a3, so set something 
here...
           Or set $a3 to zero and define DFLT_STACK_SIZE and DFLT_HEAP_SIZE 
when you compile
           your program */
 
        mttgpr($7, 0);
 
-       /* set config to be the same as vpe0, particularly kseg0 coherency alg 
*/
-       write_vpe_c0_config(read_c0_config());
+       /* set up VPE1 */
+       /* bind the TC to VPE 1 as late as possible so we only have the final 
VPE 
+          registers to set up, and so an EJTAG probe can trigger on it */
+       write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor);
 
-       /* clear out any left overs from a previous program */
-       write_vpe_c0_cause(0);
+       /* Set up the XTC bit in vpeconf0 to point at our tc */
+       write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | (t->index << 
VPECONF0_XTC_SHIFT));
+       
+       /* enable this VPE */
+       write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);   
 
        /* take system out of configuration state */
        write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC);
 
-       /* clear interrupts enabled IE, ERL, EXL, and KSU from c0 status */
-       write_vpe_c0_status(read_vpe_c0_status() & ~(ST0_ERL | ST0_KSU | ST0_IE 
| ST0_EXL));
+
+       dump_tc(t);
+       
 
        /* set it running */
        evpe(EVPE_ENABLE);
 
+       list_for_each_entry(n, &v->notify, list) {
+               n->start(v->minor);
+       }
+
        return 0;
 }
 
@@ -803,7 +839,7 @@
        struct module mod;      // so we can re-use the relocations code
 
        memset(&mod, 0, sizeof(struct module));
-       strcpy(mod.name, "VPE dummy prog module");
+       strcpy(mod.name, "VPE loader");
 
        hdr = (Elf_Ehdr *) v->pbuffer;
        len = v->plen;
@@ -873,6 +909,9 @@
                               sechdrs[i].sh_size);
                /* Update sh_addr to point to copy in image. */
                sechdrs[i].sh_addr = (unsigned long)dest;
+
+               printk(KERN_DEBUG " section sh_name %s sh_addr 0x%x\n", 
+                      secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr);
        }
 
        /* Fix up syms, so that st_value is a pointer to location. */
@@ -940,11 +979,56 @@
        }
 }
 
-/* checks for VPE is unused and gets ready to load program      */
+static void cleanup_tc(struct tc *tc)
+{
+       int tmp;
+
+       /* Put MVPE's into 'configuration state' */
+       write_c0_mvpcontrol(read_c0_mvpcontrol() | MVPCONTROL_VPC);
+
+       settc(tc->index);
+       tmp = read_tc_c0_tcstatus();
+
+       /* mark not allocated and not dynamically allocatable */
+       tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
+       tmp |= TCSTATUS_IXMT;   /* interrupt exempt */
+       write_tc_c0_tcstatus(tmp);
+       
+       write_tc_c0_tchalt(TCHALT_H);
+
+       /* clear out any left overs from a previous program */
+       write_vpe_c0_cause(0);
+
+       /* clear interrupts enabled IE, ERL, EXL, and KSU from c0 status */
+       write_vpe_c0_status(read_vpe_c0_status() & ~(ST0_ERL | ST0_KSU | ST0_IE 
| ST0_EXL));
+
+       /* bind it to anything other than VPE1 */
+       write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | 
TCBIND_CURVPE
+
+       write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC);
+}
+
+static int getcwd(char *buff, int size)
+{
+       mm_segment_t old_fs;
+       int ret;
+
+       old_fs = get_fs();
+       set_fs (KERNEL_DS); 
+
+       ret = sys_getcwd(buff,size);
+
+       set_fs(old_fs);
+       
+       return ret;
+}
+
+/* checks VPE is unused and gets ready to load program  */
 static int vpe_open(struct inode *inode, struct file *filp)
 {
-       int minor;
+       int minor, ret;
        vpe_t *v;
+       struct vpe_notifications *not;
 
        /* assume only 1 device at the mo. */
        if ((minor = MINOR(inode->i_rdev)) != 1) {
@@ -958,31 +1042,16 @@
        }
 
        if (v->state != VPE_STATE_UNUSED) {
-               unsigned long tmp;
-               struct tc *t;
-
-               printk(KERN_WARNING "VPE: device %d already in use\n", minor);
-
                dvpe();
-               dump_vpe(v);
-
-               printk(KERN_WARNING "VPE: re-initialising %d\n", minor);
-
+               
+               list_for_each_entry(not, &v->notify, list) {
+                       not->stop(minor);
+               }
+               
                release_progmem(v->load_addr);
-
-               t = get_tc(minor);
-               settc(minor);
-               tmp = read_tc_c0_tcstatus();
-
-               /* mark not allocated and not dynamically allocatable */
-               tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
-               tmp |= TCSTATUS_IXMT;   /* interrupt exempt */
-               write_tc_c0_tcstatus(tmp);
-
-               write_tc_c0_tchalt(TCHALT_H);
-
+               cleanup_tc(get_tc(minor));
        }
-
+       
        // allocate it so when we get write ops we know it's expected.
        v->state = VPE_STATE_INUSE;
 
@@ -992,6 +1061,20 @@
        v->load_addr = NULL;
        v->len = 0;
 
+       v->uid = filp->f_uid;
+       v->gid = filp->f_gid;
+
+       /* get kspd to tell us when a syscall_exit happens */
+       if( !kspd_events_reqd ) {
+               kspd_notify( &kspd_events );
+               kspd_events_reqd++;
+       }
+       
+       v->cwd[0] = 0;
+       if ((ret = getcwd(v->cwd, VPE_PATH_MAX)) < 0) {
+               printk("VPE: open, getcwd returned %d\n", ret);
+       }
+
        return 0;
 }
 
@@ -1165,7 +1248,65 @@
 
 EXPORT_SYMBOL(vpe_get_shared);
 
-static int __init vpe_module_init(void)
+int vpe_getuid(int index)
+{
+       struct vpe *v;
+
+       if ((v = get_vpe(index)) == NULL) {
+               printk(KERN_WARNING "vpe: invalid vpe index %d\n", index);
+               return -1;
+       }
+
+       return v->uid;
+}
+EXPORT_SYMBOL(vpe_getuid);
+
+int vpe_getgid(int index)
+{
+       struct vpe *v;
+
+       if ((v = get_vpe(index)) == NULL) {
+               printk(KERN_WARNING "vpe: invalid vpe index %d\n", index);
+               return -1;
+       }
+
+       return v->gid;
+}
+EXPORT_SYMBOL(vpe_getgid);
+
+int vpe_notify(int index, struct vpe_notifications *notify)
+{
+       struct vpe *v;
+
+       if ((v = get_vpe(index)) == NULL) {
+               printk(KERN_WARNING "vpe: invalid vpe index %d\n", index);
+               return -1;
+       }
+
+       list_add(&notify->list, &v->notify);
+       return 0;
+}
+EXPORT_SYMBOL(vpe_notify);
+
+char *vpe_getcwd(int index)
+{
+       struct vpe *v;
+
+       if ((v = get_vpe(index)) == NULL) {
+               printk(KERN_WARNING "vpe: invalid vpe index %d\n", index);
+               return NULL;
+       }
+
+       return v->cwd;
+}
+EXPORT_SYMBOL(vpe_getcwd);
+
+static void kspd_sp_exit( int sp_id)
+{
+       cleanup_tc(get_tc(sp_id));
+}
+
+static int vpe_module_init(void)
 {
        struct vpe *v = NULL;
        struct tc *t;
@@ -1209,7 +1350,8 @@
                                return -ENODEV;
                        }
 
-                       list_add(&t->tc, &v->tc);       /* add the tc to the 
list of this vpe's tc's. */
+                       /* add the tc to the list of this vpe's tc's. */
+                       list_add(&t->tc, &v->tc);
 
                        /* deactivate all but vpe0 */
                        if (i != 0) {
@@ -1230,35 +1372,40 @@
                                                     ~(ST0_IM | ST0_IE | 
ST0_KSU))
                                                    | ST0_CU0);
 
-                               /* set config to be the same as vpe0, 
particularly kseg0 coherency alg */
+                               /* set config to be the same as vpe0, 
+                                  particularly kseg0 coherency alg */
                                write_vpe_c0_config(read_c0_config());
                        }
-
                }
-
+               
                /* TC's */
                t->pvpe = v;    /* set the parent vpe */
 
                if (i != 0) {
                        unsigned long tmp;
 
-                       /* tc 0 will of course be running.... */
-                       if (i == 0)
-                               t->state = TC_STATE_RUNNING;
-
                        settc(i);
 
-                       /* bind a TC to each VPE, May as well put all excess 
TC's
-                          on the last VPE */
-                       if (i >= (((val & MVPCONF0_PVPE) >> 
MVPCONF0_PVPE_SHIFT) + 1))
-                               write_tc_c0_tcbind(read_tc_c0_tcbind() |
-                                                  ((val & MVPCONF0_PVPE) >> 
MVPCONF0_PVPE_SHIFT));
-                       else
-                               write_tc_c0_tcbind(read_tc_c0_tcbind() | i);
+                       /* Any TC that is bound to VPE0 gets left as is - in 
case
+                          we are running SMTC on VPE0. A TC that is bound to 
any 
+                          other VPE gets bound to VPE0, ideally I'd like to 
make
+                          it homeless but it doesn't appear to let me bind a TC
+                          to a non-existent VPE. Which is perfectly 
reasonable. 
+                          
+                          The (un)bound state is visible to an EJTAG probe so 
may 
+                          notify GDB...
+                       */
+
+                       if (((tmp = read_tc_c0_tcbind()) & TCBIND_CURVPE)) {
+                               /* tc is bound >vpe0 */
+                               write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE);
 
+                               t->pvpe = get_vpe(0);   /* set the parent vpe */
+                       }
+                                               
                        tmp = read_tc_c0_tcstatus();
 
-                       /* mark not allocated and not dynamically allocatable */
+                       /* mark not activated and not dynamically allocatable */
                        tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
                        tmp |= TCSTATUS_IXMT;   /* interrupt exempt */
                        write_tc_c0_tcstatus(tmp);
@@ -1270,10 +1417,12 @@
        /* release config state */
        write_c0_mvpcontrol(read_c0_mvpcontrol() & ~MVPCONTROL_VPC);
 
+       kspd_events.kspd_sp_exit = kspd_sp_exit;
+
        return 0;
 }
 
-static void __exit vpe_module_exit(void)
+static void vpe_module_exit(void)
 {
        struct vpe *v, *n;
 
diff -urN malta/linux/include/asm-mips/kspd.h 
malta/linux/include/asm-mips/kspd.h
--- malta/linux/include/asm-mips/Attic/kspd.h   1970/01/01 00:00:00
+++ malta/linux/include/asm-mips/Attic/kspd.h   2005-07-27 14:38:04.682649000 
+0100     1.1.1000.1
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2005 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _ASM_KSPD_H
+#define _ASM_KSPD_H
+
+struct kspd_notifications {
+       void (*kspd_sp_exit)(int sp_id);
+
+       struct list_head list;
+};
+
+extern void kspd_notify(struct kspd_notifications *notify);
+
+#endif
diff -urN malta/linux/include/asm-mips/vpe.h malta/linux/include/asm-mips/vpe.h
--- malta/linux/include/asm-mips/Attic/vpe.h    1970/01/01 00:00:00
+++ malta/linux/include/asm-mips/Attic/vpe.h    2005-07-27 14:38:04.724691000 
+0100     1.1.1000.1
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2005 MIPS Technologies, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can distribute it and/or modify it
+ *  under the terms of the GNU General Public License (Version 2) as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope it will be useful, but WITHOUT
+ *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ *  for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _ASM_VPE_H
+#define _ASM_VPE_H
+
+struct vpe_notifications {
+       void (*start)(int vpe);
+       void (*stop)(int vpe);
+
+       struct list_head list;
+};
+
+
+extern int vpe_notify(int index, struct vpe_notifications *notify);
+
+extern void *vpe_get_shared(int index);
+extern int vpe_getuid(int index);
+extern int vpe_getgid(int index);
+extern char *vpe_getcwd(int index);
+
+#endif
diff -urN malta/linux/include/asm-mips/rtlx.h 
malta/linux/include/asm-mips/rtlx.h
--- malta/linux/include/asm-mips/rtlx.h 2005/07/14 15:57:17     1.1
+++ malta/linux/include/asm-mips/rtlx.h 2005/07/27 13:38:04     1.1.1000.1
@@ -3,12 +3,12 @@
  *
  */
 
-#ifndef _RTLX_H
-#define _RTLX_H_
+#ifndef _ASM_RTLX_H
+#define _ASM_RTLX_H_
 
 #define LX_NODE_BASE 10
 
-#define MIPSCPU_INT_BASE       16
+#define MIPSCPU_INT_BASE  16
 #define MIPS_CPU_RTLX_IRQ 0
 
 #define RTLX_VERSION 1
@@ -16,6 +16,17 @@
 #define RTLX_ID (RTLX_xID | RTLX_VERSION)
 #define RTLX_CHANNELS 8
 
+#define RTLX_CHANNEL_STDIO 0
+#define RTLX_CHANNEL_DBG   1
+#define RTLX_CHANNEL_SYSIO 2
+
+extern int rtlx_open(int index, int can_sleep);
+extern int rtlx_release(int index);
+extern ssize_t rtlx_read(int index, void *buff, size_t count, int user);
+extern ssize_t rtlx_write(int index, void *buffer, size_t count, int user);
+extern unsigned int rtlx_read_poll(int index, int can_sleep);
+extern unsigned int rtlx_write_poll(int index);
+
 enum rtlx_state {
        RTLX_STATE_UNUSED = 0,
        RTLX_STATE_INITIALISED,

<Prev in Thread] Current Thread [Next in Thread>