summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2007-09-20 10:09:27 +1000
committerPaul Mackerras <paulus@samba.org>2007-09-20 10:09:27 +1000
commit0ce49a3945474fc942ec37c0c0efece60f592f80 (patch)
treef42b821b2d9e2d8775bc22f56d444c2cc7b7b7dd /arch
parent9e4859ef5462193643fd2b3c8ffb298e5a4a4319 (diff)
parenta88a8eff1e6e32d3288986a9d36c6a449c032d3a (diff)
downloadlinux-stable-0ce49a3945474fc942ec37c0c0efece60f592f80.tar.gz
linux-stable-0ce49a3945474fc942ec37c0c0efece60f592f80.tar.bz2
linux-stable-0ce49a3945474fc942ec37c0c0efece60f592f80.zip
Merge branch 'linux-2.6'
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-realview/realview_eb.c2
-rw-r--r--arch/arm/vfp/vfpmodule.c1
-rw-r--r--arch/blackfin/mach-common/pm.c6
-rw-r--r--arch/i386/xen/enlighten.c4
-rw-r--r--arch/mips/dec/setup.c2
-rw-r--r--arch/mips/kernel/cpu-bugs64.c4
-rw-r--r--arch/mips/kernel/cpu-probe.c9
-rw-r--r--arch/mips/kernel/rtlx.c4
-rw-r--r--arch/mips/kernel/scall64-n32.S2
-rw-r--r--arch/mips/kernel/time.c1
-rw-r--r--arch/mips/mips-boards/malta/malta_int.c2
-rw-r--r--arch/mips/mm/tlbex.c26
-rw-r--r--arch/powerpc/kernel/time.c8
-rw-r--r--arch/powerpc/kernel/vdso.c12
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c4
-rw-r--r--arch/sparc64/defconfig16
-rw-r--r--arch/sparc64/kernel/head.S35
-rw-r--r--arch/sparc64/kernel/mdesc.c6
-rw-r--r--arch/sparc64/kernel/prom.c6
-rw-r--r--arch/sparc64/kernel/trampoline.S33
-rw-r--r--arch/sparc64/prom/misc.c16
-rw-r--r--arch/um/include/kern_util.h2
-rw-r--r--arch/um/kernel/irq.c7
-rw-r--r--arch/um/os-Linux/file.c3
-rw-r--r--arch/um/os-Linux/signal.c4
-rw-r--r--arch/x86_64/mm/fault.c7
-rw-r--r--arch/xtensa/Makefile7
-rw-r--r--arch/xtensa/kernel/Makefile2
-rw-r--r--arch/xtensa/kernel/asm-offsets.c13
-rw-r--r--arch/xtensa/kernel/entry.S115
-rw-r--r--arch/xtensa/kernel/init_task.c38
-rw-r--r--arch/xtensa/kernel/io.c75
-rw-r--r--arch/xtensa/kernel/module.c195
-rw-r--r--arch/xtensa/kernel/pci.c69
-rw-r--r--arch/xtensa/kernel/process.c14
-rw-r--r--arch/xtensa/kernel/semaphore.c2
-rw-r--r--arch/xtensa/kernel/syscall.c5
-rw-r--r--arch/xtensa/kernel/time.c46
-rw-r--r--arch/xtensa/kernel/traps.c4
-rw-r--r--arch/xtensa/mm/Makefile6
-rw-r--r--arch/xtensa/mm/cache.c256
-rw-r--r--arch/xtensa/mm/fault.c6
-rw-r--r--arch/xtensa/mm/init.c252
-rw-r--r--arch/xtensa/mm/misc.S306
-rw-r--r--arch/xtensa/platform-iss/console.c1
45 files changed, 1143 insertions, 491 deletions
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index 3dba666151db..ecec2f85c4cd 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -165,7 +165,7 @@ static void __init gic_init_irq(void)
#endif
gic_dist_init(0, __io_address(REALVIEW_GIC_DIST_BASE), 29);
gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE));
-#ifdef CONFIG_REALVIEW_MPCORE
+#if defined(CONFIG_REALVIEW_MPCORE) && !defined(CONFIG_REALVIEW_MPCORE_REVB)
gic_dist_init(1, __io_address(REALVIEW_GIC1_DIST_BASE), 64);
gic_cpu_init(1, __io_address(REALVIEW_GIC1_CPU_BASE));
gic_cascade_irq(1, IRQ_EB_IRQ1);
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 04ddab2bd876..eea3f50743d5 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -323,6 +323,7 @@ static int __init vfp_init(void)
* we just need to read the VFPSID register.
*/
vfp_vector = vfp_testing_entry;
+ barrier();
vfpsid = fmrx(FPSID);
barrier();
vfp_vector = vfp_null_entry;
diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c
index 1772d8d2c1a7..b10302722202 100644
--- a/arch/blackfin/mach-common/pm.c
+++ b/arch/blackfin/mach-common/pm.c
@@ -158,10 +158,16 @@ static int bfin_pm_finish(suspend_state_t state)
return 0;
}
+static int bfin_pm_valid(suspend_state_t state)
+{
+ return (state == PM_SUSPEND_STANDBY);
+}
+
struct pm_ops bfin_pm_ops = {
.prepare = bfin_pm_prepare,
.enter = bfin_pm_enter,
.finish = bfin_pm_finish,
+ .valid = bfin_pm_valid,
};
static int __init bfin_pm_init(void)
diff --git a/arch/i386/xen/enlighten.c b/arch/i386/xen/enlighten.c
index f0c37511d8da..f01bfcd4bdee 100644
--- a/arch/i386/xen/enlighten.c
+++ b/arch/i386/xen/enlighten.c
@@ -623,8 +623,8 @@ static unsigned long xen_read_cr2_direct(void)
static void xen_write_cr4(unsigned long cr4)
{
- /* never allow TSC to be disabled */
- native_write_cr4(cr4 & ~X86_CR4_TSD);
+ /* Just ignore cr4 changes; Xen doesn't allow us to do
+ anything anyway. */
}
static unsigned long xen_read_cr3(void)
diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c
index b8a5e75ba0ab..3e634f2f5443 100644
--- a/arch/mips/dec/setup.c
+++ b/arch/mips/dec/setup.c
@@ -55,7 +55,7 @@ EXPORT_SYMBOL(dec_kn_slot_size);
int dec_tc_bus;
-spinlock_t ioasic_ssr_lock;
+DEFINE_SPINLOCK(ioasic_ssr_lock);
volatile u32 *ioasic_base;
diff --git a/arch/mips/kernel/cpu-bugs64.c b/arch/mips/kernel/cpu-bugs64.c
index ac04f0adc408..6648fde20b96 100644
--- a/arch/mips/kernel/cpu-bugs64.c
+++ b/arch/mips/kernel/cpu-bugs64.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003, 2004 Maciej W. Rozycki
+ * Copyright (C) 2003, 2004, 2007 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -29,7 +29,7 @@ static inline void align_mod(const int align, const int mod)
".endr\n\t"
".set pop"
:
- : "rn" (align), "rn" (mod));
+ : GCC_IMM_ASM (align), GCC_IMM_ASM (mod));
}
static inline void mult_sh_align_mod(long *v1, long *v2, long *w,
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 06448a9656dc..3e004161ebd5 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -199,7 +199,14 @@ static inline void check_wait(void)
if ((c->processor_id & 0xff) <= 0x64)
break;
- cpu_wait = r4k_wait;
+ /*
+ * Another rev is incremeting c0_count at a reduced clock
+ * rate while in WAIT mode. So we basically have the choice
+ * between using the cp0 timer as clocksource or avoiding
+ * the WAIT instruction. Until more details are known,
+ * disable the use of WAIT for 20Kc entirely.
+ cpu_wait = r4k_wait;
+ */
break;
case CPU_RM9000:
if ((c->processor_id & 0x00ff) >= 0x40)
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index aab89e97abb5..1ba00c15505b 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -56,8 +56,6 @@ static struct chan_waitqueues {
struct mutex mutex;
} channel_wqs[RTLX_CHANNELS];
-static struct irqaction irq;
-static int irq_num;
static struct vpe_notifications notify;
static int sp_stopping = 0;
@@ -111,7 +109,7 @@ static void __used dump_rtlx(void)
static int rtlx_init(struct rtlx_info *rtlxi)
{
if (rtlxi->id != RTLX_ID) {
- printk(KERN_ERR "no valid RTLX id at 0x%p 0x%x\n", rtlxi, rtlxi->id);
+ printk(KERN_ERR "no valid RTLX id at 0x%p 0x%lx\n", rtlxi, rtlxi->id);
return -ENOEXEC;
}
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 53d7a977193c..118be24224f2 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -375,7 +375,7 @@ EXPORT(sysn32_call_table)
PTR sys_mkdirat
PTR sys_mknodat
PTR sys_fchownat
- PTR sys_futimesat /* 6255 */
+ PTR compat_sys_futimesat /* 6255 */
PTR sys_newfstatat
PTR sys_unlinkat
PTR sys_renameat
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index d48d1d5bea0a..9a5596bf8571 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/param.h>
+#include <linux/profile.h>
#include <linux/time.h>
#include <linux/timex.h>
#include <linux/smp.h>
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
index 97aeb8c4e601..b73f21823c5e 100644
--- a/arch/mips/mips-boards/malta/malta_int.c
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -256,7 +256,7 @@ asmlinkage void plat_irq_dispatch(void)
if (irq == MIPSCPU_INT_I8259A)
malta_hw0_irqdispatch();
- else if (irq > 0)
+ else if (irq >= 0)
do_IRQ(MIPS_CPU_IRQ_BASE + irq);
else
spurious_interrupt();
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 9cb39644b6f1..6c425b052442 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -58,6 +58,21 @@ static __init int __maybe_unused r10000_llsc_war(void)
}
/*
+ * Found by experiment: At least some revisions of the 4kc throw under
+ * some circumstances a machine check exception, triggered by invalid
+ * values in the index register. Delaying the tlbp instruction until
+ * after the next branch, plus adding an additional nop in front of
+ * tlbwi/tlbwr avoids the invalid index register values. Nobody knows
+ * why; it's not an issue caused by the core RTL.
+ *
+ */
+static __init int __attribute__((unused)) m4kc_tlbp_war(void)
+{
+ return (current_cpu_data.processor_id & 0xffff00) ==
+ (PRID_COMP_MIPS | PRID_IMP_4KC);
+}
+
+/*
* A little micro-assembler, intended for TLB refill handler
* synthesizing. It is intentionally kept simple, does only support
* a subset of instructions, and does not try to hide pipeline effects
@@ -894,6 +909,8 @@ static __init void build_tlb_write_entry(u32 **p, struct label **l,
case CPU_20KC:
case CPU_25KF:
case CPU_LOONGSON2:
+ if (m4kc_tlbp_war())
+ i_nop(p);
tlbw(p);
break;
@@ -1705,7 +1722,8 @@ build_r4000_tlbchange_handler_head(u32 **p, struct label **l,
l_smp_pgtable_change(l, *p);
# endif
iPTE_LW(p, l, pte, ptr); /* get even pte */
- build_tlb_probe_entry(p);
+ if (!m4kc_tlbp_war())
+ build_tlb_probe_entry(p);
}
static void __init
@@ -1747,6 +1765,8 @@ static void __init build_r4000_tlb_load_handler(void)
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
build_pte_present(&p, &l, &r, K0, K1, label_nopage_tlbl);
+ if (m4kc_tlbp_war())
+ build_tlb_probe_entry(&p);
build_make_valid(&p, &r, K0, K1);
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
@@ -1781,6 +1801,8 @@ static void __init build_r4000_tlb_store_handler(void)
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
build_pte_writable(&p, &l, &r, K0, K1, label_nopage_tlbs);
+ if (m4kc_tlbp_war())
+ build_tlb_probe_entry(&p);
build_make_write(&p, &r, K0, K1);
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
@@ -1815,6 +1837,8 @@ static void __init build_r4000_tlb_modify_handler(void)
build_r4000_tlbchange_handler_head(&p, &l, &r, K0, K1);
build_pte_modifiable(&p, &l, &r, K0, K1, label_nopage_tlbm);
+ if (m4kc_tlbp_war())
+ build_tlb_probe_entry(&p);
/* Present and writable bits set, set accessed and dirty bits. */
build_make_write(&p, &r, K0, K1);
build_r4000_tlbchange_handler_tail(&p, &l, &r, K0, K1);
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index b5944d8e3802..d95e68c0a6b3 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -238,7 +238,7 @@ static void snapshot_tb_and_purr(void *data)
struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data);
local_irq_save(flags);
- p->tb = mftb();
+ p->tb = get_tb_or_rtc();
p->purr = mfspr(SPRN_PURR);
wmb();
p->initialized = 1;
@@ -316,7 +316,7 @@ static void snapshot_purr(void)
*/
void snapshot_timebase(void)
{
- __get_cpu_var(last_jiffy) = get_tb();
+ __get_cpu_var(last_jiffy) = get_tb_or_rtc();
snapshot_purr();
}
@@ -683,6 +683,8 @@ void timer_interrupt(struct pt_regs * regs)
write_seqlock(&xtime_lock);
tb_next_jiffy = tb_last_jiffy + tb_ticks_per_jiffy;
+ if (__USE_RTC() && tb_next_jiffy >= 1000000000)
+ tb_next_jiffy -= 1000000000;
if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) {
tb_last_jiffy = tb_next_jiffy;
do_timer(1);
@@ -976,7 +978,7 @@ void __init time_init(void)
tb_to_ns_scale = scale;
tb_to_ns_shift = shift;
/* Save the current timebase to pretty up CONFIG_PRINTK_TIME */
- boot_tb = get_tb();
+ boot_tb = get_tb_or_rtc();
tm = get_boot_time();
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index cef01e4e8989..213fa31ac537 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -98,6 +98,18 @@ static struct vdso_patch_def vdso_patches[] = {
CPU_FTR_USE_TB, 0,
"__kernel_gettimeofday", NULL
},
+ {
+ CPU_FTR_USE_TB, 0,
+ "__kernel_clock_gettime", NULL
+ },
+ {
+ CPU_FTR_USE_TB, 0,
+ "__kernel_clock_getres", NULL
+ },
+ {
+ CPU_FTR_USE_TB, 0,
+ "__kernel_get_tbfreq", NULL
+ },
};
/*
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 17806e001e50..4d257b3f9336 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -594,7 +594,7 @@ static struct spu *find_victim(struct spu_context *ctx)
list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) {
struct spu_context *tmp = spu->ctx;
- if (tmp->prio > ctx->prio &&
+ if (tmp && tmp->prio > ctx->prio &&
(!victim || tmp->prio > victim->prio))
victim = spu->ctx;
}
@@ -626,9 +626,9 @@ static struct spu *find_victim(struct spu_context *ctx)
mutex_lock(&cbe_spu_info[node].list_mutex);
cbe_spu_info[node].nr_active--;
+ spu_unbind_context(spu, victim);
mutex_unlock(&cbe_spu_info[node].list_mutex);
- spu_unbind_context(spu, victim);
victim->stats.invol_ctx_switch++;
spu->stats.invol_ctx_switch++;
mutex_unlock(&victim->state_mutex);
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 68338a601f70..7d07297db878 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23-rc1
-# Sun Jul 22 19:24:37 2007
+# Linux kernel version: 2.6.23-rc6
+# Sun Sep 16 09:52:11 2007
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
@@ -32,15 +32,11 @@ CONFIG_HZ=100
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
-# Code maturity level options
+# General setup
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SWAP=y
@@ -555,6 +551,7 @@ CONFIG_E1000_NAPI=y
# CONFIG_SIS190 is not set
# CONFIG_SKGE is not set
# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
CONFIG_TIGON3=m
CONFIG_BNX2=m
@@ -809,6 +806,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_THMC50 is not set
# CONFIG_SENSORS_VIA686A is not set
# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
@@ -1162,10 +1160,6 @@ CONFIG_USB_STORAGE=m
# CONFIG_MMC is not set
# CONFIG_NEW_LEDS is not set
# CONFIG_INFINIBAND is not set
-
-#
-# Real Time Clock
-#
# CONFIG_RTC_CLASS is not set
#
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 63144ad476f6..c4147ad8677b 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -98,7 +98,7 @@ sparc64_boot:
.globl prom_boot_mapped_pc, prom_boot_mapping_mode
.globl prom_boot_mapping_phys_high, prom_boot_mapping_phys_low
.globl prom_compatible_name, prom_cpu_path, prom_cpu_compatible
- .globl is_sun4v, sun4v_chip_type
+ .globl is_sun4v, sun4v_chip_type, prom_set_trap_table_name
prom_peer_name:
.asciz "peer"
prom_compatible_name:
@@ -121,6 +121,8 @@ prom_map_name:
.asciz "map"
prom_unmap_name:
.asciz "unmap"
+prom_set_trap_table_name:
+ .asciz "SUNW,set-trap-table"
prom_sun4v_name:
.asciz "sun4v"
prom_niagara_prefix:
@@ -691,15 +693,38 @@ setup_trap_table:
sethi %hi(kern_base), %g3
ldx [%g3 + %lo(kern_base)], %g3
add %g2, %g3, %o1
+ sethi %hi(sparc64_ttable_tl0), %o0
- call prom_set_trap_table_sun4v
- sethi %hi(sparc64_ttable_tl0), %o0
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 2, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ stx %o1, [%sp + 2047 + 128 + 0x20]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
ba,pt %xcc, 2f
nop
-1: call prom_set_trap_table
- sethi %hi(sparc64_ttable_tl0), %o0
+1: sethi %hi(sparc64_ttable_tl0), %o0
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 1, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
/* Start using proper page size encodings in ctx register. */
2: sethi %hi(sparc64_kern_pri_context), %g3
diff --git a/arch/sparc64/kernel/mdesc.c b/arch/sparc64/kernel/mdesc.c
index 9f22e4ff6015..856659bb1311 100644
--- a/arch/sparc64/kernel/mdesc.c
+++ b/arch/sparc64/kernel/mdesc.c
@@ -777,8 +777,12 @@ void __devinit mdesc_fill_in_cpu_data(cpumask_t mask)
cpuid = *id;
#ifdef CONFIG_SMP
- if (cpuid >= NR_CPUS)
+ if (cpuid >= NR_CPUS) {
+ printk(KERN_WARNING "Ignoring CPU %d which is "
+ ">= NR_CPUS (%d)\n",
+ cpuid, NR_CPUS);
continue;
+ }
if (!cpu_isset(cpuid, mask))
continue;
#else
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index d1a78c976cef..0614dff63d7c 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -1583,8 +1583,12 @@ static void __init of_fill_in_cpu_data(void)
ncpus_probed++;
#ifdef CONFIG_SMP
- if (cpuid >= NR_CPUS)
+ if (cpuid >= NR_CPUS) {
+ printk(KERN_WARNING "Ignoring CPU %d which is "
+ ">= NR_CPUS (%d)\n",
+ cpuid, NR_CPUS);
continue;
+ }
#else
/* On uniprocessor we only want the values for the
* real physical cpu the kernel booted onto, however
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
index 9533a25ce5d2..04e81dda13d0 100644
--- a/arch/sparc64/kernel/trampoline.S
+++ b/arch/sparc64/kernel/trampoline.S
@@ -345,7 +345,7 @@ after_lock_tlb:
sethi %hi(tramp_stack), %g1
or %g1, %lo(tramp_stack), %g1
add %g1, TRAMP_STACK_SIZE, %g1
- sub %g1, STACKFRAME_SZ + STACK_BIAS, %sp
+ sub %g1, STACKFRAME_SZ + STACK_BIAS + 256, %sp
mov 0, %fp
/* Put garbage in these registers to trap any access to them. */
@@ -411,15 +411,38 @@ after_lock_tlb:
sethi %hi(kern_base), %g3
ldx [%g3 + %lo(kern_base)], %g3
add %g2, %g3, %o1
+ sethi %hi(sparc64_ttable_tl0), %o0
- call prom_set_trap_table_sun4v
- sethi %hi(sparc64_ttable_tl0), %o0
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 2, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ stx %o1, [%sp + 2047 + 128 + 0x20]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
ba,pt %xcc, 2f
nop
-1: call prom_set_trap_table
- sethi %hi(sparc64_ttable_tl0), %o0
+1: sethi %hi(sparc64_ttable_tl0), %o0
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 1, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
2: ldx [%l0], %g6
ldx [%g6 + TI_TASK], %g4
diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c
index 68c83ad04ad9..bbec7522826c 100644
--- a/arch/sparc64/prom/misc.c
+++ b/arch/sparc64/prom/misc.c
@@ -143,22 +143,6 @@ unsigned char prom_get_idprom(char *idbuf, int num_bytes)
return 0xff;
}
-/* Install Linux trap table so PROM uses that instead of its own. */
-void prom_set_trap_table(unsigned long tba)
-{
- p1275_cmd("SUNW,set-trap-table",
- (P1275_ARG(0, P1275_ARG_IN_64B) |
- P1275_INOUT(1, 0)), tba);
-}
-
-void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa)
-{
- p1275_cmd("SUNW,set-trap-table",
- (P1275_ARG(0, P1275_ARG_IN_64B) |
- P1275_ARG(1, P1275_ARG_IN_64B) |
- P1275_INOUT(2, 0)), tba, mmfsa);
-}
-
int prom_get_mmu_ihandle(void)
{
int node, ret;
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 8d7f7c1cb9c6..6c2be26f1d7d 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -117,7 +117,7 @@ extern void sigio_handler(int sig, union uml_pt_regs *regs);
extern void copy_sc(union uml_pt_regs *regs, void *from);
-unsigned long to_irq_stack(int sig, unsigned long *mask_out);
+extern unsigned long to_irq_stack(unsigned long *mask_out);
unsigned long from_irq_stack(int nested);
#endif
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index 9870febdbead..cf0dd9cf8c43 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -518,13 +518,13 @@ int init_aio_irq(int irq, char *name, irq_handler_t handler)
static unsigned long pending_mask;
-unsigned long to_irq_stack(int sig, unsigned long *mask_out)
+unsigned long to_irq_stack(unsigned long *mask_out)
{
struct thread_info *ti;
unsigned long mask, old;
int nested;
- mask = xchg(&pending_mask, 1 << sig);
+ mask = xchg(&pending_mask, *mask_out);
if(mask != 0){
/* If any interrupts come in at this point, we want to
* make sure that their bits aren't lost by our
@@ -534,7 +534,7 @@ unsigned long to_irq_stack(int sig, unsigned long *mask_out)
* and pending_mask contains a bit for each interrupt
* that came in.
*/
- old = 1 << sig;
+ old = *mask_out;
do {
old |= mask;
mask = xchg(&pending_mask, old);
@@ -550,6 +550,7 @@ unsigned long to_irq_stack(int sig, unsigned long *mask_out)
task = cpu_tasks[ti->cpu].task;
tti = task_thread_info(task);
+
*ti = *tti;
ti->real_thread = tti;
task->stack = ti;
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index 6f92f732d253..c3ecc2a84e0c 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -320,7 +320,8 @@ int os_file_size(char *file, unsigned long long *size_out)
}
if(S_ISBLK(buf.ust_mode)){
- int fd, blocks;
+ int fd;
+ long blocks;
fd = os_open_file(file, of_read(OPENFLAGS()), 0);
if(fd < 0){
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 18e5c8b67eb8..b98f7ea2d2f6 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -119,7 +119,7 @@ void (*handlers[_NSIG])(int sig, struct sigcontext *sc);
void handle_signal(int sig, struct sigcontext *sc)
{
- unsigned long pending = 0;
+ unsigned long pending = 1UL << sig;
do {
int nested, bail;
@@ -134,7 +134,7 @@ void handle_signal(int sig, struct sigcontext *sc)
* have to return, and the upper handler will deal
* with this interrupt.
*/
- bail = to_irq_stack(sig, &pending);
+ bail = to_irq_stack(&pending);
if(bail)
return;
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 327c9f2fa626..54816adb8e93 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -374,6 +374,13 @@ asmlinkage void __kprobes do_page_fault(struct pt_regs *regs,
if (unlikely(in_atomic() || !mm))
goto bad_area_nosemaphore;
+ /*
+ * User-mode registers count as a user access even for any
+ * potential system fault or CPU buglet.
+ */
+ if (user_mode_vm(regs))
+ error_code |= PF_USER;
+
again:
/* When running in the kernel we expect faults to occur only to
* addresses in user space. All other faults represent errors in the
diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile
index 95f836db38fa..acf05be24929 100644
--- a/arch/xtensa/Makefile
+++ b/arch/xtensa/Makefile
@@ -27,7 +27,12 @@ platform-$(CONFIG_XTENSA_PLATFORM_ISS) := iss
PLATFORM = $(platform-y)
export PLATFORM
-CFLAGS += -pipe -mlongcalls
+# temporarily until string.h is fixed
+cflags-y += -ffreestanding
+
+cflags-y += -pipe -mlongcalls
+
+CFLAGS += $(cflags-y)
KBUILD_DEFCONFIG := iss_defconfig
diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile
index 71f733c4f66d..f582d6a24ec2 100644
--- a/arch/xtensa/kernel/Makefile
+++ b/arch/xtensa/kernel/Makefile
@@ -7,7 +7,7 @@ extra-y := head.o vmlinux.lds
obj-y := align.o entry.o irq.o coprocessor.o process.o ptrace.o semaphore.o \
setup.o signal.o syscall.o time.o traps.o vectors.o platform.o \
- pci-dma.o
+ pci-dma.o init_task.o io.o
## windowspill.o
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
index d0323cd6a2ea..d5ffe7b6443e 100644
--- a/arch/xtensa/kernel/asm-offsets.c
+++ b/arch/xtensa/kernel/asm-offsets.c
@@ -18,12 +18,13 @@
#include <linux/stddef.h>
#include <linux/thread_info.h>
#include <linux/ptrace.h>
+#include <linux/mm.h>
+
#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-#define BLANK() asm volatile("\n->" : : )
int main(void)
{
@@ -63,7 +64,6 @@ int main(void)
DEFINE(PT_SIZE, sizeof(struct pt_regs));
DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS]));
DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS]));
- BLANK();
/* struct task_struct */
DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace));
@@ -73,27 +73,26 @@ int main(void)
DEFINE(TASK_THREAD, offsetof (struct task_struct, thread));
DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, stack));
DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct));
- BLANK();
/* struct thread_info (offset from start_struct) */
DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
DEFINE(THREAD_CP_SAVE, offsetof (struct task_struct, thread.cp_save));
DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds));
- BLANK();
/* struct mm_struct */
DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users));
DEFINE(MM_PGD, offsetof (struct mm_struct, pgd));
DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context));
- BLANK();
- DEFINE(PT_SINGLESTEP_BIT, PT_SINGLESTEP_BIT);
+
+ /* struct page */
+ DEFINE(PAGE_FLAGS, offsetof(struct page, flags));
/* constants */
DEFINE(_CLONE_VM, CLONE_VM);
DEFINE(_CLONE_UNTRACED, CLONE_UNTRACED);
+ DEFINE(PG_ARCH_1, PG_arch_1);
return 0;
}
-
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
index 8dc7a2c26ff9..91a689eca43d 100644
--- a/arch/xtensa/kernel/entry.S
+++ b/arch/xtensa/kernel/entry.S
@@ -7,7 +7,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2004-2005 by Tensilica Inc.
+ * Copyright (C) 2004-2007 by Tensilica Inc.
*
* Chris Zankel <chris@zankel.net>
*
@@ -169,7 +169,7 @@ _user_exception:
* We have to save all registers up to the first '1' from
* the right, except the current frame (bit 0).
* Assume a2 is: 001001000110001
- * All regiser frames starting from the top fiel to the marked '1'
+ * All register frames starting from the top field to the marked '1'
* must be saved.
*/
@@ -1572,10 +1572,12 @@ ENTRY(fast_second_level_miss)
l32i a0, a1, TASK_MM # tsk->mm
beqz a0, 9f
-8: rsr a1, EXCVADDR # fault address
- _PGD_OFFSET(a0, a1, a1)
+
+ /* We deliberately destroy a3 that holds the exception table. */
+
+8: rsr a3, EXCVADDR # fault address
+ _PGD_OFFSET(a0, a3, a1)
l32i a0, a0, 0 # read pmdval
- //beqi a0, _PAGE_USER, 2f
beqz a0, 2f
/* Read ptevaddr and convert to top of page-table page.
@@ -1588,7 +1590,7 @@ ENTRY(fast_second_level_miss)
* The messy computation for 'pteval' above really simplifies
* into the following:
*
- * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_KERNEL
+ * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_DIRECTORY
*/
movi a1, -PAGE_OFFSET
@@ -1596,20 +1598,34 @@ ENTRY(fast_second_level_miss)
extui a1, a0, 0, PAGE_SHIFT # ... & PAGE_MASK
xor a0, a0, a1
-
- movi a1, PAGE_DIRECTORY
+ movi a1, _PAGE_DIRECTORY
or a0, a0, a1 # ... | PAGE_DIRECTORY
+ /*
+ * We utilize all three wired-ways (7-9) to hold pmd translations.
+ * Memory regions are mapped to the DTLBs according to bits 28 and 29.
+ * This allows to map the three most common regions to three different
+ * DTLBs:
+ * 0,1 -> way 7 program (0040.0000) and virtual (c000.0000)
+ * 2 -> way 8 shared libaries (2000.0000)
+ * 3 -> way 0 stack (3000.0000)
+ */
+
+ extui a3, a3, 28, 2 # addr. bit 28 and 29 0,1,2,3
rsr a1, PTEVADDR
+ addx2 a3, a3, a3 # -> 0,3,6,9
srli a1, a1, PAGE_SHIFT
+ extui a3, a3, 2, 2 # -> 0,0,1,2
slli a1, a1, PAGE_SHIFT # ptevaddr & PAGE_MASK
- addi a1, a1, DTLB_WAY_PGD # ... + way_number
+ addi a3, a3, DTLB_WAY_PGD
+ add a1, a1, a3 # ... + way_number
- wdtlb a0, a1
+3: wdtlb a0, a1
dsync
/* Exit critical section. */
+4: movi a3, exc_table # restore a3
movi a0, 0
s32i a0, a3, EXC_TABLE_FIXUP
@@ -1636,8 +1652,76 @@ ENTRY(fast_second_level_miss)
9: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0
j 8b
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+
+2: /* Special case for cache aliasing.
+ * We (should) only get here if a clear_user_page, copy_user_page
+ * or the aliased cache flush functions got preemptively interrupted
+ * by another task. Re-establish temporary mapping to the
+ * TLBTEMP_BASE areas.
+ */
+
+ /* We shouldn't be in a double exception */
+
+ l32i a0, a2, PT_DEPC
+ bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 2f
+
+ /* Make sure the exception originated in the special functions */
+
+ movi a0, __tlbtemp_mapping_start
+ rsr a3, EPC_1
+ bltu a3, a0, 2f
+ movi a0, __tlbtemp_mapping_end
+ bgeu a3, a0, 2f
+
+ /* Check if excvaddr was in one of the TLBTEMP_BASE areas. */
+
+ movi a3, TLBTEMP_BASE_1
+ rsr a0, EXCVADDR
+ bltu a0, a3, 2f
+
+ addi a1, a0, -(2 << (DCACHE_ALIAS_ORDER + PAGE_SHIFT))
+ bgeu a1, a3, 2f
+
+ /* Check if we have to restore an ITLB mapping. */
+
+ movi a1, __tlbtemp_mapping_itlb
+ rsr a3, EPC_1
+ sub a3, a3, a1
+
+ /* Calculate VPN */
+
+ movi a1, PAGE_MASK
+ and a1, a1, a0
+
+ /* Jump for ITLB entry */
+
+ bgez a3, 1f
+
+ /* We can use up to two TLBTEMP areas, one for src and one for dst. */
+
+ extui a3, a0, PAGE_SHIFT + DCACHE_ALIAS_ORDER, 1
+ add a1, a3, a1
+
+ /* PPN is in a6 for the first TLBTEMP area and in a7 for the second. */
+
+ mov a0, a6
+ movnez a0, a7, a3
+ j 3b
+
+ /* ITLB entry. We only use dst in a6. */
+
+1: witlb a6, a1
+ isync
+ j 4b
+
+
+#endif // DCACHE_WAY_SIZE > PAGE_SIZE
+
+
2: /* Invalid PGD, default exception handling */
+ movi a3, exc_table
rsr a1, DEPC
xsr a3, EXCSAVE_1
s32i a1, a2, PT_AREG2
@@ -1682,15 +1766,15 @@ ENTRY(fast_store_prohibited)
8: rsr a1, EXCVADDR # fault address
_PGD_OFFSET(a0, a1, a4)
l32i a0, a0, 0
- //beqi a0, _PAGE_USER, 2f # FIXME use _PAGE_INVALID
beqz a0, 2f
+ /* Note that we assume _PAGE_WRITABLE_BIT is only set if pte is valid.*/
+
_PTE_OFFSET(a0, a1, a4)
l32i a4, a0, 0 # read pteval
- movi a1, _PAGE_VALID | _PAGE_RW
- bnall a4, a1, 2f
+ bbci.l a4, _PAGE_WRITABLE_BIT, 2f
- movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_WRENABLE
+ movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_HW_WRITE
or a4, a4, a1
rsr a1, EXCVADDR
s32i a4, a0, 0
@@ -1700,10 +1784,7 @@ ENTRY(fast_store_prohibited)
dhwb a0, 0
#endif
pdtlb a0, a1
- beqz a0, 1f
- idtlb a0 // FIXME do we need this?
wdtlb a4, a0
-1:
/* Exit critical section. */
diff --git a/arch/xtensa/kernel/init_task.c b/arch/xtensa/kernel/init_task.c
new file mode 100644
index 000000000000..021b4f46ff94
--- /dev/null
+++ b/arch/xtensa/kernel/init_task.c
@@ -0,0 +1,38 @@
+/*
+ * arch/xtensa/kernel/init_task.c
+ *
+ * Xtensa Processor version.
+ *
+ * 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) 2007 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/init_task.h>
+#include <linux/module.h>
+#include <linux/mqueue.h>
+
+#include <asm/uaccess.h>
+
+static struct fs_struct init_fs = INIT_FS;
+static struct files_struct init_files = INIT_FILES;
+static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
+static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
+struct mm_struct init_mm = INIT_MM(init_mm);
+
+EXPORT_SYMBOL(init_mm);
+
+union thread_union init_thread_union
+ __attribute__((__section__(".data.init_task"))) =
+{ INIT_THREAD_INFO(init_task) };
+
+struct task_struct init_task = INIT_TASK(init_task);
+
+EXPORT_SYMBOL(init_task);
diff --git a/arch/xtensa/kernel/io.c b/arch/xtensa/kernel/io.c
new file mode 100644
index 000000000000..5b65269b1d2f
--- /dev/null
+++ b/arch/xtensa/kernel/io.c
@@ -0,0 +1,75 @@
+/*
+ * arch/xtensa/io.c
+ *
+ * IO primitives
+ *
+ * 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.
+ *
+ * Copied from sparc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+#include <asm/io.h>
+#include <asm/byteorder.h>
+
+void outsb(unsigned long addr, const void *src, unsigned long count) {
+ while (count) {
+ count -= 1;
+ writeb(*(const char *)src, addr);
+ src += 1;
+ addr += 1;
+ }
+}
+
+void outsw(unsigned long addr, const void *src, unsigned long count) {
+ while (count) {
+ count -= 2;
+ writew(*(const short *)src, addr);
+ src += 2;
+ addr += 2;
+ }
+}
+
+void outsl(unsigned long addr, const void *src, unsigned long count) {
+ while (count) {
+ count -= 4;
+ writel(*(const long *)src, addr);
+ src += 4;
+ addr += 4;
+ }
+}
+
+void insb(unsigned long addr, void *dst, unsigned long count) {
+ while (count) {
+ count -= 1;
+ *(unsigned char *)dst = readb(addr);
+ dst += 1;
+ addr += 1;
+ }
+}
+
+void insw(unsigned long addr, void *dst, unsigned long count) {
+ while (count) {
+ count -= 2;
+ *(unsigned short *)dst = readw(addr);
+ dst += 2;
+ addr += 2;
+ }
+}
+
+void insl(unsigned long addr, void *dst, unsigned long count) {
+ while (count) {
+ count -= 4;
+ /*
+ * XXX I am sure we are in for an unaligned trap here.
+ */
+ *(unsigned long *)dst = readl(addr);
+ dst += 4;
+ addr += 4;
+ }
+}
diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c
index 2ea1755a0858..ddf14dcf2ad9 100644
--- a/arch/xtensa/kernel/module.c
+++ b/arch/xtensa/kernel/module.c
@@ -7,7 +7,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2001 - 2006 Tensilica Inc.
*
* Chris Zankel <chris@zankel.net>
*
@@ -22,57 +22,216 @@
#include <linux/kernel.h>
#include <linux/cache.h>
-LIST_HEAD(module_buf_list);
+#undef DEBUG_RELOCATE
void *module_alloc(unsigned long size)
{
- panic("module_alloc not implemented");
+ if (size == 0)
+ return NULL;
+ return vmalloc(size);
}
void module_free(struct module *mod, void *module_region)
{
- panic("module_free not implemented");
+ vfree(module_region);
+ /* FIXME: If module_region == mod->init_region, trim exception
+ table entries. */
}
int module_frob_arch_sections(Elf32_Ehdr *hdr,
Elf32_Shdr *sechdrs,
char *secstrings,
- struct module *me)
+ struct module *mod)
{
- panic("module_frob_arch_sections not implemented");
+ return 0;
+}
+
+static int
+decode_calln_opcode (unsigned char *location)
+{
+#ifdef __XTENSA_EB__
+ return (location[0] & 0xf0) == 0x50;
+#endif
+#ifdef __XTENSA_EL__
+ return (location[0] & 0xf) == 0x5;
+#endif
+}
+
+static int
+decode_l32r_opcode (unsigned char *location)
+{
+#ifdef __XTENSA_EB__
+ return (location[0] & 0xf0) == 0x10;
+#endif
+#ifdef __XTENSA_EL__
+ return (location[0] & 0xf) == 0x1;
+#endif
}
int apply_relocate(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
- struct module *module)
+ struct module *mod)
{
- panic ("apply_relocate not implemented");
+ printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
+ mod->name);
+ return -ENOEXEC;
+
}
int apply_relocate_add(Elf32_Shdr *sechdrs,
const char *strtab,
unsigned int symindex,
unsigned int relsec,
- struct module *module)
+ struct module *mod)
{
- panic("apply_relocate_add not implemented");
+ unsigned int i;
+ Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
+ Elf32_Sym *sym;
+ unsigned char *location;
+ uint32_t value;
+
+#ifdef DEBUG_RELOCATE
+ printk("Applying relocate section %u to %u\n", relsec,
+ sechdrs[relsec].sh_info);
+#endif
+ for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
+ location = (char *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ + rela[i].r_offset;
+ sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ + ELF32_R_SYM(rela[i].r_info);
+ value = sym->st_value + rela[i].r_addend;
+
+ switch (ELF32_R_TYPE(rela[i].r_info)) {
+ case R_XTENSA_NONE:
+ case R_XTENSA_DIFF8:
+ case R_XTENSA_DIFF16:
+ case R_XTENSA_DIFF32:
+ case R_XTENSA_ASM_EXPAND:
+ break;
+
+ case R_XTENSA_32:
+ case R_XTENSA_PLT:
+ *(uint32_t *)location += value;
+ break;
+
+ case R_XTENSA_SLOT0_OP:
+ if (decode_calln_opcode(location)) {
+ value -= ((unsigned long)location & -4) + 4;
+ if ((value & 3) != 0 ||
+ ((value + (1 << 19)) >> 20) != 0) {
+ printk("%s: relocation out of range, "
+ "section %d reloc %d "
+ "sym '%s'\n",
+ mod->name, relsec, i,
+ strtab + sym->st_name);
+ return -ENOEXEC;
+ }
+ value = (signed int)value >> 2;
+#ifdef __XTENSA_EB__
+ location[0] = ((location[0] & ~0x3) |
+ ((value >> 16) & 0x3));
+ location[1] = (value >> 8) & 0xff;
+ location[2] = value & 0xff;
+#endif
+#ifdef __XTENSA_EL__
+ location[0] = ((location[0] & ~0xc0) |
+ ((value << 6) & 0xc0));
+ location[1] = (value >> 2) & 0xff;
+ location[2] = (value >> 10) & 0xff;
+#endif
+ } else if (decode_l32r_opcode(location)) {
+ value -= (((unsigned long)location + 3) & -4);
+ if ((value & 3) != 0 ||
+ (signed int)value >> 18 != -1) {
+ printk("%s: relocation out of range, "
+ "section %d reloc %d "
+ "sym '%s'\n",
+ mod->name, relsec, i,
+ strtab + sym->st_name);
+ return -ENOEXEC;
+ }
+ value = (signed int)value >> 2;
+
+#ifdef __XTENSA_EB__
+ location[1] = (value >> 8) & 0xff;
+ location[2] = value & 0xff;
+#endif
+#ifdef __XTENSA_EL__
+ location[1] = value & 0xff;
+ location[2] = (value >> 8) & 0xff;
+#endif
+ }
+ /* FIXME: Ignore any other opcodes. The Xtensa
+ assembler currently assumes that the linker will
+ always do relaxation and so all PC-relative
+ operands need relocations. (The assembler also
+ writes out the tentative PC-relative values,
+ assuming no link-time relaxation, so it is usually
+ safe to ignore the relocations.) If the
+ assembler's "--no-link-relax" flag can be made to
+ work, and if all kernel modules can be assembled
+ with that flag, then unexpected relocations could
+ be detected here. */
+ break;
+
+ case R_XTENSA_SLOT1_OP:
+ case R_XTENSA_SLOT2_OP:
+ case R_XTENSA_SLOT3_OP:
+ case R_XTENSA_SLOT4_OP:
+ case R_XTENSA_SLOT5_OP:
+ case R_XTENSA_SLOT6_OP:
+ case R_XTENSA_SLOT7_OP:
+ case R_XTENSA_SLOT8_OP:
+ case R_XTENSA_SLOT9_OP:
+ case R_XTENSA_SLOT10_OP:
+ case R_XTENSA_SLOT11_OP:
+ case R_XTENSA_SLOT12_OP:
+ case R_XTENSA_SLOT13_OP:
+ case R_XTENSA_SLOT14_OP:
+ printk("%s: unexpected FLIX relocation: %u\n",
+ mod->name,
+ ELF32_R_TYPE(rela[i].r_info));
+ return -ENOEXEC;
+
+ case R_XTENSA_SLOT0_ALT:
+ case R_XTENSA_SLOT1_ALT:
+ case R_XTENSA_SLOT2_ALT:
+ case R_XTENSA_SLOT3_ALT:
+ case R_XTENSA_SLOT4_ALT:
+ case R_XTENSA_SLOT5_ALT:
+ case R_XTENSA_SLOT6_ALT:
+ case R_XTENSA_SLOT7_ALT:
+ case R_XTENSA_SLOT8_ALT:
+ case R_XTENSA_SLOT9_ALT:
+ case R_XTENSA_SLOT10_ALT:
+ case R_XTENSA_SLOT11_ALT:
+ case R_XTENSA_SLOT12_ALT:
+ case R_XTENSA_SLOT13_ALT:
+ case R_XTENSA_SLOT14_ALT:
+ printk("%s: unexpected ALT relocation: %u\n",
+ mod->name,
+ ELF32_R_TYPE(rela[i].r_info));
+ return -ENOEXEC;
+
+ default:
+ printk("%s: unexpected relocation: %u\n",
+ mod->name,
+ ELF32_R_TYPE(rela[i].r_info));
+ return -ENOEXEC;
+ }
+ }
+ return 0;
}
int module_finalize(const Elf_Ehdr *hdr,
const Elf_Shdr *sechdrs,
- struct module *me)
+ struct module *mod)
{
- panic ("module_finalize not implemented");
+ return 0;
}
void module_arch_cleanup(struct module *mod)
{
- panic("module_arch_cleanup not implemented");
-}
-
-struct bug_entry *module_find_bug(unsigned long bugaddr)
-{
- panic("module_find_bug not implemented");
}
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 77deae5290f0..b7c073484e01 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -394,72 +394,3 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
return ret;
}
-
-/*
- * This probably belongs here rather than ioport.c because
- * we do not want this crud linked into SBus kernels.
- * Also, think for a moment about likes of floppy.c that
- * include architecture specific parts. They may want to redefine ins/outs.
- *
- * We do not use horrible macros here because we want to
- * advance pointer by sizeof(size).
- */
-void outsb(unsigned long addr, const void *src, unsigned long count) {
- while (count) {
- count -= 1;
- writeb(*(const char *)src, addr);
- src += 1;
- addr += 1;
- }
-}
-
-void outsw(unsigned long addr, const void *src, unsigned long count) {
- while (count) {
- count -= 2;
- writew(*(const short *)src, addr);
- src += 2;
- addr += 2;
- }
-}
-
-void outsl(unsigned long addr, const void *src, unsigned long count) {
- while (count) {
- count -= 4;
- writel(*(const long *)src, addr);
- src += 4;
- addr += 4;
- }
-}
-
-void insb(unsigned long addr, void *dst, unsigned long count) {
- while (count) {
- count -= 1;
- *(unsigned char *)dst = readb(addr);
- dst += 1;
- addr += 1;
- }
-}
-
-void insw(unsigned long addr, void *dst, unsigned long count) {
- while (count) {
- count -= 2;
- *(unsigned short *)dst = readw(addr);
- dst += 2;
- addr += 2;
- }
-}
-
-void insl(unsigned long addr, void *dst, unsigned long count) {
- while (count) {
- count -= 4;
- /*
- * XXX I am sure we are in for an unaligned trap here.
- */
- *(unsigned long *)dst = readl(addr);
- dst += 4;
- addr += 4;
- }
-}
-
-
-
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
index dd498f1604e1..f53d7bd9dfb2 100644
--- a/arch/xtensa/kernel/process.c
+++ b/arch/xtensa/kernel/process.c
@@ -46,20 +46,6 @@
extern void ret_from_fork(void);
-static struct fs_struct init_fs = INIT_FS;
-static struct files_struct init_files = INIT_FILES;
-static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
-static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
-struct mm_struct init_mm = INIT_MM(init_mm);
-EXPORT_SYMBOL(init_mm);
-
-union thread_union init_thread_union
- __attribute__((__section__(".data.init_task"))) =
-{ INIT_THREAD_INFO(init_task) };
-
-struct task_struct init_task = INIT_TASK(init_task);
-EXPORT_SYMBOL(init_task);
-
struct task_struct *current_set[NR_CPUS] = {&init_task, };
void (*pm_power_off)(void) = NULL;
diff --git a/arch/xtensa/kernel/semaphore.c b/arch/xtensa/kernel/semaphore.c
index d40f4b1b75ac..995c6410ae10 100644
--- a/arch/xtensa/kernel/semaphore.c
+++ b/arch/xtensa/kernel/semaphore.c
@@ -100,7 +100,7 @@ static __inline__ int waking_non_zero_trylock(struct semaphore *sem)
return ret;
}
-spinlock_t semaphore_wake_lock;
+DEFINE_SPINLOCK(semaphore_wake_lock);
/*
* Semaphores are implemented using a two-way counter:
diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c
index fe3834bc1dbf..f3e16efcd47a 100644
--- a/arch/xtensa/kernel/syscall.c
+++ b/arch/xtensa/kernel/syscall.c
@@ -93,3 +93,8 @@ asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg)
return (long)ret;
}
+asmlinkage long xtensa_fadvise64_64(int fd, int advice, unsigned long long offset, unsigned long long len)
+{
+ return sys_fadvise64_64(fd, offset, len, advice);
+}
+
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
index 22949be4a5d8..60d29fe0b1bd 100644
--- a/arch/xtensa/kernel/time.c
+++ b/arch/xtensa/kernel/time.c
@@ -32,12 +32,20 @@ EXPORT_SYMBOL(rtc_lock);
#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
unsigned long ccount_per_jiffy; /* per 1/HZ */
-unsigned long ccount_nsec; /* nsec per ccount increment */
+unsigned long nsec_per_ccount; /* nsec per ccount increment */
#endif
-unsigned int last_ccount_stamp;
static long last_rtc_update = 0;
+/*
+ * Scheduler clock - returns current tim in nanosec units.
+ */
+
+unsigned long long sched_clock(void)
+{
+ return (unsigned long long)jiffies * (1000000000 / HZ);
+}
+
static irqreturn_t timer_interrupt(int irq, void *dev_id);
static struct irqaction timer_irqaction = {
.handler = timer_interrupt,
@@ -69,7 +77,6 @@ void __init time_init(void)
xtime.tv_nsec = 0;
last_rtc_update = xtime.tv_sec = sec_n;
- last_ccount_stamp = get_ccount();
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
@@ -85,7 +92,7 @@ int do_settimeofday(struct timespec *tv)
{
time_t wtm_sec, sec = tv->tv_sec;
long wtm_nsec, nsec = tv->tv_nsec;
- unsigned long ccount;
+ unsigned long delta;
if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
return -EINVAL;
@@ -97,8 +104,10 @@ int do_settimeofday(struct timespec *tv)
* wall time. Discover what correction gettimeofday() would have
* made, and then undo it!
*/
- ccount = get_ccount();
- nsec -= (ccount - last_ccount_stamp) * CCOUNT_NSEC;
+
+ delta = CCOUNT_PER_JIFFY;
+ delta += get_ccount() - get_linux_timer();
+ nsec -= delta * NSEC_PER_CCOUNT;
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
@@ -117,17 +126,21 @@ EXPORT_SYMBOL(do_settimeofday);
void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
- unsigned long sec, usec, delta, seq;
+ unsigned long volatile sec, usec, delta, seq;
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
- delta = get_ccount() - last_ccount_stamp;
sec = xtime.tv_sec;
usec = (xtime.tv_nsec / NSEC_PER_USEC);
+
+ delta = get_linux_timer() - get_ccount();
+
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
- usec += (delta * CCOUNT_NSEC) / NSEC_PER_USEC;
+ usec += (((unsigned long) CCOUNT_PER_JIFFY - delta)
+ * (unsigned long) NSEC_PER_CCOUNT) / NSEC_PER_USEC;
+
for (; usec >= 1000000; sec++, usec -= 1000000)
;
@@ -158,9 +171,12 @@ again:
write_seqlock(&xtime_lock);
- last_ccount_stamp = next;
+ do_timer(1); /* Linux handler in kernel/timer.c */
+
+ /* Note that writing CCOMPARE clears the interrupt. */
+
next += CCOUNT_PER_JIFFY;
- do_timer (1); /* Linux handler in kernel/timer.c */
+ set_linux_timer(next);
if (ntp_synced() &&
xtime.tv_sec - last_rtc_update >= 659 &&
@@ -175,19 +191,15 @@ again:
write_sequnlock(&xtime_lock);
}
- /* NOTE: writing CCOMPAREn clears the interrupt. */
+ /* Allow platform to do something useful (Wdog). */
- set_linux_timer (next);
+ platform_heartbeat();
/* Make sure we didn't miss any tick... */
if ((signed long)(get_ccount() - next) > 0)
goto again;
- /* Allow platform to do something useful (Wdog). */
-
- platform_heartbeat();
-
return IRQ_HANDLED;
}
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c
index c5e62f9d9f50..8be99c777d9d 100644
--- a/arch/xtensa/kernel/traps.c
+++ b/arch/xtensa/kernel/traps.c
@@ -83,7 +83,7 @@ typedef struct {
void* handler;
} dispatch_init_table_t;
-dispatch_init_table_t __init dispatch_init_table[] = {
+static dispatch_init_table_t __initdata dispatch_init_table[] = {
{ EXCCAUSE_ILLEGAL_INSTRUCTION, 0, do_illegal_instruction},
{ EXCCAUSE_SYSTEM_CALL, KRNL, fast_syscall_kernel },
@@ -305,7 +305,7 @@ do_debug(struct pt_regs *regs)
#define set_handler(idx,handler) (exc_table[idx] = (unsigned long) (handler))
-void trap_init(void)
+void __init trap_init(void)
{
int i;
diff --git a/arch/xtensa/mm/Makefile b/arch/xtensa/mm/Makefile
index a5aed5932d7b..10aec22a8f98 100644
--- a/arch/xtensa/mm/Makefile
+++ b/arch/xtensa/mm/Makefile
@@ -5,9 +5,5 @@
# removes any old dependencies. DON'T put your own dependencies here
# unless it's something special (ie not a .c file).
#
-# Note 2! The CFLAGS definition is now in the main makefile...
-obj-y := init.o fault.o tlb.o misc.o
-obj-m :=
-obj-n :=
-obj- :=
+obj-y := init.o fault.o tlb.o misc.o cache.o
diff --git a/arch/xtensa/mm/cache.c b/arch/xtensa/mm/cache.c
new file mode 100644
index 000000000000..9a1fa9478ae7
--- /dev/null
+++ b/arch/xtensa/mm/cache.c
@@ -0,0 +1,256 @@
+/*
+ * arch/xtensa/mm/cache.c
+ *
+ * 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) 2001-2006 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Joe Taylor
+ * Marc Gauthier
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/bootmem.h>
+#include <linux/swap.h>
+#include <linux/pagemap.h>
+
+#include <asm/pgtable.h>
+#include <asm/bootparam.h>
+#include <asm/mmu_context.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+
+//#define printd(x...) printk(x)
+#define printd(x...) do { } while(0)
+
+/*
+ * Note:
+ * The kernel provides one architecture bit PG_arch_1 in the page flags that
+ * can be used for cache coherency.
+ *
+ * I$-D$ coherency.
+ *
+ * The Xtensa architecture doesn't keep the instruction cache coherent with
+ * the data cache. We use the architecture bit to indicate if the caches
+ * are coherent. The kernel clears this bit whenever a page is added to the
+ * page cache. At that time, the caches might not be in sync. We, therefore,
+ * define this flag as 'clean' if set.
+ *
+ * D-cache aliasing.
+ *
+ * With cache aliasing, we have to always flush the cache when pages are
+ * unmapped (see tlb_start_vma(). So, we use this flag to indicate a dirty
+ * page.
+ *
+ *
+ *
+ */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+
+/*
+ * Any time the kernel writes to a user page cache page, or it is about to
+ * read from a page cache page this routine is called.
+ *
+ */
+
+void flush_dcache_page(struct page *page)
+{
+ struct address_space *mapping = page_mapping(page);
+
+ /*
+ * If we have a mapping but the page is not mapped to user-space
+ * yet, we simply mark this page dirty and defer flushing the
+ * caches until update_mmu().
+ */
+
+ if (mapping && !mapping_mapped(mapping)) {
+ if (!test_bit(PG_arch_1, &page->flags))
+ set_bit(PG_arch_1, &page->flags);
+ return;
+
+ } else {
+
+ unsigned long phys = page_to_phys(page);
+ unsigned long temp = page->index << PAGE_SHIFT;
+ unsigned long alias = !(DCACHE_ALIAS_EQ(temp, phys));
+ unsigned long virt;
+
+ /*
+ * Flush the page in kernel space and user space.
+ * Note that we can omit that step if aliasing is not
+ * an issue, but we do have to synchronize I$ and D$
+ * if we have a mapping.
+ */
+
+ if (!alias && !mapping)
+ return;
+
+ __flush_invalidate_dcache_page((long)page_address(page));
+
+ virt = TLBTEMP_BASE_1 + (temp & DCACHE_ALIAS_MASK);
+
+ if (alias)
+ __flush_invalidate_dcache_page_alias(virt, phys);
+
+ if (mapping)
+ __invalidate_icache_page_alias(virt, phys);
+ }
+
+ /* There shouldn't be an entry in the cache for this page anymore. */
+}
+
+
+/*
+ * For now, flush the whole cache. FIXME??
+ */
+
+void flush_cache_range(struct vm_area_struct* vma,
+ unsigned long start, unsigned long end)
+{
+ __flush_invalidate_dcache_all();
+ __invalidate_icache_all();
+}
+
+/*
+ * Remove any entry in the cache for this page.
+ *
+ * Note that this function is only called for user pages, so use the
+ * alias versions of the cache flush functions.
+ */
+
+void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
+ unsigned long pfn)
+{
+ /* Note that we have to use the 'alias' address to avoid multi-hit */
+
+ unsigned long phys = page_to_phys(pfn_to_page(pfn));
+ unsigned long virt = TLBTEMP_BASE_1 + (address & DCACHE_ALIAS_MASK);
+
+ __flush_invalidate_dcache_page_alias(virt, phys);
+ __invalidate_icache_page_alias(virt, phys);
+}
+
+#endif
+
+void
+update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t pte)
+{
+ unsigned long pfn = pte_pfn(pte);
+ struct page *page;
+
+ if (!pfn_valid(pfn))
+ return;
+
+ page = pfn_to_page(pfn);
+
+ /* Invalidate old entry in TLBs */
+
+ invalidate_itlb_mapping(addr);
+ invalidate_dtlb_mapping(addr);
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+
+ if (!PageReserved(page) && test_bit(PG_arch_1, &page->flags)) {
+
+ unsigned long vaddr = TLBTEMP_BASE_1 + (addr & DCACHE_ALIAS_MASK);
+ unsigned long paddr = (unsigned long) page_address(page);
+ unsigned long phys = page_to_phys(page);
+
+ __flush_invalidate_dcache_page(paddr);
+
+ __flush_invalidate_dcache_page_alias(vaddr, phys);
+ __invalidate_icache_page_alias(vaddr, phys);
+
+ clear_bit(PG_arch_1, &page->flags);
+ }
+#else
+ if (!PageReserved(page) && !test_bit(PG_arch_1, &page->flags)
+ && (vma->vm_flags & VM_EXEC) != 0) {
+ unsigned long vaddr = addr & PAGE_MASK;
+ __flush_dcache_page(vaddr);
+ __invalidate_icache_page(vaddr);
+ set_bit(PG_arch_1, &page->flags);
+ }
+#endif
+}
+
+/*
+ * access_process_vm() has called get_user_pages(), which has done a
+ * flush_dcache_page() on the page.
+ */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, void *dst, const void *src,
+ unsigned long len)
+{
+ unsigned long phys = page_to_phys(page);
+ unsigned long alias = !(DCACHE_ALIAS_EQ(vaddr, phys));
+
+ /* Flush and invalidate user page if aliased. */
+
+ if (alias) {
+ unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+ __flush_invalidate_dcache_page_alias(temp, phys);
+ }
+
+ /* Copy data */
+
+ memcpy(dst, src, len);
+
+ /*
+ * Flush and invalidate kernel page if aliased and synchronize
+ * data and instruction caches for executable pages.
+ */
+
+ if (alias) {
+ unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+
+ __flush_invalidate_dcache_range((unsigned long) dst, len);
+ if ((vma->vm_flags & VM_EXEC) != 0) {
+ __invalidate_icache_page_alias(temp, phys);
+ }
+
+ } else if ((vma->vm_flags & VM_EXEC) != 0) {
+ __flush_dcache_range((unsigned long)dst,len);
+ __invalidate_icache_range((unsigned long) dst, len);
+ }
+}
+
+extern void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long vaddr, void *dst, const void *src,
+ unsigned long len)
+{
+ unsigned long phys = page_to_phys(page);
+ unsigned long alias = !(DCACHE_ALIAS_EQ(vaddr, phys));
+
+ /*
+ * Flush user page if aliased.
+ * (Note: a simply flush would be sufficient)
+ */
+
+ if (alias) {
+ unsigned long temp = TLBTEMP_BASE_1 + (vaddr & DCACHE_ALIAS_MASK);
+ __flush_invalidate_dcache_page_alias(temp, phys);
+ }
+
+ memcpy(dst, src, len);
+}
+
+#endif
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
index 16004067add3..45d28f217c03 100644
--- a/arch/xtensa/mm/fault.c
+++ b/arch/xtensa/mm/fault.c
@@ -24,6 +24,8 @@
unsigned long asid_cache = ASID_USER_FIRST;
void bad_page_fault(struct pt_regs*, unsigned long, int);
+#undef DEBUG_PAGE_FAULT
+
/*
* This routine handles page faults. It determines the address,
* and the problem, and then passes it off to one of the appropriate
@@ -64,7 +66,7 @@ void do_page_fault(struct pt_regs *regs)
exccause == EXCCAUSE_ITLB_MISS ||
exccause == EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0;
-#if 0
+#ifdef DEBUG_PAGE_FAULT
printk("[%s:%d:%08x:%d:%08x:%s%s]\n", current->comm, current->pid,
address, exccause, regs->pc, is_write? "w":"", is_exec? "x":"");
#endif
@@ -219,7 +221,7 @@ bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
/* Are we prepared to handle this kernel fault? */
if ((entry = search_exception_tables(regs->pc)) != NULL) {
-#if 1
+#ifdef DEBUG_PAGE_FAULT
printk(KERN_DEBUG "%s: Exception at pc=%#010lx (%lx)\n",
current->comm, regs->pc, entry->fixup);
#endif
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c
index 8415c76f11c2..b3086f34a8e7 100644
--- a/arch/xtensa/mm/init.c
+++ b/arch/xtensa/mm/init.c
@@ -15,40 +15,24 @@
* Kevin Chea
*/
-#include <linux/init.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
#include <linux/bootmem.h>
#include <linux/swap.h>
+#include <linux/mman.h>
+#include <linux/nodemask.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
#include <asm/pgtable.h>
#include <asm/bootparam.h>
#include <asm/mmu_context.h>
#include <asm/tlb.h>
-#include <asm/tlbflush.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-
-#define DEBUG 0
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-//static DEFINE_SPINLOCK(tlb_lock);
-
-/*
- * This flag is used to indicate that the page was mapped and modified in
- * kernel space, so the cache is probably dirty at that address.
- * If cache aliasing is enabled and the page color mismatches, update_mmu_cache
- * synchronizes the caches if this bit is set.
- */
-
-#define PG_cache_clean PG_arch_1
/* References to section boundaries */
@@ -323,228 +307,22 @@ void show_mem(void)
printk("%d free pages\n", free);
}
-/* ------------------------------------------------------------------------- */
-
-#if (DCACHE_WAY_SIZE > PAGE_SIZE)
-
-/*
- * With cache aliasing, the page color of the page in kernel space and user
- * space might mismatch. We temporarily map the page to a different virtual
- * address with the same color and clear the page there.
- */
-
-void clear_user_page(void *kaddr, unsigned long vaddr, struct page* page)
-{
-
- /* There shouldn't be any entries for this page. */
-
- __flush_invalidate_dcache_page_phys(__pa(page_address(page)));
-
- if (!PAGE_COLOR_EQ(vaddr, kaddr)) {
- unsigned long v, p;
-
- /* Temporarily map page to DTLB_WAY_DCACHE_ALIAS0. */
-
- spin_lock(&tlb_lock);
-
- p = (unsigned long)pte_val((mk_pte(page,PAGE_KERNEL)));
- kaddr = (void*)PAGE_COLOR_MAP0(vaddr);
- v = (unsigned long)kaddr | DTLB_WAY_DCACHE_ALIAS0;
- __asm__ __volatile__("wdtlb %0,%1; dsync" : :"a" (p), "a" (v));
-
- clear_page(kaddr);
-
- spin_unlock(&tlb_lock);
- } else {
- clear_page(kaddr);
- }
-
- /* We need to make sure that i$ and d$ are coherent. */
-
- clear_bit(PG_cache_clean, &page->flags);
-}
-
-/*
- * With cache aliasing, we have to make sure that the page color of the page
- * in kernel space matches that of the virtual user address before we read
- * the page. If the page color differ, we create a temporary DTLB entry with
- * the corrent page color and use this 'temporary' address as the source.
- * We then use the same approach as in clear_user_page and copy the data
- * to the kernel space and clear the PG_cache_clean bit to synchronize caches
- * later.
- *
- * Note:
- * Instead of using another 'way' for the temporary DTLB entry, we could
- * probably use the same entry that points to the kernel address (after
- * saving the original value and restoring it when we are done).
- */
+struct kmem_cache *pgtable_cache __read_mostly;
-void copy_user_page(void* to, void* from, unsigned long vaddr,
- struct page* to_page)
+static void pgd_ctor(void *addr, struct kmem_cache *cache, unsigned long flags)
{
- /* There shouldn't be any entries for the new page. */
-
- __flush_invalidate_dcache_page_phys(__pa(page_address(to_page)));
-
- spin_lock(&tlb_lock);
-
- if (!PAGE_COLOR_EQ(vaddr, from)) {
- unsigned long v, p, t;
-
- __asm__ __volatile__ ("pdtlb %1,%2; rdtlb1 %0,%1"
- : "=a"(p), "=a"(t) : "a"(from));
- from = (void*)PAGE_COLOR_MAP0(vaddr);
- v = (unsigned long)from | DTLB_WAY_DCACHE_ALIAS0;
- __asm__ __volatile__ ("wdtlb %0,%1; dsync" ::"a" (p), "a" (v));
- }
-
- if (!PAGE_COLOR_EQ(vaddr, to)) {
- unsigned long v, p;
-
- p = (unsigned long)pte_val((mk_pte(to_page,PAGE_KERNEL)));
- to = (void*)PAGE_COLOR_MAP1(vaddr);
- v = (unsigned long)to | DTLB_WAY_DCACHE_ALIAS1;
- __asm__ __volatile__ ("wdtlb %0,%1; dsync" ::"a" (p), "a" (v));
- }
- copy_page(to, from);
-
- spin_unlock(&tlb_lock);
-
- /* We need to make sure that i$ and d$ are coherent. */
-
- clear_bit(PG_cache_clean, &to_page->flags);
-}
-
-
-
-/*
- * Any time the kernel writes to a user page cache page, or it is about to
- * read from a page cache page this routine is called.
- *
- * Note:
- * The kernel currently only provides one architecture bit in the page
- * flags that we use for I$/D$ coherency. Maybe, in future, we can
- * use a sepearte bit for deferred dcache aliasing:
- * If the page is not mapped yet, we only need to set a flag,
- * if mapped, we need to invalidate the page.
- */
-// FIXME: we probably need this for WB caches not only for Page Coloring..
-
-void flush_dcache_page(struct page *page)
-{
- unsigned long addr = __pa(page_address(page));
- struct address_space *mapping = page_mapping(page);
-
- __flush_invalidate_dcache_page_phys(addr);
-
- if (!test_bit(PG_cache_clean, &page->flags))
- return;
-
- /* If this page hasn't been mapped, yet, handle I$/D$ coherency later.*/
-#if 0
- if (mapping && !mapping_mapped(mapping))
- clear_bit(PG_cache_clean, &page->flags);
- else
-#endif
- __invalidate_icache_page_phys(addr);
-}
-
-void flush_cache_range(struct vm_area_struct* vma, unsigned long s,
- unsigned long e)
-{
- __flush_invalidate_cache_all();
-}
-
-void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
- unsigned long pfn)
-{
- struct page *page = pfn_to_page(pfn);
-
- /* Remove any entry for the old mapping. */
-
- if (current->active_mm == vma->vm_mm) {
- unsigned long addr = __pa(page_address(page));
- __flush_invalidate_dcache_page_phys(addr);
- if ((vma->vm_flags & VM_EXEC) != 0)
- __invalidate_icache_page_phys(addr);
- } else {
- BUG();
- }
-}
-
-#endif /* (DCACHE_WAY_SIZE > PAGE_SIZE) */
-
-
-pte_t* pte_alloc_one_kernel (struct mm_struct* mm, unsigned long addr)
-{
- pte_t* pte = (pte_t*)__get_free_pages(GFP_KERNEL|__GFP_REPEAT, 0);
- if (likely(pte)) {
- pte_t* ptep = (pte_t*)(pte_val(*pte) + PAGE_OFFSET);
- int i;
- for (i = 0; i < 1024; i++, ptep++)
- pte_clear(mm, addr, ptep);
- }
- return pte;
-}
-
-struct page* pte_alloc_one(struct mm_struct *mm, unsigned long addr)
-{
- struct page *page;
-
- page = alloc_pages(GFP_KERNEL | __GFP_REPEAT, 0);
-
- if (likely(page)) {
- pte_t* ptep = kmap_atomic(page, KM_USER0);
- int i;
+ pte_t* ptep = (pte_t*)addr;
+ int i;
- for (i = 0; i < 1024; i++, ptep++)
- pte_clear(mm, addr, ptep);
+ for (i = 0; i < 1024; i++, ptep++)
+ pte_clear(NULL, 0, ptep);
- kunmap_atomic(ptep, KM_USER0);
- }
- return page;
}
-
-/*
- * Handle D$/I$ coherency.
- *
- * Note:
- * We only have one architecture bit for the page flags, so we cannot handle
- * cache aliasing, yet.
- */
-
-void
-update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t pte)
+void __init pgtable_cache_init(void)
{
- unsigned long pfn = pte_pfn(pte);
- struct page *page;
- unsigned long vaddr = addr & PAGE_MASK;
-
- if (!pfn_valid(pfn))
- return;
-
- page = pfn_to_page(pfn);
-
- invalidate_itlb_mapping(addr);
- invalidate_dtlb_mapping(addr);
-
- /* We have a new mapping. Use it. */
-
- write_dtlb_entry(pte, dtlb_probe(addr));
-
- /* If the processor can execute from this page, synchronize D$/I$. */
-
- if ((vma->vm_flags & VM_EXEC) != 0) {
-
- write_itlb_entry(pte, itlb_probe(addr));
-
- /* Synchronize caches, if not clean. */
-
- if (!test_and_set_bit(PG_cache_clean, &page->flags)) {
- __flush_dcache_page(vaddr);
- __invalidate_icache_page(vaddr);
- }
- }
+ pgtable_cache = kmem_cache_create("pgd",
+ PAGE_SIZE, PAGE_SIZE,
+ SLAB_HWCACHE_ALIGN,
+ pgd_ctor);
}
-
diff --git a/arch/xtensa/mm/misc.S b/arch/xtensa/mm/misc.S
index ae085332c607..e1f880368e32 100644
--- a/arch/xtensa/mm/misc.S
+++ b/arch/xtensa/mm/misc.S
@@ -7,29 +7,33 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2001 - 2005 Tensilica Inc.
+ * Copyright (C) 2001 - 2007 Tensilica Inc.
*
* Chris Zankel <chris@zankel.net>
*/
-/* Note: we might want to implement some of the loops as zero-overhead-loops,
- * where applicable and if supported by the processor.
- */
#include <linux/linkage.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/asmmacro.h>
#include <asm/cacheasm.h>
+#include <asm/tlbflush.h>
+
-/* clear_page (page) */
+/*
+ * clear_page and clear_user_page are the same for non-cache-aliased configs.
+ *
+ * clear_page (unsigned long page)
+ * a2
+ */
ENTRY(clear_page)
entry a1, 16
- addi a4, a2, PAGE_SIZE
- movi a3, 0
-1: s32i a3, a2, 0
+ movi a3, 0
+ __loopi a2, a7, PAGE_SIZE, 32
+ s32i a3, a2, 0
s32i a3, a2, 4
s32i a3, a2, 8
s32i a3, a2, 12
@@ -37,42 +41,277 @@ ENTRY(clear_page)
s32i a3, a2, 20
s32i a3, a2, 24
s32i a3, a2, 28
- addi a2, a2, 32
- blt a2, a4, 1b
+ __endla a2, a7, 32
retw
/*
+ * copy_page and copy_user_page are the same for non-cache-aliased configs.
+ *
* copy_page (void *to, void *from)
- * a2 a3
+ * a2 a3
*/
ENTRY(copy_page)
entry a1, 16
- addi a4, a2, PAGE_SIZE
-
-1: l32i a5, a3, 0
- l32i a6, a3, 4
- l32i a7, a3, 8
- s32i a5, a2, 0
- s32i a6, a2, 4
- s32i a7, a2, 8
- l32i a5, a3, 12
- l32i a6, a3, 16
- l32i a7, a3, 20
- s32i a5, a2, 12
- s32i a6, a2, 16
- s32i a7, a2, 20
- l32i a5, a3, 24
- l32i a6, a3, 28
- s32i a5, a2, 24
- s32i a6, a2, 28
- addi a2, a2, 32
- addi a3, a3, 32
- blt a2, a4, 1b
+ __loopi a2, a4, PAGE_SIZE, 32
+
+ l32i a8, a3, 0
+ l32i a9, a3, 4
+ s32i a8, a2, 0
+ s32i a9, a2, 4
+
+ l32i a8, a3, 8
+ l32i a9, a3, 12
+ s32i a8, a2, 8
+ s32i a9, a2, 12
+
+ l32i a8, a3, 16
+ l32i a9, a3, 20
+ s32i a8, a2, 16
+ s32i a9, a2, 20
+
+ l32i a8, a3, 24
+ l32i a9, a3, 28
+ s32i a8, a2, 24
+ s32i a9, a2, 28
+
+ addi a2, a2, 32
+ addi a3, a3, 32
+
+ __endl a2, a4
+
+ retw
+
+/*
+ * If we have to deal with cache aliasing, we use temporary memory mappings
+ * to ensure that the source and destination pages have the same color as
+ * the virtual address. We use way 0 and 1 for temporary mappings in such cases.
+ *
+ * The temporary DTLB entries shouldn't be flushed by interrupts, but are
+ * flushed by preemptive task switches. Special code in the
+ * fast_second_level_miss handler re-established the temporary mapping.
+ * It requires that the PPNs for the destination and source addresses are
+ * in a6, and a7, respectively.
+ */
+
+/* TLB miss exceptions are treated special in the following region */
+
+ENTRY(__tlbtemp_mapping_start)
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+
+/*
+ * clear_user_page (void *addr, unsigned long vaddr, struct page *page)
+ * a2 a3 a4
+ */
+
+ENTRY(clear_user_page)
+ entry a1, 32
+
+ /* Mark page dirty and determine alias. */
+
+ movi a7, (1 << PG_ARCH_1)
+ l32i a5, a4, PAGE_FLAGS
+ xor a6, a2, a3
+ extui a3, a3, PAGE_SHIFT, DCACHE_ALIAS_ORDER
+ extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER
+ or a5, a5, a7
+ slli a3, a3, PAGE_SHIFT
+ s32i a5, a4, PAGE_FLAGS
+
+ /* Skip setting up a temporary DTLB if not aliased. */
+
+ beqz a6, 1f
+
+ /* Invalidate kernel page. */
+
+ mov a10, a2
+ call8 __invalidate_dcache_page
+
+ /* Setup a temporary DTLB with the color of the VPN */
+
+ movi a4, -PAGE_OFFSET + (PAGE_KERNEL | _PAGE_HW_WRITE)
+ movi a5, TLBTEMP_BASE_1 # virt
+ add a6, a2, a4 # ppn
+ add a2, a5, a3 # add 'color'
+
+ wdtlb a6, a2
+ dsync
+
+1: movi a3, 0
+ __loopi a2, a7, PAGE_SIZE, 32
+ s32i a3, a2, 0
+ s32i a3, a2, 4
+ s32i a3, a2, 8
+ s32i a3, a2, 12
+ s32i a3, a2, 16
+ s32i a3, a2, 20
+ s32i a3, a2, 24
+ s32i a3, a2, 28
+ __endla a2, a7, 32
+
+ bnez a6, 1f
+ retw
+
+ /* We need to invalidate the temporary idtlb entry, if any. */
+
+1: addi a2, a2, -PAGE_SIZE
+ idtlb a2
+ dsync
+
+ retw
+
+/*
+ * copy_page_user (void *to, void *from, unsigned long vaddr, struct page *page)
+ * a2 a3 a4 a5
+ */
+
+ENTRY(copy_user_page)
+
+ entry a1, 32
+
+ /* Mark page dirty and determine alias for destination. */
+
+ movi a8, (1 << PG_ARCH_1)
+ l32i a9, a5, PAGE_FLAGS
+ xor a6, a2, a4
+ xor a7, a3, a4
+ extui a4, a4, PAGE_SHIFT, DCACHE_ALIAS_ORDER
+ extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER
+ extui a7, a7, PAGE_SHIFT, DCACHE_ALIAS_ORDER
+ or a9, a9, a8
+ slli a4, a4, PAGE_SHIFT
+ s32i a9, a5, PAGE_FLAGS
+ movi a5, -PAGE_OFFSET + (PAGE_KERNEL | _PAGE_HW_WRITE)
+
+ beqz a6, 1f
+
+ /* Invalidate dcache */
+
+ mov a10, a2
+ call8 __invalidate_dcache_page
+
+ /* Setup a temporary DTLB with a matching color. */
+
+ movi a8, TLBTEMP_BASE_1 # base
+ add a6, a2, a5 # ppn
+ add a2, a8, a4 # add 'color'
+
+ wdtlb a6, a2
+ dsync
+
+ /* Skip setting up a temporary DTLB for destination if not aliased. */
+
+1: beqz a7, 1f
+
+ /* Setup a temporary DTLB with a matching color. */
+
+ movi a8, TLBTEMP_BASE_2 # base
+ add a7, a3, a5 # ppn
+ add a3, a8, a4
+ addi a8, a3, 1 # way1
+
+ wdtlb a7, a8
+ dsync
+
+1: __loopi a2, a4, PAGE_SIZE, 32
+
+ l32i a8, a3, 0
+ l32i a9, a3, 4
+ s32i a8, a2, 0
+ s32i a9, a2, 4
+
+ l32i a8, a3, 8
+ l32i a9, a3, 12
+ s32i a8, a2, 8
+ s32i a9, a2, 12
+
+ l32i a8, a3, 16
+ l32i a9, a3, 20
+ s32i a8, a2, 16
+ s32i a9, a2, 20
+
+ l32i a8, a3, 24
+ l32i a9, a3, 28
+ s32i a8, a2, 24
+ s32i a9, a2, 28
+
+ addi a2, a2, 32
+ addi a3, a3, 32
+
+ __endl a2, a4
+
+ /* We need to invalidate any temporary mapping! */
+
+ bnez a6, 1f
+ bnez a7, 2f
+ retw
+
+1: addi a2, a2, -PAGE_SIZE
+ idtlb a2
+ dsync
+ bnez a7, 2f
+ retw
+
+2: addi a3, a3, -PAGE_SIZE+1
+ idtlb a3
+ dsync
+
+ retw
+
+#endif
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+
+/*
+ * void __flush_invalidate_dcache_page_alias (addr, phys)
+ * a2 a3
+ */
+
+ENTRY(__flush_invalidate_dcache_page_alias)
+ entry sp, 16
+
+ movi a7, 0 # required for exception handler
+ addi a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
+ mov a4, a2
+ wdtlb a6, a2
+ dsync
+
+ ___flush_invalidate_dcache_page a2 a3
+
+ idtlb a4
+ dsync
+
+ retw
+
+#endif
+
+ENTRY(__tlbtemp_mapping_itlb)
+
+#if (ICACHE_WAY_SIZE > PAGE_SIZE)
+
+ENTRY(__invalidate_icache_page_alias)
+ entry sp, 16
+
+ addi a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
+ mov a4, a2
+ witlb a6, a2
+ isync
+
+ ___invalidate_icache_page a2 a3
+
+ iitlb a4
+ isync
retw
+#endif
+
+/* End of special treatment in tlb miss exception */
+
+ENTRY(__tlbtemp_mapping_end)
+
/*
* void __invalidate_icache_page(ulong start)
*/
@@ -121,8 +360,6 @@ ENTRY(__flush_dcache_page)
dsync
retw
-
-
/*
* void __invalidate_icache_range(ulong start, ulong size)
*/
@@ -168,7 +405,6 @@ ENTRY(__invalidate_dcache_range)
___invalidate_dcache_range a2 a3 a4
-
retw
/*
diff --git a/arch/xtensa/platform-iss/console.c b/arch/xtensa/platform-iss/console.c
index 2f4f20ffe666..854677d0c3f6 100644
--- a/arch/xtensa/platform-iss/console.c
+++ b/arch/xtensa/platform-iss/console.c
@@ -20,7 +20,6 @@
#include <linux/param.h>
#include <linux/serial.h>
#include <linux/serialP.h>
-#include <linux/console.h>
#include <asm/uaccess.h>
#include <asm/irq.h>