Merge branches 'sh/xstate', 'sh/hw-breakpoints' and 'sh/stable-updates'
authorPaul Mundt <lethal@linux-sh.org>
Wed, 13 Jan 2010 04:02:55 +0000 (13:02 +0900)
committerPaul Mundt <lethal@linux-sh.org>
Wed, 13 Jan 2010 04:02:55 +0000 (13:02 +0900)
58 files changed:
arch/sh/Kconfig
arch/sh/boards/mach-se/7343/irq.c
arch/sh/boards/mach-se/7343/setup.c
arch/sh/include/asm/Kbuild
arch/sh/include/asm/alignment.h [new file with mode: 0644]
arch/sh/include/asm/atomic-grb.h
arch/sh/include/asm/atomic-llsc.h
arch/sh/include/asm/atomic.h
arch/sh/include/asm/fpu.h
arch/sh/include/asm/hw_breakpoint.h [new file with mode: 0644]
arch/sh/include/asm/kdebug.h
arch/sh/include/asm/pgalloc.h
arch/sh/include/asm/pgtable.h
arch/sh/include/asm/pgtable_64.h
arch/sh/include/asm/pgtable_nopmd.h [new file with mode: 0644]
arch/sh/include/asm/pgtable_pmd.h [new file with mode: 0644]
arch/sh/include/asm/processor_32.h
arch/sh/include/asm/ptrace.h
arch/sh/include/asm/setup.h
arch/sh/include/asm/sh_bios.h
arch/sh/include/asm/system.h
arch/sh/include/asm/thread_info.h
arch/sh/include/asm/ubc.h [deleted file]
arch/sh/include/cpu-sh2/cpu/ubc.h [deleted file]
arch/sh/include/cpu-sh3/cpu/ubc.h [deleted file]
arch/sh/include/cpu-sh4/cpu/ubc.h [deleted file]
arch/sh/include/mach-se/mach/se7343.h
arch/sh/kernel/Makefile
arch/sh/kernel/cpu/Makefile
arch/sh/kernel/cpu/fpu.c [new file with mode: 0644]
arch/sh/kernel/cpu/init.c
arch/sh/kernel/cpu/sh2a/fpu.c
arch/sh/kernel/cpu/sh3/ex.S
arch/sh/kernel/cpu/sh4/fpu.c
arch/sh/kernel/cpu/sh4a/Makefile
arch/sh/kernel/cpu/sh4a/ubc.c [new file with mode: 0644]
arch/sh/kernel/debugtraps.S
arch/sh/kernel/early_printk.c [deleted file]
arch/sh/kernel/head_64.S
arch/sh/kernel/hw_breakpoint.c [new file with mode: 0644]
arch/sh/kernel/kgdb.c
arch/sh/kernel/machine_kexec.c
arch/sh/kernel/process.c [new file with mode: 0644]
arch/sh/kernel/process_32.c
arch/sh/kernel/ptrace_32.c
arch/sh/kernel/sh_bios.c
arch/sh/kernel/signal_32.c
arch/sh/kernel/traps_32.c
arch/sh/math-emu/math.c
arch/sh/mm/Kconfig
arch/sh/mm/Makefile
arch/sh/mm/alignment.c [new file with mode: 0644]
arch/sh/mm/cache-sh4.c
arch/sh/mm/fault_32.c
arch/sh/mm/init.c
arch/sh/mm/nommu.c
arch/sh/mm/pgtable.c [new file with mode: 0644]
mm/Kconfig

index 2121fbb..4eaf340 100644 (file)
@@ -42,6 +42,8 @@ config SUPERH32
        select HAVE_FTRACE_NMI_ENTER if DYNAMIC_FTRACE
        select HAVE_FUNCTION_GRAPH_TRACER
        select HAVE_ARCH_KGDB
+       select HAVE_HW_BREAKPOINT
+       select PERF_EVENTS if HAVE_HW_BREAKPOINT
        select ARCH_HIBERNATION_POSSIBLE if MMU
 
 config SUPERH64
@@ -726,8 +728,9 @@ config GUSA_RB
          disabling interrupts around the atomic sequence.
 
 config SPARSE_IRQ
-       bool "Support sparse irq numbering"
-       depends on EXPERIMENTAL
+       def_bool y
+       depends on SUPERH32 && !SH_DREAMCAST && !SH_HIGHLANDER && \
+                  !SH_RTS7751R2D && !HD64461 && !SH_7724_SOLUTION_ENGINE
        help
          This enables support for sparse irqs. This is useful in general
          as most CPUs have a fairly sparse array of IRQ vectors, which
index 051c29d..c60fd13 100644 (file)
 #include <linux/io.h>
 #include <mach-se/mach/se7343.h>
 
+unsigned int se7343_fpga_irq[SE7343_FPGA_IRQ_NR] = { 0, };
+
 static void disable_se7343_irq(unsigned int irq)
 {
-       unsigned int bit = irq - SE7343_FPGA_IRQ_BASE;
+       unsigned int bit = (unsigned int)get_irq_chip_data(irq);
        ctrl_outw(ctrl_inw(PA_CPLD_IMSK) | 1 << bit, PA_CPLD_IMSK);
 }
 
 static void enable_se7343_irq(unsigned int irq)
 {
-       unsigned int bit = irq - SE7343_FPGA_IRQ_BASE;
+       unsigned int bit = (unsigned int)get_irq_chip_data(irq);
        ctrl_outw(ctrl_inw(PA_CPLD_IMSK) & ~(1 << bit), PA_CPLD_IMSK);
 }
 
@@ -38,18 +40,15 @@ static struct irq_chip se7343_irq_chip __read_mostly = {
 static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc)
 {
        unsigned short intv = ctrl_inw(PA_CPLD_ST);
-       struct irq_desc *ext_desc;
-       unsigned int ext_irq = SE7343_FPGA_IRQ_BASE;
+       unsigned int ext_irq = 0;
 
        intv &= (1 << SE7343_FPGA_IRQ_NR) - 1;
 
-       while (intv) {
-               if (intv & 1) {
-                       ext_desc = irq_desc + ext_irq;
-                       handle_level_irq(ext_irq, ext_desc);
-               }
-               intv >>= 1;
-               ext_irq++;
+       for (; intv; intv >>= 1, ext_irq++) {
+               if (!(intv & 1))
+                       continue;
+
+               generic_handle_irq(se7343_fpga_irq[ext_irq]);
        }
 }
 
@@ -58,16 +57,24 @@ static void se7343_irq_demux(unsigned int irq, struct irq_desc *desc)
  */
 void __init init_7343se_IRQ(void)
 {
-       int i;
+       int i, irq;
 
        ctrl_outw(0, PA_CPLD_IMSK);     /* disable all irqs */
        ctrl_outw(0x2000, 0xb03fffec);  /* mrshpc irq enable */
 
-       for (i = 0; i < SE7343_FPGA_IRQ_NR; i++)
-               set_irq_chip_and_handler_name(SE7343_FPGA_IRQ_BASE + i,
+       for (i = 0; i < SE7343_FPGA_IRQ_NR; i++) {
+               irq = create_irq();
+               if (irq < 0)
+                       return;
+               se7343_fpga_irq[i] = irq;
+
+               set_irq_chip_and_handler_name(se7343_fpga_irq[i],
                                              &se7343_irq_chip,
                                              handle_level_irq, "level");
 
+               set_irq_chip_data(se7343_fpga_irq[i], (void *)i);
+       }
+
        set_irq_chained_handler(IRQ0_IRQ, se7343_irq_demux);
        set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
        set_irq_chained_handler(IRQ1_IRQ, se7343_irq_demux);
index 4de56f3..292cc47 100644 (file)
@@ -82,7 +82,6 @@ static struct plat_serial8250_port serial_platform_data[] = {
                .mapbase        = 0x16000000,
                .regshift       = 1,
                .flags          = ST16C2550C_FLAGS,
-               .irq            = UARTA_IRQ,
                .uartclk        = 7372800,
        },
        [1] = {
@@ -90,7 +89,6 @@ static struct plat_serial8250_port serial_platform_data[] = {
                .mapbase        = 0x17000000,
                .regshift       = 1,
                .flags          = ST16C2550C_FLAGS,
-               .irq            = UARTB_IRQ,
                .uartclk        = 7372800,
        },
        { },
@@ -121,7 +119,7 @@ static struct resource usb_resources[] = {
                .flags  = IORESOURCE_MEM,
        },
        [2] = {
-               .start  = USB_IRQ,
+               /* Filled in later */
                .flags  = IORESOURCE_IRQ,
        },
 };
@@ -138,8 +136,8 @@ static struct isp116x_platform_data usb_platform_data = {
 static struct platform_device usb_device = {
        .name                   = "isp116x-hcd",
        .id                     = -1,
-       .num_resources          = ARRAY_SIZE(usb_resources),
-       .resource               = usb_resources,
+       .num_resources          = ARRAY_SIZE(usb_resources),
+       .resource               = usb_resources,
        .dev                    = {
                .platform_data  = &usb_platform_data,
        },
@@ -155,6 +153,13 @@ static struct platform_device *sh7343se_platform_devices[] __initdata = {
 
 static int __init sh7343se_devices_setup(void)
 {
+       /* Wire-up dynamic vectors */
+       serial_platform_data[0].irq = se7343_fpga_irq[SE7343_FPGA_IRQ_UARTA];
+       serial_platform_data[1].irq = se7343_fpga_irq[SE7343_FPGA_IRQ_UARTB];
+
+       usb_resources[2].start = usb_resources[2].end =
+               se7343_fpga_irq[SE7343_FPGA_IRQ_USB];
+
        return platform_add_devices(sh7343se_platform_devices,
                                    ARRAY_SIZE(sh7343se_platform_devices));
 }
@@ -179,6 +184,5 @@ static void __init sh7343se_setup(char **cmdline_p)
 static struct sh_machine_vector mv_7343se __initmv = {
        .mv_name = "SolutionEngine 7343",
        .mv_setup = sh7343se_setup,
-       .mv_nr_irqs = SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_NR,
        .mv_init_irq = init_7343se_IRQ,
 };
index e121c30..46cb934 100644 (file)
@@ -1,6 +1,8 @@
 include include/asm-generic/Kbuild.asm
 
-header-y += cachectl.h cpu-features.h
+header-y += cachectl.h
+header-y += cpu-features.h
+header-y += hw_breakpoint.h
 
 unifdef-y += unistd_32.h
 unifdef-y += unistd_64.h
diff --git a/arch/sh/include/asm/alignment.h b/arch/sh/include/asm/alignment.h
new file mode 100644 (file)
index 0000000..b12efec
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __ASM_SH_ALIGNMENT_H
+#define __ASM_SH_ALIGNMENT_H
+
+#include <linux/types.h>
+
+extern void inc_unaligned_byte_access(void);
+extern void inc_unaligned_word_access(void);
+extern void inc_unaligned_dword_access(void);
+extern void inc_unaligned_multi_access(void);
+extern void inc_unaligned_user_access(void);
+extern void inc_unaligned_kernel_access(void);
+
+#define UM_WARN                (1 << 0)
+#define UM_FIXUP       (1 << 1)
+#define UM_SIGNAL      (1 << 2)
+
+extern unsigned int unaligned_user_action(void);
+
+extern void unaligned_fixups_notify(struct task_struct *, insn_size_t, struct pt_regs *);
+
+#endif /* __ASM_SH_ALIGNMENT_H */
index 4c5b7db..a273c88 100644 (file)
@@ -120,50 +120,4 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
                : "memory" , "r0", "r1");
 }
 
-static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
-{
-       int ret;
-
-       __asm__ __volatile__ (
-               "   .align 2            \n\t"
-               "   mova     1f,  r0    \n\t"
-               "   nop                 \n\t"
-               "   mov     r15,  r1    \n\t"
-               "   mov    #-8,  r15    \n\t"
-               "   mov.l   @%1,  %0    \n\t"
-               "   cmp/eq   %2,  %0    \n\t"
-               "   bf       1f         \n\t"
-               "   mov.l    %3, @%1    \n\t"
-               "1: mov      r1,  r15   \n\t"
-               : "=&r" (ret)
-               : "r" (v), "r" (old), "r" (new)
-               : "memory" , "r0", "r1" , "t");
-
-       return ret;
-}
-
-static inline int atomic_add_unless(atomic_t *v, int a, int u)
-{
-       int ret;
-       unsigned long tmp;
-
-       __asm__ __volatile__ (
-               "   .align 2            \n\t"
-               "   mova    1f,   r0    \n\t"
-               "   nop                 \n\t"
-               "   mov    r15,   r1    \n\t"
-               "   mov    #-12,  r15   \n\t"
-               "   mov.l  @%2,   %1    \n\t"
-               "   mov     %1,   %0    \n\t"
-               "   cmp/eq  %4,   %0    \n\t"
-               "   bt/s    1f          \n\t"
-               "    add    %3,   %1    \n\t"
-               "   mov.l   %1,  @%2    \n\t"
-               "1: mov     r1,   r15   \n\t"
-               : "=&r" (ret), "=&r" (tmp)
-               : "r" (v), "r" (a), "r" (u)
-               : "memory" , "r0", "r1" , "t");
-
-       return ret != u;
-}
 #endif /* __ASM_SH_ATOMIC_GRB_H */
index b040e1e..4b00b78 100644 (file)
@@ -104,31 +104,4 @@ static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
        : "t");
 }
 
-#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
-
-/**
- * atomic_add_unless - add unless the number is a given value
- * @v: pointer of type atomic_t
- * @a: the amount to add to v...
- * @u: ...unless v is equal to u.
- *
- * Atomically adds @a to @v, so long as it was not @u.
- * Returns non-zero if @v was not @u, and zero otherwise.
- */
-static inline int atomic_add_unless(atomic_t *v, int a, int u)
-{
-       int c, old;
-       c = atomic_read(v);
-       for (;;) {
-               if (unlikely(c == (u)))
-                       break;
-               old = atomic_cmpxchg((v), c, c + (a));
-               if (likely(old == c))
-                       break;
-               c = old;
-       }
-
-       return c != (u);
-}
-
 #endif /* __ASM_SH_ATOMIC_LLSC_H */
index b16388d..275a448 100644 (file)
 #endif
 
 #define atomic_add_negative(a, v)      (atomic_add_return((a), (v)) < 0)
+#define atomic_dec_return(v)           atomic_sub_return(1, (v))
+#define atomic_inc_return(v)           atomic_add_return(1, (v))
+#define atomic_inc_and_test(v)         (atomic_inc_return(v) == 0)
+#define atomic_sub_and_test(i,v)       (atomic_sub_return((i), (v)) == 0)
+#define atomic_dec_and_test(v)         (atomic_sub_return(1, (v)) == 0)
+#define atomic_inc_not_zero(v)         atomic_add_unless((v), 1, 0)
 
-#define atomic_dec_return(v) atomic_sub_return(1,(v))
-#define atomic_inc_return(v) atomic_add_return(1,(v))
+#define atomic_inc(v)                  atomic_add(1, (v))
+#define atomic_dec(v)                  atomic_sub(1, (v))
 
-/*
- * atomic_inc_and_test - increment and test
+#define atomic_xchg(v, new)            (xchg(&((v)->counter), new))
+#define atomic_cmpxchg(v, o, n)                (cmpxchg(&((v)->counter), (o), (n)))
+
+/**
+ * atomic_add_unless - add unless the number is a given value
  * @v: pointer of type atomic_t
+ * @a: the amount to add to v...
+ * @u: ...unless v is equal to u.
  *
- * Atomically increments @v by 1
- * and returns true if the result is zero, or false for all
- * other cases.
+ * Atomically adds @a to @v, so long as it was not @u.
+ * Returns non-zero if @v was not @u, and zero otherwise.
  */
-#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
-
-#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
-#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
-
-#define atomic_inc(v) atomic_add(1,(v))
-#define atomic_dec(v) atomic_sub(1,(v))
-
-#if !defined(CONFIG_GUSA_RB) && !defined(CONFIG_CPU_SH4A)
-static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
-{
-       int ret;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       ret = v->counter;
-       if (likely(ret == old))
-               v->counter = new;
-       local_irq_restore(flags);
-
-       return ret;
-}
-
 static inline int atomic_add_unless(atomic_t *v, int a, int u)
 {
-       int ret;
-       unsigned long flags;
-
-       local_irq_save(flags);
-       ret = v->counter;
-       if (ret != u)
-               v->counter += a;
-       local_irq_restore(flags);
-
-       return ret != u;
+       int c, old;
+       c = atomic_read(v);
+       for (;;) {
+               if (unlikely(c == (u)))
+                       break;
+               old = atomic_cmpxchg((v), c, c + (a));
+               if (likely(old == c))
+                       break;
+               c = old;
+       }
+
+       return c != (u);
 }
-#endif /* !CONFIG_GUSA_RB && !CONFIG_CPU_SH4A */
-
-#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
-#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 
 #define smp_mb__before_atomic_dec()    smp_mb()
 #define smp_mb__after_atomic_dec()     smp_mb()
index fb6bbb9..06c4281 100644 (file)
@@ -2,8 +2,8 @@
 #define __ASM_SH_FPU_H
 
 #ifndef __ASSEMBLY__
-#include <linux/preempt.h>
-#include <asm/ptrace.h>
+
+struct task_struct;
 
 #ifdef CONFIG_SH_FPU
 static inline void release_fpu(struct pt_regs *regs)
@@ -16,22 +16,23 @@ static inline void grab_fpu(struct pt_regs *regs)
        regs->sr &= ~SR_FD;
 }
 
-struct task_struct;
-
 extern void save_fpu(struct task_struct *__tsk);
-void fpu_state_restore(struct pt_regs *regs);
+extern void restore_fpu(struct task_struct *__tsk);
+extern void fpu_state_restore(struct pt_regs *regs);
+extern void __fpu_state_restore(void);
 #else
-
-#define save_fpu(tsk)          do { } while (0)
-#define release_fpu(regs)      do { } while (0)
-#define grab_fpu(regs)         do { } while (0)
-#define fpu_state_restore(regs)        do { } while (0)
-
+#define save_fpu(tsk)                  do { } while (0)
+#define restore_fpu(tsk)               do { } while (0)
+#define release_fpu(regs)              do { } while (0)
+#define grab_fpu(regs)                 do { } while (0)
+#define fpu_state_restore(regs)                do { } while (0)
+#define __fpu_state_restore(regs)      do { } while (0)
 #endif
 
 struct user_regset;
 
 extern int do_fpu_inst(unsigned short, struct pt_regs *);
+extern int init_fpu(struct task_struct *);
 
 extern int fpregs_get(struct task_struct *target,
                      const struct user_regset *regset,
@@ -65,18 +66,6 @@ static inline void clear_fpu(struct task_struct *tsk, struct pt_regs *regs)
        preempt_enable();
 }
 
-static inline int init_fpu(struct task_struct *tsk)
-{
-       if (tsk_used_math(tsk)) {
-               if ((boot_cpu_data.flags & CPU_HAS_FPU) && tsk == current)
-                       unlazy_fpu(tsk, task_pt_regs(tsk));
-               return 0;
-       }
-
-       set_stopped_child_used_math(tsk);
-       return 0;
-}
-
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_SH_FPU_H */
diff --git a/arch/sh/include/asm/hw_breakpoint.h b/arch/sh/include/asm/hw_breakpoint.h
new file mode 100644 (file)
index 0000000..7295d62
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef __ASM_SH_HW_BREAKPOINT_H
+#define __ASM_SH_HW_BREAKPOINT_H
+
+#include <linux/kdebug.h>
+#include <linux/types.h>
+
+#ifdef __KERNEL__
+#define __ARCH_HW_BREAKPOINT_H
+
+struct arch_hw_breakpoint {
+       char            *name; /* Contains name of the symbol to set bkpt */
+       unsigned long   address;
+       u16             len;
+       u16             type;
+};
+
+enum {
+       SH_BREAKPOINT_READ      = (1 << 1),
+       SH_BREAKPOINT_WRITE     = (1 << 2),
+       SH_BREAKPOINT_RW        = SH_BREAKPOINT_READ | SH_BREAKPOINT_WRITE,
+
+       SH_BREAKPOINT_LEN_1     = (1 << 12),
+       SH_BREAKPOINT_LEN_2     = (1 << 13),
+       SH_BREAKPOINT_LEN_4     = SH_BREAKPOINT_LEN_1 | SH_BREAKPOINT_LEN_2,
+       SH_BREAKPOINT_LEN_8     = (1 << 14),
+};
+
+struct sh_ubc {
+       const char      *name;
+       unsigned int    num_events;
+       unsigned int    trap_nr;
+       void            (*enable)(struct arch_hw_breakpoint *, int);
+       void            (*disable)(struct arch_hw_breakpoint *, int);
+       void            (*enable_all)(unsigned long);
+       void            (*disable_all)(void);
+       unsigned long   (*active_mask)(void);
+       unsigned long   (*triggered_mask)(void);
+       void            (*clear_triggered_mask)(unsigned long);
+       struct clk      *clk;   /* optional interface clock / MSTP bit */
+};
+
+struct perf_event;
+struct task_struct;
+struct pmu;
+
+/* Maximum number of UBC channels */
+#define HBP_NUM                2
+
+/* arch/sh/kernel/hw_breakpoint.c */
+extern int arch_check_va_in_userspace(unsigned long va, u16 hbp_len);
+extern int arch_validate_hwbkpt_settings(struct perf_event *bp,
+                                        struct task_struct *tsk);
+extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
+                                          unsigned long val, void *data);
+
+int arch_install_hw_breakpoint(struct perf_event *bp);
+void arch_uninstall_hw_breakpoint(struct perf_event *bp);
+void hw_breakpoint_pmu_read(struct perf_event *bp);
+void hw_breakpoint_pmu_unthrottle(struct perf_event *bp);
+
+extern void arch_fill_perf_breakpoint(struct perf_event *bp);
+extern int register_sh_ubc(struct sh_ubc *);
+
+extern struct pmu perf_ops_bp;
+
+#endif /* __KERNEL__ */
+#endif /* __ASM_SH_HW_BREAKPOINT_H */
index 985219f..5f6d2e9 100644 (file)
@@ -6,6 +6,8 @@ enum die_val {
        DIE_TRAP,
        DIE_NMI,
        DIE_OOPS,
+       DIE_BREAKPOINT,
+       DIE_SSTEP,
 };
 
 #endif /* __ASM_SH_KDEBUG_H */
index 63ca37b..f8982f4 100644 (file)
@@ -4,8 +4,16 @@
 #include <linux/quicklist.h>
 #include <asm/page.h>
 
-#define QUICK_PGD 0    /* We preserve special mappings over free */
-#define QUICK_PT 1     /* Other page table pages that are zero on free */
+#define QUICK_PT 0     /* Other page table pages that are zero on free */
+
+extern pgd_t *pgd_alloc(struct mm_struct *);
+extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
+
+#ifdef CONFIG_PGTABLE_LEVELS_3
+extern void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd);
+extern pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address);
+extern void pmd_free(struct mm_struct *mm, pmd_t *pmd);
+#endif
 
 static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
                                       pte_t *pte)
@@ -20,28 +28,9 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
 }
 #define pmd_pgtable(pmd) pmd_page(pmd)
 
-static inline void pgd_ctor(void *x)
-{
-       pgd_t *pgd = x;
-
-       memcpy(pgd + USER_PTRS_PER_PGD,
-              swapper_pg_dir + USER_PTRS_PER_PGD,
-              (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
-}
-
 /*
  * Allocate and free page tables.
  */
-static inline pgd_t *pgd_alloc(struct mm_struct *mm)
-{
-       return quicklist_alloc(QUICK_PGD, GFP_KERNEL | __GFP_REPEAT, pgd_ctor);
-}
-
-static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
-{
-       quicklist_free(QUICK_PGD, NULL, pgd);
-}
-
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
                                          unsigned long address)
 {
@@ -81,7 +70,6 @@ do {                                                  \
 
 static inline void check_pgt_cache(void)
 {
-       quicklist_trim(QUICK_PGD, NULL, 25, 16);
        quicklist_trim(QUICK_PT, NULL, 25, 16);
 }
 
index ba3046e..78598ec 100644 (file)
 #ifndef __ASM_SH_PGTABLE_H
 #define __ASM_SH_PGTABLE_H
 
-#include <asm-generic/pgtable-nopmd.h>
+#ifdef CONFIG_PGTABLE_LEVELS_3
+#include <asm/pgtable_pmd.h>
+#else
+#include <asm/pgtable_nopmd.h>
+#endif
 #include <asm/page.h>
 
 #ifndef __ASSEMBLY__
@@ -51,28 +55,12 @@ static inline unsigned long long neff_sign_extend(unsigned long val)
 #define        NPHYS_SIGN      (1LL << (NPHYS - 1))
 #define        NPHYS_MASK      (-1LL << NPHYS)
 
-/*
- * traditional two-level paging structure
- */
-/* PTE bits */
-#if defined(CONFIG_X2TLB) || defined(CONFIG_SUPERH64)
-# define PTE_MAGNITUDE 3       /* 64-bit PTEs on extended mode SH-X2 TLB */
-#else
-# define PTE_MAGNITUDE 2       /* 32-bit PTEs */
-#endif
-#define PTE_SHIFT      PAGE_SHIFT
-#define PTE_BITS       (PTE_SHIFT - PTE_MAGNITUDE)
-
-/* PGD bits */
-#define PGDIR_SHIFT    (PTE_SHIFT + PTE_BITS)
 #define PGDIR_SIZE     (1UL << PGDIR_SHIFT)
 #define PGDIR_MASK     (~(PGDIR_SIZE-1))
 
 /* Entries per level */
 #define PTRS_PER_PTE   (PAGE_SIZE / (1 << PTE_MAGNITUDE))
-#define PTRS_PER_PGD   (PAGE_SIZE / sizeof(pgd_t))
 
-#define USER_PTRS_PER_PGD      (TASK_SIZE/PGDIR_SIZE)
 #define FIRST_USER_ADDRESS     0
 
 #define PHYS_ADDR_MASK29               0x1fffffff
@@ -153,9 +141,9 @@ typedef pte_t *pte_addr_t;
 #define pte_pfn(x)             ((unsigned long)(((x).pte_low >> PAGE_SHIFT)))
 
 /*
- * No page table caches to initialise
+ * Initialise the page table caches
  */
-#define pgtable_cache_init()   do { } while (0)
+extern void pgtable_cache_init(void);
 
 struct vm_area_struct;
 
index 17cdbec..dd38158 100644 (file)
@@ -43,11 +43,6 @@ static __inline__ void set_pte(pte_t *pteptr, pte_t pteval)
 }
 #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
-static __inline__ void pmd_set(pmd_t *pmdp,pte_t *ptep)
-{
-       pmd_val(*pmdp) = (unsigned long) ptep;
-}
-
 /*
  * PGD defines. Top level.
  */
@@ -203,12 +198,6 @@ static __inline__ void pmd_set(pmd_t *pmdp,pte_t *ptep)
 #define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE)
 
 /*
- * Handling allocation failures during page table setup.
- */
-extern void __handle_bad_pmd_kernel(pmd_t * pmd);
-#define __handle_bad_pmd(x)    __handle_bad_pmd_kernel(x)
-
-/*
  * PTE level access routines.
  *
  * Note1:
diff --git a/arch/sh/include/asm/pgtable_nopmd.h b/arch/sh/include/asm/pgtable_nopmd.h
new file mode 100644 (file)
index 0000000..f0b525b
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef __ASM_SH_PGTABLE_NOPMD_H
+#define __ASM_SH_PGTABLE_NOPMD_H
+
+#include <asm-generic/pgtable-nopmd.h>
+
+/*
+ * traditional two-level paging structure
+ */
+
+/* PTE bits */
+#define PTE_MAGNITUDE  2       /* 32-bit PTEs */
+
+#define PTE_SHIFT      PAGE_SHIFT
+#define PTE_BITS       (PTE_SHIFT - PTE_MAGNITUDE)
+
+/* PGD bits */
+#define PGDIR_SHIFT    (PTE_SHIFT + PTE_BITS)
+
+#define PTRS_PER_PGD   (PAGE_SIZE / (1 << PTE_MAGNITUDE))
+#define USER_PTRS_PER_PGD      (TASK_SIZE/PGDIR_SIZE)
+
+#endif /* __ASM_SH_PGTABLE_NOPMD_H */
diff --git a/arch/sh/include/asm/pgtable_pmd.h b/arch/sh/include/asm/pgtable_pmd.h
new file mode 100644 (file)
index 0000000..42a180e
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef __ASM_SH_PGTABLE_PMD_H
+#define __ASM_SH_PGTABLE_PMD_H
+
+#include <asm-generic/pgtable-nopud.h>
+
+/*
+ * Some cores need a 3-level page table layout, for example when using
+ * 64-bit PTEs and 4K pages.
+ */
+
+#define PTE_MAGNITUDE  3       /* 64-bit PTEs on extended mode SH-X2 TLB */
+
+/* PGD bits */
+#define PGDIR_SHIFT    30
+
+#define PTRS_PER_PGD           4
+#define USER_PTRS_PER_PGD      2
+
+/* PMD bits */
+#define PMD_SHIFT      (PAGE_SHIFT + (PAGE_SHIFT - PTE_MAGNITUDE))
+#define PMD_SIZE       (1UL << PMD_SHIFT)
+#define PMD_MASK       (~(PMD_SIZE-1))
+
+#define PTRS_PER_PMD   ((1 << PGDIR_SHIFT) / PMD_SIZE)
+
+#define pmd_ERROR(e) \
+       printk("%s:%d: bad pmd %016llx.\n", __FILE__, __LINE__, pmd_val(e))
+
+typedef struct { unsigned long long pmd; } pmd_t;
+#define pmd_val(x)     ((x).pmd)
+#define __pmd(x)       ((pmd_t) { (x) } )
+
+static inline unsigned long pud_page_vaddr(pud_t pud)
+{
+       return pud_val(pud);
+}
+
+#define pmd_index(address)     (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1))
+static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
+{
+       return (pmd_t *)pud_page_vaddr(*pud) + pmd_index(address);
+}
+
+#define pud_none(x)    (!pud_val(x))
+#define pud_present(x) (pud_val(x))
+#define pud_clear(xp)  do { set_pud(xp, __pud(0)); } while (0)
+#define        pud_bad(x)      (pud_val(x) & ~PAGE_MASK)
+
+/*
+ * (puds are folded into pgds so this doesn't get actually called,
+ * but the define is needed for a generic inline function.)
+ */
+#define set_pud(pudptr, pudval) do { *(pudptr) = (pudval); } while(0)
+
+#endif /* __ASM_SH_PGTABLE_PMD_H */
index 1f3d6fa..5fd8312 100644 (file)
@@ -14,6 +14,7 @@
 #include <asm/page.h>
 #include <asm/types.h>
 #include <asm/ptrace.h>
+#include <asm/hw_breakpoint.h>
 
 /*
  * Default implementation of macro that returns current
@@ -90,48 +91,40 @@ struct sh_fpu_soft_struct {
        unsigned long entry_pc;
 };
 
-union sh_fpu_union {
-       struct sh_fpu_hard_struct hard;
-       struct sh_fpu_soft_struct soft;
+union thread_xstate {
+       struct sh_fpu_hard_struct hardfpu;
+       struct sh_fpu_soft_struct softfpu;
 };
 
+extern unsigned int xstate_size;
+extern void free_thread_xstate(struct task_struct *);
+extern struct kmem_cache *task_xstate_cachep;
+
 struct thread_struct {
        /* Saved registers when thread is descheduled */
        unsigned long sp;
        unsigned long pc;
 
-       /* Hardware debugging registers */
-       unsigned long ubc_pc;
-
-       /* floating point info */
-       union sh_fpu_union fpu;
+       /* Save middle states of ptrace breakpoints */
+       struct perf_event       *ptrace_bps[HBP_NUM];
 
 #ifdef CONFIG_SH_DSP
        /* Dsp status information */
        struct sh_dsp_struct dsp_status;
 #endif
-};
 
-/* Count of active tasks with UBC settings */
-extern int ubc_usercnt;
+       /* Extended processor state */
+       union thread_xstate *xstate;
+};
 
 #define INIT_THREAD  {                                         \
        .sp = sizeof(init_stack) + (long) &init_stack,          \
 }
 
-/*
- * Do necessary setup to start up a newly executed thread.
- */
-#define start_thread(_regs, new_pc, new_sp)     \
-       set_fs(USER_DS);                         \
-       _regs->pr = 0;                           \
-       _regs->sr = SR_FD;      /* User mode. */ \
-       _regs->pc = new_pc;                      \
-       _regs->regs[15] = new_sp
-
 /* Forward declaration, a strange C thing */
 struct task_struct;
-struct mm_struct;
+
+extern void start_thread(struct pt_regs *regs, unsigned long new_pc, unsigned long new_sp);
 
 /* Free all resources held by a thread. */
 extern void release_thread(struct task_struct *);
index 1dc12cb..201d11e 100644 (file)
@@ -124,6 +124,12 @@ struct task_struct;
 extern void user_enable_single_step(struct task_struct *);
 extern void user_disable_single_step(struct task_struct *);
 
+struct perf_event;
+struct perf_sample_data;
+
+extern void ptrace_triggered(struct perf_event *bp, int nmi,
+                     struct perf_sample_data *data, struct pt_regs *regs);
+
 #define task_pt_regs(task) \
        ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE) - 1)
 
index ce37435..4758325 100644 (file)
@@ -18,7 +18,6 @@
 /* ... */
 #define COMMAND_LINE ((char *) (PARAM+0x100))
 
-int setup_early_printk(char *);
 void sh_mv_setup(void);
 
 #endif /* __KERNEL__ */
index d9c96d7..95714c2 100644 (file)
@@ -1,18 +1,27 @@
 #ifndef __ASM_SH_BIOS_H
 #define __ASM_SH_BIOS_H
 
+#ifdef CONFIG_SH_STANDARD_BIOS
+
 /*
  * Copyright (C) 2000 Greg Banks, Mitch Davis
  * C API to interface to the standard LinuxSH BIOS
  * usually from within the early stages of kernel boot.
  */
-
-
 extern void sh_bios_console_write(const char *buf, unsigned int len);
-extern void sh_bios_char_out(char ch);
 extern void sh_bios_gdb_detach(void);
 
 extern void sh_bios_get_node_addr(unsigned char *node_addr);
 extern void sh_bios_shutdown(unsigned int how);
 
+extern void sh_bios_vbr_init(void);
+extern void sh_bios_vbr_reload(void);
+
+#else
+
+static inline void sh_bios_vbr_init(void) { }
+static inline void sh_bios_vbr_reload(void) { }
+
+#endif /* CONFIG_SH_STANDARD_BIOS */
+
 #endif /* __ASM_SH_BIOS_H */
index c15415b..62e4fc1 100644 (file)
@@ -32,7 +32,7 @@
 #define mb()           __asm__ __volatile__ ("synco": : :"memory")
 #define rmb()          mb()
 #define wmb()          __asm__ __volatile__ ("synco": : :"memory")
-#define ctrl_barrier() __icbi(0xa8000000)
+#define ctrl_barrier() __icbi(PAGE_OFFSET)
 #define read_barrier_depends() do { } while(0)
 #else
 #define mb()           __asm__ __volatile__ ("": : :"memory")
@@ -144,8 +144,6 @@ void per_cpu_trap_init(void);
 void default_idle(void);
 void cpu_idle_wait(void);
 
-asmlinkage void break_point_trap(void);
-
 #ifdef CONFIG_SUPERH32
 #define BUILD_TRAP_HANDLER(name)                                       \
 asmlinkage void name##_trap_handler(unsigned long r4, unsigned long r5,        \
index 1f3d927..55a36fe 100644 (file)
@@ -93,14 +93,16 @@ static inline struct thread_info *current_thread_info(void)
 
 #define THREAD_SIZE_ORDER      (THREAD_SHIFT - PAGE_SHIFT)
 
-#else /* THREAD_SHIFT < PAGE_SHIFT */
-
-#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
+#endif
 
 extern struct thread_info *alloc_thread_info(struct task_struct *tsk);
 extern void free_thread_info(struct thread_info *ti);
+extern void arch_task_cache_init(void);
+#define arch_task_cache_init arch_task_cache_init
+extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
+extern void init_thread_xstate(void);
 
-#endif /* THREAD_SHIFT < PAGE_SHIFT */
+#define __HAVE_ARCH_THREAD_INFO_ALLOCATOR
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/arch/sh/include/asm/ubc.h b/arch/sh/include/asm/ubc.h
deleted file mode 100644 (file)
index 9bf9616..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * include/asm-sh/ubc.h
- *
- * Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2002, 2003 Paul Mundt
- *
- * 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.
- */
-#ifndef __ASM_SH_UBC_H
-#define __ASM_SH_UBC_H
-#ifdef __KERNEL__
-
-#include <cpu/ubc.h>
-
-/* User Break Controller */
-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
-#define UBC_TYPE_SH7729        (current_cpu_data.type == CPU_SH7729)
-#else
-#define UBC_TYPE_SH7729        0
-#endif
-
-#define BAMR_ASID              (1 << 2)
-#define BAMR_NONE              0
-#define BAMR_10                        0x1
-#define BAMR_12                        0x2
-#define BAMR_ALL               0x3
-#define BAMR_16                        0x8
-#define BAMR_20                        0x9
-
-#define BBR_INST               (1 << 4)
-#define BBR_DATA               (2 << 4)
-#define BBR_READ               (1 << 2)
-#define BBR_WRITE              (2 << 2)
-#define BBR_BYTE               0x1
-#define BBR_HALF               0x2
-#define BBR_LONG               0x3
-#define BBR_QUAD               (1 << 6)        /* SH7750 */
-#define BBR_CPU                        (1 << 6)        /* SH7709A,SH7729 */
-#define BBR_DMA                        (2 << 6)        /* SH7709A,SH7729 */
-
-#define BRCR_CMFA              (1 << 15)
-#define BRCR_CMFB              (1 << 14)
-
-#if defined CONFIG_CPU_SH2A
-#define BRCR_CMFCA             (1 << 15)
-#define BRCR_CMFCB             (1 << 14)
-#define BRCR_CMFDA             (1 << 13)
-#define BRCR_CMFDB             (1 << 12)
-#define BRCR_PCBB              (1 << 6)        /* 1: after execution */
-#define BRCR_PCBA              (1 << 5)        /* 1: after execution */
-#define BRCR_PCTE              0
-#else
-#define BRCR_PCTE              (1 << 11)
-#define BRCR_PCBA              (1 << 10)       /* 1: after execution */
-#define BRCR_DBEB              (1 << 7)
-#define BRCR_PCBB              (1 << 6)
-#define BRCR_SEQ               (1 << 3)
-#define BRCR_UBDE              (1 << 0)
-#endif
-
-#endif /* __KERNEL__ */
-#endif /* __ASM_SH_UBC_H */
diff --git a/arch/sh/include/cpu-sh2/cpu/ubc.h b/arch/sh/include/cpu-sh2/cpu/ubc.h
deleted file mode 100644 (file)
index ba0e87f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * include/asm-sh/cpu-sh2/ubc.h
- *
- * Copyright (C) 2003 Paul Mundt
- *
- * 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.
- */
-#ifndef __ASM_CPU_SH2_UBC_H
-#define __ASM_CPU_SH2_UBC_H
-
-#define UBC_BARA                0xffffff40
-#define UBC_BAMRA               0xffffff44
-#define UBC_BBRA                0xffffff48
-#define UBC_BARB                0xffffff60
-#define UBC_BAMRB               0xffffff64
-#define UBC_BBRB                0xffffff68
-#define UBC_BDRB                0xffffff70
-#define UBC_BDMRB               0xffffff74
-#define UBC_BRCR                0xffffff78
-
-/*
- * We don't have any ASID changes to make in the UBC on the SH-2.
- *
- * Make these purposely invalid to track misuse.
- */
-#define UBC_BASRA              0x00000000
-#define UBC_BASRB              0x00000000
-
-#endif /* __ASM_CPU_SH2_UBC_H */
-
diff --git a/arch/sh/include/cpu-sh3/cpu/ubc.h b/arch/sh/include/cpu-sh3/cpu/ubc.h
deleted file mode 100644 (file)
index 4e6381d..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * include/asm-sh/cpu-sh3/ubc.h
- *
- * Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2003 Paul Mundt
- *
- * 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.
- */
-#ifndef __ASM_CPU_SH3_UBC_H
-#define __ASM_CPU_SH3_UBC_H
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7710) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7720) || \
-    defined(CONFIG_CPU_SUBTYPE_SH7721)
-#define UBC_BARA               0xa4ffffb0
-#define UBC_BAMRA              0xa4ffffb4
-#define UBC_BBRA               0xa4ffffb8
-#define UBC_BASRA              0xffffffe4
-#define UBC_BARB               0xa4ffffa0
-#define UBC_BAMRB              0xa4ffffa4
-#define UBC_BBRB               0xa4ffffa8
-#define UBC_BASRB              0xffffffe8
-#define UBC_BDRB               0xa4ffff90
-#define UBC_BDMRB              0xa4ffff94
-#define UBC_BRCR               0xa4ffff98
-#else
-#define UBC_BARA                0xffffffb0
-#define UBC_BAMRA               0xffffffb4
-#define UBC_BBRA                0xffffffb8
-#define UBC_BASRA               0xffffffe4
-#define UBC_BARB                0xffffffa0
-#define UBC_BAMRB               0xffffffa4
-#define UBC_BBRB                0xffffffa8
-#define UBC_BASRB               0xffffffe8
-#define UBC_BDRB                0xffffff90
-#define UBC_BDMRB               0xffffff94
-#define UBC_BRCR                0xffffff98
-#endif
-
-#endif /* __ASM_CPU_SH3_UBC_H */
diff --git a/arch/sh/include/cpu-sh4/cpu/ubc.h b/arch/sh/include/cpu-sh4/cpu/ubc.h
deleted file mode 100644 (file)
index c86e170..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * include/asm-sh/cpu-sh4/ubc.h
- *
- * Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2003 Paul Mundt
- * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
- *
- * 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.
- */
-#ifndef __ASM_CPU_SH4_UBC_H
-#define __ASM_CPU_SH4_UBC_H
-
-#if defined(CONFIG_CPU_SH4A)
-#define UBC_CBR0               0xff200000
-#define UBC_CRR0               0xff200004
-#define UBC_CAR0               0xff200008
-#define UBC_CAMR0              0xff20000c
-#define UBC_CBR1               0xff200020
-#define UBC_CRR1               0xff200024
-#define UBC_CAR1               0xff200028
-#define UBC_CAMR1              0xff20002c
-#define UBC_CDR1               0xff200030
-#define UBC_CDMR1              0xff200034
-#define UBC_CETR1              0xff200038
-#define UBC_CCMFR              0xff200600
-#define UBC_CBCR               0xff200620
-
-/* CBR */
-#define UBC_CBR_AIE            (0x01<<30)
-#define UBC_CBR_ID_INST                (0x01<<4)
-#define UBC_CBR_RW_READ                (0x01<<1)
-#define UBC_CBR_CE             (0x01)
-
-#define        UBC_CBR_AIV_MASK        (0x00FF0000)
-#define        UBC_CBR_AIV_SHIFT       (16)
-#define UBC_CBR_AIV_SET(asid)  (((asid)<<UBC_CBR_AIV_SHIFT) & UBC_CBR_AIV_MASK)
-
-#define UBC_CBR_INIT           0x20000000
-
-/* CRR */
-#define UBC_CRR_RES            (0x01<<13)
-#define UBC_CRR_PCB            (0x01<<1)
-#define UBC_CRR_BIE            (0x01)
-
-#define UBC_CRR_INIT           0x00002000
-
-#else  /* CONFIG_CPU_SH4 */
-#define UBC_BARA               0xff200000
-#define UBC_BAMRA              0xff200004
-#define UBC_BBRA               0xff200008
-#define UBC_BASRA              0xff000014
-#define UBC_BARB               0xff20000c
-#define UBC_BAMRB              0xff200010
-#define UBC_BBRB               0xff200014
-#define UBC_BASRB              0xff000018
-#define UBC_BDRB               0xff200018
-#define UBC_BDMRB              0xff20001c
-#define UBC_BRCR               0xff200020
-#endif /* CONFIG_CPU_SH4 */
-
-#endif /* __ASM_CPU_SH4_UBC_H */
-
index 749914b..8d8170d 100644 (file)
 
 #define PORT_DRVCR     0xA4050180
 
-#define PORT_PADR      0xA4050120
-#define PORT_PBDR      0xA4050122
-#define PORT_PCDR      0xA4050124
-#define PORT_PDDR      0xA4050126
-#define PORT_PEDR      0xA4050128
-#define PORT_PFDR      0xA405012A
-#define PORT_PGDR      0xA405012C
-#define PORT_PHDR      0xA405012E
-#define PORT_PJDR      0xA4050130
-#define PORT_PKDR      0xA4050132
-#define PORT_PLDR      0xA4050134
-#define PORT_PMDR      0xA4050136
-#define PORT_PNDR      0xA4050138
-#define PORT_PQDR      0xA405013A
-#define PORT_PRDR      0xA405013C
-#define PORT_PTDR      0xA4050160
-#define PORT_PUDR      0xA4050162
-#define PORT_PVDR      0xA4050164
-#define PORT_PWDR      0xA4050166
-#define PORT_PYDR      0xA4050168
+#define PORT_PADR      0xA4050120
+#define PORT_PBDR      0xA4050122
+#define PORT_PCDR      0xA4050124
+#define PORT_PDDR      0xA4050126
+#define PORT_PEDR      0xA4050128
+#define PORT_PFDR      0xA405012A
+#define PORT_PGDR      0xA405012C
+#define PORT_PHDR      0xA405012E
+#define PORT_PJDR      0xA4050130
+#define PORT_PKDR      0xA4050132
+#define PORT_PLDR      0xA4050134
+#define PORT_PMDR      0xA4050136
+#define PORT_PNDR      0xA4050138
+#define PORT_PQDR      0xA405013A
+#define PORT_PRDR      0xA405013C
+#define PORT_PTDR      0xA4050160
+#define PORT_PUDR      0xA4050162
+#define PORT_PVDR      0xA4050164
+#define PORT_PWDR      0xA4050166
+#define PORT_PYDR      0xA4050168
 
 #define FPGA_IN                0xb1400000
 #define FPGA_OUT       0xb1400002
 #define SE7343_FPGA_IRQ_UARTB  11
 
 #define SE7343_FPGA_IRQ_NR     12
-#define SE7343_FPGA_IRQ_BASE   120
-
-#define MRSHPC_IRQ3            (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_MRSHPC3)
-#define MRSHPC_IRQ2            (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_MRSHPC2)
-#define MRSHPC_IRQ1            (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_MRSHPC1)
-#define MRSHPC_IRQ0            (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_MRSHPC0)
-#define SMC_IRQ                (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_SMC)
-#define USB_IRQ                (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_USB)
-#define UARTA_IRQ      (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_UARTA)
-#define UARTB_IRQ      (SE7343_FPGA_IRQ_BASE + SE7343_FPGA_IRQ_UARTB)
 
 /* arch/sh/boards/se/7343/irq.c */
+extern unsigned int se7343_fpga_irq[];
+
 void init_7343se_IRQ(void);
 
 #endif  /* __ASM_SH_HITACHI_SE7343_H */
index 0d587da..56704a6 100644 (file)
@@ -13,8 +13,8 @@ CFLAGS_REMOVE_return_address.o = -pg
 
 obj-y  := debugtraps.o dma-nommu.o dumpstack.o                         \
           idle.o io.o io_generic.o irq.o                               \
-          irq_$(BITS).o machvec.o nmi_debug.o process_$(BITS).o        \
-          ptrace_$(BITS).o return_address.o                            \
+          irq_$(BITS).o machvec.o nmi_debug.o process.o                \
+          process_$(BITS).o ptrace_$(BITS).o return_address.o          \
           setup.o signal_$(BITS).o sys_sh.o sys_sh$(BITS).o            \
           syscalls_$(BITS).o time.o topology.o traps.o                 \
           traps_$(BITS).o unwinder.o
@@ -22,7 +22,7 @@ obj-y := debugtraps.o dma-nommu.o dumpstack.o                         \
 obj-y                          += cpu/
 obj-$(CONFIG_VSYSCALL)         += vsyscall/
 obj-$(CONFIG_SMP)              += smp.o
-obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o early_printk.o
+obj-$(CONFIG_SH_STANDARD_BIOS) += sh_bios.o
 obj-$(CONFIG_KGDB)             += kgdb.o
 obj-$(CONFIG_SH_CPU_FREQ)      += cpufreq.o
 obj-$(CONFIG_MODULES)          += sh_ksyms_$(BITS).o module.o
@@ -39,6 +39,7 @@ obj-$(CONFIG_HIBERNATION)     += swsusp.o
 obj-$(CONFIG_DWARF_UNWINDER)   += dwarf.o
 obj-$(CONFIG_PERF_EVENTS)      += perf_event.o perf_callchain.o
 
+obj-$(CONFIG_HAVE_HW_BREAKPOINT)               += hw_breakpoint.o
 obj-$(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)    += localtimer.o
 
 EXTRA_CFLAGS += -Werror
index d97c803..0e48bc6 100644 (file)
@@ -17,5 +17,7 @@ obj-$(CONFIG_ARCH_SHMOBILE)   += shmobile/
 
 obj-$(CONFIG_SH_ADC)           += adc.o
 obj-$(CONFIG_SH_CLK_CPG)       += clock-cpg.o
+obj-$(CONFIG_SH_FPU)           += fpu.o
+obj-$(CONFIG_SH_FPU_EMU)       += fpu.o
 
 obj-y  += irq/ init.o clock.o hwblk.o
diff --git a/arch/sh/kernel/cpu/fpu.c b/arch/sh/kernel/cpu/fpu.c
new file mode 100644 (file)
index 0000000..c23e672
--- /dev/null
@@ -0,0 +1,82 @@
+#include <linux/sched.h>
+#include <asm/processor.h>
+#include <asm/fpu.h>
+
+int init_fpu(struct task_struct *tsk)
+{
+       if (tsk_used_math(tsk)) {
+               if ((boot_cpu_data.flags & CPU_HAS_FPU) && tsk == current)
+                       unlazy_fpu(tsk, task_pt_regs(tsk));
+               return 0;
+       }
+
+       /*
+        * Memory allocation at the first usage of the FPU and other state.
+        */
+       if (!tsk->thread.xstate) {
+               tsk->thread.xstate = kmem_cache_alloc(task_xstate_cachep,
+                                                     GFP_KERNEL);
+               if (!tsk->thread.xstate)
+                       return -ENOMEM;
+       }
+
+       if (boot_cpu_data.flags & CPU_HAS_FPU) {
+               struct sh_fpu_hard_struct *fp = &tsk->thread.xstate->hardfpu;
+               memset(fp, 0, xstate_size);
+               fp->fpscr = FPSCR_INIT;
+       } else {
+               struct sh_fpu_soft_struct *fp = &tsk->thread.xstate->softfpu;
+               memset(fp, 0, xstate_size);
+               fp->fpscr = FPSCR_INIT;
+       }
+
+       set_stopped_child_used_math(tsk);
+       return 0;
+}
+
+#ifdef CONFIG_SH_FPU
+void __fpu_state_restore(void)
+{
+       struct task_struct *tsk = current;
+
+       restore_fpu(tsk);
+
+       task_thread_info(tsk)->status |= TS_USEDFPU;
+       tsk->fpu_counter++;
+}
+
+void fpu_state_restore(struct pt_regs *regs)
+{
+       struct task_struct *tsk = current;
+
+       if (unlikely(!user_mode(regs))) {
+               printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
+               BUG();
+               return;
+       }
+
+       if (!tsk_used_math(tsk)) {
+               /*
+                * does a slab alloc which can sleep
+                */
+               if (init_fpu(tsk)) {
+                       /*
+                        * ran out of memory!
+                        */
+                       do_group_exit(SIGKILL);
+                       return;
+               }
+       }
+
+       grab_fpu(regs);
+
+       __fpu_state_restore();
+}
+
+BUILD_TRAP_HANDLER(fpu_state_restore)
+{
+       TRAP_HANDLER_DECL;
+
+       fpu_state_restore(regs);
+}
+#endif /* CONFIG_SH_FPU */
index 89b4b76..a5bb055 100644 (file)
 #include <asm/elf.h>
 #include <asm/io.h>
 #include <asm/smp.h>
-#ifdef CONFIG_SUPERH32
-#include <asm/ubc.h>
+
+#ifdef CONFIG_SH_FPU
+#define cpu_has_fpu    1
+#else
+#define cpu_has_fpu    0
+#endif
+
+#ifdef CONFIG_SH_DSP
+#define cpu_has_dsp    1
+#else
+#define cpu_has_dsp    0
 #endif
 
 /*
  * Generic wrapper for command line arguments to disable on-chip
  * peripherals (nofpu, nodsp, and so forth).
  */
-#define onchip_setup(x)                                \
-static int x##_disabled __initdata = 0;                \
-                                               \
-static int __init x##_setup(char *opts)                \
-{                                              \
-       x##_disabled = 1;                       \
-       return 1;                               \
-}                                              \
+#define onchip_setup(x)                                        \
+static int x##_disabled __initdata = !cpu_has_##x;     \
+                                                       \
+static int __init x##_setup(char *opts)                        \
+{                                                      \
+       x##_disabled = 1;                               \
+       return 1;                                       \
+}                                                      \
 __setup("no" __stringify(x), x##_setup);
 
 onchip_setup(fpu);
@@ -207,6 +216,18 @@ static void detect_cache_shape(void)
                l2_cache_shape = -1; /* No S-cache */
 }
 
+static void __init fpu_init(void)
+{
+       /* Disable the FPU */
+       if (fpu_disabled && (current_cpu_data.flags & CPU_HAS_FPU)) {
+               printk("FPU Disabled\n");
+               current_cpu_data.flags &= ~CPU_HAS_FPU;
+       }
+
+       disable_fpu();
+       clear_used_math();
+}
+
 #ifdef CONFIG_SH_DSP
 static void __init release_dsp(void)
 {
@@ -244,28 +265,35 @@ static void __init dsp_init(void)
        if (sr & SR_DSP)
                current_cpu_data.flags |= CPU_HAS_DSP;
 
+       /* Disable the DSP */
+       if (dsp_disabled && (current_cpu_data.flags & CPU_HAS_DSP)) {
+               printk("DSP Disabled\n");
+               current_cpu_data.flags &= ~CPU_HAS_DSP;
+       }
+
        /* Now that we've determined the DSP status, clear the DSP bit. */
        release_dsp();
 }
+#else
+static inline void __init dsp_init(void) { }
 #endif /* CONFIG_SH_DSP */
 
 /**
  * sh_cpu_init
  *
- * This is our initial entry point for each CPU, and is invoked on the boot
- * CPU prior to calling start_kernel(). For SMP, a combination of this and
- * start_secondary() will bring up each processor to a ready state prior
- * to hand forking the idle loop.
+ * This is our initial entry point for each CPU, and is invoked on the
+ * boot CPU prior to calling start_kernel(). For SMP, a combination of
+ * this and start_secondary() will bring up each processor to a ready
+ * state prior to hand forking the idle loop.
  *
- * We do all of the basic processor init here, including setting up the
- * caches, FPU, DSP, kicking the UBC, etc. By the time start_kernel() is
- * hit (and subsequently platform_setup()) things like determining the
- * CPU subtype and initial configuration will all be done.
+ * We do all of the basic processor init here, including setting up
+ * the caches, FPU, DSP, etc. By the time start_kernel() is hit (and
+ * subsequently platform_setup()) things like determining the CPU
+ * subtype and initial configuration will all be done.
  *
  * Each processor family is still responsible for doing its own probing
  * and cache configuration in detect_cpu_and_cache_system().
  */
-
 asmlinkage void __init sh_cpu_init(void)
 {
        current_thread_info()->cpu = hard_smp_processor_id();
@@ -302,18 +330,8 @@ asmlinkage void __init sh_cpu_init(void)
                detect_cache_shape();
        }
 
-       /* Disable the FPU */
-       if (fpu_disabled) {
-               printk("FPU Disabled\n");
-               current_cpu_data.flags &= ~CPU_HAS_FPU;
-       }
-
-       /* FPU initialization */
-       disable_fpu();
-       if ((current_cpu_data.flags & CPU_HAS_FPU)) {
-               current_thread_info()->status &= ~TS_USEDFPU;
-               clear_used_math();
-       }
+       fpu_init();
+       dsp_init();
 
        /*
         * Initialize the per-CPU ASID cache very early, since the
@@ -321,18 +339,12 @@ asmlinkage void __init sh_cpu_init(void)
         */
        current_cpu_data.asid_cache = NO_CONTEXT;
 
-#ifdef CONFIG_SH_DSP
-       /* Probe for DSP */
-       dsp_init();
-
-       /* Disable the DSP */
-       if (dsp_disabled) {
-               printk("DSP Disabled\n");
-               current_cpu_data.flags &= ~CPU_HAS_DSP;
-               release_dsp();
-       }
-#endif
-
        speculative_execution_init();
        expmask_init();
+
+       /*
+        * Boot processor to setup the FP and extended state context info.
+        */
+       if (raw_smp_processor_id() == 0)
+               init_thread_xstate();
 }
index d395ce5..488d24e 100644 (file)
@@ -26,8 +26,7 @@
 /*
  * Save FPU registers onto task structure.
  */
-void
-save_fpu(struct task_struct *tsk)
+void save_fpu(struct task_struct *tsk)
 {
        unsigned long dummy;
 
@@ -52,7 +51,7 @@ save_fpu(struct task_struct *tsk)
                     "fmov.s    fr0, @-%0\n\t"
                     "lds       %3, fpscr\n\t"
                     : "=r" (dummy)
-                    : "0" ((char *)(&tsk->thread.fpu.hard.status)),
+                    : "0" ((char *)(&tsk->thread.xstate->hardfpu.status)),
                       "r" (FPSCR_RCHG),
                       "r" (FPSCR_INIT)
                     : "memory");
@@ -60,8 +59,7 @@ save_fpu(struct task_struct *tsk)
        disable_fpu();
 }
 
-static void
-restore_fpu(struct task_struct *tsk)
+void restore_fpu(struct task_struct *tsk)
 {
        unsigned long dummy;
 
@@ -85,45 +83,12 @@ restore_fpu(struct task_struct *tsk)
                     "lds.l     @%0+, fpscr\n\t"
                     "lds.l     @%0+, fpul\n\t"
                     : "=r" (dummy)
-                    : "0" (&tsk->thread.fpu), "r" (FPSCR_RCHG)
+                    : "0" (tsk->thread.xstate), "r" (FPSCR_RCHG)
                     : "memory");
        disable_fpu();
 }
 
 /*
- * Load the FPU with signalling NANS.  This bit pattern we're using
- * has the property that no matter wether considered as single or as
- * double precission represents signaling NANS.
- */
-
-static void
-fpu_init(void)
-{
-       enable_fpu();
-       asm volatile("lds       %0, fpul\n\t"
-                    "fsts      fpul, fr0\n\t"
-                    "fsts      fpul, fr1\n\t"
-                    "fsts      fpul, fr2\n\t"
-                    "fsts      fpul, fr3\n\t"
-                    "fsts      fpul, fr4\n\t"
-                    "fsts      fpul, fr5\n\t"
-                    "fsts      fpul, fr6\n\t"
-                    "fsts      fpul, fr7\n\t"
-                    "fsts      fpul, fr8\n\t"
-                    "fsts      fpul, fr9\n\t"
-                    "fsts      fpul, fr10\n\t"
-                    "fsts      fpul, fr11\n\t"
-                    "fsts      fpul, fr12\n\t"
-                    "fsts      fpul, fr13\n\t"
-                    "fsts      fpul, fr14\n\t"
-                    "fsts      fpul, fr15\n\t"
-                    "lds       %2, fpscr\n\t"
-                    : /* no output */
-                    : "r" (0), "r" (FPSCR_RCHG), "r" (FPSCR_INIT));
-       disable_fpu();
-}
-
-/*
  *     Emulate arithmetic ops on denormalized number for some FPU insns.
  */
 
@@ -490,9 +455,9 @@ ieee_fpe_handler (struct pt_regs *regs)
        if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */
                struct task_struct *tsk = current;
 
-               if ((tsk->thread.fpu.hard.fpscr & FPSCR_FPU_ERROR)) {
+               if ((tsk->thread.xstate->hardfpu.fpscr & FPSCR_FPU_ERROR)) {
                        /* FPU error */
-                       denormal_to_double (&tsk->thread.fpu.hard,
+                       denormal_to_double (&tsk->thread.xstate->hardfpu,
                                            (finsn >> 8) & 0xf);
                } else
                        return 0;
@@ -507,9 +472,9 @@ ieee_fpe_handler (struct pt_regs *regs)
 
                n = (finsn >> 8) & 0xf;
                m = (finsn >> 4) & 0xf;
-               hx = tsk->thread.fpu.hard.fp_regs[n];
-               hy = tsk->thread.fpu.hard.fp_regs[m];
-               fpscr = tsk->thread.fpu.hard.fpscr;
+               hx = tsk->thread.xstate->hardfpu.fp_regs[n];
+               hy = tsk->thread.xstate->hardfpu.fp_regs[m];
+               fpscr = tsk->thread.xstate->hardfpu.fpscr;
                prec = fpscr & (1 << 19);
 
                if ((fpscr & FPSCR_FPU_ERROR)
@@ -519,15 +484,15 @@ ieee_fpe_handler (struct pt_regs *regs)
 
                        /* FPU error because of denormal */
                        llx = ((long long) hx << 32)
-                              | tsk->thread.fpu.hard.fp_regs[n+1];
+                              | tsk->thread.xstate->hardfpu.fp_regs[n+1];
                        lly = ((long long) hy << 32)
-                              | tsk->thread.fpu.hard.fp_regs[m+1];
+                              | tsk->thread.xstate->hardfpu.fp_regs[m+1];
                        if ((hx & 0x7fffffff) >= 0x00100000)
                                llx = denormal_muld(lly, llx);
                        else
                                llx = denormal_muld(llx, lly);
-                       tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
-                       tsk->thread.fpu.hard.fp_regs[n+1] = llx & 0xffffffff;
+                       tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32;
+                       tsk->thread.xstate->hardfpu.fp_regs[n+1] = llx & 0xffffffff;
                } else if ((fpscr & FPSCR_FPU_ERROR)
                     && (!prec && ((hx & 0x7fffffff) < 0x00800000
                                   || (hy & 0x7fffffff) < 0x00800000))) {
@@ -536,7 +501,7 @@ ieee_fpe_handler (struct pt_regs *regs)
                                hx = denormal_mulf(hy, hx);
                        else
                                hx = denormal_mulf(hx, hy);
-                       tsk->thread.fpu.hard.fp_regs[n] = hx;
+                       tsk->thread.xstate->hardfpu.fp_regs[n] = hx;
                } else
                        return 0;
 
@@ -550,9 +515,9 @@ ieee_fpe_handler (struct pt_regs *regs)
 
                n = (finsn >> 8) & 0xf;
                m = (finsn >> 4) & 0xf;
-               hx = tsk->thread.fpu.hard.fp_regs[n];
-               hy = tsk->thread.fpu.hard.fp_regs[m];
-               fpscr = tsk->thread.fpu.hard.fpscr;
+               hx = tsk->thread.xstate->hardfpu.fp_regs[n];
+               hy = tsk->thread.xstate->hardfpu.fp_regs[m];
+               fpscr = tsk->thread.xstate->hardfpu.fpscr;
                prec = fpscr & (1 << 19);
 
                if ((fpscr & FPSCR_FPU_ERROR)
@@ -562,15 +527,15 @@ ieee_fpe_handler (struct pt_regs *regs)
 
                        /* FPU error because of denormal */
                        llx = ((long long) hx << 32)
-                              | tsk->thread.fpu.hard.fp_regs[n+1];
+                              | tsk->thread.xstate->hardfpu.fp_regs[n+1];
                        lly = ((long long) hy << 32)
-                              | tsk->thread.fpu.hard.fp_regs[m+1];
+                              | tsk->thread.xstate->hardfpu.fp_regs[m+1];
                        if ((finsn & 0xf00f) == 0xf000)
                                llx = denormal_addd(llx, lly);
                        else
                                llx = denormal_addd(llx, lly ^ (1LL << 63));
-                       tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
-                       tsk->thread.fpu.hard.fp_regs[n+1] = llx & 0xffffffff;
+                       tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32;
+                       tsk->thread.xstate->hardfpu.fp_regs[n+1] = llx & 0xffffffff;
                } else if ((fpscr & FPSCR_FPU_ERROR)
                     && (!prec && ((hx & 0x7fffffff) < 0x00800000
                                   || (hy & 0x7fffffff) < 0x00800000))) {
@@ -579,7 +544,7 @@ ieee_fpe_handler (struct pt_regs *regs)
                                hx = denormal_addf(hx, hy);
                        else
                                hx = denormal_addf(hx, hy ^ 0x80000000);
-                       tsk->thread.fpu.hard.fp_regs[n] = hx;
+                       tsk->thread.xstate->hardfpu.fp_regs[n] = hx;
                } else
                        return 0;
 
@@ -597,7 +562,7 @@ BUILD_TRAP_HANDLER(fpu_error)
 
        __unlazy_fpu(tsk, regs);
        if (ieee_fpe_handler(regs)) {
-               tsk->thread.fpu.hard.fpscr &=
+               tsk->thread.xstate->hardfpu.fpscr &=
                        ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
                grab_fpu(regs);
                restore_fpu(tsk);
@@ -607,33 +572,3 @@ BUILD_TRAP_HANDLER(fpu_error)
 
        force_sig(SIGFPE, tsk);
 }
-
-void fpu_state_restore(struct pt_regs *regs)
-{
-       struct task_struct *tsk = current;
-
-       grab_fpu(regs);
-       if (unlikely(!user_mode(regs))) {
-               printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
-               BUG();
-               return;
-       }
-
-       if (likely(used_math())) {
-               /* Using the FPU again.  */
-               restore_fpu(tsk);
-       } else  {
-               /* First time FPU user.  */
-               fpu_init();
-               set_used_math();
-       }
-       task_thread_info(tsk)->status |= TS_USEDFPU;
-       tsk->fpu_counter++;
-}
-
-BUILD_TRAP_HANDLER(fpu_state_restore)
-{
-       TRAP_HANDLER_DECL;
-
-       fpu_state_restore(regs);
-}
index 46610c3..99b4d02 100644 (file)
@@ -49,7 +49,7 @@ ENTRY(exception_handling_table)
        .long   exception_error ! reserved_instruction (filled by trap_init) /* 180 */
        .long   exception_error ! illegal_slot_instruction (filled by trap_init) /*1A0*/
        .long   nmi_trap_handler        /* 1C0 */       ! Allow trap to debugger
-       .long   break_point_trap        /* 1E0 */
+       .long   breakpoint_trap_handler /* 1E0 */
 
        /*
         * Pad the remainder of the table out, exceptions residing in far
index e97857a..447482d 100644 (file)
@@ -85,14 +85,14 @@ void save_fpu(struct task_struct *tsk)
                      "fmov.s   fr1, @-%0\n\t"
                      "fmov.s   fr0, @-%0\n\t"
                      "lds      %3, fpscr\n\t":"=r" (dummy)
-                     :"0"((char *)(&tsk->thread.fpu.hard.status)),
+                     :"0"((char *)(&tsk->thread.xstate->hardfpu.status)),
                      "r"(FPSCR_RCHG), "r"(FPSCR_INIT)
                      :"memory");
 
        disable_fpu();
 }
 
-static void restore_fpu(struct task_struct *tsk)
+void restore_fpu(struct task_struct *tsk)
 {
        unsigned long dummy;
 
@@ -135,62 +135,11 @@ static void restore_fpu(struct task_struct *tsk)
                      "lds.l    @%0+, fpscr\n\t"
                      "lds.l    @%0+, fpul\n\t"
                      :"=r" (dummy)
-                     :"0"(&tsk->thread.fpu), "r"(FPSCR_RCHG)
+                     :"0" (tsk->thread.xstate), "r" (FPSCR_RCHG)
                      :"memory");
        disable_fpu();
 }
 
-/*
- * Load the FPU with signalling NANS.  This bit pattern we're using
- * has the property that no matter wether considered as single or as
- * double precision represents signaling NANS.
- */
-
-static void fpu_init(void)
-{
-       enable_fpu();
-       asm volatile (  "lds    %0, fpul\n\t"
-                       "lds    %1, fpscr\n\t"
-                       "fsts   fpul, fr0\n\t"
-                       "fsts   fpul, fr1\n\t"
-                       "fsts   fpul, fr2\n\t"
-                       "fsts   fpul, fr3\n\t"
-                       "fsts   fpul, fr4\n\t"
-                       "fsts   fpul, fr5\n\t"
-                       "fsts   fpul, fr6\n\t"
-                       "fsts   fpul, fr7\n\t"
-                       "fsts   fpul, fr8\n\t"
-                       "fsts   fpul, fr9\n\t"
-                       "fsts   fpul, fr10\n\t"
-                       "fsts   fpul, fr11\n\t"
-                       "fsts   fpul, fr12\n\t"
-                       "fsts   fpul, fr13\n\t"
-                       "fsts   fpul, fr14\n\t"
-                       "fsts   fpul, fr15\n\t"
-                       "frchg\n\t"
-                       "fsts   fpul, fr0\n\t"
-                       "fsts   fpul, fr1\n\t"
-                       "fsts   fpul, fr2\n\t"
-                       "fsts   fpul, fr3\n\t"
-                       "fsts   fpul, fr4\n\t"
-                       "fsts   fpul, fr5\n\t"
-                       "fsts   fpul, fr6\n\t"
-                       "fsts   fpul, fr7\n\t"
-                       "fsts   fpul, fr8\n\t"
-                       "fsts   fpul, fr9\n\t"
-                       "fsts   fpul, fr10\n\t"
-                       "fsts   fpul, fr11\n\t"
-                       "fsts   fpul, fr12\n\t"
-                       "fsts   fpul, fr13\n\t"
-                       "fsts   fpul, fr14\n\t"
-                       "fsts   fpul, fr15\n\t"
-                       "frchg\n\t"
-                       "lds    %2, fpscr\n\t"
-                       :       /* no output */
-                       :"r" (0), "r"(FPSCR_RCHG), "r"(FPSCR_INIT));
-       disable_fpu();
-}
-
 /**
  *      denormal_to_double - Given denormalized float number,
  *                           store double float
@@ -282,9 +231,9 @@ static int ieee_fpe_handler(struct pt_regs *regs)
                /* fcnvsd */
                struct task_struct *tsk = current;
 
-               if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR))
+               if ((tsk->thread.xstate->hardfpu.fpscr & FPSCR_CAUSE_ERROR))
                        /* FPU error */
