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(¬ify->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, ¬ify);
+
+ 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, ¬ify);
+
+ /* 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(¬ify->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,
|