瀏覽代碼

Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus

* 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus: (22 commits)
  MIPS: Return after handling coprocessor 2 exception
  MIPS: BCM47xx: Add NVRAM support devices
  MIPS: Loongson: Define rtc device on MC146818-equipped systems
  MIPS: MT: Fix FPU affinity.
  MIPS: Oprofile: Fixup of loongson2_exit()
  MIPS: Alchemy: sleepcode without compile-time cputype dependencies
  MIPS: Tracing: Cleanup of address space checking
  MIPS: Tracing: Cleanup of function graph tracer
  MIPS: Tracing: Reduce the overhead of dynamic Function Tracer
  MIPS: Tracing: Cleanup of instructions used
  MIPS: Tracing: Fix 32-bit support with -mmcount-ra-address
  MIPS: Tracing: Fix argument passing of the 32bit support with gcc 4.5
  MIPS: Tracing: Cleanup comments
  MIPS: Tracing: Cleanup the arguments passing of prepare_ftrace_return
  MIPS: Tracing: Merge adjacent #ifdefs with same condition.
  MIPS: AR7, BCM63xx: fix gpio_to_irq() return value
  MIPS: Restore signalling NaN behaviour for abs.[sd]
  MIPS: Loongson: CS5536: Fix ISA support
  MIPS: Loongson: Add a missing break statement in CS5536 IDE code
  MIPS: Loongson: CS5536: Add missing RDMSRs for IDE and USB
  ...
Linus Torvalds 15 年之前
父節點
當前提交
7491eb9b5f

+ 9 - 3
arch/mips/alchemy/common/power.c

@@ -193,9 +193,15 @@ static void restore_core_regs(void)
 
 
 void au_sleep(void)
 void au_sleep(void)
 {
 {
-	save_core_regs();
-	au1xxx_save_and_sleep();
-	restore_core_regs();
+	int cpuid = alchemy_get_cputype();
+	if (cpuid != ALCHEMY_CPU_UNKNOWN) {
+		save_core_regs();
+		if (cpuid <= ALCHEMY_CPU_AU1500)
+			alchemy_sleep_au1000();
+		else if (cpuid <= ALCHEMY_CPU_AU1200)
+			alchemy_sleep_au1550();
+		restore_core_regs();
+	}
 }
 }
 
 
 #endif	/* CONFIG_PM */
 #endif	/* CONFIG_PM */

+ 53 - 28
arch/mips/alchemy/common/sleeper.S

@@ -22,10 +22,9 @@
 	.set noat
 	.set noat
 	.align	5
 	.align	5
 
 
-/* Save all of the processor general registers and go to sleep.
- * A wakeup condition will get us back here to restore the registers.
- */
-LEAF(au1xxx_save_and_sleep)
+
+/* preparatory stuff */
+.macro	SETUP_SLEEP
 	subu	sp, PT_SIZE
 	subu	sp, PT_SIZE
 	sw	$1, PT_R1(sp)
 	sw	$1, PT_R1(sp)
 	sw	$2, PT_R2(sp)
 	sw	$2, PT_R2(sp)
@@ -69,12 +68,32 @@ LEAF(au1xxx_save_and_sleep)
 	 */
 	 */
 	lui	t3, 0xb190		/* sys_xxx */
 	lui	t3, 0xb190		/* sys_xxx */
 	sw	sp, 0x0018(t3)
 	sw	sp, 0x0018(t3)
-	la	k0, 3f			/* resume path */
+	la	k0, alchemy_sleep_wakeup	/* resume path */
 	sw	k0, 0x001c(t3)
 	sw	k0, 0x001c(t3)
+.endm
 
 
-	/* Put SDRAM into self refresh:  Preload instructions into cache,
-	 * issue a precharge, auto/self refresh, then sleep commands to it.
-	 */
+.macro	DO_SLEEP
+	/* put power supply and processor to sleep */
+	sw	zero, 0x0078(t3)	/* sys_slppwr */
+	sync
+	sw	zero, 0x007c(t3)	/* sys_sleep */
+	sync
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+.endm
+
+/* sleep code for Au1000/Au1100/Au1500 memory controller type */
+LEAF(alchemy_sleep_au1000)
+
+	SETUP_SLEEP
+
+	/* cache following instructions, as memory gets put to sleep */
 	la	t0, 1f
 	la	t0, 1f
 	.set	mips3
 	.set	mips3
 	cache	0x14, 0(t0)
 	cache	0x14, 0(t0)
@@ -84,17 +103,32 @@ LEAF(au1xxx_save_and_sleep)
 	.set	mips0
 	.set	mips0
 
 
 1:	lui 	a0, 0xb400		/* mem_xxx */
 1:	lui 	a0, 0xb400		/* mem_xxx */
-#if defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100) ||	\
-    defined(CONFIG_SOC_AU1500)
 	sw	zero, 0x001c(a0) 	/* Precharge */
 	sw	zero, 0x001c(a0) 	/* Precharge */
 	sync
 	sync
 	sw	zero, 0x0020(a0)	/* Auto Refresh */
 	sw	zero, 0x0020(a0)	/* Auto Refresh */
 	sync
 	sync
 	sw	zero, 0x0030(a0)  	/* Sleep */
 	sw	zero, 0x0030(a0)  	/* Sleep */
 	sync
 	sync
-#endif
 
 
-#if defined(CONFIG_SOC_AU1550) || defined(CONFIG_SOC_AU1200)
+	DO_SLEEP
+
+END(alchemy_sleep_au1000)
+
+/* sleep code for Au1550/Au1200 memory controller type */
+LEAF(alchemy_sleep_au1550)
+
+	SETUP_SLEEP
+
+	/* cache following instructions, as memory gets put to sleep */
+	la	t0, 1f
+	.set	mips3
+	cache	0x14, 0(t0)
+	cache	0x14, 32(t0)
+	cache	0x14, 64(t0)
+	cache	0x14, 96(t0)
+	.set	mips0
+
+1:	lui 	a0, 0xb400		/* mem_xxx */
 	sw	zero, 0x08c0(a0) 	/* Precharge */
 	sw	zero, 0x08c0(a0) 	/* Precharge */
 	sync
 	sync
 	sw	zero, 0x08d0(a0)	/* Self Refresh */
 	sw	zero, 0x08d0(a0)	/* Self Refresh */
@@ -114,26 +148,17 @@ LEAF(au1xxx_save_and_sleep)
 	and 	t1, t0, t1		/* clear CE[1:0] */
 	and 	t1, t0, t1		/* clear CE[1:0] */
 	sw 	t1, 0x0840(a0)		/* mem_sdconfiga */
 	sw 	t1, 0x0840(a0)		/* mem_sdconfiga */
 	sync
 	sync
-#endif
 
 
-	/* put power supply and processor to sleep */
-	sw	zero, 0x0078(t3)	/* sys_slppwr */
-	sync
-	sw	zero, 0x007c(t3)	/* sys_sleep */
-	sync
-	nop
-	nop
-	nop
-	nop
-	nop
-	nop
-	nop
-	nop
+	DO_SLEEP
+
+END(alchemy_sleep_au1550)
+
 
 
 	/* This is where we return upon wakeup.
 	/* This is where we return upon wakeup.
 	 * Reload all of the registers and return.
 	 * Reload all of the registers and return.
 	 */
 	 */
-3:	lw	k0, 0x20(sp)
+LEAF(alchemy_sleep_wakeup)
+	lw	k0, 0x20(sp)
 	mtc0	k0, CP0_STATUS
 	mtc0	k0, CP0_STATUS
 	lw	k0, 0x1c(sp)
 	lw	k0, 0x1c(sp)
 	mtc0	k0, CP0_CONTEXT
 	mtc0	k0, CP0_CONTEXT
@@ -169,4 +194,4 @@ LEAF(au1xxx_save_and_sleep)
 	lw	$31, PT_R31(sp)
 	lw	$31, PT_R31(sp)
 	jr	ra
 	jr	ra
 	 addiu	sp, PT_SIZE
 	 addiu	sp, PT_SIZE
-END(au1xxx_save_and_sleep)
+END(alchemy_sleep_wakeup)

+ 1 - 1
arch/mips/ar7/platform.c

@@ -542,7 +542,7 @@ static int __init ar7_register_uarts(void)
 	if (IS_ERR(bus_clk))
 	if (IS_ERR(bus_clk))
 		panic("unable to get bus clk\n");
 		panic("unable to get bus clk\n");
 
 
-	uart_port.type		= PORT_16550A;
+	uart_port.type		= PORT_AR7;
 	uart_port.uartclk	= clk_get_rate(bus_clk) / 2;
 	uart_port.uartclk	= clk_get_rate(bus_clk) / 2;
 	uart_port.iotype	= UPIO_MEM32;
 	uart_port.iotype	= UPIO_MEM32;
 	uart_port.regshift	= 2;
 	uart_port.regshift	= 2;

+ 1 - 1
arch/mips/bcm47xx/Makefile

@@ -3,4 +3,4 @@
 # under Linux.
 # under Linux.
 #
 #
 
 
-obj-y := gpio.o irq.o prom.o serial.o setup.o time.o wgt634u.o
+obj-y := gpio.o irq.o nvram.o prom.o serial.o setup.o time.o wgt634u.o

+ 94 - 0
arch/mips/bcm47xx/nvram.c

@@ -0,0 +1,94 @@
+/*
+ * BCM947xx nvram variable access
+ *
+ * Copyright (C) 2005 Broadcom Corporation
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/ssb/ssb.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <asm/addrspace.h>
+#include <asm/mach-bcm47xx/nvram.h>
+#include <asm/mach-bcm47xx/bcm47xx.h>
+
+static char nvram_buf[NVRAM_SPACE];
+
+/* Probe for NVRAM header */
+static void __init early_nvram_init(void)
+{
+	struct ssb_mipscore *mcore = &ssb_bcm47xx.mipscore;
+	struct nvram_header *header;
+	int i;
+	u32 base, lim, off;
+	u32 *src, *dst;
+
+	base = mcore->flash_window;
+	lim = mcore->flash_window_size;
+
+	off = FLASH_MIN;
+	while (off <= lim) {
+		/* Windowed flash access */
+		header = (struct nvram_header *)
+			KSEG1ADDR(base + off - NVRAM_SPACE);
+		if (header->magic == NVRAM_HEADER)
+			goto found;
+		off <<= 1;
+	}
+
+	/* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
+	header = (struct nvram_header *) KSEG1ADDR(base + 4096);
+	if (header->magic == NVRAM_HEADER)
+		goto found;
+
+	header = (struct nvram_header *) KSEG1ADDR(base + 1024);
+	if (header->magic == NVRAM_HEADER)
+		goto found;
+
+	return;
+
+found:
+	src = (u32 *) header;
+	dst = (u32 *) nvram_buf;
+	for (i = 0; i < sizeof(struct nvram_header); i += 4)
+		*dst++ = *src++;
+	for (; i < header->len && i < NVRAM_SPACE; i += 4)
+		*dst++ = le32_to_cpu(*src++);
+}
+
+int nvram_getenv(char *name, char *val, size_t val_len)
+{
+	char *var, *value, *end, *eq;
+
+	if (!name)
+		return 1;
+
+	if (!nvram_buf[0])
+		early_nvram_init();
+
+	/* Look for name=value and return value */
+	var = &nvram_buf[sizeof(struct nvram_header)];
+	end = nvram_buf + sizeof(nvram_buf) - 2;
+	end[0] = end[1] = '\0';
+	for (; *var; var = value + strlen(value) + 1) {
+		eq = strchr(var, '=');
+		if (!eq)
+			break;
+		value = eq + 1;
+		if ((eq - var) == strlen(name) &&
+			strncmp(var, name, (eq - var)) == 0) {
+			snprintf(val, val_len, "%s", value);
+			return 0;
+		}
+	}
+	return 1;
+}
+EXPORT_SYMBOL(nvram_getenv);

+ 27 - 12
arch/mips/bcm47xx/setup.c

@@ -1,8 +1,8 @@
 /*
 /*
  *  Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
  *  Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
- *  Copyright (C) 2005 Waldemar Brodkorb <wbx@openwrt.org>
  *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
  *  Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
  *  Copyright (C) 2006 Michael Buesch <mb@bu3sch.de>
  *  Copyright (C) 2006 Michael Buesch <mb@bu3sch.de>
+ *  Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
  *
  *
  *  This program is free software; you can redistribute  it and/or modify it
  *  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
  *  under  the terms of  the GNU General  Public License as published by the
@@ -33,6 +33,7 @@
 #include <asm/time.h>
 #include <asm/time.h>
 #include <bcm47xx.h>
 #include <bcm47xx.h>
 #include <asm/fw/cfe/cfe_api.h>
 #include <asm/fw/cfe/cfe_api.h>
+#include <asm/mach-bcm47xx/nvram.h>
 
 
 struct ssb_bus ssb_bcm47xx;
 struct ssb_bus ssb_bcm47xx;
 EXPORT_SYMBOL(ssb_bcm47xx);
 EXPORT_SYMBOL(ssb_bcm47xx);
@@ -81,28 +82,42 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
 	/* Fill boardinfo structure */
 	/* Fill boardinfo structure */
 	memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
 	memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
 
 
-	if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0)
+	if (cfe_getenv("boardvendor", buf, sizeof(buf)) >= 0 ||
+	    nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0)
 		iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
 		iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
-	if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0)
+	if (cfe_getenv("boardtype", buf, sizeof(buf)) >= 0 ||
+	    nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
 		iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
 		iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
-	if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0)
+	if (cfe_getenv("boardrev", buf, sizeof(buf)) >= 0 ||
+	    nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
 		iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
 		iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
 
 
 	/* Fill sprom structure */
 	/* Fill sprom structure */
 	memset(&(iv->sprom), 0, sizeof(struct ssb_sprom));
 	memset(&(iv->sprom), 0, sizeof(struct ssb_sprom));
 	iv->sprom.revision = 3;
 	iv->sprom.revision = 3;
 
 
-	if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
+	if (cfe_getenv("et0macaddr", buf, sizeof(buf)) >= 0 ||
+	    nvram_getenv("et0macaddr", buf, sizeof(buf)) >= 0)
 		str2eaddr(buf, iv->sprom.et0mac);
 		str2eaddr(buf, iv->sprom.et0mac);
-	if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
+
+	if (cfe_getenv("et1macaddr", buf, sizeof(buf)) >= 0 ||
+	    nvram_getenv("et1macaddr", buf, sizeof(buf)) >= 0)
 		str2eaddr(buf, iv->sprom.et1mac);
 		str2eaddr(buf, iv->sprom.et1mac);
-	if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
-		iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 10);
-	if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0)
-		iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 10);
-	if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0)
+
+	if (cfe_getenv("et0phyaddr", buf, sizeof(buf)) >= 0 ||
+	    nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
+		iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 0);
+
+	if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0 ||
+	    nvram_getenv("et1phyaddr", buf, sizeof(buf)) >= 0)
+		iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 0);
+
+	if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 0 ||
+	    nvram_getenv("et0mdcport", buf, sizeof(buf)) >= 0)
 		iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10);
 		iv->sprom.et0mdcport = simple_strtoul(buf, NULL, 10);
-	if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0)
+
+	if (cfe_getenv("et1mdcport", buf, sizeof(buf)) >= 0 ||
+	    nvram_getenv("et1mdcport", buf, sizeof(buf)) >= 0)
 		iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10);
 		iv->sprom.et1mdcport = simple_strtoul(buf, NULL, 10);
 
 
 	return 0;
 	return 0;

+ 3 - 3
arch/mips/include/asm/mach-ar7/ar7.h

@@ -50,7 +50,7 @@
 #define UR8_REGS_WDT	(AR7_REGS_BASE + 0x0b00)
 #define UR8_REGS_WDT	(AR7_REGS_BASE + 0x0b00)
 #define UR8_REGS_UART1	(AR7_REGS_BASE + 0x0f00)
 #define UR8_REGS_UART1	(AR7_REGS_BASE + 0x0f00)
 
 
-#define AR7_RESET_PEREPHERIAL	0x0
+#define AR7_RESET_PERIPHERAL	0x0
 #define AR7_RESET_SOFTWARE	0x4
 #define AR7_RESET_SOFTWARE	0x4
 #define AR7_RESET_STATUS	0x8
 #define AR7_RESET_STATUS	0x8
 
 
@@ -128,7 +128,7 @@ static inline int ar7_has_high_cpmac(void)
 static inline void ar7_device_enable(u32 bit)
 static inline void ar7_device_enable(u32 bit)
 {
 {
 	void *reset_reg =
 	void *reset_reg =
-		(void *)KSEG1ADDR(AR7_REGS_RESET + AR7_RESET_PEREPHERIAL);
+		(void *)KSEG1ADDR(AR7_REGS_RESET + AR7_RESET_PERIPHERAL);
 	writel(readl(reset_reg) | (1 << bit), reset_reg);
 	writel(readl(reset_reg) | (1 << bit), reset_reg);
 	msleep(20);
 	msleep(20);
 }
 }
@@ -136,7 +136,7 @@ static inline void ar7_device_enable(u32 bit)
 static inline void ar7_device_disable(u32 bit)
 static inline void ar7_device_disable(u32 bit)
 {
 {
 	void *reset_reg =
 	void *reset_reg =
-		(void *)KSEG1ADDR(AR7_REGS_RESET + AR7_RESET_PEREPHERIAL);
+		(void *)KSEG1ADDR(AR7_REGS_RESET + AR7_RESET_PERIPHERAL);
 	writel(readl(reset_reg) & ~(1 << bit), reset_reg);
 	writel(readl(reset_reg) & ~(1 << bit), reset_reg);
 	msleep(20);
 	msleep(20);
 }
 }

+ 1 - 1
arch/mips/include/asm/mach-ar7/gpio.h

@@ -24,7 +24,7 @@
 #define AR7_GPIO_MAX 32
 #define AR7_GPIO_MAX 32
 #define NR_BUILTIN_GPIO AR7_GPIO_MAX
 #define NR_BUILTIN_GPIO AR7_GPIO_MAX
 
 
-#define gpio_to_irq(gpio)	NULL
+#define gpio_to_irq(gpio)	-1
 
 
 #define gpio_get_value __gpio_get_value
 #define gpio_get_value __gpio_get_value
 #define gpio_set_value __gpio_set_value
 #define gpio_set_value __gpio_set_value

+ 2 - 1
arch/mips/include/asm/mach-au1x00/au1000.h

@@ -188,7 +188,8 @@ extern unsigned long get_au1x00_uart_baud_base(void);
 extern unsigned long au1xxx_calc_clock(void);
 extern unsigned long au1xxx_calc_clock(void);
 
 
 /* PM: arch/mips/alchemy/common/sleeper.S, power.c, irq.c */
 /* PM: arch/mips/alchemy/common/sleeper.S, power.c, irq.c */
-void au1xxx_save_and_sleep(void);
+void alchemy_sleep_au1000(void);
+void alchemy_sleep_au1550(void);
 void au_sleep(void);
 void au_sleep(void);
 
 
 
 

+ 36 - 0
arch/mips/include/asm/mach-bcm47xx/nvram.h

@@ -0,0 +1,36 @@
+/*
+ *  Copyright (C) 2005, Broadcom Corporation
+ *  Copyright (C) 2006, Felix Fietkau <nbd@openwrt.org>
+ *
+ *  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.
+ */
+
+#ifndef __NVRAM_H
+#define __NVRAM_H
+
+#include <linux/types.h>
+
+struct nvram_header {
+	u32 magic;
+	u32 len;
+	u32 crc_ver_init;	/* 0:7 crc, 8:15 ver, 16:31 sdram_init */
+	u32 config_refresh;	/* 0:15 sdram_config, 16:31 sdram_refresh */
+	u32 config_ncdl;	/* ncdl values for memc */
+};
+
+#define NVRAM_HEADER		0x48534C46	/* 'FLSH' */
+#define NVRAM_VERSION		1
+#define NVRAM_HEADER_SIZE	20
+#define NVRAM_SPACE		0x8000
+
+#define FLASH_MIN		0x00020000	/* Minimum flash size */
+
+#define NVRAM_MAX_VALUE_LEN 255
+#define NVRAM_MAX_PARAM_LEN 64
+
+extern int nvram_getenv(char *name, char *val, size_t val_len);
+
+#endif

+ 1 - 1
arch/mips/include/asm/mach-bcm63xx/gpio.h

@@ -3,7 +3,7 @@
 
 
 #include <bcm63xx_gpio.h>
 #include <bcm63xx_gpio.h>
 
 
-#define gpio_to_irq(gpio)	NULL
+#define gpio_to_irq(gpio)	-1
 
 
 #define gpio_get_value __gpio_get_value
 #define gpio_get_value __gpio_get_value
 #define gpio_set_value __gpio_set_value
 #define gpio_set_value __gpio_set_value

+ 112 - 72
arch/mips/kernel/ftrace.c

@@ -2,7 +2,7 @@
  * Code for replacing ftrace calls with jumps.
  * Code for replacing ftrace calls with jumps.
  *
  *
  * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
  * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
- * Copyright (C) 2009 DSLab, Lanzhou University, China
+ * Copyright (C) 2009, 2010 DSLab, Lanzhou University, China
  * Author: Wu Zhangjin <wuzhangjin@gmail.com>
  * Author: Wu Zhangjin <wuzhangjin@gmail.com>
  *
  *
  * Thanks goes to Steven Rostedt for writing the original x86 version.
  * Thanks goes to Steven Rostedt for writing the original x86 version.
@@ -12,18 +12,62 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/ftrace.h>
 #include <linux/ftrace.h>
 
 
-#include <asm/cacheflush.h>
 #include <asm/asm.h>
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
 #include <asm/asm-offsets.h>
+#include <asm/cacheflush.h>
+#include <asm/uasm.h>
+
+/*
+ * If the Instruction Pointer is in module space (0xc0000000), return true;
+ * otherwise, it is in kernel space (0x80000000), return false.
+ *
+ * FIXME: This will not work when the kernel space and module space are the
+ * same. If they are the same, we need to modify scripts/recordmcount.pl,
+ * ftrace_make_nop/call() and the other related parts to ensure the
+ * enabling/disabling of the calling site to _mcount is right for both kernel
+ * and module.
+ */
+
+static inline int in_module(unsigned long ip)
+{
+	return ip & 0x40000000;
+}
 
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 #ifdef CONFIG_DYNAMIC_FTRACE
 
 
 #define JAL 0x0c000000		/* jump & link: ip --> ra, jump to target */
 #define JAL 0x0c000000		/* jump & link: ip --> ra, jump to target */
 #define ADDR_MASK 0x03ffffff	/*  op_code|addr : 31...26|25 ....0 */
 #define ADDR_MASK 0x03ffffff	/*  op_code|addr : 31...26|25 ....0 */
-#define jump_insn_encode(op_code, addr) \
-	((unsigned int)((op_code) | (((addr) >> 2) & ADDR_MASK)))
 
 
-static unsigned int ftrace_nop = 0x00000000;
+#define INSN_B_1F_4 0x10000004	/* b 1f; offset = 4 */
+#define INSN_B_1F_5 0x10000005	/* b 1f; offset = 5 */
+#define INSN_NOP 0x00000000	/* nop */
+#define INSN_JAL(addr)	\
+	((unsigned int)(JAL | (((addr) >> 2) & ADDR_MASK)))
+
+static unsigned int insn_jal_ftrace_caller __read_mostly;
+static unsigned int insn_lui_v1_hi16_mcount __read_mostly;
+static unsigned int insn_j_ftrace_graph_caller __maybe_unused __read_mostly;
+
+static inline void ftrace_dyn_arch_init_insns(void)
+{
+	u32 *buf;
+	unsigned int v1;
+
+	/* lui v1, hi16_mcount */
+	v1 = 3;
+	buf = (u32 *)&insn_lui_v1_hi16_mcount;
+	UASM_i_LA_mostly(&buf, v1, MCOUNT_ADDR);
+
+	/* jal (ftrace_caller + 8), jump over the first two instruction */
+	buf = (u32 *)&insn_jal_ftrace_caller;
+	uasm_i_jal(&buf, (FTRACE_ADDR + 8));
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	/* j ftrace_graph_caller */
+	buf = (u32 *)&insn_j_ftrace_graph_caller;
+	uasm_i_j(&buf, (unsigned long)ftrace_graph_caller);
+#endif
+}
 
 
 static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
 static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
 {
 {
@@ -40,67 +84,56 @@ static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
 	return 0;
 	return 0;
 }
 }
 
 
-static int lui_v1;
-static int jal_mcount;
-
 int ftrace_make_nop(struct module *mod,
 int ftrace_make_nop(struct module *mod,
 		    struct dyn_ftrace *rec, unsigned long addr)
 		    struct dyn_ftrace *rec, unsigned long addr)
 {
 {
 	unsigned int new;
 	unsigned int new;
-	int faulted;
 	unsigned long ip = rec->ip;
 	unsigned long ip = rec->ip;
 
 
-	/* We have compiled module with -mlong-calls, but compiled the kernel
-	 * without it, we need to cope with them respectively. */
-	if (ip & 0x40000000) {
-		/* record it for ftrace_make_call */
-		if (lui_v1 == 0) {
-			/* lui_v1 = *(unsigned int *)ip; */
-			safe_load_code(lui_v1, ip, faulted);
-
-			if (unlikely(faulted))
-				return -EFAULT;
-		}
-
-		/* lui v1, hi_16bit_of_mcount        --> b 1f (0x10000004)
+	/*
+	 * We have compiled module with -mlong-calls, but compiled the kernel
+	 * without it, we need to cope with them respectively.
+	 */
+	if (in_module(ip)) {
+#if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT)
+		/*
+		 * lui v1, hi_16bit_of_mcount        --> b 1f (0x10000005)
+		 * addiu v1, v1, low_16bit_of_mcount
+		 * move at, ra
+		 * move $12, ra_address
+		 * jalr v1
+		 *  sub sp, sp, 8
+		 *                                  1: offset = 5 instructions
+		 */
+		new = INSN_B_1F_5;
+#else
+		/*
+		 * lui v1, hi_16bit_of_mcount        --> b 1f (0x10000004)
 		 * addiu v1, v1, low_16bit_of_mcount
 		 * addiu v1, v1, low_16bit_of_mcount
 		 * move at, ra
 		 * move at, ra
 		 * jalr v1
 		 * jalr v1
-		 * nop
-		 * 				     1f: (ip + 12)
+		 *  nop | move $12, ra_address | sub sp, sp, 8
+		 *                                  1: offset = 4 instructions
 		 */
 		 */
-		new = 0x10000004;
+		new = INSN_B_1F_4;
+#endif
 	} else {
 	} else {
-		/* record/calculate it for ftrace_make_call */
-		if (jal_mcount == 0) {
-			/* We can record it directly like this:
-			 *     jal_mcount = *(unsigned int *)ip;
-			 * Herein, jump over the first two nop instructions */
-			jal_mcount = jump_insn_encode(JAL, (MCOUNT_ADDR + 8));
-		}
-
-		/* move at, ra
-		 * jalr v1		--> nop
+		/*
+		 * move at, ra
+		 * jal _mcount		--> nop
 		 */
 		 */
-		new = ftrace_nop;
+		new = INSN_NOP;
 	}
 	}
 	return ftrace_modify_code(ip, new);
 	return ftrace_modify_code(ip, new);
 }
 }
 
 
-static int modified;	/* initialized as 0 by default */
-
 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 {
 {
 	unsigned int new;
 	unsigned int new;
 	unsigned long ip = rec->ip;
 	unsigned long ip = rec->ip;
 
 
-	/* We just need to remove the "b ftrace_stub" at the fist time! */
-	if (modified == 0) {
-		modified = 1;
-		ftrace_modify_code(addr, ftrace_nop);
-	}
 	/* ip, module: 0xc0000000, kernel: 0x80000000 */
 	/* ip, module: 0xc0000000, kernel: 0x80000000 */
-	new = (ip & 0x40000000) ? lui_v1 : jal_mcount;
+	new = in_module(ip) ? insn_lui_v1_hi16_mcount : insn_jal_ftrace_caller;
 
 
 	return ftrace_modify_code(ip, new);
 	return ftrace_modify_code(ip, new);
 }
 }
@@ -111,44 +144,48 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
 {
 {
 	unsigned int new;
 	unsigned int new;
 
 
-	new = jump_insn_encode(JAL, (unsigned long)func);
+	new = INSN_JAL((unsigned long)func);
 
 
 	return ftrace_modify_code(FTRACE_CALL_IP, new);
 	return ftrace_modify_code(FTRACE_CALL_IP, new);
 }
 }
 
 
 int __init ftrace_dyn_arch_init(void *data)
 int __init ftrace_dyn_arch_init(void *data)
 {
 {
+	/* Encode the instructions when booting */
+	ftrace_dyn_arch_init_insns();
+
+	/* Remove "b ftrace_stub" to ensure ftrace_caller() is executed */
+	ftrace_modify_code(MCOUNT_ADDR, INSN_NOP);
+
 	/* The return code is retured via data */
 	/* The return code is retured via data */
 	*(unsigned long *)data = 0;
 	*(unsigned long *)data = 0;
 
 
 	return 0;
 	return 0;
 }
 }
-#endif				/* CONFIG_DYNAMIC_FTRACE */
+#endif	/* CONFIG_DYNAMIC_FTRACE */
 
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
 
 #ifdef CONFIG_DYNAMIC_FTRACE
 #ifdef CONFIG_DYNAMIC_FTRACE
 
 
 extern void ftrace_graph_call(void);
 extern void ftrace_graph_call(void);
-#define JMP	0x08000000	/* jump to target directly */
-#define CALL_FTRACE_GRAPH_CALLER \
-	jump_insn_encode(JMP, (unsigned long)(&ftrace_graph_caller))
 #define FTRACE_GRAPH_CALL_IP	((unsigned long)(&ftrace_graph_call))
 #define FTRACE_GRAPH_CALL_IP	((unsigned long)(&ftrace_graph_call))
 
 
 int ftrace_enable_ftrace_graph_caller(void)
 int ftrace_enable_ftrace_graph_caller(void)
 {
 {
 	return ftrace_modify_code(FTRACE_GRAPH_CALL_IP,
 	return ftrace_modify_code(FTRACE_GRAPH_CALL_IP,
-				  CALL_FTRACE_GRAPH_CALLER);
+			insn_j_ftrace_graph_caller);
 }
 }
 
 
 int ftrace_disable_ftrace_graph_caller(void)
 int ftrace_disable_ftrace_graph_caller(void)
 {
 {
-	return ftrace_modify_code(FTRACE_GRAPH_CALL_IP, ftrace_nop);
+	return ftrace_modify_code(FTRACE_GRAPH_CALL_IP, INSN_NOP);
 }
 }
 
 
-#endif				/* !CONFIG_DYNAMIC_FTRACE */
+#endif	/* CONFIG_DYNAMIC_FTRACE */
 
 
 #ifndef KBUILD_MCOUNT_RA_ADDRESS
 #ifndef KBUILD_MCOUNT_RA_ADDRESS
+
 #define S_RA_SP	(0xafbf << 16)	/* s{d,w} ra, offset(sp) */
 #define S_RA_SP	(0xafbf << 16)	/* s{d,w} ra, offset(sp) */
 #define S_R_SP	(0xafb0 << 16)  /* s{d,w} R, offset(sp) */
 #define S_R_SP	(0xafb0 << 16)  /* s{d,w} R, offset(sp) */
 #define OFFSET_MASK	0xffff	/* stack offset range: 0 ~ PT_SIZE */
 #define OFFSET_MASK	0xffff	/* stack offset range: 0 ~ PT_SIZE */
@@ -162,17 +199,17 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr,
 	unsigned int code;
 	unsigned int code;
 	int faulted;
 	int faulted;
 
 
-	/* in module or kernel? */
-	if (self_addr & 0x40000000) {
-		/* module: move to the instruction "lui v1, HI_16BIT_OF_MCOUNT" */
-		ip = self_addr - 20;
-	} else {
-		/* kernel: move to the instruction "move ra, at" */
-		ip = self_addr - 12;
-	}
+	/*
+	 * For module, move the ip from calling site of mcount to the
+	 * instruction "lui v1, hi_16bit_of_mcount"(offset is 20), but for
+	 * kernel, move to the instruction "move ra, at"(offset is 12)
+	 */
+	ip = self_addr - (in_module(self_addr) ? 20 : 12);
 
 
-	/* search the text until finding the non-store instruction or "s{d,w}
-	 * ra, offset(sp)" instruction */
+	/*
+	 * search the text until finding the non-store instruction or "s{d,w}
+	 * ra, offset(sp)" instruction
+	 */
 	do {
 	do {
 		ip -= 4;
 		ip -= 4;
 
 
@@ -181,10 +218,11 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr,
 
 
 		if (unlikely(faulted))
 		if (unlikely(faulted))
 			return 0;
 			return 0;
-
-		/* If we hit the non-store instruction before finding where the
+		/*
+		 * If we hit the non-store instruction before finding where the
 		 * ra is stored, then this is a leaf function and it does not
 		 * ra is stored, then this is a leaf function and it does not
-		 * store the ra on the stack. */
+		 * store the ra on the stack
+		 */
 		if ((code & S_R_SP) != S_R_SP)
 		if ((code & S_R_SP) != S_R_SP)
 			return parent_addr;
 			return parent_addr;
 
 
@@ -202,7 +240,7 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr,
 	return 0;
 	return 0;
 }
 }
 
 
-#endif
+#endif	/* !KBUILD_MCOUNT_RA_ADDRESS */
 
 
 /*
 /*
  * Hook the return address and push it in the stack of return addrs
  * Hook the return address and push it in the stack of return addrs
@@ -220,7 +258,8 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
 	if (unlikely(atomic_read(&current->tracing_graph_pause)))
 	if (unlikely(atomic_read(&current->tracing_graph_pause)))
 		return;
 		return;
 
 
-	/* "parent" is the stack address saved the return address of the caller
+	/*
+	 * "parent" is the stack address saved the return address of the caller
 	 * of _mcount.
 	 * of _mcount.
 	 *
 	 *
 	 * if the gcc < 4.5, a leaf function does not save the return address
 	 * if the gcc < 4.5, a leaf function does not save the return address
@@ -242,10 +281,11 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
 		goto out;
 		goto out;
 #ifndef KBUILD_MCOUNT_RA_ADDRESS
 #ifndef KBUILD_MCOUNT_RA_ADDRESS
 	parent = (unsigned long *)ftrace_get_parent_addr(self_addr, old,
 	parent = (unsigned long *)ftrace_get_parent_addr(self_addr, old,
-							 (unsigned long)parent,
-							 fp);
-	/* If fails when getting the stack address of the non-leaf function's
-	 * ra, stop function graph tracer and return */
+			(unsigned long)parent, fp);
+	/*
+	 * If fails when getting the stack address of the non-leaf function's
+	 * ra, stop function graph tracer and return
+	 */
 	if (parent == 0)
 	if (parent == 0)
 		goto out;
 		goto out;
 #endif
 #endif
@@ -272,4 +312,4 @@ out:
 	ftrace_graph_stop();
 	ftrace_graph_stop();
 	WARN_ON(1);
 	WARN_ON(1);
 }
 }
-#endif				/* CONFIG_FUNCTION_GRAPH_TRACER */
+#endif	/* CONFIG_FUNCTION_GRAPH_TRACER */

+ 34 - 21
arch/mips/kernel/mcount.S

@@ -6,6 +6,7 @@
  * more details.
  * more details.
  *
  *
  * Copyright (C) 2009 Lemote Inc. & DSLab, Lanzhou University, China
  * Copyright (C) 2009 Lemote Inc. & DSLab, Lanzhou University, China
+ * Copyright (C) 2010 DSLab, Lanzhou University, China
  * Author: Wu Zhangjin <wuzhangjin@gmail.com>
  * Author: Wu Zhangjin <wuzhangjin@gmail.com>
  */
  */
 
 
@@ -45,8 +46,6 @@
 	PTR_L	a5, PT_R9(sp)
 	PTR_L	a5, PT_R9(sp)
 	PTR_L	a6, PT_R10(sp)
 	PTR_L	a6, PT_R10(sp)
 	PTR_L	a7, PT_R11(sp)
 	PTR_L	a7, PT_R11(sp)
-#endif
-#ifdef CONFIG_64BIT
 	PTR_ADDIU	sp, PT_SIZE
 	PTR_ADDIU	sp, PT_SIZE
 #else
 #else
 	PTR_ADDIU	sp, (PT_SIZE + 8)
 	PTR_ADDIU	sp, (PT_SIZE + 8)
@@ -58,6 +57,12 @@
 	 move ra, AT
 	 move ra, AT
 	.endm
 	.endm
 
 
+/*
+ * The -mmcount-ra-address option of gcc 4.5 uses register $12 to pass
+ * the location of the parent's return address.
+ */
+#define MCOUNT_RA_ADDRESS_REG	$12
+
 #ifdef CONFIG_DYNAMIC_FTRACE
 #ifdef CONFIG_DYNAMIC_FTRACE
 
 
 NESTED(ftrace_caller, PT_SIZE, ra)
 NESTED(ftrace_caller, PT_SIZE, ra)
@@ -71,14 +76,14 @@ _mcount:
 
 
 	MCOUNT_SAVE_REGS
 	MCOUNT_SAVE_REGS
 #ifdef KBUILD_MCOUNT_RA_ADDRESS
 #ifdef KBUILD_MCOUNT_RA_ADDRESS
