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 ...
This commit is contained in:
commit
7491eb9b5f
|
@ -193,9 +193,15 @@ static void restore_core_regs(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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
|
@ -1,8 +1,8 @@
|
|||
/*
|
||||
* 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);
|
||||
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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,44 +144,48 @@ 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;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DYNAMIC_FTRACE */
|
||||
#endif /* CONFIG_DYNAMIC_FTRACE */
|
||||
|
||||
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
|
||||
|
||||
#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(¤t->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
|
||||
|
@ -272,4 +312,4 @@ out:
|
|||
ftrace_graph_stop();
|
||||
WARN_ON(1);
|
||||
}
|
||||
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
||||
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
|
||||
|
|
|
@ -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 */
|
||||
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 */
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
PTR_L a0, PT_R12(sp)
|
||||
#else
|
||||
PTR_LA a0, PT_R1(sp) /* arg1: &AT -> a0 */
|
||||
move a0, MCOUNT_RA_ADDRESS_REG
|
||||
#endif
|
||||
jal prepare_ftrace_return
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
move a2, fp /* arg3: frame pointer */
|
||||
bnez a0, 1f /* non-leaf func: stored in MCOUNT_RA_ADDRESS_REG */
|
||||
nop
|
||||
#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
|
||||
move a1, ra
|
||||
#endif
|
||||
|
||||
/* arg3: Get frame pointer of current stack */
|
||||
#ifdef CONFIG_FRAME_POINTER
|
||||
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();
|
||||
retval = -EPERM;
|
||||
if (euid != p->cred->euid && euid != p->cred->uid &&
|
||||
!capable(CAP_SYS_NICE)) {
|
||||
read_unlock(&tasklist_lock);
|
||||
goto out_unlock;
|
||||
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 (!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;
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue