summaryrefslogtreecommitdiff
path: root/arch/mips/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/Makefile17
-rw-r--r--arch/mips/kernel/asm-offsets.c4
-rw-r--r--arch/mips/kernel/cevt-gt641xx.c10
-rw-r--r--arch/mips/kernel/cevt-r4k.c2
-rw-r--r--arch/mips/kernel/cpu-probe.c43
-rw-r--r--arch/mips/kernel/cpufreq/Kconfig41
-rw-r--r--arch/mips/kernel/cpufreq/Makefile5
-rw-r--r--arch/mips/kernel/cpufreq/loongson2_clock.c170
-rw-r--r--arch/mips/kernel/cpufreq/loongson2_cpufreq.c227
-rw-r--r--arch/mips/kernel/csrc-powertv.c180
-rw-r--r--arch/mips/kernel/ftrace.c275
-rw-r--r--arch/mips/kernel/i8259.c22
-rw-r--r--arch/mips/kernel/irq-gt641xx.c18
-rw-r--r--arch/mips/kernel/irq.c35
-rw-r--r--arch/mips/kernel/kspd.c1
-rw-r--r--arch/mips/kernel/linux32.c99
-rw-r--r--arch/mips/kernel/mcount.S189
-rw-r--r--arch/mips/kernel/mips_ksyms.c5
-rw-r--r--arch/mips/kernel/octeon_switch.S1
-rw-r--r--arch/mips/kernel/process.c8
-rw-r--r--arch/mips/kernel/ptrace.c30
-rw-r--r--arch/mips/kernel/rtlx.c2
-rw-r--r--arch/mips/kernel/scall32-o32.S1
-rw-r--r--arch/mips/kernel/scall64-64.S1
-rw-r--r--arch/mips/kernel/scall64-n32.S5
-rw-r--r--arch/mips/kernel/scall64-o32.S5
-rw-r--r--arch/mips/kernel/setup.c44
-rw-r--r--arch/mips/kernel/signal-common.h5
-rw-r--r--arch/mips/kernel/signal.c130
-rw-r--r--arch/mips/kernel/signal32.c79
-rw-r--r--arch/mips/kernel/signal_n32.c26
-rw-r--r--arch/mips/kernel/smp.c3
-rw-r--r--arch/mips/kernel/smtc.c26
-rw-r--r--arch/mips/kernel/spinlock_test.c141
-rw-r--r--arch/mips/kernel/syscall.c170
-rw-r--r--arch/mips/kernel/time.c33
-rw-r--r--arch/mips/kernel/traps.c168
-rw-r--r--arch/mips/kernel/unaligned.c25
-rw-r--r--arch/mips/kernel/vdso.c112
-rw-r--r--arch/mips/kernel/vmlinux.lds.S1
-rw-r--r--arch/mips/kernel/vpe.c1
41 files changed, 1719 insertions, 641 deletions
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index eecd2a9f155c..7a6ac501cbb5 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -2,13 +2,16 @@
# Makefile for the Linux/MIPS kernel.
#
-CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
-
extra-y := head.o init_task.o vmlinux.lds
obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
ptrace.o reset.o setup.o signal.o syscall.o \
- time.o topology.o traps.o unaligned.o watch.o
+ time.o topology.o traps.o unaligned.o watch.o vdso.o
+
+ifdef CONFIG_FUNCTION_TRACER
+CFLAGS_REMOVE_ftrace.o = -pg
+CFLAGS_REMOVE_early_printk.o = -pg
+endif
obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o
obj-$(CONFIG_CEVT_R4K_LIB) += cevt-r4k.o
@@ -19,6 +22,7 @@ obj-$(CONFIG_CEVT_SB1250) += cevt-sb1250.o
obj-$(CONFIG_CEVT_TXX9) += cevt-txx9.o
obj-$(CONFIG_CSRC_BCM1480) += csrc-bcm1480.o
obj-$(CONFIG_CSRC_IOASIC) += csrc-ioasic.o
+obj-$(CONFIG_CSRC_POWERTV) += csrc-powertv.o
obj-$(CONFIG_CSRC_R4K_LIB) += csrc-r4k.o
obj-$(CONFIG_CSRC_SB1250) += csrc-sb1250.o
obj-$(CONFIG_SYNC_R4K) += sync-r4k.o
@@ -26,6 +30,8 @@ obj-$(CONFIG_SYNC_R4K) += sync-r4k.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_MODULES) += mips_ksyms.o module.o
+obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o
+
obj-$(CONFIG_CPU_LOONGSON2) += r4k_fpu.o r4k_switch.o
obj-$(CONFIG_CPU_MIPS32) += r4k_fpu.o r4k_switch.o
obj-$(CONFIG_CPU_MIPS64) += r4k_fpu.o r4k_switch.o
@@ -87,9 +93,14 @@ obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o
CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o
+obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/
+
EXTRA_CFLAGS += -Werror
+
+CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS)
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index 2c1e1d02338b..ca6c83218caa 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -188,11 +188,15 @@ void output_mm_defines(void)
DEFINE(_PTE_T_SIZE, sizeof(pte_t));
BLANK();
DEFINE(_PGD_T_LOG2, PGD_T_LOG2);
+#ifndef __PAGETABLE_PMD_FOLDED
DEFINE(_PMD_T_LOG2, PMD_T_LOG2);
+#endif
DEFINE(_PTE_T_LOG2, PTE_T_LOG2);
BLANK();
DEFINE(_PGD_ORDER, PGD_ORDER);
+#ifndef __PAGETABLE_PMD_FOLDED
DEFINE(_PMD_ORDER, PMD_ORDER);
+#endif
DEFINE(_PTE_ORDER, PTE_ORDER);
BLANK();
DEFINE(_PMD_SHIFT, PMD_SHIFT);
diff --git a/arch/mips/kernel/cevt-gt641xx.c b/arch/mips/kernel/cevt-gt641xx.c
index f5d265eb6eae..392ef3756c56 100644
--- a/arch/mips/kernel/cevt-gt641xx.c
+++ b/arch/mips/kernel/cevt-gt641xx.c
@@ -25,7 +25,7 @@
#include <asm/gt64120.h>
#include <asm/time.h>
-static DEFINE_SPINLOCK(gt641xx_timer_lock);
+static DEFINE_RAW_SPINLOCK(gt641xx_timer_lock);
static unsigned int gt641xx_base_clock;
void gt641xx_set_base_clock(unsigned int clock)
@@ -49,7 +49,7 @@ static int gt641xx_timer0_set_next_event(unsigned long delta,
{
u32 ctrl;
- spin_lock(&gt641xx_timer_lock);
+ raw_spin_lock(&gt641xx_timer_lock);
ctrl = GT_READ(GT_TC_CONTROL_OFS);
ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
@@ -58,7 +58,7 @@ static int gt641xx_timer0_set_next_event(unsigned long delta,
GT_WRITE(GT_TC0_OFS, delta);
GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
- spin_unlock(&gt641xx_timer_lock);
+ raw_spin_unlock(&gt641xx_timer_lock);
return 0;
}
@@ -68,7 +68,7 @@ static void gt641xx_timer0_set_mode(enum clock_event_mode mode,
{
u32 ctrl;
- spin_lock(&gt641xx_timer_lock);
+ raw_spin_lock(&gt641xx_timer_lock);
ctrl = GT_READ(GT_TC_CONTROL_OFS);
ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK);
@@ -86,7 +86,7 @@ static void gt641xx_timer0_set_mode(enum clock_event_mode mode,
GT_WRITE(GT_TC_CONTROL_OFS, ctrl);
- spin_unlock(&gt641xx_timer_lock);
+ raw_spin_unlock(&gt641xx_timer_lock);
}
static void gt641xx_timer0_event_handler(struct clock_event_device *dev)
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index b469ad05d520..0b2450ceb13f 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -97,7 +97,7 @@ void mips_event_handler(struct clock_event_device *dev)
*/
static int c0_compare_int_pending(void)
{
- return (read_c0_cause() >> cp0_compare_irq) & 0x100;
+ return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP);
}
/*
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 7a51866068a4..be5bb16be4e0 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -16,6 +16,7 @@
#include <linux/ptrace.h>
#include <linux/smp.h>
#include <linux/stddef.h>
+#include <linux/module.h>
#include <asm/bugs.h>
#include <asm/cpu.h>
@@ -32,6 +33,7 @@
* the CPU very much.
*/
void (*cpu_wait)(void);
+EXPORT_SYMBOL(cpu_wait);
static void r3081_wait(void)
{
@@ -160,6 +162,7 @@ void __init check_wait(void)
case CPU_BCM6348:
case CPU_BCM6358:
case CPU_CAVIUM_OCTEON:
+ case CPU_CAVIUM_OCTEON_PLUS:
cpu_wait = r4k_wait;
break;
@@ -282,6 +285,15 @@ static inline int __cpu_has_fpu(void)
return ((cpu_get_fpu_id() & 0xff00) != FPIR_IMP_NONE);
}
+static inline void cpu_probe_vmbits(struct cpuinfo_mips *c)
+{
+#ifdef __NEED_VMBITS_PROBE
+ write_c0_entryhi(0x3fffffffffffe000ULL);
+ back_to_back_c0_hazard();
+ c->vmbits = fls64(read_c0_entryhi() & 0x3fffffffffffe000ULL);
+#endif
+}
+
#define R4K_OPTS (MIPS_CPU_TLB | MIPS_CPU_4KEX | MIPS_CPU_4K_CACHE \
| MIPS_CPU_COUNTER)
@@ -689,6 +701,19 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
return config3 & MIPS_CONF_M;
}
+static inline unsigned int decode_config4(struct cpuinfo_mips *c)
+{
+ unsigned int config4;
+
+ config4 = read_c0_config4();
+
+ if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT
+ && cpu_has_tlb)
+ c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
+
+ return config4 & MIPS_CONF_M;
+}
+
static void __cpuinit decode_configs(struct cpuinfo_mips *c)
{
int ok;
@@ -707,6 +732,8 @@ static void __cpuinit decode_configs(struct cpuinfo_mips *c)
ok = decode_config2(c);
if (ok)
ok = decode_config3(c);
+ if (ok)
+ ok = decode_config4(c);
mips_probe_watch_registers(c);
}
@@ -720,9 +747,6 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
__cpu_name[cpu] = "MIPS 4Kc";
break;
case PRID_IMP_4KEC:
- c->cputype = CPU_4KEC;
- __cpu_name[cpu] = "MIPS 4KEc";
- break;
case PRID_IMP_4KECR2:
c->cputype = CPU_4KEC;
__cpu_name[cpu] = "MIPS 4KEc";
@@ -888,12 +912,18 @@ static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
case PRID_IMP_CAVIUM_CN38XX:
case PRID_IMP_CAVIUM_CN31XX:
case PRID_IMP_CAVIUM_CN30XX:
+ c->cputype = CPU_CAVIUM_OCTEON;
+ __cpu_name[cpu] = "Cavium Octeon";
+ goto platform;
case PRID_IMP_CAVIUM_CN58XX:
case PRID_IMP_CAVIUM_CN56XX:
case PRID_IMP_CAVIUM_CN50XX:
case PRID_IMP_CAVIUM_CN52XX:
- c->cputype = CPU_CAVIUM_OCTEON;
- __cpu_name[cpu] = "Cavium Octeon";
+ c->cputype = CPU_CAVIUM_OCTEON_PLUS;
+ __cpu_name[cpu] = "Cavium Octeon+";
+platform:
+ if (cpu == 0)
+ __elf_platform = "octeon";
break;
default:
printk(KERN_INFO "Unknown Octeon chip!\n");
@@ -903,6 +933,7 @@ static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu)
}
const char *__cpu_name[NR_CPUS];
+const char *__elf_platform;
__cpuinit void cpu_probe(void)
{
@@ -967,6 +998,8 @@ __cpuinit void cpu_probe(void)
c->srsets = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
else
c->srsets = 1;
+
+ cpu_probe_vmbits(c);
}
__cpuinit void cpu_report(void)
diff --git a/arch/mips/kernel/cpufreq/Kconfig b/arch/mips/kernel/cpufreq/Kconfig
new file mode 100644
index 000000000000..58c601eee6fd
--- /dev/null
+++ b/arch/mips/kernel/cpufreq/Kconfig
@@ -0,0 +1,41 @@
+#
+# CPU Frequency scaling
+#
+
+config MIPS_EXTERNAL_TIMER
+ bool
+
+config MIPS_CPUFREQ
+ bool
+ default y
+ depends on CPU_SUPPORTS_CPUFREQ && MIPS_EXTERNAL_TIMER
+
+if MIPS_CPUFREQ
+
+menu "CPU Frequency scaling"
+
+source "drivers/cpufreq/Kconfig"
+
+if CPU_FREQ
+
+comment "CPUFreq processor drivers"
+
+config LOONGSON2_CPUFREQ
+ tristate "Loongson2 CPUFreq Driver"
+ select CPU_FREQ_TABLE
+ depends on MIPS_CPUFREQ
+ help
+ This option adds a CPUFreq driver for loongson processors which
+ support software configurable cpu frequency.
+
+ Loongson2F and it's successors support this feature.
+
+ For details, take a look at <file:Documentation/cpu-freq/>.
+
+ If in doubt, say N.
+
+endif # CPU_FREQ
+
+endmenu
+
+endif # MIPS_CPUFREQ
diff --git a/arch/mips/kernel/cpufreq/Makefile b/arch/mips/kernel/cpufreq/Makefile
new file mode 100644
index 000000000000..c3479a432efe
--- /dev/null
+++ b/arch/mips/kernel/cpufreq/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Linux/MIPS cpufreq.
+#
+
+obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o loongson2_clock.o
diff --git a/arch/mips/kernel/cpufreq/loongson2_clock.c b/arch/mips/kernel/cpufreq/loongson2_clock.c
new file mode 100644
index 000000000000..cefc6e259baf
--- /dev/null
+++ b/arch/mips/kernel/cpufreq/loongson2_clock.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology
+ * Author: Yanhua, yanh@lemote.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/platform_device.h>
+
+#include <asm/clock.h>
+
+#include <loongson.h>
+
+static LIST_HEAD(clock_list);
+static DEFINE_SPINLOCK(clock_lock);
+static DEFINE_MUTEX(clock_list_sem);
+
+/* Minimum CLK support */
+enum {
+ DC_ZERO, DC_25PT = 2, DC_37PT, DC_50PT, DC_62PT, DC_75PT,
+ DC_87PT, DC_DISABLE, DC_RESV
+};
+
+struct cpufreq_frequency_table loongson2_clockmod_table[] = {
+ {DC_RESV, CPUFREQ_ENTRY_INVALID},
+ {DC_ZERO, CPUFREQ_ENTRY_INVALID},
+ {DC_25PT, 0},
+ {DC_37PT, 0},
+ {DC_50PT, 0},
+ {DC_62PT, 0},
+ {DC_75PT, 0},
+ {DC_87PT, 0},
+ {DC_DISABLE, 0},
+ {DC_RESV, CPUFREQ_TABLE_END},
+};
+EXPORT_SYMBOL_GPL(loongson2_clockmod_table);
+
+static struct clk cpu_clk = {
+ .name = "cpu_clk",
+ .flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
+ .rate = 800000000,
+};
+
+struct clk *clk_get(struct device *dev, const char *id)
+{
+ return &cpu_clk;
+}
+EXPORT_SYMBOL(clk_get);
+
+static void propagate_rate(struct clk *clk)
+{
+ struct clk *clkp;
+
+ list_for_each_entry(clkp, &clock_list, node) {
+ if (likely(clkp->parent != clk))
+ continue;
+ if (likely(clkp->ops && clkp->ops->recalc))
+ clkp->ops->recalc(clkp);
+ if (unlikely(clkp->flags & CLK_RATE_PROPAGATES))
+ propagate_rate(clkp);
+ }
+}
+
+int clk_enable(struct clk *clk)
+{
+ return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+ return (unsigned long)clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_put);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+ return clk_set_rate_ex(clk, rate, 0);
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
+
+int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
+{
+ int ret = 0;
+ int regval;
+ int i;
+
+ if (likely(clk->ops && clk->ops->set_rate)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&clock_lock, flags);
+ ret = clk->ops->set_rate(clk, rate, algo_id);
+ spin_unlock_irqrestore(&clock_lock, flags);
+ }
+
+ if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
+ propagate_rate(clk);
+
+ for (i = 0; loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END;
+ i++) {
+ if (loongson2_clockmod_table[i].frequency ==
+ CPUFREQ_ENTRY_INVALID)
+ continue;
+ if (rate == loongson2_clockmod_table[i].frequency)
+ break;
+ }
+ if (rate != loongson2_clockmod_table[i].frequency)
+ return -ENOTSUPP;
+
+ clk->rate = rate;
+
+ regval = LOONGSON_CHIPCFG0;
+ regval = (regval & ~0x7) | (loongson2_clockmod_table[i].index - 1);
+ LOONGSON_CHIPCFG0 = regval;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate_ex);
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (likely(clk->ops && clk->ops->round_rate)) {
+ unsigned long flags, rounded;
+
+ spin_lock_irqsave(&clock_lock, flags);
+ rounded = clk->ops->round_rate(clk, rate);
+ spin_unlock_irqrestore(&clock_lock, flags);
+
+ return rounded;
+ }
+
+ return rate;
+}
+EXPORT_SYMBOL_GPL(clk_round_rate);
+
+/*
+ * This is the simple version of Loongson-2 wait, Maybe we need do this in
+ * interrupt disabled content
+ */
+
+DEFINE_SPINLOCK(loongson2_wait_lock);
+void loongson2_cpu_wait(void)
+{
+ u32 cpu_freq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&loongson2_wait_lock, flags);
+ cpu_freq = LOONGSON_CHIPCFG0;
+ LOONGSON_CHIPCFG0 &= ~0x7; /* Put CPU into wait mode */
+ LOONGSON_CHIPCFG0 = cpu_freq; /* Restore CPU state */
+ spin_unlock_irqrestore(&loongson2_wait_lock, flags);
+}
+EXPORT_SYMBOL_GPL(loongson2_cpu_wait);
+
+MODULE_AUTHOR("Yanhua <yanh@lemote.com>");
+MODULE_DESCRIPTION("cpufreq driver for Loongson 2F");
+MODULE_LICENSE("GPL");
diff --git a/arch/mips/kernel/cpufreq/loongson2_cpufreq.c b/arch/mips/kernel/cpufreq/loongson2_cpufreq.c
new file mode 100644
index 000000000000..2f6a0b147ab8
--- /dev/null
+++ b/arch/mips/kernel/cpufreq/loongson2_cpufreq.c
@@ -0,0 +1,227 @@
+/*
+ * Cpufreq driver for the loongson-2 processors
+ *
+ * The 2E revision of loongson processor not support this feature.
+ *
+ * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology
+ * Author: Yanhua, yanh@lemote.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/cpufreq.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/sched.h> /* set_cpus_allowed() */
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+
+#include <asm/clock.h>
+
+#include <loongson.h>
+
+static uint nowait;
+
+static struct clk *cpuclk;
+
+static void (*saved_cpu_wait) (void);
+
+static int loongson2_cpu_freq_notifier(struct notifier_block *nb,
+ unsigned long val, void *data);
+
+static struct notifier_block loongson2_cpufreq_notifier_block = {
+ .notifier_call = loongson2_cpu_freq_notifier
+};
+
+static int loongson2_cpu_freq_notifier(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ if (val == CPUFREQ_POSTCHANGE)
+ current_cpu_data.udelay_val = loops_per_jiffy;
+
+ return 0;
+}
+
+static unsigned int loongson2_cpufreq_get(unsigned int cpu)
+{
+ return clk_get_rate(cpuclk);
+}
+
+/*
+ * Here we notify other drivers of the proposed change and the final change.
+ */
+static int loongson2_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ unsigned int cpu = policy->cpu;
+ unsigned int newstate = 0;
+ cpumask_t cpus_allowed;
+ struct cpufreq_freqs freqs;
+ unsigned int freq;
+
+ if (!cpu_online(cpu))
+ return -ENODEV;
+
+ cpus_allowed = current->cpus_allowed;
+ set_cpus_allowed(current, cpumask_of_cpu(cpu));
+
+ if (cpufreq_frequency_table_target
+ (policy, &loongson2_clockmod_table[0], target_freq, relation,
+ &newstate))
+ return -EINVAL;
+
+ freq =
+ ((cpu_clock_freq / 1000) *
+ loongson2_clockmod_table[newstate].index) / 8;
+ if (freq < policy->min || freq > policy->max)
+ return -EINVAL;
+
+ pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000);
+
+ freqs.cpu = cpu;
+ freqs.old = loongson2_cpufreq_get(cpu);
+ freqs.new = freq;
+ freqs.flags = 0;
+
+ if (freqs.new == freqs.old)
+ return 0;
+
+ /* notifiers */
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ set_cpus_allowed(current, cpus_allowed);
+
+ /* setting the cpu frequency */
+ clk_set_rate(cpuclk, freq);
+
+ /* notifiers */
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+ pr_debug("cpufreq: set frequency %u kHz\n", freq);
+
+ return 0;
+}
+
+static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ int i;
+
+ if (!cpu_online(policy->cpu))
+ return -ENODEV;
+
+ cpuclk = clk_get(NULL, "cpu_clk");
+ if (IS_ERR(cpuclk)) {
+ printk(KERN_ERR "cpufreq: couldn't get CPU clk\n");
+ return PTR_ERR(cpuclk);
+ }
+
+ cpuclk->rate = cpu_clock_freq / 1000;
+ if (!cpuclk->rate)
+ return -EINVAL;
+
+ /* clock table init */
+ for (i = 2;
+ (loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END);
+ i++)
+ loongson2_clockmod_table[i].frequency = (cpuclk->rate * i) / 8;
+
+ policy->cur = loongson2_cpufreq_get(policy->cpu);
+
+ cpufreq_frequency_table_get_attr(&loongson2_clockmod_table[0],
+ policy->cpu);
+
+ return cpufreq_frequency_table_cpuinfo(policy,
+ &loongson2_clockmod_table[0]);
+}
+
+static int loongson2_cpufreq_verify(struct cpufreq_policy *policy)
+{
+ return cpufreq_frequency_table_verify(policy,
+ &loongson2_clockmod_table[0]);
+}
+
+static int loongson2_cpufreq_exit(struct cpufreq_policy *policy)
+{
+ clk_put(cpuclk);
+ return 0;
+}
+
+static struct freq_attr *loongson2_table_attr[] = {
+ &cpufreq_freq_attr_scaling_available_freqs,
+ NULL,
+};
+
+static struct cpufreq_driver loongson2_cpufreq_driver = {
+ .owner = THIS_MODULE,
+ .name = "loongson2",
+ .init = loongson2_cpufreq_cpu_init,
+ .verify = loongson2_cpufreq_verify,
+ .target = loongson2_cpufreq_target,
+ .get = loongson2_cpufreq_get,
+ .exit = loongson2_cpufreq_exit,
+ .attr = loongson2_table_attr,
+};
+
+static struct platform_device_id platform_device_ids[] = {
+ {
+ .name = "loongson2_cpufreq",
+ },
+ {}
+};
+
+MODULE_DEVICE_TABLE(platform, platform_device_ids);
+
+static struct platform_driver platform_driver = {
+ .driver = {
+ .name = "loongson2_cpufreq",
+ .owner = THIS_MODULE,
+ },
+ .id_table = platform_device_ids,
+};
+
+static int __init cpufreq_init(void)
+{
+ int ret;
+
+ /* Register platform stuff */
+ ret = platform_driver_register(&platform_driver);
+ if (ret)
+ return ret;
+
+ pr_info("cpufreq: Loongson-2F CPU frequency driver.\n");
+
+ cpufreq_register_notifier(&loongson2_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ ret = cpufreq_register_driver(&loongson2_cpufreq_driver);
+
+ if (!ret && !nowait) {
+ saved_cpu_wait = cpu_wait;
+ cpu_wait = loongson2_cpu_wait;
+ }
+
+ return ret;
+}
+
+static void __exit cpufreq_exit(void)
+{
+ if (!nowait && saved_cpu_wait)
+ cpu_wait = saved_cpu_wait;
+ cpufreq_unregister_driver(&loongson2_cpufreq_driver);
+ cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ platform_driver_unregister(&platform_driver);
+}
+
+module_init(cpufreq_init);
+module_exit(cpufreq_exit);
+
+module_param(nowait, uint, 0644);
+MODULE_PARM_DESC(nowait, "Disable Loongson-2F specific wait");
+
+MODULE_AUTHOR("Yanhua <yanh@lemote.com>");
+MODULE_DESCRIPTION("cpufreq driver for Loongson2F");
+MODULE_LICENSE("GPL");
diff --git a/arch/mips/kernel/csrc-powertv.c b/arch/mips/kernel/csrc-powertv.c
new file mode 100644
index 000000000000..a27c16c8690e
--- /dev/null
+++ b/arch/mips/kernel/csrc-powertv.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2008 Scientific-Atlanta, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+/*
+ * The file comes from kernel/csrc-r4k.c
+ */
+#include <linux/clocksource.h>
+#include <linux/init.h>
+
+#include <asm/time.h> /* Not included in linux/time.h */
+
+#include <asm/mach-powertv/asic_regs.h>
+#include "powertv-clock.h"
+
+/* MIPS PLL Register Definitions */
+#define PLL_GET_M(x) (((x) >> 8) & 0x000000FF)
+#define PLL_GET_N(x) (((x) >> 16) & 0x000000FF)
+#define PLL_GET_P(x) (((x) >> 24) & 0x00000007)
+
+/*
+ * returns: Clock frequency in kHz
+ */
+unsigned int __init mips_get_pll_freq(void)
+{
+ unsigned int pll_reg, m, n, p;
+ unsigned int fin = 54000; /* Base frequency in kHz */
+ unsigned int fout;
+
+ /* Read PLL register setting */
+ pll_reg = asic_read(mips_pll_setup);
+ m = PLL_GET_M(pll_reg);
+ n = PLL_GET_N(pll_reg);
+ p = PLL_GET_P(pll_reg);
+ pr_info("MIPS PLL Register:0x%x M=%d N=%d P=%d\n", pll_reg, m, n, p);
+
+ /* Calculate clock frequency = (2 * N * 54MHz) / (M * (2**P)) */
+ fout = ((2 * n * fin) / (m * (0x01 << p)));
+
+ pr_info("MIPS Clock Freq=%d kHz\n", fout);
+
+ return fout;
+}
+
+static cycle_t c0_hpt_read(struct clocksource *cs)
+{
+ return read_c0_count();
+}
+
+static struct clocksource clocksource_mips = {
+ .name = "powertv-counter",
+ .read = c0_hpt_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static void __init powertv_c0_hpt_clocksource_init(void)
+{
+ unsigned int pll_freq = mips_get_pll_freq();
+
+ pr_info("CPU frequency %d.%02d MHz\n", pll_freq / 1000,
+ (pll_freq % 1000) * 100 / 1000);
+
+ mips_hpt_frequency = pll_freq / 2 * 1000;
+
+ clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
+
+ clocksource_set_clock(&clocksource_mips, mips_hpt_frequency);
+
+ clocksource_register(&clocksource_mips);
+}
+
+/**
+ * struct tim_c - free running counter
+ * @hi: High 16 bits of the counter
+ * @lo: Low 32 bits of the counter
+ *
+ * Lays out the structure of the free running counter in memory. This counter
+ * increments at a rate of 27 MHz/8 on all platforms.
+ */
+struct tim_c {
+ unsigned int hi;
+ unsigned int lo;
+};
+
+static struct tim_c *tim_c;
+
+static cycle_t tim_c_read(struct clocksource *cs)
+{
+ unsigned int hi;
+ unsigned int next_hi;
+ unsigned int lo;
+
+ hi = readl(&tim_c->hi);
+
+ for (;;) {
+ lo = readl(&tim_c->lo);
+ next_hi = readl(&tim_c->hi);
+ if (next_hi == hi)
+ break;
+ hi = next_hi;
+ }
+
+pr_crit("%s: read %llx\n", __func__, ((u64) hi << 32) | lo);
+ return ((u64) hi << 32) | lo;
+}
+
+#define TIM_C_SIZE 48 /* # bits in the timer */
+
+static struct clocksource clocksource_tim_c = {
+ .name = "powertv-tim_c",
+ .read = tim_c_read,
+ .mask = CLOCKSOURCE_MASK(TIM_C_SIZE),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+/**
+ * powertv_tim_c_clocksource_init - set up a clock source for the TIM_C clock
+ *
+ * The hard part here is coming up with a constant k and shift s such that
+ * the 48-bit TIM_C value multiplied by k doesn't overflow and that value,
+ * when shifted right by s, yields the corresponding number of nanoseconds.
+ * We know that TIM_C counts at 27 MHz/8, so each cycle corresponds to
+ * 1 / (27,000,000/8) seconds. Multiply that by a billion and you get the
+ * number of nanoseconds. Since the TIM_C value has 48 bits and the math is
+ * done in 64 bits, avoiding an overflow means that k must be less than
+ * 64 - 48 = 16 bits.
+ */
+static void __init powertv_tim_c_clocksource_init(void)
+{
+ int prescale;
+ unsigned long dividend;
+ unsigned long k;
+ int s;
+ const int max_k_bits = (64 - 48) - 1;
+ const unsigned long billion = 1000000000;
+ const unsigned long counts_per_second = 27000000 / 8;
+
+ prescale = BITS_PER_LONG - ilog2(billion) - 1;
+ dividend = billion << prescale;
+ k = dividend / counts_per_second;
+ s = ilog2(k) - max_k_bits;
+
+ if (s < 0)
+ s = prescale;
+
+ else {
+ k >>= s;
+ s += prescale;
+ }
+
+ clocksource_tim_c.mult = k;
+ clocksource_tim_c.shift = s;
+ clocksource_tim_c.rating = 200;
+
+ clocksource_register(&clocksource_tim_c);
+ tim_c = (struct tim_c *) asic_reg_addr(tim_ch);
+}
+
+/**
+ powertv_clocksource_init - initialize all clocksources
+ */
+void __init powertv_clocksource_init(void)
+{
+ powertv_c0_hpt_clocksource_init();
+ powertv_tim_c_clocksource_init();
+}
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c
new file mode 100644
index 000000000000..e9e64e0ff7aa
--- /dev/null
+++ b/arch/mips/kernel/ftrace.c
@@ -0,0 +1,275 @@
+/*
+ * Code for replacing ftrace calls with jumps.
+ *
+ * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
+ * Copyright (C) 2009 DSLab, Lanzhou University, China
+ * Author: Wu Zhangjin <wuzhangjin@gmail.com>
+ *
+ * Thanks goes to Steven Rostedt for writing the original x86 version.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/init.h>
+#include <linux/ftrace.h>
+
+#include <asm/cacheflush.h>
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+#define JAL 0x0c000000 /* jump & link: ip --> ra, jump to target */
+#define ADDR_MASK 0x03ffffff /* op_code|addr : 31...26|25 ....0 */
+#define jump_insn_encode(op_code, addr) \
+ ((unsigned int)((op_code) | (((addr) >> 2) & ADDR_MASK)))
+
+static unsigned int ftrace_nop = 0x00000000;
+
+static int ftrace_modify_code(unsigned long ip, unsigned int new_code)
+{
+ int faulted;
+
+ /* *(unsigned int *)ip = new_code; */
+ safe_store_code(new_code, ip, faulted);
+
+ if (unlikely(faulted))
+ return -EFAULT;
+
+ flush_icache_range(ip, ip + 8);
+
+ return 0;
+}
+
+static int lui_v1;
+static int jal_mcount;
+
+int ftrace_make_nop(struct module *mod,
+ struct dyn_ftrace *rec, unsigned long addr)
+{
+ unsigned int new;
+ int faulted;
+ unsigned long ip = rec->ip;
+
+ /* We have compiled module with -mlong-calls, but compiled the kernel
+ * without it, we need to cope with them respectively. */
+ if (ip & 0x40000000) {
+ /* record it for ftrace_make_call */
+ if (lui_v1 == 0) {
+ /* lui_v1 = *(unsigned int *)ip; */
+ safe_load_code(lui_v1, ip, faulted);
+
+ if (unlikely(faulted))
+ return -EFAULT;
+ }
+
+ /* lui v1, hi_16bit_of_mcount --> b 1f (0x10000004)
+ * addiu v1, v1, low_16bit_of_mcount
+ * move at, ra
+ * jalr v1
+ * nop
+ * 1f: (ip + 12)
+ */
+ new = 0x10000004;
+ } else {
+ /* record/calculate it for ftrace_make_call */
+ if (jal_mcount == 0) {
+ /* We can record it directly like this:
+ * jal_mcount = *(unsigned int *)ip;
+ * Herein, jump over the first two nop instructions */
+ jal_mcount = jump_insn_encode(JAL, (MCOUNT_ADDR + 8));
+ }
+
+ /* move at, ra
+ * jalr v1 --> nop
+ */
+ new = ftrace_nop;
+ }
+ return ftrace_modify_code(ip, new);
+}
+
+static int modified; /* initialized as 0 by default */
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+ unsigned int new;
+ unsigned long ip = rec->ip;
+
+ /* We just need to remove the "b ftrace_stub" at the fist time! */
+ if (modified == 0) {
+ modified = 1;
+ ftrace_modify_code(addr, ftrace_nop);
+ }
+ /* ip, module: 0xc0000000, kernel: 0x80000000 */
+ new = (ip & 0x40000000) ? lui_v1 : jal_mcount;
+
+ return ftrace_modify_code(ip, new);
+}
+
+#define FTRACE_CALL_IP ((unsigned long)(&ftrace_call))
+
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+ unsigned int new;
+
+ new = jump_insn_encode(JAL, (unsigned long)func);
+
+ return ftrace_modify_code(FTRACE_CALL_IP, new);
+}
+
+int __init ftrace_dyn_arch_init(void *data)
+{
+ /* The return code is retured via data */
+ *(unsigned long *)data = 0;
+
+ return 0;
+}
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+extern void ftrace_graph_call(void);
+#define JMP 0x08000000 /* jump to target directly */
+#define CALL_FTRACE_GRAPH_CALLER \
+ jump_insn_encode(JMP, (unsigned long)(&ftrace_graph_caller))
+#define FTRACE_GRAPH_CALL_IP ((unsigned long)(&ftrace_graph_call))
+
+int ftrace_enable_ftrace_graph_caller(void)
+{
+ return ftrace_modify_code(FTRACE_GRAPH_CALL_IP,
+ CALL_FTRACE_GRAPH_CALLER);
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+ return ftrace_modify_code(FTRACE_GRAPH_CALL_IP, ftrace_nop);
+}
+
+#endif /* !CONFIG_DYNAMIC_FTRACE */
+
+#ifndef KBUILD_MCOUNT_RA_ADDRESS
+#define S_RA_SP (0xafbf << 16) /* s{d,w} ra, offset(sp) */
+#define S_R_SP (0xafb0 << 16) /* s{d,w} R, offset(sp) */
+#define OFFSET_MASK 0xffff /* stack offset range: 0 ~ PT_SIZE */
+
+unsigned long ftrace_get_parent_addr(unsigned long self_addr,
+ unsigned long parent,
+ unsigned long parent_addr,
+ unsigned long fp)
+{
+ unsigned long sp, ip, ra;
+ unsigned int code;
+ int faulted;
+
+ /* in module or kernel? */
+ if (self_addr & 0x40000000) {
+ /* module: move to the instruction "lui v1, HI_16BIT_OF_MCOUNT" */
+ ip = self_addr - 20;
+ } else {
+ /* kernel: move to the instruction "move ra, at" */
+ ip = self_addr - 12;
+ }
+
+ /* search the text until finding the non-store instruction or "s{d,w}
+ * ra, offset(sp)" instruction */
+ do {
+ ip -= 4;
+
+ /* get the code at "ip": code = *(unsigned int *)ip; */
+ safe_load_code(code, ip, faulted);
+
+ if (unlikely(faulted))
+ return 0;
+
+ /* If we hit the non-store instruction before finding where the
+ * ra is stored, then this is a leaf function and it does not
+ * store the ra on the stack. */
+ if ((code & S_R_SP) != S_R_SP)
+ return parent_addr;
+
+ } while (((code & S_RA_SP) != S_RA_SP));
+
+ sp = fp + (code & OFFSET_MASK);
+
+ /* ra = *(unsigned long *)sp; */
+ safe_load_stack(ra, sp, faulted);
+ if (unlikely(faulted))
+ return 0;
+
+ if (ra == parent)
+ return sp;
+ return 0;
+}
+
+#endif
+
+/*
+ * Hook the return address and push it in the stack of return addrs
+ * in current thread info.
+ */
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
+ unsigned long fp)
+{
+ unsigned long old;
+ struct ftrace_graph_ent trace;
+ unsigned long return_hooker = (unsigned long)
+ &return_to_handler;
+ int faulted;
+
+ if (unlikely(atomic_read(&current->tracing_graph_pause)))
+ return;
+
+ /* "parent" is the stack address saved the return address of the caller
+ * of _mcount.
+ *
+ * if the gcc < 4.5, a leaf function does not save the return address
+ * in the stack address, so, we "emulate" one in _mcount's stack space,
+ * and hijack it directly, but for a non-leaf function, it save the
+ * return address to the its own stack space, we can not hijack it
+ * directly, but need to find the real stack address,
+ * ftrace_get_parent_addr() does it!
+ *
+ * if gcc>= 4.5, with the new -mmcount-ra-address option, for a
+ * non-leaf function, the location of the return address will be saved
+ * to $12 for us, and for a leaf function, only put a zero into $12. we
+ * do it in ftrace_graph_caller of mcount.S.
+ */
+
+ /* old = *parent; */
+ safe_load_stack(old, parent, faulted);
+ if (unlikely(faulted))
+ goto out;
+#ifndef KBUILD_MCOUNT_RA_ADDRESS
+ parent = (unsigned long *)ftrace_get_parent_addr(self_addr, old,
+ (unsigned long)parent,
+ fp);
+ /* If fails when getting the stack address of the non-leaf function's
+ * ra, stop function graph tracer and return */
+ if (parent == 0)
+ goto out;
+#endif
+ /* *parent = return_hooker; */
+ safe_store_stack(return_hooker, parent, faulted);
+ if (unlikely(faulted))
+ goto out;
+
+ if (ftrace_push_return_trace(old, self_addr, &trace.depth, fp) ==
+ -EBUSY) {
+ *parent = old;
+ return;
+ }
+
+ trace.func = self_addr;
+
+ /* Only trace if the calling function expects to */
+ if (!ftrace_graph_entry(&trace)) {
+ current->curr_ret_stack--;
+ *parent = old;
+ }
+ return;
+out:
+ ftrace_graph_stop();
+ WARN_ON(1);
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
index 01c0885a8061..27799113332c 100644
--- a/arch/mips/kernel/i8259.c
+++ b/arch/mips/kernel/i8259.c
@@ -29,7 +29,7 @@
*/
static int i8259A_auto_eoi = -1;
-DEFINE_SPINLOCK(i8259A_lock);
+DEFINE_RAW_SPINLOCK(i8259A_lock);
static void disable_8259A_irq(unsigned int irq);
static void enable_8259A_irq(unsigned int irq);
static void mask_and_ack_8259A(unsigned int irq);
@@ -65,13 +65,13 @@ static void disable_8259A_irq(unsigned int irq)
irq -= I8259A_IRQ_BASE;
mask = 1 << irq;
- spin_lock_irqsave(&i8259A_lock, flags);
+ raw_spin_lock_irqsave(&i8259A_lock, flags);
cached_irq_mask |= mask;
if (irq & 8)
outb(cached_slave_mask, PIC_SLAVE_IMR);
else
outb(cached_master_mask, PIC_MASTER_IMR);
- spin_unlock_irqrestore(&i8259A_lock, flags);
+ raw_spin_unlock_irqrestore(&i8259A_lock, flags);
}
static void enable_8259A_irq(unsigned int irq)
@@ -81,13 +81,13 @@ static void enable_8259A_irq(unsigned int irq)
irq -= I8259A_IRQ_BASE;
mask = ~(1 << irq);
- spin_lock_irqsave(&i8259A_lock, flags);
+ raw_spin_lock_irqsave(&i8259A_lock, flags);
cached_irq_mask &= mask;
if (irq & 8)
outb(cached_slave_mask, PIC_SLAVE_IMR);
else
outb(cached_master_mask, PIC_MASTER_IMR);
- spin_unlock_irqrestore(&i8259A_lock, flags);
+ raw_spin_unlock_irqrestore(&i8259A_lock, flags);
}
int i8259A_irq_pending(unsigned int irq)
@@ -98,12 +98,12 @@ int i8259A_irq_pending(unsigned int irq)
irq -= I8259A_IRQ_BASE;
mask = 1 << irq;
- spin_lock_irqsave(&i8259A_lock, flags);
+ raw_spin_lock_irqsave(&i8259A_lock, flags);
if (irq < 8)
ret = inb(PIC_MASTER_CMD) & mask;
else
ret = inb(PIC_SLAVE_CMD) & (mask >> 8);
- spin_unlock_irqrestore(&i8259A_lock, flags);
+ raw_spin_unlock_irqrestore(&i8259A_lock, flags);
return ret;
}
@@ -151,7 +151,7 @@ static void mask_and_ack_8259A(unsigned int irq)
irq -= I8259A_IRQ_BASE;
irqmask = 1 << irq;
- spin_lock_irqsave(&i8259A_lock, flags);
+ raw_spin_lock_irqsave(&i8259A_lock, flags);
/*
* Lightweight spurious IRQ detection. We do not want
* to overdo spurious IRQ handling - it's usually a sign
@@ -183,7 +183,7 @@ handle_real_irq:
outb(0x60+irq, PIC_MASTER_CMD); /* 'Specific EOI to master */
}
smtc_im_ack_irq(irq);
- spin_unlock_irqrestore(&i8259A_lock, flags);
+ raw_spin_unlock_irqrestore(&i8259A_lock, flags);
return;
spurious_8259A_irq:
@@ -264,7 +264,7 @@ static void init_8259A(int auto_eoi)
i8259A_auto_eoi = auto_eoi;
- spin_lock_irqsave(&i8259A_lock, flags);
+ raw_spin_lock_irqsave(&i8259A_lock, flags);
outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */
outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */
@@ -298,7 +298,7 @@ static void init_8259A(int auto_eoi)
outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */
outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */
- spin_unlock_irqrestore(&i8259A_lock, flags);
+ raw_spin_unlock_irqrestore(&i8259A_lock, flags);
}
/*
diff --git a/arch/mips/kernel/irq-gt641xx.c b/arch/mips/kernel/irq-gt641xx.c
index ebcc5f7ad9c2..42ef81461bfc 100644
--- a/arch/mips/kernel/irq-gt641xx.c
+++ b/arch/mips/kernel/irq-gt641xx.c
@@ -27,18 +27,18 @@
#define GT641XX_IRQ_TO_BIT(irq) (1U << (irq - GT641XX_IRQ_BASE))
-static DEFINE_SPINLOCK(gt641xx_irq_lock);
+static DEFINE_RAW_SPINLOCK(gt641xx_irq_lock);
static void ack_gt641xx_irq(unsigned int irq)
{
unsigned long flags;
u32 cause;
- spin_lock_irqsave(&gt641xx_irq_lock, flags);
+ raw_spin_lock_irqsave(&gt641xx_irq_lock, flags);
cause = GT_READ(GT_INTRCAUSE_OFS);
cause &= ~GT641XX_IRQ_TO_BIT(irq);
GT_WRITE(GT_INTRCAUSE_OFS, cause);
- spin_unlock_irqrestore(&gt641xx_irq_lock, flags);
+ raw_spin_unlock_irqrestore(&gt641xx_irq_lock, flags);
}
static void mask_gt641xx_irq(unsigned int irq)
@@ -46,11 +46,11 @@ static void mask_gt641xx_irq(unsigned int irq)
unsigned long flags;
u32 mask;
- spin_lock_irqsave(&gt641xx_irq_lock, flags);
+ raw_spin_lock_irqsave(&gt641xx_irq_lock, flags);
mask = GT_READ(GT_INTRMASK_OFS);
mask &= ~GT641XX_IRQ_TO_BIT(irq);
GT_WRITE(GT_INTRMASK_OFS, mask);
- spin_unlock_irqrestore(&gt641xx_irq_lock, flags);
+ raw_spin_unlock_irqrestore(&gt641xx_irq_lock, flags);
}
static void mask_ack_gt641xx_irq(unsigned int irq)
@@ -58,7 +58,7 @@ static void mask_ack_gt641xx_irq(unsigned int irq)
unsigned long flags;
u32 cause, mask;
- spin_lock_irqsave(&gt641xx_irq_lock, flags);
+ raw_spin_lock_irqsave(&gt641xx_irq_lock, flags);
mask = GT_READ(GT_INTRMASK_OFS);
mask &= ~GT641XX_IRQ_TO_BIT(irq);
GT_WRITE(GT_INTRMASK_OFS, mask);
@@ -66,7 +66,7 @@ static void mask_ack_gt641xx_irq(unsigned int irq)
cause = GT_READ(GT_INTRCAUSE_OFS);
cause &= ~GT641XX_IRQ_TO_BIT(irq);
GT_WRITE(GT_INTRCAUSE_OFS, cause);
- spin_unlock_irqrestore(&gt641xx_irq_lock, flags);
+ raw_spin_unlock_irqrestore(&gt641xx_irq_lock, flags);
}
static void unmask_gt641xx_irq(unsigned int irq)
@@ -74,11 +74,11 @@ static void unmask_gt641xx_irq(unsigned int irq)
unsigned long flags;
u32 mask;
- spin_lock_irqsave(&gt641xx_irq_lock, flags);
+ raw_spin_lock_irqsave(&gt641xx_irq_lock, flags);
mask = GT_READ(GT_INTRMASK_OFS);
mask |= GT641XX_IRQ_TO_BIT(irq);
GT_WRITE(GT_INTRMASK_OFS, mask);
- spin_unlock_irqrestore(&gt641xx_irq_lock, flags);
+ raw_spin_unlock_irqrestore(&gt641xx_irq_lock, flags);
}
static struct irq_chip gt641xx_irq_chip = {
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index 7b845ba9dff4..c6345f579a8a 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -15,13 +15,13 @@
#include <linux/kernel_stat.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
-#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/random.h>
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/kallsyms.h>
#include <linux/kgdb.h>
+#include <linux/ftrace.h>
#include <asm/atomic.h>
#include <asm/system.h>
@@ -99,7 +99,7 @@ int show_interrupts(struct seq_file *p, void *v)
}
if (i < NR_IRQS) {
- spin_lock_irqsave(&irq_desc[i].lock, flags);
+ raw_spin_lock_irqsave(&irq_desc[i].lock, flags);
action = irq_desc[i].action;
if (!action)
goto skip;
@@ -118,7 +118,7 @@ int show_interrupts(struct seq_file *p, void *v)
seq_putc(p, '\n');
skip:
- spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+ raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags);
} else if (i == NR_IRQS) {
seq_putc(p, '\n');
seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
@@ -150,3 +150,32 @@ void __init init_IRQ(void)
kgdb_early_setup = 1;
#endif
}
+
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+void __irq_entry do_IRQ(unsigned int irq)
+{
+ irq_enter();
+ __DO_IRQ_SMTC_HOOK(irq);
+ generic_handle_irq(irq);
+ irq_exit();
+}
+
+#ifdef CONFIG_MIPS_MT_SMTC_IRQAFF
+/*
+ * To avoid inefficient and in some cases pathological re-checking of
+ * IRQ affinity, we have this variant that skips the affinity check.
+ */
+
+void __irq_entry do_IRQ_no_affinity(unsigned int irq)
+{
+ irq_enter();
+ __NO_AFFINITY_IRQ_SMTC_HOOK(irq);
+ generic_handle_irq(irq);
+ irq_exit();
+}
+
+#endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c
index ad4e017ed2f3..80e2ba694bab 100644
--- a/arch/mips/kernel/kspd.c
+++ b/arch/mips/kernel/kspd.c
@@ -82,6 +82,7 @@ static int sp_stopping;
#define MTSP_O_SHLOCK 0x0010
#define MTSP_O_EXLOCK 0x0020
#define MTSP_O_ASYNC 0x0040
+/* XXX: check which of these is actually O_SYNC vs O_DSYNC */
#define MTSP_O_FSYNC O_SYNC
#define MTSP_O_NOFOLLOW 0x0100
#define MTSP_O_SYNC 0x0080
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index b77fefaff9da..c2dab140dc98 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -9,14 +9,12 @@
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/file.h>
-#include <linux/smp_lock.h>
#include <linux/highuid.h>
#include <linux/resource.h>
#include <linux/highmem.h>
#include <linux/time.h>
#include <linux/times.h>
#include <linux/poll.h>
-#include <linux/slab.h>
#include <linux/skbuff.h>
#include <linux/filter.h>
#include <linux/shm.h>
@@ -35,6 +33,7 @@
#include <linux/compat.h>
#include <linux/vfs.h>
#include <linux/ipc.h>
+#include <linux/slab.h>
#include <net/sock.h>
#include <net/scm.h>
@@ -67,28 +66,13 @@ SYSCALL_DEFINE6(32_mmap2, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags, unsigned long, fd,
unsigned long, pgoff)
{
- struct file * file = NULL;
unsigned long error;
error = -EINVAL;
if (pgoff & (~PAGE_MASK >> 12))
goto out;
- pgoff >>= PAGE_SHIFT-12;
-
- if (!(flags & MAP_ANONYMOUS)) {
- error = -EBADF;
- file = fget(fd);
- if (!file)
- goto out;
- }
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-
- down_write(&current->mm->mmap_sem);
- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
- up_write(&current->mm->mmap_sem);
- if (file)
- fput(file);
-
+ error = sys_mmap_pgoff(addr, len, prot, flags, fd,
+ pgoff >> (PAGE_SHIFT-12));
out:
return error;
}
@@ -265,83 +249,6 @@ SYSCALL_DEFINE5(n32_msgrcv, int, msqid, u32, msgp, size_t, msgsz,
}
#endif
-struct sysctl_args32
-{
- compat_caddr_t name;
- int nlen;
- compat_caddr_t oldval;
- compat_caddr_t oldlenp;
- compat_caddr_t newval;
- compat_size_t newlen;
- unsigned int __unused[4];
-};
-
-#ifdef CONFIG_SYSCTL_SYSCALL
-
-SYSCALL_DEFINE1(32_sysctl, struct sysctl_args32 __user *, args)
-{
- struct sysctl_args32 tmp;
- int error;
- size_t oldlen;
- size_t __user *oldlenp = NULL;
- unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7;
-
- if (copy_from_user(&tmp, args, sizeof(tmp)))
- return -EFAULT;
-
- if (tmp.oldval && tmp.oldlenp) {
- /* Duh, this is ugly and might not work if sysctl_args
- is in read-only memory, but do_sysctl does indirectly
- a lot of uaccess in both directions and we'd have to
- basically copy the whole sysctl.c here, and
- glibc's __sysctl uses rw memory for the structure
- anyway. */
- if (get_user(oldlen, (u32 __user *)A(tmp.oldlenp)) ||
- put_user(oldlen, (size_t __user *)addr))
- return -EFAULT;
- oldlenp = (size_t __user *)addr;
- }
-
- lock_kernel();
- error = do_sysctl((int __user *)A(tmp.name), tmp.nlen, (void __user *)A(tmp.oldval),
- oldlenp, (void __user *)A(tmp.newval), tmp.newlen);
- unlock_kernel();
- if (oldlenp) {
- if (!error) {
- if (get_user(oldlen, (size_t __user *)addr) ||
- put_user(oldlen, (u32 __user *)A(tmp.oldlenp)))
- error = -EFAULT;
- }
- copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused));
- }
- return error;
-}
-
-#else
-
-SYSCALL_DEFINE1(32_sysctl, struct sysctl_args32 __user *, args)
-{
- return -ENOSYS;
-}
-
-#endif /* CONFIG_SYSCTL_SYSCALL */
-
-SYSCALL_DEFINE1(32_newuname, struct new_utsname __user *, name)
-{
- int ret = 0;
-
- down_read(&uts_sem);
- if (copy_to_user(name, utsname(), sizeof *name))
- ret = -EFAULT;
- up_read(&uts_sem);
-
- if (current->personality == PER_LINUX32 && !ret)
- if (copy_to_user(name->machine, "mips\0\0\0", 8))
- ret = -EFAULT;
-
- return ret;
-}
-
SYSCALL_DEFINE1(32_personality, unsigned long, personality)
{
int ret;
diff --git a/arch/mips/kernel/mcount.S b/arch/mips/kernel/mcount.S
new file mode 100644
index 000000000000..6851fc97a511
--- /dev/null
+++ b/arch/mips/kernel/mcount.S
@@ -0,0 +1,189 @@
+/*
+ * MIPS specific _mcount support
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive for
+ * more details.
+ *
+ * Copyright (C) 2009 Lemote Inc. & DSLab, Lanzhou University, China
+ * Author: Wu Zhangjin <wuzhangjin@gmail.com>
+ */
+
+#include <asm/regdef.h>
+#include <asm/stackframe.h>
+#include <asm/ftrace.h>
+
+ .text
+ .set noreorder
+ .set noat
+
+ .macro MCOUNT_SAVE_REGS
+ PTR_SUBU sp, PT_SIZE
+ PTR_S ra, PT_R31(sp)
+ PTR_S AT, PT_R1(sp)
+ PTR_S a0, PT_R4(sp)
+ PTR_S a1, PT_R5(sp)
+ PTR_S a2, PT_R6(sp)
+ PTR_S a3, PT_R7(sp)
+#ifdef CONFIG_64BIT
+ PTR_S a4, PT_R8(sp)
+ PTR_S a5, PT_R9(sp)
+ PTR_S a6, PT_R10(sp)
+ PTR_S a7, PT_R11(sp)
+#endif
+ .endm
+
+ .macro MCOUNT_RESTORE_REGS
+ PTR_L ra, PT_R31(sp)
+ PTR_L AT, PT_R1(sp)
+ PTR_L a0, PT_R4(sp)
+ PTR_L a1, PT_R5(sp)
+ PTR_L a2, PT_R6(sp)
+ PTR_L a3, PT_R7(sp)
+#ifdef CONFIG_64BIT
+ PTR_L a4, PT_R8(sp)
+ PTR_L a5, PT_R9(sp)
+ PTR_L a6, PT_R10(sp)
+ PTR_L a7, PT_R11(sp)
+#endif
+#ifdef CONFIG_64BIT
+ PTR_ADDIU sp, PT_SIZE
+#else
+ PTR_ADDIU sp, (PT_SIZE + 8)
+#endif
+.endm
+
+ .macro RETURN_BACK
+ jr ra
+ move ra, AT
+ .endm
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+NESTED(ftrace_caller, PT_SIZE, ra)
+ .globl _mcount
+_mcount:
+ b ftrace_stub
+ nop
+ lw t1, function_trace_stop
+ bnez t1, ftrace_stub
+ nop
+
+ MCOUNT_SAVE_REGS
+#ifdef KBUILD_MCOUNT_RA_ADDRESS
+ PTR_S t0, PT_R12(sp) /* t0 saved the location of the return address(at) by -mmcount-ra-address */
+#endif
+
+ move a0, ra /* arg1: next ip, selfaddr */
+ .globl ftrace_call
+ftrace_call:
+ nop /* a placeholder for the call to a real tracing function */
+ move a1, AT /* arg2: the caller's next ip, parent */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ .globl ftrace_graph_call
+ftrace_graph_call:
+ nop
+ nop
+#endif
+
+ MCOUNT_RESTORE_REGS
+ .globl ftrace_stub
+ftrace_stub:
+ RETURN_BACK
+ END(ftrace_caller)
+
+#else /* ! CONFIG_DYNAMIC_FTRACE */
+
+NESTED(_mcount, PT_SIZE, ra)
+ lw t1, function_trace_stop
+ bnez t1, ftrace_stub
+ nop
+ PTR_LA t1, ftrace_stub
+ PTR_L t2, ftrace_trace_function /* Prepare t2 for (1) */
+ bne t1, t2, static_trace
+ nop
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ PTR_L t3, ftrace_graph_return
+ bne t1, t3, ftrace_graph_caller
+ nop
+ PTR_LA t1, ftrace_graph_entry_stub
+ PTR_L t3, ftrace_graph_entry
+ bne t1, t3, ftrace_graph_caller
+ nop
+#endif
+ b ftrace_stub
+ nop
+
+static_trace:
+ MCOUNT_SAVE_REGS
+
+ move a0, ra /* arg1: next ip, selfaddr */
+ jalr t2 /* (1) call *ftrace_trace_function */
+ move a1, AT /* arg2: the caller's next ip, parent */
+
+ MCOUNT_RESTORE_REGS
+ .globl ftrace_stub
+ftrace_stub:
+ RETURN_BACK
+ END(_mcount)
+
+#endif /* ! CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+NESTED(ftrace_graph_caller, PT_SIZE, ra)
+#ifdef CONFIG_DYNAMIC_FTRACE
+ PTR_L a1, PT_R31(sp) /* load the original ra from the stack */
+#ifdef KBUILD_MCOUNT_RA_ADDRESS
+ PTR_L t0, PT_R12(sp) /* load the original t0 from the stack */
+#endif
+#else
+ MCOUNT_SAVE_REGS
+ move a1, ra /* arg2: next ip, selfaddr */
+#endif
+
+#ifdef KBUILD_MCOUNT_RA_ADDRESS
+ bnez t0, 1f /* non-leaf func: t0 saved the location of the return address */
+ nop
+ PTR_LA t0, PT_R1(sp) /* leaf func: get the location of at(old ra) from our own stack */
+1: move a0, t0 /* arg1: the location of the return address */
+#else
+ PTR_LA a0, PT_R1(sp) /* arg1: &AT -> a0 */
+#endif
+ jal prepare_ftrace_return
+#ifdef CONFIG_FRAME_POINTER
+ move a2, fp /* arg3: frame pointer */
+#else
+#ifdef CONFIG_64BIT
+ PTR_LA a2, PT_SIZE(sp)
+#else
+ PTR_LA a2, (PT_SIZE+8)(sp)
+#endif
+#endif
+
+ MCOUNT_RESTORE_REGS
+ RETURN_BACK
+ END(ftrace_graph_caller)
+
+ .align 2
+ .globl return_to_handler
+return_to_handler:
+ PTR_SUBU sp, PT_SIZE
+ PTR_S v0, PT_R2(sp)
+
+ jal ftrace_return_to_handler
+ PTR_S v1, PT_R3(sp)
+
+ /* restore the real parent address: v0 -> ra */
+ move ra, v0
+
+ PTR_L v0, PT_R2(sp)
+ PTR_L v1, PT_R3(sp)
+ jr ra
+ PTR_ADDIU sp, PT_SIZE
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+ .set at
+ .set reorder
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index 225755d0c1f6..1d04807874db 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -13,6 +13,7 @@
#include <asm/checksum.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
+#include <asm/ftrace.h>
extern void *__bzero(void *__s, size_t __count);
extern long __strncpy_from_user_nocheck_asm(char *__to,
@@ -51,3 +52,7 @@ EXPORT_SYMBOL(csum_partial_copy_nocheck);
EXPORT_SYMBOL(__csum_partial_copy_user);
EXPORT_SYMBOL(invalid_pte_table);
+#ifdef CONFIG_FUNCTION_TRACER
+/* _mcount is defined in arch/mips/kernel/mcount.S */
+EXPORT_SYMBOL(_mcount);
+#endif
diff --git a/arch/mips/kernel/octeon_switch.S b/arch/mips/kernel/octeon_switch.S
index 3952b8323efa..dd18b26a358a 100644
--- a/arch/mips/kernel/octeon_switch.S
+++ b/arch/mips/kernel/octeon_switch.S
@@ -500,4 +500,3 @@ done_restore:
nop
END(octeon_mult_restore)
.set pop
-
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index f3d73e1831c1..99960940d4a4 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -17,7 +17,6 @@
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <linux/ptrace.h>
-#include <linux/slab.h>
#include <linux/mman.h>
#include <linux/personality.h>
#include <linux/sys.h>
@@ -64,8 +63,13 @@ void __noreturn cpu_idle(void)
smtc_idle_loop_hook();
#endif
- if (cpu_wait)
+
+ if (cpu_wait) {
+ /* Don't trace irqs off for idle */
+ stop_critical_timings();
(*cpu_wait)();
+ start_critical_timings();
+ }
}
#ifdef CONFIG_HOTPLUG_CPU
if (!cpu_online(cpu) && !cpu_isset(cpu, cpu_callin_map) &&
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 054861ccb4dd..c51b95ff8644 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -493,36 +493,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
ret = ptrace_setfpregs(child, (__u32 __user *) data);
break;
- case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
- case PTRACE_CONT: { /* restart after signal. */
- ret = -EIO;
- if (!valid_signal(data))
- break;
- if (request == PTRACE_SYSCALL) {
- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- }
- else {
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- }
- child->exit_code = data;
- wake_up_process(child);
- ret = 0;
- break;
- }
-
- /*
- * make the child exit. Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
- case PTRACE_KILL:
- ret = 0;
- if (child->exit_state == EXIT_ZOMBIE) /* already dead */
- break;
- child->exit_code = SIGKILL;
- wake_up_process(child);
- break;
-
case PTRACE_GET_THREAD_AREA:
ret = put_user(task_thread_info(child)->tp_value,
(unsigned long __user *) data);
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index 364f066cb497..26f9b9ab19cc 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -23,12 +23,10 @@
#include <linux/fs.h>
#include <linux/init.h>
#include <asm/uaccess.h>
-#include <linux/slab.h>
#include <linux/list.h>
#include <linux/vmalloc.h>
#include <linux/elf.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/moduleloader.h>
#include <linux/interrupt.h>
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index fd2a9bb620d6..17202bbe843f 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -583,6 +583,7 @@ einval: li v0, -ENOSYS
sys sys_rt_tgsigqueueinfo 4
sys sys_perf_event_open 5
sys sys_accept4 4
+ sys sys_recvmmsg 5
.endm
/* We pre-compute the number of _instruction_ bytes needed to
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index 18bf7f32c5e4..a8a6c596eb04 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -420,4 +420,5 @@ sys_call_table:
PTR sys_rt_tgsigqueueinfo
PTR sys_perf_event_open
PTR sys_accept4
+ PTR sys_recvmmsg
.size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 6ebc07976694..44337ba03717 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -181,7 +181,7 @@ EXPORT(sysn32_call_table)
PTR sys_exit
PTR compat_sys_wait4
PTR sys_kill /* 6060 */
- PTR sys_32_newuname
+ PTR sys_newuname
PTR sys_semget
PTR sys_semop
PTR sys_n32_semctl
@@ -272,7 +272,7 @@ EXPORT(sysn32_call_table)
PTR sys_munlockall
PTR sys_vhangup /* 6150 */
PTR sys_pivot_root
- PTR sys_32_sysctl
+ PTR compat_sys_sysctl
PTR sys_prctl
PTR compat_sys_adjtimex
PTR compat_sys_setrlimit /* 6155 */
@@ -418,4 +418,5 @@ EXPORT(sysn32_call_table)
PTR compat_sys_rt_tgsigqueueinfo /* 5295 */
PTR sys_perf_event_open
PTR sys_accept4
+ PTR compat_sys_recvmmsg
.size sysn32_call_table,.-sysn32_call_table
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 14dde4ca932e..813689ef2384 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -325,7 +325,7 @@ sys_call_table:
PTR sys32_sigreturn
PTR sys32_clone /* 4120 */
PTR sys_setdomainname
- PTR sys_32_newuname
+ PTR sys_newuname
PTR sys_ni_syscall /* sys_modify_ldt */
PTR compat_sys_adjtimex
PTR sys_mprotect /* 4125 */
@@ -356,7 +356,7 @@ sys_call_table:
PTR sys_ni_syscall /* 4150 */
PTR sys_getsid
PTR sys_fdatasync
- PTR sys_32_sysctl
+ PTR compat_sys_sysctl
PTR sys_mlock
PTR sys_munlock /* 4155 */
PTR sys_mlockall
@@ -538,4 +538,5 @@ sys_call_table:
PTR compat_sys_rt_tgsigqueueinfo
PTR sys_perf_event_open
PTR sys_accept4
+ PTR compat_sys_recvmmsg
.size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 2b290d70083e..f9513f9e61d3 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -58,8 +58,12 @@ EXPORT_SYMBOL(mips_machtype);
struct boot_mem_map boot_mem_map;
-static char command_line[CL_SIZE];
- char arcs_cmdline[CL_SIZE]=CONFIG_CMDLINE;
+static char __initdata command_line[COMMAND_LINE_SIZE];
+char __initdata arcs_cmdline[COMMAND_LINE_SIZE];
+
+#ifdef CONFIG_CMDLINE_BOOL
+static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
+#endif
/*
* mips_io_port_base is the begin of the address space to which x86 style
@@ -166,26 +170,8 @@ static unsigned long __init init_initrd(void)
* already set up initrd_start and initrd_end. In these cases
* perfom sanity checks and use them if all looks good.
*/
- if (!initrd_start || initrd_end <= initrd_start) {
-#ifdef CONFIG_PROBE_INITRD_HEADER
- u32 *initrd_header;
-
- /*
- * See if initrd has been added to the kernel image by
- * arch/mips/boot/addinitrd.c. In that case a header is
- * prepended to initrd and is made up by 8 bytes. The first
- * word is a magic number and the second one is the size of
- * initrd. Initrd start must be page aligned in any cases.
- */
- initrd_header = __va(PAGE_ALIGN(__pa_symbol(&_end) + 8)) - 8;
- if (initrd_header[0] != 0x494E5244)
- goto disable;
- initrd_start = (unsigned long)(initrd_header + 2);
- initrd_end = initrd_start + initrd_header[1];
-#else
+ if (!initrd_start || initrd_end <= initrd_start)
goto disable;
-#endif
- }
if (initrd_start & ~PAGE_MASK) {
pr_err("initrd start must be page aligned\n");
@@ -476,8 +462,20 @@ static void __init arch_mem_init(char **cmdline_p)
pr_info("Determined physical RAM map:\n");
print_memory_map();
- strlcpy(command_line, arcs_cmdline, sizeof(command_line));
- strlcpy(boot_command_line, command_line, COMMAND_LINE_SIZE);
+#ifdef CONFIG_CMDLINE_BOOL
+#ifdef CONFIG_CMDLINE_OVERRIDE
+ strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+#else
+ if (builtin_cmdline[0]) {
+ strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
+ strlcat(arcs_cmdline, builtin_cmdline, COMMAND_LINE_SIZE);
+ }
+ strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
+#endif
+#else
+ strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
+#endif
+ strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;
diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h
index 6c8e8c4246f7..10263b405981 100644
--- a/arch/mips/kernel/signal-common.h
+++ b/arch/mips/kernel/signal-common.h
@@ -26,11 +26,6 @@
*/
extern void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
size_t frame_size);
-/*
- * install trampoline code to get back from the sig handler
- */
-extern int install_sigtramp(unsigned int __user *tramp, unsigned int syscall);
-
/* Check and clear pending FPU exceptions in saved CSR */
extern int fpcsr_pending(unsigned int __user *fpcsr);
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 6254041b942f..2099d5a4c4b7 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -32,50 +32,33 @@
#include <asm/ucontext.h>
#include <asm/cpu-features.h>
#include <asm/war.h>
+#include <asm/vdso.h>
#include "signal-common.h"
-/*
- * Horribly complicated - with the bloody RM9000 workarounds enabled
- * the signal trampolines is moving to the end of the structure so we can
- * increase the alignment without breaking software compatibility.
- */
-#if ICACHE_REFILLS_WORKAROUND_WAR == 0
+static int (*save_fp_context)(struct sigcontext __user *sc);
+static int (*restore_fp_context)(struct sigcontext __user *sc);
+
+extern asmlinkage int _save_fp_context(struct sigcontext __user *sc);
+extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc);
+
+extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc);
+extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc);
struct sigframe {
u32 sf_ass[4]; /* argument save space for o32 */
- u32 sf_code[2]; /* signal trampoline */
+ u32 sf_pad[2]; /* Was: signal trampoline */
struct sigcontext sf_sc;
sigset_t sf_mask;
};
struct rt_sigframe {
u32 rs_ass[4]; /* argument save space for o32 */
- u32 rs_code[2]; /* signal trampoline */
- struct siginfo rs_info;
- struct ucontext rs_uc;
-};
-
-#else
-
-struct sigframe {
- u32 sf_ass[4]; /* argument save space for o32 */
- u32 sf_pad[2];
- struct sigcontext sf_sc; /* hw context */
- sigset_t sf_mask;
- u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */
-};
-
-struct rt_sigframe {
- u32 rs_ass[4]; /* argument save space for o32 */
- u32 rs_pad[2];
+ u32 rs_pad[2]; /* Was: signal trampoline */
struct siginfo rs_info;
struct ucontext rs_uc;
- u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */
};
-#endif
-
/*
* Helper routines
*/
@@ -257,32 +240,6 @@ void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK));
}
-int install_sigtramp(unsigned int __user *tramp, unsigned int syscall)
-{
- int err;
-
- /*
- * Set up the return code ...
- *
- * li v0, __NR__foo_sigreturn
- * syscall
- */
-
- err = __put_user(0x24020000 + syscall, tramp + 0);
- err |= __put_user(0x0000000c , tramp + 1);
- if (ICACHE_REFILLS_WORKAROUND_WAR) {
- err |= __put_user(0, tramp + 2);
- err |= __put_user(0, tramp + 3);
- err |= __put_user(0, tramp + 4);
- err |= __put_user(0, tramp + 5);
- err |= __put_user(0, tramp + 6);
- err |= __put_user(0, tramp + 7);
- }
- flush_cache_sigtramp((unsigned long) tramp);
-
- return err;
-}
-
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -475,8 +432,8 @@ badframe:
}
#ifdef CONFIG_TRAD_SIGNALS
-static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
- int signr, sigset_t *set)
+static int setup_frame(void *sig_return, struct k_sigaction *ka,
+ struct pt_regs *regs, int signr, sigset_t *set)
{
struct sigframe __user *frame;
int err = 0;
@@ -485,8 +442,6 @@ static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
goto give_sigsegv;
- err |= install_sigtramp(frame->sf_code, __NR_sigreturn);
-
err |= setup_sigcontext(regs, &frame->sf_sc);
err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
if (err)
@@ -506,7 +461,7 @@ static int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
regs->regs[ 5] = 0;
regs->regs[ 6] = (unsigned long) &frame->sf_sc;
regs->regs[29] = (unsigned long) frame;
- regs->regs[31] = (unsigned long) frame->sf_code;
+ regs->regs[31] = (unsigned long) sig_return;
regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
@@ -520,8 +475,9 @@ give_sigsegv:
}
#endif
-static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
- int signr, sigset_t *set, siginfo_t *info)
+static int setup_rt_frame(void *sig_return, struct k_sigaction *ka,
+ struct pt_regs *regs, int signr, sigset_t *set,
+ siginfo_t *info)
{
struct rt_sigframe __user *frame;
int err = 0;
@@ -530,8 +486,6 @@ static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
goto give_sigsegv;
- err |= install_sigtramp(frame->rs_code, __NR_rt_sigreturn);
-
/* Create siginfo. */
err |= copy_siginfo_to_user(&frame->rs_info, info);
@@ -564,7 +518,7 @@ static int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs,
regs->regs[ 5] = (unsigned long) &frame->rs_info;
regs->regs[ 6] = (unsigned long) &frame->rs_uc;
regs->regs[29] = (unsigned long) frame;
- regs->regs[31] = (unsigned long) frame->rs_code;
+ regs->regs[31] = (unsigned long) sig_return;
regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
@@ -581,8 +535,11 @@ give_sigsegv:
struct mips_abi mips_abi = {
#ifdef CONFIG_TRAD_SIGNALS
.setup_frame = setup_frame,
+ .signal_return_offset = offsetof(struct mips_vdso, signal_trampoline),
#endif
.setup_rt_frame = setup_rt_frame,
+ .rt_signal_return_offset =
+ offsetof(struct mips_vdso, rt_signal_trampoline),
.restart = __NR_restart_syscall
};
@@ -590,6 +547,8 @@ static int handle_signal(unsigned long sig, siginfo_t *info,
struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs)
{
int ret;
+ struct mips_abi *abi = current->thread.abi;
+ void *vdso = current->mm->context.vdso;
switch(regs->regs[0]) {
case ERESTART_RESTARTBLOCK:
@@ -610,9 +569,11 @@ static int handle_signal(unsigned long sig, siginfo_t *info,
regs->regs[0] = 0; /* Don't deal with this again. */
if (sig_uses_siginfo(ka))
- ret = current->thread.abi->setup_rt_frame(ka, regs, sig, oldset, info);
+ ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset,
+ ka, regs, sig, oldset, info);
else
- ret = current->thread.abi->setup_frame(ka, regs, sig, oldset);
+ ret = abi->setup_frame(vdso + abi->signal_return_offset,
+ ka, regs, sig, oldset);
spin_lock_irq(&current->sighand->siglock);
sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
@@ -709,3 +670,40 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
key_replace_session_keyring();
}
}
+
+#ifdef CONFIG_SMP
+static int smp_save_fp_context(struct sigcontext __user *sc)
+{
+ return raw_cpu_has_fpu
+ ? _save_fp_context(sc)
+ : fpu_emulator_save_context(sc);
+}
+
+static int smp_restore_fp_context(struct sigcontext __user *sc)
+{
+ return raw_cpu_has_fpu
+ ? _restore_fp_context(sc)
+ : fpu_emulator_restore_context(sc);
+}
+#endif
+
+static int signal_setup(void)
+{
+#ifdef CONFIG_SMP
+ /* For now just do the cpu_has_fpu check when the functions are invoked */
+ save_fp_context = smp_save_fp_context;
+ restore_fp_context = smp_restore_fp_context;
+#else
+ if (cpu_has_fpu) {
+ save_fp_context = _save_fp_context;
+ restore_fp_context = _restore_fp_context;
+ } else {
+ save_fp_context = fpu_emulator_save_context;
+ restore_fp_context = fpu_emulator_restore_context;
+ }
+#endif
+
+ return 0;
+}
+
+arch_initcall(signal_setup);
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index 2e74075ac0ca..a0ed0e052b2e 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -32,14 +32,22 @@
#include <asm/system.h>
#include <asm/fpu.h>
#include <asm/war.h>
+#include <asm/vdso.h>
#include "signal-common.h"
+static int (*save_fp_context32)(struct sigcontext32 __user *sc);
+static int (*restore_fp_context32)(struct sigcontext32 __user *sc);
+
+extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc);
+extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc);
+
+extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc);
+extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc);
+
/*
* Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
*/
-#define __NR_O32_sigreturn 4119
-#define __NR_O32_rt_sigreturn 4193
#define __NR_O32_restart_syscall 4253
/* 32-bit compatibility types */
@@ -68,47 +76,20 @@ struct ucontext32 {
compat_sigset_t uc_sigmask; /* mask last for extensibility */
};
-/*
- * Horribly complicated - with the bloody RM9000 workarounds enabled
- * the signal trampolines is moving to the end of the structure so we can
- * increase the alignment without breaking software compatibility.
- */
-#if ICACHE_REFILLS_WORKAROUND_WAR == 0
-
struct sigframe32 {
u32 sf_ass[4]; /* argument save space for o32 */
- u32 sf_code[2]; /* signal trampoline */
+ u32 sf_pad[2]; /* Was: signal trampoline */
struct sigcontext32 sf_sc;
compat_sigset_t sf_mask;
};
struct rt_sigframe32 {
u32 rs_ass[4]; /* argument save space for o32 */
- u32 rs_code[2]; /* signal trampoline */
- compat_siginfo_t rs_info;
- struct ucontext32 rs_uc;
-};
-
-#else /* ICACHE_REFILLS_WORKAROUND_WAR */
-
-struct sigframe32 {
- u32 sf_ass[4]; /* argument save space for o32 */
- u32 sf_pad[2];
- struct sigcontext32 sf_sc; /* hw context */
- compat_sigset_t sf_mask;
- u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */
-};
-
-struct rt_sigframe32 {
- u32 rs_ass[4]; /* argument save space for o32 */
- u32 rs_pad[2];
+ u32 rs_pad[2]; /* Was: signal trampoline */
compat_siginfo_t rs_info;
struct ucontext32 rs_uc;
- u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */
};
-#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */
-
/*
* sigcontext handlers
*/
@@ -589,8 +570,8 @@ badframe:
force_sig(SIGSEGV, current);
}
-static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
- int signr, sigset_t *set)
+static int setup_frame_32(void *sig_return, struct k_sigaction *ka,
+ struct pt_regs *regs, int signr, sigset_t *set)
{
struct sigframe32 __user *frame;
int err = 0;
@@ -599,8 +580,6 @@ static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
goto give_sigsegv;
- err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
-
err |= setup_sigcontext32(regs, &frame->sf_sc);
err |= __copy_conv_sigset_to_user(&frame->sf_mask, set);
@@ -621,7 +600,7 @@ static int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
regs->regs[ 5] = 0;
regs->regs[ 6] = (unsigned long) &frame->sf_sc;
regs->regs[29] = (unsigned long) frame;
- regs->regs[31] = (unsigned long) frame->sf_code;
+ regs->regs[31] = (unsigned long) sig_return;
regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
@@ -635,8 +614,9 @@ give_sigsegv:
return -EFAULT;
}
-static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
- int signr, sigset_t *set, siginfo_t *info)
+static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka,
+ struct pt_regs *regs, int signr, sigset_t *set,
+ siginfo_t *info)
{
struct rt_sigframe32 __user *frame;
int err = 0;
@@ -646,8 +626,6 @@ static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
goto give_sigsegv;
- err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn);
-
/* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
err |= copy_siginfo_to_user32(&frame->rs_info, info);
@@ -681,7 +659,7 @@ static int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
regs->regs[ 5] = (unsigned long) &frame->rs_info;
regs->regs[ 6] = (unsigned long) &frame->rs_uc;
regs->regs[29] = (unsigned long) frame;
- regs->regs[31] = (unsigned long) frame->rs_code;
+ regs->regs[31] = (unsigned long) sig_return;
regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
@@ -700,7 +678,11 @@ give_sigsegv:
*/
struct mips_abi mips_abi_32 = {
.setup_frame = setup_frame_32,
+ .signal_return_offset =
+ offsetof(struct mips_vdso, o32_signal_trampoline),
.setup_rt_frame = setup_rt_frame_32,
+ .rt_signal_return_offset =
+ offsetof(struct mips_vdso, o32_rt_signal_trampoline),
.restart = __NR_O32_restart_syscall
};
@@ -828,3 +810,18 @@ SYSCALL_DEFINE5(32_waitid, int, which, compat_pid_t, pid,
info.si_code |= __SI_CHLD;
return copy_siginfo_to_user32(uinfo, &info);
}
+
+static int signal32_init(void)
+{
+ if (cpu_has_fpu) {
+ save_fp_context32 = _save_fp_context32;
+ restore_fp_context32 = _restore_fp_context32;
+ } else {
+ save_fp_context32 = fpu_emulator_save_context32;
+ restore_fp_context32 = fpu_emulator_restore_context32;
+ }
+
+ return 0;
+}
+
+arch_initcall(signal32_init);
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index bb277e82d421..2c5df818c65a 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -39,13 +39,13 @@
#include <asm/fpu.h>
#include <asm/cpu-features.h>
#include <asm/war.h>
+#include <asm/vdso.h>
#include "signal-common.h"
/*
* Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
*/
-#define __NR_N32_rt_sigreturn 6211
#define __NR_N32_restart_syscall 6214
extern int setup_sigcontext(struct pt_regs *, struct sigcontext __user *);
@@ -67,27 +67,13 @@ struct ucontextn32 {
compat_sigset_t uc_sigmask; /* mask last for extensibility */
};
-#if ICACHE_REFILLS_WORKAROUND_WAR == 0
-
-struct rt_sigframe_n32 {
- u32 rs_ass[4]; /* argument save space for o32 */
- u32 rs_code[2]; /* signal trampoline */
- struct compat_siginfo rs_info;
- struct ucontextn32 rs_uc;
-};
-
-#else /* ICACHE_REFILLS_WORKAROUND_WAR */
-
struct rt_sigframe_n32 {
u32 rs_ass[4]; /* argument save space for o32 */
- u32 rs_pad[2];
+ u32 rs_pad[2]; /* Was: signal trampoline */
struct compat_siginfo rs_info;
struct ucontextn32 rs_uc;
- u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */
};
-#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */
-
extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat);
asmlinkage int sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
@@ -173,7 +159,7 @@ badframe:
force_sig(SIGSEGV, current);
}
-static int setup_rt_frame_n32(struct k_sigaction * ka,
+static int setup_rt_frame_n32(void *sig_return, struct k_sigaction *ka,
struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info)
{
struct rt_sigframe_n32 __user *frame;
@@ -184,8 +170,6 @@ static int setup_rt_frame_n32(struct k_sigaction * ka,
if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
goto give_sigsegv;
- install_sigtramp(frame->rs_code, __NR_N32_rt_sigreturn);
-
/* Create siginfo. */
err |= copy_siginfo_to_user32(&frame->rs_info, info);
@@ -219,7 +203,7 @@ static int setup_rt_frame_n32(struct k_sigaction * ka,
regs->regs[ 5] = (unsigned long) &frame->rs_info;
regs->regs[ 6] = (unsigned long) &frame->rs_uc;
regs->regs[29] = (unsigned long) frame;
- regs->regs[31] = (unsigned long) frame->rs_code;
+ regs->regs[31] = (unsigned long) sig_return;
regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
@@ -235,5 +219,7 @@ give_sigsegv:
struct mips_abi mips_abi_n32 = {
.setup_rt_frame = setup_rt_frame_n32,
+ .rt_signal_return_offset =
+ offsetof(struct mips_vdso, n32_rt_signal_trampoline),
.restart = __NR_N32_restart_syscall
};
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index e72e6844d134..6cdca1956b77 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -32,6 +32,7 @@
#include <linux/cpumask.h>
#include <linux/cpu.h>
#include <linux/err.h>
+#include <linux/ftrace.h>
#include <asm/atomic.h>
#include <asm/cpu.h>
@@ -130,7 +131,7 @@ asmlinkage __cpuinit void start_secondary(void)
/*
* Call into both interrupt handlers, as we share the IPI for them
*/
-void smp_call_function_interrupt(void)
+void __irq_entry smp_call_function_interrupt(void)
{
irq_enter();
generic_smp_call_function_single_interrupt();
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 24630fd8ef60..a95dea5459c4 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -25,6 +25,8 @@
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/module.h>
+#include <linux/ftrace.h>
+#include <linux/slab.h>
#include <asm/cpu.h>
#include <asm/processor.h>
@@ -180,7 +182,7 @@ static int vpemask[2][8] = {
{0, 0, 0, 0, 0, 0, 0, 1}
};
int tcnoprog[NR_CPUS];
-static atomic_t idle_hook_initialized = {0};
+static atomic_t idle_hook_initialized = ATOMIC_INIT(0);
static int clock_hang_reported[NR_CPUS];
#endif /* CONFIG_SMTC_IDLE_HOOK_DEBUG */
@@ -939,23 +941,29 @@ static void ipi_call_interrupt(void)
DECLARE_PER_CPU(struct clock_event_device, mips_clockevent_device);
-void ipi_decode(struct smtc_ipi *pipi)
+static void __irq_entry smtc_clock_tick_interrupt(void)
{
unsigned int cpu = smp_processor_id();
struct clock_event_device *cd;
+ int irq = MIPS_CPU_IRQ_BASE + 1;
+
+ irq_enter();
+ kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
+ cd = &per_cpu(mips_clockevent_device, cpu);
+ cd->event_handler(cd);
+ irq_exit();
+}
+
+void ipi_decode(struct smtc_ipi *pipi)
+{
void *arg_copy = pipi->arg;
int type_copy = pipi->type;
- int irq = MIPS_CPU_IRQ_BASE + 1;
smtc_ipi_nq(&freeIPIq, pipi);
switch (type_copy) {
case SMTC_CLOCK_TICK:
- irq_enter();
- kstat_incr_irqs_this_cpu(irq, irq_to_desc(irq));
- cd = &per_cpu(mips_clockevent_device, cpu);
- cd->event_handler(cd);
- irq_exit();
+ smtc_clock_tick_interrupt();
break;
case LINUX_SMP_IPI:
@@ -1331,7 +1339,7 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
if (!((asid += ASID_INC) & ASID_MASK) ) {
if (cpu_has_vtag_icache)
flush_icache_all();
- /* Traverse all online CPUs (hack requires contigous range) */
+ /* Traverse all online CPUs (hack requires contiguous range) */
for_each_online_cpu(i) {
/*
* We don't need to worry about our own CPU, nor those of
diff --git a/arch/mips/kernel/spinlock_test.c b/arch/mips/kernel/spinlock_test.c
new file mode 100644
index 000000000000..da61134dfc53
--- /dev/null
+++ b/arch/mips/kernel/spinlock_test.c
@@ -0,0 +1,141 @@
+#include <linux/init.h>
+#include <linux/kthread.h>
+#include <linux/hrtimer.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+
+static int ss_get(void *data, u64 *val)
+{
+ ktime_t start, finish;
+ int loops;
+ int cont;
+ DEFINE_RAW_SPINLOCK(ss_spin);
+
+ loops = 1000000;
+ cont = 1;
+
+ start = ktime_get();
+
+ while (cont) {
+ raw_spin_lock(&ss_spin);
+ loops--;
+ if (loops == 0)
+ cont = 0;
+ raw_spin_unlock(&ss_spin);
+ }
+
+ finish = ktime_get();
+
+ *val = ktime_us_delta(finish, start);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_ss, ss_get, NULL, "%llu\n");
+
+
+
+struct spin_multi_state {
+ raw_spinlock_t lock;
+ atomic_t start_wait;
+ atomic_t enter_wait;
+ atomic_t exit_wait;
+ int loops;
+};
+
+struct spin_multi_per_thread {
+ struct spin_multi_state *state;
+ ktime_t start;
+};
+
+static int multi_other(void *data)
+{
+ int loops;
+ int cont;
+ struct spin_multi_per_thread *pt = data;
+ struct spin_multi_state *s = pt->state;
+
+ loops = s->loops;
+ cont = 1;
+
+ atomic_dec(&s->enter_wait);
+
+ while (atomic_read(&s->enter_wait))
+ ; /* spin */
+
+ pt->start = ktime_get();
+
+ atomic_dec(&s->start_wait);
+
+ while (atomic_read(&s->start_wait))
+ ; /* spin */
+
+ while (cont) {
+ raw_spin_lock(&s->lock);
+ loops--;
+ if (loops == 0)
+ cont = 0;
+ raw_spin_unlock(&s->lock);
+ }
+
+ atomic_dec(&s->exit_wait);
+ while (atomic_read(&s->exit_wait))
+ ; /* spin */
+ return 0;
+}
+
+static int multi_get(void *data, u64 *val)
+{
+ ktime_t finish;
+ struct spin_multi_state ms;
+ struct spin_multi_per_thread t1, t2;
+
+ ms.lock = __RAW_SPIN_LOCK_UNLOCKED("multi_get");
+ ms.loops = 1000000;
+
+ atomic_set(&ms.start_wait, 2);
+ atomic_set(&ms.enter_wait, 2);
+ atomic_set(&ms.exit_wait, 2);
+ t1.state = &ms;
+ t2.state = &ms;
+
+ kthread_run(multi_other, &t2, "multi_get");
+
+ multi_other(&t1);
+
+ finish = ktime_get();
+
+ *val = ktime_us_delta(finish, t1.start);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(fops_multi, multi_get, NULL, "%llu\n");
+
+
+extern struct dentry *mips_debugfs_dir;
+static int __init spinlock_test(void)
+{
+ struct dentry *d;
+
+ if (!mips_debugfs_dir)
+ return -ENODEV;
+
+ d = debugfs_create_file("spin_single", S_IRUGO,
+ mips_debugfs_dir, NULL,
+ &fops_ss);
+ if (!d)
+ return -ENOMEM;
+
+ d = debugfs_create_file("spin_multi", S_IRUGO,
+ mips_debugfs_dir, NULL,
+ &fops_multi);
+ if (!d)
+ return -ENOMEM;
+
+ return 0;
+}
+device_initcall(spinlock_test);
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index fe0d79805603..dd81b0f87518 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -19,7 +19,6 @@
#include <linux/string.h>
#include <linux/syscalls.h>
#include <linux/file.h>
-#include <linux/slab.h>
#include <linux/utsname.h>
#include <linux/unistd.h>
#include <linux/sem.h>
@@ -29,6 +28,7 @@
#include <linux/module.h>
#include <linux/ipc.h>
#include <linux/uaccess.h>
+#include <linux/slab.h>
#include <asm/asm.h>
#include <asm/branch.h>
@@ -79,7 +79,11 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
int do_color_align;
unsigned long task_size;
- task_size = STACK_TOP;
+#ifdef CONFIG_32BIT
+ task_size = TASK_SIZE;
+#else /* Must be CONFIG_64BIT*/
+ task_size = test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE;
+#endif
if (len > task_size)
return -ENOMEM;
@@ -93,7 +97,8 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
* We do not accept a shared mapping if it would violate
* cache aliasing constraints.
*/
- if ((flags & MAP_SHARED) && (addr & shm_align_mask))
+ if ((flags & MAP_SHARED) &&
+ ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask))
return -EINVAL;
return addr;
}
@@ -129,31 +134,6 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
}
}
-/* common code for old and new mmaps */
-static inline unsigned long
-do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
- unsigned long flags, unsigned long fd, unsigned long pgoff)
-{
- unsigned long error = -EBADF;
- struct file * file = NULL;
-
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
- if (!(flags & MAP_ANONYMOUS)) {
- file = fget(fd);
- if (!file)
- goto out;
- }
-
- down_write(&current->mm->mmap_sem);
- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
- up_write(&current->mm->mmap_sem);
-
- if (file)
- fput(file);
-out:
- return error;
-}
-
SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
unsigned long, prot, unsigned long, flags, unsigned long,
fd, off_t, offset)
@@ -164,7 +144,7 @@ SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
if (offset & ~PAGE_MASK)
goto out;
- result = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
+ result = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
out:
return result;
@@ -177,7 +157,7 @@ SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len,
if (pgoff & (~PAGE_MASK >> 12))
return -EINVAL;
- return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12));
+ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12));
}
save_static_function(sys_fork);
@@ -239,48 +219,6 @@ out:
return error;
}
-/*
- * Compacrapability ...
- */
-SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)
-{
- if (name && !copy_to_user(name, utsname(), sizeof (*name)))
- return 0;
- return -EFAULT;
-}
-
-/*
- * Compacrapability ...
- */
-SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)
-{
- int error;
-
- if (!name)
- return -EFAULT;
- if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
- return -EFAULT;
-
- error = __copy_to_user(&name->sysname, &utsname()->sysname,
- __OLD_UTS_LEN);
- error -= __put_user(0, name->sysname + __OLD_UTS_LEN);
- error -= __copy_to_user(&name->nodename, &utsname()->nodename,
- __OLD_UTS_LEN);
- error -= __put_user(0, name->nodename + __OLD_UTS_LEN);
- error -= __copy_to_user(&name->release, &utsname()->release,
- __OLD_UTS_LEN);
- error -= __put_user(0, name->release + __OLD_UTS_LEN);
- error -= __copy_to_user(&name->version, &utsname()->version,
- __OLD_UTS_LEN);
- error -= __put_user(0, name->version + __OLD_UTS_LEN);
- error -= __copy_to_user(&name->machine, &utsname()->machine,
- __OLD_UTS_LEN);
- error = __put_user(0, name->machine + __OLD_UTS_LEN);
- error = error ? -EFAULT : 0;
-
- return error;
-}
-
SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
{
struct thread_info *ti = task_thread_info(current);
@@ -431,94 +369,6 @@ _sys_sysmips(nabi_no_regargs struct pt_regs regs)
}
/*
- * sys_ipc() is the de-multiplexer for the SysV IPC calls..
- *
- * This is really horribly ugly.
- */
-SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, int, second,
- unsigned long, third, void __user *, ptr, long, fifth)
-{
- int version, ret;
-
- version = call >> 16; /* hack for backward compatibility */
- call &= 0xffff;
-
- switch (call) {
- case SEMOP:
- return sys_semtimedop(first, (struct sembuf __user *)ptr,
- second, NULL);
- case SEMTIMEDOP:
- return sys_semtimedop(first, (struct sembuf __user *)ptr,
- second,
- (const struct timespec __user *)fifth);
- case SEMGET:
- return sys_semget(first, second, third);
- case SEMCTL: {
- union semun fourth;
- if (!ptr)
- return -EINVAL;
- if (get_user(fourth.__pad, (void __user *__user *) ptr))
- return -EFAULT;
- return sys_semctl(first, second, third, fourth);
- }
-
- case MSGSND:
- return sys_msgsnd(first, (struct msgbuf __user *) ptr,
- second, third);
- case MSGRCV:
- switch (version) {
- case 0: {
- struct ipc_kludge tmp;
- if (!ptr)
- return -EINVAL;
-
- if (copy_from_user(&tmp,
- (struct ipc_kludge __user *) ptr,
- sizeof(tmp)))
- return -EFAULT;
- return sys_msgrcv(first, tmp.msgp, second,
- tmp.msgtyp, third);
- }
- default:
- return sys_msgrcv(first,
- (struct msgbuf __user *) ptr,
- second, fifth, third);
- }
- case MSGGET:
- return sys_msgget((key_t) first, second);
- case MSGCTL:
- return sys_msgctl(first, second,
- (struct msqid_ds __user *) ptr);
-
- case SHMAT:
- switch (version) {
- default: {
- unsigned long raddr;
- ret = do_shmat(first, (char __user *) ptr, second,
- &raddr);
- if (ret)
- return ret;
- return put_user(raddr, (unsigned long __user *) third);
- }
- case 1: /* iBCS2 emulator entry point */
- if (!segment_eq(get_fs(), get_ds()))
- return -EINVAL;
- return do_shmat(first, (char __user *) ptr, second,
- (unsigned long *) third);
- }
- case SHMDT:
- return sys_shmdt((char __user *)ptr);
- case SHMGET:
- return sys_shmget(first, second, third);
- case SHMCTL:
- return sys_shmctl(first, second,
- (struct shmid_ds __user *) ptr);
- default:
- return -ENOSYS;
- }
-}
-
-/*
* No implemented yet ...
*/
SYSCALL_DEFINE3(cachectl, char *, addr, int, nbytes, int, op)
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 1f467d534642..fb7497405510 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -71,39 +71,6 @@ EXPORT_SYMBOL(perf_irq);
unsigned int mips_hpt_frequency;
-void __init clocksource_set_clock(struct clocksource *cs, unsigned int clock)
-{
- u64 temp;
- u32 shift;
-
- /* Find a shift value */
- for (shift = 32; shift > 0; shift--) {
- temp = (u64) NSEC_PER_SEC << shift;
- do_div(temp, clock);
- if ((temp >> 32) == 0)
- break;
- }
- cs->shift = shift;
- cs->mult = (u32) temp;
-}
-
-void __cpuinit clockevent_set_clock(struct clock_event_device *cd,
- unsigned int clock)
-{
- u64 temp;
- u32 shift;
-
- /* Find a shift value */
- for (shift = 32; shift > 0; shift--) {
- temp = (u64) clock << shift;
- do_div(temp, NSEC_PER_SEC);
- if ((temp >> 32) == 0)
- break;
- }
- cd->shift = shift;
- cd->mult = (u32) temp;
-}
-
/*
* This function exists in order to cause an error due to a duplicate
* definition if platform code should have its own implementation. The hook
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 0a18b4c62afb..1a4dd657ccb9 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -25,10 +25,12 @@
#include <linux/ptrace.h>
#include <linux/kgdb.h>
#include <linux/kdebug.h>
+#include <linux/notifier.h>
#include <asm/bootinfo.h>
#include <asm/branch.h>
#include <asm/break.h>
+#include <asm/cop2.h>
#include <asm/cpu.h>
#include <asm/dsp.h>
#include <asm/fpu.h>
@@ -48,6 +50,7 @@
#include <asm/types.h>
#include <asm/stacktrace.h>
#include <asm/irq.h>
+#include <asm/uasm.h>
extern void check_wait(void);
extern asmlinkage void r4k_wait(void);
@@ -79,10 +82,6 @@ extern asmlinkage void handle_reserved(void);
extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
struct mips_fpu_struct *ctx, int has_fpu);
-#ifdef CONFIG_CPU_CAVIUM_OCTEON
-extern asmlinkage void octeon_cop2_restore(struct octeon_cop2_state *task);
-#endif
-
void (*board_be_init)(void);
int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
void (*board_nmi_handler_setup)(void);
@@ -857,6 +856,44 @@ static void mt_ase_fp_affinity(void)
#endif /* CONFIG_MIPS_MT_FPAFF */
}
+/*
+ * No lock; only written during early bootup by CPU 0.
+ */
+static RAW_NOTIFIER_HEAD(cu2_chain);
+
+int __ref register_cu2_notifier(struct notifier_block *nb)
+{
+ return raw_notifier_chain_register(&cu2_chain, nb);
+}
+
+int cu2_notifier_call_chain(unsigned long val, void *v)
+{
+ return raw_notifier_call_chain(&cu2_chain, val, v);
+}
+
+static int default_cu2_call(struct notifier_block *nfb, unsigned long action,
+ void *data)
+{
+ struct pt_regs *regs = data;
+
+ switch (action) {
+ default:
+ die_if_kernel("Unhandled kernel unaligned access or invalid "
+ "instruction", regs);
+ /* Fall through */
+
+ case CU2_EXCEPTION:
+ force_sig(SIGILL, current);
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block default_cu2_notifier = {
+ .notifier_call = default_cu2_call,
+ .priority = 0x80000000, /* Run last */
+};
+
asmlinkage void do_cpu(struct pt_regs *regs)
{
unsigned int __user *epc;
@@ -920,17 +957,9 @@ asmlinkage void do_cpu(struct pt_regs *regs)
return;
case 2:
-#ifdef CONFIG_CPU_CAVIUM_OCTEON
- prefetch(&current->thread.cp2);
- local_irq_save(flags);
- KSTK_STATUS(current) |= ST0_CU2;
- status = read_c0_status();
- write_c0_status(status | ST0_CU2);
- octeon_cop2_restore(&(current->thread.cp2));
- write_c0_status(status & ~ST0_CU2);
- local_irq_restore(flags);
- return;
-#endif
+ raw_notifier_call_chain(&cu2_chain, CU2_EXCEPTION, regs);
+ break;
+
case 3:
break;
}
@@ -1243,21 +1272,25 @@ unsigned long ebase;
unsigned long exception_handlers[32];
unsigned long vi_handlers[64];
-/*
- * As a side effect of the way this is implemented we're limited
- * to interrupt handlers in the address range from
- * KSEG0 <= x < KSEG0 + 256mb on the Nevada. Oh well ...
- */
-void *set_except_vector(int n, void *addr)
+void __init *set_except_vector(int n, void *addr)
{
unsigned long handler = (unsigned long) addr;
unsigned long old_handler = exception_handlers[n];
exception_handlers[n] = handler;
if (n == 0 && cpu_has_divec) {
- *(u32 *)(ebase + 0x200) = 0x08000000 |
- (0x03ffffff & (handler >> 2));
- local_flush_icache_range(ebase + 0x200, ebase + 0x204);
+ unsigned long jump_mask = ~((1 << 28) - 1);
+ u32 *buf = (u32 *)(ebase + 0x200);
+ unsigned int k0 = 26;
+ if ((handler & jump_mask) == ((ebase + 0x200) & jump_mask)) {
+ uasm_i_j(&buf, handler & ~jump_mask);
+ uasm_i_nop(&buf);
+ } else {
+ UASM_i_LA(&buf, k0, handler);
+ uasm_i_jr(&buf, k0);
+ uasm_i_nop(&buf);
+ }
+ local_flush_icache_range(ebase + 0x200, (unsigned long)buf);
}
return (void *)old_handler;
}
@@ -1367,77 +1400,6 @@ void *set_vi_handler(int n, vi_handler_t addr)
return set_vi_srs_handler(n, addr, 0);
}
-/*
- * This is used by native signal handling
- */
-asmlinkage int (*save_fp_context)(struct sigcontext __user *sc);
-asmlinkage int (*restore_fp_context)(struct sigcontext __user *sc);
-
-extern asmlinkage int _save_fp_context(struct sigcontext __user *sc);
-extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc);
-
-extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc);
-extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc);
-
-#ifdef CONFIG_SMP
-static int smp_save_fp_context(struct sigcontext __user *sc)
-{
- return raw_cpu_has_fpu
- ? _save_fp_context(sc)
- : fpu_emulator_save_context(sc);
-}
-
-static int smp_restore_fp_context(struct sigcontext __user *sc)
-{
- return raw_cpu_has_fpu
- ? _restore_fp_context(sc)
- : fpu_emulator_restore_context(sc);
-}
-#endif
-
-static inline void signal_init(void)
-{
-#ifdef CONFIG_SMP
- /* For now just do the cpu_has_fpu check when the functions are invoked */
- save_fp_context = smp_save_fp_context;
- restore_fp_context = smp_restore_fp_context;
-#else
- if (cpu_has_fpu) {
- save_fp_context = _save_fp_context;
- restore_fp_context = _restore_fp_context;
- } else {
- save_fp_context = fpu_emulator_save_context;
- restore_fp_context = fpu_emulator_restore_context;
- }
-#endif
-}
-
-#ifdef CONFIG_MIPS32_COMPAT
-
-/*
- * This is used by 32-bit signal stuff on the 64-bit kernel
- */
-asmlinkage int (*save_fp_context32)(struct sigcontext32 __user *sc);
-asmlinkage int (*restore_fp_context32)(struct sigcontext32 __user *sc);
-
-extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc);
-extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc);
-
-extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc);
-extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc);
-
-static inline void signal32_init(void)
-{
- if (cpu_has_fpu) {
- save_fp_context32 = _save_fp_context32;
- restore_fp_context32 = _restore_fp_context32;
- } else {
- save_fp_context32 = fpu_emulator_save_context32;
- restore_fp_context32 = fpu_emulator_restore_context32;
- }
-}
-#endif
-
extern void cpu_cache_init(void);
extern void tlb_init(void);
extern void flush_tlb_handlers(void);
@@ -1446,6 +1408,7 @@ extern void flush_tlb_handlers(void);
* Timer interrupt
*/
int cp0_compare_irq;
+int cp0_compare_irq_shift;
/*
* Performance counter IRQ or -1 if shared with timer
@@ -1536,12 +1499,14 @@ void __cpuinit per_cpu_trap_init(void)
* o read IntCtl.IPPCI to determine the performance counter interrupt
*/
if (cpu_has_mips_r2) {
- cp0_compare_irq = (read_c0_intctl() >> 29) & 7;
- cp0_perfcount_irq = (read_c0_intctl() >> 26) & 7;
+ cp0_compare_irq_shift = CAUSEB_TI - CAUSEB_IP;
+ cp0_compare_irq = (read_c0_intctl() >> INTCTLB_IPTI) & 7;
+ cp0_perfcount_irq = (read_c0_intctl() >> INTCTLB_IPPCI) & 7;
if (cp0_perfcount_irq == cp0_compare_irq)
cp0_perfcount_irq = -1;
} else {
cp0_compare_irq = CP0_LEGACY_COMPARE_IRQ;
+ cp0_compare_irq_shift = cp0_compare_irq;
cp0_perfcount_irq = -1;
}
@@ -1634,7 +1599,7 @@ void __init trap_init(void)
ebase = (unsigned long)
__alloc_bootmem(size, 1 << fls(size), 0);
} else {
- ebase = CAC_BASE;
+ ebase = CKSEG0;
if (cpu_has_mips_r2)
ebase += (read_c0_ebase() & 0x3ffff000);
}
@@ -1751,13 +1716,10 @@ void __init trap_init(void)
else
memcpy((void *)(ebase + 0x080), &except_vec3_generic, 0x80);
- signal_init();
-#ifdef CONFIG_MIPS32_COMPAT
- signal32_init();
-#endif
-
local_flush_icache_range(ebase, ebase + 0x400);
flush_tlb_handlers();
sort_extable(__start___dbe_table, __stop___dbe_table);
+
+ register_cu2_notifier(&default_cu2_notifier);
}
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index 67bd626942ab..69b039ca8d83 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -81,6 +81,7 @@
#include <asm/asm.h>
#include <asm/branch.h>
#include <asm/byteorder.h>
+#include <asm/cop2.h>
#include <asm/inst.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -451,17 +452,27 @@ static void emulate_load_store_insn(struct pt_regs *regs,
*/
goto sigbus;
+ /*
+ * COP2 is available to implementor for application specific use.
+ * It's up to applications to register a notifier chain and do
+ * whatever they have to do, including possible sending of signals.
+ */
case lwc2_op:
+ cu2_notifier_call_chain(CU2_LWC2_OP, regs);
+ break;
+
case ldc2_op:
+ cu2_notifier_call_chain(CU2_LDC2_OP, regs);
+ break;
+
case swc2_op:
+ cu2_notifier_call_chain(CU2_SWC2_OP, regs);
+ break;
+
case sdc2_op:
- /*
- * These are the coprocessor 2 load/stores. The current
- * implementations don't use cp2 and cp2 should always be
- * disabled in c0_status. So send SIGILL.
- * (No longer true: The Sony Praystation uses cp2 for
- * 3D matrix operations. Dunno if that thingy has a MMU ...)
- */
+ cu2_notifier_call_chain(CU2_SDC2_OP, regs);
+ break;
+
default:
/*
* Pheeee... We encountered an yet unknown instruction or
diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c
new file mode 100644
index 000000000000..b773c1112b14
--- /dev/null
+++ b/arch/mips/kernel/vdso.c
@@ -0,0 +1,112 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009, 2010 Cavium Networks, Inc.
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/binfmts.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/unistd.h>
+
+#include <asm/vdso.h>
+#include <asm/uasm.h>
+
+/*
+ * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
+ */
+#define __NR_O32_sigreturn 4119
+#define __NR_O32_rt_sigreturn 4193
+#define __NR_N32_rt_sigreturn 6211
+
+static struct page *vdso_page;
+
+static void __init install_trampoline(u32 *tramp, unsigned int sigreturn)
+{
+ uasm_i_addiu(&tramp, 2, 0, sigreturn); /* li v0, sigreturn */
+ uasm_i_syscall(&tramp, 0);
+}
+
+static int __init init_vdso(void)
+{
+ struct mips_vdso *vdso;
+
+ vdso_page = alloc_page(GFP_KERNEL);
+ if (!vdso_page)
+ panic("Cannot allocate vdso");
+
+ vdso = vmap(&vdso_page, 1, 0, PAGE_KERNEL);
+ if (!vdso)
+ panic("Cannot map vdso");
+ clear_page(vdso);
+
+ install_trampoline(vdso->rt_signal_trampoline, __NR_rt_sigreturn);
+#ifdef CONFIG_32BIT
+ install_trampoline(vdso->signal_trampoline, __NR_sigreturn);
+#else
+ install_trampoline(vdso->n32_rt_signal_trampoline,
+ __NR_N32_rt_sigreturn);
+ install_trampoline(vdso->o32_signal_trampoline, __NR_O32_sigreturn);
+ install_trampoline(vdso->o32_rt_signal_trampoline,
+ __NR_O32_rt_sigreturn);
+#endif
+
+ vunmap(vdso);
+
+ pr_notice("init_vdso successfull\n");
+
+ return 0;
+}
+device_initcall(init_vdso);
+
+static unsigned long vdso_addr(unsigned long start)
+{
+ return STACK_TOP;
+}
+
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+ int ret;
+ unsigned long addr;
+ struct mm_struct *mm = current->mm;
+
+ down_write(&mm->mmap_sem);
+
+ addr = vdso_addr(mm->start_stack);
+
+ addr = get_unmapped_area(NULL, addr, PAGE_SIZE, 0, 0);
+ if (IS_ERR_VALUE(addr)) {
+ ret = addr;
+ goto up_fail;
+ }
+
+ ret = install_special_mapping(mm, addr, PAGE_SIZE,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+ VM_ALWAYSDUMP,
+ &vdso_page);
+
+ if (ret)
+ goto up_fail;
+
+ mm->context.vdso = (void *)addr;
+
+up_fail:
+ up_write(&mm->mmap_sem);
+ return ret;
+}
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+ if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
+ return "[vdso]";
+ return NULL;
+}
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index 162b29954baa..f25df73db923 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -46,6 +46,7 @@ SECTIONS
SCHED_TEXT
LOCK_TEXT
KPROBES_TEXT
+ IRQENTRY_TEXT
*(.text.*)
*(.fixup)
*(.gnu.warning)
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index 60477529362e..2bd2151c586a 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -38,7 +38,6 @@
#include <linux/vmalloc.h>
#include <linux/elf.h>
#include <linux/seq_file.h>
-#include <linux/smp_lock.h>
#include <linux/syscalls.h>
#include <linux/moduleloader.h>
#include <linux/interrupt.h>