-	PTR_S	t0, PT_R12(sp)	/* t0 saved the location of the return address(at) by -mmcount-ra-address */
+	PTR_S	MCOUNT_RA_ADDRESS_REG, PT_R12(sp)
 #endif
 #endif
 
 
-	move	a0, ra		/* arg1: next ip, selfaddr */
+	move	a0, ra		/* arg1: self return address */
 	.globl ftrace_call
 	.globl ftrace_call
 ftrace_call:
 ftrace_call:
 	nop	/* a placeholder for the call to a real tracing function */
 	nop	/* a placeholder for the call to a real tracing function */
-	 move	a1, AT		/* arg2: the caller's next ip, parent */
+	 move	a1, AT		/* arg2: parent's return address */
 
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 	.globl ftrace_graph_call
 	.globl ftrace_graph_call
@@ -119,9 +124,9 @@ NESTED(_mcount, PT_SIZE, ra)
 static_trace:
 static_trace:
 	MCOUNT_SAVE_REGS
 	MCOUNT_SAVE_REGS
 
 
-	move	a0, ra		/* arg1: next ip, selfaddr */
+	move	a0, ra		/* arg1: self return address */
 	jalr	t2		/* (1) call *ftrace_trace_function */
 	jalr	t2		/* (1) call *ftrace_trace_function */
-	 move	a1, AT		/* arg2: the caller's next ip, parent */
+	 move	a1, AT		/* arg2: parent's return address */
 
 
 	MCOUNT_RESTORE_REGS
 	MCOUNT_RESTORE_REGS
 	.globl ftrace_stub
 	.globl ftrace_stub
@@ -134,28 +139,34 @@ ftrace_stub:
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 
 
 NESTED(ftrace_graph_caller, PT_SIZE, ra)
 NESTED(ftrace_graph_caller, PT_SIZE, ra)
-#ifdef CONFIG_DYNAMIC_FTRACE
-	PTR_L	a1, PT_R31(sp)	/* load the original ra from the stack */
-#ifdef KBUILD_MCOUNT_RA_ADDRESS
-	PTR_L	t0, PT_R12(sp)	/* load the original t0 from the stack */
-#endif
-#else
+#ifndef CONFIG_DYNAMIC_FTRACE
 	MCOUNT_SAVE_REGS
 	MCOUNT_SAVE_REGS
-	move	a1, ra		/* arg2: next ip, selfaddr */
 #endif
 #endif
 
 
+	/* arg1: Get the location of the parent's return address */
 #ifdef KBUILD_MCOUNT_RA_ADDRESS
 #ifdef KBUILD_MCOUNT_RA_ADDRESS
-	bnez	t0, 1f		/* non-leaf func: t0 saved the location of the return address */
+#ifdef CONFIG_DYNAMIC_FTRACE
+	PTR_L	a0, PT_R12(sp)
+#else
+	move	a0, MCOUNT_RA_ADDRESS_REG
+#endif
+	bnez	a0, 1f	/* non-leaf func: stored in MCOUNT_RA_ADDRESS_REG */
 	 nop
 	 nop
-	PTR_LA	t0, PT_R1(sp)	/* leaf func: get the location of at(old ra) from our own stack */
-1:	move	a0, t0		/* arg1: the location of the return address */
+#endif
+	PTR_LA	a0, PT_R1(sp)	/* leaf func: the location in current stack */
+1:
+
+	/* arg2: Get self return address */
+#ifdef CONFIG_DYNAMIC_FTRACE
+	PTR_L	a1, PT_R31(sp)
 #else
 #else
-	PTR_LA	a0, PT_R1(sp)	/* arg1: &AT -> a0 */
+	move	a1, ra
 #endif
 #endif
-	jal	prepare_ftrace_return
+
+	/* arg3: Get frame pointer of current stack */
 #ifdef CONFIG_FRAME_POINTER
 #ifdef CONFIG_FRAME_POINTER
-	 move	a2, fp		/* arg3: frame pointer */
-#else
+	 move	a2, fp
+#else /* ! CONFIG_FRAME_POINTER */
 #ifdef CONFIG_64BIT
 #ifdef CONFIG_64BIT
 	 PTR_LA	a2, PT_SIZE(sp)
 	 PTR_LA	a2, PT_SIZE(sp)
 #else
 #else
@@ -163,6 +174,8 @@ NESTED(ftrace_graph_caller, PT_SIZE, ra)
 #endif
 #endif
 #endif
 #endif
 
 
+	jal	prepare_ftrace_return
+	 nop
 	MCOUNT_RESTORE_REGS
 	MCOUNT_RESTORE_REGS
 	RETURN_BACK
 	RETURN_BACK
 	END(ftrace_graph_caller)
 	END(ftrace_graph_caller)

+ 61 - 26
arch/mips/kernel/mips-mt-fpaff.c

@@ -3,6 +3,7 @@
  * Copyright (C) 2005 Mips Technologies, Inc
  * Copyright (C) 2005 Mips Technologies, Inc
  */
  */
 #include <linux/cpu.h>
 #include <linux/cpu.h>
+#include <linux/cpuset.h>
 #include <linux/cpumask.h>
 #include <linux/cpumask.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
@@ -39,6 +40,21 @@ static inline struct task_struct *find_process_by_pid(pid_t pid)
 	return pid ? find_task_by_vpid(pid) : current;
 	return pid ? find_task_by_vpid(pid) : current;
 }
 }
 
 
+/*
+ * check the target process has a UID that matches the current process's
+ */
+static bool check_same_owner(struct task_struct *p)
+{
+	const struct cred *cred = current_cred(), *pcred;
+	bool match;
+
+	rcu_read_lock();
+	pcred = __task_cred(p);
+	match = (cred->euid == pcred->euid ||
+		 cred->euid == pcred->uid);
+	rcu_read_unlock();
+	return match;
+}
 
 
 /*
 /*
  * mipsmt_sys_sched_setaffinity - set the cpu affinity of a process
  * mipsmt_sys_sched_setaffinity - set the cpu affinity of a process
@@ -46,12 +62,10 @@ static inline struct task_struct *find_process_by_pid(pid_t pid)
 asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
 asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
 				      unsigned long __user *user_mask_ptr)
 				      unsigned long __user *user_mask_ptr)
 {
 {
-	cpumask_t new_mask;
-	cpumask_t effective_mask;
-	int retval;
-	struct task_struct *p;
+	cpumask_var_t cpus_allowed, new_mask, effective_mask;
 	struct thread_info *ti;
 	struct thread_info *ti;
-	uid_t euid;
+	struct task_struct *p;
+	int retval;
 
 
 	if (len < sizeof(new_mask))
 	if (len < sizeof(new_mask))
 		return -EINVAL;
 		return -EINVAL;
@@ -60,53 +74,74 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
 		return -EFAULT;
 		return -EFAULT;
 
 
 	get_online_cpus();
 	get_online_cpus();
-	read_lock(&tasklist_lock);
+	rcu_read_lock();
 
 
 	p = find_process_by_pid(pid);
 	p = find_process_by_pid(pid);
 	if (!p) {
 	if (!p) {
-		read_unlock(&tasklist_lock);
+		rcu_read_unlock();
 		put_online_cpus();
 		put_online_cpus();
 		return -ESRCH;
 		return -ESRCH;
 	}
 	}
 
 
-	/*
-	 * It is not safe to call set_cpus_allowed with the
-	 * tasklist_lock held.  We will bump the task_struct's
-	 * usage count and drop tasklist_lock before invoking
-	 * set_cpus_allowed.
-	 */
+	/* Prevent p going away */
 	get_task_struct(p);
 	get_task_struct(p);
