Commit 7491eb9b authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 7263e715 55dc9d51
...@@ -193,9 +193,15 @@ static void restore_core_regs(void) ...@@ -193,9 +193,15 @@ static void restore_core_regs(void)
void au_sleep(void) void au_sleep(void)
{ {
save_core_regs(); int cpuid = alchemy_get_cputype();
au1xxx_save_and_sleep(); if (cpuid != ALCHEMY_CPU_UNKNOWN) {
restore_core_regs(); 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 */
...@@ -22,10 +22,9 @@ ...@@ -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. /* preparatory stuff */
*/ .macro SETUP_SLEEP
LEAF(au1xxx_save_and_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) ...@@ -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, .macro DO_SLEEP
* issue a precharge, auto/self refresh, then sleep commands to it. /* 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) ...@@ -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) ...@@ -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 */ DO_SLEEP
sw zero, 0x0078(t3) /* sys_slppwr */
sync END(alchemy_sleep_au1550)
sw zero, 0x007c(t3) /* sys_sleep */
sync
nop
nop
nop
nop
nop
nop
nop
nop
/* 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) ...@@ -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)
...@@ -542,7 +542,7 @@ static int __init ar7_register_uarts(void) ...@@ -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;
......
...@@ -3,4 +3,4 @@ ...@@ -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
/*
* 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);
/* /*
* 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 @@ ...@@ -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, ...@@ -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("et0phyaddr", buf, sizeof(buf)) >= 0 ||
if (cfe_getenv("et1phyaddr", buf, sizeof(buf)) >= 0) nvram_getenv("et0phyaddr", buf, sizeof(buf)) >= 0)
iv->sprom.et1phyaddr = simple_strtoul(buf, NULL, 10); iv->sprom.et0phyaddr = simple_strtoul(buf, NULL, 0);
if (cfe_getenv("et0mdcport", buf, sizeof(buf)) >= 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;
......
...@@ -50,7 +50,7 @@ ...@@ -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) ...@@ -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) ...@@ -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);
} }
......
...@@ -24,7 +24,7 @@ ...@@ -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
......
...@@ -188,7 +188,8 @@ extern unsigned long get_au1x00_uart_baud_base(void); ...@@ -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);
......
/*
* 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
...@@ -3,7 +3,7 @@ ...@@ -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
......
...@@ -2,7 +2,7 @@ ...@@ -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 @@ ...@@ -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) ...@@ -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. */ * We have compiled module with -mlong-calls, but compiled the kernel
if (ip & 0x40000000) { * without it, we need to cope with them respectively.
/* record it for ftrace_make_call */ */
if (lui_v1 == 0) { if (in_module(ip)) {
/* lui_v1 = *(unsigned int *)ip; */ #if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT)
safe_load_code(lui_v1, ip, faulted); /*
* lui v1, hi_16bit_of_mcount --> b 1f (0x10000005)
if (unlikely(faulted)) * addiu v1, v1, low_16bit_of_mcount
return -EFAULT; * move at, ra
} * move $12, ra_address
* jalr v1
/* lui v1, hi_16bit_of_mcount --> b 1f (0x10000004) * 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 * nop | move $12, ra_address | sub sp, sp, 8
* 1f: (ip + 12) * 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) { * move at, ra
/* We can record it directly like this: * jal _mcount --> nop
* 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
*/ */
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) ...@@ -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, ...@@ -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) { * For module, move the ip from calling site of mcount to the
/* module: move to the instruction "lui v1, HI_16BIT_OF_MCOUNT" */ * instruction "lui v1, hi_16bit_of_mcount"(offset is 20), but for
ip = self_addr - 20; * kernel, move to the instruction "move ra, at"(offset is 12)
} else { */
/* kernel: move to the instruction "move ra, at" */ ip = self_addr - (in_module(self_addr) ? 20 : 12);
ip = self_addr - 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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, (unsigned long)parent, fp);
fp); /*
/* If fails when getting the stack address of the non-leaf function's * If fails when getting the stack address of the non-leaf function's
* ra, stop function graph tracer and return */ * ra, stop function graph tracer and return
*/
if (parent == 0) if (parent == 0)
goto out; goto out;
#endif #endif
...@@ -272,4 +312,4 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, ...@@ -272,4 +312,4 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
ftrace_graph_stop(); ftrace_graph_stop();
WARN_ON(1); WARN_ON(1);
} }
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ #endif /* CONFIG_FUNCTION_GRAPH_TRACER */
...@@ -6,6 +6,7 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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: ...@@ -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) ...@@ -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: ...@@ -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 #ifndef 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
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 */ #endif
1: move a0, t0 /* arg1: the location of the return address */ 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 */ move a2, fp
#else #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) ...@@ -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)
......
...@@ -3,6 +3,7 @@ ...@@ -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) ...@@ -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) ...@@ -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_var_t cpus_allowed, new_mask, effective_mask;
cpumask_t effective_mask;
int retval;
struct task_struct *p;
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, ...@@ -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;
} }
/* /* Prevent p going away */
* 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.
*/
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 && if (!check_same_owner(p) && !capable(CAP_SYS_NICE))
!capable(CAP_SYS_NICE)) {
read_unlock(&tasklist_lock);
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; cpumask_copy(&p->thread.user_cpus_allowed, new_mask);
/* Unlock the task list */
read_unlock(&tasklist_lock);
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_intersects(*new_mask, mt_fpu_cpumask)) {
cpus_and(effective_mask, new_mask, mt_fpu_cpumask); cpus_and(*effective_mask, *new_mask, mt_fpu_cpumask);
retval = set_cpus_allowed_ptr(p, &effective_mask); 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;
......
...@@ -976,7 +976,7 @@ asmlinkage void do_cpu(struct pt_regs *regs) ...@@ -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;
......
...@@ -23,6 +23,7 @@ config LEMOTE_FULOONG2E ...@@ -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 ...@@ -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 ...@@ -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
...@@ -12,6 +12,7 @@ obj-$(CONFIG_GENERIC_GPIO) += gpio.o ...@@ -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
......
...@@ -49,6 +49,8 @@ void pci_ehci_write_reg(int reg, u32 value) ...@@ -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;
......
...@@ -51,6 +51,7 @@ void pci_ide_write_reg(int reg, u32 value) ...@@ -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) ...@@ -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) ...@@ -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;
......
...@@ -61,7 +61,7 @@ static void divil_lbar_enable(void) ...@@ -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) ...@@ -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);
} }
} }
......
...@@ -49,6 +49,8 @@ void pci_ohci_write_reg(int reg, u32 value) ...@@ -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;
......
/*
* 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);
...@@ -78,6 +78,7 @@ ieee754dp ieee754dp_abs(ieee754dp x) ...@@ -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");
} }
......
...@@ -78,6 +78,7 @@ ieee754sp ieee754sp_abs(ieee754sp x) ...@@ -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");
} }
......
...@@ -43,6 +43,12 @@ static struct loongson2_register_config { ...@@ -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) ...@@ -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);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment