forked from rubenslte/android_kernel_samsung_msm8226
Merge remote-tracking branch 'common/android-3.0' into msm-3.0
* common/android-3.0: (570 commits) misc: remove kernel debugger core ARM: common: fiq_debugger: dump sysrq directly to console if enabled ARM: common: fiq_debugger: add irq context debug functions net: wireless: bcmdhd: Call init_ioctl() only if was started properly for WEXT net: wireless: bcmdhd: Call init_ioctl() only if was started properly net: wireless: bcmdhd: Fix possible memory leak in escan/iscan cpufreq: interactive governor: default 20ms timer cpufreq: interactive governor: go to intermediate hi speed before max cpufreq: interactive governor: scale to max only if at min speed cpufreq: interactive governor: apply intermediate load on current speed ARM: idle: update idle ticks before call idle end notifier input: gpio_input: don't print debounce message unless flag is set net: wireless: bcm4329: Skip dhd_bus_stop() if bus is already down net: wireless: bcmdhd: Skip dhd_bus_stop() if bus is already down net: wireless: bcmdhd: Improve suspend/resume processing net: wireless: bcmdhd: Check if FW is Ok for internal FW call tcp: Don't nuke connections for the wrong protocol ARM: common: fiq_debugger: make uart irq be no_suspend net: wireless: Skip connect warning for CONFIG_CFG80211_ALLOW_RECONNECT mm: avoid livelock on !__GFP_FS allocations ... Conflicts: arch/arm/mm/cache-l2x0.c arch/arm/vfp/vfpmodule.c drivers/mmc/core/host.c kernel/power/wakelock.c net/bluetooth/hci_event.c Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
This commit is contained in:
@@ -469,6 +469,7 @@ pm_runtime_autosuspend()
|
||||
pm_runtime_resume()
|
||||
pm_runtime_get_sync()
|
||||
pm_runtime_put_sync_suspend()
|
||||
pm_runtime_put_sync_autosuspend()
|
||||
|
||||
5. Run-time PM Initialization, Device Probing and Removal
|
||||
|
||||
|
||||
@@ -2008,6 +2008,9 @@ int main(int argc, char *argv[])
|
||||
/* We use a simple helper to copy the arguments separated by spaces. */
|
||||
concat((char *)(boot + 1), argv+optind+2);
|
||||
|
||||
/* Set kernel alignment to 16M (CONFIG_PHYSICAL_ALIGN) */
|
||||
boot->hdr.kernel_alignment = 0x1000000;
|
||||
|
||||
/* Boot protocol version: 2.07 supports the fields for lguest. */
|
||||
boot->hdr.version = 0x207;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
VERSION = 3
|
||||
PATCHLEVEL = 0
|
||||
SUBLEVEL = 1
|
||||
SUBLEVEL = 8
|
||||
EXTRAVERSION =
|
||||
NAME = Sneaky Weasel
|
||||
|
||||
|
||||
@@ -1344,6 +1344,20 @@ source "drivers/pci/Kconfig"
|
||||
|
||||
source "drivers/pcmcia/Kconfig"
|
||||
|
||||
config ARM_ERRATA_764369
|
||||
bool "ARM errata: Data cache line maintenance operation by MVA may not succeed"
|
||||
depends on CPU_V7 && SMP
|
||||
help
|
||||
This option enables the workaround for erratum 764369
|
||||
affecting Cortex-A9 MPCore with two or more processors (all
|
||||
current revisions). Under certain timing circumstances, a data
|
||||
cache line maintenance operation by MVA targeting an Inner
|
||||
Shareable memory region may fail to proceed up to either the
|
||||
Point of Coherency or to the Point of Unification of the
|
||||
system. This workaround adds a DSB instruction before the
|
||||
relevant cache maintenance functions and sets a specific bit
|
||||
in the diagnostic control register of the SCU.
|
||||
|
||||
endmenu
|
||||
|
||||
menu "Kernel Features"
|
||||
|
||||
@@ -49,12 +49,11 @@ config FIQ_DEBUGGER
|
||||
bool "FIQ Mode Serial Debugger"
|
||||
select FIQ
|
||||
select FIQ_GLUE
|
||||
select KERNEL_DEBUGGER_CORE
|
||||
default n
|
||||
help
|
||||
The FIQ serial debugger can accept commands even when the
|
||||
kernel is unresponsive due to being stuck with interrupts
|
||||
disabled. Depends on the kernel debugger core in drivers/misc.
|
||||
disabled.
|
||||
|
||||
|
||||
config FIQ_DEBUGGER_NO_SLEEP
|
||||
|
||||
+332
-78
@@ -22,12 +22,12 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/kernel_debugger.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_flip.h>
|
||||
@@ -53,6 +53,7 @@ struct fiq_debugger_state {
|
||||
struct fiq_glue_handler handler;
|
||||
|
||||
int fiq;
|
||||
int uart_irq;
|
||||
int signal_irq;
|
||||
int wakeup_irq;
|
||||
bool wakeup_irq_no_set_wake;
|
||||
@@ -71,7 +72,8 @@ struct fiq_debugger_state {
|
||||
bool debug_enable;
|
||||
bool ignore_next_wakeup_irq;
|
||||
struct timer_list sleep_timer;
|
||||
bool uart_clk_enabled;
|
||||
spinlock_t sleep_timer_lock;
|
||||
bool uart_enabled;
|
||||
struct wake_lock debugger_wake_lock;
|
||||
bool console_enable;
|
||||
int current_cpu;
|
||||
@@ -84,6 +86,7 @@ struct fiq_debugger_state {
|
||||
struct tty_struct *tty;
|
||||
int tty_open_count;
|
||||
struct fiq_debugger_ringbuf *tty_rbuf;
|
||||
bool syslog_dumping;
|
||||
#endif
|
||||
|
||||
unsigned int last_irqs[NR_IRQS];
|
||||
@@ -130,18 +133,42 @@ static inline void disable_wakeup_irq(struct fiq_debugger_state *state)
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool inline debug_have_fiq(struct fiq_debugger_state *state)
|
||||
{
|
||||
return (state->fiq >= 0);
|
||||
}
|
||||
|
||||
static void debug_force_irq(struct fiq_debugger_state *state)
|
||||
{
|
||||
unsigned int irq = state->signal_irq;
|
||||
if (state->pdata->force_irq)
|
||||
|
||||
if (WARN_ON(!debug_have_fiq(state)))
|
||||
return;
|
||||
if (state->pdata->force_irq) {
|
||||
state->pdata->force_irq(state->pdev, irq);
|
||||
else {
|
||||
} else {
|
||||
struct irq_chip *chip = irq_get_chip(irq);
|
||||
if (chip && chip->irq_retrigger)
|
||||
chip->irq_retrigger(irq_get_irq_data(irq));
|
||||
}
|
||||
}
|
||||
|
||||
static void debug_uart_enable(struct fiq_debugger_state *state)
|
||||
{
|
||||
if (state->clk)
|
||||
clk_enable(state->clk);
|
||||
if (state->pdata->uart_enable)
|
||||
state->pdata->uart_enable(state->pdev);
|
||||
}
|
||||
|
||||
static void debug_uart_disable(struct fiq_debugger_state *state)
|
||||
{
|
||||
if (state->pdata->uart_disable)
|
||||
state->pdata->uart_disable(state->pdev);
|
||||
if (state->clk)
|
||||
clk_disable(state->clk);
|
||||
}
|
||||
|
||||
static void debug_uart_flush(struct fiq_debugger_state *state)
|
||||
{
|
||||
if (state->pdata->uart_flush)
|
||||
@@ -447,6 +474,81 @@ void dump_stacktrace(struct fiq_debugger_state *state,
|
||||
tail = user_backtrace(state, tail);
|
||||
}
|
||||
|
||||
static void do_ps(struct fiq_debugger_state *state)
|
||||
{
|
||||
struct task_struct *g;
|
||||
struct task_struct *p;
|
||||
unsigned task_state;
|
||||
static const char stat_nam[] = "RSDTtZX";
|
||||
|
||||
debug_printf(state, "pid ppid prio task pc\n");
|
||||
read_lock(&tasklist_lock);
|
||||
do_each_thread(g, p) {
|
||||
task_state = p->state ? __ffs(p->state) + 1 : 0;
|
||||
debug_printf(state,
|
||||
"%5d %5d %4d ", p->pid, p->parent->pid, p->prio);
|
||||
debug_printf(state, "%-13.13s %c", p->comm,
|
||||
task_state >= sizeof(stat_nam) ? '?' : stat_nam[task_state]);
|
||||
if (task_state == TASK_RUNNING)
|
||||
debug_printf(state, " running\n");
|
||||
else
|
||||
debug_printf(state, " %08lx\n", thread_saved_pc(p));
|
||||
} while_each_thread(g, p);
|
||||
read_unlock(&tasklist_lock);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
|
||||
static void begin_syslog_dump(struct fiq_debugger_state *state)
|
||||
{
|
||||
state->syslog_dumping = true;
|
||||
}
|
||||
|
||||
static void end_syslog_dump(struct fiq_debugger_state *state)
|
||||
{
|
||||
state->syslog_dumping = false;
|
||||
}
|
||||
#else
|
||||
extern int do_syslog(int type, char __user *bug, int count);
|
||||
static void begin_syslog_dump(struct fiq_debugger_state *state)
|
||||
{
|
||||
do_syslog(5 /* clear */, NULL, 0);
|
||||
}
|
||||
|
||||
static void end_syslog_dump(struct fiq_debugger_state *state)
|
||||
{
|
||||
char buf[128];
|
||||
int ret;
|
||||
int idx = 0;
|
||||
|
||||
while (1) {
|
||||
ret = log_buf_copy(buf, idx, sizeof(buf) - 1);
|
||||
if (ret <= 0)
|
||||
break;
|
||||
buf[ret] = 0;
|
||||
debug_printf(state, "%s", buf);
|
||||
idx += ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void do_sysrq(struct fiq_debugger_state *state, char rq)
|
||||
{
|
||||
begin_syslog_dump(state);
|
||||
handle_sysrq(rq);
|
||||
end_syslog_dump(state);
|
||||
}
|
||||
|
||||
/* This function CANNOT be called in FIQ context */
|
||||
static void debug_irq_exec(struct fiq_debugger_state *state, char *cmd)
|
||||
{
|
||||
if (!strcmp(cmd, "ps"))
|
||||
do_ps(state);
|
||||
if (!strcmp(cmd, "sysrq"))
|
||||
do_sysrq(state, 'h');
|
||||
if (!strncmp(cmd, "sysrq ", 6))
|
||||
do_sysrq(state, cmd[6]);
|
||||
}
|
||||
|
||||
static void debug_help(struct fiq_debugger_state *state)
|
||||
{
|
||||
debug_printf(state, "FIQ Debugger commands:\n"
|
||||
@@ -463,16 +565,34 @@ static void debug_help(struct fiq_debugger_state *state)
|
||||
" console Switch terminal to console\n"
|
||||
" cpu Current CPU\n"
|
||||
" cpu <number> Switch to CPU<number>\n");
|
||||
if (!state->debug_busy) {
|
||||
strcpy(state->debug_cmd, "help");
|
||||
state->debug_busy = 1;
|
||||
debug_force_irq(state);
|
||||
}
|
||||
debug_printf(state, " ps Process list\n"
|
||||
" sysrq sysrq options\n"
|
||||
" sysrq <param> Execute sysrq with <param>\n");
|
||||
}
|
||||
|
||||
static void debug_exec(struct fiq_debugger_state *state,
|
||||
static void take_affinity(void *info)
|
||||
{
|
||||
struct fiq_debugger_state *state = info;
|
||||
struct cpumask cpumask;
|
||||
|
||||
cpumask_clear(&cpumask);
|
||||
cpumask_set_cpu(get_cpu(), &cpumask);
|
||||
|
||||
irq_set_affinity(state->uart_irq, &cpumask);
|
||||
}
|
||||
|
||||
static void switch_cpu(struct fiq_debugger_state *state, int cpu)
|
||||
{
|
||||
if (!debug_have_fiq(state))
|
||||
smp_call_function_single(cpu, take_affinity, state, false);
|
||||
state->current_cpu = cpu;
|
||||
}
|
||||
|
||||
static bool debug_fiq_exec(struct fiq_debugger_state *state,
|
||||
const char *cmd, unsigned *regs, void *svc_sp)
|
||||
{
|
||||
bool signal_helper = false;
|
||||
|
||||
if (!strcmp(cmd, "help") || !strcmp(cmd, "?")) {
|
||||
debug_help(state);
|
||||
} else if (!strcmp(cmd, "pc")) {
|
||||
@@ -494,8 +614,10 @@ static void debug_exec(struct fiq_debugger_state *state,
|
||||
debug_printf(state, "%s\n", linux_banner);
|
||||
} else if (!strcmp(cmd, "sleep")) {
|
||||
state->no_sleep = false;
|
||||
debug_printf(state, "enabling sleep\n");
|
||||
} else if (!strcmp(cmd, "nosleep")) {
|
||||
state->no_sleep = true;
|
||||
debug_printf(state, "disabling sleep\n");
|
||||
} else if (!strcmp(cmd, "console")) {
|
||||
state->console_enable = true;
|
||||
debug_printf(state, "console mode\n");
|
||||
@@ -504,7 +626,7 @@ static void debug_exec(struct fiq_debugger_state *state,
|
||||
} else if (!strncmp(cmd, "cpu ", 4)) {
|
||||
unsigned long cpu = 0;
|
||||
if (strict_strtoul(cmd + 4, 10, &cpu) == 0)
|
||||
state->current_cpu = cpu;
|
||||
switch_cpu(state, cpu);
|
||||
else
|
||||
debug_printf(state, "invalid cpu\n");
|
||||
debug_printf(state, "cpu %d\n", state->current_cpu);
|
||||
@@ -518,30 +640,49 @@ static void debug_exec(struct fiq_debugger_state *state,
|
||||
state->debug_busy = 1;
|
||||
}
|
||||
|
||||
debug_force_irq(state);
|
||||
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
if (!state->console_enable)
|
||||
debug_prompt(state);
|
||||
|
||||
return signal_helper;
|
||||
}
|
||||
|
||||
static void sleep_timer_expired(unsigned long data)
|
||||
{
|
||||
struct fiq_debugger_state *state = (struct fiq_debugger_state *)data;
|
||||
unsigned long flags;
|
||||
|
||||
if (state->uart_clk_enabled && !state->no_sleep) {
|
||||
if (state->debug_enable) {
|
||||
spin_lock_irqsave(&state->sleep_timer_lock, flags);
|
||||
if (state->uart_enabled && !state->no_sleep) {
|
||||
if (state->debug_enable && !state->console_enable) {
|
||||
state->debug_enable = false;
|
||||
debug_printf_nfiq(state, "suspending fiq debugger\n");
|
||||
}
|
||||
state->ignore_next_wakeup_irq = true;
|
||||
if (state->clk)
|
||||
clk_disable(state->clk);
|
||||
state->uart_clk_enabled = false;
|
||||
debug_uart_disable(state);
|
||||
state->uart_enabled = false;
|
||||
enable_wakeup_irq(state);
|
||||
}
|
||||
wake_unlock(&state->debugger_wake_lock);
|
||||
spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
|
||||
}
|
||||
|
||||
static void handle_wakeup(struct fiq_debugger_state *state)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&state->sleep_timer_lock, flags);
|
||||
if (state->wakeup_irq >= 0 && state->ignore_next_wakeup_irq) {
|
||||
state->ignore_next_wakeup_irq = false;
|
||||
} else if (!state->uart_enabled) {
|
||||
wake_lock(&state->debugger_wake_lock);
|
||||
debug_uart_enable(state);
|
||||
state->uart_enabled = true;
|
||||
disable_wakeup_irq(state);
|
||||
mod_timer(&state->sleep_timer, jiffies + HZ / 2);
|
||||
}
|
||||
spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
|
||||
}
|
||||
|
||||
static irqreturn_t wakeup_irq_handler(int irq, void *dev)
|
||||
@@ -550,35 +691,28 @@ static irqreturn_t wakeup_irq_handler(int irq, void *dev)
|
||||
|
||||
if (!state->no_sleep)
|
||||
debug_puts(state, "WAKEUP\n");
|
||||
if (state->ignore_next_wakeup_irq)
|
||||
state->ignore_next_wakeup_irq = false;
|
||||
else if (!state->uart_clk_enabled) {
|
||||
wake_lock(&state->debugger_wake_lock);
|
||||
if (state->clk)
|
||||
clk_enable(state->clk);
|
||||
state->uart_clk_enabled = true;
|
||||
disable_wakeup_irq(state);
|
||||
mod_timer(&state->sleep_timer, jiffies + HZ / 2);
|
||||
}
|
||||
handle_wakeup(state);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t debug_irq(int irq, void *dev)
|
||||
{
|
||||
struct fiq_debugger_state *state = dev;
|
||||
if (state->pdata->force_irq_ack)
|
||||
state->pdata->force_irq_ack(state->pdev, state->signal_irq);
|
||||
|
||||
static void debug_handle_irq_context(struct fiq_debugger_state *state)
|
||||
{
|
||||
if (!state->no_sleep) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&state->sleep_timer_lock, flags);
|
||||
wake_lock(&state->debugger_wake_lock);
|
||||
mod_timer(&state->sleep_timer, jiffies + HZ * 5);
|
||||
spin_unlock_irqrestore(&state->sleep_timer_lock, flags);
|
||||
}
|
||||
#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
|
||||
if (state->tty) {
|
||||
int i;
|
||||
int count = fiq_debugger_ringbuf_level(state->tty_rbuf);
|
||||
for (i = 0; i < count; i++) {
|
||||
int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, i);
|
||||
int c = fiq_debugger_ringbuf_peek(state->tty_rbuf, 0);
|
||||
tty_insert_flip_char(state->tty, c, TTY_NORMAL);
|
||||
if (!fiq_debugger_ringbuf_consume(state->tty_rbuf, 1))
|
||||
pr_warn("fiq tty failed to consume byte\n");
|
||||
@@ -587,16 +721,10 @@ static irqreturn_t debug_irq(int irq, void *dev)
|
||||
}
|
||||
#endif
|
||||
if (state->debug_busy) {
|
||||
struct kdbg_ctxt ctxt;
|
||||
|
||||
ctxt.printf = debug_printf_nfiq;
|
||||
ctxt.cookie = state;
|
||||
kernel_debugger(&ctxt, state->debug_cmd);
|
||||
debug_irq_exec(state, state->debug_cmd);
|
||||
debug_prompt(state);
|
||||
|
||||
state->debug_busy = 0;
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int debug_getc(struct fiq_debugger_state *state)
|
||||
@@ -604,30 +732,29 @@ static int debug_getc(struct fiq_debugger_state *state)
|
||||
return state->pdata->uart_getc(state->pdev);
|
||||
}
|
||||
|
||||
static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
|
||||
static bool debug_handle_uart_interrupt(struct fiq_debugger_state *state,
|
||||
int this_cpu, void *regs, void *svc_sp)
|
||||
{
|
||||
struct fiq_debugger_state *state =
|
||||
container_of(h, struct fiq_debugger_state, handler);
|
||||
int c;
|
||||
static int last_c;
|
||||
int count = 0;
|
||||
unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu;
|
||||
bool signal_helper = false;
|
||||
|
||||
if (this_cpu != state->current_cpu) {
|
||||
if (state->in_fiq)
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (atomic_inc_return(&state->unhandled_fiq_count) !=
|
||||
MAX_UNHANDLED_FIQ_COUNT)
|
||||
return;
|
||||
return false;
|
||||
|
||||
debug_printf(state, "fiq_debugger: cpu %d not responding, "
|
||||
"reverting to cpu %d\n", state->current_cpu,
|
||||
this_cpu);
|
||||
|
||||
atomic_set(&state->unhandled_fiq_count, 0);
|
||||
state->current_cpu = this_cpu;
|
||||
return;
|
||||
switch_cpu(state, this_cpu);
|
||||
return false;
|
||||
}
|
||||
|
||||
state->in_fiq = true;
|
||||
@@ -648,7 +775,7 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
|
||||
#ifdef CONFIG_FIQ_DEBUGGER_CONSOLE
|
||||
} else if (state->console_enable && state->tty_rbuf) {
|
||||
fiq_debugger_ringbuf_push(state->tty_rbuf, c);
|
||||
debug_force_irq(state);
|
||||
signal_helper = true;
|
||||
#endif
|
||||
} else if ((c >= ' ') && (c < 127)) {
|
||||
if (state->debug_count < (DEBUG_MAX - 1)) {
|
||||
@@ -670,8 +797,9 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
|
||||
if (state->debug_count) {
|
||||
state->debug_buf[state->debug_count] = 0;
|
||||
state->debug_count = 0;
|
||||
debug_exec(state, state->debug_buf,
|
||||
regs, svc_sp);
|
||||
signal_helper |=
|
||||
debug_fiq_exec(state, state->debug_buf,
|
||||
regs, svc_sp);
|
||||
} else {
|
||||
debug_prompt(state);
|
||||
}
|
||||
@@ -684,10 +812,63 @@ static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
|
||||
|
||||
/* poke sleep timer if necessary */
|
||||
if (state->debug_enable && !state->no_sleep)
|
||||
debug_force_irq(state);
|
||||
signal_helper = true;
|
||||
|
||||
atomic_set(&state->unhandled_fiq_count, 0);
|
||||
state->in_fiq = false;
|
||||
|
||||
return signal_helper;
|
||||
}
|
||||
|
||||
static void debug_fiq(struct fiq_glue_handler *h, void *regs, void *svc_sp)
|
||||
{
|
||||
struct fiq_debugger_state *state =
|
||||
container_of(h, struct fiq_debugger_state, handler);
|
||||
unsigned int this_cpu = THREAD_INFO(svc_sp)->cpu;
|
||||
bool need_irq;
|
||||
|
||||
need_irq = debug_handle_uart_interrupt(state, this_cpu, regs, svc_sp);
|
||||
if (need_irq)
|
||||
debug_force_irq(state);
|
||||
}
|
||||
|
||||
/*
|
||||
* When not using FIQs, we only use this single interrupt as an entry point.
|
||||
* This just effectively takes over the UART interrupt and does all the work
|
||||
* in this context.
|
||||
*/
|
||||
static irqreturn_t debug_uart_irq(int irq, void *dev)
|
||||
{
|
||||
struct fiq_debugger_state *state = dev;
|
||||
bool not_done;
|
||||
|
||||
handle_wakeup(state);
|
||||
|
||||
/* handle the debugger irq in regular context */
|
||||
not_done = debug_handle_uart_interrupt(state, smp_processor_id(),
|
||||
get_irq_regs(),
|
||||
current_thread_info());
|
||||
if (not_done)
|
||||
debug_handle_irq_context(state);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*
|
||||
* If FIQs are used, not everything can happen in fiq context.
|
||||
* FIQ handler does what it can and then signals this interrupt to finish the
|
||||
* job in irq context.
|
||||
*/
|
||||
static irqreturn_t debug_signal_irq(int irq, void *dev)
|
||||
{
|
||||
struct fiq_debugger_state *state = dev;
|
||||
|
||||
if (state->pdata->force_irq_ack)
|
||||
state->pdata->force_irq_ack(state->pdev, state->signal_irq);
|
||||
|
||||
debug_handle_irq_context(state);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void debug_resume(struct fiq_glue_handler *h)
|
||||
@@ -714,15 +895,17 @@ static void debug_console_write(struct console *co,
|
||||
|
||||
state = container_of(co, struct fiq_debugger_state, console);
|
||||
|
||||
if (!state->console_enable)
|
||||
if (!state->console_enable && !state->syslog_dumping)
|
||||
return;
|
||||
|
||||
debug_uart_enable(state);
|
||||
while (count--) {
|
||||
if (*s == '\n')
|
||||
state->pdata->uart_putc(state->pdev, '\r');
|
||||
state->pdata->uart_putc(state->pdev, *s++);
|
||||
}
|
||||
debug_uart_flush(state);
|
||||
debug_uart_disable(state);
|
||||
}
|
||||
|
||||
static struct console fiq_debugger_console = {
|
||||
@@ -759,12 +942,10 @@ int fiq_tty_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
if (!state->console_enable)
|
||||
return count;
|
||||
|
||||
if (state->clk)
|
||||
clk_enable(state->clk);
|
||||
debug_uart_enable(state);
|
||||
for (i = 0; i < count; i++)
|
||||
state->pdata->uart_putc(state->pdev, *buf++);
|
||||
if (state->clk)
|
||||
clk_disable(state->clk);
|
||||
debug_uart_disable(state);
|
||||
|
||||
return count;
|
||||
}
|
||||
@@ -829,18 +1010,51 @@ err:
|
||||
}
|
||||
#endif
|
||||
|
||||
static int fiq_debugger_dev_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct fiq_debugger_state *state = platform_get_drvdata(pdev);
|
||||
|
||||
if (state->pdata->uart_dev_suspend)
|
||||
return state->pdata->uart_dev_suspend(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiq_debugger_dev_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct fiq_debugger_state *state = platform_get_drvdata(pdev);
|
||||
|
||||
if (state->pdata->uart_dev_resume)
|
||||
return state->pdata->uart_dev_resume(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fiq_debugger_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct fiq_debugger_pdata *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct fiq_debugger_state *state;
|
||||
int fiq;
|
||||
int uart_irq;
|
||||
|
||||
if (!pdata->uart_getc || !pdata->uart_putc || !pdata->fiq_enable)
|
||||
if (!pdata->uart_getc || !pdata->uart_putc)
|
||||
return -EINVAL;
|
||||
if ((pdata->uart_enable && !pdata->uart_disable) ||
|
||||
(!pdata->uart_enable && pdata->uart_disable))
|
||||
return -EINVAL;
|
||||
|
||||
fiq = platform_get_irq_byname(pdev, "fiq");
|
||||
uart_irq = platform_get_irq_byname(pdev, "uart_irq");
|
||||
|
||||
/* uart_irq mode and fiq mode are mutually exclusive, but one of them
|
||||
* is required */
|
||||
if ((uart_irq < 0 && fiq < 0) || (uart_irq >= 0 && fiq >= 0))
|
||||
return -EINVAL;
|
||||
if (fiq >= 0 && !pdata->fiq_enable)
|
||||
return -EINVAL;
|
||||
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
state->handler.fiq = debug_fiq;
|
||||
state->handler.resume = debug_resume;
|
||||
setup_timer(&state->sleep_timer, sleep_timer_expired,
|
||||
(unsigned long)state);
|
||||
state->pdata = pdata;
|
||||
@@ -849,11 +1063,16 @@ static int fiq_debugger_probe(struct platform_device *pdev)
|
||||
state->debug_enable = initial_debug_enable;
|
||||
state->console_enable = initial_console_enable;
|
||||
|
||||
state->fiq = platform_get_irq_byname(pdev, "fiq");
|
||||
state->fiq = fiq;
|
||||
state->uart_irq = uart_irq;
|
||||
state->signal_irq = platform_get_irq_byname(pdev, "signal");
|
||||
state->wakeup_irq = platform_get_irq_byname(pdev, "wakeup");
|
||||
|
||||
if (state->wakeup_irq < 0)
|
||||
platform_set_drvdata(pdev, state);
|
||||
|
||||
spin_lock_init(&state->sleep_timer_lock);
|
||||
|
||||
if (state->wakeup_irq < 0 && debug_have_fiq(state))
|
||||
state->no_sleep = true;
|
||||
state->ignore_next_wakeup_irq = !state->no_sleep;
|
||||
|
||||
@@ -864,6 +1083,10 @@ static int fiq_debugger_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(state->clk))
|
||||
state->clk = NULL;
|
||||
|
||||
/* do not call pdata->uart_enable here since uart_init may still
|
||||
* need to do some initialization before uart_enable can work.
|
||||
* So, only try to manage the clock during init.
|
||||
*/
|
||||
if (state->clk)
|
||||
clk_enable(state->clk);
|
||||
|
||||
@@ -876,21 +1099,39 @@ static int fiq_debugger_probe(struct platform_device *pdev)
|
||||
debug_printf_nfiq(state, "<hit enter %sto activate fiq debugger>\n",
|
||||
state->no_sleep ? "" : "twice ");
|
||||
|
||||
ret = fiq_glue_register_handler(&state->handler);
|
||||
if (ret) {
|
||||
pr_err("serial_debugger: could not install fiq handler\n");
|
||||
goto err_register_fiq;
|
||||
}
|
||||
if (debug_have_fiq(state)) {
|
||||
state->handler.fiq = debug_fiq;
|
||||
state->handler.resume = debug_resume;
|
||||
ret = fiq_glue_register_handler(&state->handler);
|
||||
if (ret) {
|
||||
pr_err("%s: could not install fiq handler\n", __func__);
|
||||
goto err_register_fiq;
|
||||
}
|
||||
|
||||
pdata->fiq_enable(pdev, state->fiq, 1);
|
||||
pdata->fiq_enable(pdev, state->fiq, 1);
|
||||
} else {
|
||||
ret = request_irq(state->uart_irq, debug_uart_irq,
|
||||
IRQF_NO_SUSPEND, "debug", state);
|
||||
if (ret) {
|
||||
pr_err("%s: could not install irq handler\n", __func__);
|
||||
goto err_register_irq;
|
||||
}
|
||||
|
||||
/* for irq-only mode, we want this irq to wake us up, if it
|
||||
* can.
|
||||
*/
|
||||
enable_irq_wake(state->uart_irq);
|
||||
}
|
||||
|
||||
if (state->clk)
|
||||
clk_disable(state->clk);
|
||||
|
||||
ret = request_irq(state->signal_irq, debug_irq,
|
||||
IRQF_TRIGGER_RISING, "debug", state);
|
||||
if (ret)
|
||||
pr_err("serial_debugger: could not install signal_irq");
|
||||
if (state->signal_irq >= 0) {
|
||||
ret = request_irq(state->signal_irq, debug_signal_irq,
|
||||
IRQF_TRIGGER_RISING, "debug-signal", state);
|
||||
if (ret)
|
||||
pr_err("serial_debugger: could not install signal_irq");
|
||||
}
|
||||
|
||||
if (state->wakeup_irq >= 0) {
|
||||
ret = request_irq(state->wakeup_irq, wakeup_irq_handler,
|
||||
@@ -910,7 +1151,7 @@ static int fiq_debugger_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
if (state->no_sleep)
|
||||
wakeup_irq_handler(state->wakeup_irq, state);
|
||||
handle_wakeup(state);
|
||||
|
||||
#if defined(CONFIG_FIQ_DEBUGGER_CONSOLE)
|
||||
state->console = fiq_debugger_console;
|
||||
@@ -919,19 +1160,32 @@ static int fiq_debugger_probe(struct platform_device *pdev)
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
err_register_irq:
|
||||
err_register_fiq:
|
||||
if (pdata->uart_free)
|
||||
pdata->uart_free(pdev);
|
||||
err_uart_init:
|
||||
kfree(state);
|
||||
if (state->clk)
|
||||
clk_disable(state->clk);
|
||||
if (state->clk)
|
||||
clk_put(state->clk);
|
||||
wake_lock_destroy(&state->debugger_wake_lock);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(state);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops fiq_debugger_dev_pm_ops = {
|
||||
.suspend = fiq_debugger_dev_suspend,
|
||||
.resume = fiq_debugger_dev_resume,
|
||||
};
|
||||
|
||||
static struct platform_driver fiq_debugger_driver = {
|
||||
.probe = fiq_debugger_probe,
|
||||
.driver.name = "fiq_debugger",
|
||||
.probe = fiq_debugger_probe,
|
||||
.driver = {
|
||||
.name = "fiq_debugger",
|
||||
.pm = &fiq_debugger_dev_pm_ops,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init fiq_debugger_init(void)
|
||||
|
||||
@@ -27,6 +27,19 @@
|
||||
#define FIQ_DEBUGGER_SIGNAL_IRQ_NAME "signal"
|
||||
#define FIQ_DEBUGGER_WAKEUP_IRQ_NAME "wakeup"
|
||||
|
||||
/**
|
||||
* struct fiq_debugger_pdata - fiq debugger platform data
|
||||
* @uart_resume: used to restore uart state right before enabling
|
||||
* the fiq.
|
||||
* @uart_enable: Do the work necessary to communicate with the uart
|
||||
* hw (enable clocks, etc.). This must be ref-counted.
|
||||
* @uart_disable: Do the work necessary to disable the uart hw
|
||||
* (disable clocks, etc.). This must be ref-counted.
|
||||
* @uart_dev_suspend: called during PM suspend, generally not needed
|
||||
* for real fiq mode debugger.
|
||||
* @uart_dev_resume: called during PM resume, generally not needed
|
||||
* for real fiq mode debugger.
|
||||
*/
|
||||
struct fiq_debugger_pdata {
|
||||
int (*uart_init)(struct platform_device *pdev);
|
||||
void (*uart_free)(struct platform_device *pdev);
|
||||
@@ -34,6 +47,11 @@ struct fiq_debugger_pdata {
|
||||
int (*uart_getc)(struct platform_device *pdev);
|
||||
void (*uart_putc)(struct platform_device *pdev, unsigned int c);
|
||||
void (*uart_flush)(struct platform_device *pdev);
|
||||
void (*uart_enable)(struct platform_device *pdev);
|
||||
void (*uart_disable)(struct platform_device *pdev);
|
||||
|
||||
int (*uart_dev_suspend)(struct platform_device *pdev);
|
||||
int (*uart_dev_resume)(struct platform_device *pdev);
|
||||
|
||||
void (*fiq_enable)(struct platform_device *pdev, unsigned int fiq,
|
||||
bool enable);
|
||||
|
||||
@@ -25,17 +25,17 @@
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
|
||||
#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
|
||||
#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
|
||||
smp_mb(); \
|
||||
__asm__ __volatile__( \
|
||||
"1: ldrex %1, [%2]\n" \
|
||||
"1: ldrex %1, [%3]\n" \
|
||||
" " insn "\n" \
|
||||
"2: strex %1, %0, [%2]\n" \
|
||||
" teq %1, #0\n" \
|
||||
"2: strex %2, %0, [%3]\n" \
|
||||
" teq %2, #0\n" \
|
||||
" bne 1b\n" \
|
||||
" mov %0, #0\n" \
|
||||
__futex_atomic_ex_table("%4") \
|
||||
: "=&r" (ret), "=&r" (oldval) \
|
||||
__futex_atomic_ex_table("%5") \
|
||||
: "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \
|
||||
: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
|
||||
: "cc", "memory")
|
||||
|
||||
@@ -73,14 +73,14 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
|
||||
#include <linux/preempt.h>
|
||||
#include <asm/domain.h>
|
||||
|
||||
#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
|
||||
#define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \
|
||||
__asm__ __volatile__( \
|
||||
"1: " T(ldr) " %1, [%2]\n" \
|
||||
"1: " T(ldr) " %1, [%3]\n" \
|
||||
" " insn "\n" \
|
||||
"2: " T(str) " %0, [%2]\n" \
|
||||
"2: " T(str) " %0, [%3]\n" \
|
||||
" mov %0, #0\n" \
|
||||
__futex_atomic_ex_table("%4") \
|
||||
: "=&r" (ret), "=&r" (oldval) \
|
||||
__futex_atomic_ex_table("%5") \
|
||||
: "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \
|
||||
: "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \
|
||||
: "cc", "memory")
|
||||
|
||||
@@ -117,7 +117,7 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
||||
int cmp = (encoded_op >> 24) & 15;
|
||||
int oparg = (encoded_op << 8) >> 20;
|
||||
int cmparg = (encoded_op << 20) >> 20;
|
||||
int oldval = 0, ret;
|
||||
int oldval = 0, ret, tmp;
|
||||
|
||||
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
||||
oparg = 1 << oparg;
|
||||
@@ -129,19 +129,19 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
||||
|
||||
switch (op) {
|
||||
case FUTEX_OP_SET:
|
||||
__futex_atomic_op("mov %0, %3", ret, oldval, uaddr, oparg);
|
||||
__futex_atomic_op("mov %0, %4", ret, oldval, tmp, uaddr, oparg);
|
||||
break;
|
||||
case FUTEX_OP_ADD:
|
||||
__futex_atomic_op("add %0, %1, %3", ret, oldval, uaddr, oparg);
|
||||
__futex_atomic_op("add %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
|
||||
break;
|
||||
case FUTEX_OP_OR:
|
||||
__futex_atomic_op("orr %0, %1, %3", ret, oldval, uaddr, oparg);
|
||||
__futex_atomic_op("orr %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
|
||||
break;
|
||||
case FUTEX_OP_ANDN:
|
||||
__futex_atomic_op("and %0, %1, %3", ret, oldval, uaddr, ~oparg);
|
||||
__futex_atomic_op("and %0, %1, %4", ret, oldval, tmp, uaddr, ~oparg);
|
||||
break;
|
||||
case FUTEX_OP_XOR:
|
||||
__futex_atomic_op("eor %0, %1, %3", ret, oldval, uaddr, oparg);
|
||||
__futex_atomic_op("eor %0, %1, %4", ret, oldval, tmp, uaddr, oparg);
|
||||
break;
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <linux/threads.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#define NR_IPI 6
|
||||
#define NR_IPI 7
|
||||
|
||||
typedef struct {
|
||||
unsigned int __softirq_pending;
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
#define L2X0_STNDBY_MODE_EN (1 << 0)
|
||||
|
||||
/* Registers shifts and masks */
|
||||
#define L2X0_CACHE_ID_REV_MASK (0x3f)
|
||||
#define L2X0_CACHE_ID_PART_MASK (0xf << 6)
|
||||
#define L2X0_CACHE_ID_PART_L210 (1 << 6)
|
||||
#define L2X0_CACHE_ID_PART_L220 (2 << 6)
|
||||
@@ -65,7 +66,7 @@
|
||||
#define L2X0_AUX_CTRL_MASK 0xc0000fff
|
||||
#define L2X0_AUX_CTRL_ASSOCIATIVITY_SHIFT 16
|
||||
#define L2X0_AUX_CTRL_WAY_SIZE_SHIFT 17
|
||||
#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x3 << 17)
|
||||
#define L2X0_AUX_CTRL_WAY_SIZE_MASK (0x7 << 17)
|
||||
#define L2X0_AUX_CTRL_SHARE_OVERRIDE_SHIFT 22
|
||||
#define L2X0_AUX_CTRL_NS_LOCKDOWN_SHIFT 26
|
||||
#define L2X0_AUX_CTRL_NS_INT_CTRL_SHIFT 27
|
||||
@@ -74,6 +75,8 @@
|
||||
#define L2X0_AUX_CTRL_EARLY_BRESP_SHIFT 30
|
||||
#define L2X0_AUX_CTRL_EVNT_MON_BUS_EN_SHIFT 20
|
||||
|
||||
#define REV_PL310_R2P0 4
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
extern void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask);
|
||||
extern void l2x0_suspend(void);
|
||||
|
||||
@@ -26,6 +26,9 @@ extern void asm_do_IRQ(unsigned int, struct pt_regs *);
|
||||
void handle_IRQ(unsigned int, struct pt_regs *);
|
||||
void init_IRQ(void);
|
||||
|
||||
void arch_trigger_all_cpu_backtrace(void);
|
||||
#define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -98,4 +98,6 @@ extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
|
||||
*/
|
||||
extern void show_local_irqs(struct seq_file *, int);
|
||||
|
||||
extern void smp_send_all_cpu_backtrace(void);
|
||||
|
||||
#endif /* ifndef __ASM_ARM_SMP_H */
|
||||
|
||||
@@ -307,8 +307,8 @@ static const unsigned armv7_a9_perf_map[PERF_COUNT_HW_MAX] = {
|
||||
[PERF_COUNT_HW_CPU_CYCLES] = ARMV7_PERFCTR_CPU_CYCLES,
|
||||
[PERF_COUNT_HW_INSTRUCTIONS] =
|
||||
ARMV7_PERFCTR_INST_OUT_OF_RENAME_STAGE,
|
||||
[PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_COHERENT_LINE_HIT,
|
||||
[PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_COHERENT_LINE_MISS,
|
||||
[PERF_COUNT_HW_CACHE_REFERENCES] = ARMV7_PERFCTR_DCACHE_ACCESS,
|
||||
[PERF_COUNT_HW_CACHE_MISSES] = ARMV7_PERFCTR_DCACHE_REFILL,
|
||||
[PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = ARMV7_PERFCTR_PC_WRITE,
|
||||
[PERF_COUNT_HW_BRANCH_MISSES] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
|
||||
[PERF_COUNT_HW_BUS_CYCLES] = ARMV7_PERFCTR_CLOCK_CYCLES,
|
||||
|
||||
@@ -62,6 +62,18 @@ static volatile int hlt_counter;
|
||||
|
||||
#include <mach/system.h>
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
void arch_trigger_all_cpu_backtrace(void)
|
||||
{
|
||||
smp_send_all_cpu_backtrace();
|
||||
}
|
||||
#else
|
||||
void arch_trigger_all_cpu_backtrace(void)
|
||||
{
|
||||
dump_stack();
|
||||
}
|
||||
#endif
|
||||
|
||||
void disable_hlt(void)
|
||||
{
|
||||
hlt_counter++;
|
||||
@@ -239,8 +251,8 @@ void cpu_idle(void)
|
||||
local_irq_enable();
|
||||
}
|
||||
}
|
||||
idle_notifier_call_chain(IDLE_END);
|
||||
tick_nohz_restart_sched_tick();
|
||||
idle_notifier_call_chain(IDLE_END);
|
||||
preempt_enable_no_resched();
|
||||
schedule();
|
||||
preempt_disable();
|
||||
|
||||
@@ -54,6 +54,7 @@ enum ipi_msg_type {
|
||||
IPI_CALL_FUNC,
|
||||
IPI_CALL_FUNC_SINGLE,
|
||||
IPI_CPU_STOP,
|
||||
IPI_CPU_BACKTRACE,
|
||||
};
|
||||
|
||||
int __cpuinit __cpu_up(unsigned int cpu)
|
||||
@@ -407,6 +408,7 @@ static const char *ipi_types[NR_IPI] = {
|
||||
S(IPI_CALL_FUNC, "Function call interrupts"),
|
||||
S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
|
||||
S(IPI_CPU_STOP, "CPU stop interrupts"),
|
||||
S(IPI_CPU_BACKTRACE, "CPU backtrace"),
|
||||
};
|
||||
|
||||
void show_ipi_list(struct seq_file *p, int prec)
|
||||
@@ -557,6 +559,58 @@ static void ipi_cpu_stop(unsigned int cpu)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
static cpumask_t backtrace_mask;
|
||||
static DEFINE_RAW_SPINLOCK(backtrace_lock);
|
||||
|
||||
/* "in progress" flag of arch_trigger_all_cpu_backtrace */
|
||||
static unsigned long backtrace_flag;
|
||||
|
||||
void smp_send_all_cpu_backtrace(void)
|
||||
{
|
||||
unsigned int this_cpu = smp_processor_id();
|
||||
int i;
|
||||
|
||||
if (test_and_set_bit(0, &backtrace_flag))
|
||||
/*
|
||||
* If there is already a trigger_all_cpu_backtrace() in progress
|
||||
* (backtrace_flag == 1), don't output double cpu dump infos.
|
||||
*/
|
||||
return;
|
||||
|
||||
cpumask_copy(&backtrace_mask, cpu_online_mask);
|
||||
cpu_clear(this_cpu, backtrace_mask);
|
||||
|
||||
pr_info("Backtrace for cpu %d (current):\n", this_cpu);
|
||||
dump_stack();
|
||||
|
||||
pr_info("\nsending IPI to all other CPUs:\n");
|
||||
smp_cross_call(&backtrace_mask, IPI_CPU_BACKTRACE);
|
||||
|
||||
/* Wait for up to 10 seconds for all other CPUs to do the backtrace */
|
||||
for (i = 0; i < 10 * 1000; i++) {
|
||||
if (cpumask_empty(&backtrace_mask))
|
||||
break;
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
clear_bit(0, &backtrace_flag);
|
||||
smp_mb__after_clear_bit();
|
||||
}
|
||||
|
||||
/*
|
||||
* ipi_cpu_backtrace - handle IPI from smp_send_all_cpu_backtrace()
|
||||
*/
|
||||
static void ipi_cpu_backtrace(unsigned int cpu, struct pt_regs *regs)
|
||||
{
|
||||
if (cpu_isset(cpu, backtrace_mask)) {
|
||||
raw_spin_lock(&backtrace_lock);
|
||||
pr_warning("IPI backtrace for cpu %d\n", cpu);
|
||||
show_regs(regs);
|
||||
raw_spin_unlock(&backtrace_lock);
|
||||
cpu_clear(cpu, backtrace_mask);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Main handler for inter-processor interrupts
|
||||
*/
|
||||
@@ -597,6 +651,10 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
|
||||
ipi_cpu_stop(cpu);
|
||||
break;
|
||||
|
||||
case IPI_CPU_BACKTRACE:
|
||||
ipi_cpu_backtrace(cpu, regs);
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_CRIT "CPU%u: Unknown IPI message 0x%x\n",
|
||||
cpu, ipinr);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <asm/smp_scu.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/cputype.h>
|
||||
|
||||
#define SCU_CTRL 0x00
|
||||
#define SCU_CONFIG 0x04
|
||||
@@ -36,6 +37,15 @@ void __init scu_enable(void __iomem *scu_base)
|
||||
{
|
||||
u32 scu_ctrl;
|
||||
|
||||
#ifdef CONFIG_ARM_ERRATA_764369
|
||||
/* Cortex-A9 only */
|
||||
if ((read_cpuid(CPUID_ID) & 0xff0ffff0) == 0x410fc090) {
|
||||
scu_ctrl = __raw_readl(scu_base + 0x30);
|
||||
if (!(scu_ctrl & 1))
|
||||
__raw_writel(scu_ctrl | 0x1, scu_base + 0x30);
|
||||
}
|
||||
#endif
|
||||
|
||||
scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
|
||||
/* already enabled? */
|
||||
if (scu_ctrl & 1)
|
||||
|
||||
@@ -115,6 +115,32 @@ static struct spi_board_info da850evm_spi_info[] = {
|
||||
},
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MTD
|
||||
static void da850_evm_m25p80_notify_add(struct mtd_info *mtd)
|
||||
{
|
||||
char *mac_addr = davinci_soc_info.emac_pdata->mac_addr;
|
||||
size_t retlen;
|
||||
|
||||
if (!strcmp(mtd->name, "MAC-Address")) {
|
||||
mtd->read(mtd, 0, ETH_ALEN, &retlen, mac_addr);
|
||||
if (retlen == ETH_ALEN)
|
||||
pr_info("Read MAC addr from SPI Flash: %pM\n",
|
||||
mac_addr);
|
||||
}
|
||||
}
|
||||
|
||||
static struct mtd_notifier da850evm_spi_notifier = {
|
||||
.add = da850_evm_m25p80_notify_add,
|
||||
};
|
||||
|
||||
static void da850_evm_setup_mac_addr(void)
|
||||
{
|
||||
register_mtd_user(&da850evm_spi_notifier);
|
||||
}
|
||||
#else
|
||||
static void da850_evm_setup_mac_addr(void) { }
|
||||
#endif
|
||||
|
||||
static struct mtd_partition da850_evm_norflash_partition[] = {
|
||||
{
|
||||
.name = "bootloaders + env",
|
||||
@@ -1237,6 +1263,8 @@ static __init void da850_evm_init(void)
|
||||
if (ret)
|
||||
pr_warning("da850_evm_init: spi 1 registration failed: %d\n",
|
||||
ret);
|
||||
|
||||
da850_evm_setup_mac_addr();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SERIAL_8250_CONSOLE
|
||||
|
||||
@@ -217,7 +217,11 @@ ddr2clk_stop_done:
|
||||
ENDPROC(davinci_ddr_psc_config)
|
||||
|
||||
CACHE_FLUSH:
|
||||
.word arm926_flush_kern_cache_all
|
||||
#ifdef CONFIG_CPU_V6
|
||||
.word v6_flush_kern_cache_all
|
||||
#else
|
||||
.word arm926_flush_kern_cache_all
|
||||
#endif
|
||||
|
||||
ENTRY(davinci_cpu_suspend_sz)
|
||||
.word . - davinci_cpu_suspend
|
||||
|
||||
@@ -160,7 +160,7 @@ void __init dove_spi0_init(void)
|
||||
|
||||
void __init dove_spi1_init(void)
|
||||
{
|
||||
orion_spi_init(DOVE_SPI1_PHYS_BASE, get_tclk());
|
||||
orion_spi_1_init(DOVE_SPI1_PHYS_BASE, get_tclk());
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
@@ -337,15 +337,15 @@ static unsigned long timer_reload;
|
||||
static void integrator_clocksource_init(u32 khz)
|
||||
{
|
||||
void __iomem *base = (void __iomem *)TIMER2_VA_BASE;
|
||||
u32 ctrl = TIMER_CTRL_ENABLE;
|
||||
u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
|
||||
|
||||
if (khz >= 1500) {
|
||||
khz /= 16;
|
||||
ctrl = TIMER_CTRL_DIV16;
|
||||
ctrl |= TIMER_CTRL_DIV16;
|
||||
}
|
||||
|
||||
writel(ctrl, base + TIMER_CTRL);
|
||||
writel(0xffff, base + TIMER_LOAD);
|
||||
writel(ctrl, base + TIMER_CTRL);
|
||||
|
||||
clocksource_mmio_init(base + TIMER_VALUE, "timer2",
|
||||
khz * 1000, 200, 16, clocksource_mmio_readl_down);
|
||||
|
||||
@@ -6,6 +6,7 @@ config UX500_SOC_COMMON
|
||||
select ARM_GIC
|
||||
select HAS_MTU
|
||||
select ARM_ERRATA_753970
|
||||
select ARM_ERRATA_754322
|
||||
|
||||
menu "Ux500 SoC"
|
||||
|
||||
|
||||
+55
-13
@@ -32,6 +32,16 @@ static uint32_t data_latency_ctrl;
|
||||
static DEFINE_SPINLOCK(l2x0_lock);
|
||||
static uint32_t l2x0_way_mask; /* Bitmask of active ways */
|
||||
static uint32_t l2x0_size;
|
||||
static u32 l2x0_cache_id;
|
||||
static unsigned int l2x0_sets;
|
||||
static unsigned int l2x0_ways;
|
||||
|
||||
static inline bool is_pl310_rev(int rev)
|
||||
{
|
||||
return (l2x0_cache_id &
|
||||
(L2X0_CACHE_ID_PART_MASK | L2X0_CACHE_ID_REV_MASK)) ==
|
||||
(L2X0_CACHE_ID_PART_L310 | rev);
|
||||
}
|
||||
|
||||
static inline void cache_wait_way(void __iomem *reg, unsigned long mask)
|
||||
{
|
||||
@@ -119,6 +129,23 @@ void l2x0_cache_sync(void)
|
||||
cache_sync();
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PL310_ERRATA_727915
|
||||
static void l2x0_for_each_set_way(void __iomem *reg)
|
||||
{
|
||||
int set;
|
||||
int way;
|
||||
unsigned long flags;
|
||||
|
||||
for (way = 0; way < l2x0_ways; way++) {
|
||||
spin_lock_irqsave(&l2x0_lock, flags);
|
||||
for (set = 0; set < l2x0_sets; set++)
|
||||
writel_relaxed((way << 28) | (set << 5), reg);
|
||||
cache_sync();
|
||||
spin_unlock_irqrestore(&l2x0_lock, flags);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void __l2x0_flush_all(void)
|
||||
{
|
||||
debug_writel(0x03);
|
||||
@@ -132,6 +159,13 @@ static void l2x0_flush_all(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
#ifdef CONFIG_PL310_ERRATA_727915
|
||||
if (is_pl310_rev(REV_PL310_R2P0)) {
|
||||
l2x0_for_each_set_way(l2x0_base + L2X0_CLEAN_INV_LINE_IDX);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* clean all ways */
|
||||
spin_lock_irqsave(&l2x0_lock, flags);
|
||||
__l2x0_flush_all();
|
||||
@@ -142,11 +176,20 @@ static void l2x0_clean_all(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
#ifdef CONFIG_PL310_ERRATA_727915
|
||||
if (is_pl310_rev(REV_PL310_R2P0)) {
|
||||
l2x0_for_each_set_way(l2x0_base + L2X0_CLEAN_LINE_IDX);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* clean all ways */
|
||||
spin_lock_irqsave(&l2x0_lock, flags);
|
||||
debug_writel(0x03);
|
||||
writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_WAY);
|
||||
cache_wait_way(l2x0_base + L2X0_CLEAN_WAY, l2x0_way_mask);
|
||||
cache_sync();
|
||||
debug_writel(0x00);
|
||||
spin_unlock_irqrestore(&l2x0_lock, flags);
|
||||
}
|
||||
|
||||
@@ -322,13 +365,11 @@ static void l2x0_disable(void)
|
||||
void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
|
||||
{
|
||||
__u32 aux, bits;
|
||||
__u32 cache_id;
|
||||
__u32 way_size = 0;
|
||||
int ways;
|
||||
const char *type;
|
||||
|
||||
l2x0_base = base;
|
||||
cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
|
||||
l2x0_cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
|
||||
|
||||
bits = readl_relaxed(l2x0_base + L2X0_CTRL);
|
||||
bits &= ~0x01; /* clear bit 0 */
|
||||
@@ -340,33 +381,34 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
|
||||
aux |= aux_val;
|
||||
|
||||
/* Determine the number of ways */
|
||||
switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
|
||||
switch (l2x0_cache_id & L2X0_CACHE_ID_PART_MASK) {
|
||||
case L2X0_CACHE_ID_PART_L310:
|
||||
if (aux & (1 << 16))
|
||||
ways = 16;
|
||||
l2x0_ways = 16;
|
||||
else
|
||||
ways = 8;
|
||||
l2x0_ways = 8;
|
||||
type = "L310";
|
||||
break;
|
||||
case L2X0_CACHE_ID_PART_L210:
|
||||
ways = (aux >> 13) & 0xf;
|
||||
l2x0_ways = (aux >> 13) & 0xf;
|
||||
type = "L210";
|
||||
break;
|
||||
default:
|
||||
/* Assume unknown chips have 8 ways */
|
||||
ways = 8;
|
||||
l2x0_ways = 8;
|
||||
type = "L2x0 series";
|
||||
break;
|
||||
}
|
||||
writel_relaxed(aux, l2x0_base + L2X0_AUX_CTRL);
|
||||
l2x0_way_mask = (1 << ways) - 1;
|
||||
l2x0_way_mask = (1 << l2x0_ways) - 1;
|
||||
|
||||
/*
|
||||
* L2 cache Size = Way size * Number of ways
|
||||
*/
|
||||
way_size = (aux & L2X0_AUX_CTRL_WAY_SIZE_MASK) >> 17;
|
||||
way_size = 1 << (way_size + 3);
|
||||
l2x0_size = ways * way_size * SZ_1K;
|
||||
way_size = SZ_1K << (way_size + 3);
|
||||
l2x0_size = l2x0_ways * way_size;
|
||||
l2x0_sets = way_size / CACHE_LINE_SIZE;
|
||||
|
||||
l2x0_inv_all();
|
||||
|
||||
@@ -375,7 +417,7 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
|
||||
bits |= 0x01; /* set bit 0 */
|
||||
writel_relaxed(bits, l2x0_base + L2X0_CTRL);
|
||||
|
||||
switch (cache_id & L2X0_CACHE_ID_PART_MASK) {
|
||||
switch (l2x0_cache_id & L2X0_CACHE_ID_PART_MASK) {
|
||||
case L2X0_CACHE_ID_PART_L220:
|
||||
outer_cache.inv_range = l2x0_inv_range;
|
||||
outer_cache.clean_range = l2x0_clean_range;
|
||||
@@ -407,7 +449,7 @@ void __init l2x0_init(void __iomem *base, __u32 aux_val, __u32 aux_mask)
|
||||
mb();
|
||||
printk(KERN_INFO "%s cache controller enabled\n", type);
|
||||
printk(KERN_INFO "l2x0: %d ways, CACHE_ID 0x%08x, AUX_CTRL 0x%08x, Cache size: %d B\n",
|
||||
ways, cache_id, aux, l2x0_size);
|
||||
l2x0_ways, l2x0_cache_id, aux, l2x0_size);
|
||||
}
|
||||
|
||||
void l2x0_suspend(void)
|
||||
|
||||
@@ -174,6 +174,10 @@ ENTRY(v7_coherent_user_range)
|
||||
dcache_line_size r2, r3
|
||||
sub r3, r2, #1
|
||||
bic r12, r0, r3
|
||||
#ifdef CONFIG_ARM_ERRATA_764369
|
||||
ALT_SMP(W(dsb))
|
||||
ALT_UP(W(nop))
|
||||
#endif
|
||||
1:
|
||||
USER( mcr p15, 0, r12, c7, c11, 1 ) @ clean D line to the point of unification
|
||||
add r12, r12, r2
|
||||
@@ -223,6 +227,10 @@ ENTRY(v7_flush_kern_dcache_area)
|
||||
add r1, r0, r1
|
||||
sub r3, r2, #1
|
||||
bic r0, r0, r3
|
||||
#ifdef CONFIG_ARM_ERRATA_764369
|
||||
ALT_SMP(W(dsb))
|
||||
ALT_UP(W(nop))
|
||||
#endif
|
||||
1:
|
||||
mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D line / unified line
|
||||
add r0, r0, r2
|
||||
@@ -247,6 +255,10 @@ ENTRY(v7_dma_inv_range)
|
||||
sub r3, r2, #1
|
||||
tst r0, r3
|
||||
bic r0, r0, r3
|
||||
#ifdef CONFIG_ARM_ERRATA_764369
|
||||
ALT_SMP(W(dsb))
|
||||
ALT_UP(W(nop))
|
||||
#endif
|
||||
mcrne p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
|
||||
|
||||
tst r1, r3
|
||||
@@ -270,6 +282,10 @@ ENTRY(v7_dma_clean_range)
|
||||
dcache_line_size r2, r3
|
||||
sub r3, r2, #1
|
||||
bic r0, r0, r3
|
||||
#ifdef CONFIG_ARM_ERRATA_764369
|
||||
ALT_SMP(W(dsb))
|
||||
ALT_UP(W(nop))
|
||||
#endif
|
||||
1:
|
||||
mcr p15, 0, r0, c7, c10, 1 @ clean D / U line
|
||||
add r0, r0, r2
|
||||
@@ -288,6 +304,10 @@ ENTRY(v7_dma_flush_range)
|
||||
dcache_line_size r2, r3
|
||||
sub r3, r2, #1
|
||||
bic r0, r0, r3
|
||||
#ifdef CONFIG_ARM_ERRATA_764369
|
||||
ALT_SMP(W(dsb))
|
||||
ALT_UP(W(nop))
|
||||
#endif
|
||||
1:
|
||||
mcr p15, 0, r0, c7, c14, 1 @ clean & invalidate D / U line
|
||||
add r0, r0, r2
|
||||
|
||||
@@ -322,6 +322,8 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
|
||||
|
||||
if (addr)
|
||||
*handle = pfn_to_dma(dev, page_to_pfn(page));
|
||||
else
|
||||
__dma_free_buffer(page, size);
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
@@ -546,6 +546,13 @@ static void __init free_unused_memmap(struct meminfo *mi)
|
||||
*/
|
||||
bank_start = min(bank_start,
|
||||
ALIGN(prev_bank_end, PAGES_PER_SECTION));
|
||||
#else
|
||||
/*
|
||||
* Align down here since the VM subsystem insists that the
|
||||
* memmap entries are valid from the bank start aligned to
|
||||
* MAX_ORDER_NR_PAGES.
|
||||
*/
|
||||
bank_start = round_down(bank_start, MAX_ORDER_NR_PAGES);
|
||||
#endif
|
||||
/*
|
||||
* If we had a previous bank, and there is a space
|
||||
|
||||
@@ -66,7 +66,6 @@ typedef u64 iomux_v3_cfg_t;
|
||||
#define MUX_MODE_MASK ((iomux_v3_cfg_t)0x1f << MUX_MODE_SHIFT)
|
||||
#define MUX_PAD_CTRL_SHIFT 41
|
||||
#define MUX_PAD_CTRL_MASK ((iomux_v3_cfg_t)0x1ffff << MUX_PAD_CTRL_SHIFT)
|
||||
#define NO_PAD_CTRL ((iomux_v3_cfg_t)1 << (MUX_PAD_CTRL_SHIFT + 16))
|
||||
#define MUX_SEL_INPUT_SHIFT 58
|
||||
#define MUX_SEL_INPUT_MASK ((iomux_v3_cfg_t)0xf << MUX_SEL_INPUT_SHIFT)
|
||||
|
||||
@@ -85,6 +84,7 @@ typedef u64 iomux_v3_cfg_t;
|
||||
* Use to set PAD control
|
||||
*/
|
||||
|
||||
#define NO_PAD_CTRL (1 << 16)
|
||||
#define PAD_CTL_DVS (1 << 13)
|
||||
#define PAD_CTL_HYS (1 << 8)
|
||||
|
||||
|
||||
+9
-11
@@ -77,15 +77,12 @@ ENTRY(vfp_support_entry)
|
||||
bne look_for_VFP_exceptions @ VFP is already enabled
|
||||
|
||||
DBGSTR1 "enable %x", r10
|
||||
ldr r3, last_VFP_context_address
|
||||
ldr r3, vfp_current_hw_state_address
|
||||
orr r1, r1, #FPEXC_EN @ user FPEXC has the enable bit set
|
||||
ldr r4, [r3, r11, lsl #2] @ last_VFP_context pointer
|
||||
ldr r4, [r3, r11, lsl #2] @ vfp_current_hw_state pointer
|
||||
bic r5, r1, #FPEXC_EX @ make sure exceptions are disabled
|
||||
cmp r4, r10
|
||||
beq check_for_exception @ we are returning to the same
|
||||
@ process, so the registers are
|
||||
@ still there. In this case, we do
|
||||
@ not want to drop a pending exception.
|
||||
cmp r4, r10 @ this thread owns the hw context?
|
||||
beq vfp_hw_state_valid
|
||||
|
||||
VFPFMXR FPEXC, r5 @ enable VFP, disable any pending
|
||||
@ exceptions, so we can get at the
|
||||
@@ -116,7 +113,7 @@ ENTRY(vfp_support_entry)
|
||||
|
||||
no_old_VFP_process:
|
||||
DBGSTR1 "load state %p", r10
|
||||
str r10, [r3, r11, lsl #2] @ update the last_VFP_context pointer
|
||||
str r10, [r3, r11, lsl #2] @ update the vfp_current_hw_state pointer
|
||||
@ Load the saved state back into the VFP
|
||||
VFPFLDMIA r10, r5 @ reload the working registers while
|
||||
@ FPEXC is in a safe state
|
||||
@@ -132,7 +129,8 @@ no_old_VFP_process:
|
||||
#endif
|
||||
VFPFMXR FPSCR, r5 @ restore status
|
||||
|
||||
check_for_exception:
|
||||
@ The context stored in the VFP hardware is up to date with this thread
|
||||
vfp_hw_state_valid:
|
||||
tst r1, #FPEXC_EX
|
||||
bne process_exception @ might as well handle the pending
|
||||
@ exception before retrying branch
|
||||
@@ -207,8 +205,8 @@ ENTRY(vfp_save_state)
|
||||
ENDPROC(vfp_save_state)
|
||||
|
||||
.align
|
||||
last_VFP_context_address:
|
||||
.word last_VFP_context
|
||||
vfp_current_hw_state_address:
|
||||
.word vfp_current_hw_state
|
||||
|
||||
.macro tbl_branch, base, tmp, shift
|
||||
#ifdef CONFIG_THUMB2_KERNEL
|
||||
|
||||
+25
-19
@@ -33,7 +33,13 @@ void vfp_support_entry(void);
|
||||
void vfp_null_entry(void);
|
||||
|
||||
void (*vfp_vector)(void) = vfp_null_entry;
|
||||
union vfp_state *last_VFP_context[NR_CPUS];
|
||||
|
||||
/*
|
||||
* The pointer to the vfpstate structure of the thread which currently
|
||||
* owns the context held in the VFP hardware, or NULL if the hardware
|
||||
* context is invalid.
|
||||
*/
|
||||
union vfp_state *vfp_current_hw_state[NR_CPUS];
|
||||
|
||||
/*
|
||||
* Dual-use variable.
|
||||
@@ -57,12 +63,12 @@ static void vfp_thread_flush(struct thread_info *thread)
|
||||
|
||||
/*
|
||||
* Disable VFP to ensure we initialize it first. We must ensure
|
||||
* that the modification of last_VFP_context[] and hardware disable
|
||||
* that the modification of vfp_current_hw_state[] and hardware disable
|
||||
* are done for the same CPU and without preemption.
|
||||
*/
|
||||
cpu = get_cpu();
|
||||
if (last_VFP_context[cpu] == vfp)
|
||||
last_VFP_context[cpu] = NULL;
|
||||
if (vfp_current_hw_state[cpu] == vfp)
|
||||
vfp_current_hw_state[cpu] = NULL;
|
||||
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
|
||||
put_cpu();
|
||||
}
|
||||
@@ -73,8 +79,8 @@ static void vfp_thread_exit(struct thread_info *thread)
|
||||
union vfp_state *vfp = &thread->vfpstate;
|
||||
unsigned int cpu = get_cpu();
|
||||
|
||||
if (last_VFP_context[cpu] == vfp)
|
||||
last_VFP_context[cpu] = NULL;
|
||||
if (vfp_current_hw_state[cpu] == vfp)
|
||||
vfp_current_hw_state[cpu] = NULL;
|
||||
put_cpu();
|
||||
}
|
||||
|
||||
@@ -129,9 +135,9 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
|
||||
* case the thread migrates to a different CPU. The
|
||||
* restoring is done lazily.
|
||||
*/
|
||||
if ((fpexc & FPEXC_EN) && last_VFP_context[cpu]) {
|
||||
vfp_save_state(last_VFP_context[cpu], fpexc);
|
||||
last_VFP_context[cpu]->hard.cpu = cpu;
|
||||
if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) {
|
||||
vfp_save_state(vfp_current_hw_state[cpu], fpexc);
|
||||
vfp_current_hw_state[cpu]->hard.cpu = cpu;
|
||||
}
|
||||
/*
|
||||
* Thread migration, just force the reloading of the
|
||||
@@ -139,7 +145,7 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
|
||||
* contain stale data.
|
||||
*/
|
||||
if (thread->vfpstate.hard.cpu != cpu)
|
||||
last_VFP_context[cpu] = NULL;
|
||||
vfp_current_hw_state[cpu] = NULL;
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -413,22 +419,22 @@ int vfp_flush_context(void)
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* On SMP, if VFP is enabled, save the old state */
|
||||
if ((fpexc & FPEXC_EN) && last_VFP_context[cpu]) {
|
||||
last_VFP_context[cpu]->hard.cpu = cpu;
|
||||
if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) {
|
||||
vfp_current_hw_state[cpu]->hard.cpu = cpu;
|
||||
#else
|
||||
/* If there is a VFP context we must save it. */
|
||||
if (last_VFP_context[cpu]) {
|
||||
if (vfp_current_hw_state[cpu]) {
|
||||
/* Enable VFP so we can save the old state. */
|
||||
fmxr(FPEXC, fpexc | FPEXC_EN);
|
||||
isb();
|
||||
#endif
|
||||
vfp_save_state(last_VFP_context[cpu], fpexc);
|
||||
vfp_save_state(vfp_current_hw_state[cpu], fpexc);
|
||||
|
||||
/* disable, just in case */
|
||||
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
|
||||
saved = 1;
|
||||
}
|
||||
last_VFP_context[cpu] = NULL;
|
||||
vfp_current_hw_state[cpu] = NULL;
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
@@ -481,7 +487,7 @@ void vfp_sync_hwstate(struct thread_info *thread)
|
||||
* If the thread we're interested in is the current owner of the
|
||||
* hardware VFP state, then we need to save its state.
|
||||
*/
|
||||
if (last_VFP_context[cpu] == &thread->vfpstate) {
|
||||
if (vfp_current_hw_state[cpu] == &thread->vfpstate) {
|
||||
u32 fpexc = fmrx(FPEXC);
|
||||
|
||||
/*
|
||||
@@ -503,7 +509,7 @@ void vfp_flush_hwstate(struct thread_info *thread)
|
||||
* If the thread we're interested in is the current owner of the
|
||||
* hardware VFP state, then we need to save its state.
|
||||
*/
|
||||
if (last_VFP_context[cpu] == &thread->vfpstate) {
|
||||
if (vfp_current_hw_state[cpu] == &thread->vfpstate) {
|
||||
u32 fpexc = fmrx(FPEXC);
|
||||
|
||||
fmxr(FPEXC, fpexc & ~FPEXC_EN);
|
||||
@@ -512,7 +518,7 @@ void vfp_flush_hwstate(struct thread_info *thread)
|
||||
* Set the context to NULL to force a reload the next time
|
||||
* the thread uses the VFP.
|
||||
*/
|
||||
last_VFP_context[cpu] = NULL;
|
||||
vfp_current_hw_state[cpu] = NULL;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
@@ -544,7 +550,7 @@ static int vfp_hotplug(struct notifier_block *b, unsigned long action,
|
||||
{
|
||||
if (action == CPU_DYING || action == CPU_DYING_FROZEN) {
|
||||
unsigned int cpu = (long)hcpu;
|
||||
last_VFP_context[cpu] = NULL;
|
||||
vfp_current_hw_state[cpu] = NULL;
|
||||
} else if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
|
||||
vfp_enable(NULL);
|
||||
return NOTIFY_OK;
|
||||
|
||||
@@ -158,7 +158,7 @@ static int sync_serial_open(struct inode *inode, struct file *file);
|
||||
static int sync_serial_release(struct inode *inode, struct file *file);
|
||||
static unsigned int sync_serial_poll(struct file *filp, poll_table *wait);
|
||||
|
||||
static int sync_serial_ioctl(struct file *file,
|
||||
static long sync_serial_ioctl(struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
static ssize_t sync_serial_write(struct file *file, const char *buf,
|
||||
size_t count, loff_t *ppos);
|
||||
@@ -625,11 +625,11 @@ static int sync_serial_open(struct inode *inode, struct file *file)
|
||||
*R_IRQ_MASK1_SET = 1 << port->data_avail_bit;
|
||||
DEBUG(printk(KERN_DEBUG "sser%d rec started\n", dev));
|
||||
}
|
||||
ret = 0;
|
||||
err = 0;
|
||||
|
||||
out:
|
||||
mutex_unlock(&sync_serial_mutex);
|
||||
return ret;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sync_serial_release(struct inode *inode, struct file *file)
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
#define crisv10_mask_irq(irq_nr) (*R_VECT_MASK_CLR = 1 << (irq_nr));
|
||||
#define crisv10_unmask_irq(irq_nr) (*R_VECT_MASK_SET = 1 << (irq_nr));
|
||||
|
||||
extern void kgdb_init(void);
|
||||
extern void breakpoint(void);
|
||||
|
||||
/* don't use set_int_vector, it bypasses the linux interrupt handlers. it is
|
||||
* global just so that the kernel gdb can use it.
|
||||
*/
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <asm/types.h>
|
||||
#include <asm/processor.h>
|
||||
@@ -67,8 +65,10 @@ struct thread_info {
|
||||
|
||||
#define init_thread_info (init_thread_union.thread_info)
|
||||
|
||||
#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
|
||||
/* thread information allocation */
|
||||
#define alloc_thread_info(tsk, node) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
|
||||
#define alloc_thread_info_node(tsk, node) \
|
||||
((struct thread_info *) __get_free_pages(GFP_KERNEL, 1))
|
||||
#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
+24
-32
@@ -18,7 +18,7 @@
|
||||
#include <linux/init.h>
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sysdev.h>
|
||||
#include <linux/syscore_ops.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/delay.h>
|
||||
@@ -86,7 +86,6 @@ struct jz_gpio_chip {
|
||||
spinlock_t lock;
|
||||
|
||||
struct gpio_chip gpio_chip;
|
||||
struct sys_device sysdev;
|
||||
};
|
||||
|
||||
static struct jz_gpio_chip jz4740_gpio_chips[];
|
||||
@@ -459,49 +458,47 @@ static struct jz_gpio_chip jz4740_gpio_chips[] = {
|
||||
JZ4740_GPIO_CHIP(D),
|
||||
};
|
||||
|
||||
static inline struct jz_gpio_chip *sysdev_to_chip(struct sys_device *dev)
|
||||
static void jz4740_gpio_suspend_chip(struct jz_gpio_chip *chip)
|
||||
{
|
||||
return container_of(dev, struct jz_gpio_chip, sysdev);
|
||||
}
|
||||
|
||||
static int jz4740_gpio_suspend(struct sys_device *dev, pm_message_t state)
|
||||
{
|
||||
struct jz_gpio_chip *chip = sysdev_to_chip(dev);
|
||||
|
||||
chip->suspend_mask = readl(chip->base + JZ_REG_GPIO_MASK);
|
||||
writel(~(chip->wakeup), chip->base + JZ_REG_GPIO_MASK_SET);
|
||||
writel(chip->wakeup, chip->base + JZ_REG_GPIO_MASK_CLEAR);
|
||||
}
|
||||
|
||||
static int jz4740_gpio_suspend(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); i++)
|
||||
jz4740_gpio_suspend_chip(&jz4740_gpio_chips[i]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int jz4740_gpio_resume(struct sys_device *dev)
|
||||
static void jz4740_gpio_resume_chip(struct jz_gpio_chip *chip)
|
||||
{
|
||||
struct jz_gpio_chip *chip = sysdev_to_chip(dev);
|
||||
uint32_t mask = chip->suspend_mask;
|
||||
|
||||
writel(~mask, chip->base + JZ_REG_GPIO_MASK_CLEAR);
|
||||
writel(mask, chip->base + JZ_REG_GPIO_MASK_SET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct sysdev_class jz4740_gpio_sysdev_class = {
|
||||
.name = "gpio",
|
||||
static void jz4740_gpio_resume(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = ARRAY_SIZE(jz4740_gpio_chips) - 1; i >= 0 ; i--)
|
||||
jz4740_gpio_resume_chip(&jz4740_gpio_chips[i]);
|
||||
}
|
||||
|
||||
static struct syscore_ops jz4740_gpio_syscore_ops = {
|
||||
.suspend = jz4740_gpio_suspend,
|
||||
.resume = jz4740_gpio_resume,
|
||||
};
|
||||
|
||||
static int jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
|
||||
static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
|
||||
{
|
||||
int ret, irq;
|
||||
|
||||
chip->sysdev.id = id;
|
||||
chip->sysdev.cls = &jz4740_gpio_sysdev_class;
|
||||
ret = sysdev_register(&chip->sysdev);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
int irq;
|
||||
|
||||
spin_lock_init(&chip->lock);
|
||||
|
||||
@@ -519,22 +516,17 @@ static int jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id)
|
||||
irq_set_chip_and_handler(irq, &jz_gpio_irq_chip,
|
||||
handle_level_irq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init jz4740_gpio_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
ret = sysdev_class_register(&jz4740_gpio_sysdev_class);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(jz4740_gpio_chips); ++i)
|
||||
jz4740_gpio_chip_init(&jz4740_gpio_chips[i], i);
|
||||
|
||||
register_syscore_ops(&jz4740_gpio_syscore_ops);
|
||||
|
||||
printk(KERN_INFO "JZ4740 GPIO initialized\n");
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -259,10 +259,10 @@ static __inline__ int atomic_add_unless(atomic_t *v, int a, int u)
|
||||
|
||||
#define ATOMIC64_INIT(i) ((atomic64_t) { (i) })
|
||||
|
||||
static __inline__ int
|
||||
static __inline__ s64
|
||||
__atomic64_add_return(s64 i, atomic64_t *v)
|
||||
{
|
||||
int ret;
|
||||
s64 ret;
|
||||
unsigned long flags;
|
||||
_atomic_spin_lock_irqsave(v, flags);
|
||||
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
|
||||
#include <linux/futex.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
static inline int
|
||||
futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
||||
{
|
||||
unsigned long int flags;
|
||||
u32 val;
|
||||
int op = (encoded_op >> 28) & 7;
|
||||
int cmp = (encoded_op >> 24) & 15;
|
||||
int oparg = (encoded_op << 8) >> 20;
|
||||
@@ -18,21 +21,58 @@ futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
|
||||
if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
|
||||
oparg = 1 << oparg;
|
||||
|
||||
if (! access_ok (VERIFY_WRITE, uaddr, sizeof(u32)))
|
||||
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(*uaddr)))
|
||||
return -EFAULT;
|
||||
|
||||
pagefault_disable();
|
||||
|
||||
_atomic_spin_lock_irqsave(uaddr, flags);
|
||||
|
||||
switch (op) {
|
||||
case FUTEX_OP_SET:
|
||||
/* *(int *)UADDR2 = OPARG; */
|
||||
ret = get_user(oldval, uaddr);
|
||||
if (!ret)
|
||||
ret = put_user(oparg, uaddr);
|
||||
break;
|
||||
case FUTEX_OP_ADD:
|
||||
/* *(int *)UADDR2 += OPARG; */
|
||||
ret = get_user(oldval, uaddr);
|
||||
if (!ret) {
|
||||
val = oldval + oparg;
|
||||
ret = put_user(val, uaddr);
|
||||
}
|
||||
break;
|
||||
case FUTEX_OP_OR:
|
||||
/* *(int *)UADDR2 |= OPARG; */
|
||||
ret = get_user(oldval, uaddr);
|
||||
if (!ret) {
|
||||
val = oldval | oparg;
|
||||
ret = put_user(val, uaddr);
|
||||
}
|
||||
break;
|
||||
case FUTEX_OP_ANDN:
|
||||
/* *(int *)UADDR2 &= ~OPARG; */
|
||||
ret = get_user(oldval, uaddr);
|
||||
if (!ret) {
|
||||
val = oldval & ~oparg;
|
||||
ret = put_user(val, uaddr);
|
||||
}
|
||||
break;
|
||||
case FUTEX_OP_XOR:
|
||||
/* *(int *)UADDR2 ^= OPARG; */
|
||||
ret = get_user(oldval, uaddr);
|
||||
if (!ret) {
|
||||
val = oldval ^ oparg;
|
||||
ret = put_user(val, uaddr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
|
||||
_atomic_spin_unlock_irqrestore(uaddr, flags);
|
||||
|
||||
pagefault_enable();
|
||||
|
||||
if (!ret) {
|
||||
@@ -54,7 +94,9 @@ static inline int
|
||||
futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
|
||||
u32 oldval, u32 newval)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
unsigned long flags;
|
||||
|
||||
/* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
|
||||
* our gateway page, and causes no end of trouble...
|
||||
@@ -65,12 +107,24 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
|
||||
if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
|
||||
return -EFAULT;
|
||||
|
||||
if (get_user(val, uaddr))
|
||||
return -EFAULT;
|
||||
if (val == oldval && put_user(newval, uaddr))
|
||||
return -EFAULT;
|
||||
/* HPPA has no cmpxchg in hardware and therefore the
|
||||
* best we can do here is use an array of locks. The
|
||||
* lock selected is based on a hash of the userspace
|
||||
* address. This should scale to a couple of CPUs.
|
||||
*/
|
||||
|
||||
_atomic_spin_lock_irqsave(uaddr, flags);
|
||||
|
||||
ret = get_user(val, uaddr);
|
||||
|
||||
if (!ret && val == oldval)
|
||||
ret = put_user(newval, uaddr);
|
||||
|
||||
*uval = val;
|
||||
return 0;
|
||||
|
||||
_atomic_spin_unlock_irqrestore(uaddr, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /*__KERNEL__*/
|
||||
|
||||
@@ -821,8 +821,9 @@
|
||||
#define __NR_open_by_handle_at (__NR_Linux + 326)
|
||||
#define __NR_syncfs (__NR_Linux + 327)
|
||||
#define __NR_setns (__NR_Linux + 328)
|
||||
#define __NR_sendmmsg (__NR_Linux + 329)
|
||||
|
||||
#define __NR_Linux_syscalls (__NR_setns + 1)
|
||||
#define __NR_Linux_syscalls (__NR_sendmmsg + 1)
|
||||
|
||||
|
||||
#define __IGNORE_select /* newselect */
|
||||
|
||||
@@ -427,6 +427,7 @@
|
||||
ENTRY_COMP(open_by_handle_at)
|
||||
ENTRY_SAME(syncfs)
|
||||
ENTRY_SAME(setns)
|
||||
ENTRY_COMP(sendmmsg)
|
||||
|
||||
/* Nothing yet */
|
||||
|
||||
|
||||
@@ -1020,7 +1020,7 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align)
|
||||
}
|
||||
if (addr == 0)
|
||||
return 0;
|
||||
RELOC(alloc_bottom) = addr;
|
||||
RELOC(alloc_bottom) = addr + size;
|
||||
|
||||
prom_debug(" -> %x\n", addr);
|
||||
prom_debug(" alloc_bottom : %x\n", RELOC(alloc_bottom));
|
||||
@@ -1834,7 +1834,7 @@ static void __init *make_room(unsigned long *mem_start, unsigned long *mem_end,
|
||||
chunk = alloc_up(room, 0);
|
||||
if (chunk == 0)
|
||||
prom_panic("No memory for flatten_device_tree (claim failed)");
|
||||
*mem_end = RELOC(alloc_top);
|
||||
*mem_end = chunk + room;
|
||||
}
|
||||
|
||||
ret = (void *)*mem_start;
|
||||
@@ -2053,7 +2053,7 @@ static void __init flatten_device_tree(void)
|
||||
mem_start = (unsigned long)alloc_up(room, PAGE_SIZE);
|
||||
if (mem_start == 0)
|
||||
prom_panic("Can't allocate initial device-tree chunk\n");
|
||||
mem_end = RELOC(alloc_top);
|
||||
mem_end = mem_start + room;
|
||||
|
||||
/* Get root of tree */
|
||||
root = call_prom("peer", 1, 1, (phandle)0);
|
||||
|
||||
@@ -181,7 +181,7 @@ static void dtl_stop(struct dtl *dtl)
|
||||
|
||||
lppaca_of(dtl->cpu).dtl_enable_mask = 0x0;
|
||||
|
||||
unregister_dtl(hwcpu, __pa(dtl->buf));
|
||||
unregister_dtl(hwcpu);
|
||||
}
|
||||
|
||||
static u64 dtl_current_index(struct dtl *dtl)
|
||||
|
||||
@@ -26,6 +26,17 @@ static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
|
||||
/* Don't risk a hypervisor call if we're crashing */
|
||||
if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) {
|
||||
unsigned long addr;
|
||||
int ret;
|
||||
|
||||
if (get_lppaca()->dtl_enable_mask) {
|
||||
ret = unregister_dtl(hard_smp_processor_id());
|
||||
if (ret) {
|
||||
pr_err("WARNING: DTL deregistration for cpu "
|
||||
"%d (hw %d) failed with %d\n",
|
||||
smp_processor_id(),
|
||||
hard_smp_processor_id(), ret);
|
||||
}
|
||||
}
|
||||
|
||||
addr = __pa(get_slb_shadow());
|
||||
if (unregister_slb_shadow(hard_smp_processor_id(), addr))
|
||||
|
||||
@@ -395,7 +395,7 @@ static void pSeries_lpar_hptab_clear(void)
|
||||
unsigned long ptel;
|
||||
} ptes[4];
|
||||
long lpar_rc;
|
||||
int i, j;
|
||||
unsigned long i, j;
|
||||
|
||||
/* Read in batches of 4,
|
||||
* invalidate only valid entries not in the VRMA
|
||||
|
||||
@@ -73,9 +73,9 @@ static inline long register_slb_shadow(unsigned long cpu, unsigned long vpa)
|
||||
return vpa_call(0x3, cpu, vpa);
|
||||
}
|
||||
|
||||
static inline long unregister_dtl(unsigned long cpu, unsigned long vpa)
|
||||
static inline long unregister_dtl(unsigned long cpu)
|
||||
{
|
||||
return vpa_call(0x6, cpu, vpa);
|
||||
return vpa_call(0x6, cpu, 0);
|
||||
}
|
||||
|
||||
static inline long register_dtl(unsigned long cpu, unsigned long vpa)
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#define ODSR_CLEAR 0x1c00
|
||||
#define LTLEECSR_ENABLE_ALL 0xFFC000FC
|
||||
#define ESCSR_CLEAR 0x07120204
|
||||
#define IECSR_CLEAR 0x80000000
|
||||
|
||||
#define RIO_PORT1_EDCSR 0x0640
|
||||
#define RIO_PORT2_EDCSR 0x0680
|
||||
@@ -1089,11 +1090,11 @@ static void port_error_handler(struct rio_mport *port, int offset)
|
||||
|
||||
if (offset == 0) {
|
||||
out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0);
|
||||
out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), 0);
|
||||
out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), IECSR_CLEAR);
|
||||
out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR);
|
||||
} else {
|
||||
out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0);
|
||||
out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), 0);
|
||||
out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), IECSR_CLEAR);
|
||||
out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ config SPARC64
|
||||
select HAVE_PERF_EVENTS
|
||||
select PERF_USE_VMALLOC
|
||||
select IRQ_PREFLOW_FASTEOI
|
||||
select HAVE_C_RECORDMCOUNT
|
||||
|
||||
config ARCH_DEFCONFIG
|
||||
string
|
||||
|
||||
@@ -26,61 +26,28 @@ extern void change_bit(unsigned long nr, volatile unsigned long *addr);
|
||||
#define smp_mb__before_clear_bit() barrier()
|
||||
#define smp_mb__after_clear_bit() barrier()
|
||||
|
||||
#include <asm-generic/bitops/ffz.h>
|
||||
#include <asm-generic/bitops/__ffs.h>
|
||||
#include <asm-generic/bitops/fls.h>
|
||||
#include <asm-generic/bitops/__fls.h>
|
||||
#include <asm-generic/bitops/fls64.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
extern int ffs(int x);
|
||||
extern unsigned long __ffs(unsigned long);
|
||||
|
||||
#include <asm-generic/bitops/ffz.h>
|
||||
#include <asm-generic/bitops/sched.h>
|
||||
#include <asm-generic/bitops/ffs.h>
|
||||
|
||||
/*
|
||||
* hweightN: returns the hamming weight (i.e. the number
|
||||
* of bits set) of a N-bit word
|
||||
*/
|
||||
|
||||
#ifdef ULTRA_HAS_POPULATION_COUNT
|
||||
extern unsigned long __arch_hweight64(__u64 w);
|
||||
extern unsigned int __arch_hweight32(unsigned int w);
|
||||
extern unsigned int __arch_hweight16(unsigned int w);
|
||||
extern unsigned int __arch_hweight8(unsigned int w);
|
||||
|
||||
static inline unsigned int __arch_hweight64(unsigned long w)
|
||||
{
|
||||
unsigned int res;
|
||||
|
||||
__asm__ ("popc %1,%0" : "=r" (res) : "r" (w));
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline unsigned int __arch_hweight32(unsigned int w)
|
||||
{
|
||||
unsigned int res;
|
||||
|
||||
__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffffffff));
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline unsigned int __arch_hweight16(unsigned int w)
|
||||
{
|
||||
unsigned int res;
|
||||
|
||||
__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xffff));
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline unsigned int __arch_hweight8(unsigned int w)
|
||||
{
|
||||
unsigned int res;
|
||||
|
||||
__asm__ ("popc %1,%0" : "=r" (res) : "r" (w & 0xff));
|
||||
return res;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <asm-generic/bitops/arch_hweight.h>
|
||||
|
||||
#endif
|
||||
#include <asm-generic/bitops/const_hweight.h>
|
||||
#include <asm-generic/bitops/lock.h>
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
@@ -59,15 +59,33 @@
|
||||
#define R_SPARC_6 45
|
||||
|
||||
/* Bits present in AT_HWCAP, primarily for Sparc32. */
|
||||
#define HWCAP_SPARC_FLUSH 0x00000001
|
||||
#define HWCAP_SPARC_STBAR 0x00000002
|
||||
#define HWCAP_SPARC_SWAP 0x00000004
|
||||
#define HWCAP_SPARC_MULDIV 0x00000008
|
||||
#define HWCAP_SPARC_V9 0x00000010
|
||||
#define HWCAP_SPARC_ULTRA3 0x00000020
|
||||
#define HWCAP_SPARC_BLKINIT 0x00000040
|
||||
#define HWCAP_SPARC_N2 0x00000080
|
||||
|
||||
#define HWCAP_SPARC_FLUSH 1 /* CPU supports flush instruction. */
|
||||
#define HWCAP_SPARC_STBAR 2
|
||||
#define HWCAP_SPARC_SWAP 4
|
||||
#define HWCAP_SPARC_MULDIV 8
|
||||
#define HWCAP_SPARC_V9 16
|
||||
#define HWCAP_SPARC_ULTRA3 32
|
||||
#define HWCAP_SPARC_BLKINIT 64
|
||||
#define HWCAP_SPARC_N2 128
|
||||
/* Solaris compatible AT_HWCAP bits. */
|
||||
#define AV_SPARC_MUL32 0x00000100 /* 32x32 multiply is efficient */
|
||||
#define AV_SPARC_DIV32 0x00000200 /* 32x32 divide is efficient */
|
||||
#define AV_SPARC_FSMULD 0x00000400 /* 'fsmuld' is efficient */
|
||||
#define AV_SPARC_V8PLUS 0x00000800 /* v9 insn available to 32bit */
|
||||
#define AV_SPARC_POPC 0x00001000 /* 'popc' is efficient */
|
||||
#define AV_SPARC_VIS 0x00002000 /* VIS insns available */
|
||||
#define AV_SPARC_VIS2 0x00004000 /* VIS2 insns available */
|
||||
#define AV_SPARC_ASI_BLK_INIT 0x00008000 /* block init ASIs available */
|
||||
#define AV_SPARC_FMAF 0x00010000 /* fused multiply-add */
|
||||
#define AV_SPARC_VIS3 0x00020000 /* VIS3 insns available */
|
||||
#define AV_SPARC_HPC 0x00040000 /* HPC insns available */
|
||||
#define AV_SPARC_RANDOM 0x00080000 /* 'random' insn available */
|
||||
#define AV_SPARC_TRANS 0x00100000 /* transaction insns available */
|
||||
#define AV_SPARC_FJFMAU 0x00200000 /* unfused multiply-add */
|
||||
#define AV_SPARC_IMA 0x00400000 /* integer multiply-add */
|
||||
#define AV_SPARC_ASI_CACHE_SPARING \
|
||||
0x00800000 /* cache sparing ASIs available */
|
||||
|
||||
#define CORE_DUMP_USE_REGSET
|
||||
|
||||
@@ -162,31 +180,8 @@ typedef struct {
|
||||
#define ELF_ET_DYN_BASE 0x0000010000000000UL
|
||||
#define COMPAT_ELF_ET_DYN_BASE 0x0000000070000000UL
|
||||
|
||||
|
||||
/* This yields a mask that user programs can use to figure out what
|
||||
instruction set this cpu supports. */
|
||||
|
||||
/* On Ultra, we support all of the v8 capabilities. */
|
||||
static inline unsigned int sparc64_elf_hwcap(void)
|
||||
{
|
||||
unsigned int cap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
|
||||
HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV |
|
||||
HWCAP_SPARC_V9);
|
||||
|
||||
if (tlb_type == cheetah || tlb_type == cheetah_plus)
|
||||
cap |= HWCAP_SPARC_ULTRA3;
|
||||
else if (tlb_type == hypervisor) {
|
||||
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 ||
|
||||
sun4v_chip_type == SUN4V_CHIP_NIAGARA2)
|
||||
cap |= HWCAP_SPARC_BLKINIT;
|
||||
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2)
|
||||
cap |= HWCAP_SPARC_N2;
|
||||
}
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
#define ELF_HWCAP sparc64_elf_hwcap();
|
||||
extern unsigned long sparc64_elf_hwcap;
|
||||
#define ELF_HWCAP sparc64_elf_hwcap
|
||||
|
||||
/* This yields a string that ld.so will use to load implementation
|
||||
specific libraries for optimization. This is more specific in
|
||||
|
||||
@@ -2927,6 +2927,13 @@ extern unsigned long sun4v_ncs_request(unsigned long request,
|
||||
#define HV_FAST_FIRE_GET_PERFREG 0x120
|
||||
#define HV_FAST_FIRE_SET_PERFREG 0x121
|
||||
|
||||
#define HV_FAST_REBOOT_DATA_SET 0x172
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
extern unsigned long sun4v_reboot_data_set(unsigned long ra,
|
||||
unsigned long len);
|
||||
#endif
|
||||
|
||||
/* Function numbers for HV_CORE_TRAP. */
|
||||
#define HV_CORE_SET_VER 0x00
|
||||
#define HV_CORE_PUTCHAR 0x01
|
||||
@@ -2940,16 +2947,23 @@ extern unsigned long sun4v_ncs_request(unsigned long request,
|
||||
#define HV_GRP_CORE 0x0001
|
||||
#define HV_GRP_INTR 0x0002
|
||||
#define HV_GRP_SOFT_STATE 0x0003
|
||||
#define HV_GRP_TM 0x0080
|
||||
#define HV_GRP_PCI 0x0100
|
||||
#define HV_GRP_LDOM 0x0101
|
||||
#define HV_GRP_SVC_CHAN 0x0102
|
||||
#define HV_GRP_NCS 0x0103
|
||||
#define HV_GRP_RNG 0x0104
|
||||
#define HV_GRP_PBOOT 0x0105
|
||||
#define HV_GRP_TPM 0x0107
|
||||
#define HV_GRP_SDIO 0x0108
|
||||
#define HV_GRP_SDIO_ERR 0x0109
|
||||
#define HV_GRP_REBOOT_DATA 0x0110
|
||||
#define HV_GRP_NIAG_PERF 0x0200
|
||||
#define HV_GRP_FIRE_PERF 0x0201
|
||||
#define HV_GRP_N2_CPU 0x0202
|
||||
#define HV_GRP_NIU 0x0204
|
||||
#define HV_GRP_VF_CPU 0x0205
|
||||
#define HV_GRP_KT_CPU 0x0209
|
||||
#define HV_GRP_DIAG 0x0300
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
@@ -45,6 +45,19 @@ typedef struct {
|
||||
int si_mask;
|
||||
} __siginfo32_t;
|
||||
|
||||
#define __SIGC_MAXWIN 7
|
||||
|
||||
typedef struct {
|
||||
unsigned long locals[8];
|
||||
unsigned long ins[8];
|
||||
} __siginfo_reg_window;
|
||||
|
||||
typedef struct {
|
||||
int wsaved;
|
||||
__siginfo_reg_window reg_window[__SIGC_MAXWIN];
|
||||
unsigned long rwbuf_stkptrs[__SIGC_MAXWIN];
|
||||
} __siginfo_rwin_t;
|
||||
|
||||
#ifdef CONFIG_SPARC64
|
||||
typedef struct {
|
||||
unsigned int si_float_regs [64];
|
||||
@@ -73,6 +86,7 @@ struct sigcontext {
|
||||
unsigned long ss_size;
|
||||
} sigc_stack;
|
||||
unsigned long sigc_mask;
|
||||
__siginfo_rwin_t * sigc_rwin_save;
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
@@ -131,6 +131,15 @@ static inline void arch_write_lock(arch_rwlock_t *rw)
|
||||
*(volatile __u32 *)&lp->lock = ~0U;
|
||||
}
|
||||
|
||||
static void inline arch_write_unlock(arch_rwlock_t *lock)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
" st %%g0, [%0]"
|
||||
: /* no outputs */
|
||||
: "r" (lock)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static inline int arch_write_trylock(arch_rwlock_t *rw)
|
||||
{
|
||||
unsigned int val;
|
||||
@@ -175,8 +184,6 @@ static inline int __arch_read_trylock(arch_rwlock_t *rw)
|
||||
res; \
|
||||
})
|
||||
|
||||
#define arch_write_unlock(rw) do { (rw)->lock = 0; } while(0)
|
||||
|
||||
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
|
||||
#define arch_read_lock_flags(rw, flags) arch_read_lock(rw)
|
||||
#define arch_write_lock_flags(rw, flags) arch_write_lock(rw)
|
||||
|
||||
@@ -210,14 +210,8 @@ static int inline arch_write_trylock(arch_rwlock_t *lock)
|
||||
return result;
|
||||
}
|
||||
|
||||
#define arch_read_lock(p) arch_read_lock(p)
|
||||
#define arch_read_lock_flags(p, f) arch_read_lock(p)
|
||||
#define arch_read_trylock(p) arch_read_trylock(p)
|
||||
#define arch_read_unlock(p) arch_read_unlock(p)
|
||||
#define arch_write_lock(p) arch_write_lock(p)
|
||||
#define arch_write_lock_flags(p, f) arch_write_lock(p)
|
||||
#define arch_write_unlock(p) arch_write_unlock(p)
|
||||
#define arch_write_trylock(p) arch_write_trylock(p)
|
||||
|
||||
#define arch_read_can_lock(rw) (!((rw)->lock & 0x80000000UL))
|
||||
#define arch_write_can_lock(rw) (!(rw)->lock)
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#define SUN4V_CHIP_INVALID 0x00
|
||||
#define SUN4V_CHIP_NIAGARA1 0x01
|
||||
#define SUN4V_CHIP_NIAGARA2 0x02
|
||||
#define SUN4V_CHIP_NIAGARA3 0x03
|
||||
#define SUN4V_CHIP_UNKNOWN 0xff
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
@@ -133,29 +133,6 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
|
||||
sub TSB, 0x8, TSB; \
|
||||
TSB_STORE(TSB, TAG);
|
||||
|
||||
#define KTSB_LOAD_QUAD(TSB, REG) \
|
||||
ldda [TSB] ASI_NUCLEUS_QUAD_LDD, REG;
|
||||
|
||||
#define KTSB_STORE(ADDR, VAL) \
|
||||
stxa VAL, [ADDR] ASI_N;
|
||||
|
||||
#define KTSB_LOCK_TAG(TSB, REG1, REG2) \
|
||||
99: lduwa [TSB] ASI_N, REG1; \
|
||||
sethi %hi(TSB_TAG_LOCK_HIGH), REG2;\
|
||||
andcc REG1, REG2, %g0; \
|
||||
bne,pn %icc, 99b; \
|
||||
nop; \
|
||||
casa [TSB] ASI_N, REG1, REG2;\
|
||||
cmp REG1, REG2; \
|
||||
bne,pn %icc, 99b; \
|
||||
nop; \
|
||||
|
||||
#define KTSB_WRITE(TSB, TTE, TAG) \
|
||||
add TSB, 0x8, TSB; \
|
||||
stxa TTE, [TSB] ASI_N; \
|
||||
sub TSB, 0x8, TSB; \
|
||||
stxa TAG, [TSB] ASI_N;
|
||||
|
||||
/* Do a kernel page table walk. Leaves physical PTE pointer in
|
||||
* REG1. Jumps to FAIL_LABEL on early page table walk termination.
|
||||
* VADDR will not be clobbered, but REG2 will.
|
||||
@@ -239,6 +216,8 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
|
||||
(KERNEL_TSB_SIZE_BYTES / 16)
|
||||
#define KERNEL_TSB4M_NENTRIES 4096
|
||||
|
||||
#define KTSB_PHYS_SHIFT 15
|
||||
|
||||
/* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL
|
||||
* on TSB hit. REG1, REG2, REG3, and REG4 are used as temporaries
|
||||
* and the found TTE will be left in REG1. REG3 and REG4 must
|
||||
@@ -247,13 +226,22 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
|
||||
* VADDR and TAG will be preserved and not clobbered by this macro.
|
||||
*/
|
||||
#define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
|
||||
sethi %hi(swapper_tsb), REG1; \
|
||||
661: sethi %hi(swapper_tsb), REG1; \
|
||||
or REG1, %lo(swapper_tsb), REG1; \
|
||||
.section .swapper_tsb_phys_patch, "ax"; \
|
||||
.word 661b; \
|
||||
.previous; \
|
||||
661: nop; \
|
||||
.section .tsb_ldquad_phys_patch, "ax"; \
|
||||
.word 661b; \
|
||||
sllx REG1, KTSB_PHYS_SHIFT, REG1; \
|
||||
sllx REG1, KTSB_PHYS_SHIFT, REG1; \
|
||||
.previous; \
|
||||
srlx VADDR, PAGE_SHIFT, REG2; \
|
||||
and REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \
|
||||
sllx REG2, 4, REG2; \
|
||||
add REG1, REG2, REG2; \
|
||||
KTSB_LOAD_QUAD(REG2, REG3); \
|
||||
TSB_LOAD_QUAD(REG2, REG3); \
|
||||
cmp REG3, TAG; \
|
||||
be,a,pt %xcc, OK_LABEL; \
|
||||
mov REG4, REG1;
|
||||
@@ -263,12 +251,21 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
|
||||
* we can make use of that for the index computation.
|
||||
*/
|
||||
#define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
|
||||
sethi %hi(swapper_4m_tsb), REG1; \
|
||||
661: sethi %hi(swapper_4m_tsb), REG1; \
|
||||
or REG1, %lo(swapper_4m_tsb), REG1; \
|
||||
.section .swapper_4m_tsb_phys_patch, "ax"; \
|
||||
.word 661b; \
|
||||
.previous; \
|
||||
661: nop; \
|
||||
.section .tsb_ldquad_phys_patch, "ax"; \
|
||||
.word 661b; \
|
||||
sllx REG1, KTSB_PHYS_SHIFT, REG1; \
|
||||
sllx REG1, KTSB_PHYS_SHIFT, REG1; \
|
||||
.previous; \
|
||||
and TAG, (KERNEL_TSB4M_NENTRIES - 1), REG2; \
|
||||
sllx REG2, 4, REG2; \
|
||||
add REG1, REG2, REG2; \
|
||||
KTSB_LOAD_QUAD(REG2, REG3); \
|
||||
TSB_LOAD_QUAD(REG2, REG3); \
|
||||
cmp REG3, TAG; \
|
||||
be,a,pt %xcc, OK_LABEL; \
|
||||
mov REG4, REG1;
|
||||
|
||||
@@ -65,6 +65,7 @@ static struct xor_block_template xor_block_niagara = {
|
||||
#define XOR_SELECT_TEMPLATE(FASTEST) \
|
||||
((tlb_type == hypervisor && \
|
||||
(sun4v_chip_type == SUN4V_CHIP_NIAGARA1 || \
|
||||
sun4v_chip_type == SUN4V_CHIP_NIAGARA2)) ? \
|
||||
sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || \
|
||||
sun4v_chip_type == SUN4V_CHIP_NIAGARA3)) ? \
|
||||
&xor_block_niagara : \
|
||||
&xor_block_VIS)
|
||||
|
||||
@@ -32,6 +32,7 @@ obj-$(CONFIG_SPARC32) += sun4m_irq.o sun4c_irq.o sun4d_irq.o
|
||||
|
||||
obj-y += process_$(BITS).o
|
||||
obj-y += signal_$(BITS).o
|
||||
obj-y += sigutil_$(BITS).o
|
||||
obj-$(CONFIG_SPARC32) += ioport.o
|
||||
obj-y += setup_$(BITS).o
|
||||
obj-y += idprom.o
|
||||
|
||||
@@ -396,6 +396,7 @@ static int show_cpuinfo(struct seq_file *m, void *__unused)
|
||||
, cpu_data(0).clock_tick
|
||||
#endif
|
||||
);
|
||||
cpucap_info(m);
|
||||
#ifdef CONFIG_SMP
|
||||
smp_bogo(m);
|
||||
#endif
|
||||
@@ -474,11 +475,18 @@ static void __init sun4v_cpu_probe(void)
|
||||
sparc_pmu_type = "niagara2";
|
||||
break;
|
||||
|
||||
case SUN4V_CHIP_NIAGARA3:
|
||||
sparc_cpu_type = "UltraSparc T3 (Niagara3)";
|
||||
sparc_fpu_type = "UltraSparc T3 integrated FPU";
|
||||
sparc_pmu_type = "niagara3";
|
||||
break;
|
||||
|
||||
default:
|
||||
printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",
|
||||
prom_cpu_compatible);
|
||||
sparc_cpu_type = "Unknown SUN4V CPU";
|
||||
sparc_fpu_type = "Unknown SUN4V FPU";
|
||||
sparc_pmu_type = "Unknown SUN4V PMU";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,6 +324,7 @@ static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index)
|
||||
switch (sun4v_chip_type) {
|
||||
case SUN4V_CHIP_NIAGARA1:
|
||||
case SUN4V_CHIP_NIAGARA2:
|
||||
case SUN4V_CHIP_NIAGARA3:
|
||||
rover_inc_table = niagara_iterate_method;
|
||||
break;
|
||||
default:
|
||||
|
||||
+29
-2
@@ -15,12 +15,15 @@
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/cpu.h>
|
||||
|
||||
#include <asm/hypervisor.h>
|
||||
#include <asm/ldc.h>
|
||||
#include <asm/vio.h>
|
||||
#include <asm/mdesc.h>
|
||||
#include <asm/head.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
#include "kernel.h"
|
||||
|
||||
#define DRV_MODULE_NAME "ds"
|
||||
#define PFX DRV_MODULE_NAME ": "
|
||||
#define DRV_MODULE_VERSION "1.0"
|
||||
@@ -828,18 +831,32 @@ void ldom_set_var(const char *var, const char *value)
|
||||
}
|
||||
}
|
||||
|
||||
static char full_boot_str[256] __attribute__((aligned(32)));
|
||||
static int reboot_data_supported;
|
||||
|
||||
void ldom_reboot(const char *boot_command)
|
||||
{
|
||||
/* Don't bother with any of this if the boot_command
|
||||
* is empty.
|
||||
*/
|
||||
if (boot_command && strlen(boot_command)) {
|
||||
char full_boot_str[256];
|
||||
unsigned long len;
|
||||
|
||||
strcpy(full_boot_str, "boot ");
|
||||
strcpy(full_boot_str + strlen("boot "), boot_command);
|
||||
len = strlen(full_boot_str);
|
||||
|
||||
ldom_set_var("reboot-command", full_boot_str);
|
||||
if (reboot_data_supported) {
|
||||
unsigned long ra = kimage_addr_to_ra(full_boot_str);
|
||||
unsigned long hv_ret;
|
||||
|
||||
hv_ret = sun4v_reboot_data_set(ra, len);
|
||||
if (hv_ret != HV_EOK)
|
||||
pr_err("SUN4V: Unable to set reboot data "
|
||||
"hv_ret=%lu\n", hv_ret);
|
||||
} else {
|
||||
ldom_set_var("reboot-command", full_boot_str);
|
||||
}
|
||||
}
|
||||
sun4v_mach_sir();
|
||||
}
|
||||
@@ -1237,6 +1254,16 @@ static struct vio_driver ds_driver = {
|
||||
|
||||
static int __init ds_init(void)
|
||||
{
|
||||
unsigned long hv_ret, major, minor;
|
||||
|
||||
if (tlb_type == hypervisor) {
|
||||
hv_ret = sun4v_get_version(HV_GRP_REBOOT_DATA, &major, &minor);
|
||||
if (hv_ret == HV_EOK) {
|
||||
pr_info("SUN4V: Reboot data supported (maj=%lu,min=%lu).\n",
|
||||
major, minor);
|
||||
reboot_data_supported = 1;
|
||||
}
|
||||
}
|
||||
kthread_run(ds_thread, NULL, "kldomd");
|
||||
|
||||
return vio_register_driver(&ds_driver);
|
||||
|
||||
@@ -42,6 +42,20 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
|
||||
extern void fpload(unsigned long *fpregs, unsigned long *fsr);
|
||||
|
||||
#else /* CONFIG_SPARC32 */
|
||||
struct popc_3insn_patch_entry {
|
||||
unsigned int addr;
|
||||
unsigned int insns[3];
|
||||
};
|
||||
extern struct popc_3insn_patch_entry __popc_3insn_patch,
|
||||
__popc_3insn_patch_end;
|
||||
|
||||
struct popc_6insn_patch_entry {
|
||||
unsigned int addr;
|
||||
unsigned int insns[6];
|
||||
};
|
||||
extern struct popc_6insn_patch_entry __popc_6insn_patch,
|
||||
__popc_6insn_patch_end;
|
||||
|
||||
extern void __init per_cpu_patch(void);
|
||||
extern void __init sun4v_patch(void);
|
||||
extern void __init boot_cpu_id_too_large(int cpu);
|
||||
|
||||
@@ -132,6 +132,8 @@ prom_sun4v_name:
|
||||
.asciz "sun4v"
|
||||
prom_niagara_prefix:
|
||||
.asciz "SUNW,UltraSPARC-T"
|
||||
prom_sparc_prefix:
|
||||
.asciz "SPARC-T"
|
||||
.align 4
|
||||
prom_root_compatible:
|
||||
.skip 64
|
||||
@@ -379,6 +381,22 @@ sun4v_chip_type:
|
||||
sethi %hi(prom_niagara_prefix), %g7
|
||||
or %g7, %lo(prom_niagara_prefix), %g7
|
||||
mov 17, %g3
|
||||
90: ldub [%g7], %g2
|
||||
ldub [%g1], %g4
|
||||
cmp %g2, %g4
|
||||
bne,pn %icc, 89f
|
||||
add %g7, 1, %g7
|
||||
subcc %g3, 1, %g3
|
||||
bne,pt %xcc, 90b
|
||||
add %g1, 1, %g1
|
||||
ba,pt %xcc, 91f
|
||||
nop
|
||||
|
||||
89: sethi %hi(prom_cpu_compatible), %g1
|
||||
or %g1, %lo(prom_cpu_compatible), %g1
|
||||
sethi %hi(prom_sparc_prefix), %g7
|
||||
or %g7, %lo(prom_sparc_prefix), %g7
|
||||
mov 7, %g3
|
||||
90: ldub [%g7], %g2
|
||||
ldub [%g1], %g4
|
||||
cmp %g2, %g4
|
||||
@@ -389,6 +407,15 @@ sun4v_chip_type:
|
||||
add %g1, 1, %g1
|
||||
|
||||
sethi %hi(prom_cpu_compatible), %g1
|
||||
or %g1, %lo(prom_cpu_compatible), %g1
|
||||
ldub [%g1 + 7], %g2
|
||||
cmp %g2, '3'
|
||||
be,pt %xcc, 5f
|
||||
mov SUN4V_CHIP_NIAGARA3, %g4
|
||||
ba,pt %xcc, 4f
|
||||
nop
|
||||
|
||||
91: sethi %hi(prom_cpu_compatible), %g1
|
||||
or %g1, %lo(prom_cpu_compatible), %g1
|
||||
ldub [%g1 + 17], %g2
|
||||
cmp %g2, '1'
|
||||
@@ -397,6 +424,7 @@ sun4v_chip_type:
|
||||
cmp %g2, '2'
|
||||
be,pt %xcc, 5f
|
||||
mov SUN4V_CHIP_NIAGARA2, %g4
|
||||
|
||||
4:
|
||||
mov SUN4V_CHIP_UNKNOWN, %g4
|
||||
5: sethi %hi(sun4v_chip_type), %g2
|
||||
@@ -514,6 +542,9 @@ niagara_tlb_fixup:
|
||||
cmp %g1, SUN4V_CHIP_NIAGARA2
|
||||
be,pt %xcc, niagara2_patch
|
||||
nop
|
||||
cmp %g1, SUN4V_CHIP_NIAGARA3
|
||||
be,pt %xcc, niagara2_patch
|
||||
nop
|
||||
|
||||
call generic_patch_copyops
|
||||
nop
|
||||
@@ -528,7 +559,7 @@ niagara2_patch:
|
||||
nop
|
||||
call niagara_patch_bzero
|
||||
nop
|
||||
call niagara2_patch_pageops
|
||||
call niagara_patch_pageops
|
||||
nop
|
||||
|
||||
ba,a,pt %xcc, 80f
|
||||
|
||||
@@ -28,16 +28,23 @@ static struct api_info api_table[] = {
|
||||
{ .group = HV_GRP_CORE, .flags = FLAG_PRE_API },
|
||||
{ .group = HV_GRP_INTR, },
|
||||
{ .group = HV_GRP_SOFT_STATE, },
|
||||
{ .group = HV_GRP_TM, },
|
||||
{ .group = HV_GRP_PCI, .flags = FLAG_PRE_API },
|
||||
{ .group = HV_GRP_LDOM, },
|
||||
{ .group = HV_GRP_SVC_CHAN, .flags = FLAG_PRE_API },
|
||||
{ .group = HV_GRP_NCS, .flags = FLAG_PRE_API },
|
||||
{ .group = HV_GRP_RNG, },
|
||||
{ .group = HV_GRP_PBOOT, },
|
||||
{ .group = HV_GRP_TPM, },
|
||||
{ .group = HV_GRP_SDIO, },
|
||||
{ .group = HV_GRP_SDIO_ERR, },
|
||||
{ .group = HV_GRP_REBOOT_DATA, },
|
||||
{ .group = HV_GRP_NIAG_PERF, .flags = FLAG_PRE_API },
|
||||
{ .group = HV_GRP_FIRE_PERF, },
|
||||
{ .group = HV_GRP_N2_CPU, },
|
||||
{ .group = HV_GRP_NIU, },
|
||||
{ .group = HV_GRP_VF_CPU, },
|
||||
{ .group = HV_GRP_KT_CPU, },
|
||||
{ .group = HV_GRP_DIAG, .flags = FLAG_PRE_API },
|
||||
};
|
||||
|
||||
|
||||
@@ -798,3 +798,10 @@ ENTRY(sun4v_niagara2_setperf)
|
||||
retl
|
||||
nop
|
||||
ENDPROC(sun4v_niagara2_setperf)
|
||||
|
||||
ENTRY(sun4v_reboot_data_set)
|
||||
mov HV_FAST_REBOOT_DATA_SET, %o5
|
||||
ta HV_FAST_TRAP
|
||||
retl
|
||||
nop
|
||||
ENDPROC(sun4v_reboot_data_set)
|
||||
|
||||
@@ -88,7 +88,7 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int)
|
||||
#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
|
||||
|
||||
/* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */
|
||||
#define SUN4D_IPI_IRQ 14
|
||||
#define SUN4D_IPI_IRQ 13
|
||||
|
||||
extern void sun4d_ipi_interrupt(void);
|
||||
|
||||
|
||||
@@ -4,12 +4,27 @@
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/traps.h>
|
||||
#include <asm/head.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
/* cpu.c */
|
||||
extern const char *sparc_pmu_type;
|
||||
extern unsigned int fsr_storage;
|
||||
extern int ncpus_probed;
|
||||
|
||||
#ifdef CONFIG_SPARC64
|
||||
/* setup_64.c */
|
||||
struct seq_file;
|
||||
extern void cpucap_info(struct seq_file *);
|
||||
|
||||
static inline unsigned long kimage_addr_to_ra(const char *p)
|
||||
{
|
||||
unsigned long val = (unsigned long) p;
|
||||
|
||||
return kern_base + (val - KERNBASE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SPARC32
|
||||
/* cpu.c */
|
||||
extern void cpu_probe(void);
|
||||
|
||||
+12
-12
@@ -47,16 +47,16 @@ kvmap_itlb_tsb_miss:
|
||||
kvmap_itlb_vmalloc_addr:
|
||||
KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath)
|
||||
|
||||
KTSB_LOCK_TAG(%g1, %g2, %g7)
|
||||
TSB_LOCK_TAG(%g1, %g2, %g7)
|
||||
|
||||
/* Load and check PTE. */
|
||||
ldxa [%g5] ASI_PHYS_USE_EC, %g5
|
||||
mov 1, %g7
|
||||
sllx %g7, TSB_TAG_INVALID_BIT, %g7
|
||||
brgez,a,pn %g5, kvmap_itlb_longpath
|
||||
KTSB_STORE(%g1, %g7)
|
||||
TSB_STORE(%g1, %g7)
|
||||
|
||||
KTSB_WRITE(%g1, %g5, %g6)
|
||||
TSB_WRITE(%g1, %g5, %g6)
|
||||
|
||||
/* fallthrough to TLB load */
|
||||
|
||||
@@ -102,9 +102,9 @@ kvmap_itlb_longpath:
|
||||
kvmap_itlb_obp:
|
||||
OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_itlb_longpath)
|
||||
|
||||
KTSB_LOCK_TAG(%g1, %g2, %g7)
|
||||
TSB_LOCK_TAG(%g1, %g2, %g7)
|
||||
|
||||
KTSB_WRITE(%g1, %g5, %g6)
|
||||
TSB_WRITE(%g1, %g5, %g6)
|
||||
|
||||
ba,pt %xcc, kvmap_itlb_load
|
||||
nop
|
||||
@@ -112,17 +112,17 @@ kvmap_itlb_obp:
|
||||
kvmap_dtlb_obp:
|
||||
OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_dtlb_longpath)
|
||||
|
||||
KTSB_LOCK_TAG(%g1, %g2, %g7)
|
||||
TSB_LOCK_TAG(%g1, %g2, %g7)
|
||||
|
||||
KTSB_WRITE(%g1, %g5, %g6)
|
||||
TSB_WRITE(%g1, %g5, %g6)
|
||||
|
||||
ba,pt %xcc, kvmap_dtlb_load
|
||||
nop
|
||||
|
||||
.align 32
|
||||
kvmap_dtlb_tsb4m_load:
|
||||
KTSB_LOCK_TAG(%g1, %g2, %g7)
|
||||
KTSB_WRITE(%g1, %g5, %g6)
|
||||
TSB_LOCK_TAG(%g1, %g2, %g7)
|
||||
TSB_WRITE(%g1, %g5, %g6)
|
||||
ba,pt %xcc, kvmap_dtlb_load
|
||||
nop
|
||||
|
||||
@@ -222,16 +222,16 @@ kvmap_linear_patch:
|
||||
kvmap_dtlb_vmalloc_addr:
|
||||
KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath)
|
||||
|
||||
KTSB_LOCK_TAG(%g1, %g2, %g7)
|
||||
TSB_LOCK_TAG(%g1, %g2, %g7)
|
||||
|
||||
/* Load and check PTE. */
|
||||
ldxa [%g5] ASI_PHYS_USE_EC, %g5
|
||||
mov 1, %g7
|
||||
sllx %g7, TSB_TAG_INVALID_BIT, %g7
|
||||
brgez,a,pn %g5, kvmap_dtlb_longpath
|
||||
KTSB_STORE(%g1, %g7)
|
||||
TSB_STORE(%g1, %g7)
|
||||
|
||||
KTSB_WRITE(%g1, %g5, %g6)
|
||||
TSB_WRITE(%g1, %g5, %g6)
|
||||
|
||||
/* fallthrough to TLB load */
|
||||
|
||||
|
||||
@@ -508,6 +508,8 @@ const char *mdesc_node_name(struct mdesc_handle *hp, u64 node)
|
||||
}
|
||||
EXPORT_SYMBOL(mdesc_node_name);
|
||||
|
||||
static u64 max_cpus = 64;
|
||||
|
||||
static void __init report_platform_properties(void)
|
||||
{
|
||||
struct mdesc_handle *hp = mdesc_grab();
|
||||
@@ -543,8 +545,10 @@ static void __init report_platform_properties(void)
|
||||
if (v)
|
||||
printk("PLATFORM: watchdog-max-timeout [%llu ms]\n", *v);
|
||||
v = mdesc_get_property(hp, pn, "max-cpus", NULL);
|
||||
if (v)
|
||||
printk("PLATFORM: max-cpus [%llu]\n", *v);
|
||||
if (v) {
|
||||
max_cpus = *v;
|
||||
printk("PLATFORM: max-cpus [%llu]\n", max_cpus);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
{
|
||||
@@ -715,7 +719,7 @@ static void __cpuinit set_proc_ids(struct mdesc_handle *hp)
|
||||
}
|
||||
|
||||
static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
|
||||
unsigned char def)
|
||||
unsigned long def, unsigned long max)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
@@ -726,6 +730,9 @@ static void __cpuinit get_one_mondo_bits(const u64 *p, unsigned int *mask,
|
||||
if (!val || val >= 64)
|
||||
goto use_default;
|
||||
|
||||
if (val > max)
|
||||
val = max;
|
||||
|
||||
*mask = ((1U << val) * 64U) - 1U;
|
||||
return;
|
||||
|
||||
@@ -736,19 +743,28 @@ use_default:
|
||||
static void __cpuinit get_mondo_data(struct mdesc_handle *hp, u64 mp,
|
||||
struct trap_per_cpu *tb)
|
||||
{
|
||||
static int printed;
|
||||
const u64 *val;
|
||||
|
||||
val = mdesc_get_property(hp, mp, "q-cpu-mondo-#bits", NULL);
|
||||
get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7);
|
||||
get_one_mondo_bits(val, &tb->cpu_mondo_qmask, 7, ilog2(max_cpus * 2));
|
||||
|
||||
val = mdesc_get_property(hp, mp, "q-dev-mondo-#bits", NULL);
|
||||
get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7);
|
||||
get_one_mondo_bits(val, &tb->dev_mondo_qmask, 7, 8);
|
||||
|
||||
val = mdesc_get_property(hp, mp, "q-resumable-#bits", NULL);
|
||||
get_one_mondo_bits(val, &tb->resum_qmask, 6);
|
||||
get_one_mondo_bits(val, &tb->resum_qmask, 6, 7);
|
||||
|
||||
val = mdesc_get_property(hp, mp, "q-nonresumable-#bits", NULL);
|
||||
get_one_mondo_bits(val, &tb->nonresum_qmask, 2);
|
||||
get_one_mondo_bits(val, &tb->nonresum_qmask, 2, 2);
|
||||
if (!printed++) {
|
||||
pr_info("SUN4V: Mondo queue sizes "
|
||||
"[cpu(%u) dev(%u) r(%u) nr(%u)]\n",
|
||||
tb->cpu_mondo_qmask + 1,
|
||||
tb->dev_mondo_qmask + 1,
|
||||
tb->resum_qmask + 1,
|
||||
tb->nonresum_qmask + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void * __cpuinit mdesc_iterate_over_cpus(void *(*func)(struct mdesc_handle *, u64, int, void *), void *arg, cpumask_t *mask)
|
||||
|
||||
@@ -352,8 +352,8 @@ int __init pcic_probe(void)
|
||||
strcpy(pbm->prom_name, namebuf);
|
||||
|
||||
{
|
||||
extern volatile int t_nmi[1];
|
||||
extern int pcic_nmi_trap_patch[1];
|
||||
extern volatile int t_nmi[4];
|
||||
extern int pcic_nmi_trap_patch[4];
|
||||
|
||||
t_nmi[0] = pcic_nmi_trap_patch[0];
|
||||
t_nmi[1] = pcic_nmi_trap_patch[1];
|
||||
|
||||
@@ -80,8 +80,11 @@ static void n2_pcr_write(u64 val)
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val);
|
||||
if (ret != HV_EOK)
|
||||
if (val & PCR_N2_HTRACE) {
|
||||
ret = sun4v_niagara2_setperf(HV_N2_PERF_SPARC_CTL, val);
|
||||
if (ret != HV_EOK)
|
||||
write_pcr(val);
|
||||
} else
|
||||
write_pcr(val);
|
||||
}
|
||||
|
||||
@@ -106,6 +109,10 @@ static int __init register_perf_hsvc(void)
|
||||
perf_hsvc_group = HV_GRP_N2_CPU;
|
||||
break;
|
||||
|
||||
case SUN4V_CHIP_NIAGARA3:
|
||||
perf_hsvc_group = HV_GRP_KT_CPU;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
@@ -1301,7 +1301,8 @@ static bool __init supported_pmu(void)
|
||||
sparc_pmu = &niagara1_pmu;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(sparc_pmu_type, "niagara2")) {
|
||||
if (!strcmp(sparc_pmu_type, "niagara2") ||
|
||||
!strcmp(sparc_pmu_type, "niagara3")) {
|
||||
sparc_pmu = &niagara2_pmu;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/initrd.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/io.h>
|
||||
@@ -46,6 +47,8 @@
|
||||
#include <asm/mmu.h>
|
||||
#include <asm/ns87303.h>
|
||||
#include <asm/btext.h>
|
||||
#include <asm/elf.h>
|
||||
#include <asm/mdesc.h>
|
||||
|
||||
#ifdef CONFIG_IP_PNP
|
||||
#include <net/ipconfig.h>
|
||||
@@ -269,6 +272,40 @@ void __init sun4v_patch(void)
|
||||
sun4v_hvapi_init();
|
||||
}
|
||||
|
||||
static void __init popc_patch(void)
|
||||
{
|
||||
struct popc_3insn_patch_entry *p3;
|
||||
struct popc_6insn_patch_entry *p6;
|
||||
|
||||
p3 = &__popc_3insn_patch;
|
||||
while (p3 < &__popc_3insn_patch_end) {
|
||||
unsigned long i, addr = p3->addr;
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
*(unsigned int *) (addr + (i * 4)) = p3->insns[i];
|
||||
wmb();
|
||||
__asm__ __volatile__("flush %0"
|
||||
: : "r" (addr + (i * 4)));
|
||||
}
|
||||
|
||||
p3++;
|
||||
}
|
||||
|
||||
p6 = &__popc_6insn_patch;
|
||||
while (p6 < &__popc_6insn_patch_end) {
|
||||
unsigned long i, addr = p6->addr;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
*(unsigned int *) (addr + (i * 4)) = p6->insns[i];
|
||||
wmb();
|
||||
__asm__ __volatile__("flush %0"
|
||||
: : "r" (addr + (i * 4)));
|
||||
}
|
||||
|
||||
p6++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
void __init boot_cpu_id_too_large(int cpu)
|
||||
{
|
||||
@@ -278,6 +315,160 @@ void __init boot_cpu_id_too_large(int cpu)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* On Ultra, we support all of the v8 capabilities. */
|
||||
unsigned long sparc64_elf_hwcap = (HWCAP_SPARC_FLUSH | HWCAP_SPARC_STBAR |
|
||||
HWCAP_SPARC_SWAP | HWCAP_SPARC_MULDIV |
|
||||
HWCAP_SPARC_V9);
|
||||
EXPORT_SYMBOL(sparc64_elf_hwcap);
|
||||
|
||||
static const char *hwcaps[] = {
|
||||
"flush", "stbar", "swap", "muldiv", "v9",
|
||||
"ultra3", "blkinit", "n2",
|
||||
|
||||
/* These strings are as they appear in the machine description
|
||||
* 'hwcap-list' property for cpu nodes.
|
||||
*/
|
||||
"mul32", "div32", "fsmuld", "v8plus", "popc", "vis", "vis2",
|
||||
"ASIBlkInit", "fmaf", "vis3", "hpc", "random", "trans", "fjfmau",
|
||||
"ima", "cspare",
|
||||
};
|
||||
|
||||
void cpucap_info(struct seq_file *m)
|
||||
{
|
||||
unsigned long caps = sparc64_elf_hwcap;
|
||||
int i, printed = 0;
|
||||
|
||||
seq_puts(m, "cpucaps\t\t: ");
|
||||
for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
|
||||
unsigned long bit = 1UL << i;
|
||||
if (caps & bit) {
|
||||
seq_printf(m, "%s%s",
|
||||
printed ? "," : "", hwcaps[i]);
|
||||
printed++;
|
||||
}
|
||||
}
|
||||
seq_putc(m, '\n');
|
||||
}
|
||||
|
||||
static void __init report_hwcaps(unsigned long caps)
|
||||
{
|
||||
int i, printed = 0;
|
||||
|
||||
printk(KERN_INFO "CPU CAPS: [");
|
||||
for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
|
||||
unsigned long bit = 1UL << i;
|
||||
if (caps & bit) {
|
||||
printk(KERN_CONT "%s%s",
|
||||
printed ? "," : "", hwcaps[i]);
|
||||
if (++printed == 8) {
|
||||
printk(KERN_CONT "]\n");
|
||||
printk(KERN_INFO "CPU CAPS: [");
|
||||
printed = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
printk(KERN_CONT "]\n");
|
||||
}
|
||||
|
||||
static unsigned long __init mdesc_cpu_hwcap_list(void)
|
||||
{
|
||||
struct mdesc_handle *hp;
|
||||
unsigned long caps = 0;
|
||||
const char *prop;
|
||||
int len;
|
||||
u64 pn;
|
||||
|
||||
hp = mdesc_grab();
|
||||
if (!hp)
|
||||
return 0;
|
||||
|
||||
pn = mdesc_node_by_name(hp, MDESC_NODE_NULL, "cpu");
|
||||
if (pn == MDESC_NODE_NULL)
|
||||
goto out;
|
||||
|
||||
prop = mdesc_get_property(hp, pn, "hwcap-list", &len);
|
||||
if (!prop)
|
||||
goto out;
|
||||
|
||||
while (len) {
|
||||
int i, plen;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
|
||||
unsigned long bit = 1UL << i;
|
||||
|
||||
if (!strcmp(prop, hwcaps[i])) {
|
||||
caps |= bit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
plen = strlen(prop) + 1;
|
||||
prop += plen;
|
||||
len -= plen;
|
||||
}
|
||||
|
||||
out:
|
||||
mdesc_release(hp);
|
||||
return caps;
|
||||
}
|
||||
|
||||
/* This yields a mask that user programs can use to figure out what
|
||||
* instruction set this cpu supports.
|
||||
*/
|
||||
static void __init init_sparc64_elf_hwcap(void)
|
||||
{
|
||||
unsigned long cap = sparc64_elf_hwcap;
|
||||
unsigned long mdesc_caps;
|
||||
|
||||
if (tlb_type == cheetah || tlb_type == cheetah_plus)
|
||||
cap |= HWCAP_SPARC_ULTRA3;
|
||||
else if (tlb_type == hypervisor) {
|
||||
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1 ||
|
||||
sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
|
||||
sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
|
||||
cap |= HWCAP_SPARC_BLKINIT;
|
||||
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
|
||||
sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
|
||||
cap |= HWCAP_SPARC_N2;
|
||||
}
|
||||
|
||||
cap |= (AV_SPARC_MUL32 | AV_SPARC_DIV32 | AV_SPARC_V8PLUS);
|
||||
|
||||
mdesc_caps = mdesc_cpu_hwcap_list();
|
||||
if (!mdesc_caps) {
|
||||
if (tlb_type == spitfire)
|
||||
cap |= AV_SPARC_VIS;
|
||||
if (tlb_type == cheetah || tlb_type == cheetah_plus)
|
||||
cap |= AV_SPARC_VIS | AV_SPARC_VIS2;
|
||||
if (tlb_type == cheetah_plus) {
|
||||
unsigned long impl, ver;
|
||||
|
||||
__asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
|
||||
impl = ((ver >> 32) & 0xffff);
|
||||
if (impl == PANTHER_IMPL)
|
||||
cap |= AV_SPARC_POPC;
|
||||
}
|
||||
if (tlb_type == hypervisor) {
|
||||
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA1)
|
||||
cap |= AV_SPARC_ASI_BLK_INIT;
|
||||
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
|
||||
sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
|
||||
cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 |
|
||||
AV_SPARC_ASI_BLK_INIT |
|
||||
AV_SPARC_POPC);
|
||||
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3)
|
||||
cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC |
|
||||
AV_SPARC_FMAF);
|
||||
}
|
||||
}
|
||||
sparc64_elf_hwcap = cap | mdesc_caps;
|
||||
|
||||
report_hwcaps(sparc64_elf_hwcap);
|
||||
|
||||
if (sparc64_elf_hwcap & AV_SPARC_POPC)
|
||||
popc_patch();
|
||||
}
|
||||
|
||||
void __init setup_arch(char **cmdline_p)
|
||||
{
|
||||
/* Initialize PROM console and command line. */
|
||||
@@ -337,6 +528,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
init_cur_cpu_trap(current_thread_info());
|
||||
|
||||
paging_init();
|
||||
init_sparc64_elf_hwcap();
|
||||
}
|
||||
|
||||
extern int stop_a_enabled;
|
||||
|
||||
+105
-79
@@ -29,6 +29,8 @@
|
||||
#include <asm/visasm.h>
|
||||
#include <asm/compat_signal.h>
|
||||
|
||||
#include "sigutil.h"
|
||||
|
||||
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
||||
|
||||
/* This magic should be in g_upper[0] for all upper parts
|
||||
@@ -44,14 +46,14 @@ typedef struct {
|
||||
struct signal_frame32 {
|
||||
struct sparc_stackf32 ss;
|
||||
__siginfo32_t info;
|
||||
/* __siginfo_fpu32_t * */ u32 fpu_save;
|
||||
/* __siginfo_fpu_t * */ u32 fpu_save;
|
||||
unsigned int insns[2];
|
||||
unsigned int extramask[_COMPAT_NSIG_WORDS - 1];
|
||||
unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
|
||||
/* Only valid if (info.si_regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
|
||||
siginfo_extra_v8plus_t v8plus;
|
||||
__siginfo_fpu_t fpu_state;
|
||||
};
|
||||
/* __siginfo_rwin_t * */u32 rwin_save;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
typedef struct compat_siginfo{
|
||||
int si_signo;
|
||||
@@ -110,18 +112,14 @@ struct rt_signal_frame32 {
|
||||
compat_siginfo_t info;
|
||||
struct pt_regs32 regs;
|
||||
compat_sigset_t mask;
|
||||
/* __siginfo_fpu32_t * */ u32 fpu_save;
|
||||
/* __siginfo_fpu_t * */ u32 fpu_save;
|
||||
unsigned int insns[2];
|
||||
stack_t32 stack;
|
||||
unsigned int extra_size; /* Should be sizeof(siginfo_extra_v8plus_t) */
|
||||
/* Only valid if (regs.psr & (PSR_VERS|PSR_IMPL)) == PSR_V8PLUS */
|
||||
siginfo_extra_v8plus_t v8plus;
|
||||
__siginfo_fpu_t fpu_state;
|
||||
};
|
||||
|
||||
/* Align macros */
|
||||
#define SF_ALIGNEDSZ (((sizeof(struct signal_frame32) + 15) & (~15)))
|
||||
#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame32) + 15) & (~15)))
|
||||
/* __siginfo_rwin_t * */u32 rwin_save;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
|
||||
{
|
||||
@@ -192,30 +190,13 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int restore_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||
{
|
||||
unsigned long *fpregs = current_thread_info()->fpregs;
|
||||
unsigned long fprs;
|
||||
int err;
|
||||
|
||||
err = __get_user(fprs, &fpu->si_fprs);
|
||||
fprs_write(0);
|
||||
regs->tstate &= ~TSTATE_PEF;
|
||||
if (fprs & FPRS_DL)
|
||||
err |= copy_from_user(fpregs, &fpu->si_float_regs[0], (sizeof(unsigned int) * 32));
|
||||
if (fprs & FPRS_DU)
|
||||
err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32], (sizeof(unsigned int) * 32));
|
||||
err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
|
||||
err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
|
||||
current_thread_info()->fpsaved[0] |= fprs;
|
||||
return err;
|
||||
}
|
||||
|
||||
void do_sigreturn32(struct pt_regs *regs)
|
||||
{
|
||||
struct signal_frame32 __user *sf;
|
||||
compat_uptr_t fpu_save;
|
||||
compat_uptr_t rwin_save;
|
||||
unsigned int psr;
|
||||
unsigned pc, npc, fpu_save;
|
||||
unsigned pc, npc;
|
||||
sigset_t set;
|
||||
unsigned seta[_COMPAT_NSIG_WORDS];
|
||||
int err, i;
|
||||
@@ -273,8 +254,13 @@ void do_sigreturn32(struct pt_regs *regs)
|
||||
pt_regs_clear_syscall(regs);
|
||||
|
||||
err |= __get_user(fpu_save, &sf->fpu_save);
|
||||
if (fpu_save)
|
||||
err |= restore_fpu_state32(regs, &sf->fpu_state);
|
||||
if (!err && fpu_save)
|
||||
err |= restore_fpu_state(regs, compat_ptr(fpu_save));
|
||||
err |= __get_user(rwin_save, &sf->rwin_save);
|
||||
if (!err && rwin_save) {
|
||||
if (restore_rwin_state(compat_ptr(rwin_save)))
|
||||
goto segv;
|
||||
}
|
||||
err |= __get_user(seta[0], &sf->info.si_mask);
|
||||
err |= copy_from_user(seta+1, &sf->extramask,
|
||||
(_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
|
||||
@@ -300,7 +286,9 @@ segv:
|
||||
asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
|
||||
{
|
||||
struct rt_signal_frame32 __user *sf;
|
||||
unsigned int psr, pc, npc, fpu_save, u_ss_sp;
|
||||
unsigned int psr, pc, npc, u_ss_sp;
|
||||
compat_uptr_t fpu_save;
|
||||
compat_uptr_t rwin_save;
|
||||
mm_segment_t old_fs;
|
||||
sigset_t set;
|
||||
compat_sigset_t seta;
|
||||
@@ -359,8 +347,8 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
|
||||
pt_regs_clear_syscall(regs);
|
||||
|
||||
err |= __get_user(fpu_save, &sf->fpu_save);
|
||||
if (fpu_save)
|
||||
err |= restore_fpu_state32(regs, &sf->fpu_state);
|
||||
if (!err && fpu_save)
|
||||
err |= restore_fpu_state(regs, compat_ptr(fpu_save));
|
||||
err |= copy_from_user(&seta, &sf->mask, sizeof(compat_sigset_t));
|
||||
err |= __get_user(u_ss_sp, &sf->stack.ss_sp);
|
||||
st.ss_sp = compat_ptr(u_ss_sp);
|
||||
@@ -376,6 +364,12 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
|
||||
do_sigaltstack((stack_t __user *) &st, NULL, (unsigned long)sf);
|
||||
set_fs(old_fs);
|
||||
|
||||
err |= __get_user(rwin_save, &sf->rwin_save);
|
||||
if (!err && rwin_save) {
|
||||
if (restore_rwin_state(compat_ptr(rwin_save)))
|
||||
goto segv;
|
||||
}
|
||||
|
||||
switch (_NSIG_WORDS) {
|
||||
case 4: set.sig[3] = seta.sig[6] + (((long)seta.sig[7]) << 32);
|
||||
case 3: set.sig[2] = seta.sig[4] + (((long)seta.sig[5]) << 32);
|
||||
@@ -433,26 +427,6 @@ static void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, uns
|
||||
return (void __user *) sp;
|
||||
}
|
||||
|
||||
static int save_fpu_state32(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||
{
|
||||
unsigned long *fpregs = current_thread_info()->fpregs;
|
||||
unsigned long fprs;
|
||||
int err = 0;
|
||||
|
||||
fprs = current_thread_info()->fpsaved[0];
|
||||
if (fprs & FPRS_DL)
|
||||
err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
|
||||
(sizeof(unsigned int) * 32));
|
||||
if (fprs & FPRS_DU)
|
||||
err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
|
||||
(sizeof(unsigned int) * 32));
|
||||
err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
|
||||
err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
|
||||
err |= __put_user(fprs, &fpu->si_fprs);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* The I-cache flush instruction only works in the primary ASI, which
|
||||
* right now is the nucleus, aka. kernel space.
|
||||
*
|
||||
@@ -515,18 +489,23 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
int signo, sigset_t *oldset)
|
||||
{
|
||||
struct signal_frame32 __user *sf;
|
||||
int i, err, wsaved;
|
||||
void __user *tail;
|
||||
int sigframe_size;
|
||||
u32 psr;
|
||||
int i, err;
|
||||
unsigned int seta[_COMPAT_NSIG_WORDS];
|
||||
|
||||
/* 1. Make sure everything is clean */
|
||||
synchronize_user_stack();
|
||||
save_and_clear_fpu();
|
||||
|
||||
sigframe_size = SF_ALIGNEDSZ;
|
||||
if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
|
||||
sigframe_size -= sizeof(__siginfo_fpu_t);
|
||||
wsaved = get_thread_wsaved();
|
||||
|
||||
sigframe_size = sizeof(*sf);
|
||||
if (current_thread_info()->fpsaved[0] & FPRS_FEF)
|
||||
sigframe_size += sizeof(__siginfo_fpu_t);
|
||||
if (wsaved)
|
||||
sigframe_size += sizeof(__siginfo_rwin_t);
|
||||
|
||||
sf = (struct signal_frame32 __user *)
|
||||
get_sigframe(&ka->sa, regs, sigframe_size);
|
||||
@@ -534,8 +513,7 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
if (invalid_frame_pointer(sf, sigframe_size))
|
||||
goto sigill;
|
||||
|
||||
if (get_thread_wsaved() != 0)
|
||||
goto sigill;
|
||||
tail = (sf + 1);
|
||||
|
||||
/* 2. Save the current process state */
|
||||
if (test_thread_flag(TIF_32BIT)) {
|
||||
@@ -560,11 +538,22 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
&sf->v8plus.asi);
|
||||
|
||||
if (psr & PSR_EF) {
|
||||
err |= save_fpu_state32(regs, &sf->fpu_state);
|
||||
err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
|
||||
__siginfo_fpu_t __user *fp = tail;
|
||||
tail += sizeof(*fp);
|
||||
err |= save_fpu_state(regs, fp);
|
||||
err |= __put_user((u64)fp, &sf->fpu_save);
|
||||
} else {
|
||||
err |= __put_user(0, &sf->fpu_save);
|
||||
}
|
||||
if (wsaved) {
|
||||
__siginfo_rwin_t __user *rwp = tail;
|
||||
tail += sizeof(*rwp);
|
||||
err |= save_rwin_state(wsaved, rwp);
|
||||
err |= __put_user((u64)rwp, &sf->rwin_save);
|
||||
set_thread_wsaved(0);
|
||||
} else {
|
||||
err |= __put_user(0, &sf->rwin_save);
|
||||
}
|
||||
|
||||
switch (_NSIG_WORDS) {
|
||||
case 4: seta[7] = (oldset->sig[3] >> 32);
|
||||
@@ -580,10 +569,21 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
err |= __copy_to_user(sf->extramask, seta + 1,
|
||||
(_COMPAT_NSIG_WORDS - 1) * sizeof(unsigned int));
|
||||
|
||||
err |= copy_in_user((u32 __user *)sf,
|
||||
(u32 __user *)(regs->u_regs[UREG_FP]),
|
||||
sizeof(struct reg_window32));
|
||||
|
||||
if (!wsaved) {
|
||||
err |= copy_in_user((u32 __user *)sf,
|
||||
(u32 __user *)(regs->u_regs[UREG_FP]),
|
||||
sizeof(struct reg_window32));
|
||||
} else {
|
||||
struct reg_window *rp;
|
||||
|
||||
rp = ¤t_thread_info()->reg_window[wsaved - 1];
|
||||
for (i = 0; i < 8; i++)
|
||||
err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
|
||||
for (i = 0; i < 6; i++)
|
||||
err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
|
||||
err |= __put_user(rp->ins[6], &sf->ss.fp);
|
||||
err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
|
||||
}
|
||||
if (err)
|
||||
goto sigsegv;
|
||||
|
||||
@@ -613,7 +613,6 @@ static int setup_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
err |= __put_user(0x91d02010, &sf->insns[1]); /*t 0x10*/
|
||||
if (err)
|
||||
goto sigsegv;
|
||||
|
||||
flush_signal_insns(address);
|
||||
}
|
||||
return 0;
|
||||
@@ -632,18 +631,23 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
siginfo_t *info)
|
||||
{
|
||||
struct rt_signal_frame32 __user *sf;
|
||||
int i, err, wsaved;
|
||||
void __user *tail;
|
||||
int sigframe_size;
|
||||
u32 psr;
|
||||
int i, err;
|
||||
compat_sigset_t seta;
|
||||
|
||||
/* 1. Make sure everything is clean */
|
||||
synchronize_user_stack();
|
||||
save_and_clear_fpu();
|
||||
|
||||
sigframe_size = RT_ALIGNEDSZ;
|
||||
if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
|
||||
sigframe_size -= sizeof(__siginfo_fpu_t);
|
||||
wsaved = get_thread_wsaved();
|
||||
|
||||
sigframe_size = sizeof(*sf);
|
||||
if (current_thread_info()->fpsaved[0] & FPRS_FEF)
|
||||
sigframe_size += sizeof(__siginfo_fpu_t);
|
||||
if (wsaved)
|
||||
sigframe_size += sizeof(__siginfo_rwin_t);
|
||||
|
||||
sf = (struct rt_signal_frame32 __user *)
|
||||
get_sigframe(&ka->sa, regs, sigframe_size);
|
||||
@@ -651,8 +655,7 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
if (invalid_frame_pointer(sf, sigframe_size))
|
||||
goto sigill;
|
||||
|
||||
if (get_thread_wsaved() != 0)
|
||||
goto sigill;
|
||||
tail = (sf + 1);
|
||||
|
||||
/* 2. Save the current process state */
|
||||
if (test_thread_flag(TIF_32BIT)) {
|
||||
@@ -677,11 +680,22 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
&sf->v8plus.asi);
|
||||
|
||||
if (psr & PSR_EF) {
|
||||
err |= save_fpu_state32(regs, &sf->fpu_state);
|
||||
err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
|
||||
__siginfo_fpu_t __user *fp = tail;
|
||||
tail += sizeof(*fp);
|
||||
err |= save_fpu_state(regs, fp);
|
||||
err |= __put_user((u64)fp, &sf->fpu_save);
|
||||
} else {
|
||||
err |= __put_user(0, &sf->fpu_save);
|
||||
}
|
||||
if (wsaved) {
|
||||
__siginfo_rwin_t __user *rwp = tail;
|
||||
tail += sizeof(*rwp);
|
||||
err |= save_rwin_state(wsaved, rwp);
|
||||
err |= __put_user((u64)rwp, &sf->rwin_save);
|
||||
set_thread_wsaved(0);
|
||||
} else {
|
||||
err |= __put_user(0, &sf->rwin_save);
|
||||
}
|
||||
|
||||
/* Update the siginfo structure. */
|
||||
err |= copy_siginfo_to_user32(&sf->info, info);
|
||||
@@ -703,9 +717,21 @@ static int setup_rt_frame32(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
}
|
||||
err |= __copy_to_user(&sf->mask, &seta, sizeof(compat_sigset_t));
|
||||
|
||||
err |= copy_in_user((u32 __user *)sf,
|
||||
(u32 __user *)(regs->u_regs[UREG_FP]),
|
||||
sizeof(struct reg_window32));
|
||||
if (!wsaved) {
|
||||
err |= copy_in_user((u32 __user *)sf,
|
||||
(u32 __user *)(regs->u_regs[UREG_FP]),
|
||||
sizeof(struct reg_window32));
|
||||
} else {
|
||||
struct reg_window *rp;
|
||||
|
||||
rp = ¤t_thread_info()->reg_window[wsaved - 1];
|
||||
for (i = 0; i < 8; i++)
|
||||
err |= __put_user(rp->locals[i], &sf->ss.locals[i]);
|
||||
for (i = 0; i < 6; i++)
|
||||
err |= __put_user(rp->ins[i], &sf->ss.ins[i]);
|
||||
err |= __put_user(rp->ins[6], &sf->ss.fp);
|
||||
err |= __put_user(rp->ins[7], &sf->ss.callers_pc);
|
||||
}
|
||||
if (err)
|
||||
goto sigsegv;
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/cacheflush.h> /* flush_sig_insns */
|
||||
|
||||
#include "sigutil.h"
|
||||
|
||||
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
||||
|
||||
extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
|
||||
@@ -39,8 +41,8 @@ struct signal_frame {
|
||||
unsigned long insns[2] __attribute__ ((aligned (8)));
|
||||
unsigned int extramask[_NSIG_WORDS - 1];
|
||||
unsigned int extra_size; /* Should be 0 */
|
||||
__siginfo_fpu_t fpu_state;
|
||||
};
|
||||
__siginfo_rwin_t __user *rwin_save;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
struct rt_signal_frame {
|
||||
struct sparc_stackf ss;
|
||||
@@ -51,8 +53,8 @@ struct rt_signal_frame {
|
||||
unsigned int insns[2];
|
||||
stack_t stack;
|
||||
unsigned int extra_size; /* Should be 0 */
|
||||
__siginfo_fpu_t fpu_state;
|
||||
};
|
||||
__siginfo_rwin_t __user *rwin_save;
|
||||
} __attribute__((aligned(8)));
|
||||
|
||||
/* Align macros */
|
||||
#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
|
||||
@@ -79,43 +81,13 @@ asmlinkage int sys_sigsuspend(old_sigset_t set)
|
||||
return _sigpause_common(set);
|
||||
}
|
||||
|
||||
static inline int
|
||||
restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||
{
|
||||
int err;
|
||||
#ifdef CONFIG_SMP
|
||||
if (test_tsk_thread_flag(current, TIF_USEDFPU))
|
||||
regs->psr &= ~PSR_EF;
|
||||
#else
|
||||
if (current == last_task_used_math) {
|
||||
last_task_used_math = NULL;
|
||||
regs->psr &= ~PSR_EF;
|
||||
}
|
||||
#endif
|
||||
set_used_math();
|
||||
clear_tsk_thread_flag(current, TIF_USEDFPU);
|
||||
|
||||
if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
|
||||
return -EFAULT;
|
||||
|
||||
err = __copy_from_user(¤t->thread.float_regs[0], &fpu->si_float_regs[0],
|
||||
(sizeof(unsigned long) * 32));
|
||||
err |= __get_user(current->thread.fsr, &fpu->si_fsr);
|
||||
err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
|
||||
if (current->thread.fpqdepth != 0)
|
||||
err |= __copy_from_user(¤t->thread.fpqueue[0],
|
||||
&fpu->si_fpqueue[0],
|
||||
((sizeof(unsigned long) +
|
||||
(sizeof(unsigned long *)))*16));
|
||||
return err;
|
||||
}
|
||||
|
||||
asmlinkage void do_sigreturn(struct pt_regs *regs)
|
||||
{
|
||||
struct signal_frame __user *sf;
|
||||
unsigned long up_psr, pc, npc;
|
||||
sigset_t set;
|
||||
__siginfo_fpu_t __user *fpu_save;
|
||||
__siginfo_rwin_t __user *rwin_save;
|
||||
int err;
|
||||
|
||||
/* Always make any pending restarted system calls return -EINTR */
|
||||
@@ -150,9 +122,11 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
|
||||
pt_regs_clear_syscall(regs);
|
||||
|
||||
err |= __get_user(fpu_save, &sf->fpu_save);
|
||||
|
||||
if (fpu_save)
|
||||
err |= restore_fpu_state(regs, fpu_save);
|
||||
err |= __get_user(rwin_save, &sf->rwin_save);
|
||||
if (rwin_save)
|
||||
err |= restore_rwin_state(rwin_save);
|
||||
|
||||
/* This is pretty much atomic, no amount locking would prevent
|
||||
* the races which exist anyways.
|
||||
@@ -180,6 +154,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
|
||||
struct rt_signal_frame __user *sf;
|
||||
unsigned int psr, pc, npc;
|
||||
__siginfo_fpu_t __user *fpu_save;
|
||||
__siginfo_rwin_t __user *rwin_save;
|
||||
mm_segment_t old_fs;
|
||||
sigset_t set;
|
||||
stack_t st;
|
||||
@@ -207,8 +182,7 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
|
||||
pt_regs_clear_syscall(regs);
|
||||
|
||||
err |= __get_user(fpu_save, &sf->fpu_save);
|
||||
|
||||
if (fpu_save)
|
||||
if (!err && fpu_save)
|
||||
err |= restore_fpu_state(regs, fpu_save);
|
||||
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
|
||||
|
||||
@@ -228,6 +202,12 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
|
||||
do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf);
|
||||
set_fs(old_fs);
|
||||
|
||||
err |= __get_user(rwin_save, &sf->rwin_save);
|
||||
if (!err && rwin_save) {
|
||||
if (restore_rwin_state(rwin_save))
|
||||
goto segv;
|
||||
}
|
||||
|
||||
sigdelsetmask(&set, ~_BLOCKABLE);
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
current->blocked = set;
|
||||
@@ -280,53 +260,23 @@ static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *re
|
||||
return (void __user *) sp;
|
||||
}
|
||||
|
||||
static inline int
|
||||
save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||
{
|
||||
int err = 0;
|
||||
#ifdef CONFIG_SMP
|
||||
if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
|
||||
put_psr(get_psr() | PSR_EF);
|
||||
fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
|
||||
¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
|
||||
regs->psr &= ~(PSR_EF);
|
||||
clear_tsk_thread_flag(current, TIF_USEDFPU);
|
||||
}
|
||||
#else
|
||||
if (current == last_task_used_math) {
|
||||
put_psr(get_psr() | PSR_EF);
|
||||
fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
|
||||
¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
|
||||
last_task_used_math = NULL;
|
||||
regs->psr &= ~(PSR_EF);
|
||||
}
|
||||
#endif
|
||||
err |= __copy_to_user(&fpu->si_float_regs[0],
|
||||
¤t->thread.float_regs[0],
|
||||
(sizeof(unsigned long) * 32));
|
||||
err |= __put_user(current->thread.fsr, &fpu->si_fsr);
|
||||
err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
|
||||
if (current->thread.fpqdepth != 0)
|
||||
err |= __copy_to_user(&fpu->si_fpqueue[0],
|
||||
¤t->thread.fpqueue[0],
|
||||
((sizeof(unsigned long) +
|
||||
(sizeof(unsigned long *)))*16));
|
||||
clear_used_math();
|
||||
return err;
|
||||
}
|
||||
|
||||
static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
int signo, sigset_t *oldset)
|
||||
{
|
||||
struct signal_frame __user *sf;
|
||||
int sigframe_size, err;
|
||||
int sigframe_size, err, wsaved;
|
||||
void __user *tail;
|
||||
|
||||
/* 1. Make sure everything is clean */
|
||||
synchronize_user_stack();
|
||||
|
||||
sigframe_size = SF_ALIGNEDSZ;
|
||||
if (!used_math())
|
||||
sigframe_size -= sizeof(__siginfo_fpu_t);
|
||||
wsaved = current_thread_info()->w_saved;
|
||||
|
||||
sigframe_size = sizeof(*sf);
|
||||
if (used_math())
|
||||
sigframe_size += sizeof(__siginfo_fpu_t);
|
||||
if (wsaved)
|
||||
sigframe_size += sizeof(__siginfo_rwin_t);
|
||||
|
||||
sf = (struct signal_frame __user *)
|
||||
get_sigframe(&ka->sa, regs, sigframe_size);
|
||||
@@ -334,8 +284,7 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
if (invalid_frame_pointer(sf, sigframe_size))
|
||||
goto sigill_and_return;
|
||||
|
||||
if (current_thread_info()->w_saved != 0)
|
||||
goto sigill_and_return;
|
||||
tail = sf + 1;
|
||||
|
||||
/* 2. Save the current process state */
|
||||
err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs));
|
||||
@@ -343,17 +292,34 @@ static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
err |= __put_user(0, &sf->extra_size);
|
||||
|
||||
if (used_math()) {
|
||||
err |= save_fpu_state(regs, &sf->fpu_state);
|
||||
err |= __put_user(&sf->fpu_state, &sf->fpu_save);
|
||||
__siginfo_fpu_t __user *fp = tail;
|
||||
tail += sizeof(*fp);
|
||||
err |= save_fpu_state(regs, fp);
|
||||
err |= __put_user(fp, &sf->fpu_save);
|
||||
} else {
|
||||
err |= __put_user(0, &sf->fpu_save);
|
||||
}
|
||||
if (wsaved) {
|
||||
__siginfo_rwin_t __user *rwp = tail;
|
||||
tail += sizeof(*rwp);
|
||||
err |= save_rwin_state(wsaved, rwp);
|
||||
err |= __put_user(rwp, &sf->rwin_save);
|
||||
} else {
|
||||
err |= __put_user(0, &sf->rwin_save);
|
||||
}
|
||||
|
||||
err |= __put_user(oldset->sig[0], &sf->info.si_mask);
|
||||
err |= __copy_to_user(sf->extramask, &oldset->sig[1],
|
||||
(_NSIG_WORDS - 1) * sizeof(unsigned int));
|
||||
err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
|
||||
sizeof(struct reg_window32));
|
||||
if (!wsaved) {
|
||||
err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
|
||||
sizeof(struct reg_window32));
|
||||
} else {
|
||||
struct reg_window32 *rp;
|
||||
|
||||
rp = ¤t_thread_info()->reg_window[wsaved - 1];
|
||||
err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
|
||||
}
|
||||
if (err)
|
||||
goto sigsegv;
|
||||
|
||||
@@ -399,21 +365,24 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
int signo, sigset_t *oldset, siginfo_t *info)
|
||||
{
|
||||
struct rt_signal_frame __user *sf;
|
||||
int sigframe_size;
|
||||
int sigframe_size, wsaved;
|
||||
void __user *tail;
|
||||
unsigned int psr;
|
||||
int err;
|
||||
|
||||
synchronize_user_stack();
|
||||
sigframe_size = RT_ALIGNEDSZ;
|
||||
if (!used_math())
|
||||
sigframe_size -= sizeof(__siginfo_fpu_t);
|
||||
wsaved = current_thread_info()->w_saved;
|
||||
sigframe_size = sizeof(*sf);
|
||||
if (used_math())
|
||||
sigframe_size += sizeof(__siginfo_fpu_t);
|
||||
if (wsaved)
|
||||
sigframe_size += sizeof(__siginfo_rwin_t);
|
||||
sf = (struct rt_signal_frame __user *)
|
||||
get_sigframe(&ka->sa, regs, sigframe_size);
|
||||
if (invalid_frame_pointer(sf, sigframe_size))
|
||||
goto sigill;
|
||||
if (current_thread_info()->w_saved != 0)
|
||||
goto sigill;
|
||||
|
||||
tail = sf + 1;
|
||||
err = __put_user(regs->pc, &sf->regs.pc);
|
||||
err |= __put_user(regs->npc, &sf->regs.npc);
|
||||
err |= __put_user(regs->y, &sf->regs.y);
|
||||
@@ -425,11 +394,21 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
err |= __put_user(0, &sf->extra_size);
|
||||
|
||||
if (psr & PSR_EF) {
|
||||
err |= save_fpu_state(regs, &sf->fpu_state);
|
||||
err |= __put_user(&sf->fpu_state, &sf->fpu_save);
|
||||
__siginfo_fpu_t *fp = tail;
|
||||
tail += sizeof(*fp);
|
||||
err |= save_fpu_state(regs, fp);
|
||||
err |= __put_user(fp, &sf->fpu_save);
|
||||
} else {
|
||||
err |= __put_user(0, &sf->fpu_save);
|
||||
}
|
||||
if (wsaved) {
|
||||
__siginfo_rwin_t *rwp = tail;
|
||||
tail += sizeof(*rwp);
|
||||
err |= save_rwin_state(wsaved, rwp);
|
||||
err |= __put_user(rwp, &sf->rwin_save);
|
||||
} else {
|
||||
err |= __put_user(0, &sf->rwin_save);
|
||||
}
|
||||
err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t));
|
||||
|
||||
/* Setup sigaltstack */
|
||||
@@ -437,8 +416,15 @@ static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags);
|
||||
err |= __put_user(current->sas_ss_size, &sf->stack.ss_size);
|
||||
|
||||
err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
|
||||
sizeof(struct reg_window32));
|
||||
if (!wsaved) {
|
||||
err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP],
|
||||
sizeof(struct reg_window32));
|
||||
} else {
|
||||
struct reg_window32 *rp;
|
||||
|
||||
rp = ¤t_thread_info()->reg_window[wsaved - 1];
|
||||
err |= __copy_to_user(sf, rp, sizeof(struct reg_window32));
|
||||
}
|
||||
|
||||
err |= copy_siginfo_to_user(&sf->info, info);
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "entry.h"
|
||||
#include "systbls.h"
|
||||
#include "sigutil.h"
|
||||
|
||||
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
|
||||
|
||||
@@ -236,7 +237,7 @@ struct rt_signal_frame {
|
||||
__siginfo_fpu_t __user *fpu_save;
|
||||
stack_t stack;
|
||||
sigset_t mask;
|
||||
__siginfo_fpu_t fpu_state;
|
||||
__siginfo_rwin_t *rwin_save;
|
||||
};
|
||||
|
||||
static long _sigpause_common(old_sigset_t set)
|
||||
@@ -266,33 +267,12 @@ asmlinkage long sys_sigsuspend(old_sigset_t set)
|
||||
return _sigpause_common(set);
|
||||
}
|
||||
|
||||
static inline int
|
||||
restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||
{
|
||||
unsigned long *fpregs = current_thread_info()->fpregs;
|
||||
unsigned long fprs;
|
||||
int err;
|
||||
|
||||
err = __get_user(fprs, &fpu->si_fprs);
|
||||
fprs_write(0);
|
||||
regs->tstate &= ~TSTATE_PEF;
|
||||
if (fprs & FPRS_DL)
|
||||
err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
|
||||
(sizeof(unsigned int) * 32));
|
||||
if (fprs & FPRS_DU)
|
||||
err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
|
||||
(sizeof(unsigned int) * 32));
|
||||
err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
|
||||
err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
|
||||
current_thread_info()->fpsaved[0] |= fprs;
|
||||
return err;
|
||||
}
|
||||
|
||||
void do_rt_sigreturn(struct pt_regs *regs)
|
||||
{
|
||||
struct rt_signal_frame __user *sf;
|
||||
unsigned long tpc, tnpc, tstate;
|
||||
__siginfo_fpu_t __user *fpu_save;
|
||||
__siginfo_rwin_t __user *rwin_save;
|
||||
sigset_t set;
|
||||
int err;
|
||||
|
||||
@@ -325,8 +305,8 @@ void do_rt_sigreturn(struct pt_regs *regs)
|
||||
regs->tstate |= (tstate & (TSTATE_ASI | TSTATE_ICC | TSTATE_XCC));
|
||||
|
||||
err |= __get_user(fpu_save, &sf->fpu_save);
|
||||
if (fpu_save)
|
||||
err |= restore_fpu_state(regs, &sf->fpu_state);
|
||||
if (!err && fpu_save)
|
||||
err |= restore_fpu_state(regs, fpu_save);
|
||||
|
||||
err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t));
|
||||
err |= do_sigaltstack(&sf->stack, NULL, (unsigned long)sf);
|
||||
@@ -334,6 +314,12 @@ void do_rt_sigreturn(struct pt_regs *regs)
|
||||
if (err)
|
||||
goto segv;
|
||||
|
||||
err |= __get_user(rwin_save, &sf->rwin_save);
|
||||
if (!err && rwin_save) {
|
||||
if (restore_rwin_state(rwin_save))
|
||||
goto segv;
|
||||
}
|
||||
|
||||
regs->tpc = tpc;
|
||||
regs->tnpc = tnpc;
|
||||
|
||||
@@ -351,34 +337,13 @@ segv:
|
||||
}
|
||||
|
||||
/* Checks if the fp is valid */
|
||||
static int invalid_frame_pointer(void __user *fp, int fplen)
|
||||
static int invalid_frame_pointer(void __user *fp)
|
||||
{
|
||||
if (((unsigned long) fp) & 15)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int
|
||||
save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||
{
|
||||
unsigned long *fpregs = current_thread_info()->fpregs;
|
||||
unsigned long fprs;
|
||||
int err = 0;
|
||||
|
||||
fprs = current_thread_info()->fpsaved[0];
|
||||
if (fprs & FPRS_DL)
|
||||
err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
|
||||
(sizeof(unsigned int) * 32));
|
||||
if (fprs & FPRS_DU)
|
||||
err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
|
||||
(sizeof(unsigned int) * 32));
|
||||
err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
|
||||
err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
|
||||
err |= __put_user(fprs, &fpu->si_fprs);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, unsigned long framesize)
|
||||
{
|
||||
unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
|
||||
@@ -414,34 +379,48 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
int signo, sigset_t *oldset, siginfo_t *info)
|
||||
{
|
||||
struct rt_signal_frame __user *sf;
|
||||
int sigframe_size, err;
|
||||
int wsaved, err, sf_size;
|
||||
void __user *tail;
|
||||
|
||||
/* 1. Make sure everything is clean */
|
||||
synchronize_user_stack();
|
||||
save_and_clear_fpu();
|
||||
|
||||
sigframe_size = sizeof(struct rt_signal_frame);
|
||||
if (!(current_thread_info()->fpsaved[0] & FPRS_FEF))
|
||||
sigframe_size -= sizeof(__siginfo_fpu_t);
|
||||
wsaved = get_thread_wsaved();
|
||||
|
||||
sf_size = sizeof(struct rt_signal_frame);
|
||||
if (current_thread_info()->fpsaved[0] & FPRS_FEF)
|
||||
sf_size += sizeof(__siginfo_fpu_t);
|
||||
if (wsaved)
|
||||
sf_size += sizeof(__siginfo_rwin_t);
|
||||
sf = (struct rt_signal_frame __user *)
|
||||
get_sigframe(ka, regs, sigframe_size);
|
||||
|
||||
if (invalid_frame_pointer (sf, sigframe_size))
|
||||
get_sigframe(ka, regs, sf_size);
|
||||
|
||||
if (invalid_frame_pointer (sf))
|
||||
goto sigill;
|
||||
|
||||
if (get_thread_wsaved() != 0)
|
||||
goto sigill;
|
||||
tail = (sf + 1);
|
||||
|
||||
/* 2. Save the current process state */
|
||||
err = copy_to_user(&sf->regs, regs, sizeof (*regs));
|
||||
|
||||
if (current_thread_info()->fpsaved[0] & FPRS_FEF) {
|
||||
err |= save_fpu_state(regs, &sf->fpu_state);
|
||||
err |= __put_user((u64)&sf->fpu_state, &sf->fpu_save);
|
||||
__siginfo_fpu_t __user *fpu_save = tail;
|
||||
tail += sizeof(__siginfo_fpu_t);
|
||||
err |= save_fpu_state(regs, fpu_save);
|
||||
err |= __put_user((u64)fpu_save, &sf->fpu_save);
|
||||
} else {
|
||||
err |= __put_user(0, &sf->fpu_save);
|
||||
}
|
||||
if (wsaved) {
|
||||
__siginfo_rwin_t __user *rwin_save = tail;
|
||||
tail += sizeof(__siginfo_rwin_t);
|
||||
err |= save_rwin_state(wsaved, rwin_save);
|
||||
err |= __put_user((u64)rwin_save, &sf->rwin_save);
|
||||
set_thread_wsaved(0);
|
||||
} else {
|
||||
err |= __put_user(0, &sf->rwin_save);
|
||||
}
|
||||
|
||||
/* Setup sigaltstack */
|
||||
err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp);
|
||||
@@ -450,10 +429,17 @@ setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs,
|
||||
|
||||
err |= copy_to_user(&sf->mask, oldset, sizeof(sigset_t));
|
||||
|
||||
err |= copy_in_user((u64 __user *)sf,
|
||||
(u64 __user *)(regs->u_regs[UREG_FP]+STACK_BIAS),
|
||||
sizeof(struct reg_window));
|
||||
if (!wsaved) {
|
||||
err |= copy_in_user((u64 __user *)sf,
|
||||
(u64 __user *)(regs->u_regs[UREG_FP] +
|
||||
STACK_BIAS),
|
||||
sizeof(struct reg_window));
|
||||
} else {
|
||||
struct reg_window *rp;
|
||||
|
||||
rp = ¤t_thread_info()->reg_window[wsaved - 1];
|
||||
err |= copy_to_user(sf, rp, sizeof(struct reg_window));
|
||||
}
|
||||
if (info)
|
||||
err |= copy_siginfo_to_user(&sf->info, info);
|
||||
else {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef _SIGUTIL_H
|
||||
#define _SIGUTIL_H
|
||||
|
||||
int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
|
||||
int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu);
|
||||
int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin);
|
||||
int restore_rwin_state(__siginfo_rwin_t __user *rp);
|
||||
|
||||
#endif /* _SIGUTIL_H */
|
||||
@@ -0,0 +1,120 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/thread_info.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <asm/sigcontext.h>
|
||||
#include <asm/fpumacro.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#include "sigutil.h"
|
||||
|
||||
int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||
{
|
||||
int err = 0;
|
||||
#ifdef CONFIG_SMP
|
||||
if (test_tsk_thread_flag(current, TIF_USEDFPU)) {
|
||||
put_psr(get_psr() | PSR_EF);
|
||||
fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
|
||||
¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
|
||||
regs->psr &= ~(PSR_EF);
|
||||
clear_tsk_thread_flag(current, TIF_USEDFPU);
|
||||
}
|
||||
#else
|
||||
if (current == last_task_used_math) {
|
||||
put_psr(get_psr() | PSR_EF);
|
||||
fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr,
|
||||
¤t->thread.fpqueue[0], ¤t->thread.fpqdepth);
|
||||
last_task_used_math = NULL;
|
||||
regs->psr &= ~(PSR_EF);
|
||||
}
|
||||
#endif
|
||||
err |= __copy_to_user(&fpu->si_float_regs[0],
|
||||
¤t->thread.float_regs[0],
|
||||
(sizeof(unsigned long) * 32));
|
||||
err |= __put_user(current->thread.fsr, &fpu->si_fsr);
|
||||
err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
|
||||
if (current->thread.fpqdepth != 0)
|
||||
err |= __copy_to_user(&fpu->si_fpqueue[0],
|
||||
¤t->thread.fpqueue[0],
|
||||
((sizeof(unsigned long) +
|
||||
(sizeof(unsigned long *)))*16));
|
||||
clear_used_math();
|
||||
return err;
|
||||
}
|
||||
|
||||
int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||
{
|
||||
int err;
|
||||
#ifdef CONFIG_SMP
|
||||
if (test_tsk_thread_flag(current, TIF_USEDFPU))
|
||||
regs->psr &= ~PSR_EF;
|
||||
#else
|
||||
if (current == last_task_used_math) {
|
||||
last_task_used_math = NULL;
|
||||
regs->psr &= ~PSR_EF;
|
||||
}
|
||||
#endif
|
||||
set_used_math();
|
||||
clear_tsk_thread_flag(current, TIF_USEDFPU);
|
||||
|
||||
if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu)))
|
||||
return -EFAULT;
|
||||
|
||||
err = __copy_from_user(¤t->thread.float_regs[0], &fpu->si_float_regs[0],
|
||||
(sizeof(unsigned long) * 32));
|
||||
err |= __get_user(current->thread.fsr, &fpu->si_fsr);
|
||||
err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
|
||||
if (current->thread.fpqdepth != 0)
|
||||
err |= __copy_from_user(¤t->thread.fpqueue[0],
|
||||
&fpu->si_fpqueue[0],
|
||||
((sizeof(unsigned long) +
|
||||
(sizeof(unsigned long *)))*16));
|
||||
return err;
|
||||
}
|
||||
|
||||
int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
|
||||
{
|
||||
int i, err = __put_user(wsaved, &rwin->wsaved);
|
||||
|
||||
for (i = 0; i < wsaved; i++) {
|
||||
struct reg_window32 *rp;
|
||||
unsigned long fp;
|
||||
|
||||
rp = ¤t_thread_info()->reg_window[i];
|
||||
fp = current_thread_info()->rwbuf_stkptrs[i];
|
||||
err |= copy_to_user(&rwin->reg_window[i], rp,
|
||||
sizeof(struct reg_window32));
|
||||
err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int restore_rwin_state(__siginfo_rwin_t __user *rp)
|
||||
{
|
||||
struct thread_info *t = current_thread_info();
|
||||
int i, wsaved, err;
|
||||
|
||||
__get_user(wsaved, &rp->wsaved);
|
||||
if (wsaved > NSWINS)
|
||||
return -EFAULT;
|
||||
|
||||
err = 0;
|
||||
for (i = 0; i < wsaved; i++) {
|
||||
err |= copy_from_user(&t->reg_window[i],
|
||||
&rp->reg_window[i],
|
||||
sizeof(struct reg_window32));
|
||||
err |= __get_user(t->rwbuf_stkptrs[i],
|
||||
&rp->rwbuf_stkptrs[i]);
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
t->w_saved = wsaved;
|
||||
synchronize_user_stack();
|
||||
if (t->w_saved)
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/thread_info.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/sigcontext.h>
|
||||
#include <asm/fpumacro.h>
|
||||
#include <asm/ptrace.h>
|
||||
|
||||
#include "sigutil.h"
|
||||
|
||||
int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||
{
|
||||
unsigned long *fpregs = current_thread_info()->fpregs;
|
||||
unsigned long fprs;
|
||||
int err = 0;
|
||||
|
||||
fprs = current_thread_info()->fpsaved[0];
|
||||
if (fprs & FPRS_DL)
|
||||
err |= copy_to_user(&fpu->si_float_regs[0], fpregs,
|
||||
(sizeof(unsigned int) * 32));
|
||||
if (fprs & FPRS_DU)
|
||||
err |= copy_to_user(&fpu->si_float_regs[32], fpregs+16,
|
||||
(sizeof(unsigned int) * 32));
|
||||
err |= __put_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
|
||||
err |= __put_user(current_thread_info()->gsr[0], &fpu->si_gsr);
|
||||
err |= __put_user(fprs, &fpu->si_fprs);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
|
||||
{
|
||||
unsigned long *fpregs = current_thread_info()->fpregs;
|
||||
unsigned long fprs;
|
||||
int err;
|
||||
|
||||
err = __get_user(fprs, &fpu->si_fprs);
|
||||
fprs_write(0);
|
||||
regs->tstate &= ~TSTATE_PEF;
|
||||
if (fprs & FPRS_DL)
|
||||
err |= copy_from_user(fpregs, &fpu->si_float_regs[0],
|
||||
(sizeof(unsigned int) * 32));
|
||||
if (fprs & FPRS_DU)
|
||||
err |= copy_from_user(fpregs+16, &fpu->si_float_regs[32],
|
||||
(sizeof(unsigned int) * 32));
|
||||
err |= __get_user(current_thread_info()->xfsr[0], &fpu->si_fsr);
|
||||
err |= __get_user(current_thread_info()->gsr[0], &fpu->si_gsr);
|
||||
current_thread_info()->fpsaved[0] |= fprs;
|
||||
return err;
|
||||
}
|
||||
|
||||
int save_rwin_state(int wsaved, __siginfo_rwin_t __user *rwin)
|
||||
{
|
||||
int i, err = __put_user(wsaved, &rwin->wsaved);
|
||||
|
||||
for (i = 0; i < wsaved; i++) {
|
||||
struct reg_window *rp = ¤t_thread_info()->reg_window[i];
|
||||
unsigned long fp = current_thread_info()->rwbuf_stkptrs[i];
|
||||
|
||||
err |= copy_to_user(&rwin->reg_window[i], rp,
|
||||
sizeof(struct reg_window));
|
||||
err |= __put_user(fp, &rwin->rwbuf_stkptrs[i]);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int restore_rwin_state(__siginfo_rwin_t __user *rp)
|
||||
{
|
||||
struct thread_info *t = current_thread_info();
|
||||
int i, wsaved, err;
|
||||
|
||||
__get_user(wsaved, &rp->wsaved);
|
||||
if (wsaved > NSWINS)
|
||||
return -EFAULT;
|
||||
|
||||
err = 0;
|
||||
for (i = 0; i < wsaved; i++) {
|
||||
err |= copy_from_user(&t->reg_window[i],
|
||||
&rp->reg_window[i],
|
||||
sizeof(struct reg_window));
|
||||
err |= __get_user(t->rwbuf_stkptrs[i],
|
||||
&rp->rwbuf_stkptrs[i]);
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
set_thread_wsaved(wsaved);
|
||||
synchronize_user_stack();
|
||||
if (get_thread_wsaved())
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
#include <asm/cpudata.h>
|
||||
@@ -38,5 +39,15 @@ EXPORT_SYMBOL(sun4v_niagara_setperf);
|
||||
EXPORT_SYMBOL(sun4v_niagara2_getperf);
|
||||
EXPORT_SYMBOL(sun4v_niagara2_setperf);
|
||||
|
||||
/* from hweight.S */
|
||||
EXPORT_SYMBOL(__arch_hweight8);
|
||||
EXPORT_SYMBOL(__arch_hweight16);
|
||||
EXPORT_SYMBOL(__arch_hweight32);
|
||||
EXPORT_SYMBOL(__arch_hweight64);
|
||||
|
||||
/* from ffs_ffz.S */
|
||||
EXPORT_SYMBOL(ffs);
|
||||
EXPORT_SYMBOL(__ffs);
|
||||
|
||||
/* Exporting a symbol from /init/main.c */
|
||||
EXPORT_SYMBOL(saved_command_line);
|
||||
|
||||
@@ -14,15 +14,10 @@
|
||||
#include <asm/head.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "kernel.h"
|
||||
|
||||
static int hv_supports_soft_state;
|
||||
|
||||
static unsigned long kimage_addr_to_ra(const char *p)
|
||||
{
|
||||
unsigned long val = (unsigned long) p;
|
||||
|
||||
return kern_base + (val - KERNBASE);
|
||||
}
|
||||
|
||||
static void do_set_sstate(unsigned long state, const char *msg)
|
||||
{
|
||||
unsigned long err;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <asm/fpumacro.h>
|
||||
|
||||
enum direction {
|
||||
@@ -373,16 +374,11 @@ asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn)
|
||||
}
|
||||
}
|
||||
|
||||
static char popc_helper[] = {
|
||||
0, 1, 1, 2, 1, 2, 2, 3,
|
||||
1, 2, 2, 3, 2, 3, 3, 4,
|
||||
};
|
||||
|
||||
int handle_popc(u32 insn, struct pt_regs *regs)
|
||||
{
|
||||
u64 value;
|
||||
int ret, i, rd = ((insn >> 25) & 0x1f);
|
||||
int from_kernel = (regs->tstate & TSTATE_PRIV) != 0;
|
||||
int ret, rd = ((insn >> 25) & 0x1f);
|
||||
u64 value;
|
||||
|
||||
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, 0, regs, 0);
|
||||
if (insn & 0x2000) {
|
||||
@@ -392,10 +388,7 @@ int handle_popc(u32 insn, struct pt_regs *regs)
|
||||
maybe_flush_windows(0, insn & 0x1f, rd, from_kernel);
|
||||
value = fetch_reg(insn & 0x1f, regs);
|
||||
}
|
||||
for (ret = 0, i = 0; i < 16; i++) {
|
||||
ret += popc_helper[value & 0xf];
|
||||
value >>= 4;
|
||||
}
|
||||
ret = hweight64(value);
|
||||
if (rd < 16) {
|
||||
if (rd)
|
||||
regs->u_regs[rd] = ret;
|
||||
|
||||
@@ -107,7 +107,26 @@ SECTIONS
|
||||
*(.sun4v_2insn_patch)
|
||||
__sun4v_2insn_patch_end = .;
|
||||
}
|
||||
|
||||
.swapper_tsb_phys_patch : {
|
||||
__swapper_tsb_phys_patch = .;
|
||||
*(.swapper_tsb_phys_patch)
|
||||
__swapper_tsb_phys_patch_end = .;
|
||||
}
|
||||
.swapper_4m_tsb_phys_patch : {
|
||||
__swapper_4m_tsb_phys_patch = .;
|
||||
*(.swapper_4m_tsb_phys_patch)
|
||||
__swapper_4m_tsb_phys_patch_end = .;
|
||||
}
|
||||
.popc_3insn_patch : {
|
||||
__popc_3insn_patch = .;
|
||||
*(.popc_3insn_patch)
|
||||
__popc_3insn_patch_end = .;
|
||||
}
|
||||
.popc_6insn_patch : {
|
||||
__popc_6insn_patch = .;
|
||||
*(.popc_6insn_patch)
|
||||
__popc_6insn_patch_end = .;
|
||||
}
|
||||
PERCPU_SECTION(SMP_CACHE_BYTES)
|
||||
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
|
||||
@@ -31,13 +31,13 @@ lib-$(CONFIG_SPARC64) += NGmemcpy.o NGcopy_from_user.o NGcopy_to_user.o
|
||||
lib-$(CONFIG_SPARC64) += NGpatch.o NGpage.o NGbzero.o
|
||||
|
||||
lib-$(CONFIG_SPARC64) += NG2memcpy.o NG2copy_from_user.o NG2copy_to_user.o
|
||||
lib-$(CONFIG_SPARC64) += NG2patch.o NG2page.o
|
||||
lib-$(CONFIG_SPARC64) += NG2patch.o
|
||||
|
||||
lib-$(CONFIG_SPARC64) += GENmemcpy.o GENcopy_from_user.o GENcopy_to_user.o
|
||||
lib-$(CONFIG_SPARC64) += GENpatch.o GENpage.o GENbzero.o
|
||||
|
||||
lib-$(CONFIG_SPARC64) += copy_in_user.o user_fixup.o memmove.o
|
||||
lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o
|
||||
lib-$(CONFIG_SPARC64) += mcount.o ipcsum.o xor.o hweight.o ffs.o
|
||||
|
||||
obj-y += iomap.o
|
||||
obj-$(CONFIG_SPARC32) += atomic32.o
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/* NG2page.S: Niagara-2 optimized clear and copy page.
|
||||
*
|
||||
* Copyright (C) 2007 (davem@davemloft.net)
|
||||
*/
|
||||
|
||||
#include <asm/asi.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/visasm.h>
|
||||
|
||||
.text
|
||||
.align 32
|
||||
|
||||
/* This is heavily simplified from the sun4u variants
|
||||
* because Niagara-2 does not have any D-cache aliasing issues.
|
||||
*/
|
||||
NG2copy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
|
||||
prefetch [%o1 + 0x00], #one_read
|
||||
prefetch [%o1 + 0x40], #one_read
|
||||
VISEntryHalf
|
||||
set PAGE_SIZE, %g7
|
||||
sub %o0, %o1, %g3
|
||||
1: stxa %g0, [%o1 + %g3] ASI_BLK_INIT_QUAD_LDD_P
|
||||
subcc %g7, 64, %g7
|
||||
ldda [%o1] ASI_BLK_P, %f0
|
||||
stda %f0, [%o1 + %g3] ASI_BLK_P
|
||||
add %o1, 64, %o1
|
||||
bne,pt %xcc, 1b
|
||||
prefetch [%o1 + 0x40], #one_read
|
||||
membar #Sync
|
||||
VISExitHalf
|
||||
retl
|
||||
nop
|
||||
|
||||
#define BRANCH_ALWAYS 0x10680000
|
||||
#define NOP 0x01000000
|
||||
#define NG_DO_PATCH(OLD, NEW) \
|
||||
sethi %hi(NEW), %g1; \
|
||||
or %g1, %lo(NEW), %g1; \
|
||||
sethi %hi(OLD), %g2; \
|
||||
or %g2, %lo(OLD), %g2; \
|
||||
sub %g1, %g2, %g1; \
|
||||
sethi %hi(BRANCH_ALWAYS), %g3; \
|
||||
sll %g1, 11, %g1; \
|
||||
srl %g1, 11 + 2, %g1; \
|
||||
or %g3, %lo(BRANCH_ALWAYS), %g3; \
|
||||
or %g3, %g1, %g3; \
|
||||
stw %g3, [%g2]; \
|
||||
sethi %hi(NOP), %g3; \
|
||||
or %g3, %lo(NOP), %g3; \
|
||||
stw %g3, [%g2 + 0x4]; \
|
||||
flush %g2;
|
||||
|
||||
.globl niagara2_patch_pageops
|
||||
.type niagara2_patch_pageops,#function
|
||||
niagara2_patch_pageops:
|
||||
NG_DO_PATCH(copy_user_page, NG2copy_user_page)
|
||||
NG_DO_PATCH(_clear_page, NGclear_page)
|
||||
NG_DO_PATCH(clear_user_page, NGclear_user_page)
|
||||
retl
|
||||
nop
|
||||
.size niagara2_patch_pageops,.-niagara2_patch_pageops
|
||||
+75
-39
@@ -16,55 +16,91 @@
|
||||
*/
|
||||
|
||||
NGcopy_user_page: /* %o0=dest, %o1=src, %o2=vaddr */
|
||||
prefetch [%o1 + 0x00], #one_read
|
||||
mov 8, %g1
|
||||
mov 16, %g2
|
||||
mov 24, %g3
|
||||
save %sp, -192, %sp
|
||||
rd %asi, %g3
|
||||
wr %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi
|
||||
set PAGE_SIZE, %g7
|
||||
prefetch [%i1 + 0x00], #one_read
|
||||
prefetch [%i1 + 0x40], #one_read
|
||||
|
||||
1: ldda [%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2
|
||||
ldda [%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4
|
||||
prefetch [%o1 + 0x40], #one_read
|
||||
add %o1, 32, %o1
|
||||
stxa %o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
|
||||
stxa %o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
|
||||
ldda [%o1 + %g0] ASI_BLK_INIT_QUAD_LDD_P, %o2
|
||||
stxa %o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
|
||||
stxa %o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
|
||||
ldda [%o1 + %g2] ASI_BLK_INIT_QUAD_LDD_P, %o4
|
||||
add %o1, 32, %o1
|
||||
add %o0, 32, %o0
|
||||
stxa %o2, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
|
||||
stxa %o3, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
|
||||
stxa %o4, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
|
||||
stxa %o5, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
|
||||
subcc %g7, 64, %g7
|
||||
1: prefetch [%i1 + 0x80], #one_read
|
||||
prefetch [%i1 + 0xc0], #one_read
|
||||
ldda [%i1 + 0x00] %asi, %o2
|
||||
ldda [%i1 + 0x10] %asi, %o4
|
||||
ldda [%i1 + 0x20] %asi, %l2
|
||||
ldda [%i1 + 0x30] %asi, %l4
|
||||
stxa %o2, [%i0 + 0x00] %asi
|
||||
stxa %o3, [%i0 + 0x08] %asi
|
||||
stxa %o4, [%i0 + 0x10] %asi
|
||||
stxa %o5, [%i0 + 0x18] %asi
|
||||
stxa %l2, [%i0 + 0x20] %asi
|
||||
stxa %l3, [%i0 + 0x28] %asi
|
||||
stxa %l4, [%i0 + 0x30] %asi
|
||||
stxa %l5, [%i0 + 0x38] %asi
|
||||
ldda [%i1 + 0x40] %asi, %o2
|
||||
ldda [%i1 + 0x50] %asi, %o4
|
||||
ldda [%i1 + 0x60] %asi, %l2
|
||||
ldda [%i1 + 0x70] %asi, %l4
|
||||
stxa %o2, [%i0 + 0x40] %asi
|
||||
stxa %o3, [%i0 + 0x48] %asi
|
||||
stxa %o4, [%i0 + 0x50] %asi
|
||||
stxa %o5, [%i0 + 0x58] %asi
|
||||
stxa %l2, [%i0 + 0x60] %asi
|
||||
stxa %l3, [%i0 + 0x68] %asi
|
||||
stxa %l4, [%i0 + 0x70] %asi
|
||||
stxa %l5, [%i0 + 0x78] %asi
|
||||
add %i1, 128, %i1
|
||||
subcc %g7, 128, %g7
|
||||
bne,pt %xcc, 1b
|
||||
add %o0, 32, %o0
|
||||
add %i0, 128, %i0
|
||||
wr %g3, 0x0, %asi
|
||||
membar #Sync
|
||||
retl
|
||||
nop
|
||||
ret
|
||||
restore
|
||||
|
||||
.globl NGclear_page, NGclear_user_page
|
||||
.align 32
|
||||
NGclear_page: /* %o0=dest */
|
||||
NGclear_user_page: /* %o0=dest, %o1=vaddr */
|
||||
mov 8, %g1
|
||||
mov 16, %g2
|
||||
mov 24, %g3
|
||||
rd %asi, %g3
|
||||
wr %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi
|
||||
set PAGE_SIZE, %g7
|
||||
|
||||
1: stxa %g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
|
||||
stxa %g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
|
||||
stxa %g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
|
||||
stxa %g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
|
||||
add %o0, 32, %o0
|
||||
stxa %g0, [%o0 + %g0] ASI_BLK_INIT_QUAD_LDD_P
|
||||
stxa %g0, [%o0 + %g1] ASI_BLK_INIT_QUAD_LDD_P
|
||||
stxa %g0, [%o0 + %g2] ASI_BLK_INIT_QUAD_LDD_P
|
||||
stxa %g0, [%o0 + %g3] ASI_BLK_INIT_QUAD_LDD_P
|
||||
subcc %g7, 64, %g7
|
||||
1: stxa %g0, [%o0 + 0x00] %asi
|
||||
stxa %g0, [%o0 + 0x08] %asi
|
||||
stxa %g0, [%o0 + 0x10] %asi
|
||||
stxa %g0, [%o0 + 0x18] %asi
|
||||
stxa %g0, [%o0 + 0x20] %asi
|
||||
stxa %g0, [%o0 + 0x28] %asi
|
||||
stxa %g0, [%o0 + 0x30] %asi
|
||||
stxa %g0, [%o0 + 0x38] %asi
|
||||
stxa %g0, [%o0 + 0x40] %asi
|
||||
stxa %g0, [%o0 + 0x48] %asi
|
||||
stxa %g0, [%o0 + 0x50] %asi
|
||||
stxa %g0, [%o0 + 0x58] %asi
|
||||
stxa %g0, [%o0 + 0x60] %asi
|
||||
stxa %g0, [%o0 + 0x68] %asi
|
||||
stxa %g0, [%o0 + 0x70] %asi
|
||||
stxa %g0, [%o0 + 0x78] %asi
|
||||
stxa %g0, [%o0 + 0x80] %asi
|
||||
stxa %g0, [%o0 + 0x88] %asi
|
||||
stxa %g0, [%o0 + 0x90] %asi
|
||||
stxa %g0, [%o0 + 0x98] %asi
|
||||
stxa %g0, [%o0 + 0xa0] %asi
|
||||
stxa %g0, [%o0 + 0xa8] %asi
|
||||
stxa %g0, [%o0 + 0xb0] %asi
|
||||
stxa %g0, [%o0 + 0xb8] %asi
|
||||
stxa %g0, [%o0 + 0xc0] %asi
|
||||
stxa %g0, [%o0 + 0xc8] %asi
|
||||
stxa %g0, [%o0 + 0xd0] %asi
|
||||
stxa %g0, [%o0 + 0xd8] %asi
|
||||
stxa %g0, [%o0 + 0xe0] %asi
|
||||
stxa %g0, [%o0 + 0xe8] %asi
|
||||
stxa %g0, [%o0 + 0xf0] %asi
|
||||
stxa %g0, [%o0 + 0xf8] %asi
|
||||
subcc %g7, 256, %g7
|
||||
bne,pt %xcc, 1b
|
||||
add %o0, 32, %o0
|
||||
add %o0, 256, %o0
|
||||
wr %g3, 0x0, %asi
|
||||
membar #Sync
|
||||
retl
|
||||
nop
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
#include <linux/linkage.h>
|
||||
|
||||
.register %g2,#scratch
|
||||
|
||||
.text
|
||||
.align 32
|
||||
|
||||
ENTRY(ffs)
|
||||
brnz,pt %o0, 1f
|
||||
mov 1, %o1
|
||||
retl
|
||||
clr %o0
|
||||
nop
|
||||
nop
|
||||
ENTRY(__ffs)
|
||||
sllx %o0, 32, %g1 /* 1 */
|
||||
srlx %o0, 32, %g2
|
||||
|
||||
clr %o1 /* 2 */
|
||||
movrz %g1, %g2, %o0
|
||||
|
||||
movrz %g1, 32, %o1 /* 3 */
|
||||
1: clr %o2
|
||||
|
||||
sllx %o0, (64 - 16), %g1 /* 4 */
|
||||
srlx %o0, 16, %g2
|
||||
|
||||
movrz %g1, %g2, %o0 /* 5 */
|
||||
clr %o3
|
||||
|
||||
movrz %g1, 16, %o2 /* 6 */
|
||||
clr %o4
|
||||
|
||||
and %o0, 0xff, %g1 /* 7 */
|
||||
srlx %o0, 8, %g2
|
||||
|
||||
movrz %g1, %g2, %o0 /* 8 */
|
||||
clr %o5
|
||||
|
||||
movrz %g1, 8, %o3 /* 9 */
|
||||
add %o2, %o1, %o2
|
||||
|
||||
and %o0, 0xf, %g1 /* 10 */
|
||||
srlx %o0, 4, %g2
|
||||
|
||||
movrz %g1, %g2, %o0 /* 11 */
|
||||
add %o2, %o3, %o2
|
||||
|
||||
movrz %g1, 4, %o4 /* 12 */
|
||||
|
||||
and %o0, 0x3, %g1 /* 13 */
|
||||
srlx %o0, 2, %g2
|
||||
|
||||
movrz %g1, %g2, %o0 /* 14 */
|
||||
add %o2, %o4, %o2
|
||||
|
||||
movrz %g1, 2, %o5 /* 15 */
|
||||
|
||||
and %o0, 0x1, %g1 /* 16 */
|
||||
|
||||
add %o2, %o5, %o2 /* 17 */
|
||||
xor %g1, 0x1, %g1
|
||||
|
||||
retl /* 18 */
|
||||
add %o2, %g1, %o0
|
||||
ENDPROC(ffs)
|
||||
ENDPROC(__ffs)
|
||||
|
||||
.section .popc_6insn_patch, "ax"
|
||||
.word ffs
|
||||
brz,pn %o0, 98f
|
||||
neg %o0, %g1
|
||||
xnor %o0, %g1, %o1
|
||||
popc %o1, %o0
|
||||
98: retl
|
||||
nop
|
||||
.word __ffs
|
||||
neg %o0, %g1
|
||||
xnor %o0, %g1, %o1
|
||||
popc %o1, %o0
|
||||
retl
|
||||
sub %o0, 1, %o0
|
||||
nop
|
||||
.previous
|
||||
@@ -0,0 +1,51 @@
|
||||
#include <linux/linkage.h>
|
||||
|
||||
.text
|
||||
.align 32
|
||||
ENTRY(__arch_hweight8)
|
||||
ba,pt %xcc, __sw_hweight8
|
||||
nop
|
||||
nop
|
||||
ENDPROC(__arch_hweight8)
|
||||
.section .popc_3insn_patch, "ax"
|
||||
.word __arch_hweight8
|
||||
sllx %o0, 64-8, %g1
|
||||
retl
|
||||
popc %g1, %o0
|
||||
.previous
|
||||
|
||||
ENTRY(__arch_hweight16)
|
||||
ba,pt %xcc, __sw_hweight16
|
||||
nop
|
||||
nop
|
||||
ENDPROC(__arch_hweight16)
|
||||
.section .popc_3insn_patch, "ax"
|
||||
.word __arch_hweight16
|
||||
sllx %o0, 64-16, %g1
|
||||
retl
|
||||
popc %g1, %o0
|
||||
.previous
|
||||
|
||||
ENTRY(__arch_hweight32)
|
||||
ba,pt %xcc, __sw_hweight32
|
||||
nop
|
||||
nop
|
||||
ENDPROC(__arch_hweight32)
|
||||
.section .popc_3insn_patch, "ax"
|
||||
.word __arch_hweight32
|
||||
sllx %o0, 64-32, %g1
|
||||
retl
|
||||
popc %g1, %o0
|
||||
.previous
|
||||
|
||||
ENTRY(__arch_hweight64)
|
||||
ba,pt %xcc, __sw_hweight64
|
||||
nop
|
||||
nop
|
||||
ENDPROC(__arch_hweight64)
|
||||
.section .popc_3insn_patch, "ax"
|
||||
.word __arch_hweight64
|
||||
retl
|
||||
popc %o0, %o0
|
||||
nop
|
||||
.previous
|
||||
+46
-1
@@ -511,6 +511,11 @@ static void __init read_obp_translations(void)
|
||||
for (i = 0; i < prom_trans_ents; i++)
|
||||
prom_trans[i].data &= ~0x0003fe0000000000UL;
|
||||
}
|
||||
|
||||
/* Force execute bit on. */
|
||||
for (i = 0; i < prom_trans_ents; i++)
|
||||
prom_trans[i].data |= (tlb_type == hypervisor ?
|
||||
_PAGE_EXEC_4V : _PAGE_EXEC_4U);
|
||||
}
|
||||
|
||||
static void __init hypervisor_tlb_lock(unsigned long vaddr,
|
||||
@@ -1597,6 +1602,44 @@ static void __init tsb_phys_patch(void)
|
||||
static struct hv_tsb_descr ktsb_descr[NUM_KTSB_DESCR];
|
||||
extern struct tsb swapper_tsb[KERNEL_TSB_NENTRIES];
|
||||
|
||||
static void patch_one_ktsb_phys(unsigned int *start, unsigned int *end, unsigned long pa)
|
||||
{
|
||||
pa >>= KTSB_PHYS_SHIFT;
|
||||
|
||||
while (start < end) {
|
||||
unsigned int *ia = (unsigned int *)(unsigned long)*start;
|
||||
|
||||
ia[0] = (ia[0] & ~0x3fffff) | (pa >> 10);
|
||||
__asm__ __volatile__("flush %0" : : "r" (ia));
|
||||
|
||||
ia[1] = (ia[1] & ~0x3ff) | (pa & 0x3ff);
|
||||
__asm__ __volatile__("flush %0" : : "r" (ia + 1));
|
||||
|
||||
start++;
|
||||
}
|
||||
}
|
||||
|
||||
static void ktsb_phys_patch(void)
|
||||
{
|
||||
extern unsigned int __swapper_tsb_phys_patch;
|
||||
extern unsigned int __swapper_tsb_phys_patch_end;
|
||||
unsigned long ktsb_pa;
|
||||
|
||||
ktsb_pa = kern_base + ((unsigned long)&swapper_tsb[0] - KERNBASE);
|
||||
patch_one_ktsb_phys(&__swapper_tsb_phys_patch,
|
||||
&__swapper_tsb_phys_patch_end, ktsb_pa);
|
||||
#ifndef CONFIG_DEBUG_PAGEALLOC
|
||||
{
|
||||
extern unsigned int __swapper_4m_tsb_phys_patch;
|
||||
extern unsigned int __swapper_4m_tsb_phys_patch_end;
|
||||
ktsb_pa = (kern_base +
|
||||
((unsigned long)&swapper_4m_tsb[0] - KERNBASE));
|
||||
patch_one_ktsb_phys(&__swapper_4m_tsb_phys_patch,
|
||||
&__swapper_4m_tsb_phys_patch_end, ktsb_pa);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void __init sun4v_ktsb_init(void)
|
||||
{
|
||||
unsigned long ktsb_pa;
|
||||
@@ -1716,8 +1759,10 @@ void __init paging_init(void)
|
||||
sun4u_pgprot_init();
|
||||
|
||||
if (tlb_type == cheetah_plus ||
|
||||
tlb_type == hypervisor)
|
||||
tlb_type == hypervisor) {
|
||||
tsb_phys_patch();
|
||||
ktsb_phys_patch();
|
||||
}
|
||||
|
||||
if (tlb_type == hypervisor) {
|
||||
sun4v_patch_tlb_handlers();
|
||||
|
||||
@@ -39,7 +39,7 @@ typedef struct xpaddr {
|
||||
((unsigned long)((u64)CONFIG_XEN_MAX_DOMAIN_MEMORY * 1024 * 1024 * 1024 / PAGE_SIZE))
|
||||
|
||||
extern unsigned long *machine_to_phys_mapping;
|
||||
extern unsigned int machine_to_phys_order;
|
||||
extern unsigned long machine_to_phys_nr;
|
||||
|
||||
extern unsigned long get_phys_to_machine(unsigned long pfn);
|
||||
extern bool set_phys_to_machine(unsigned long pfn, unsigned long mfn);
|
||||
@@ -87,7 +87,7 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
|
||||
if (xen_feature(XENFEAT_auto_translated_physmap))
|
||||
return mfn;
|
||||
|
||||
if (unlikely((mfn >> machine_to_phys_order) != 0)) {
|
||||
if (unlikely(mfn >= machine_to_phys_nr)) {
|
||||
pfn = ~0;
|
||||
goto try_override;
|
||||
}
|
||||
|
||||
@@ -531,7 +531,9 @@ static void build_inv_all(struct iommu_cmd *cmd)
|
||||
* Writes the command to the IOMMUs command buffer and informs the
|
||||
* hardware about the new command.
|
||||
*/
|
||||
static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
|
||||
static int iommu_queue_command_sync(struct amd_iommu *iommu,
|
||||
struct iommu_cmd *cmd,
|
||||
bool sync)
|
||||
{
|
||||
u32 left, tail, head, next_tail;
|
||||
unsigned long flags;
|
||||
@@ -565,13 +567,18 @@ again:
|
||||
copy_cmd_to_buffer(iommu, cmd, tail);
|
||||
|
||||
/* We need to sync now to make sure all commands are processed */
|
||||
iommu->need_sync = true;
|
||||
iommu->need_sync = sync;
|
||||
|
||||
spin_unlock_irqrestore(&iommu->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iommu_queue_command(struct amd_iommu *iommu, struct iommu_cmd *cmd)
|
||||
{
|
||||
return iommu_queue_command_sync(iommu, cmd, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function queues a completion wait command into the command
|
||||
* buffer of an IOMMU
|
||||
@@ -587,7 +594,7 @@ static int iommu_completion_wait(struct amd_iommu *iommu)
|
||||
|
||||
build_completion_wait(&cmd, (u64)&sem);
|
||||
|
||||
ret = iommu_queue_command(iommu, &cmd);
|
||||
ret = iommu_queue_command_sync(iommu, &cmd, false);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -773,14 +780,9 @@ static void domain_flush_complete(struct protection_domain *domain)
|
||||
static void domain_flush_devices(struct protection_domain *domain)
|
||||
{
|
||||
struct iommu_dev_data *dev_data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&domain->lock, flags);
|
||||
|
||||
list_for_each_entry(dev_data, &domain->dev_list, list)
|
||||
device_flush_dte(dev_data->dev);
|
||||
|
||||
spin_unlock_irqrestore(&domain->lock, flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@@ -207,7 +207,6 @@ static int __cpuinit uv_wakeup_secondary(int phys_apicid, unsigned long start_ri
|
||||
((start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) |
|
||||
APIC_DM_INIT;
|
||||
uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
|
||||
mdelay(10);
|
||||
|
||||
val = (1UL << UVH_IPI_INT_SEND_SHFT) |
|
||||
(phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) |
|
||||
|
||||
@@ -465,11 +465,11 @@ static void __cpuinit init_intel(struct cpuinfo_x86 *c)
|
||||
u64 epb;
|
||||
|
||||
rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
|
||||
if ((epb & 0xF) == 0) {
|
||||
printk_once(KERN_WARNING, "x86: updated energy_perf_bias"
|
||||
" to 'normal' from 'performance'\n"
|
||||
"You can view and update epb via utility,"
|
||||
" such as x86_energy_perf_policy(8)\n");
|
||||
if ((epb & 0xF) == ENERGY_PERF_BIAS_PERFORMANCE) {
|
||||
printk_once(KERN_WARNING "ENERGY_PERF_BIAS:"
|
||||
" Set to 'normal', was 'performance'\n"
|
||||
"ENERGY_PERF_BIAS: View and update with"
|
||||
" x86_energy_perf_policy(8)\n");
|
||||
epb = (epb & ~0xF) | ENERGY_PERF_BIAS_NORMAL;
|
||||
wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb);
|
||||
}
|
||||
|
||||
@@ -248,6 +248,25 @@ set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type typ
|
||||
unsigned long flags;
|
||||
int cpu;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
* If this cpu is not yet active, we are in the cpu online path. There
|
||||
* can be no stop_machine() in parallel, as stop machine ensures this
|
||||
* by using get_online_cpus(). We can skip taking the stop_cpus_mutex,
|
||||
* as we don't need it and also we can't afford to block while waiting
|
||||
* for the mutex.
|
||||
*
|
||||
* If this cpu is active, we need to prevent stop_machine() happening
|
||||
* in parallel by taking the stop cpus mutex.
|
||||
*
|
||||
* Also, this is called in the context of cpu online path or in the
|
||||
* context where cpu hotplug is prevented. So checking the active status
|
||||
* of the raw_smp_processor_id() is safe.
|
||||
*/
|
||||
if (cpu_active(raw_smp_processor_id()))
|
||||
mutex_lock(&stop_cpus_mutex);
|
||||
#endif
|
||||
|
||||
preempt_disable();
|
||||
|
||||
data.smp_reg = reg;
|
||||
@@ -330,6 +349,10 @@ set_mtrr(unsigned int reg, unsigned long base, unsigned long size, mtrr_type typ
|
||||
|
||||
local_irq_restore(flags);
|
||||
preempt_enable();
|
||||
#ifdef CONFIG_SMP
|
||||
if (cpu_active(raw_smp_processor_id()))
|
||||
mutex_unlock(&stop_cpus_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1856,6 +1856,9 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
|
||||
|
||||
perf_callchain_store(entry, regs->ip);
|
||||
|
||||
if (!current->mm)
|
||||
return;
|
||||
|
||||
if (perf_callchain_user32(regs, entry))
|
||||
return;
|
||||
|
||||
|
||||
@@ -1495,6 +1495,7 @@ static __init int intel_pmu_init(void)
|
||||
break;
|
||||
|
||||
case 42: /* SandyBridge */
|
||||
case 45: /* SandyBridge, "Romely-EP" */
|
||||
memcpy(hw_cache_event_ids, snb_hw_cache_event_ids,
|
||||
sizeof(hw_cache_event_ids));
|
||||
|
||||
|
||||
+1
-2
@@ -63,9 +63,8 @@ static void __init find_early_table_space(unsigned long end, int use_pse,
|
||||
#ifdef CONFIG_X86_32
|
||||
/* for fixmap */
|
||||
tables += roundup(__end_of_fixed_addresses * sizeof(pte_t), PAGE_SIZE);
|
||||
|
||||
good_end = max_pfn_mapped << PAGE_SHIFT;
|
||||
#endif
|
||||
good_end = max_pfn_mapped << PAGE_SHIFT;
|
||||
|
||||
base = memblock_find_in_range(start, good_end, tables, PAGE_SIZE);
|
||||
if (base == MEMBLOCK_ERROR)
|
||||
|
||||
@@ -43,6 +43,17 @@ static const struct dmi_system_id pci_use_crs_table[] __initconst = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "ALiveSATA2-GLAN"),
|
||||
},
|
||||
},
|
||||
/* https://bugzilla.kernel.org/show_bug.cgi?id=30552 */
|
||||
/* 2006 AMD HT/VIA system with two host bridges */
|
||||
{
|
||||
.callback = set_use_crs,
|
||||
.ident = "ASUS M2V-MX SE",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "M2V-MX SE"),
|
||||
DMI_MATCH(DMI_BIOS_VENDOR, "American Megatrends Inc."),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -157,13 +157,13 @@ restart:
|
||||
if (inbuf && inlen) {
|
||||
/* write data to EC */
|
||||
for (i = 0; i < inlen; i++) {
|
||||
pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]);
|
||||
outb(inbuf[i], 0x68);
|
||||
if (wait_on_ibf(0x6c, 0)) {
|
||||
printk(KERN_ERR "olpc-ec: timeout waiting for"
|
||||
" EC accept data!\n");
|
||||
goto err;
|
||||
}
|
||||
pr_devel("olpc-ec: sending cmd arg 0x%x\n", inbuf[i]);
|
||||
outb(inbuf[i], 0x68);
|
||||
}
|
||||
}
|
||||
if (outbuf && outlen) {
|
||||
|
||||
@@ -43,7 +43,7 @@ __kernel_vsyscall:
|
||||
.space 7,0x90
|
||||
|
||||
/* 14: System call restart point is here! (SYSENTER_RETURN-2) */
|
||||
jmp .Lenter_kernel
|
||||
int $0x80
|
||||
/* 16: System call normal return point is here! */
|
||||
VDSO32_SYSENTER_RETURN: /* Symbol used by sysenter.c via vdso32-syms.h */
|
||||
pop %ebp
|
||||
|
||||
@@ -18,5 +18,5 @@ obj-y := enlighten.o setup.o multicalls.o mmu.o irq.o \
|
||||
obj-$(CONFIG_SMP) += smp.o
|
||||
obj-$(CONFIG_PARAVIRT_SPINLOCKS)+= spinlock.o
|
||||
obj-$(CONFIG_XEN_DEBUG_FS) += debugfs.o
|
||||
|
||||
obj-$(CONFIG_XEN_DOM0) += vga.o
|
||||
obj-$(CONFIG_SWIOTLB_XEN) += pci-swiotlb-xen.o
|
||||
|
||||
@@ -77,8 +77,8 @@ EXPORT_SYMBOL_GPL(xen_domain_type);
|
||||
|
||||
unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START;
|
||||
EXPORT_SYMBOL(machine_to_phys_mapping);
|
||||
unsigned int machine_to_phys_order;
|
||||
EXPORT_SYMBOL(machine_to_phys_order);
|
||||
unsigned long machine_to_phys_nr;
|
||||
EXPORT_SYMBOL(machine_to_phys_nr);
|
||||
|
||||
struct start_info *xen_start_info;
|
||||
EXPORT_SYMBOL_GPL(xen_start_info);
|
||||
@@ -1248,6 +1248,14 @@ asmlinkage void __init xen_start_kernel(void)
|
||||
if (pci_xen)
|
||||
x86_init.pci.arch_init = pci_xen_init;
|
||||
} else {
|
||||
const struct dom0_vga_console_info *info =
|
||||
(void *)((char *)xen_start_info +
|
||||
xen_start_info->console.dom0.info_off);
|
||||
|
||||
xen_init_vga(info, xen_start_info->console.dom0.info_size);
|
||||
xen_start_info->console.domU.mfn = 0;
|
||||
xen_start_info->console.domU.evtchn = 0;
|
||||
|
||||
/* Make sure ACS will be enabled */
|
||||
pci_request_acs();
|
||||
}
|
||||
|
||||
+8
-4
@@ -1626,15 +1626,19 @@ static void __init xen_map_identity_early(pmd_t *pmd, unsigned long max_pfn)
|
||||
void __init xen_setup_machphys_mapping(void)
|
||||
{
|
||||
struct xen_machphys_mapping mapping;
|
||||
unsigned long machine_to_phys_nr_ents;
|
||||
|
||||
if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
|
||||
machine_to_phys_mapping = (unsigned long *)mapping.v_start;
|
||||
machine_to_phys_nr_ents = mapping.max_mfn + 1;
|
||||
machine_to_phys_nr = mapping.max_mfn + 1;
|
||||
} else {
|
||||
machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
|
||||
machine_to_phys_nr = MACH2PHYS_NR_ENTRIES;
|
||||
}
|
||||
machine_to_phys_order = fls(machine_to_phys_nr_ents - 1);
|
||||
#ifdef CONFIG_X86_32
|
||||
if ((machine_to_phys_mapping + machine_to_phys_nr)
|
||||
< machine_to_phys_mapping)
|
||||
machine_to_phys_nr = (unsigned long *)NULL
|
||||
- machine_to_phys_mapping;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
|
||||
@@ -185,6 +185,19 @@ static unsigned long __init xen_set_identity(const struct e820entry *list,
|
||||
PFN_UP(start_pci), PFN_DOWN(last));
|
||||
return identity;
|
||||
}
|
||||
|
||||
static unsigned long __init xen_get_max_pages(void)
|
||||
{
|
||||
unsigned long max_pages = MAX_DOMAIN_PAGES;
|
||||
domid_t domid = DOMID_SELF;
|
||||
int ret;
|
||||
|
||||
ret = HYPERVISOR_memory_op(XENMEM_maximum_reservation, &domid);
|
||||
if (ret > 0)
|
||||
max_pages = ret;
|
||||
return min(max_pages, MAX_DOMAIN_PAGES);
|
||||
}
|
||||
|
||||
/**
|
||||
* machine_specific_memory_setup - Hook for machine specific memory setup.
|
||||
**/
|
||||
@@ -293,6 +306,14 @@ char * __init xen_memory_setup(void)
|
||||
|
||||
sanitize_e820_map(e820.map, ARRAY_SIZE(e820.map), &e820.nr_map);
|
||||
|
||||
extra_limit = xen_get_max_pages();
|
||||
if (max_pfn + extra_pages > extra_limit) {
|
||||
if (extra_limit > max_pfn)
|
||||
extra_pages = extra_limit - max_pfn;
|
||||
else
|
||||
extra_pages = 0;
|
||||
}
|
||||
|
||||
extra_pages += xen_return_unused_memory(xen_start_info->nr_pages, &e820);
|
||||
|
||||
/*
|
||||
|
||||
+12
-2
@@ -32,6 +32,7 @@
|
||||
#include <xen/page.h>
|
||||
#include <xen/events.h>
|
||||
|
||||
#include <xen/hvc-console.h>
|
||||
#include "xen-ops.h"
|
||||
#include "mmu.h"
|
||||
|
||||
@@ -207,6 +208,15 @@ static void __init xen_smp_prepare_cpus(unsigned int max_cpus)
|
||||
unsigned cpu;
|
||||
unsigned int i;
|
||||
|
||||
if (skip_ioapic_setup) {
|
||||
char *m = (max_cpus == 0) ?
|
||||
"The nosmp parameter is incompatible with Xen; " \
|
||||
"use Xen dom0_max_vcpus=1 parameter" :
|
||||
"The noapic parameter is incompatible with Xen";
|
||||
|
||||
xen_raw_printk(m);
|
||||
panic(m);
|
||||
}
|
||||
xen_init_lock_cpu(0);
|
||||
|
||||
smp_store_cpu_info(0);
|
||||
@@ -521,8 +531,6 @@ static void __init xen_hvm_smp_prepare_cpus(unsigned int max_cpus)
|
||||
native_smp_prepare_cpus(max_cpus);
|
||||
WARN_ON(xen_smp_intr_init(0));
|
||||
|
||||
if (!xen_have_vector_callback)
|
||||
return;
|
||||
xen_init_lock_cpu(0);
|
||||
xen_init_spinlocks();
|
||||
}
|
||||
@@ -546,6 +554,8 @@ static void xen_hvm_cpu_die(unsigned int cpu)
|
||||
|
||||
void __init xen_hvm_smp_init(void)
|
||||
{
|
||||
if (!xen_have_vector_callback)
|
||||
return;
|
||||
smp_ops.smp_prepare_cpus = xen_hvm_smp_prepare_cpus;
|
||||
smp_ops.smp_send_reschedule = xen_smp_send_reschedule;
|
||||
smp_ops.cpu_up = xen_hvm_cpu_up;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user