+	rcu_read_unlock();
 
 
-	euid = current_euid();
+	if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) {
+		retval = -ENOMEM;
+		goto out_put_task;
+	}
+	if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) {
+		retval = -ENOMEM;
+		goto out_free_cpus_allowed;
+	}
+	if (!alloc_cpumask_var(&effective_mask, GFP_KERNEL)) {
+		retval = -ENOMEM;
+		goto out_free_new_mask;
+	}
 	retval = -EPERM;
 	retval = -EPERM;
-	if (euid != p->cred->euid && euid != p->cred->uid &&
-	    !capable(CAP_SYS_NICE)) {
-		read_unlock(&tasklist_lock);
+	if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
 		goto out_unlock;
 		goto out_unlock;
-	}
 
 
 	retval = security_task_setscheduler(p, 0, NULL);
 	retval = security_task_setscheduler(p, 0, NULL);
 	if (retval)
 	if (retval)
 		goto out_unlock;
 		goto out_unlock;
 
 
 	/* Record new user-specified CPU set for future reference */
 	/* Record new user-specified CPU set for future reference */
-	p->thread.user_cpus_allowed = new_mask;
-
-	/* Unlock the task list */
-	read_unlock(&tasklist_lock);
+	cpumask_copy(&p->thread.user_cpus_allowed, new_mask);
 
 
+ again:
 	/* Compute new global allowed CPU set if necessary */
 	/* Compute new global allowed CPU set if necessary */
 	ti = task_thread_info(p);
 	ti = task_thread_info(p);
 	if (test_ti_thread_flag(ti, TIF_FPUBOUND) &&
 	if (test_ti_thread_flag(ti, TIF_FPUBOUND) &&
-	    cpus_intersects(new_mask, mt_fpu_cpumask)) {
-		cpus_and(effective_mask, new_mask, mt_fpu_cpumask);
-		retval = set_cpus_allowed_ptr(p, &effective_mask);
+	    cpus_intersects(*new_mask, mt_fpu_cpumask)) {
+		cpus_and(*effective_mask, *new_mask, mt_fpu_cpumask);
+		retval = set_cpus_allowed_ptr(p, effective_mask);
 	} else {
 	} else {
+		cpumask_copy(effective_mask, new_mask);
 		clear_ti_thread_flag(ti, TIF_FPUBOUND);
 		clear_ti_thread_flag(ti, TIF_FPUBOUND);
-		retval = set_cpus_allowed_ptr(p, &new_mask);
+		retval = set_cpus_allowed_ptr(p, new_mask);
 	}
 	}
 
 
+	if (!retval) {
+		cpuset_cpus_allowed(p, cpus_allowed);
+		if (!cpumask_subset(effective_mask, cpus_allowed)) {
+			/*
+			 * We must have raced with a concurrent cpuset
+			 * update. Just reset the cpus_allowed to the
+			 * cpuset's cpus_allowed
+			 */
+			cpumask_copy(new_mask, cpus_allowed);
+			goto again;
+		}
+	}
 out_unlock:
 out_unlock:
+	free_cpumask_var(effective_mask);
+out_free_new_mask:
+	free_cpumask_var(new_mask);
+out_free_cpus_allowed:
+	free_cpumask_var(cpus_allowed);
+out_put_task:
 	put_task_struct(p);
 	put_task_struct(p);
 	put_online_cpus();
 	put_online_cpus();
 	return retval;
 	return retval;

+ 1 - 1
arch/mips/kernel/traps.c

@@ -976,7 +976,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
 
 
 	case 2:
 	case 2:
 		raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs);
 		raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs);
-		break;
+		return;
 
 
 	case 3:
 	case 3:
 		break;
 		break;

+ 6 - 0
arch/mips/loongson/Kconfig

@@ -23,6 +23,7 @@ config LEMOTE_FULOONG2E
 	select GENERIC_HARDIRQS_NO__DO_IRQ
 	select GENERIC_HARDIRQS_NO__DO_IRQ
 	select GENERIC_ISA_DMA_SUPPORT_BROKEN
 	select GENERIC_ISA_DMA_SUPPORT_BROKEN
 	select CPU_HAS_WB
 	select CPU_HAS_WB
+	select LOONGSON_MC146818
 	help
 	help
 	  Lemote Fuloong(2e) mini-PC board based on the Chinese Loongson-2E CPU and
 	  Lemote Fuloong(2e) mini-PC board based on the Chinese Loongson-2E CPU and
 	  an FPGA northbridge
 	  an FPGA northbridge
@@ -51,6 +52,7 @@ config LEMOTE_MACH2F
 	select SYS_SUPPORTS_64BIT_KERNEL
 	select SYS_SUPPORTS_64BIT_KERNEL
 	select SYS_SUPPORTS_HIGHMEM
 	select SYS_SUPPORTS_HIGHMEM
 	select SYS_SUPPORTS_LITTLE_ENDIAN
 	select SYS_SUPPORTS_LITTLE_ENDIAN
+	select LOONGSON_MC146818
 	help
 	help
 	  Lemote Loongson 2F family machines utilize the 2F revision of
 	  Lemote Loongson 2F family machines utilize the 2F revision of
 	  Loongson processor and the AMD CS5536 south bridge.
 	  Loongson processor and the AMD CS5536 south bridge.
@@ -83,3 +85,7 @@ config LOONGSON_UART_BASE
 	bool
 	bool
 	default y
 	default y
 	depends on EARLY_PRINTK || SERIAL_8250
 	depends on EARLY_PRINTK || SERIAL_8250
+
+config LOONGSON_MC146818
+	bool
+	default n

+ 1 - 0
arch/mips/loongson/common/Makefile

@@ -12,6 +12,7 @@ obj-$(CONFIG_GENERIC_GPIO) += gpio.o
 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
 obj-$(CONFIG_SERIAL_8250) += serial.o
 obj-$(CONFIG_SERIAL_8250) += serial.o
 obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o
 obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o
+obj-$(CONFIG_LOONGSON_MC146818) += rtc.o
 
 
 #
 #
 # Enable CS5536 Virtual Support Module(VSM) to virtulize the PCI configure
 # Enable CS5536 Virtual Support Module(VSM) to virtulize the PCI configure

+ 2 - 0
arch/mips/loongson/common/cs5536/cs5536_ehci.c

@@ -49,6 +49,8 @@ void pci_ehci_write_reg(int reg, u32 value)
 			lo |= SOFT_BAR_EHCI_FLAG;
 			lo |= SOFT_BAR_EHCI_FLAG;
 			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
 			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
 		} else if ((value & 0x01) == 0x00) {
 		} else if ((value & 0x01) == 0x00) {
+			_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
+			lo = value;
 			_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
 			_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
 
 
 			value &= 0xfffffff0;
 			value &= 0xfffffff0;

+ 14 - 1
arch/mips/loongson/common/cs5536/cs5536_ide.c

@@ -51,6 +51,7 @@ void pci_ide_write_reg(int reg, u32 value)
 			lo |= SOFT_BAR_IDE_FLAG;
 			lo |= SOFT_BAR_IDE_FLAG;
 			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
 			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
 		} else if (value & 0x01) {
 		} else if (value & 0x01) {
+			_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
 			lo = (value & 0xfffffff0) | 0x1;
 			lo = (value & 0xfffffff0) | 0x1;
 			_wrmsr(IDE_MSR_REG(IDE_IO_BAR), hi, lo);
 			_wrmsr(IDE_MSR_REG(IDE_IO_BAR), hi, lo);
 
 
@@ -65,19 +66,30 @@ void pci_ide_write_reg(int reg, u32 value)
 			_rdmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), &hi, &lo);
 			_rdmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), &hi, &lo);
 			lo |= 0x01;
 			lo |= 0x01;
 			_wrmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), hi, lo);
 			_wrmsr(DIVIL_MSR_REG(DIVIL_BALL_OPTS), hi, lo);
