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)
void au_sleep(void)
{
int cpuid = alchemy_get_cputype();
if (cpuid != ALCHEMY_CPU_UNKNOWN) {
save_core_regs();
au1xxx_save_and_sleep();
if (cpuid <= ALCHEMY_CPU_AU1500)
alchemy_sleep_au1000();
else if (cpuid <= ALCHEMY_CPU_AU1200)
alchemy_sleep_au1550();
restore_core_regs();
}
}
#endif /* CONFIG_PM */
......@@ -22,10 +22,9 @@
.set noat
.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
sw $1, PT_R1(sp)
sw $2, PT_R2(sp)
......@@ -69,12 +68,32 @@ LEAF(au1xxx_save_and_sleep)
*/
lui t3, 0xb190 /* sys_xxx */
sw sp, 0x0018(t3)
la k0, 3f /* resume path */
la k0, alchemy_sleep_wakeup /* resume path */
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
.set mips3
cache 0x14, 0(t0)
......@@ -84,17 +103,32 @@ LEAF(au1xxx_save_and_sleep)
.set mips0
1: lui a0, 0xb400 /* mem_xxx */
#if defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100) || \
defined(CONFIG_SOC_AU1500)
sw zero, 0x001c(a0) /* Precharge */
sync
sw zero, 0x0020(a0) /* Auto Refresh */
sync
sw zero, 0x0030(a0) /* Sleep */
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 */
sync
sw zero, 0x08d0(a0) /* Self Refresh */
......@@ -114,26 +148,17 @@ LEAF(au1xxx_save_and_sleep)
and t1, t0, t1 /* clear CE[1:0] */
sw t1, 0x0840(a0) /* mem_sdconfiga */
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.
* Reload all of the registers and return.
*/
3: lw k0, 0x20(sp)
LEAF(alchemy_sleep_wakeup)
lw k0, 0x20(sp)
mtc0 k0, CP0_STATUS
lw k0, 0x1c(sp)
mtc0 k0, CP0_CONTEXT
......@@ -169,4 +194,4 @@ LEAF(au1xxx_save_and_sleep)
lw $31, PT_R31(sp)
jr ra
addiu sp, PT_SIZE
END(au1xxx_save_and_sleep)
END(alchemy_sleep_wakeup)
......@@ -542,7 +542,7 @@ static int __init ar7_register_uarts(void)
if (IS_ERR(bus_clk))
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.iotype = UPIO_MEM32;
uart_port.regshift = 2;
......
......@@ -3,4 +3,4 @@
# 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) 2005 Waldemar Brodkorb <wbx@openwrt.org>
* Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
* 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
* under the terms of the GNU General Public License as published by the
......@@ -33,6 +33,7 @@
#include <asm/time.h>
#include <bcm47xx.h>
#include <asm/fw/cfe/cfe_api.h>
#include <asm/mach-bcm47xx/nvram.h>
struct ssb_bus ssb_bcm47xx;
EXPORT_SYMBOL(ssb_bcm47xx);
......@@ -81,28 +82,42 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
/* Fill boardinfo structure */
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);
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);
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);
/* Fill sprom structure */
memset(&(iv->sprom), 0, sizeof(struct ssb_sprom));
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);
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);
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);
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);
return 0;
......
......@@ -50,7 +50,7 @@
#define UR8_REGS_WDT (AR7_REGS_BASE + 0x0b00)
#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_STATUS 0x8
......@@ -128,7 +128,7 @@ static inline int ar7_has_high_cpmac(void)
static inline void ar7_device_enable(u32 bit)
{
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);
msleep(20);
}
......@@ -136,7 +136,7 @@ static inline void ar7_device_enable(u32 bit)
static inline void ar7_device_disable(u32 bit)
{
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);
msleep(20);
}
......
......@@ -24,7 +24,7 @@
#define AR7_GPIO_MAX 32
#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_set_value __gpio_set_value
......
......@@ -188,7 +188,8 @@ extern unsigned long get_au1x00_uart_baud_base(void);
extern unsigned long au1xxx_calc_clock(void);
/* 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);
......
/*
* 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 @@
#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_set_value __gpio_set_value
......
......@@ -2,7 +2,7 @@
* Code for replacing ftrace calls with jumps.
*
* 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>
*
* Thanks goes to Steven Rostedt for writing the original x86 version.
......@@ -12,18 +12,62 @@
#include <linux/init.h>
#include <linux/ftrace.h>
#include <asm/cacheflush.h>
#include <asm/asm.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
#define JAL 0x0c000000 /* jump & link: ip --> ra, jump to target */
#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)
{
......@@ -40,67 +84,56 @@ static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
return 0;
}
static int lui_v1;
static int jal_mcount;
int ftrace_make_nop(struct module *mod,
struct dyn_ftrace *rec, unsigned long addr)
{
unsigned int new;
int faulted;
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
* move at, ra
* 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 {
/* 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);
}
static int modified; /* initialized as 0 by default */
int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
{
unsigned int new;
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 */
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);
}
......@@ -111,13 +144,19 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
{
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);
}
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 */
*(unsigned long *)data = 0;
......@@ -130,25 +169,23 @@ int __init ftrace_dyn_arch_init(void *data)
#ifdef CONFIG_DYNAMIC_FTRACE
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))
int ftrace_enable_ftrace_graph_caller(void)
{
return ftrace_modify_code(FTRACE_GRAPH_CALL_IP,
CALL_FTRACE_GRAPH_CALLER);
insn_j_ftrace_graph_caller);
}
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
#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 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;
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 {
ip -= 4;
......@@ -181,10 +218,11 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr,
if (unlikely(faulted))
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
* store the ra on the stack. */
* store the ra on the stack
*/
if ((code & S_R_SP) != S_R_SP)
return parent_addr;
......@@ -202,7 +240,7 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr,
return 0;
}
#endif
#endif /* !KBUILD_MCOUNT_RA_ADDRESS */
/*
* 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)))
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.
*
* 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;
#ifndef KBUILD_MCOUNT_RA_ADDRESS
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)
goto out;
#endif
......
......@@ -6,6 +6,7 @@
* more details.
*
* Copyright (C) 2009 Lemote Inc. & DSLab, Lanzhou University, China
* Copyright (C) 2010 DSLab, Lanzhou University, China
* Author: Wu Zhangjin <wuzhangjin@gmail.com>
*/
......@@ -45,8 +46,6 @@
PTR_L a5, PT_R9(sp)
PTR_L a6, PT_R10(sp)
PTR_L a7, PT_R11(sp)
#endif
#ifdef CONFIG_64BIT
PTR_ADDIU sp, PT_SIZE
#else
PTR_ADDIU sp, (PT_SIZE + 8)
......@@ -58,6 +57,12 @@
move ra, AT
.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
NESTED(ftrace_caller, PT_SIZE, ra)
......@@ -71,14 +76,14 @@ _mcount:
MCOUNT_SAVE_REGS
#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
move a0, ra /* arg1: next ip, selfaddr */
move a0, ra /* arg1: self return address */
.globl ftrace_call
ftrace_call:
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
.globl ftrace_graph_call
......@@ -119,9 +124,9 @@ NESTED(_mcount, PT_SIZE, ra)
static_trace:
MCOUNT_SAVE_REGS
move a0, ra /* arg1: next ip, selfaddr */
move a0, ra /* arg1: self return address */
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
.globl ftrace_stub
......@@ -134,28 +139,34 @@ ftrace_stub:
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
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
move a1, ra /* arg2: next ip, selfaddr */
#endif
/* arg1: Get the location of the parent's return 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
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
PTR_LA a0, PT_R1(sp) /* arg1: &AT -> a0 */
move a1, ra
#endif
jal prepare_ftrace_return
/* arg3: Get frame pointer of current stack */
#ifdef CONFIG_FRAME_POINTER
move a2, fp /* arg3: frame pointer */
#else
move a2, fp
#else /* ! CONFIG_FRAME_POINTER */
#ifdef CONFIG_64BIT
PTR_LA a2, PT_SIZE(sp)
#else
......@@ -163,6 +174,8 @@ NESTED(ftrace_graph_caller, PT_SIZE, ra)
#endif
#endif
jal prepare_ftrace_return
nop
MCOUNT_RESTORE_REGS
RETURN_BACK
END(ftrace_graph_caller)
......
......@@ -3,6 +3,7 @@
* Copyright (C) 2005 Mips Technologies, Inc
*/
#include <linux/cpu.h>
#include <linux/cpuset.h>
#include <linux/cpumask.h>
#include <linux/delay.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;
}
/*
* 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
......@@ -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,
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;
uid_t euid;
struct task_struct *p;
int retval;
if (len < sizeof(new_mask))
return -EINVAL;
......@@ -60,53 +74,74 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
return -EFAULT;
get_online_cpus();
read_lock(&tasklist_lock);
rcu_read_lock();
p = find_process_by_pid(pid);
if (!p) {
read_unlock(&tasklist_lock);
rcu_read_unlock();
put_online_cpus();
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);
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;
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;
}
retval = security_task_setscheduler(p, 0, NULL);
if (retval)
goto out_unlock;
/* Record new user-specified CPU set for future reference */
p->thread.user_cpus_allowed = new_mask;
/* 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 */
ti = task_thread_info(p);
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 {
cpumask_copy(effective_mask, new_mask);
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:
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_online_cpus();
return retval;
......
......@@ -976,7 +976,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
case 2:
raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs);
break;
return;
case 3:
break;
......
......@@ -23,6 +23,7 @@ config LEMOTE_FULOONG2E
select GENERIC_HARDIRQS_NO__DO_IRQ
select GENERIC_ISA_DMA_SUPPORT_BROKEN
select CPU_HAS_WB
select LOONGSON_MC146818
help
Lemote Fuloong(2e) mini-PC board based on the Chinese Loongson-2E CPU and
an FPGA northbridge
......@@ -51,6 +52,7 @@ config LEMOTE_MACH2F
select SYS_SUPPORTS_64BIT_KERNEL
select SYS_SUPPORTS_HIGHMEM
select SYS_SUPPORTS_LITTLE_ENDIAN
select LOONGSON_MC146818
help
Lemote Loongson 2F family machines utilize the 2F revision of
Loongson processor and the AMD CS5536 south bridge.
......@@ -83,3 +85,7 @@ config LOONGSON_UART_BASE
bool
default y
depends on EARLY_PRINTK || SERIAL_8250
config LOONGSON_MC146818
bool
default n
......@@ -12,6 +12,7 @@ obj-$(CONFIG_GENERIC_GPIO) += gpio.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_SERIAL_8250) += serial.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
......
......@@ -49,6 +49,8 @@ void pci_ehci_write_reg(int reg, u32 value)
lo |= SOFT_BAR_EHCI_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else if ((value & 0x01) == 0x00) {
_rdmsr(USB_MSR_REG(USB_EHCI), &hi, &lo);
lo = value;
_wrmsr(USB_MSR_REG(USB_EHCI), hi, lo);
value &= 0xfffffff0;
......
......@@ -51,6 +51,7 @@ void pci_ide_write_reg(int reg, u32 value)
lo |= SOFT_BAR_IDE_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else if (value & 0x01) {
_rdmsr(IDE_MSR_REG(IDE_IO_BAR), &hi, &lo);
lo = (value & 0xfffffff0) | 0x1;
_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);
lo |= 0x01;
_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);
}
break;
case PCI_IDE_DTC_REG:
_rdmsr(IDE_MSR_REG(IDE_DTC), &hi, &lo);
lo = value;
_wrmsr(IDE_MSR_REG(IDE_DTC), hi, lo);
break;
case PCI_IDE_CAST_REG:
_rdmsr(IDE_MSR_REG(IDE_CAST), &hi, &lo);
lo = value;
_wrmsr(IDE_MSR_REG(IDE_CAST), hi, lo);
break;
case PCI_IDE_ETC_REG:
_rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
lo = value;
_wrmsr(IDE_MSR_REG(IDE_ETC), hi, lo);
break;
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);
break;
default:
......@@ -167,6 +179,7 @@ u32 pci_ide_read_reg(int reg)
case PCI_IDE_ETC_REG:
_rdmsr(IDE_MSR_REG(IDE_ETC), &hi, &lo);
conf_data = lo;
break;
case PCI_IDE_PM_REG:
_rdmsr(IDE_MSR_REG(IDE_INTERNAL_PM), &hi, &lo);
conf_data = lo;
......
......@@ -61,7 +61,7 @@ static void divil_lbar_enable(void)
for (offset = DIVIL_LBAR_SMB; offset <= DIVIL_LBAR_PMS; offset++) {
_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
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++) {
_rdmsr(DIVIL_MSR_REG(offset), &hi, &lo);
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)
lo |= SOFT_BAR_OHCI_FLAG;
_wrmsr(GLCP_MSR_REG(GLCP_SOFT_COM), hi, lo);
} else if ((value & 0x01) == 0x00) {
_rdmsr(USB_MSR_REG(USB_OHCI), &hi, &lo);
lo = value;
_wrmsr(USB_MSR_REG(USB_OHCI), hi, lo);
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)
DPSIGN(x) = 0;
if (xc == IEEE754_CLASS_SNAN) {
SETCX(IEEE754_INVALID_OPERATION);
return ieee754dp_nanxcpt(ieee754dp_indef(), "abs");
}
......
......@@ -78,6 +78,7 @@ ieee754sp ieee754sp_abs(ieee754sp x)
SPSIGN(x) = 0;
if (xc == IEEE754_CLASS_SNAN) {
SETCX(IEEE754_INVALID_OPERATION);
return ieee754sp_nanxcpt(ieee754sp_indef(), "abs");
}
......
......@@ -43,6 +43,12 @@ static struct loongson2_register_config {
static char *oprofid = "LoongsonPerf";
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)
{
unsigned int ctrl = 0;
......@@ -139,7 +145,7 @@ static int __init loongson2_init(void)
static void loongson2_exit(void)
{
write_c0_perfctrl(0);
reset_counters(NULL);
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