Submitted By: Jim Gifford (patches at jg555 dot com) Date: 2006-09-23 Initial Package Version: 2.6.18 Origin: Linux-MIPS Upstream Status: http://www.linux-mips.org/pub/linux/mips/kernel/v2.6/ diff -Naur linux-2.6.18/arch/mips/au1000/db1x00/Makefile linux-2.6.18.mips/arch/mips/au1000/db1x00/Makefile --- linux-2.6.18/arch/mips/au1000/db1x00/Makefile 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/au1000/db1x00/Makefile 2006-09-20 06:55:21.000000000 -0700 @@ -6,4 +6,3 @@ # Makefile for the Alchemy Semiconductor Db1x00 board. lib-y := init.o board_setup.o irqmap.o -obj-$(CONFIG_WM97XX_COMODULE) += mirage_ts.o diff -Naur linux-2.6.18/arch/mips/au1000/db1x00/mirage_ts.c linux-2.6.18.mips/arch/mips/au1000/db1x00/mirage_ts.c --- linux-2.6.18/arch/mips/au1000/db1x00/mirage_ts.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/au1000/db1x00/mirage_ts.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,260 +0,0 @@ -/* - * linux/arch/mips/au1000/db1x00/mirage_ts.c - * - * BRIEF MODULE DESCRIPTION - * Glue between Mirage board-specific touchscreen pieces - * and generic Wolfson Codec touchscreen support. - * - * Based on pb1100_ts.c used in Hydrogen II. - * - * Copyright (c) 2003 Embedded Edge, LLC - * dan@embeddededge.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * 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., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * Imported interface to Wolfson Codec driver. - */ -extern void *wm97xx_ts_get_handle(int which); -extern int wm97xx_ts_ready(void* ts_handle); -extern void wm97xx_ts_set_cal(void* ts_handle, int xscale, int xtrans, int yscale, int ytrans); -extern u16 wm97xx_ts_get_ac97(void* ts_handle, u8 reg); -extern void wm97xx_ts_set_ac97(void* ts_handle, u8 reg, u16 val); -extern int wm97xx_ts_read_data(void* ts_handle, long* x, long* y, long* pressure); -extern void wm97xx_ts_send_data(void* ts_handle, long x, long y, long z); - -int wm97xx_comodule_present = 1; - - -#define TS_NAME "mirage_ts" - -#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg) -#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg) -#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg) -#define DPRINTK(format, arg...) printk("%s: " format "\n", __FUNCTION__ , ## arg) - - -#define PEN_DOWN_IRQ AU1000_GPIO_7 - -static struct task_struct *ts_task = 0; -static DECLARE_COMPLETION(ts_complete); -static DECLARE_WAIT_QUEUE_HEAD(pendown_wait); - -#ifdef CONFIG_WM97XX_FIVEWIRETS -static int release_pressure = 1; -#else -static int release_pressure = 50; -#endif - -typedef struct { - long x; - long y; -} DOWN_EVENT; - -#define SAMPLE_RATE 50 /* samples per second */ -#define PEN_DEBOUNCE 5 /* samples for settling - fn of SAMPLE_RATE */ -#define PEN_UP_TIMEOUT 10 /* in seconds */ -#define PEN_UP_SETTLE 5 /* samples per second */ - -static struct { - int xscale; - int xtrans; - int yscale; - int ytrans; -} mirage_ts_cal = -{ -#if 0 - .xscale = 84, - .xtrans = -157, - .yscale = 66, - .ytrans = -150, -#else - .xscale = 84, - .xtrans = -150, - .yscale = 66, - .ytrans = -146, -#endif -}; - - -static void pendown_irq(int irqnr, void *devid, struct pt_regs *regs) -{ -//DPRINTK("got one 0x%x", au_readl(SYS_PINSTATERD)); - wake_up(&pendown_wait); -} - -static int ts_thread(void *id) -{ - static int pen_was_down = 0; - static DOWN_EVENT pen_xy; - long x, y, z; - void *ts; /* handle */ - struct task_struct *tsk = current; - int timeout = HZ / SAMPLE_RATE; - - ts_task = tsk; - - daemonize(); - tsk->tty = NULL; - tsk->policy = SCHED_FIFO; - tsk->rt_priority = 1; - strcpy(tsk->comm, "touchscreen"); - - /* only want to receive SIGKILL */ - spin_lock_irq(&tsk->sigmask_lock); - siginitsetinv(&tsk->blocked, sigmask(SIGKILL)); - recalc_sigpending(tsk); - spin_unlock_irq(&tsk->sigmask_lock); - - /* get handle for codec */ - ts = wm97xx_ts_get_handle(0); - - /* proceed only after everybody is ready */ - wait_event_timeout(pendown_wait, wm97xx_ts_ready(ts), HZ/4); - - /* board-specific calibration */ - wm97xx_ts_set_cal(ts, - mirage_ts_cal.xscale, - mirage_ts_cal.xtrans, - mirage_ts_cal.yscale, - mirage_ts_cal.ytrans); - - /* route Wolfson pendown interrupts to our GPIO */ - au_sync(); - wm97xx_ts_set_ac97(ts, 0x4c, wm97xx_ts_get_ac97(ts, 0x4c) & ~0x0008); - au_sync(); - wm97xx_ts_set_ac97(ts, 0x56, wm97xx_ts_get_ac97(ts, 0x56) & ~0x0008); - au_sync(); - wm97xx_ts_set_ac97(ts, 0x52, wm97xx_ts_get_ac97(ts, 0x52) | 0x2008); - au_sync(); - - for (;;) { - interruptible_sleep_on_timeout(&pendown_wait, timeout); - disable_irq(PEN_DOWN_IRQ); - if (signal_pending(tsk)) { - break; - } - - /* read codec */ - if (!wm97xx_ts_read_data(ts, &x, &y, &z)) - z = 0; /* treat no-data and pen-up the same */ - - if (signal_pending(tsk)) { - break; - } - - if (z >= release_pressure) { - y = ~y; /* top to bottom */ - if (pen_was_down > 1 /*&& pen_was_down < PEN_DEBOUNCE*/) {//THXXX - /* bounce ? */ - x = pen_xy.x; - y = pen_xy.y; - --pen_was_down; - } else if (pen_was_down <= 1) { - pen_xy.x = x; - pen_xy.y = y; - if (pen_was_down) - wm97xx_ts_send_data(ts, x, y, z); - pen_was_down = PEN_DEBOUNCE; - } - //wm97xx_ts_send_data(ts, x, y, z); - timeout = HZ / SAMPLE_RATE; - } else { - if (pen_was_down) { - if (--pen_was_down) - z = release_pressure; - else //THXXX - wm97xx_ts_send_data(ts, pen_xy.x, pen_xy.y, z); - } - /* The pendown signal takes some time to settle after - * reading the pen pressure so wait a little - * before enabling the pen. - */ - if (! pen_was_down) { -// interruptible_sleep_on_timeout(&pendown_wait, HZ / PEN_UP_SETTLE); - timeout = HZ * PEN_UP_TIMEOUT; - } - } - enable_irq(PEN_DOWN_IRQ); - } - enable_irq(PEN_DOWN_IRQ); - ts_task = NULL; - complete(&ts_complete); - return 0; -} - -static int __init ts_mirage_init(void) -{ - int ret; - - /* pen down signal is connected to GPIO 7 */ - - ret = request_irq(PEN_DOWN_IRQ, pendown_irq, 0, "ts-pendown", NULL); - if (ret) { - err("unable to get pendown irq%d: [%d]", PEN_DOWN_IRQ, ret); - return ret; - } - - lock_kernel(); - ret = kernel_thread(ts_thread, NULL, CLONE_FS | CLONE_FILES); - if (ret < 0) { - unlock_kernel(); - return ret; - } - unlock_kernel(); - - info("Mirage touchscreen IRQ initialized."); - - return 0; -} - -static void __exit ts_mirage_exit(void) -{ - if (ts_task) { - send_sig(SIGKILL, ts_task, 1); - wait_for_completion(&ts_complete); - } - - free_irq(PEN_DOWN_IRQ, NULL); -} - -module_init(ts_mirage_init); -module_exit(ts_mirage_exit); - diff -Naur linux-2.6.18/arch/mips/configs/e55_defconfig linux-2.6.18.mips/arch/mips/configs/e55_defconfig --- linux-2.6.18/arch/mips/configs/e55_defconfig 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/configs/e55_defconfig 2006-09-20 06:55:21.000000000 -0700 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc1 -# Thu Jul 6 10:04:02 2006 +# Linux kernel version: 2.6.18-rc2 +# Tue Jul 25 23:15:03 2006 # CONFIG_MIPS=y @@ -227,7 +227,6 @@ # # PCCARD (PCMCIA/CardBus) support # -# CONFIG_PCCARD is not set # # PCI Hotplug Support @@ -254,7 +253,6 @@ # CONFIG_STANDALONE=y CONFIG_PREVENT_FIRMWARE_BUILD=y -# CONFIG_FW_LOADER is not set # CONFIG_SYS_HYPERVISOR is not set # @@ -284,6 +282,7 @@ CONFIG_BLK_DEV_RAM=m CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_BLK_DEV_INITRD is not set # CONFIG_CDROM_PKTCDVD is not set @@ -643,6 +642,7 @@ # # Kernel hacking # +CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set @@ -650,7 +650,7 @@ CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_FS is not set CONFIG_CROSSCOMPILE=y -CONFIG_CMDLINE="console=ttyVR0,19200 mem=8M" +CONFIG_CMDLINE="console=ttyVR0,19200 ide0=0x1f0,0x3f6,40 mem=8M" # # Security options diff -Naur linux-2.6.18/arch/mips/configs/mpc30x_defconfig linux-2.6.18.mips/arch/mips/configs/mpc30x_defconfig --- linux-2.6.18/arch/mips/configs/mpc30x_defconfig 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/configs/mpc30x_defconfig 2006-09-20 06:55:21.000000000 -0700 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc1 -# Thu Jul 6 10:04:15 2006 +# Linux kernel version: 2.6.18-rc2 +# Tue Jul 25 23:16:46 2006 # CONFIG_MIPS=y @@ -71,7 +71,6 @@ CONFIG_VICTOR_MPC30X=y # CONFIG_ZAO_CAPCELLA is not set CONFIG_PCI_VR41XX=y -CONFIG_VRC4173=y CONFIG_RWSEM_GENERIC_SPINLOCK=y CONFIG_GENERIC_FIND_NEXT_BIT=y CONFIG_GENERIC_HWEIGHT=y @@ -168,6 +167,7 @@ CONFIG_SYSVIPC=y # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set @@ -841,7 +841,7 @@ # CONFIG_USB_LEGOTOWER is not set # CONFIG_USB_LCD is not set # CONFIG_USB_LED is not set -# CONFIG_USB_CY7C63 is not set +# CONFIG_USB_CYPRESS_CY7C63 is not set # CONFIG_USB_CYTHERM is not set # CONFIG_USB_PHIDGETKIT is not set # CONFIG_USB_PHIDGETSERVO is not set @@ -982,7 +982,6 @@ # CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set # CONFIG_CIFS is not set -# CONFIG_CIFS_DEBUG2 is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set @@ -1007,6 +1006,7 @@ # # Kernel hacking # +CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set @@ -1014,7 +1014,7 @@ CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_FS is not set CONFIG_CROSSCOMPILE=y -CONFIG_CMDLINE="mem=32M console=ttyVR0,19200" +CONFIG_CMDLINE="mem=32M console=ttyVR0,19200 ide0=0x170,0x376,73" # # Security options diff -Naur linux-2.6.18/arch/mips/configs/workpad_defconfig linux-2.6.18.mips/arch/mips/configs/workpad_defconfig --- linux-2.6.18/arch/mips/configs/workpad_defconfig 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/configs/workpad_defconfig 2006-09-20 06:55:21.000000000 -0700 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.18-rc1 -# Thu Jul 6 10:04:21 2006 +# Linux kernel version: 2.6.18-rc2 +# Tue Jul 25 23:13:04 2006 # CONFIG_MIPS=y @@ -166,6 +166,7 @@ CONFIG_SYSVIPC=y # CONFIG_POSIX_MQUEUE is not set # CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_TASKSTATS is not set CONFIG_SYSCTL=y # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set @@ -379,6 +380,7 @@ CONFIG_BLK_DEV_RAM=m CONFIG_BLK_DEV_RAM_COUNT=16 CONFIG_BLK_DEV_RAM_SIZE=4096 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_BLK_DEV_INITRD is not set # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set @@ -855,7 +857,6 @@ # CONFIG_RPCSEC_GSS_SPKM3 is not set # CONFIG_SMB_FS is not set # CONFIG_CIFS is not set -# CONFIG_CIFS_DEBUG2 is not set # CONFIG_NCP_FS is not set # CONFIG_CODA_FS is not set # CONFIG_AFS_FS is not set @@ -880,6 +881,7 @@ # # Kernel hacking # +CONFIG_TRACE_IRQFLAGS_SUPPORT=y # CONFIG_PRINTK_TIME is not set # CONFIG_MAGIC_SYSRQ is not set # CONFIG_UNUSED_SYMBOLS is not set @@ -887,7 +889,7 @@ CONFIG_LOG_BUF_SHIFT=14 # CONFIG_DEBUG_FS is not set CONFIG_CROSSCOMPILE=y -CONFIG_CMDLINE="console=ttyVR0,19200 mem=16M" +CONFIG_CMDLINE="console=ttyVR0,19200 ide0=0x170,0x376,49 mem=16M" # # Security options diff -Naur linux-2.6.18/arch/mips/Kconfig linux-2.6.18.mips/arch/mips/Kconfig --- linux-2.6.18/arch/mips/Kconfig 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/Kconfig 2006-09-20 06:55:21.000000000 -0700 @@ -126,7 +126,6 @@ select IRQ_CPU select IRQ_CPU_RM7K select IRQ_CPU_RM9K - select SERIAL_RM9000 select SYS_HAS_CPU_RM9000 select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL @@ -480,7 +479,6 @@ select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN - select ARCH_SPARSEMEM_ENABLE help The Ocelot is a MIPS-based Single Board Computer (SBC) made by Momentum Computer . @@ -524,8 +522,6 @@ config MACH_VR41XX bool "NEC VR41XX-based machines" select SYS_HAS_CPU_VR41XX - select SYS_SUPPORTS_32BIT_KERNEL - select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL config PMC_YOSEMITE bool "PMC-Sierra Yosemite eval board" @@ -614,6 +610,7 @@ select SYS_SUPPORTS_64BIT_KERNEL select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_NUMA + select SYS_SUPPORTS_SMP help This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics workstations. To compile a Linux kernel that runs on these, say Y @@ -1200,7 +1197,7 @@ select CPU_SUPPORTS_32BIT_KERNEL select CPU_SUPPORTS_64BIT_KERNEL help - The options selects support for the NEC VR4100 series of processors. + The options selects support for the NEC VR41xx series of processors. Only choose this option if you have one of these processors as a kernel built with this option will not run on any other type of processor or vice versa. @@ -1527,6 +1524,7 @@ select CPU_MIPSR2_SRS select MIPS_MT select SMP + select SYS_SUPPORTS_SMP help This is a kernel model which is known a SMTC or lately has been marketesed into SMVP. @@ -1538,6 +1536,7 @@ select CPU_MIPSR2_SRS select MIPS_MT select SMP + select SYS_SUPPORTS_SMP help This is a kernel model which is also known a VSMP or lately has been marketesed into SMVP. @@ -1649,9 +1648,7 @@ default y config IRQ_PER_CPU - depends on SMP bool - default y # # - Highmem only makes sense for the 32-bit kernel. @@ -1691,9 +1688,6 @@ config ARCH_SPARSEMEM_ENABLE bool - -config ARCH_SPARSEMEM_ENABLE - bool select SPARSEMEM_STATIC config NUMA @@ -1719,6 +1713,7 @@ config SMP bool "Multi-Processing support" depends on SYS_SUPPORTS_SMP + select IRQ_PER_CPU help This enables support for systems with more than one CPU. If you have a system with only one CPU, like most personal computers, say N. If diff -Naur linux-2.6.18/arch/mips/kernel/cpu-probe.c linux-2.6.18.mips/arch/mips/kernel/cpu-probe.c --- linux-2.6.18/arch/mips/kernel/cpu-probe.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/cpu-probe.c 2006-09-20 06:55:21.000000000 -0700 @@ -38,15 +38,40 @@ static void r39xx_wait(void) { - unsigned long cfg = read_c0_conf(); - write_c0_conf(cfg | TX39_CONF_HALT); + local_irq_disable(); + if (!need_resched()) + write_c0_conf(read_c0_conf() | TX39_CONF_HALT); + local_irq_enable(); } +/* + * There is a race when WAIT instruction executed with interrupt + * enabled. + * But it is implementation-dependent wheter the pipelie restarts when + * a non-enabled interrupt is requested. + */ static void r4k_wait(void) { - __asm__(".set\tmips3\n\t" - "wait\n\t" - ".set\tmips0"); + __asm__(" .set mips3 \n" + " wait \n" + " .set mips0 \n"); +} + +/* + * This variant is preferable as it allows testing need_resched and going to + * sleep depending on the outcome atomically. Unfortunately the "It is + * implementation-dependent whether the pipeline restarts when a non-enabled + * interrupt is requested" restriction in the MIPS32/MIPS64 architecture makes + * using this version a gamble. + */ +static void r4k_wait_irqoff(void) +{ + local_irq_disable(); + if (!need_resched()) + __asm__(" .set mips3 \n" + " wait \n" + " .set mips0 \n"); + local_irq_enable(); } /* The Au1xxx wait is available only if using 32khz counter or @@ -56,17 +81,17 @@ static void au1k_wait(void) { /* using the wait instruction makes CP0 counter unusable */ - __asm__(".set mips3\n\t" - "cache 0x14, 0(%0)\n\t" - "cache 0x14, 32(%0)\n\t" - "sync\n\t" - "nop\n\t" - "wait\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - "nop\n\t" - ".set mips0\n\t" + __asm__(" .set mips3 \n" + " cache 0x14, 0(%0) \n" + " cache 0x14, 32(%0) \n" + " sync \n" + " nop \n" + " wait \n" + " nop \n" + " nop \n" + " nop \n" + " nop \n" + " .set mips0 \n" : : "r" (au1k_wait)); } @@ -110,8 +135,6 @@ case CPU_R5000: case CPU_NEVADA: case CPU_RM7000: - case CPU_RM9000: - case CPU_TX49XX: case CPU_4KC: case CPU_4KEC: case CPU_4KSC: @@ -125,6 +148,10 @@ cpu_wait = r4k_wait; printk(" available.\n"); break; + case CPU_TX49XX: + cpu_wait = r4k_wait_irqoff; + printk(" available.\n"); + break; case CPU_AU1000: case CPU_AU1100: case CPU_AU1500: @@ -136,6 +163,14 @@ } else printk(" unavailable.\n"); break; + case CPU_RM9000: + if ((c->processor_id & 0x00ff) >= 0x40) { + cpu_wait = r4k_wait; + printk(" available.\n"); + } else { + printk(" unavailable.\n"); + } + break; default: printk(" unavailable.\n"); break; diff -Naur linux-2.6.18/arch/mips/kernel/irixsig.c linux-2.6.18.mips/arch/mips/kernel/irixsig.c --- linux-2.6.18/arch/mips/kernel/irixsig.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/irixsig.c 2006-09-20 06:55:21.000000000 -0700 @@ -17,6 +17,7 @@ #include #include +#include #undef DEBUG_SIG @@ -172,11 +173,12 @@ return ret; } -asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs) +void do_irix_signal(struct pt_regs *regs) { struct k_sigaction ka; siginfo_t info; int signr; + sigset_t *oldset; /* * We want the common case to go fast, which is why we may in certain @@ -184,19 +186,28 @@ * if so. */ if (!user_mode(regs)) - return 1; + return; - if (try_to_freeze()) - goto no_signal; - - if (!oldset) + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + oldset = ¤t->saved_sigmask; + else oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, &ka, regs, NULL); - if (signr > 0) - return handle_signal(signr, &info, &ka, oldset, regs); + if (signr > 0) { + /* Whee! Actually deliver the signal. */ + if (handle_signal(signr, &info, &ka, oldset, regs) == 0) { + /* a signal was successfully delivered; the saved + * sigmask will have been stored in the signal frame, + * and will be restored by sigreturn, so we can simply + * clear the TIF_RESTORE_SIGMASK flag */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) + clear_thread_flag(TIF_RESTORE_SIGMASK); + } + + return; + } -no_signal: /* * Who's code doesn't conform to the restartable syscall convention * dies here!!! The li instruction, a single machine instruction, @@ -208,8 +219,22 @@ regs->regs[2] == ERESTARTNOINTR) { regs->cp0_epc -= 8; } + if (regs->regs[2] == ERESTART_RESTARTBLOCK) { + regs->regs[2] = __NR_restart_syscall; + regs->regs[7] = regs->regs[26]; + regs->cp0_epc -= 4; + } + regs->regs[0] = 0; /* Don't deal with this again. */ + } + + /* + * If there's no signal to deliver, we just put the saved sigmask + * back + */ + if (test_thread_flag(TIF_RESTORE_SIGMASK)) { + clear_thread_flag(TIF_RESTORE_SIGMASK); + sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); } - return 0; } asmlinkage void @@ -413,7 +438,7 @@ asmlinkage int irix_sigsuspend(struct pt_regs *regs) { - sigset_t saveset, newset; + sigset_t newset; sigset_t __user *uset; uset = (sigset_t __user *) regs->regs[4]; @@ -422,18 +447,15 @@ sigdelsetmask(&newset, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); - saveset = current->blocked; + current->saved_sigmask = current->blocked; current->blocked = newset; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); - regs->regs[2] = -EINTR; - while (1) { - current->state = TASK_INTERRUPTIBLE; - schedule(); - if (do_irix_signal(&saveset, regs)) - return -EINTR; - } + current->state = TASK_INTERRUPTIBLE; + schedule(); + set_thread_flag(TIF_RESTORE_SIGMASK); + return -ERESTARTNOHAND; } /* hate hate hate... */ diff -Naur linux-2.6.18/arch/mips/kernel/linux32.c linux-2.6.18.mips/arch/mips/kernel/linux32.c --- linux-2.6.18/arch/mips/kernel/linux32.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/linux32.c 2006-09-20 06:55:21.000000000 -0700 @@ -1296,9 +1296,3 @@ return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr); } - -extern asmlinkage void sys_set_thread_area(u32 addr); -asmlinkage void sys32_set_thread_area(u32 addr) -{ - sys_set_thread_area(AA(addr)); -} diff -Naur linux-2.6.18/arch/mips/kernel/mips-mt.c linux-2.6.18.mips/arch/mips/kernel/mips-mt.c --- linux-2.6.18/arch/mips/kernel/mips-mt.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/mips-mt.c 2006-09-20 06:55:21.000000000 -0700 @@ -96,6 +96,10 @@ goto out_unlock; } + retval = security_task_setscheduler(p, 0, NULL); + if (retval) + goto out_unlock; + /* Record new user-specified CPU set for future reference */ p->thread.user_cpus_allowed = new_mask; @@ -141,8 +145,9 @@ p = find_process_by_pid(pid); if (!p) goto out_unlock; - - retval = 0; + retval = security_task_getscheduler(p); + if (retval) + goto out_unlock; cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map); diff -Naur linux-2.6.18/arch/mips/kernel/process.c linux-2.6.18.mips/arch/mips/kernel/process.c --- linux-2.6.18/arch/mips/kernel/process.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/process.c 2006-09-20 06:55:21.000000000 -0700 @@ -281,62 +281,63 @@ } *schedule_frame, mfinfo[64]; static int mfinfo_num; -static int __init get_frame_info(struct mips_frame_info *info) +static inline int is_ra_save_ins(union mips_instruction *ip) { - int i; - void *func = info->func; - union mips_instruction *ip = (union mips_instruction *)func; + /* sw / sd $ra, offset($sp) */ + return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) && + ip->i_format.rs == 29 && + ip->i_format.rt == 31; +} + +static inline int is_jal_jalr_jr_ins(union mips_instruction *ip) +{ + if (ip->j_format.opcode == jal_op) + return 1; + if (ip->r_format.opcode != spec_op) + return 0; + return ip->r_format.func == jalr_op || ip->r_format.func == jr_op; +} + +static inline int is_sp_move_ins(union mips_instruction *ip) +{ + /* addiu/daddiu sp,sp,-imm */ + if (ip->i_format.rs != 29 || ip->i_format.rt != 29) + return 0; + if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op) + return 1; + return 0; +} + +static int get_frame_info(struct mips_frame_info *info) +{ + union mips_instruction *ip = info->func; + int i, max_insns = + min(128UL, info->func_size / sizeof(union mips_instruction)); + info->pc_offset = -1; info->frame_size = 0; - for (i = 0; i < 128; i++, ip++) { - /* if jal, jalr, jr, stop. */ - if (ip->j_format.opcode == jal_op || - (ip->r_format.opcode == spec_op && - (ip->r_format.func == jalr_op || - ip->r_format.func == jr_op))) - break; - if (info->func_size && i >= info->func_size / 4) - break; - if ( -#ifdef CONFIG_32BIT - ip->i_format.opcode == addiu_op && -#endif -#ifdef CONFIG_64BIT - ip->i_format.opcode == daddiu_op && -#endif - ip->i_format.rs == 29 && - ip->i_format.rt == 29) { - /* addiu/daddiu sp,sp,-imm */ - if (info->frame_size) - continue; - info->frame_size = - ip->i_format.simmediate; - } + for (i = 0; i < max_insns; i++, ip++) { - if ( -#ifdef CONFIG_32BIT - ip->i_format.opcode == sw_op && -#endif -#ifdef CONFIG_64BIT - ip->i_format.opcode == sd_op && -#endif - ip->i_format.rs == 29 && - ip->i_format.rt == 31) { - /* sw / sd $ra, offset($sp) */ - if (info->pc_offset != -1) - continue; + if (is_jal_jalr_jr_ins(ip)) + break; + if (!info->frame_size) { + if (is_sp_move_ins(ip)) + info->frame_size = - ip->i_format.simmediate; + continue; + } + if (info->pc_offset == -1 && is_ra_save_ins(ip)) { info->pc_offset = ip->i_format.simmediate / sizeof(long); + break; } } - if (info->pc_offset == -1 || info->frame_size == 0) { - if (func == schedule) - printk("Can't analyze prologue code at %p\n", func); - info->pc_offset = -1; - info->frame_size = 0; - } - - return 0; + if (info->frame_size && info->pc_offset >= 0) /* nested */ + return 0; + if (info->pc_offset < 0) /* leaf */ + return 1; + /* prologue seems boggus... */ + return -1; } static int __init frame_info_init(void) @@ -368,7 +369,14 @@ schedule_frame = &mfinfo[0]; #endif for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++) - get_frame_info(&mfinfo[i]); + get_frame_info(mfinfo + i); + + /* + * Without schedule() frame info, result given by + * thread_saved_pc() and get_wchan() are not reliable. + */ + if (schedule_frame->pc_offset < 0) + printk("Can't analyze schedule() prologue at %p\n", schedule); mfinfo_num = i; return 0; @@ -427,6 +435,8 @@ if (i < 0) break; + if (mfinfo[i].pc_offset < 0) + break; pc = ((unsigned long *)frame)[mfinfo[i].pc_offset]; if (!mfinfo[i].frame_size) break; @@ -437,3 +447,49 @@ return pc; } +#ifdef CONFIG_KALLSYMS +/* used by show_backtrace() */ +unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, + unsigned long pc, unsigned long ra) +{ + unsigned long stack_page; + struct mips_frame_info info; + char *modname; + char namebuf[KSYM_NAME_LEN + 1]; + unsigned long size, ofs; + int leaf; + + stack_page = (unsigned long)task_stack_page(task); + if (!stack_page) + return 0; + + if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf)) + return 0; + if (ofs == 0) + return 0; + + info.func = (void *)(pc - ofs); + info.func_size = ofs; /* analyze from start to ofs */ + leaf = get_frame_info(&info); + if (leaf < 0) + return 0; + + if (*sp < stack_page || + *sp + info.frame_size > stack_page + THREAD_SIZE - 32) + return 0; + + if (leaf) + /* + * For some extreme cases, get_frame_info() can + * consider wrongly a nested function as a leaf + * one. In that cases avoid to return always the + * same value. + */ + pc = pc != ra ? ra : 0; + else + pc = ((unsigned long *)(*sp))[info.pc_offset]; + + *sp += info.frame_size; + return __kernel_text_address(pc) ? pc : 0; +} +#endif diff -Naur linux-2.6.18/arch/mips/kernel/ptrace.c linux-2.6.18.mips/arch/mips/kernel/ptrace.c --- linux-2.6.18/arch/mips/kernel/ptrace.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/ptrace.c 2006-09-20 06:55:21.000000000 -0700 @@ -20,12 +20,12 @@ #include #include #include -#include #include #include #include #include -#include +#include +#include #include #include @@ -471,12 +471,16 @@ */ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) { + /* do the secure computing check first */ + secure_computing(regs->orig_eax); + if (unlikely(current->audit_context) && entryexit) audit_syscall_exit(AUDITSC_RESULT(regs->regs[2]), regs->regs[2]); if (!(current->ptrace & PT_PTRACED)) goto out; + if (!test_thread_flag(TIF_SYSCALL_TRACE)) goto out; @@ -494,9 +498,14 @@ send_sig(current->exit_code, current, 1); current->exit_code = 0; } - out: + +out: + /* There is no ->orig_eax and that's quite intensional for now making + this work will require some work in various other place before it's + more than a placebo. */ + if (unlikely(current->audit_context) && !entryexit) - audit_syscall_entry(audit_arch(), regs->regs[2], - regs->regs[4], regs->regs[5], - regs->regs[6], regs->regs[7]); + audit_syscall_entry(audit_arch(), regs->orig_eax, + regs->regs[4], regs->regs[5], + regs->regs[6], regs->regs[7]); } diff -Naur linux-2.6.18/arch/mips/kernel/scall32-o32.S linux-2.6.18.mips/arch/mips/kernel/scall32-o32.S --- linux-2.6.18/arch/mips/kernel/scall32-o32.S 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/scall32-o32.S 2006-09-20 06:55:21.000000000 -0700 @@ -662,6 +662,8 @@ sys sys_tee 4 sys sys_vmsplice 4 sys sys_move_pages 6 + sys sys_set_robust_list 2 + sys sys_get_robust_list 3 .endm /* We pre-compute the number of _instruction_ bytes needed to diff -Naur linux-2.6.18/arch/mips/kernel/scall64-64.S linux-2.6.18.mips/arch/mips/kernel/scall64-64.S --- linux-2.6.18/arch/mips/kernel/scall64-64.S 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/scall64-64.S 2006-09-20 06:55:21.000000000 -0700 @@ -466,3 +466,5 @@ PTR sys_tee /* 5265 */ PTR sys_vmsplice PTR sys_move_pages + PTR sys_set_robust_list + PTR sys_get_robust_list diff -Naur linux-2.6.18/arch/mips/kernel/scall64-n32.S linux-2.6.18.mips/arch/mips/kernel/scall64-n32.S --- linux-2.6.18/arch/mips/kernel/scall64-n32.S 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/scall64-n32.S 2006-09-20 06:55:21.000000000 -0700 @@ -247,7 +247,7 @@ PTR sys_capset PTR sys32_rt_sigpending /* 6125 */ PTR compat_sys_rt_sigtimedwait - PTR sys_rt_sigqueueinfo + PTR sys32_rt_sigqueueinfo PTR sysn32_rt_sigsuspend PTR sys32_sigaltstack PTR compat_sys_utime /* 6130 */ @@ -390,5 +390,7 @@ PTR sys_splice PTR sys_sync_file_range PTR sys_tee - PTR sys_vmsplice /* 6271 */ + PTR sys_vmsplice /* 6270 */ PTR sys_move_pages + PTR compat_sys_set_robust_list + PTR compat_sys_get_robust_list diff -Naur linux-2.6.18/arch/mips/kernel/scall64-o32.S linux-2.6.18.mips/arch/mips/kernel/scall64-o32.S --- linux-2.6.18/arch/mips/kernel/scall64-o32.S 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/scall64-o32.S 2006-09-20 06:55:21.000000000 -0700 @@ -514,4 +514,6 @@ PTR sys_tee PTR sys_vmsplice PTR compat_sys_move_pages + PTR compat_sys_set_robust_list + PTR compat_sys_get_robust_list /* 4310 */ .size sys_call_table,.-sys_call_table diff -Naur linux-2.6.18/arch/mips/kernel/signal32.c linux-2.6.18.mips/arch/mips/kernel/signal32.c --- linux-2.6.18/arch/mips/kernel/signal32.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/signal32.c 2006-09-20 06:55:21.000000000 -0700 @@ -815,9 +815,6 @@ if (!user_mode(regs)) return; - if (try_to_freeze()) - goto no_signal; - if (test_thread_flag(TIF_RESTORE_SIGMASK)) oldset = ¤t->saved_sigmask; else @@ -836,9 +833,10 @@ if (test_thread_flag(TIF_RESTORE_SIGMASK)) clear_thread_flag(TIF_RESTORE_SIGMASK); } + + return; } -no_signal: /* * Who's code doesn't conform to the restartable syscall convention * dies here!!! The li instruction, a single machine instruction, @@ -856,6 +854,7 @@ regs->regs[7] = regs->regs[26]; regs->cp0_epc -= 4; } + regs->regs[0] = 0; /* Don't deal with this again. */ } /* diff -Naur linux-2.6.18/arch/mips/kernel/signal.c linux-2.6.18.mips/arch/mips/kernel/signal.c --- linux-2.6.18/arch/mips/kernel/signal.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/signal.c 2006-09-20 06:55:21.000000000 -0700 @@ -424,15 +424,11 @@ if (!user_mode(regs)) return; - if (try_to_freeze()) - goto no_signal; - if (test_thread_flag(TIF_RESTORE_SIGMASK)) oldset = ¤t->saved_sigmask; else oldset = ¤t->blocked; - signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Whee! Actually deliver the signal. */ @@ -446,9 +442,10 @@ if (test_thread_flag(TIF_RESTORE_SIGMASK)) clear_thread_flag(TIF_RESTORE_SIGMASK); } + + return; } -no_signal: /* * Who's code doesn't conform to the restartable syscall convention * dies here!!! The li instruction, a single machine instruction, @@ -466,6 +463,7 @@ regs->regs[7] = regs->regs[26]; regs->cp0_epc -= 4; } + regs->regs[0] = 0; /* Don't deal with this again. */ } /* diff -Naur linux-2.6.18/arch/mips/kernel/smp.c linux-2.6.18.mips/arch/mips/kernel/smp.c --- linux-2.6.18/arch/mips/kernel/smp.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/smp.c 2006-09-20 06:55:21.000000000 -0700 @@ -467,14 +467,18 @@ static int __init topology_init(void) { - int cpu; - int ret; + int i, ret; - for_each_present_cpu(cpu) { - ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu); +#ifdef CONFIG_NUMA + for_each_online_node(i) + register_one_node(i); +#endif /* CONFIG_NUMA */ + + for_each_present_cpu(i) { + ret = register_cpu(&per_cpu(cpu_devices, i), i); if (ret) printk(KERN_WARNING "topology_init: register_cpu %d " - "failed (%d)\n", cpu, ret); + "failed (%d)\n", i, ret); } return 0; diff -Naur linux-2.6.18/arch/mips/kernel/smp-mt.c linux-2.6.18.mips/arch/mips/kernel/smp-mt.c --- linux-2.6.18/arch/mips/kernel/smp-mt.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/smp-mt.c 2006-09-20 06:55:21.000000000 -0700 @@ -203,7 +203,7 @@ write_vpe_c0_config( read_c0_config()); /* make sure there are no software interrupts pending */ - write_vpe_c0_cause(read_vpe_c0_cause() & ~(C_SW1|C_SW0)); + write_vpe_c0_cause(0); /* Propagate Config7 */ write_vpe_c0_config7(read_c0_config7()); diff -Naur linux-2.6.18/arch/mips/kernel/smtc-asm.S linux-2.6.18.mips/arch/mips/kernel/smtc-asm.S --- linux-2.6.18/arch/mips/kernel/smtc-asm.S 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/smtc-asm.S 2006-09-20 06:55:21.000000000 -0700 @@ -8,7 +8,7 @@ #include #include #include -#include +#include /* * "Software Interrupt" linkage. diff -Naur linux-2.6.18/arch/mips/kernel/syscall.c linux-2.6.18.mips/arch/mips/kernel/syscall.c --- linux-2.6.18/arch/mips/kernel/syscall.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/syscall.c 2006-09-20 06:55:21.000000000 -0700 @@ -263,7 +263,7 @@ return error; } -void sys_set_thread_area(unsigned long addr) +asmlinkage int sys_set_thread_area(unsigned long addr) { struct thread_info *ti = task_thread_info(current); @@ -271,6 +271,8 @@ /* If some future MIPS implementation has this register in hardware, * we will need to update it here (and in context switches). */ + + return 0; } asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3) diff -Naur linux-2.6.18/arch/mips/kernel/traps.c linux-2.6.18.mips/arch/mips/kernel/traps.c --- linux-2.6.18/arch/mips/kernel/traps.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/traps.c 2006-09-20 06:55:21.000000000 -0700 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -72,28 +73,68 @@ void (*board_ejtag_handler_setup)(void); void (*board_bind_eic_interrupt)(int irq, int regset); -/* - * These constant is for searching for possible module text segments. - * MODULE_RANGE is a guess of how much space is likely to be vmalloced. - */ -#define MODULE_RANGE (8*1024*1024) + +static void show_raw_backtrace(unsigned long reg29) +{ + unsigned long *sp = (unsigned long *)reg29; + unsigned long addr; + + printk("Call Trace:"); +#ifdef CONFIG_KALLSYMS + printk("\n"); +#endif + while (!kstack_end(sp)) { + addr = *sp++; + if (__kernel_text_address(addr)) + print_ip_sym(addr); + } + printk("\n"); +} + +#ifdef CONFIG_KALLSYMS +static int raw_show_trace; +static int __init set_raw_show_trace(char *str) +{ + raw_show_trace = 1; + return 1; +} +__setup("raw_show_trace", set_raw_show_trace); + +extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, + unsigned long pc, unsigned long ra); + +static void show_backtrace(struct task_struct *task, struct pt_regs *regs) +{ + unsigned long sp = regs->regs[29]; + unsigned long ra = regs->regs[31]; + unsigned long pc = regs->cp0_epc; + + if (raw_show_trace || !__kernel_text_address(pc)) { + show_raw_backtrace(sp); + return; + } + printk("Call Trace:\n"); + do { + print_ip_sym(pc); + pc = unwind_stack(task, &sp, pc, ra); + ra = 0; + } while (pc); + printk("\n"); +} +#else +#define show_backtrace(task, r) show_raw_backtrace((r)->regs[29]); +#endif /* * This routine abuses get_user()/put_user() to reference pointers * with at least a bit of error checking ... */ -void show_stack(struct task_struct *task, unsigned long *sp) +static void show_stacktrace(struct task_struct *task, struct pt_regs *regs) { const int field = 2 * sizeof(unsigned long); long stackdata; int i; - - if (!sp) { - if (task && task != current) - sp = (unsigned long *) task->thread.reg29; - else - sp = (unsigned long *) &sp; - } + unsigned long *sp = (unsigned long *)regs->regs[29]; printk("Stack :"); i = 0; @@ -114,32 +155,48 @@ i++; } printk("\n"); + show_backtrace(task, regs); } -void show_trace(struct task_struct *task, unsigned long *stack) +static __always_inline void prepare_frametrace(struct pt_regs *regs) { - const int field = 2 * sizeof(unsigned long); - unsigned long addr; - - if (!stack) { - if (task && task != current) - stack = (unsigned long *) task->thread.reg29; - else - stack = (unsigned long *) &stack; - } - - printk("Call Trace:"); -#ifdef CONFIG_KALLSYMS - printk("\n"); + __asm__ __volatile__( + ".set push\n\t" + ".set noat\n\t" +#ifdef CONFIG_64BIT + "1: dla $1, 1b\n\t" + "sd $1, %0\n\t" + "sd $29, %1\n\t" + "sd $31, %2\n\t" +#else + "1: la $1, 1b\n\t" + "sw $1, %0\n\t" + "sw $29, %1\n\t" + "sw $31, %2\n\t" #endif - while (!kstack_end(stack)) { - addr = *stack++; - if (__kernel_text_address(addr)) { - printk(" [<%0*lx>] ", field, addr); - print_symbol("%s\n", addr); + ".set pop\n\t" + : "=m" (regs->cp0_epc), + "=m" (regs->regs[29]), "=m" (regs->regs[31]) + : : "memory"); +} + +void show_stack(struct task_struct *task, unsigned long *sp) +{ + struct pt_regs regs; + if (sp) { + regs.regs[29] = (unsigned long)sp; + regs.regs[31] = 0; + regs.cp0_epc = 0; + } else { + if (task && task != current) { + regs.regs[29] = task->thread.reg29; + regs.regs[31] = 0; + regs.cp0_epc = task->thread.reg31; + } else { + prepare_frametrace(®s); } } - printk("\n"); + show_stacktrace(task, ®s); } /* @@ -147,9 +204,15 @@ */ void dump_stack(void) { - unsigned long stack; + struct pt_regs regs; - show_trace(current, &stack); + /* + * Remove any garbage that may be in regs (specially func + * addresses) to avoid show_raw_backtrace() to report them + */ + memset(®s, 0, sizeof(regs)); + prepare_frametrace(®s); + show_backtrace(current, ®s); } EXPORT_SYMBOL(dump_stack); @@ -268,8 +331,7 @@ print_modules(); printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n", current->comm, current->pid, current_thread_info(), current); - show_stack(current, (long *) regs->regs[29]); - show_trace(current, (long *) regs->regs[29]); + show_stacktrace(current, regs); show_code((unsigned int *) regs->cp0_epc); printk("\n"); } @@ -292,6 +354,16 @@ printk("%s[#%d]:\n", str, ++die_counter); show_registers(regs); spin_unlock_irq(&die_lock); + + if (in_interrupt()) + panic("Fatal exception in interrupt"); + + if (panic_on_oops) { + printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); + ssleep(5); + panic("Fatal exception"); + } + do_exit(SIGSEGV); } diff -Naur linux-2.6.18/arch/mips/kernel/vpe.c linux-2.6.18.mips/arch/mips/kernel/vpe.c --- linux-2.6.18/arch/mips/kernel/vpe.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/kernel/vpe.c 2006-09-20 06:55:21.000000000 -0700 @@ -768,10 +768,16 @@ */ write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor); + write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA)); + + back_to_back_c0_hazard(); + /* Set up the XTC bit in vpeconf0 to point at our tc */ write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC)) | (t->index << VPECONF0_XTC_SHIFT)); + back_to_back_c0_hazard(); + /* enable this VPE */ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA); diff -Naur linux-2.6.18/arch/mips/lib/iomap.c linux-2.6.18.mips/arch/mips/lib/iomap.c --- linux-2.6.18/arch/mips/lib/iomap.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/lib/iomap.c 1969-12-31 16:00:00.000000000 -0800 @@ -1,78 +0,0 @@ -/* - * iomap.c, Memory Mapped I/O routines for MIPS architecture. - * - * This code is based on lib/iomap.c, by Linus Torvalds. - * - * Copyright (C) 2004-2005 Yoichi Yuasa - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that 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 -#include -#include - -#include - -void __iomem *ioport_map(unsigned long port, unsigned int nr) -{ - unsigned long end; - - end = port + nr - 1UL; - if (ioport_resource.start > port || - ioport_resource.end < end || port > end) - return NULL; - - return (void __iomem *)(mips_io_port_base + port); -} - -void ioport_unmap(void __iomem *addr) -{ -} -EXPORT_SYMBOL(ioport_map); -EXPORT_SYMBOL(ioport_unmap); - -void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) -{ - unsigned long start, len, flags; - - if (dev == NULL) - return NULL; - - start = pci_resource_start(dev, bar); - len = pci_resource_len(dev, bar); - if (!start || !len) - return NULL; - - if (maxlen != 0 && len > maxlen) - len = maxlen; - - flags = pci_resource_flags(dev, bar); - if (flags & IORESOURCE_IO) - return ioport_map(start, len); - if (flags & IORESOURCE_MEM) { - if (flags & IORESOURCE_CACHEABLE) - return ioremap_cachable(start, len); - return ioremap_nocache(start, len); - } - - return NULL; -} - -void pci_iounmap(struct pci_dev *dev, void __iomem *addr) -{ - iounmap(addr); -} -EXPORT_SYMBOL(pci_iomap); -EXPORT_SYMBOL(pci_iounmap); diff -Naur linux-2.6.18/arch/mips/lib/Makefile linux-2.6.18.mips/arch/mips/lib/Makefile --- linux-2.6.18/arch/mips/lib/Makefile 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/lib/Makefile 2006-09-20 06:55:21.000000000 -0700 @@ -5,8 +5,6 @@ lib-y += csum_partial_copy.o memcpy.o promlib.o strlen_user.o strncpy_user.o \ strnlen_user.o uncached.o -obj-y += iomap.o - # libgcc-style stuff needed in the kernel lib-y += ashldi3.o ashrdi3.o lshrdi3.o diff -Naur linux-2.6.18/arch/mips/lib-32/dump_tlb.c linux-2.6.18.mips/arch/mips/lib-32/dump_tlb.c --- linux-2.6.18/arch/mips/lib-32/dump_tlb.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/lib-32/dump_tlb.c 2006-09-20 06:55:21.000000000 -0700 @@ -40,8 +40,6 @@ return "256Mb"; #endif } - - return "unknown"; } #define BARRIER() \ diff -Naur linux-2.6.18/arch/mips/lib-64/dump_tlb.c linux-2.6.18.mips/arch/mips/lib-64/dump_tlb.c --- linux-2.6.18/arch/mips/lib-64/dump_tlb.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/lib-64/dump_tlb.c 2006-09-20 06:55:21.000000000 -0700 @@ -31,8 +31,6 @@ case PM_256M: return "256Mb"; #endif } - - return "unknown"; } #define BARRIER() \ diff -Naur linux-2.6.18/arch/mips/Makefile linux-2.6.18.mips/arch/mips/Makefile --- linux-2.6.18/arch/mips/Makefile 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/Makefile 2006-09-20 06:55:21.000000000 -0700 @@ -330,6 +330,7 @@ # MIPS SEAD board # core-$(CONFIG_MIPS_SEAD) += arch/mips/mips-boards/sead/ +cflags-$(CONFIG_MIPS_SEAD) += -Iinclude/asm-mips/mach-mips load-$(CONFIG_MIPS_SEAD) += 0xffffffff80100000 # diff -Naur linux-2.6.18/arch/mips/mips-boards/atlas/atlas_int.c linux-2.6.18.mips/arch/mips/mips-boards/atlas/atlas_int.c --- linux-2.6.18/arch/mips/mips-boards/atlas/atlas_int.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/mips-boards/atlas/atlas_int.c 2006-09-20 06:55:21.000000000 -0700 @@ -1,6 +1,8 @@ /* - * Carsten Langgaard, carstenl@mips.com - * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved. + * Copyright (C) 1999, 2000, 2006 MIPS Technologies, Inc. + * All rights reserved. + * Authors: Carsten Langgaard + * Maciej W. Rozycki * * ######################################################################## * @@ -25,17 +27,20 @@ */ #include #include +#include #include #include #include #include -#include +#include #include +#include +#include + #include #include -#include - +#include static struct atlas_ictrl_regs *atlas_hw0_icregs; @@ -47,13 +52,13 @@ void disable_atlas_irq(unsigned int irq_nr) { - atlas_hw0_icregs->intrsten = (1 << (irq_nr-ATLASINT_BASE)); + atlas_hw0_icregs->intrsten = 1 << (irq_nr - ATLAS_INT_BASE); iob(); } void enable_atlas_irq(unsigned int irq_nr) { - atlas_hw0_icregs->intseten = (1 << (irq_nr-ATLASINT_BASE)); + atlas_hw0_icregs->intseten = 1 << (irq_nr - ATLAS_INT_BASE); iob(); } @@ -107,7 +112,7 @@ if (unlikely(int_status == 0)) return; - irq = ATLASINT_BASE + ls1bit32(int_status); + irq = ATLAS_INT_BASE + ls1bit32(int_status); DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq); @@ -161,15 +166,14 @@ } /* - * IRQs on the Atlas board look basically (barring software IRQs which we - * don't use at all and all external interrupt sources are combined together - * on hardware interrupt 0 (MIPS IRQ 2)) like: + * IRQs on the Atlas board look basically like (all external interrupt + * sources are combined together on hardware interrupt 0 (MIPS IRQ 2)): * - * MIPS IRQ Source + * MIPS IRQ Source * -------- ------ - * 0 Software (ignored) - * 1 Software (ignored) - * 2 Combined hardware interrupt (hw0) + * 0 Software 0 (reschedule IPI on MT) + * 1 Software 1 (remote call IPI on MT) + * 2 Combined Atlas hardware interrupt (hw0) * 3 Hardware (ignored) * 4 Hardware (ignored) * 5 Hardware (ignored) @@ -179,7 +183,7 @@ * We handle the IRQ according to _our_ priority which is: * * Highest ---- R4k Timer - * Lowest ---- Combined hardware interrupt + * Lowest ---- Software 0 * * then we just return, if multiple IRQs are pending then we will just take * another exception, big deal. @@ -193,17 +197,19 @@ if (irq == MIPSCPU_INT_ATLAS) atlas_hw0_irqdispatch(regs); - else if (irq > 0) + else if (irq >= 0) do_IRQ(MIPSCPU_INT_BASE + irq, regs); else spurious_interrupt(regs); } -void __init arch_init_irq(void) +static inline void init_atlas_irqs (int base) { int i; - atlas_hw0_icregs = (struct atlas_ictrl_regs *)ioremap (ATLAS_ICTRL_REGS_BASE, sizeof(struct atlas_ictrl_regs *)); + atlas_hw0_icregs = (struct atlas_ictrl_regs *) + ioremap(ATLAS_ICTRL_REGS_BASE, + sizeof(struct atlas_ictrl_regs *)); /* * Mask out all interrupt by writing "1" to all bit position in @@ -211,7 +217,7 @@ */ atlas_hw0_icregs->intrsten = 0xffffffff; - for (i = ATLASINT_BASE; i <= ATLASINT_END; i++) { + for (i = ATLAS_INT_BASE; i <= ATLAS_INT_END; i++) { irq_desc[i].status = IRQ_DISABLED; irq_desc[i].action = 0; irq_desc[i].depth = 1; @@ -219,3 +225,62 @@ spin_lock_init(&irq_desc[i].lock); } } + +static struct irqaction atlasirq = { + .handler = no_action, + .name = "Atlas cascade" +}; + +msc_irqmap_t __initdata msc_irqmap[] = { + {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0}, + {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0}, +}; +int __initdata msc_nr_irqs = sizeof(msc_irqmap) / sizeof(*msc_irqmap); + +msc_irqmap_t __initdata msc_eicirqmap[] = { + {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_ATLAS, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0}, + {MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0}, + {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0} +}; +int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap) / sizeof(*msc_eicirqmap); + +void __init arch_init_irq(void) +{ + init_atlas_irqs(ATLAS_INT_BASE); + + if (!cpu_has_veic) + mips_cpu_irq_init(MIPSCPU_INT_BASE); + + switch(mips_revision_corid) { + case MIPS_REVISION_CORID_CORE_MSC: + case MIPS_REVISION_CORID_CORE_FPGA2: + case MIPS_REVISION_CORID_CORE_FPGA3: + case MIPS_REVISION_CORID_CORE_24K: + case MIPS_REVISION_CORID_CORE_EMUL_MSC: + if (cpu_has_veic) + init_msc_irqs (MSC01E_INT_BASE, + msc_eicirqmap, msc_nr_eicirqs); + else + init_msc_irqs (MSC01C_INT_BASE, + msc_irqmap, msc_nr_irqs); + } + + + if (cpu_has_veic) { + set_vi_handler (MSC01E_INT_ATLAS, atlas_hw0_irqdispatch); + setup_irq (MSC01E_INT_BASE + MSC01E_INT_ATLAS, &atlasirq); + } else if (cpu_has_vint) { + set_vi_handler (MIPSCPU_INT_ATLAS, atlas_hw0_irqdispatch); +#ifdef CONFIG_MIPS_MT_SMTC + setup_irq_smtc (MIPSCPU_INT_BASE + MIPSCPU_INT_ATLAS, + &atlasirq, (0x100 << MIPSCPU_INT_ATLAS)); +#else /* Not SMTC */ + setup_irq(MIPSCPU_INT_BASE + MIPSCPU_INT_ATLAS, &atlasirq); +#endif /* CONFIG_MIPS_MT_SMTC */ + } else + setup_irq(MIPSCPU_INT_BASE + MIPSCPU_INT_ATLAS, &atlasirq); +} diff -Naur linux-2.6.18/arch/mips/mips-boards/atlas/atlas_setup.c linux-2.6.18.mips/arch/mips/mips-boards/atlas/atlas_setup.c --- linux-2.6.18/arch/mips/mips-boards/atlas/atlas_setup.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/mips-boards/atlas/atlas_setup.c 2006-09-20 06:55:21.000000000 -0700 @@ -77,7 +77,7 @@ #else s.iobase = ATLAS_UART_REGS_BASE+3; #endif - s.irq = ATLASINT_UART; + s.irq = ATLAS_INT_UART; s.uartclk = ATLAS_BASE_BAUD * 16; s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ; s.iotype = UPIO_PORT; diff -Naur linux-2.6.18/arch/mips/mips-boards/generic/time.c linux-2.6.18.mips/arch/mips/mips-boards/generic/time.c --- linux-2.6.18/arch/mips/mips-boards/generic/time.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/mips-boards/generic/time.c 2006-09-20 06:55:21.000000000 -0700 @@ -41,8 +41,13 @@ #include #include + +#ifdef CONFIG_MIPS_ATLAS +#include +#endif +#ifdef CONFIG_MIPS_MALTA #include -#include +#endif unsigned long cpu_khz; @@ -92,10 +97,9 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int cpu = smp_processor_id(); - int r2 = cpu_has_mips_r2; #ifdef CONFIG_MIPS_MT_SMTC - /* + /* * In an SMTC system, one Count/Compare set exists per VPE. * Which TC within a VPE gets the interrupt is essentially * random - we only know that it shouldn't be one with @@ -108,29 +112,46 @@ * the general MIPS timer_interrupt routine. */ + int vpflags; + /* - * DVPE is necessary so long as cross-VPE interrupts - * are done via read-modify-write of Cause register. + * We could be here due to timer interrupt, + * perf counter overflow, or both. */ - int vpflags = dvpe(); - write_c0_compare (read_c0_count() - 1); - clear_c0_cause(CPUCTR_IMASKBIT); - evpe(vpflags); - - if (cpu_data[cpu].vpe_id == 0) { - timer_interrupt(irq, dev_id, regs); - scroll_display_message(); - } else - write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ)); - smtc_timer_broadcast(cpu_data[cpu].vpe_id); + if (read_c0_cause() & (1 << 26)) + perf_irq(regs); - if (cpu != 0) + if (read_c0_cause() & (1 << 30)) { + /* If timer interrupt, make it de-assert */ + write_c0_compare (read_c0_count() - 1); /* - * Other CPUs should do profiling and process accounting + * DVPE is necessary so long as cross-VPE interrupts + * are done via read-modify-write of Cause register. */ - local_timer_interrupt(irq, dev_id, regs); - + vpflags = dvpe(); + clear_c0_cause(CPUCTR_IMASKBIT); + evpe(vpflags); + /* + * There are things we only want to do once per tick + * in an "MP" system. One TC of each VPE will take + * the actual timer interrupt. The others will get + * timer broadcast IPIs. We use whoever it is that takes + * the tick on VPE 0 to run the full timer_interrupt(). + */ + if (cpu_data[cpu].vpe_id == 0) { + timer_interrupt(irq, NULL, regs); + smtc_timer_broadcast(cpu_data[cpu].vpe_id); + scroll_display_message(); + } else { + write_c0_compare(read_c0_count() + + (mips_hpt_frequency/HZ)); + local_timer_interrupt(irq, dev_id, regs); + smtc_timer_broadcast(cpu_data[cpu].vpe_id); + } + } #else /* CONFIG_MIPS_MT_SMTC */ + int r2 = cpu_has_mips_r2; + if (cpu == 0) { /* * CPU 0 handles the global timer interrupt job and process @@ -161,9 +182,8 @@ */ local_timer_interrupt(irq, dev_id, regs); } -#endif /* CONFIG_MIPS_MT_SMTC */ - out: +#endif /* CONFIG_MIPS_MT_SMTC */ return IRQ_HANDLED; } diff -Naur linux-2.6.18/arch/mips/mips-boards/malta/malta_int.c linux-2.6.18.mips/arch/mips/mips-boards/malta/malta_int.c --- linux-2.6.18/arch/mips/mips-boards/malta/malta_int.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/mips-boards/malta/malta_int.c 2006-09-20 06:55:21.000000000 -0700 @@ -208,23 +208,23 @@ unsigned int a0 = 7; unsigned int t0; - t0 = s0 & 0xf000; + t0 = pending & 0xf000; t0 = t0 < 1; t0 = t0 << 2; a0 = a0 - t0; - s0 = s0 << t0; + pending = pending << t0; - t0 = s0 & 0xc000; + t0 = pending & 0xc000; t0 = t0 < 1; t0 = t0 << 1; a0 = a0 - t0; - s0 = s0 << t0; + pending = pending << t0; - t0 = s0 & 0x8000; + t0 = pending & 0x8000; t0 = t0 < 1; //t0 = t0 << 2; a0 = a0 - t0; - //s0 = s0 << t0; + //pending = pending << t0; return a0; #endif diff -Naur linux-2.6.18/arch/mips/mm/cache.c linux-2.6.18.mips/arch/mips/mm/cache.c --- linux-2.6.18/arch/mips/mm/cache.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/mm/cache.c 2006-09-20 06:55:21.000000000 -0700 @@ -25,7 +25,7 @@ void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page, unsigned long pfn); void (*flush_icache_range)(unsigned long start, unsigned long end); -void (*flush_icache_page)(struct vm_area_struct *vma, struct page *page); +void (*__flush_icache_page)(struct vm_area_struct *vma, struct page *page); /* MIPS specific cache operations */ void (*flush_cache_sigtramp)(unsigned long addr); @@ -70,6 +70,8 @@ struct address_space *mapping = page_mapping(page); unsigned long addr; + if (PageHighMem(page)) + return; if (mapping && !mapping_mapped(mapping)) { SetPageDcacheDirty(page); return; @@ -91,16 +93,16 @@ { struct page *page; unsigned long pfn, addr; + int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc; pfn = pte_pfn(pte); - if (pfn_valid(pfn) && (page = pfn_to_page(pfn), page_mapping(page)) && - Page_dcache_dirty(page)) { - if (pages_do_alias((unsigned long)page_address(page), - address & PAGE_MASK)) { - addr = (unsigned long) page_address(page); + if (unlikely(!pfn_valid(pfn))) + return; + page = pfn_to_page(pfn); + if (page_mapping(page) && Page_dcache_dirty(page)) { + addr = (unsigned long) page_address(page); + if (exec || pages_do_alias(addr, address & PAGE_MASK)) flush_data_cache_page(addr); - } - ClearPageDcacheDirty(page); } } diff -Naur linux-2.6.18/arch/mips/mm/c-r3k.c linux-2.6.18.mips/arch/mips/mm/c-r3k.c --- linux-2.6.18/arch/mips/mm/c-r3k.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/mm/c-r3k.c 2006-09-20 06:55:21.000000000 -0700 @@ -335,7 +335,7 @@ flush_cache_mm = r3k_flush_cache_mm; flush_cache_range = r3k_flush_cache_range; flush_cache_page = r3k_flush_cache_page; - flush_icache_page = r3k_flush_icache_page; + __flush_icache_page = r3k_flush_icache_page; flush_icache_range = r3k_flush_icache_range; flush_cache_sigtramp = r3k_flush_cache_sigtramp; diff -Naur linux-2.6.18/arch/mips/mm/c-r4k.c linux-2.6.18.mips/arch/mips/mm/c-r4k.c --- linux-2.6.18/arch/mips/mm/c-r4k.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/mm/c-r4k.c 2006-09-20 06:55:21.000000000 -0700 @@ -475,7 +475,7 @@ } } if (exec) { - if (cpu_has_vtag_icache) { + if (cpu_has_vtag_icache && mm == current->active_mm) { int cpu = smp_processor_id(); if (cpu_context(cpu, mm) != 0) @@ -599,7 +599,7 @@ * We're not sure of the virtual address(es) involved here, so * we have to flush the entire I-cache. */ - if (cpu_has_vtag_icache) { + if (cpu_has_vtag_icache && vma->vm_mm == current->active_mm) { int cpu = smp_processor_id(); if (cpu_context(cpu, vma->vm_mm) != 0) @@ -1242,7 +1242,7 @@ clear_c0_config(CONF_CU); break; /* - * We need to catch the ealry Alchemy SOCs with + * We need to catch the early Alchemy SOCs with * the write-only co_config.od bit and set it back to one... */ case CPU_AU1000: /* rev. DA, HA, HB */ @@ -1291,7 +1291,7 @@ __flush_cache_all = r4k___flush_cache_all; flush_cache_mm = r4k_flush_cache_mm; flush_cache_page = r4k_flush_cache_page; - flush_icache_page = r4k_flush_icache_page; + __flush_icache_page = r4k_flush_icache_page; flush_cache_range = r4k_flush_cache_range; flush_cache_sigtramp = r4k_flush_cache_sigtramp; diff -Naur linux-2.6.18/arch/mips/mm/c-sb1.c linux-2.6.18.mips/arch/mips/mm/c-sb1.c --- linux-2.6.18/arch/mips/mm/c-sb1.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/mm/c-sb1.c 2006-09-20 06:55:21.000000000 -0700 @@ -155,6 +155,26 @@ } /* + * Invalidate a range of the icache. The addresses are virtual, and + * the cache is virtually indexed and tagged. However, we don't + * necessarily have the right ASID context, so use index ops instead + * of hit ops. + */ +static inline void __sb1_flush_icache_range(unsigned long start, + unsigned long end) +{ + start &= ~(icache_line_size - 1); + end = (end + icache_line_size - 1) & ~(icache_line_size - 1); + + while (start != end) { + cache_set_op(Index_Invalidate_I, start & icache_index_mask); + start += icache_line_size; + } + mispredict(); + sync(); +} + +/* * Flush the icache for a given physical page. Need to writeback the * dcache first, then invalidate the icache. If the page isn't * executable, nothing is required. @@ -173,8 +193,11 @@ /* * Bumping the ASID is probably cheaper than the flush ... */ - if (cpu_context(cpu, vma->vm_mm) != 0) - drop_mmu_context(vma->vm_mm, cpu); + if (vma->vm_mm == current->active_mm) { + if (cpu_context(cpu, vma->vm_mm) != 0) + drop_mmu_context(vma->vm_mm, cpu); + } else + __sb1_flush_icache_range(addr, addr + PAGE_SIZE); } #ifdef CONFIG_SMP @@ -210,26 +233,6 @@ __attribute__((alias("local_sb1_flush_cache_page"))); #endif -/* - * Invalidate a range of the icache. The addresses are virtual, and - * the cache is virtually indexed and tagged. However, we don't - * necessarily have the right ASID context, so use index ops instead - * of hit ops. - */ -static inline void __sb1_flush_icache_range(unsigned long start, - unsigned long end) -{ - start &= ~(icache_line_size - 1); - end = (end + icache_line_size - 1) & ~(icache_line_size - 1); - - while (start != end) { - cache_set_op(Index_Invalidate_I, start & icache_index_mask); - start += icache_line_size; - } - mispredict(); - sync(); -} - /* * Invalidate all caches on this CPU @@ -326,9 +329,12 @@ * If there's a context, bump the ASID (cheaper than a flush, * since we don't know VAs!) */ - if (cpu_context(cpu, vma->vm_mm) != 0) { - drop_mmu_context(vma->vm_mm, cpu); - } + if (vma->vm_mm == current->active_mm) { + if (cpu_context(cpu, vma->vm_mm) != 0) + drop_mmu_context(vma->vm_mm, cpu); + } else + __sb1_flush_icache_range(start, start + PAGE_SIZE); + } #ifdef CONFIG_SMP @@ -520,7 +526,7 @@ /* These routines are for Icache coherence with the Dcache */ flush_icache_range = sb1_flush_icache_range; - flush_icache_page = sb1_flush_icache_page; + __flush_icache_page = sb1_flush_icache_page; flush_icache_all = __sb1_flush_icache_all; /* local only */ /* This implies an Icache flush too, so can't be nop'ed */ diff -Naur linux-2.6.18/arch/mips/mm/c-tx39.c linux-2.6.18.mips/arch/mips/mm/c-tx39.c --- linux-2.6.18/arch/mips/mm/c-tx39.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/mm/c-tx39.c 2006-09-20 06:55:21.000000000 -0700 @@ -382,7 +382,7 @@ flush_cache_mm = (void *) tx39h_flush_icache_all; flush_cache_range = (void *) tx39h_flush_icache_all; flush_cache_page = (void *) tx39h_flush_icache_all; - flush_icache_page = (void *) tx39h_flush_icache_all; + __flush_icache_page = (void *) tx39h_flush_icache_all; flush_icache_range = (void *) tx39h_flush_icache_all; flush_cache_sigtramp = (void *) tx39h_flush_icache_all; @@ -408,7 +408,7 @@ flush_cache_mm = tx39_flush_cache_mm; flush_cache_range = tx39_flush_cache_range; flush_cache_page = tx39_flush_cache_page; - flush_icache_page = tx39_flush_icache_page; + __flush_icache_page = tx39_flush_icache_page; flush_icache_range = tx39_flush_icache_range; flush_cache_sigtramp = tx39_flush_cache_sigtramp; diff -Naur linux-2.6.18/arch/mips/mm/fault.c linux-2.6.18.mips/arch/mips/mm/fault.c --- linux-2.6.18/arch/mips/mm/fault.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/mm/fault.c 2006-09-20 06:55:21.000000000 -0700 @@ -89,7 +89,7 @@ if (!(vma->vm_flags & VM_WRITE)) goto bad_area; } else { - if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC))) goto bad_area; } diff -Naur linux-2.6.18/arch/mips/mm/init.c linux-2.6.18.mips/arch/mips/mm/init.c --- linux-2.6.18/arch/mips/mm/init.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/mm/init.c 2006-09-20 06:55:21.000000000 -0700 @@ -30,11 +30,39 @@ #include #include #include +#include #include #include #include #include #include +#include + +/* CP0 hazard avoidance. */ +#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \ + "nop; nop; nop; nop; nop; nop;\n\t" \ + ".set reorder\n\t") + +/* Atomicity and interruptability */ +#ifdef CONFIG_MIPS_MT_SMTC + +#include + +#define ENTER_CRITICAL(flags) \ + { \ + unsigned int mvpflags; \ + local_irq_save(flags);\ + mvpflags = dvpe() +#define EXIT_CRITICAL(flags) \ + evpe(mvpflags); \ + local_irq_restore(flags); \ + } +#else + +#define ENTER_CRITICAL(flags) local_irq_save(flags) +#define EXIT_CRITICAL(flags) local_irq_restore(flags) + +#endif /* CONFIG_MIPS_MT_SMTC */ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); @@ -80,13 +108,184 @@ return 1UL << order; } -#ifdef CONFIG_HIGHMEM -pte_t *kmap_pte; -pgprot_t kmap_prot; +/* + * These are almost like kmap_atomic / kunmap_atmic except they take an + * additional address argument as the hint. + */ #define kmap_get_fixmap_pte(vaddr) \ pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)), (vaddr)) +#ifdef CONFIG_MIPS_MT_SMTC +static pte_t *kmap_coherent_pte; +static void __init kmap_coherent_init(void) +{ + unsigned long vaddr; + + /* cache the first coherent kmap pte */ + vaddr = __fix_to_virt(FIX_CMAP_BEGIN); + kmap_coherent_pte = kmap_get_fixmap_pte(vaddr); +} +#else +static inline void kmap_coherent_init(void) {} +#endif + +static inline void *kmap_coherent(struct page *page, unsigned long addr) +{ + enum fixed_addresses idx; + unsigned long vaddr, flags, entrylo; + unsigned long old_ctx; + pte_t pte; + int tlbidx; + + inc_preempt_count(); + idx = (addr >> PAGE_SHIFT) & (FIX_N_COLOURS - 1); +#ifdef CONFIG_MIPS_MT_SMTC + idx += FIX_N_COLOURS * smp_processor_id(); +#endif + vaddr = __fix_to_virt(FIX_CMAP_END - idx); + pte = mk_pte(page, PAGE_KERNEL); +#if defined(CONFIG_64BIT_PHYS_ADDR) && defined(CONFIG_CPU_MIPS32_R1) + entrylo = pte.pte_high; +#else + entrylo = pte_val(pte) >> 6; +#endif + + ENTER_CRITICAL(flags); + old_ctx = read_c0_entryhi(); + write_c0_entryhi(vaddr & (PAGE_MASK << 1)); + write_c0_entrylo0(entrylo); + write_c0_entrylo1(entrylo); +#ifdef CONFIG_MIPS_MT_SMTC + set_pte(kmap_coherent_pte - (FIX_CMAP_END - idx), pte); + /* preload TLB instead of local_flush_tlb_one() */ + mtc0_tlbw_hazard(); + tlb_probe(); + BARRIER; + tlbidx = read_c0_index(); + mtc0_tlbw_hazard(); + if (tlbidx < 0) + tlb_write_random(); + else + tlb_write_indexed(); +#else + tlbidx = read_c0_wired(); + write_c0_wired(tlbidx + 1); + write_c0_index(tlbidx); + mtc0_tlbw_hazard(); + tlb_write_indexed(); +#endif + tlbw_use_hazard(); + write_c0_entryhi(old_ctx); + EXIT_CRITICAL(flags); + + return (void*) vaddr; +} + +#define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1))) + +static inline void kunmap_coherent(struct page *page) +{ +#ifndef CONFIG_MIPS_MT_SMTC + unsigned int wired; + unsigned long flags, old_ctx; + + ENTER_CRITICAL(flags); + old_ctx = read_c0_entryhi(); + wired = read_c0_wired() - 1; + write_c0_wired(wired); + write_c0_index(wired); + write_c0_entryhi(UNIQUE_ENTRYHI(wired)); + write_c0_entrylo0(0); + write_c0_entrylo1(0); + mtc0_tlbw_hazard(); + tlb_write_indexed(); + tlbw_use_hazard(); + write_c0_entryhi(old_ctx); + EXIT_CRITICAL(flags); +#endif + dec_preempt_count(); + preempt_check_resched(); +} + +void copy_user_highpage(struct page *to, struct page *from, + unsigned long vaddr, struct vm_area_struct *vma) +{ + void *vfrom, *vto; + + vto = kmap_atomic(to, KM_USER1); + if (cpu_has_dc_aliases) { + vfrom = kmap_coherent(from, vaddr); + copy_page(vto, vfrom); + kunmap_coherent(from); + } else { + vfrom = kmap_atomic(from, KM_USER0); + copy_page(vto, vfrom); + kunmap_atomic(vfrom, KM_USER0); + } + if (((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) || + pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) + flush_data_cache_page((unsigned long)vto); + kunmap_atomic(vto, KM_USER1); + /* Make sure this page is cleared on other CPU's too before using it */ + smp_wmb(); +} + +EXPORT_SYMBOL(copy_user_highpage); + +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, + struct page *to) +{ + if (cpu_has_dc_aliases) { + struct page *from = virt_to_page(vfrom); + vfrom = kmap_coherent(from, vaddr); + copy_page(vto, vfrom); + kunmap_coherent(from); + } else + copy_page(vto, vfrom); + if (!cpu_has_ic_fills_f_dc || + pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK)) + flush_data_cache_page((unsigned long)vto); +} + +EXPORT_SYMBOL(copy_user_page); + +void copy_to_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, void *dst, const void *src, + unsigned long len) +{ + if (cpu_has_dc_aliases) { + void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(vto, src, len); + kunmap_coherent(page); + } else + memcpy(dst, src, len); + if ((vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc) + flush_cache_page(vma, vaddr, page_to_pfn(page)); +} + +EXPORT_SYMBOL(copy_to_user_page); + +void copy_from_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, void *dst, const void *src, + unsigned long len) +{ + if (cpu_has_dc_aliases) { + void *vfrom = + kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK); + memcpy(dst, vfrom, len); + kunmap_coherent(page); + } else + memcpy(dst, src, len); +} + +EXPORT_SYMBOL(copy_from_user_page); + + +#ifdef CONFIG_HIGHMEM +pte_t *kmap_pte; +pgprot_t kmap_prot; + static void __init kmap_init(void) { unsigned long kmap_vstart; @@ -97,11 +296,12 @@ kmap_prot = PAGE_KERNEL; } +#endif /* CONFIG_HIGHMEM */ -#ifdef CONFIG_32BIT void __init fixrange_init(unsigned long start, unsigned long end, pgd_t *pgd_base) { +#if defined(CONFIG_HIGHMEM) || defined(CONFIG_MIPS_MT_SMTC) pgd_t *pgd; pud_t *pud; pmd_t *pmd; @@ -122,7 +322,7 @@ for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) { if (pmd_none(*pmd)) { pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pmd(pmd, __pmd(pte)); + set_pmd(pmd, __pmd((unsigned long)pte)); if (pte != pte_offset_kernel(pmd, 0)) BUG(); } @@ -132,9 +332,8 @@ } j = 0; } +#endif } -#endif /* CONFIG_32BIT */ -#endif /* CONFIG_HIGHMEM */ #ifndef CONFIG_NEED_MULTIPLE_NODES extern void pagetable_init(void); @@ -175,6 +374,7 @@ #ifdef CONFIG_HIGHMEM kmap_init(); #endif + kmap_coherent_init(); max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT; low = max_low_pfn; diff -Naur linux-2.6.18/arch/mips/mm/pgtable-32.c linux-2.6.18.mips/arch/mips/mm/pgtable-32.c --- linux-2.6.18/arch/mips/mm/pgtable-32.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/mm/pgtable-32.c 2006-09-20 06:55:21.000000000 -0700 @@ -31,9 +31,10 @@ void __init pagetable_init(void) { -#ifdef CONFIG_HIGHMEM unsigned long vaddr; - pgd_t *pgd, *pgd_base; + pgd_t *pgd_base; +#ifdef CONFIG_HIGHMEM + pgd_t *pgd; pud_t *pud; pmd_t *pmd; pte_t *pte; @@ -44,7 +45,6 @@ pgd_init((unsigned long)swapper_pg_dir + sizeof(pgd_t) * USER_PTRS_PER_PGD); -#ifdef CONFIG_HIGHMEM pgd_base = swapper_pg_dir; /* @@ -53,6 +53,7 @@ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; fixrange_init(vaddr, 0, pgd_base); +#ifdef CONFIG_HIGHMEM /* * Permanent kmaps: */ diff -Naur linux-2.6.18/arch/mips/mm/pgtable-64.c linux-2.6.18.mips/arch/mips/mm/pgtable-64.c --- linux-2.6.18/arch/mips/mm/pgtable-64.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/mm/pgtable-64.c 2006-09-20 06:55:21.000000000 -0700 @@ -8,6 +8,7 @@ */ #include #include +#include #include void pgd_init(unsigned long page) @@ -52,7 +53,17 @@ void __init pagetable_init(void) { + unsigned long vaddr; + pgd_t *pgd_base; + /* Initialize the entire pgd. */ pgd_init((unsigned long)swapper_pg_dir); pmd_init((unsigned long)invalid_pmd_table, (unsigned long)invalid_pte_table); + + pgd_base = swapper_pg_dir; + /* + * Fixed mappings: + */ + vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; + fixrange_init(vaddr, 0, pgd_base); } diff -Naur linux-2.6.18/arch/mips/pci/fixup-atlas.c linux-2.6.18.mips/arch/mips/pci/fixup-atlas.c --- linux-2.6.18/arch/mips/pci/fixup-atlas.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/pci/fixup-atlas.c 2006-09-20 06:55:21.000000000 -0700 @@ -21,16 +21,16 @@ #include -#define PCIA ATLASINT_PCIA -#define PCIB ATLASINT_PCIB -#define PCIC ATLASINT_PCIC -#define PCID ATLASINT_PCID -#define INTA ATLASINT_INTA -#define INTB ATLASINT_INTB -#define ETH ATLASINT_ETH -#define INTC ATLASINT_INTC -#define SCSI ATLASINT_SCSI -#define INTD ATLASINT_INTD +#define PCIA ATLAS_INT_PCIA +#define PCIB ATLAS_INT_PCIB +#define PCIC ATLAS_INT_PCIC +#define PCID ATLAS_INT_PCID +#define INTA ATLAS_INT_INTA +#define INTB ATLAS_INT_INTB +#define ETH ATLAS_INT_ETH +#define INTC ATLAS_INT_INTC +#define SCSI ATLAS_INT_SCSI +#define INTD ATLAS_INT_INTD static char irq_tab[][5] __initdata = { /* INTA INTB INTC INTD */ diff -Naur linux-2.6.18/arch/mips/pci/fixup-tb0219.c linux-2.6.18.mips/arch/mips/pci/fixup-tb0219.c --- linux-2.6.18/arch/mips/pci/fixup-tb0219.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/pci/fixup-tb0219.c 2006-09-20 06:55:21.000000000 -0700 @@ -2,7 +2,7 @@ * fixup-tb0219.c, The TANBAC TB0219 specific PCI fixups. * * Copyright (C) 2003 Megasolution Inc. - * Copyright (C) 2004 Yoichi Yuasa + * Copyright (C) 2004-2005 Yoichi Yuasa * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff -Naur linux-2.6.18/arch/mips/pci/Makefile linux-2.6.18.mips/arch/mips/pci/Makefile --- linux-2.6.18/arch/mips/pci/Makefile 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/pci/Makefile 2006-09-20 06:55:21.000000000 -0700 @@ -28,7 +28,7 @@ obj-$(CONFIG_LASAT) += pci-lasat.o obj-$(CONFIG_MIPS_ATLAS) += fixup-atlas.o obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o -obj-$(CONFIG_MIPS_EV96100) += fixup-ev64120.o +obj-$(CONFIG_MIPS_EV64120) += fixup-ev64120.o obj-$(CONFIG_MIPS_EV96100) += fixup-ev96100.o pci-ev96100.o obj-$(CONFIG_MIPS_ITE8172) += fixup-ite8172g.o obj-$(CONFIG_MIPS_IVR) += fixup-ivr.o diff -Naur linux-2.6.18/arch/mips/pci/ops-au1000.c linux-2.6.18.mips/arch/mips/pci/ops-au1000.c --- linux-2.6.18/arch/mips/pci/ops-au1000.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/pci/ops-au1000.c 2006-09-20 06:55:21.000000000 -0700 @@ -110,7 +110,7 @@ if (first_cfg) { /* reserve a wired entry for pci config accesses */ first_cfg = 0; - pci_cfg_vm = get_vm_area(0x2000, 0); + pci_cfg_vm = get_vm_area(0x2000, VM_IOREMAP); if (!pci_cfg_vm) panic (KERN_ERR "PCI unable to get vm area\n"); pci_cfg_wired_entry = read_c0_wired(); diff -Naur linux-2.6.18/arch/mips/qemu/Makefile linux-2.6.18.mips/arch/mips/qemu/Makefile --- linux-2.6.18/arch/mips/qemu/Makefile 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/qemu/Makefile 2006-09-20 06:55:21.000000000 -0700 @@ -4,4 +4,5 @@ obj-y = q-firmware.o q-irq.o q-mem.o q-setup.o q-reset.o +obj-$(CONFIG_VT) += q-vga.o obj-$(CONFIG_SMP) += q-smp.o diff -Naur linux-2.6.18/arch/mips/qemu/q-setup.c linux-2.6.18.mips/arch/mips/qemu/q-setup.c --- linux-2.6.18/arch/mips/qemu/q-setup.c 2006-09-19 20:42:06.000000000 -0700 +++ linux-2.6.18.mips/arch/mips/qemu/q-setup.c 2006-09-20 06:55:21.000000000 -0700 @@ -2,6 +2,7 @@ #include #include +extern void qvga_init(void); extern void qemu_reboot_setup(void); #define QEMU_PORT_BASE 0xb4000000 @@ -23,5 +24,9 @@ void __init plat_mem_setup(void) { set_io_port_base(QEMU_PORT_BASE); +#ifdef CONFIG_VT + qvga_init(); +#endif + qemu_reboot_setup(); } diff -Naur linux-2.6.18/arch/mips/qemu/q-vga.c linux-2.6.18.mips/arch/mips/qemu/q-vga.c --- linux-2.6.18/arch/mips/qemu/q-vga.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.6.18.mips/arch/mips/qemu/q-vga.c 2006-09-20 06:55:21.000000000 -0700 @@ -0,0 +1,189 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2005 by Ralf Baechle (ralf@linux-mips.org) + * + * This will eventually go into the qemu firmware. + */ +#include +#include +#include +#include +#include