-                       denormal_to_double(&tsk->thread.fpu.hard,
+                       denormal_to_double(&tsk->thread.xstate->hardfpu,
                                           (finsn >> 8) & 0xf);
                else
                        return 0;
@@ -300,9 +249,9 @@ static int ieee_fpe_handler(struct pt_regs *regs)
 
                n = (finsn >> 8) & 0xf;
                m = (finsn >> 4) & 0xf;
-               hx = tsk->thread.fpu.hard.fp_regs[n];
-               hy = tsk->thread.fpu.hard.fp_regs[m];
-               fpscr = tsk->thread.fpu.hard.fpscr;
+               hx = tsk->thread.xstate->hardfpu.fp_regs[n];
+               hy = tsk->thread.xstate->hardfpu.fp_regs[m];
+               fpscr = tsk->thread.xstate->hardfpu.fpscr;
                prec = fpscr & FPSCR_DBL_PRECISION;
 
                if ((fpscr & FPSCR_CAUSE_ERROR)
@@ -312,18 +261,18 @@ static int ieee_fpe_handler(struct pt_regs *regs)
 
                        /* FPU error because of denormal (doubles) */
                        llx = ((long long)hx << 32)
-                           | tsk->thread.fpu.hard.fp_regs[n + 1];
+                           | tsk->thread.xstate->hardfpu.fp_regs[n + 1];
                        lly = ((long long)hy << 32)
-                           | tsk->thread.fpu.hard.fp_regs[m + 1];
+                           | tsk->thread.xstate->hardfpu.fp_regs[m + 1];
                        llx = float64_mul(llx, lly);
-                       tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
-                       tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff;
+                       tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32;
+                       tsk->thread.xstate->hardfpu.fp_regs[n + 1] = llx & 0xffffffff;
                } else if ((fpscr & FPSCR_CAUSE_ERROR)
                           && (!prec && ((hx & 0x7fffffff) < 0x00800000
                                         || (hy & 0x7fffffff) < 0x00800000))) {
                        /* FPU error because of denormal (floats) */
                        hx = float32_mul(hx, hy);
-                       tsk->thread.fpu.hard.fp_regs[n] = hx;
+                       tsk->thread.xstate->hardfpu.fp_regs[n] = hx;
                } else
                        return 0;
 
@@ -338,9 +287,9 @@ static int ieee_fpe_handler(struct pt_regs *regs)
 
                n = (finsn >> 8) & 0xf;
                m = (finsn >> 4) & 0xf;
-               hx = tsk->thread.fpu.hard.fp_regs[n];
-               hy = tsk->thread.fpu.hard.fp_regs[m];
-               fpscr = tsk->thread.fpu.hard.fpscr;
+               hx = tsk->thread.xstate->hardfpu.fp_regs[n];
+               hy = tsk->thread.xstate->hardfpu.fp_regs[m];
+               fpscr = tsk->thread.xstate->hardfpu.fpscr;
                prec = fpscr & FPSCR_DBL_PRECISION;
 
                if ((fpscr & FPSCR_CAUSE_ERROR)
@@ -350,15 +299,15 @@ static int ieee_fpe_handler(struct pt_regs *regs)
 
                        /* FPU error because of denormal (doubles) */
                        llx = ((long long)hx << 32)
-                           | tsk->thread.fpu.hard.fp_regs[n + 1];
+                           | tsk->thread.xstate->hardfpu.fp_regs[n + 1];
                        lly = ((long long)hy << 32)
-                           | tsk->thread.fpu.hard.fp_regs[m + 1];
+                           | tsk->thread.xstate->hardfpu.fp_regs[m + 1];
                        if ((finsn & 0xf00f) == 0xf000)
                                llx = float64_add(llx, lly);
                        else
                                llx = float64_sub(llx, lly);
-                       tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
-                       tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff;
+                       tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32;
+                       tsk->thread.xstate->hardfpu.fp_regs[n + 1] = llx & 0xffffffff;
                } else if ((fpscr & FPSCR_CAUSE_ERROR)
                           && (!prec && ((hx & 0x7fffffff) < 0x00800000
                                         || (hy & 0x7fffffff) < 0x00800000))) {
@@ -367,7 +316,7 @@ static int ieee_fpe_handler(struct pt_regs *regs)
                                hx = float32_add(hx, hy);
                        else
                                hx = float32_sub(hx, hy);
-                       tsk->thread.fpu.hard.fp_regs[n] = hx;
+                       tsk->thread.xstate->hardfpu.fp_regs[n] = hx;
                } else
                        return 0;
 
@@ -382,9 +331,9 @@ static int ieee_fpe_handler(struct pt_regs *regs)
 
                n = (finsn >> 8) & 0xf;
                m = (finsn >> 4) & 0xf;
-               hx = tsk->thread.fpu.hard.fp_regs[n];
-               hy = tsk->thread.fpu.hard.fp_regs[m];
-               fpscr = tsk->thread.fpu.hard.fpscr;
+               hx = tsk->thread.xstate->hardfpu.fp_regs[n];
+               hy = tsk->thread.xstate->hardfpu.fp_regs[m];
+               fpscr = tsk->thread.xstate->hardfpu.fpscr;
                prec = fpscr & FPSCR_DBL_PRECISION;
 
                if ((fpscr & FPSCR_CAUSE_ERROR)
@@ -394,20 +343,20 @@ static int ieee_fpe_handler(struct pt_regs *regs)
 
                        /* FPU error because of denormal (doubles) */
                        llx = ((long long)hx << 32)
-                           | tsk->thread.fpu.hard.fp_regs[n + 1];
+                           | tsk->thread.xstate->hardfpu.fp_regs[n + 1];
                        lly = ((long long)hy << 32)
-                           | tsk->thread.fpu.hard.fp_regs[m + 1];
+                           | tsk->thread.xstate->hardfpu.fp_regs[m + 1];
 
                        llx = float64_div(llx, lly);
 
-                       tsk->thread.fpu.hard.fp_regs[n] = llx >> 32;
-                       tsk->thread.fpu.hard.fp_regs[n + 1] = llx & 0xffffffff;
+                       tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32;
+                       tsk->thread.xstate->hardfpu.fp_regs[n + 1] = llx & 0xffffffff;
                } else if ((fpscr & FPSCR_CAUSE_ERROR)
                           && (!prec && ((hx & 0x7fffffff) < 0x00800000
                                         || (hy & 0x7fffffff) < 0x00800000))) {
                        /* FPU error because of denormal (floats) */
                        hx = float32_div(hx, hy);
-                       tsk->thread.fpu.hard.fp_regs[n] = hx;
+                       tsk->thread.xstate->hardfpu.fp_regs[n] = hx;
                } else
                        return 0;
 
@@ -420,17 +369,17 @@ static int ieee_fpe_handler(struct pt_regs *regs)
                unsigned int hx;
 
                m = (finsn >> 8) & 0x7;
-               hx = tsk->thread.fpu.hard.fp_regs[m];
+               hx = tsk->thread.xstate->hardfpu.fp_regs[m];
 
-               if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR)
+               if ((tsk->thread.xstate->hardfpu.fpscr & FPSCR_CAUSE_ERROR)
                        && ((hx & 0x7fffffff) < 0x00100000)) {
                        /* subnormal double to float conversion */
                        long long llx;
 
-                       llx = ((long long)tsk->thread.fpu.hard.fp_regs[m] << 32)
-                           | tsk->thread.fpu.hard.fp_regs[m + 1];
+                       llx = ((long long)tsk->thread.xstate->hardfpu.fp_regs[m] << 32)
+                           | tsk->thread.xstate->hardfpu.fp_regs[m + 1];
 
-                       tsk->thread.fpu.hard.fpul = float64_to_float32(llx);
+                       tsk->thread.xstate->hardfpu.fpul = float64_to_float32(llx);
                } else
                        return 0;
 
@@ -449,7 +398,7 @@ void float_raise(unsigned int flags)
 int float_rounding_mode(void)
 {
        struct task_struct *tsk = current;
-       int roundingMode = FPSCR_ROUNDING_MODE(tsk->thread.fpu.hard.fpscr);
+       int roundingMode = FPSCR_ROUNDING_MODE(tsk->thread.xstate->hardfpu.fpscr);
        return roundingMode;
 }
 
@@ -461,16 +410,16 @@ BUILD_TRAP_HANDLER(fpu_error)
        __unlazy_fpu(tsk, regs);
        fpu_exception_flags = 0;
        if (ieee_fpe_handler(regs)) {
-               tsk->thread.fpu.hard.fpscr &=
+               tsk->thread.xstate->hardfpu.fpscr &=
                    ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
-               tsk->thread.fpu.hard.fpscr |= fpu_exception_flags;
+               tsk->thread.xstate->hardfpu.fpscr |= fpu_exception_flags;
                /* Set the FPSCR flag as well as cause bits - simply
                 * replicate the cause */
-               tsk->thread.fpu.hard.fpscr |= (fpu_exception_flags >> 10);
+               tsk->thread.xstate->hardfpu.fpscr |= (fpu_exception_flags >> 10);
                grab_fpu(regs);
                restore_fpu(tsk);
                task_thread_info(tsk)->status |= TS_USEDFPU;
-               if ((((tsk->thread.fpu.hard.fpscr & FPSCR_ENABLE_MASK) >> 7) &
+               if ((((tsk->thread.xstate->hardfpu.fpscr & FPSCR_ENABLE_MASK) >> 7) &
                     (fpu_exception_flags >> 2)) == 0) {
                        return;
                }
@@ -478,33 +427,3 @@ BUILD_TRAP_HANDLER(fpu_error)
 
        force_sig(SIGFPE, tsk);
 }
-
-void fpu_state_restore(struct pt_regs *regs)
-{
-       struct task_struct *tsk = current;
-
-       grab_fpu(regs);
-       if (unlikely(!user_mode(regs))) {
-               printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
-               BUG();
-               return;
-       }
-
-       if (likely(used_math())) {
-               /* Using the FPU again.  */
-               restore_fpu(tsk);
-       } else {
-               /* First time FPU user.  */
-               fpu_init();
-               set_used_math();
-       }
-       task_thread_info(tsk)->status |= TS_USEDFPU;
-       tsk->fpu_counter++;
-}
-
-BUILD_TRAP_HANDLER(fpu_state_restore)
-{
-       TRAP_HANDLER_DECL;
-
-       fpu_state_restore(regs);
-}
index 33bab47..b144e8a 100644 (file)
@@ -41,7 +41,8 @@ pinmux-$(CONFIG_CPU_SUBTYPE_SH7757)   := pinmux-sh7757.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7785)    := pinmux-sh7785.o
 pinmux-$(CONFIG_CPU_SUBTYPE_SH7786)    := pinmux-sh7786.o
 
-obj-y                          += $(clock-y)
-obj-$(CONFIG_SMP)              += $(smp-y)
-obj-$(CONFIG_GENERIC_GPIO)     += $(pinmux-y)
-obj-$(CONFIG_PERF_EVENTS)      += perf_event.o
+obj-y                                  += $(clock-y)
+obj-$(CONFIG_SMP)                      += $(smp-y)
+obj-$(CONFIG_GENERIC_GPIO)             += $(pinmux-y)
+obj-$(CONFIG_PERF_EVENTS)              += perf_event.o
+obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += ubc.o
diff --git a/arch/sh/kernel/cpu/sh4a/ubc.c b/arch/sh/kernel/cpu/sh4a/ubc.c
new file mode 100644 (file)
index 0000000..efb2745
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * arch/sh/kernel/cpu/sh4a/ubc.c
+ *
+ * On-chip UBC support for SH-4A CPUs.
+ *
+ * Copyright (C) 2009 - 2010  Paul Mundt
+ *
+ * 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/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <asm/hw_breakpoint.h>
+
+#define UBC_CBR(idx)   (0xff200000 + (0x20 * idx))
+#define UBC_CRR(idx)   (0xff200004 + (0x20 * idx))
+#define UBC_CAR(idx)   (0xff200008 + (0x20 * idx))
+#define UBC_CAMR(idx)  (0xff20000c + (0x20 * idx))
+
+#define UBC_CCMFR      0xff200600
+#define UBC_CBCR       0xff200620
+
+/* CRR */
+#define UBC_CRR_PCB    (1 << 1)
+#define UBC_CRR_BIE    (1 << 0)
+
+/* CBR */
+#define UBC_CBR_CE     (1 << 0)
+
+static struct sh_ubc sh4a_ubc;
+
+static void sh4a_ubc_enable(struct arch_hw_breakpoint *info, int idx)
+{
+       __raw_writel(UBC_CBR_CE | info->len | info->type, UBC_CBR(idx));
+       __raw_writel(info->address, UBC_CAR(idx));
+}
+
+static void sh4a_ubc_disable(struct arch_hw_breakpoint *info, int idx)
+{
+       __raw_writel(0, UBC_CBR(idx));
+       __raw_writel(0, UBC_CAR(idx));
+}
+
+static void sh4a_ubc_enable_all(unsigned long mask)
+{
+       int i;
+
+       for (i = 0; i < sh4a_ubc.num_events; i++)
+               if (mask & (1 << i))
+                       __raw_writel(__raw_readl(UBC_CBR(i)) | UBC_CBR_CE,
+                                    UBC_CBR(i));
+}
+
+static void sh4a_ubc_disable_all(void)
+{
+       int i;
+
+       for (i = 0; i < sh4a_ubc.num_events; i++)
+               __raw_writel(__raw_readl(UBC_CBR(i)) & ~UBC_CBR_CE,
+                            UBC_CBR(i));
+}
+
+static unsigned long sh4a_ubc_active_mask(void)
+{
+       unsigned long active = 0;
+       int i;
+
+       for (i = 0; i < sh4a_ubc.num_events; i++)
+               if (__raw_readl(UBC_CBR(i)) & UBC_CBR_CE)
+                       active |= (1 << i);
+
+       return active;
+}
+
+static unsigned long sh4a_ubc_triggered_mask(void)
+{
+       return __raw_readl(UBC_CCMFR);
+}
+
+static void sh4a_ubc_clear_triggered_mask(unsigned long mask)
+{
+       __raw_writel(__raw_readl(UBC_CCMFR) & ~mask, UBC_CCMFR);
+}
+
+static struct sh_ubc sh4a_ubc = {
+       .name                   = "SH-4A",
+       .num_events             = 2,
+       .trap_nr                = 0x1e0,
+       .enable                 = sh4a_ubc_enable,
+       .disable                = sh4a_ubc_disable,
+       .enable_all             = sh4a_ubc_enable_all,
+       .disable_all            = sh4a_ubc_disable_all,
+       .active_mask            = sh4a_ubc_active_mask,
+       .triggered_mask         = sh4a_ubc_triggered_mask,
+       .clear_triggered_mask   = sh4a_ubc_clear_triggered_mask,
+};
+
+static int __init sh4a_ubc_init(void)
+{
+       struct clk *ubc_iclk = clk_get(NULL, "ubc0");
+       int i;
+
+       /*
+        * The UBC MSTP bit is optional, as not all platforms will have
+        * it. Just ignore it if we can't find it.
+        */
+       if (IS_ERR(ubc_iclk))
+               ubc_iclk = NULL;
+
+       clk_enable(ubc_iclk);
+
+       __raw_writel(0, UBC_CBCR);
+
+       for (i = 0; i < sh4a_ubc.num_events; i++) {
+               __raw_writel(0, UBC_CAMR(i));
+               __raw_writel(0, UBC_CBR(i));
+
+               __raw_writel(UBC_CRR_BIE | UBC_CRR_PCB, UBC_CRR(i));
+
+               /* dummy read for write posting */
+               (void)__raw_readl(UBC_CRR(i));
+       }
+
+       clk_disable(ubc_iclk);
+
+       sh4a_ubc.clk = ubc_iclk;
+
+       return register_sh_ubc(&sh4a_ubc);
+}
+arch_initcall(sh4a_ubc_init);
index 5917413..7a1b46f 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/linkage.h>
 
 #if !defined(CONFIG_KGDB)
-#define breakpoint_trap_handler                debug_trap_handler
 #define singlestep_trap_handler                debug_trap_handler
 #endif
 
diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c
deleted file mode 100644 (file)
index f8bb50c..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * arch/sh/kernel/early_printk.c
- *
- *  Copyright (C) 1999, 2000  Niibe Yutaka
- *  Copyright (C) 2002  M. R. Brown
- *  Copyright (C) 2004 - 2007  Paul Mundt
- *
- * 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/console.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-
-#include <asm/sh_bios.h>
-
-/*
- *     Print a string through the BIOS
- */
-static void sh_console_write(struct console *co, const char *s,
-                                unsigned count)
-{
-       sh_bios_console_write(s, count);
-}
-
-/*
- *     Setup initial baud/bits/parity. We do two things here:
- *     - construct a cflag setting for the first rs_open()
- *     - initialize the serial port
- *     Return non-zero if we didn't find a serial port.
- */
-static int __init sh_console_setup(struct console *co, char *options)
-{
-       int     cflag = CREAD | HUPCL | CLOCAL;
-
-       /*
-        *      Now construct a cflag setting.
-        *      TODO: this is a totally bogus cflag, as we have
-        *      no idea what serial settings the BIOS is using, or
-        *      even if its using the serial port at all.
-        */
-       cflag |= B115200 | CS8 | /*no parity*/0;
-
-       co->cflag = cflag;
-
-       return 0;
-}
-
-static struct console bios_console = {
-       .name           = "bios",
-       .write          = sh_console_write,
-       .setup          = sh_console_setup,
-       .flags          = CON_PRINTBUFFER,
-       .index          = -1,
-};
-
-static struct console *early_console;
-
-static int __init setup_early_printk(char *buf)
-{
-       int keep_early = 0;
-
-       if (!buf)
-               return 0;
-
-       if (strstr(buf, "keep"))
-               keep_early = 1;
-
-       if (!strncmp(buf, "bios", 4))
-               early_console = &bios_console;
-
-       if (likely(early_console)) {
-               if (keep_early)
-                       early_console->flags &= ~CON_BOOT;
-               else
-                       early_console->flags |= CON_BOOT;
-               register_console(early_console);
-       }
-
-       return 0;
-}
-early_param("earlyprintk", setup_early_printk);
index 3ea7658..defd851 100644 (file)
@@ -220,7 +220,6 @@ clear_DTLB:
        add.l   r22, r63, r22           /* Sign extend */
        putcfg  r21, 0, r22             /* Set MMUDR[0].PTEH */
 
-#ifdef CONFIG_EARLY_PRINTK
        /*
         * Setup a DTLB translation for SCIF phys.
         */
@@ -231,7 +230,6 @@ clear_DTLB:
        movi    0xfa03, r22     /* 0xfa030000, fixed SCIF virt */
        shori   0x0003, r22
        putcfg  r21, 0, r22     /* PTEH last */
-#endif
 
        /*
         * Set cache behaviours.
diff --git a/arch/sh/kernel/hw_breakpoint.c b/arch/sh/kernel/hw_breakpoint.c
new file mode 100644 (file)
index 0000000..e2f1753
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * arch/sh/kernel/hw_breakpoint.c
+ *
+ * Unified kernel/user-space hardware breakpoint facility for the on-chip UBC.
+ *
+ * Copyright (C) 2009 - 2010  Paul Mundt
+ *
+ * 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/init.h>
+#include <linux/perf_event.h>
+#include <linux/hw_breakpoint.h>
+#include <linux/percpu.h>
+#include <linux/kallsyms.h>
+#include <linux/notifier.h>
+#include <linux/kprobes.h>
+#include <linux/kdebug.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <asm/hw_breakpoint.h>
+#include <asm/mmu_context.h>
+#include <asm/ptrace.h>
+
+/*
+ * Stores the breakpoints currently in use on each breakpoint address
+ * register for each cpus
+ */
+static DEFINE_PER_CPU(struct perf_event *, bp_per_reg[HBP_NUM]);
+
+/*
+ * A dummy placeholder for early accesses until the CPUs get a chance to
+ * register their UBCs later in the boot process.
+ */
+static struct sh_ubc ubc_dummy = { .num_events = 0 };
+
+static struct sh_ubc *sh_ubc __read_mostly = &ubc_dummy;
+
+/*
+ * Install a perf counter breakpoint.
+ *
+ * We seek a free UBC channel and use it for this breakpoint.
+ *
+ * Atomic: we hold the counter->ctx->lock and we only handle variables
+ * and registers local to this cpu.
+ */
+int arch_install_hw_breakpoint(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+       int i;
+
+       for (i = 0; i < sh_ubc->num_events; i++) {
+               struct perf_event **slot = &__get_cpu_var(bp_per_reg[i]);
+
+               if (!*slot) {
+                       *slot = bp;
+                       break;
+               }
+       }
+
+       if (WARN_ONCE(i == sh_ubc->num_events, "Can't find any breakpoint slot"))
+               return -EBUSY;
+
+       clk_enable(sh_ubc->clk);
+       sh_ubc->enable(info, i);
+
+       return 0;
+}
+
+/*
+ * Uninstall the breakpoint contained in the given counter.
+ *
+ * First we search the debug address register it uses and then we disable
+ * it.
+ *
+ * Atomic: we hold the counter->ctx->lock and we only handle variables
+ * and registers local to this cpu.
+ */
+void arch_uninstall_hw_breakpoint(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+       int i;
+
+       for (i = 0; i < sh_ubc->num_events; i++) {
+               struct perf_event **slot = &__get_cpu_var(bp_per_reg[i]);
+
+               if (*slot == bp) {
+                       *slot = NULL;
+                       break;
+               }
+       }
+
+       if (WARN_ONCE(i == sh_ubc->num_events, "Can't find any breakpoint slot"))
+               return;
+
+       sh_ubc->disable(info, i);
+       clk_disable(sh_ubc->clk);
+}
+
+static int get_hbp_len(u16 hbp_len)
+{
+       unsigned int len_in_bytes = 0;
+
+       switch (hbp_len) {
+       case SH_BREAKPOINT_LEN_1:
+               len_in_bytes = 1;
+               break;
+       case SH_BREAKPOINT_LEN_2:
+               len_in_bytes = 2;
+               break;
+       case SH_BREAKPOINT_LEN_4:
+               len_in_bytes = 4;
+               break;
+       case SH_BREAKPOINT_LEN_8:
+               len_in_bytes = 8;
+               break;
+       }
+       return len_in_bytes;
+}
+
+/*
+ * Check for virtual address in user space.
+ */
+int arch_check_va_in_userspace(unsigned long va, u16 hbp_len)
+{
+       unsigned int len;
+
+       len = get_hbp_len(hbp_len);
+
+       return (va <= TASK_SIZE - len);
+}
+
+/*
+ * Check for virtual address in kernel space.
+ */
+static int arch_check_va_in_kernelspace(unsigned long va, u8 hbp_len)
+{
+       unsigned int len;
+
+       len = get_hbp_len(hbp_len);
+
+       return (va >= TASK_SIZE) && ((va + len - 1) >= TASK_SIZE);
+}
+
+/*
+ * Store a breakpoint's encoded address, length, and type.
+ */
+static int arch_store_info(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+
+       /*
+        * User-space requests will always have the address field populated
+        * For kernel-addresses, either the address or symbol name can be
+        * specified.
+        */
+       if (info->name)
+               info->address = (unsigned long)kallsyms_lookup_name(info->name);
+       if (info->address)
+               return 0;
+
+       return -EINVAL;
+}
+
+int arch_bp_generic_fields(int sh_len, int sh_type,
+                          int *gen_len, int *gen_type)
+{
+       /* Len */
+       switch (sh_len) {
+       case SH_BREAKPOINT_LEN_1:
+               *gen_len = HW_BREAKPOINT_LEN_1;
+               break;
+       case SH_BREAKPOINT_LEN_2:
+               *gen_len = HW_BREAKPOINT_LEN_2;
+               break;
+       case SH_BREAKPOINT_LEN_4:
+               *gen_len = HW_BREAKPOINT_LEN_4;
+               break;
+       case SH_BREAKPOINT_LEN_8:
+               *gen_len = HW_BREAKPOINT_LEN_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Type */
+       switch (sh_type) {
+       case SH_BREAKPOINT_READ:
+               *gen_type = HW_BREAKPOINT_R;
+       case SH_BREAKPOINT_WRITE:
+               *gen_type = HW_BREAKPOINT_W;
+               break;
+       case SH_BREAKPOINT_RW:
+               *gen_type = HW_BREAKPOINT_W | HW_BREAKPOINT_R;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int arch_build_bp_info(struct perf_event *bp)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+
+       info->address = bp->attr.bp_addr;
+
+       /* Len */
+       switch (bp->attr.bp_len) {
+       case HW_BREAKPOINT_LEN_1:
+               info->len = SH_BREAKPOINT_LEN_1;
+               break;
+       case HW_BREAKPOINT_LEN_2:
+               info->len = SH_BREAKPOINT_LEN_2;
+               break;
+       case HW_BREAKPOINT_LEN_4:
+               info->len = SH_BREAKPOINT_LEN_4;
+               break;
+       case HW_BREAKPOINT_LEN_8:
+               info->len = SH_BREAKPOINT_LEN_8;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* Type */
+       switch (bp->attr.bp_type) {
+       case HW_BREAKPOINT_R:
+               info->type = SH_BREAKPOINT_READ;
+               break;
+       case HW_BREAKPOINT_W:
+               info->type = SH_BREAKPOINT_WRITE;
+               break;
+       case HW_BREAKPOINT_W | HW_BREAKPOINT_R:
+               info->type = SH_BREAKPOINT_RW;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+ * Validate the arch-specific HW Breakpoint register settings
+ */
+int arch_validate_hwbkpt_settings(struct perf_event *bp,
+                                 struct task_struct *tsk)
+{
+       struct arch_hw_breakpoint *info = counter_arch_bp(bp);
+       unsigned int align;
+       int ret;
+
+       ret = arch_build_bp_info(bp);
+       if (ret)
+               return ret;
+
+       ret = -EINVAL;
+
+       switch (info->len) {
+       case SH_BREAKPOINT_LEN_1:
+               align = 0;
+               break;
+       case SH_BREAKPOINT_LEN_2:
+               align = 1;
+               break;
+       case SH_BREAKPOINT_LEN_4:
+               align = 3;
+               break;
+       case SH_BREAKPOINT_LEN_8:
+               align = 7;
+               break;
+       default:
+               return ret;
+       }
+
+       ret = arch_store_info(bp);
+
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Check that the low-order bits of the address are appropriate
+        * for the alignment implied by len.
+        */
+       if (info->address & align)
+               return -EINVAL;
+
+       /* Check that the virtual address is in the proper range */
+       if (tsk) {
+               if (!arch_check_va_in_userspace(info->address, info->len))
+                       return -EFAULT;
+       } else {
+               if (!arch_check_va_in_kernelspace(info->address, info->len))
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+/*
+ * Release the user breakpoints used by ptrace
+ */
+void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
+{
+       int i;
+       struct thread_struct *t = &tsk->thread;
+
+       for (i = 0; i < sh_ubc->num_events; i++) {
+               unregister_hw_breakpoint(t->ptrace_bps[i]);
+               t->ptrace_bps[i] = NULL;
+       }
+}
+
+static int __kprobes hw_breakpoint_handler(struct die_args *args)
+{
+       int cpu, i, rc = NOTIFY_STOP;
+       struct perf_event *bp;
+       unsigned int cmf, resume_mask;
+
+       /*
+        * Do an early return if none of the channels triggered.
+        */
+       cmf = sh_ubc->triggered_mask();
+       if (unlikely(!cmf))
+               return NOTIFY_DONE;
+
+       /*
+        * By default, resume all of the active channels.
+        */
+       resume_mask = sh_ubc->active_mask();
+
+       /*
+        * Disable breakpoints during exception handling.
+        */
+       sh_ubc->disable_all();
+
+       cpu = get_cpu();
+       for (i = 0; i < sh_ubc->num_events; i++) {
+               unsigned long event_mask = (1 << i);
+
+               if (likely(!(cmf & event_mask)))
+                       continue;
+
+               /*
+                * The counter may be concurrently released but that can only
+                * occur from a call_rcu() path. We can then safely fetch
+                * the breakpoint, use its callback, touch its counter
+                * while we are in an rcu_read_lock() path.
+                */
+               rcu_read_lock();
+
+               bp = per_cpu(bp_per_reg[i], cpu);
+               if (bp)
+                       rc = NOTIFY_DONE;
+
+               /*
+                * Reset the condition match flag to denote completion of
+                * exception handling.
+                */
+               sh_ubc->clear_triggered_mask(event_mask);
+
+               /*
+                * bp can be NULL due to concurrent perf counter
+                * removing.
+                */
+               if (!bp) {
+                       rcu_read_unlock();
+                       break;
+               }
+
+               /*
+                * Don't restore the channel if the breakpoint is from
+                * ptrace, as it always operates in one-shot mode.
+                */
+               if (bp->overflow_handler == ptrace_triggered)
+                       resume_mask &= ~(1 << i);
+
+               perf_bp_event(bp, args->regs);
+
+               /* Deliver the signal to userspace */
+               if (arch_check_va_in_userspace(bp->attr.bp_addr,
+                                              bp->attr.bp_len)) {
+                       siginfo_t info;
+
+                       info.si_signo = args->signr;
+                       info.si_errno = notifier_to_errno(rc);
+                       info.si_code = TRAP_HWBKPT;
+
+                       force_sig_info(args->signr, &info, current);
+               }
+
+               rcu_read_unlock();
+       }
+
+       if (cmf == 0)
+               rc = NOTIFY_DONE;
+
+       sh_ubc->enable_all(resume_mask);
+
+       put_cpu();
+
+       return rc;
+}
+
+BUILD_TRAP_HANDLER(breakpoint)
+{
+       unsigned long ex = lookup_exception_vector();
+       TRAP_HANDLER_DECL;
+
+       notify_die(DIE_BREAKPOINT, "breakpoint", regs, 0, ex, SIGTRAP);
+}
+
+/*
+ * Handle debug exception notifications.
+ */
+int __kprobes hw_breakpoint_exceptions_notify(struct notifier_block *unused,
+                                   unsigned long val, void *data)
+{
+       struct die_args *args = data;
+
+       if (val != DIE_BREAKPOINT)
+               return NOTIFY_DONE;
+
+       /*
+        * If the breakpoint hasn't been triggered by the UBC, it's
+        * probably from a debugger, so don't do anything more here.
+        *
+        * This also permits the UBC interface clock to remain off for
+        * non-UBC breakpoints, as we don't need to check the triggered
+        * or active channel masks.
+        */
+       if (args->trapnr != sh_ubc->trap_nr)
+               return NOTIFY_DONE;
+
+       return hw_breakpoint_handler(data);
+}
+
+void hw_breakpoint_pmu_read(struct perf_event *bp)
+{
+       /* TODO */
+}
+
+void hw_breakpoint_pmu_unthrottle(struct perf_event *bp)
+{
+       /* TODO */
+}
+
+int register_sh_ubc(struct sh_ubc *ubc)
+{
+       /* Bail if it's already assigned */
+       if (sh_ubc != &ubc_dummy)
+               return -EBUSY;
+       sh_ubc = ubc;
+
+       pr_info("HW Breakpoints: %s UBC support registered\n", ubc->name);
+
+       WARN_ON(ubc->num_events > HBP_NUM);
+
+       return 0;
+}
index 3e532d0..70c6965 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * SuperH KGDB support
  *
- * Copyright (C) 2008  Paul Mundt
+ * Copyright (C) 2008 - 2009  Paul Mundt
  *
  * Single stepping taken from the old stub by Henry Bell and Jeremy Siegel.
  *
@@ -251,24 +251,60 @@ BUILD_TRAP_HANDLER(singlestep)
        local_irq_restore(flags);
 }
 
+static int __kgdb_notify(struct die_args *args, unsigned long cmd)
+{
+       int ret;
+
+       switch (cmd) {
+       case DIE_BREAKPOINT:
+               /*
+                * This means a user thread is single stepping
+                * a system call which should be ignored
+                */
+               if (test_thread_flag(TIF_SINGLESTEP))
+                       return NOTIFY_DONE;
+
+               ret = kgdb_handle_exception(args->trapnr & 0xff, args->signr,
+                                           args->err, args->regs);
+               if (ret)
+                       return NOTIFY_DONE;
+
+               break;
+       }
 
-BUILD_TRAP_HANDLER(breakpoint)
+       return NOTIFY_STOP;
+}
+
+static int
+kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
 {
        unsigned long flags;
-       TRAP_HANDLER_DECL;
+       int ret;
 
        local_irq_save(flags);
-       kgdb_handle_exception(vec >> 2, SIGTRAP, 0, regs);
+       ret = __kgdb_notify(ptr, cmd);
        local_irq_restore(flags);
+
+       return ret;
 }
 
+static struct notifier_block kgdb_notifier = {
+       .notifier_call  = kgdb_notify,
+
+       /*
+        * Lowest-prio notifier priority, we want to be notified last:
+        */
+       .priority       = -INT_MAX,
+};
+
 int kgdb_arch_init(void)
 {
-       return 0;
+       return register_die_notifier(&kgdb_notifier);
 }
 
 void kgdb_arch_exit(void)
 {
+       unregister_die_notifier(&kgdb_notifier);
 }
 
 struct kgdb_arch arch_kgdb_ops = {
index 76f2802..f52d8ed 100644 (file)
@@ -21,6 +21,7 @@
 #include <asm/mmu_context.h>
 #include <asm/io.h>
 #include <asm/cacheflush.h>
+#include <asm/sh_bios.h>
 
 typedef void (*relocate_new_kernel_t)(unsigned long indirection_page,
                                      unsigned long reboot_code_buffer,
@@ -28,7 +29,6 @@ typedef void (*relocate_new_kernel_t)(unsigned long indirection_page,
 
 extern const unsigned char relocate_new_kernel[];
 extern const unsigned int relocate_new_kernel_size;
-extern void *gdb_vbr_vector;
 extern void *vbr_base;
 
 void machine_shutdown(void)
@@ -117,11 +117,7 @@ void machine_kexec(struct kimage *image)
        kexec_info(image);
        flush_cache_all();
 
-#if defined(CONFIG_SH_STANDARD_BIOS)
-       asm volatile("ldc %0, vbr" :
-                    : "r" (((unsigned long) gdb_vbr_vector) - 0x100)
-                    : "memory");
-#endif
+       sh_bios_vbr_reload();
 
        /* now call it */
        rnk = (relocate_new_kernel_t) reboot_code_buffer;
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
new file mode 100644 (file)
index 0000000..81add9b
--- /dev/null
@@ -0,0 +1,100 @@
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+struct kmem_cache *task_xstate_cachep = NULL;
+unsigned int xstate_size;
+
+int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
+{
+       *dst = *src;
+
+       if (src->thread.xstate) {
+               dst->thread.xstate = kmem_cache_alloc(task_xstate_cachep,
+                                                     GFP_KERNEL);
+               if (!dst->thread.xstate)
+                       return -ENOMEM;
+               memcpy(dst->thread.xstate, src->thread.xstate, xstate_size);
+       }
+
+       return 0;
+}
+
+void free_thread_xstate(struct task_struct *tsk)
+{
+       if (tsk->thread.xstate) {
+               kmem_cache_free(task_xstate_cachep, tsk->thread.xstate);
+               tsk->thread.xstate = NULL;
+       }
+}
+
+#if THREAD_SHIFT < PAGE_SHIFT
+static struct kmem_cache *thread_info_cache;
+
+struct thread_info *alloc_thread_info(struct task_struct *tsk)
+{
+       struct thread_info *ti;
+
+       ti = kmem_cache_alloc(thread_info_cache, GFP_KERNEL);
+       if (unlikely(ti == NULL))
+               return NULL;
+#ifdef CONFIG_DEBUG_STACK_USAGE
+       memset(ti, 0, THREAD_SIZE);
+#endif
+       return ti;
+}
+
+void free_thread_info(struct thread_info *ti)
+{
+       free_thread_xstate(ti->task);
+       kmem_cache_free(thread_info_cache, ti);
+}
+
+void thread_info_cache_init(void)
+{
+       thread_info_cache = kmem_cache_create("thread_info", THREAD_SIZE,
+                                             THREAD_SIZE, SLAB_PANIC, NULL);
+}
+#else
+struct thread_info *alloc_thread_info(struct task_struct *tsk)
+{
+#ifdef CONFIG_DEBUG_STACK_USAGE
+       gfp_t mask = GFP_KERNEL | __GFP_ZERO;
+#else
+       gfp_t mask = GFP_KERNEL;
+#endif
+       return (struct thread_info *)__get_free_pages(mask, THREAD_SIZE_ORDER);
+}
+
+void free_thread_info(struct thread_info *ti)
+{
+       free_thread_xstate(ti->task);
+       free_pages((unsigned long)ti, THREAD_SIZE_ORDER);
+}
+#endif /* THREAD_SHIFT < PAGE_SHIFT */
+
+void arch_task_cache_init(void)
+{
+       if (!xstate_size)
+               return;
+
+       task_xstate_cachep = kmem_cache_create("task_xstate", xstate_size,
+                                              __alignof__(union thread_xstate),
+                                              SLAB_PANIC | SLAB_NOTRACK, NULL);
+}
+
+#ifdef CONFIG_SH_FPU_EMU
+# define HAVE_SOFTFP   1
+#else
+# define HAVE_SOFTFP   0
+#endif
+
+void init_thread_xstate(void)
+{
+       if (boot_cpu_data.flags & CPU_HAS_FPU)
+               xstate_size = sizeof(struct sh_fpu_hard_struct);
+       else if (HAVE_SOFTFP)
+               xstate_size = sizeof(struct sh_fpu_soft_struct);
+       else
+               xstate_size = 0;
+}
index d8af889..856010f 100644 (file)
 #include <linux/fs.h>
 #include <linux/ftrace.h>
 #include <linux/preempt.h>
+#include <linux/hw_breakpoint.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/pgalloc.h>
 #include <asm/system.h>
-#include <asm/ubc.h>
 #include <asm/fpu.h>
 #include <asm/syscalls.h>
 #include <asm/watchdog.h>
 
-int ubc_usercnt = 0;
-
 #ifdef CONFIG_32BIT
 static void watchdog_trigger_immediate(void)
 {
@@ -147,21 +145,34 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 }
 EXPORT_SYMBOL(kernel_thread);
 
+void start_thread(struct pt_regs *regs, unsigned long new_pc,
+                 unsigned long new_sp)
+{
+       set_fs(USER_DS);
+
+       regs->pr = 0;
+       regs->sr = SR_FD;
+       regs->pc = new_pc;
+       regs->regs[15] = new_sp;
+
+       free_thread_xstate(current);
+}
+EXPORT_SYMBOL(start_thread);
+
 /*
  * Free current thread data structures etc..
  */
 void exit_thread(void)
 {
-       if (current->thread.ubc_pc) {
-               current->thread.ubc_pc = 0;
-               ubc_usercnt -= 1;
-       }
 }
 
 void flush_thread(void)
 {
-#if defined(CONFIG_SH_FPU)
        struct task_struct *tsk = current;
+
+       flush_ptrace_hw_breakpoint(tsk);
+
+#if defined(CONFIG_SH_FPU)
        /* Forget lazy FPU state */
        clear_fpu(tsk, task_pt_regs(tsk));
        clear_used_math();
@@ -209,11 +220,10 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
 {
        struct thread_info *ti = task_thread_info(p);
        struct pt_regs *childregs;
+
 #if defined(CONFIG_SH_DSP)
        struct task_struct *tsk = current;
-#endif
 
-#if defined(CONFIG_SH_DSP)
        if (is_dsp_enabled(tsk)) {
                /* We can use the __save_dsp or just copy the struct:
                 * __save_dsp(p);
@@ -244,53 +254,11 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
        p->thread.sp = (unsigned long) childregs;
        p->thread.pc = (unsigned long) ret_from_fork;
 
-       p->thread.ubc_pc = 0;
+       memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
 
        return 0;
 }
 
-/* Tracing by user break controller.  */
-static void ubc_set_tracing(int asid, unsigned long pc)
-{
-#if defined(CONFIG_CPU_SH4A)
-       unsigned long val;
-
-       val = (UBC_CBR_ID_INST | UBC_CBR_RW_READ | UBC_CBR_CE);
-       val |= (UBC_CBR_AIE | UBC_CBR_AIV_SET(asid));
-
-       ctrl_outl(val, UBC_CBR0);
-       ctrl_outl(pc,  UBC_CAR0);
-       ctrl_outl(0x0, UBC_CAMR0);
-       ctrl_outl(0x0, UBC_CBCR);
-
-       val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE);
-       ctrl_outl(val, UBC_CRR0);
-
-       /* Read UBC register that we wrote last, for checking update */
-       val = ctrl_inl(UBC_CRR0);
-
-#else  /* CONFIG_CPU_SH4A */
-       ctrl_outl(pc, UBC_BARA);
-
-#ifdef CONFIG_MMU
-       ctrl_outb(asid, UBC_BASRA);
-#endif
-
-       ctrl_outl(0, UBC_BAMRA);
-
-       if (current_cpu_data.type == CPU_SH7729 ||
-           current_cpu_data.type == CPU_SH7710 ||
-           current_cpu_data.type == CPU_SH7712 ||
-           current_cpu_data.type == CPU_SH7203){
-               ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
-               ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
-       } else {
-               ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA);
-               ctrl_outw(BRCR_PCBA, UBC_BRCR);
-       }
-#endif /* CONFIG_CPU_SH4A */
-}
-
 /*
  *     switch_to(x,y) should switch tasks from x to y.
  *
@@ -304,7 +272,7 @@ __switch_to(struct task_struct *prev, struct task_struct *next)
 
        /* we're going to use this soon, after a few expensive things */
        if (next->fpu_counter > 5)
-               prefetch(&next_t->fpu.hard);
+               prefetch(next_t->xstate);
 
 #ifdef CONFIG_MMU
        /*
@@ -316,32 +284,13 @@ __switch_to(struct task_struct *prev, struct task_struct *next)
                     : "r" (task_thread_info(next)));
 #endif
 
-       /* If no tasks are using the UBC, we're done */
-       if (ubc_usercnt == 0)
-               /* If no tasks are using the UBC, we're done */;
-       else if (next->thread.ubc_pc && next->mm) {
-               int asid = 0;
-#ifdef CONFIG_MMU
-               asid |= cpu_asid(smp_processor_id(), next->mm);
-#endif
-               ubc_set_tracing(asid, next->thread.ubc_pc);
-       } else {
-#if defined(CONFIG_CPU_SH4A)
-               ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
-               ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
-#else
-               ctrl_outw(0, UBC_BBRA);
-               ctrl_outw(0, UBC_BBRB);
-#endif
-       }
-
        /*
         * If the task has used fpu the last 5 timeslices, just do a full
         * restore of the math state immediately to avoid the trap; the
         * chances of needing FPU soon are obviously high now
         */
        if (next->fpu_counter > 5)
-               fpu_state_restore(task_pt_regs(next));
+               __fpu_state_restore();
 
        return prev;
 }
@@ -434,20 +383,3 @@ unsigned long get_wchan(struct task_struct *p)
 
        return pc;
 }
-
-asmlinkage void break_point_trap(void)
-{
-       /* Clear tracing.  */
-#if defined(CONFIG_CPU_SH4A)
-       ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
-       ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
-#else
-       ctrl_outw(0, UBC_BBRA);
-       ctrl_outw(0, UBC_BBRB);
-       ctrl_outl(0, UBC_BRCR);
-#endif
-       current->thread.ubc_pc = 0;
-       ubc_usercnt -= 1;
-
-       force_sig(SIGTRAP, current);
-}
index 9be35f3..c625cda 100644 (file)
@@ -2,7 +2,7 @@
  * SuperH process tracing
  *
  * Copyright (C) 1999, 2000  Kaz Kojima & Niibe Yutaka
- * Copyright (C) 2002 - 2008  Paul Mundt
+ * Copyright (C) 2002 - 2009  Paul Mundt
  *
  * Audit support by Yuichi Nakamura <ynakam@hitachisoft.jp>
  *
@@ -26,6 +26,7 @@
 #include <linux/tracehook.h>
 #include <linux/elf.h>
 #include <linux/regset.h>
+#include <linux/hw_breakpoint.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
@@ -63,33 +64,64 @@ static inline int put_stack_long(struct task_struct *task, int offset,
        return 0;
 }
 
-void user_enable_single_step(struct task_struct *child)
+void ptrace_triggered(struct perf_event *bp, int nmi,
+                     struct perf_sample_data *data, struct pt_regs *regs)
 {
-       /* Next scheduling will set up UBC */
-       if (child->thread.ubc_pc == 0)
-               ubc_usercnt += 1;
+       struct perf_event_attr attr;
+
+       /*
+        * Disable the breakpoint request here since ptrace has defined a
+        * one-shot behaviour for breakpoint exceptions.
+        */
+       attr = bp->attr;
+       attr.disabled = true;
+       modify_user_hw_breakpoint(bp, &attr);
+}
+
+static int set_single_step(struct task_struct *tsk, unsigned long addr)
+{
+       struct thread_struct *thread = &tsk->thread;
+       struct perf_event *bp;
+       struct perf_event_attr attr;
+
+       bp = thread->ptrace_bps[0];
+       if (!bp) {
+               hw_breakpoint_init(&attr);
+
+               attr.bp_addr = addr;
+               attr.bp_len = HW_BREAKPOINT_LEN_2;
+               attr.bp_type = HW_BREAKPOINT_R;
+
+               bp = register_user_hw_breakpoint(&attr, ptrace_triggered, tsk);
+               if (IS_ERR(bp))
+                       return PTR_ERR(bp);
+
+               thread->ptrace_bps[0] = bp;
+       } else {
+               int err;
+
+               attr = bp->attr;
+               attr.bp_addr = addr;
+               err = modify_user_hw_breakpoint(bp, &attr);
+               if (unlikely(err))
+                       return err;
+       }
+
+       return 0;
+}
 
-       child->thread.ubc_pc = get_stack_long(child,
-                               offsetof(struct pt_regs, pc));
+void user_enable_single_step(struct task_struct *child)
+{
+       unsigned long pc = get_stack_long(child, offsetof(struct pt_regs, pc));
 
        set_tsk_thread_flag(child, TIF_SINGLESTEP);
+
+       set_single_step(child, pc);
 }
 
 void user_disable_single_step(struct task_struct *child)
 {
        clear_tsk_thread_flag(child, TIF_SINGLESTEP);
-
-       /*
-        * Ensure the UBC is not programmed at the next context switch.
-        *
-        * Normally this is not needed but there are sequences such as
-        * singlestep, signal delivery, and continue that leave the
-        * ubc_pc non-zero leading to spurious SIGTRAPs.
-        */
-       if (child->thread.ubc_pc != 0) {
-               ubc_usercnt -= 1;
-               child->thread.ubc_pc = 0;
-       }
 }
 
 /*
@@ -163,10 +195,10 @@ int fpregs_get(struct task_struct *target,
 
        if ((boot_cpu_data.flags & CPU_HAS_FPU))
                return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                          &target->thread.fpu.hard, 0, -1);
+                                          &target->thread.xstate->hardfpu, 0, -1);
 
        return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
-                                  &target->thread.fpu.soft, 0, -1);
+                                  &target->thread.xstate->softfpu, 0, -1);
 }
 
 static int fpregs_set(struct task_struct *target,
@@ -184,10 +216,10 @@ static int fpregs_set(struct task_struct *target,
 
        if ((boot_cpu_data.flags & CPU_HAS_FPU))
                return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                         &target->thread.fpu.hard, 0, -1);
+                                         &target->thread.xstate->hardfpu, 0, -1);
 
        return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
-                                 &target->thread.fpu.soft, 0, -1);
+                                 &target->thread.xstate->softfpu, 0, -1);
 }
 
 static int fpregs_active(struct task_struct *target,
@@ -333,7 +365,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                                else
                                        tmp = 0;
                        } else
-                               tmp = ((long *)&child->thread.fpu)
+                               tmp = ((long *)child->thread.xstate)
                                        [(addr - (long)&dummy->fpu) >> 2];
                } else if (addr == (long) &dummy->u_fpvalid)
                        tmp = !!tsk_used_math(child);
@@ -362,7 +394,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
                else if (addr >= (long) &dummy->fpu &&
                         addr < (long) &dummy->u_fpvalid) {
                        set_stopped_child_used_math(child);
-                       ((long *)&child->thread.fpu)
+                       ((long *)child->thread.xstate)
                                [(addr - (long)&dummy->fpu) >> 2] = data;
                        ret = 0;
                } else if (addr == (long) &dummy->u_fpvalid) {
index c852f78..47475cc 100644 (file)
@@ -1,19 +1,30 @@
 /*
- *  linux/arch/sh/kernel/sh_bios.c
  *  C interface for trapping into the standard LinuxSH BIOS.
  *
  *  Copyright (C) 2000 Greg Banks, Mitch Davis
+ *  Copyright (C) 1999, 2000  Niibe Yutaka
+ *  Copyright (C) 2002  M. R. Brown
+ *  Copyright (C) 2004 - 2010  Paul Mundt
  *
+ * 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/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/delay.h>
 #include <asm/sh_bios.h>
 
 #define BIOS_CALL_CONSOLE_WRITE                0
 #define BIOS_CALL_ETH_NODE_ADDR                10
 #define BIOS_CALL_SHUTDOWN             11
-#define BIOS_CALL_CHAR_OUT             0x1f    /* TODO: hack */
 #define BIOS_CALL_GDB_DETACH           0xff
 
+void *gdb_vbr_vector = NULL;
+
 static inline long sh_bios_call(long func, long arg0, long arg1, long arg2,
                                    long arg3)
 {
@@ -23,6 +34,9 @@ static inline long sh_bios_call(long func, long arg0, long arg1, long arg2,
        register long r6 __asm__("r6") = arg2;
        register long r7 __asm__("r7") = arg3;
 
+       if (!gdb_vbr_vector)
+               return -ENOSYS;
+
        __asm__ __volatile__("trapa     #0x3f":"=z"(r0)
                             :"0"(r0), "r"(r4), "r"(r5), "r"(r6), "r"(r7)
                             :"memory");
@@ -34,11 +48,6 @@ void sh_bios_console_write(const char *buf, unsigned int len)
        sh_bios_call(BIOS_CALL_CONSOLE_WRITE, (long)buf, (long)len, 0, 0);
 }
 
-void sh_bios_char_out(char ch)
-{
-       sh_bios_call(BIOS_CALL_CHAR_OUT, ch, 0, 0, 0);
-}
-
 void sh_bios_gdb_detach(void)
 {
        sh_bios_call(BIOS_CALL_GDB_DETACH, 0, 0, 0, 0);
@@ -55,3 +64,109 @@ void sh_bios_shutdown(unsigned int how)
 {
        sh_bios_call(BIOS_CALL_SHUTDOWN, how, 0, 0, 0);
 }
+
+/*
+ * Read the old value of the VBR register to initialise the vector
+ * through which debug and BIOS traps are delegated by the Linux trap
+ * handler.
+ */
+void sh_bios_vbr_init(void)
+{
+       unsigned long vbr;
+
+       if (unlikely(gdb_vbr_vector))
+               return;
+
+       __asm__ __volatile__ ("stc vbr, %0" : "=r" (vbr));
+
+       if (vbr) {
+               gdb_vbr_vector = (void *)(vbr + 0x100);
+               printk(KERN_NOTICE "Setting GDB trap vector to %p\n",
+                      gdb_vbr_vector);
+       } else
+               printk(KERN_NOTICE "SH-BIOS not detected\n");
+}
+
+/**
+ * sh_bios_vbr_reload - Re-load the system VBR from the BIOS vector.
+ *
+ * This can be used by save/restore code to reinitialize the system VBR
+ * from the fixed BIOS VBR. A no-op if no BIOS VBR is known.
+ */
+void sh_bios_vbr_reload(void)
+{
+       if (gdb_vbr_vector)
+               __asm__ __volatile__ (
+                       "ldc %0, vbr"
+                       :
+                       : "r" (((unsigned long) gdb_vbr_vector) - 0x100)
+                       : "memory"
+               );
+}
+
+/*
+ *     Print a string through the BIOS
+ */
+static void sh_console_write(struct console *co, const char *s,
+                                unsigned count)
+{
+       sh_bios_console_write(s, count);
+}
+
+/*
+ *     Setup initial baud/bits/parity. We do two things here:
+ *     - construct a cflag setting for the first rs_open()
+ *     - initialize the serial port
+ *     Return non-zero if we didn't find a serial port.
+ */
+static int __init sh_console_setup(struct console *co, char *options)
+{
+       int     cflag = CREAD | HUPCL | CLOCAL;
+
+       /*
+        *      Now construct a cflag setting.
+        *      TODO: this is a totally bogus cflag, as we have
+        *      no idea what serial settings the BIOS is using, or
+        *      even if its using the serial port at all.
+        */
+       cflag |= B115200 | CS8 | /*no parity*/0;
+
+       co->cflag = cflag;
+
+       return 0;
+}
+
+static struct console bios_console = {
+       .name           = "bios",
+       .write          = sh_console_write,
+       .setup          = sh_console_setup,
+       .flags          = CON_PRINTBUFFER,
+       .index          = -1,
+};
+
+static struct console *early_console;
+
+static int __init setup_early_printk(char *buf)
+{
+       int keep_early = 0;
+
+       if (!buf)
+               return 0;
+
+       if (strstr(buf, "keep"))
+               keep_early = 1;
+
+       if (!strncmp(buf, "bios", 4))
+               early_console = &bios_console;
+
+       if (likely(early_console)) {
+               if (keep_early)
+                       early_console->flags &= ~CON_BOOT;
+               else
+                       early_console->flags |= CON_BOOT;
+               register_console(early_console);
+       }
+
+       return 0;
+}
+early_param("earlyprintk", setup_early_printk);
index 12815ce..6a7cce7 100644 (file)
@@ -150,7 +150,7 @@ static inline int restore_sigcontext_fpu(struct sigcontext __user *sc)
                return 0;
 
        set_used_math();
-       return __copy_from_user(&tsk->thread.fpu.hard, &sc->sc_fpregs[0],
+       return __copy_from_user(&tsk->thread.xstate->hardfpu, &sc->sc_fpregs[0],
                                sizeof(long)*(16*2+2));
 }
 
@@ -175,7 +175,7 @@ static inline int save_sigcontext_fpu(struct sigcontext __user *sc,
        clear_used_math();
 
        unlazy_fpu(tsk, regs);
-       return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.fpu.hard,
+       return __copy_to_user(&sc->sc_fpregs[0], &tsk->thread.xstate->hardfpu,
                              sizeof(long)*(16*2+2));
 }
 #endif /* CONFIG_SH_FPU */
index 86639be..9c090cb 100644 (file)
 #include <linux/kdebug.h>
 #include <linux/kexec.h>
 #include <linux/limits.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
 #include <linux/sysfs.h>
+#include <linux/uaccess.h>
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <asm/alignment.h>
 #include <asm/fpu.h>
 #include <asm/kprobes.h>
+#include <asm/sh_bios.h>
 
 #ifdef CONFIG_CPU_SH2
 # define TRAP_RESERVED_INST    4
 #define TRAP_ILLEGAL_SLOT_INST 13
 #endif
 
-static unsigned long se_user;
-static unsigned long se_sys;
-static unsigned long se_half;
-static unsigned long se_word;
-static unsigned long se_dword;
-static unsigned long se_multi;
-/* bitfield: 1: warn 2: fixup 4: signal -> combinations 2|4 && 1|2|4 are not
-   valid! */
-static int se_usermode = 3;
-/* 0: no warning 1: print a warning message, disabled by default */
-static int se_kernmode_warn;
-
-#ifdef CONFIG_PROC_FS
-static const char *se_usermode_action[] = {
-       "ignored",
-       "warn",
-       "fixup",
-       "fixup+warn",
-       "signal",
-       "signal+warn"
-};
-
-static int alignment_proc_show(struct seq_file *m, void *v)
-{
-       seq_printf(m, "User:\t\t%lu\n", se_user);
-       seq_printf(m, "System:\t\t%lu\n", se_sys);
-       seq_printf(m, "Half:\t\t%lu\n", se_half);
-       seq_printf(m, "Word:\t\t%lu\n", se_word);
-       seq_printf(m, "DWord:\t\t%lu\n", se_dword);
-       seq_printf(m, "Multi:\t\t%lu\n", se_multi);
-       seq_printf(m, "User faults:\t%i (%s)\n", se_usermode,
-                       se_usermode_action[se_usermode]);
-       seq_printf(m, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn,
-                       se_kernmode_warn ? "+warn" : "");
-       return 0;
-}
-
-static int alignment_proc_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, alignment_proc_show, NULL);
-}
-
-static ssize_t alignment_proc_write(struct file *file,
-               const char __user *buffer, size_t count, loff_t *pos)
-{
-       int *data = PDE(file->f_path.dentry->d_inode)->data;
-       char mode;
-
-       if (count > 0) {
-               if (get_user(mode, buffer))
-                       return -EFAULT;
-               if (mode >= '0' && mode <= '5')
-                       *data = mode - '0';
-       }
-       return count;
-}
-
-static const struct file_operations alignment_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = alignment_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-       .write          = alignment_proc_write,
-};
-#endif
-
 static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
 {
        unsigned long p;
@@ -265,10 +198,10 @@ static int handle_unaligned_ins(insn_size_t instruction, struct pt_regs *regs,
        count = 1<<(instruction&3);
 
        switch (count) {
-       case 1: se_half  += 1; break;
-       case 2: se_word  += 1; break;
-       case 4: se_dword += 1; break;
-       case 8: se_multi += 1; break; /* ??? */
+       case 1: inc_unaligned_byte_access(); break;
+       case 2: inc_unaligned_word_access(); break;
+       case 4: inc_unaligned_dword_access(); break;
+       case 8: inc_unaligned_multi_access(); break;
        }
 
        ret = -EFAULT;
@@ -452,18 +385,8 @@ int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs,
        rm = regs->regs[index];
 
        /* shout about fixups */
-       if (!expected) {
-               if (user_mode(regs) && (se_usermode & 1) && printk_ratelimit())
-                       pr_notice("Fixing up unaligned userspace access "
-                                 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
-                                 current->comm, task_pid_nr(current),
-                                 (void *)regs->pc, instruction);
-               else if (se_kernmode_warn && printk_ratelimit())
-                       pr_notice("Fixing up unaligned kernel access "
-                                 "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
-                                 current->comm, task_pid_nr(current),
-                                 (void *)regs->pc, instruction);
-       }
+       if (!expected)
+               unaligned_fixups_notify(current, instruction, regs);
 
        ret = -EFAULT;
        switch (instruction&0xF000) {
@@ -616,10 +539,10 @@ asmlinkage void do_address_error(struct pt_regs *regs,
 
        if (user_mode(regs)) {
                int si_code = BUS_ADRERR;
+               unsigned int user_action;
 
                local_irq_enable();
-
-               se_user += 1;
+               inc_unaligned_user_access();
 
                set_fs(USER_DS);
                if (copy_from_user(&instruction, (insn_size_t *)(regs->pc & ~1),
@@ -630,16 +553,12 @@ asmlinkage void do_address_error(struct pt_regs *regs,
                set_fs(oldfs);
 
                /* shout about userspace fixups */
-               if (se_usermode & 1)
-                       printk(KERN_NOTICE "Unaligned userspace access "
-                              "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
-                              current->comm, current->pid, (void *)regs->pc,
-                              instruction);
+               unaligned_fixups_notify(current, instruction, regs);
 
-               if (se_usermode & 2)
+               user_action = unaligned_user_action();
+               if (user_action & UM_FIXUP)
                        goto fixup;
-
-               if (se_usermode & 4)
+               if (user_action & UM_SIGNAL)
                        goto uspace_segv;
                else {
                        /* ignore */
@@ -659,7 +578,7 @@ fixup:
                                              &user_mem_access, 0);
                set_fs(oldfs);
 
-               if (tmp==0)
+               if (tmp == 0)
                        return; /* sorted */
 uspace_segv:
                printk(KERN_NOTICE "Sending SIGBUS to \"%s\" due to unaligned "
@@ -672,7 +591,7 @@ uspace_segv:
                info.si_addr = (void __user *)address;
                force_sig_info(SIGBUS, &info, current);
        } else {
-               se_sys += 1;
+               inc_unaligned_kernel_access();
 
                if (regs->pc & 1)
                        die("unaligned program counter", regs, error_code);
@@ -687,11 +606,7 @@ uspace_segv:
                        die("insn faulting in do_address_error", regs, 0);
                }
 
-               if (se_kernmode_warn)
-                       printk(KERN_NOTICE "Unaligned kernel access "
-                              "on behalf of \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
-                              current->comm, current->pid, (void *)regs->pc,
-                              instruction);
+               unaligned_fixups_notify(current, instruction, regs);
 
                handle_unaligned_access(instruction, regs,
                                        &user_mem_access, 0);
@@ -876,35 +791,10 @@ asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
        die_if_kernel("exception", regs, ex);
 }
 
-#if defined(CONFIG_SH_STANDARD_BIOS)
-void *gdb_vbr_vector;
-
-static inline void __init gdb_vbr_init(void)
-{
-       register unsigned long vbr;
-
-       /*
-        * Read the old value of the VBR register to initialise
-        * the vector through which debug and BIOS traps are
-        * delegated by the Linux trap handler.
-        */
-       asm volatile("stc vbr, %0" : "=r" (vbr));
-
-       gdb_vbr_vector = (void *)(vbr + 0x100);
-       printk("Setting GDB trap vector to 0x%08lx\n",
-              (unsigned long)gdb_vbr_vector);
-}
-#endif
-
 void __cpuinit per_cpu_trap_init(void)
 {
        extern void *vbr_base;
 
-#ifdef CONFIG_SH_STANDARD_BIOS
-       if (raw_smp_processor_id() == 0)
-               gdb_vbr_init();
-#endif
-
        /* NOTE: The VBR value should be at P1
           (or P2, virtural "fixed" address space).
           It's definitely should not in physical address.  */
@@ -956,9 +846,12 @@ void __init trap_init(void)
 #endif
 
 #ifdef TRAP_UBC
-       set_exception_table_vec(TRAP_UBC, break_point_trap);
+       set_exception_table_vec(TRAP_UBC, breakpoint_trap_handler);
 #endif
 
+       /* Save off the BIOS VBR, if there is one */
+       sh_bios_vbr_init();
+
        /* Setup VBR for boot cpu */
        per_cpu_trap_init();
 }
@@ -985,34 +878,3 @@ void dump_stack(void)
        show_stack(NULL, NULL);
 }
 EXPORT_SYMBOL(dump_stack);
-
-#ifdef CONFIG_PROC_FS
-/*
- * This needs to be done after sysctl_init, otherwise sys/ will be
- * overwritten.  Actually, this shouldn't be in sys/ at all since
- * it isn't a sysctl, and it doesn't contain sysctl information.
- * We now locate it in /proc/cpu/alignment instead.
- */
-static int __init alignment_init(void)
-{
-       struct proc_dir_entry *dir, *res;
-
-       dir = proc_mkdir("cpu", NULL);
-       if (!dir)
-               return -ENOMEM;
-
-       res = proc_create_data("alignment", S_IWUSR | S_IRUGO, dir,
-                              &alignment_proc_fops, &se_usermode);
-       if (!res)
-               return -ENOMEM;
-
-        res = proc_create_data("kernel_alignment", S_IWUSR | S_IRUGO, dir,
-                              &alignment_proc_fops, &se_kernmode_warn);
-        if (!res)
-                return -ENOMEM;
-
-       return 0;
-}
-
-fs_initcall(alignment_init);
-#endif
index d6c15ca..1fcdb12 100644 (file)
@@ -471,10 +471,10 @@ static int fpu_emulate(u16 code, struct sh_fpu_soft_struct *fregs, struct pt_reg
  *     denormal_to_double - Given denormalized float number,
  *                          store double float
  *
- *     @fpu: Pointer to sh_fpu_hard structure
+ *     @fpu: Pointer to sh_fpu_soft structure
  *     @n: Index to FP register
  */
-static void denormal_to_double(struct sh_fpu_hard_struct *fpu, int n)
+static void denormal_to_double(struct sh_fpu_soft_struct *fpu, int n)
 {
        unsigned long du, dl;
        unsigned long x = fpu->fpul;
@@ -552,11 +552,11 @@ static int ieee_fpe_handler(struct pt_regs *regs)
        if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */
                struct task_struct *tsk = current;
 
-               if ((tsk->thread.fpu.hard.fpscr & (1 << 17))) {
+               if ((tsk->thread.xstate->softfpu.fpscr & (1 << 17))) {
                        /* FPU error */
-                       denormal_to_double (&tsk->thread.fpu.hard,
+                       denormal_to_double (&tsk->thread.xstate->softfpu,
                                            (finsn >> 8) & 0xf);
-                       tsk->thread.fpu.hard.fpscr &=
+                       tsk->thread.xstate->softfpu.fpscr &=
                                ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
                        task_thread_info(tsk)->status |= TS_USEDFPU;
                } else {
@@ -617,7 +617,7 @@ static void fpu_init(struct sh_fpu_soft_struct *fpu)
 int do_fpu_inst(unsigned short inst, struct pt_regs *regs)
 {
        struct task_struct *tsk = current;
-       struct sh_fpu_soft_struct *fpu = &(tsk->thread.fpu.soft);
+       struct sh_fpu_soft_struct *fpu = &(tsk->thread.xstate->softfpu);
 
        if (!(task_thread_info(tsk)->status & TS_USEDFPU)) {
                /* initialize once. */
index 986a71b..358c860 100644 (file)
@@ -189,13 +189,31 @@ config ARCH_MEMORY_PROBE
        depends on MEMORY_HOTPLUG
 
 choice
+       prompt "Page table layout"
+       default PGTABLE_LEVELS_3 if X2TLB
+       default PGTABLE_LEVELS_2
+
+config PGTABLE_LEVELS_2
+       bool "2 Levels"
+       help
+         This is the default page table layout for all SuperH CPUs.
+
+config PGTABLE_LEVELS_3
+       bool "3 Levels"
+       depends on X2TLB
+       help
+         This enables a 3 level page table structure.
+
+endchoice
+
+choice
        prompt "Kernel page size"
        default PAGE_SIZE_8KB if X2TLB
        default PAGE_SIZE_4KB
 
 config PAGE_SIZE_4KB
        bool "4kB"
-       depends on !MMU || !X2TLB
+       depends on !MMU || !X2TLB || PGTABLE_LEVELS_3
        help
          This is the default page size used by all SuperH CPUs.
 
index 8a70535..9fa11d6 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the Linux SuperH-specific parts of the memory manager.
 #
 
-obj-y                  := cache.o init.o consistent.o mmap.o
+obj-y                  := alignment.o cache.o init.o consistent.o mmap.o
 
 cacheops-$(CONFIG_CPU_SH2)             := cache-sh2.o
 cacheops-$(CONFIG_CPU_SH2A)            := cache-sh2a.o
@@ -15,7 +15,7 @@ obj-y                 += $(cacheops-y)
 
 mmu-y                  := nommu.o extable_32.o
 mmu-$(CONFIG_MMU)      := extable_$(BITS).o fault_$(BITS).o \
-                          ioremap_$(BITS).o kmap.o tlbflush_$(BITS).o
+                          ioremap_$(BITS).o kmap.o pgtable.o tlbflush_$(BITS).o
 
 obj-y                  += $(mmu-y)
 obj-$(CONFIG_DEBUG_FS) += asids-debugfs.o
diff --git a/arch/sh/mm/alignment.c b/arch/sh/mm/alignment.c
new file mode 100644 (file)
index 0000000..e615151
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Alignment access counters and corresponding user-space interfaces.
+ *
+ * Copyright (C) 2009 ST Microelectronics
+ * Copyright (C) 2009 - 2010 Paul Mundt
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <linux/uaccess.h>
+#include <asm/alignment.h>
+
+static unsigned long se_user;
+static unsigned long se_sys;
+static unsigned long se_half;
+static unsigned long se_word;
+static unsigned long se_dword;
+static unsigned long se_multi;
+/* bitfield: 1: warn 2: fixup 4: signal -> combinations 2|4 && 1|2|4 are not
+   valid! */
+static int se_usermode = UM_WARN | UM_FIXUP;
+/* 0: no warning 1: print a warning message, disabled by default */
+static int se_kernmode_warn;
+
+void inc_unaligned_byte_access(void)
+{
+       se_half++;
+}
+
+void inc_unaligned_word_access(void)
+{
+       se_word++;
+}
+
+void inc_unaligned_dword_access(void)
+{
+       se_dword++;
+}
+
+void inc_unaligned_multi_access(void)
+{
+       se_multi++;
+}
+
+void inc_unaligned_user_access(void)
+{
+       se_user++;
+}
+
+void inc_unaligned_kernel_access(void)
+{
+       se_sys++;
+}
+
+unsigned int unaligned_user_action(void)
+{
+       return se_usermode;
+}
+
+void unaligned_fixups_notify(struct task_struct *tsk, insn_size_t insn,
+                            struct pt_regs *regs)
+{
+       if (user_mode(regs) && (se_usermode & UM_WARN) && printk_ratelimit())
+               pr_notice("Fixing up unaligned userspace access "
+                         "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
+                         tsk->comm, task_pid_nr(tsk),
+                         (void *)regs->pc, insn);
+       else if (se_kernmode_warn && printk_ratelimit())
+               pr_notice("Fixing up unaligned kernel access "
+                         "in \"%s\" pid=%d pc=0x%p ins=0x%04hx\n",
+                         tsk->comm, task_pid_nr(tsk),
+                         (void *)regs->pc, insn);
+}
+
+static const char *se_usermode_action[] = {
+       "ignored",
+       "warn",
+       "fixup",
+       "fixup+warn",
+       "signal",
+       "signal+warn"
+};
+
+static int alignment_proc_show(struct seq_file *m, void *v)
+{
+       seq_printf(m, "User:\t\t%lu\n", se_user);
+       seq_printf(m, "System:\t\t%lu\n", se_sys);
+       seq_printf(m, "Half:\t\t%lu\n", se_half);
+       seq_printf(m, "Word:\t\t%lu\n", se_word);
+       seq_printf(m, "DWord:\t\t%lu\n", se_dword);
+       seq_printf(m, "Multi:\t\t%lu\n", se_multi);
+       seq_printf(m, "User faults:\t%i (%s)\n", se_usermode,
+                       se_usermode_action[se_usermode]);
+       seq_printf(m, "Kernel faults:\t%i (fixup%s)\n", se_kernmode_warn,
+                       se_kernmode_warn ? "+warn" : "");
+       return 0;
+}
+
+static int alignment_proc_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, alignment_proc_show, NULL);
+}
+
+static ssize_t alignment_proc_write(struct file *file,
+               const char __user *buffer, size_t count, loff_t *pos)
+{
+       int *data = PDE(file->f_path.dentry->d_inode)->data;
+       char mode;
+
+       if (count > 0) {
+               if (get_user(mode, buffer))
+                       return -EFAULT;
+               if (mode >= '0' && mode <= '5')
+                       *data = mode - '0';
+       }
+       return count;
+}
+
+static const struct file_operations alignment_proc_fops = {
+       .owner          = THIS_MODULE,
+       .open           = alignment_proc_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+       .write          = alignment_proc_write,
+};
+
+/*
+ * This needs to be done after sysctl_init, otherwise sys/ will be
+ * overwritten.  Actually, this shouldn't be in sys/ at all since
+ * it isn't a sysctl, and it doesn't contain sysctl information.
+ * We now locate it in /proc/cpu/alignment instead.
+ */
+static int __init alignment_init(void)
+{
+       struct proc_dir_entry *dir, *res;
+
+       dir = proc_mkdir("cpu", NULL);
+       if (!dir)
+               return -ENOMEM;
+
+       res = proc_create_data("alignment", S_IWUSR | S_IRUGO, dir,
+                              &alignment_proc_fops, &se_usermode);
+       if (!res)
+               return -ENOMEM;
+
+        res = proc_create_data("kernel_alignment", S_IWUSR | S_IRUGO, dir,
+                              &alignment_proc_fops, &se_kernmode_warn);
+        if (!res)
+                return -ENOMEM;
+
+       return 0;
+}
+fs_initcall(alignment_init);
index 560ddb6..a2301da 100644 (file)
@@ -109,6 +109,7 @@ static inline void flush_cache_one(unsigned long start, unsigned long phys)
 static void sh4_flush_dcache_page(void *arg)
 {
        struct page *page = arg;
+       unsigned long addr = (unsigned long)page_address(page);
 #ifndef CONFIG_SMP
        struct address_space *mapping = page_mapping(page);
 
@@ -116,16 +117,8 @@ static void sh4_flush_dcache_page(void *arg)
                set_bit(PG_dcache_dirty, &page->flags);
        else
 #endif
-       {
-               unsigned long phys = page_to_phys(page);
-               unsigned long addr = CACHE_OC_ADDRESS_ARRAY;
-               int i, n;
-
-               /* Loop all the D-cache */
-               n = boot_cpu_data.dcache.n_aliases;
-               for (i = 0; i < n; i++, addr += PAGE_SIZE)
-                       flush_cache_one(addr, phys);
-       }
+               flush_cache_one(CACHE_OC_ADDRESS_ARRAY |
+                               (addr & shm_align_mask), page_to_phys(page));
 
        wmb();
 }
index 4753010..28e2283 100644 (file)
@@ -53,6 +53,9 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address)
        if (!pud_present(*pud_k))
                return NULL;
 
+       if (!pud_present(*pud))
+           set_pud(pud, *pud_k);
+
        pmd = pmd_offset(pud, address);
        pmd_k = pmd_offset(pud_k, address);
        if (!pmd_present(*pmd_k))
index 432acd0..d5fb014 100644 (file)
@@ -120,7 +120,13 @@ void __init page_table_range_init(unsigned long start, unsigned long end,
        for ( ; (i < PTRS_PER_PGD) && (vaddr != end); pgd++, i++) {
                pud = (pud_t *)pgd;
                for ( ; (j < PTRS_PER_PUD) && (vaddr != end); pud++, j++) {
+#ifdef __PAGETABLE_PMD_FOLDED
                        pmd = (pmd_t *)pud;
+#else
+                       pmd = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE);
+                       pud_populate(&init_mm, pud, pmd);
+                       pmd += k;
+#endif
                        for (; (k < PTRS_PER_PMD) && (vaddr != end); pmd++, k++) {
                                if (pmd_none(*pmd)) {
                                        pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE);
@@ -277,35 +283,6 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 }
 #endif
 
-#if THREAD_SHIFT < PAGE_SHIFT
-static struct kmem_cache *thread_info_cache;
-
-struct thread_info *alloc_thread_info(struct task_struct *tsk)
-{
-       struct thread_info *ti;
-
-       ti = kmem_cache_alloc(thread_info_cache, GFP_KERNEL);
-       if (unlikely(ti == NULL))
-               return NULL;
-#ifdef CONFIG_DEBUG_STACK_USAGE
-       memset(ti, 0, THREAD_SIZE);
-#endif
-       return ti;
-}
-
-void free_thread_info(struct thread_info *ti)
-{
-       kmem_cache_free(thread_info_cache, ti);
-}
-
-void thread_info_cache_init(void)
-{
-       thread_info_cache = kmem_cache_create("thread_info", THREAD_SIZE,
-                                             THREAD_SIZE, 0, NULL);
-       BUG_ON(thread_info_cache == NULL);
-}
-#endif /* THREAD_SHIFT < PAGE_SHIFT */
-
 #ifdef CONFIG_MEMORY_HOTPLUG
 int arch_add_memory(int nid, u64 start, u64 size)
 {
index ac16c05..7694f50 100644 (file)
@@ -94,3 +94,7 @@ void __init page_table_range_init(unsigned long start, unsigned long end,
 void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t prot)
 {
 }
+
+void pgtable_cache_init(void)
+{
+}
diff --git a/arch/sh/mm/pgtable.c b/arch/sh/mm/pgtable.c
new file mode 100644 (file)
index 0000000..e1bc548
--- /dev/null
@@ -0,0 +1,57 @@
+#include <linux/mm.h>
+
+#define PGALLOC_GFP GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO
+
+static struct kmem_cache *pgd_cachep;
+
+#ifdef CONFIG_PGTABLE_LEVELS_3
+static struct kmem_cache *pmd_cachep;
+#endif
+
+void pgd_ctor(void *x)
+{
+       pgd_t *pgd = x;
+
+       memcpy(pgd + USER_PTRS_PER_PGD,
+              swapper_pg_dir + USER_PTRS_PER_PGD,
+              (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+}
+
+void pgtable_cache_init(void)
+{
+       pgd_cachep = kmem_cache_create("pgd_cache",
+                                      PTRS_PER_PGD * (1<<PTE_MAGNITUDE),
+                                      PAGE_SIZE, SLAB_PANIC, pgd_ctor);
+#ifdef CONFIG_PGTABLE_LEVELS_3
+       pmd_cachep = kmem_cache_create("pmd_cache",
+                                      PTRS_PER_PMD * (1<<PTE_MAGNITUDE),
+                                      PAGE_SIZE, SLAB_PANIC, NULL);
+#endif
+}
+
+pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+       return kmem_cache_alloc(pgd_cachep, PGALLOC_GFP);
+}
+
+void pgd_free(struct mm_struct *mm, pgd_t *pgd)
+{
+       kmem_cache_free(pgd_cachep, pgd);
+}
+
+#ifdef CONFIG_PGTABLE_LEVELS_3
+void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
+{
+       set_pud(pud, __pud((unsigned long)pmd));
+}
+
+pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+       return kmem_cache_alloc(pmd_cachep, PGALLOC_GFP);
+}
+
+void pmd_free(struct mm_struct *mm, pmd_t *pmd)
+{
+       kmem_cache_free(pmd_cachep, pmd);
+}
+#endif /* CONFIG_PGTABLE_LEVELS_3 */
index 17b8947..d34c2b9 100644 (file)
@@ -195,7 +195,7 @@ config BOUNCE
 config NR_QUICK
        int
        depends on QUICKLIST
-       default "2" if SUPERH || AVR32
+       default "2" if AVR32
        default "1"
 
 config VIRT_TO_BUS