-		} else
+		} else {
+			_rdmsr(IDE_MSR_REG(IDE_CFG), &hi, &lo);
+			lo = value;
 			_wrmsr(IDE_MSR_REG(IDE_CFG), hi, lo);
 			_wrmsr(IDE_MSR_REG(IDE_CFG), hi, lo);
+		}
 		break;
 		break;
 	case PCI_IDE_DTC_REG:
 	case PCI_IDE_DTC_REG:
+		_rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
+		lo = value;
 		_wrmsr(IDE_MSR_REG(IDE_DTC), hi, lo);
 		_wrmsr(IDE_MSR_REG(IDE_DTC), hi, lo);
 		break;
 		break;
 	case PCI_IDE_CAST_REG:
 	case PCI_IDE_CAST_REG:
+		_rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
+		lo = value;
 		_wrmsr(IDE_MSR_REG(IDE_CAST), hi, lo);
 		_wrmsr(IDE_MSR_REG(IDE_CAST), hi, lo);
 		break;
 		break;
 	case PCI_IDE_ETC_REG:
 	case PCI_IDE_ETC_REG:
+		_rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
+		lo = value;
 		_wrmsr(IDE_MSR_REG(IDE_ETC), hi, lo);
 		_wrmsr(IDE_MSR_REG(IDE_ETC), hi, lo);
 		break;
 		break;
 	case PCI_IDE_PM_REG:
 	case PCI_IDE_PM_REG:
+		_rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
+		lo = value;
 		_wrmsr(IDE_MSR_REG(IDE_INTERNAL_PM), hi, lo);
 		_wrmsr(IDE_MSR_REG(IDE_INTERNAL_PM), hi, lo);
 		break;
 		break;
 	default:
 	default:
@@ -167,6 +179,7 @@ u32 pci_ide_read_reg(int reg)
 	case PCI_IDE_ETC_REG:
 	case PCI_IDE_ETC_REG:
 		_rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
 		_rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
 		conf_data = lo;
 		conf_data = lo;
+		break;
 	case PCI_IDE_PM_REG:
 	case PCI_IDE_PM_REG:
 		_rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
 		_rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
 		conf_data = lo;
 		conf_data = lo;

+ 2 - 2
arch/mips/loongson/common/cs5536/cs5536_isa.c

@@ -61,7 +61,7 @@ static void divil_lbar_enable(void)
 	for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
 	for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
 		_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
 		_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
 		hi |= 0x01;
 		hi |= 0x01;
-		_wrmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), hi, lo);
+		_wrmsr(DIVIL_MSR_REG(offset), hi, lo);
 	}
 	}
 }
 }
 
 
@@ -76,7 +76,7 @@ static void divil_lbar_disable(void)
 	for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
 	for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
 		_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
 		_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
 		hi &= ~0x01;
 		hi &= ~0x01;
-		_wrmsr(DIVIL_MSR_REG(DIVIL_LBAR_SMB), hi, lo);
+		_wrmsr(DIVIL_MSR_REG(offset), hi, lo);
 	}
 	}
 }
 }
 
 

+ 2 - 0
arch/mips/loongson/common/cs5536/cs5536_ohci.c

@@ -49,6 +49,8 @@ void pci_ohci_write_reg(int reg, u32 value)
 			lo |= SOFT_BAR_OHCI_FLAG;
 			lo |= SOFT_BAR_OHCI_FLAG;
 			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
 			_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
 		} else if ((value & 0x01) == 0x00) {
 		} else if ((value & 0x01) == 0x00) {
+			_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
+			lo = value;
 			_wrmsr(USB_MSR_REG(USB_OHCI), hi, lo);
 			_wrmsr(USB_MSR_REG(USB_OHCI), hi, lo);
 
 
 			value &= 0xfffffff0;
 			value &= 0xfffffff0;

+ 43 - 0
arch/mips/loongson/common/rtc.c

@@ -0,0 +1,43 @@
+/*
+ *  Lemote Fuloong platform support
+ *
+ *  Copyright(c) 2010 Arnaud Patard <apatard@mandriva.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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/mc146818rtc.h>
+
+struct resource loongson_rtc_resources[] = {
+	{
+		.start	= RTC_PORT(0),
+		.end	= RTC_PORT(1),
+		.flags	= IORESOURCE_IO,
+	}, {
+		.start	= RTC_IRQ,
+		.end	= RTC_IRQ,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device loongson_rtc_device = {
+	.name		= "rtc_cmos",
+	.id		= -1,
+	.resource	= loongson_rtc_resources,
+	.num_resources	= ARRAY_SIZE(loongson_rtc_resources),
+};
+
+
+static int __init loongson_rtc_platform_init(void)
+{
+	platform_device_register(&loongson_rtc_device);
+	return 0;
+}
+
+device_initcall(loongson_rtc_platform_init);

+ 1 - 0
arch/mips/math-emu/dp_simple.c

@@ -78,6 +78,7 @@ ieee754dp ieee754dp_abs(ieee754dp x)
 	DPSIGN(x) = 0;
 	DPSIGN(x) = 0;
 
 
 	if (xc == IEEE754_CLASS_SNAN) {
 	if (xc == IEEE754_CLASS_SNAN) {
+		SETCX(IEEE754_INVALID_OPERATION);
 		return ieee754dp_nanxcpt(ieee754dp_indef(), "abs");
 		return ieee754dp_nanxcpt(ieee754dp_indef(), "abs");
 	}
 	}
 
 

+ 1 - 0
arch/mips/math-emu/sp_simple.c

@@ -78,6 +78,7 @@ ieee754sp ieee754sp_abs(ieee754sp x)
 	SPSIGN(x) = 0;
 	SPSIGN(x) = 0;
 
 
 	if (xc == IEEE754_CLASS_SNAN) {
 	if (xc == IEEE754_CLASS_SNAN) {
+		SETCX(IEEE754_INVALID_OPERATION);
 		return ieee754sp_nanxcpt(ieee754sp_indef(), "abs");
 		return ieee754sp_nanxcpt(ieee754sp_indef(), "abs");
 	}
 	}
 
 

+ 7 - 1
arch/mips/oprofile/op_model_loongson2.c

@@ -43,6 +43,12 @@ static struct loongson2_register_config {
 static char *oprofid = "LoongsonPerf";
 static char *oprofid = "LoongsonPerf";
 static irqreturn_t loongson2_perfcount_handler(int irq, void *dev_id);
 static irqreturn_t loongson2_perfcount_handler(int irq, void *dev_id);
 
 
+static void reset_counters(void *arg)
+{
+	write_c0_perfctrl(0);
+	write_c0_perfcnt(0);
+}
+
 static void loongson2_reg_setup(struct op_counter_config *cfg)
 static void loongson2_reg_setup(struct op_counter_config *cfg)
 {
 {
 	unsigned int ctrl = 0;
 	unsigned int ctrl = 0;
@@ -139,7 +145,7 @@ static int __init loongson2_init(void)
 
 
 static void loongson2_exit(void)
 static void loongson2_exit(void)
 {
 {
-	write_c0_perfctrl(0);
+	reset_counters(NULL);
 	free_irq(LOONGSON2_PERFCNT_IRQ, oprofid);
 	free_irq(LOONGSON2_PERFCNT_IRQ, oprofid);
 }
 }