diff options
Diffstat (limited to 'arch/sh/include/asm')
154 files changed, 11862 insertions, 0 deletions
diff --git a/arch/sh/include/asm/Kbuild b/arch/sh/include/asm/Kbuild new file mode 100644 index 000000000..654ebb6bd --- /dev/null +++ b/arch/sh/include/asm/Kbuild @@ -0,0 +1,39 @@ + +generic-y += bitsperlong.h +generic-y += cputime.h +generic-y += current.h +generic-y += delay.h +generic-y += div64.h +generic-y += emergency-restart.h +generic-y += errno.h +generic-y += exec.h +generic-y += fcntl.h +generic-y += ioctl.h +generic-y += ipcbuf.h +generic-y += irq_regs.h +generic-y += irq_work.h +generic-y += kvm_para.h +generic-y += local.h +generic-y += local64.h +generic-y += mcs_spinlock.h +generic-y += mman.h +generic-y += msgbuf.h +generic-y += param.h +generic-y += parport.h +generic-y += percpu.h +generic-y += poll.h +generic-y += preempt.h +generic-y += resource.h +generic-y += scatterlist.h +generic-y += sembuf.h +generic-y += serial.h +generic-y += shmbuf.h +generic-y += siginfo.h +generic-y += sizes.h +generic-y += socket.h +generic-y += statfs.h +generic-y += termbits.h +generic-y += termios.h +generic-y += trace_clock.h +generic-y += ucontext.h +generic-y += xor.h diff --git a/arch/sh/include/asm/adc.h b/arch/sh/include/asm/adc.h new file mode 100644 index 000000000..48824c1fa --- /dev/null +++ b/arch/sh/include/asm/adc.h @@ -0,0 +1,13 @@ +#ifndef __ASM_ADC_H +#define __ASM_ADC_H +#ifdef __KERNEL__ +/* + * Copyright (C) 2004 Andriy Skulysh + */ + +#include <cpu/adc.h> + +int adc_single(unsigned int channel); + +#endif /* __KERNEL__ */ +#endif /* __ASM_ADC_H */ diff --git a/arch/sh/include/asm/addrspace.h b/arch/sh/include/asm/addrspace.h new file mode 100644 index 000000000..3d1ae2bfa --- /dev/null +++ b/arch/sh/include/asm/addrspace.h @@ -0,0 +1,69 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999 by Kaz Kojima + * + * Defitions for the address spaces of the SH CPUs. + */ +#ifndef __ASM_SH_ADDRSPACE_H +#define __ASM_SH_ADDRSPACE_H + +#ifdef __KERNEL__ + +#include <cpu/addrspace.h> + +/* If this CPU supports segmentation, hook up the helpers */ +#ifdef P1SEG + +/* + [ P0/U0 (virtual) ] 0x00000000 <------ User space + [ P1 (fixed) cached ] 0x80000000 <------ Kernel space + [ P2 (fixed) non-cachable] 0xA0000000 <------ Physical access + [ P3 (virtual) cached] 0xC0000000 <------ vmalloced area + [ P4 control ] 0xE0000000 + */ + +/* Returns the privileged segment base of a given address */ +#define PXSEG(a) (((unsigned long)(a)) & 0xe0000000) + +#ifdef CONFIG_29BIT +/* + * Map an address to a certain privileged segment + */ +#define P1SEGADDR(a) \ + ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P1SEG)) +#define P2SEGADDR(a) \ + ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P2SEG)) +#define P3SEGADDR(a) \ + ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P3SEG)) +#define P4SEGADDR(a) \ + ((__typeof__(a))(((unsigned long)(a) & 0x1fffffff) | P4SEG)) +#else +/* + * These will never work in 32-bit, don't even bother. + */ +#define P1SEGADDR(a) ({ (void)(a); BUG(); NULL; }) +#define P2SEGADDR(a) ({ (void)(a); BUG(); NULL; }) +#define P3SEGADDR(a) ({ (void)(a); BUG(); NULL; }) +#define P4SEGADDR(a) ({ (void)(a); BUG(); NULL; }) +#endif +#endif /* P1SEG */ + +/* Check if an address can be reached in 29 bits */ +#define IS_29BIT(a) (((unsigned long)(a)) < 0x20000000) + +#ifdef CONFIG_SH_STORE_QUEUES +/* + * This is a special case for the SH-4 store queues, as pages for this + * space still need to be faulted in before it's possible to flush the + * store queue cache for writeout to the remapped region. + */ +#define P3_ADDR_MAX (P4SEG_STORE_QUE + 0x04000000) +#else +#define P3_ADDR_MAX P4SEG +#endif + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_ADDRSPACE_H */ diff --git a/arch/sh/include/asm/alignment.h b/arch/sh/include/asm/alignment.h new file mode 100644 index 000000000..b12efecf5 --- /dev/null +++ b/arch/sh/include/asm/alignment.h @@ -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 */ diff --git a/arch/sh/include/asm/asm-offsets.h b/arch/sh/include/asm/asm-offsets.h new file mode 100644 index 000000000..d370ee36a --- /dev/null +++ b/arch/sh/include/asm/asm-offsets.h @@ -0,0 +1 @@ +#include <generated/asm-offsets.h> diff --git a/arch/sh/include/asm/atomic-grb.h b/arch/sh/include/asm/atomic-grb.h new file mode 100644 index 000000000..97a5fda83 --- /dev/null +++ b/arch/sh/include/asm/atomic-grb.h @@ -0,0 +1,94 @@ +#ifndef __ASM_SH_ATOMIC_GRB_H +#define __ASM_SH_ATOMIC_GRB_H + +#define ATOMIC_OP(op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + int tmp; \ + \ + __asm__ __volatile__ ( \ + " .align 2 \n\t" \ + " mova 1f, r0 \n\t" /* r0 = end point */ \ + " mov r15, r1 \n\t" /* r1 = saved sp */ \ + " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ \ + " mov.l @%1, %0 \n\t" /* load old value */ \ + " " #op " %2, %0 \n\t" /* $op */ \ + " mov.l %0, @%1 \n\t" /* store new value */ \ + "1: mov r1, r15 \n\t" /* LOGOUT */ \ + : "=&r" (tmp), \ + "+r" (v) \ + : "r" (i) \ + : "memory" , "r0", "r1"); \ +} \ + +#define ATOMIC_OP_RETURN(op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + int tmp; \ + \ + __asm__ __volatile__ ( \ + " .align 2 \n\t" \ + " mova 1f, r0 \n\t" /* r0 = end point */ \ + " mov r15, r1 \n\t" /* r1 = saved sp */ \ + " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ \ + " mov.l @%1, %0 \n\t" /* load old value */ \ + " " #op " %2, %0 \n\t" /* $op */ \ + " mov.l %0, @%1 \n\t" /* store new value */ \ + "1: mov r1, r15 \n\t" /* LOGOUT */ \ + : "=&r" (tmp), \ + "+r" (v) \ + : "r" (i) \ + : "memory" , "r0", "r1"); \ + \ + return tmp; \ +} + +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) + +ATOMIC_OPS(add) +ATOMIC_OPS(sub) + +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP + +static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + int tmp; + unsigned int _mask = ~mask; + + __asm__ __volatile__ ( + " .align 2 \n\t" + " mova 1f, r0 \n\t" /* r0 = end point */ + " mov r15, r1 \n\t" /* r1 = saved sp */ + " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ + " mov.l @%1, %0 \n\t" /* load old value */ + " and %2, %0 \n\t" /* add */ + " mov.l %0, @%1 \n\t" /* store new value */ + "1: mov r1, r15 \n\t" /* LOGOUT */ + : "=&r" (tmp), + "+r" (v) + : "r" (_mask) + : "memory" , "r0", "r1"); +} + +static inline void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + int tmp; + + __asm__ __volatile__ ( + " .align 2 \n\t" + " mova 1f, r0 \n\t" /* r0 = end point */ + " mov r15, r1 \n\t" /* r1 = saved sp */ + " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ + " mov.l @%1, %0 \n\t" /* load old value */ + " or %2, %0 \n\t" /* or */ + " mov.l %0, @%1 \n\t" /* store new value */ + "1: mov r1, r15 \n\t" /* LOGOUT */ + : "=&r" (tmp), + "+r" (v) + : "r" (mask) + : "memory" , "r0", "r1"); +} + +#endif /* __ASM_SH_ATOMIC_GRB_H */ diff --git a/arch/sh/include/asm/atomic-irq.h b/arch/sh/include/asm/atomic-irq.h new file mode 100644 index 000000000..61d107523 --- /dev/null +++ b/arch/sh/include/asm/atomic-irq.h @@ -0,0 +1,63 @@ +#ifndef __ASM_SH_ATOMIC_IRQ_H +#define __ASM_SH_ATOMIC_IRQ_H + +#include <linux/irqflags.h> + +/* + * To get proper branch prediction for the main line, we must branch + * forward to code at the end of this object's .text section, then + * branch back to restart the operation. + */ + +#define ATOMIC_OP(op, c_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + \ + raw_local_irq_save(flags); \ + v->counter c_op i; \ + raw_local_irq_restore(flags); \ +} + +#define ATOMIC_OP_RETURN(op, c_op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + unsigned long temp, flags; \ + \ + raw_local_irq_save(flags); \ + temp = v->counter; \ + temp c_op i; \ + v->counter = temp; \ + raw_local_irq_restore(flags); \ + \ + return temp; \ +} + +#define ATOMIC_OPS(op, c_op) ATOMIC_OP(op, c_op) ATOMIC_OP_RETURN(op, c_op) + +ATOMIC_OPS(add, +=) +ATOMIC_OPS(sub, -=) + +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP + +static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + unsigned long flags; + + raw_local_irq_save(flags); + v->counter &= ~mask; + raw_local_irq_restore(flags); +} + +static inline void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + unsigned long flags; + + raw_local_irq_save(flags); + v->counter |= mask; + raw_local_irq_restore(flags); +} + +#endif /* __ASM_SH_ATOMIC_IRQ_H */ diff --git a/arch/sh/include/asm/atomic-llsc.h b/arch/sh/include/asm/atomic-llsc.h new file mode 100644 index 000000000..8575dccb9 --- /dev/null +++ b/arch/sh/include/asm/atomic-llsc.h @@ -0,0 +1,88 @@ +#ifndef __ASM_SH_ATOMIC_LLSC_H +#define __ASM_SH_ATOMIC_LLSC_H + +/* + * SH-4A note: + * + * We basically get atomic_xxx_return() for free compared with + * atomic_xxx(). movli.l/movco.l require r0 due to the instruction + * encoding, so the retval is automatically set without having to + * do any special work. + */ +/* + * To get proper branch prediction for the main line, we must branch + * forward to code at the end of this object's .text section, then + * branch back to restart the operation. + */ + +#define ATOMIC_OP(op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + unsigned long tmp; \ + \ + __asm__ __volatile__ ( \ +"1: movli.l @%2, %0 ! atomic_" #op "\n" \ +" " #op " %1, %0 \n" \ +" movco.l %0, @%2 \n" \ +" bf 1b \n" \ + : "=&z" (tmp) \ + : "r" (i), "r" (&v->counter) \ + : "t"); \ +} + +#define ATOMIC_OP_RETURN(op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + unsigned long temp; \ + \ + __asm__ __volatile__ ( \ +"1: movli.l @%2, %0 ! atomic_" #op "_return \n" \ +" " #op " %1, %0 \n" \ +" movco.l %0, @%2 \n" \ +" bf 1b \n" \ +" synco \n" \ + : "=&z" (temp) \ + : "r" (i), "r" (&v->counter) \ + : "t"); \ + \ + return temp; \ +} + +#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) + +ATOMIC_OPS(add) +ATOMIC_OPS(sub) + +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP + +static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + unsigned long tmp; + + __asm__ __volatile__ ( +"1: movli.l @%2, %0 ! atomic_clear_mask \n" +" and %1, %0 \n" +" movco.l %0, @%2 \n" +" bf 1b \n" + : "=&z" (tmp) + : "r" (~mask), "r" (&v->counter) + : "t"); +} + +static inline void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + unsigned long tmp; + + __asm__ __volatile__ ( +"1: movli.l @%2, %0 ! atomic_set_mask \n" +" or %1, %0 \n" +" movco.l %0, @%2 \n" +" bf 1b \n" + : "=&z" (tmp) + : "r" (mask), "r" (&v->counter) + : "t"); +} + +#endif /* __ASM_SH_ATOMIC_LLSC_H */ diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h new file mode 100644 index 000000000..05b9f74ce --- /dev/null +++ b/arch/sh/include/asm/atomic.h @@ -0,0 +1,66 @@ +#ifndef __ASM_SH_ATOMIC_H +#define __ASM_SH_ATOMIC_H + +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc.. + * + */ + +#include <linux/compiler.h> +#include <linux/types.h> +#include <asm/cmpxchg.h> +#include <asm/barrier.h> + +#define ATOMIC_INIT(i) { (i) } + +#define atomic_read(v) ACCESS_ONCE((v)->counter) +#define atomic_set(v,i) ((v)->counter = (i)) + +#if defined(CONFIG_GUSA_RB) +#include <asm/atomic-grb.h> +#elif defined(CONFIG_CPU_SH4A) +#include <asm/atomic-llsc.h> +#else +#include <asm/atomic-irq.h> +#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(v) atomic_add(1, (v)) +#define atomic_dec(v) atomic_sub(1, (v)) + +#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 adds @a to @v, so long as it was not @u. + * Returns the old value of @v. + */ +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; +} + +#endif /* __ASM_SH_ATOMIC_H */ diff --git a/arch/sh/include/asm/barrier.h b/arch/sh/include/asm/barrier.h new file mode 100644 index 000000000..43715308b --- /dev/null +++ b/arch/sh/include/asm/barrier.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima + * Copyright (C) 2002 Paul Mundt + */ +#ifndef __ASM_SH_BARRIER_H +#define __ASM_SH_BARRIER_H + +#if defined(CONFIG_CPU_SH4A) || defined(CONFIG_CPU_SH5) +#include <asm/cache_insns.h> +#endif + +/* + * A brief note on ctrl_barrier(), the control register write barrier. + * + * Legacy SH cores typically require a sequence of 8 nops after + * modification of a control register in order for the changes to take + * effect. On newer cores (like the sh4a and sh5) this is accomplished + * with icbi. + * + * Also note that on sh4a in the icbi case we can forego a synco for the + * write barrier, as it's not necessary for control registers. + * + * Historically we have only done this type of barrier for the MMUCR, but + * it's also necessary for the CCR, so we make it generic here instead. + */ +#if defined(CONFIG_CPU_SH4A) || defined(CONFIG_CPU_SH5) +#define mb() __asm__ __volatile__ ("synco": : :"memory") +#define rmb() mb() +#define wmb() mb() +#define ctrl_barrier() __icbi(PAGE_OFFSET) +#else +#define ctrl_barrier() __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop") +#endif + +#define set_mb(var, value) do { (void)xchg(&var, value); } while (0) + +#include <asm-generic/barrier.h> + +#endif /* __ASM_SH_BARRIER_H */ diff --git a/arch/sh/include/asm/bitops-grb.h b/arch/sh/include/asm/bitops-grb.h new file mode 100644 index 000000000..e73af33ac --- /dev/null +++ b/arch/sh/include/asm/bitops-grb.h @@ -0,0 +1,172 @@ +#ifndef __ASM_SH_BITOPS_GRB_H +#define __ASM_SH_BITOPS_GRB_H + +static inline void set_bit(int nr, volatile void * addr) +{ + int mask; + volatile unsigned int *a = addr; + unsigned long tmp; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + + __asm__ __volatile__ ( + " .align 2 \n\t" + " mova 1f, r0 \n\t" /* r0 = end point */ + " mov r15, r1 \n\t" /* r1 = saved sp */ + " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ + " mov.l @%1, %0 \n\t" /* load old value */ + " or %2, %0 \n\t" /* or */ + " mov.l %0, @%1 \n\t" /* store new value */ + "1: mov r1, r15 \n\t" /* LOGOUT */ + : "=&r" (tmp), + "+r" (a) + : "r" (mask) + : "memory" , "r0", "r1"); +} + +static inline void clear_bit(int nr, volatile void * addr) +{ + int mask; + volatile unsigned int *a = addr; + unsigned long tmp; + + a += nr >> 5; + mask = ~(1 << (nr & 0x1f)); + __asm__ __volatile__ ( + " .align 2 \n\t" + " mova 1f, r0 \n\t" /* r0 = end point */ + " mov r15, r1 \n\t" /* r1 = saved sp */ + " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ + " mov.l @%1, %0 \n\t" /* load old value */ + " and %2, %0 \n\t" /* and */ + " mov.l %0, @%1 \n\t" /* store new value */ + "1: mov r1, r15 \n\t" /* LOGOUT */ + : "=&r" (tmp), + "+r" (a) + : "r" (mask) + : "memory" , "r0", "r1"); +} + +static inline void change_bit(int nr, volatile void * addr) +{ + int mask; + volatile unsigned int *a = addr; + unsigned long tmp; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + __asm__ __volatile__ ( + " .align 2 \n\t" + " mova 1f, r0 \n\t" /* r0 = end point */ + " mov r15, r1 \n\t" /* r1 = saved sp */ + " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ + " mov.l @%1, %0 \n\t" /* load old value */ + " xor %2, %0 \n\t" /* xor */ + " mov.l %0, @%1 \n\t" /* store new value */ + "1: mov r1, r15 \n\t" /* LOGOUT */ + : "=&r" (tmp), + "+r" (a) + : "r" (mask) + : "memory" , "r0", "r1"); +} + +static inline int test_and_set_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + unsigned long tmp; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + + __asm__ __volatile__ ( + " .align 2 \n\t" + " mova 1f, r0 \n\t" /* r0 = end point */ + " mov r15, r1 \n\t" /* r1 = saved sp */ + " mov #-14, r15 \n\t" /* LOGIN: r15 = size */ + " mov.l @%2, %0 \n\t" /* load old value */ + " mov %0, %1 \n\t" + " tst %1, %3 \n\t" /* T = ((*a & mask) == 0) */ + " mov #-1, %1 \n\t" /* retvat = -1 */ + " negc %1, %1 \n\t" /* retval = (mask & *a) != 0 */ + " or %3, %0 \n\t" + " mov.l %0, @%2 \n\t" /* store new value */ + "1: mov r1, r15 \n\t" /* LOGOUT */ + : "=&r" (tmp), + "=&r" (retval), + "+r" (a) + : "r" (mask) + : "memory" , "r0", "r1" ,"t"); + + return retval; +} + +static inline int test_and_clear_bit(int nr, volatile void * addr) +{ + int mask, retval,not_mask; + volatile unsigned int *a = addr; + unsigned long tmp; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + + not_mask = ~mask; + + __asm__ __volatile__ ( + " .align 2 \n\t" + " mova 1f, r0 \n\t" /* r0 = end point */ + " mov r15, r1 \n\t" /* r1 = saved sp */ + " mov #-14, r15 \n\t" /* LOGIN */ + " mov.l @%2, %0 \n\t" /* load old value */ + " mov %0, %1 \n\t" /* %1 = *a */ + " tst %1, %3 \n\t" /* T = ((*a & mask) == 0) */ + " mov #-1, %1 \n\t" /* retvat = -1 */ + " negc %1, %1 \n\t" /* retval = (mask & *a) != 0 */ + " and %4, %0 \n\t" + " mov.l %0, @%2 \n\t" /* store new value */ + "1: mov r1, r15 \n\t" /* LOGOUT */ + : "=&r" (tmp), + "=&r" (retval), + "+r" (a) + : "r" (mask), + "r" (not_mask) + : "memory" , "r0", "r1", "t"); + + return retval; +} + +static inline int test_and_change_bit(int nr, volatile void * addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + unsigned long tmp; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + + __asm__ __volatile__ ( + " .align 2 \n\t" + " mova 1f, r0 \n\t" /* r0 = end point */ + " mov r15, r1 \n\t" /* r1 = saved sp */ + " mov #-14, r15 \n\t" /* LOGIN */ + " mov.l @%2, %0 \n\t" /* load old value */ + " mov %0, %1 \n\t" /* %1 = *a */ + " tst %1, %3 \n\t" /* T = ((*a & mask) == 0) */ + " mov #-1, %1 \n\t" /* retvat = -1 */ + " negc %1, %1 \n\t" /* retval = (mask & *a) != 0 */ + " xor %3, %0 \n\t" + " mov.l %0, @%2 \n\t" /* store new value */ + "1: mov r1, r15 \n\t" /* LOGOUT */ + : "=&r" (tmp), + "=&r" (retval), + "+r" (a) + : "r" (mask) + : "memory" , "r0", "r1", "t"); + + return retval; +} + +#include <asm-generic/bitops/non-atomic.h> + +#endif /* __ASM_SH_BITOPS_GRB_H */ diff --git a/arch/sh/include/asm/bitops-llsc.h b/arch/sh/include/asm/bitops-llsc.h new file mode 100644 index 000000000..d8328be06 --- /dev/null +++ b/arch/sh/include/asm/bitops-llsc.h @@ -0,0 +1,146 @@ +#ifndef __ASM_SH_BITOPS_LLSC_H +#define __ASM_SH_BITOPS_LLSC_H + +static inline void set_bit(int nr, volatile void *addr) +{ + int mask; + volatile unsigned int *a = addr; + unsigned long tmp; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%1, %0 ! set_bit \n\t" + "or %2, %0 \n\t" + "movco.l %0, @%1 \n\t" + "bf 1b \n\t" + : "=&z" (tmp) + : "r" (a), "r" (mask) + : "t", "memory" + ); +} + +static inline void clear_bit(int nr, volatile void *addr) +{ + int mask; + volatile unsigned int *a = addr; + unsigned long tmp; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%1, %0 ! clear_bit \n\t" + "and %2, %0 \n\t" + "movco.l %0, @%1 \n\t" + "bf 1b \n\t" + : "=&z" (tmp) + : "r" (a), "r" (~mask) + : "t", "memory" + ); +} + +static inline void change_bit(int nr, volatile void *addr) +{ + int mask; + volatile unsigned int *a = addr; + unsigned long tmp; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%1, %0 ! change_bit \n\t" + "xor %2, %0 \n\t" + "movco.l %0, @%1 \n\t" + "bf 1b \n\t" + : "=&z" (tmp) + : "r" (a), "r" (mask) + : "t", "memory" + ); +} + +static inline int test_and_set_bit(int nr, volatile void *addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + unsigned long tmp; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%2, %0 ! test_and_set_bit \n\t" + "mov %0, %1 \n\t" + "or %3, %0 \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "and %3, %1 \n\t" + : "=&z" (tmp), "=&r" (retval) + : "r" (a), "r" (mask) + : "t", "memory" + ); + + return retval != 0; +} + +static inline int test_and_clear_bit(int nr, volatile void *addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + unsigned long tmp; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%2, %0 ! test_and_clear_bit \n\t" + "mov %0, %1 \n\t" + "and %4, %0 \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "and %3, %1 \n\t" + "synco \n\t" + : "=&z" (tmp), "=&r" (retval) + : "r" (a), "r" (mask), "r" (~mask) + : "t", "memory" + ); + + return retval != 0; +} + +static inline int test_and_change_bit(int nr, volatile void *addr) +{ + int mask, retval; + volatile unsigned int *a = addr; + unsigned long tmp; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%2, %0 ! test_and_change_bit \n\t" + "mov %0, %1 \n\t" + "xor %3, %0 \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "and %3, %1 \n\t" + "synco \n\t" + : "=&z" (tmp), "=&r" (retval) + : "r" (a), "r" (mask) + : "t", "memory" + ); + + return retval != 0; +} + +#include <asm-generic/bitops/non-atomic.h> + +#endif /* __ASM_SH_BITOPS_LLSC_H */ diff --git a/arch/sh/include/asm/bitops-op32.h b/arch/sh/include/asm/bitops-op32.h new file mode 100644 index 000000000..f0ae7e921 --- /dev/null +++ b/arch/sh/include/asm/bitops-op32.h @@ -0,0 +1,142 @@ +#ifndef __ASM_SH_BITOPS_OP32_H +#define __ASM_SH_BITOPS_OP32_H + +/* + * The bit modifying instructions on SH-2A are only capable of working + * with a 3-bit immediate, which signifies the shift position for the bit + * being worked on. + */ +#if defined(__BIG_ENDIAN) +#define BITOP_LE_SWIZZLE ((BITS_PER_LONG-1) & ~0x7) +#define BYTE_NUMBER(nr) ((nr ^ BITOP_LE_SWIZZLE) / BITS_PER_BYTE) +#define BYTE_OFFSET(nr) ((nr ^ BITOP_LE_SWIZZLE) % BITS_PER_BYTE) +#else +#define BYTE_NUMBER(nr) ((nr) / BITS_PER_BYTE) +#define BYTE_OFFSET(nr) ((nr) % BITS_PER_BYTE) +#endif + +#define IS_IMMEDIATE(nr) (__builtin_constant_p(nr)) + +static inline void __set_bit(int nr, volatile unsigned long *addr) +{ + if (IS_IMMEDIATE(nr)) { + __asm__ __volatile__ ( + "bset.b %1, @(%O2,%0) ! __set_bit\n\t" + : "+r" (addr) + : "i" (BYTE_OFFSET(nr)), "i" (BYTE_NUMBER(nr)) + : "t", "memory" + ); + } else { + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + *p |= mask; + } +} + +static inline void __clear_bit(int nr, volatile unsigned long *addr) +{ + if (IS_IMMEDIATE(nr)) { + __asm__ __volatile__ ( + "bclr.b %1, @(%O2,%0) ! __clear_bit\n\t" + : "+r" (addr) + : "i" (BYTE_OFFSET(nr)), + "i" (BYTE_NUMBER(nr)) + : "t", "memory" + ); + } else { + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + *p &= ~mask; + } +} + +/** + * __change_bit - Toggle a bit in memory + * @nr: the bit to change + * @addr: the address to start counting from + * + * Unlike change_bit(), this function is non-atomic and may be reordered. + * If it's called on the same region of memory simultaneously, the effect + * may be that only one operation succeeds. + */ +static inline void __change_bit(int nr, volatile unsigned long *addr) +{ + if (IS_IMMEDIATE(nr)) { + __asm__ __volatile__ ( + "bxor.b %1, @(%O2,%0) ! __change_bit\n\t" + : "+r" (addr) + : "i" (BYTE_OFFSET(nr)), + "i" (BYTE_NUMBER(nr)) + : "t", "memory" + ); + } else { + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + + *p ^= mask; + } +} + +/** + * __test_and_set_bit - Set a bit and return its old value + * @nr: Bit to set + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long old = *p; + + *p = old | mask; + return (old & mask) != 0; +} + +/** + * __test_and_clear_bit - Clear a bit and return its old value + * @nr: Bit to clear + * @addr: Address to count from + * + * This operation is non-atomic and can be reordered. + * If two examples of this operation race, one can appear to succeed + * but actually fail. You must protect multiple accesses with a lock. + */ +static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long old = *p; + + *p = old & ~mask; + return (old & mask) != 0; +} + +/* WARNING: non atomic and it can be reordered! */ +static inline int __test_and_change_bit(int nr, + volatile unsigned long *addr) +{ + unsigned long mask = BIT_MASK(nr); + unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); + unsigned long old = *p; + + *p = old ^ mask; + return (old & mask) != 0; +} + +/** + * test_bit - Determine whether a bit is set + * @nr: bit number to test + * @addr: Address to start counting from + */ +static inline int test_bit(int nr, const volatile unsigned long *addr) +{ + return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); +} + +#endif /* __ASM_SH_BITOPS_OP32_H */ diff --git a/arch/sh/include/asm/bitops.h b/arch/sh/include/asm/bitops.h new file mode 100644 index 000000000..fc8e652cf --- /dev/null +++ b/arch/sh/include/asm/bitops.h @@ -0,0 +1,99 @@ +#ifndef __ASM_SH_BITOPS_H +#define __ASM_SH_BITOPS_H + +#ifdef __KERNEL__ + +#ifndef _LINUX_BITOPS_H +#error only <linux/bitops.h> can be included directly +#endif + +/* For __swab32 */ +#include <asm/byteorder.h> +#include <asm/barrier.h> + +#ifdef CONFIG_GUSA_RB +#include <asm/bitops-grb.h> +#elif defined(CONFIG_CPU_SH2A) +#include <asm-generic/bitops/atomic.h> +#include <asm/bitops-op32.h> +#elif defined(CONFIG_CPU_SH4A) +#include <asm/bitops-llsc.h> +#else +#include <asm-generic/bitops/atomic.h> +#include <asm-generic/bitops/non-atomic.h> +#endif + +#ifdef CONFIG_SUPERH32 +static inline unsigned long ffz(unsigned long word) +{ + unsigned long result; + + __asm__("1:\n\t" + "shlr %1\n\t" + "bt/s 1b\n\t" + " add #1, %0" + : "=r" (result), "=r" (word) + : "0" (~0L), "1" (word) + : "t"); + return result; +} + +/** + * __ffs - find first bit in word. + * @word: The word to search + * + * Undefined if no bit exists, so code should check against 0 first. + */ +static inline unsigned long __ffs(unsigned long word) +{ + unsigned long result; + + __asm__("1:\n\t" + "shlr %1\n\t" + "bf/s 1b\n\t" + " add #1, %0" + : "=r" (result), "=r" (word) + : "0" (~0L), "1" (word) + : "t"); + return result; +} +#else +static inline unsigned long ffz(unsigned long word) +{ + unsigned long result, __d2, __d3; + + __asm__("gettr tr0, %2\n\t" + "pta $+32, tr0\n\t" + "andi %1, 1, %3\n\t" + "beq %3, r63, tr0\n\t" + "pta $+4, tr0\n" + "0:\n\t" + "shlri.l %1, 1, %1\n\t" + "addi %0, 1, %0\n\t" + "andi %1, 1, %3\n\t" + "beqi %3, 1, tr0\n" + "1:\n\t" + "ptabs %2, tr0\n\t" + : "=r" (result), "=r" (word), "=r" (__d2), "=r" (__d3) + : "0" (0L), "1" (word)); + + return result; +} + +#include <asm-generic/bitops/__ffs.h> +#endif + +#include <asm-generic/bitops/find.h> +#include <asm-generic/bitops/ffs.h> +#include <asm-generic/bitops/hweight.h> +#include <asm-generic/bitops/lock.h> +#include <asm-generic/bitops/sched.h> +#include <asm-generic/bitops/le.h> +#include <asm-generic/bitops/ext2-atomic.h> +#include <asm-generic/bitops/fls.h> +#include <asm-generic/bitops/__fls.h> +#include <asm-generic/bitops/fls64.h> + +#endif /* __KERNEL__ */ + +#endif /* __ASM_SH_BITOPS_H */ diff --git a/arch/sh/include/asm/bl_bit.h b/arch/sh/include/asm/bl_bit.h new file mode 100644 index 000000000..06e4163c6 --- /dev/null +++ b/arch/sh/include/asm/bl_bit.h @@ -0,0 +1,10 @@ +#ifndef __ASM_SH_BL_BIT_H +#define __ASM_SH_BL_BIT_H + +#ifdef CONFIG_SUPERH32 +# include <asm/bl_bit_32.h> +#else +# include <asm/bl_bit_64.h> +#endif + +#endif /* __ASM_SH_BL_BIT_H */ diff --git a/arch/sh/include/asm/bl_bit_32.h b/arch/sh/include/asm/bl_bit_32.h new file mode 100644 index 000000000..fd21eee62 --- /dev/null +++ b/arch/sh/include/asm/bl_bit_32.h @@ -0,0 +1,33 @@ +#ifndef __ASM_SH_BL_BIT_32_H +#define __ASM_SH_BL_BIT_32_H + +static inline void set_bl_bit(void) +{ + unsigned long __dummy0, __dummy1; + + __asm__ __volatile__ ( + "stc sr, %0\n\t" + "or %2, %0\n\t" + "and %3, %0\n\t" + "ldc %0, sr\n\t" + : "=&r" (__dummy0), "=r" (__dummy1) + : "r" (0x10000000), "r" (0xffffff0f) + : "memory" + ); +} + +static inline void clear_bl_bit(void) +{ + unsigned long __dummy0, __dummy1; + + __asm__ __volatile__ ( + "stc sr, %0\n\t" + "and %2, %0\n\t" + "ldc %0, sr\n\t" + : "=&r" (__dummy0), "=r" (__dummy1) + : "1" (~0x10000000) + : "memory" + ); +} + +#endif /* __ASM_SH_BL_BIT_32_H */ diff --git a/arch/sh/include/asm/bl_bit_64.h b/arch/sh/include/asm/bl_bit_64.h new file mode 100644 index 000000000..6cc8711af --- /dev/null +++ b/arch/sh/include/asm/bl_bit_64.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2004 Richard Curnow + * + * 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_BL_BIT_64_H +#define __ASM_SH_BL_BIT_64_H + +#include <asm/processor.h> + +#define SR_BL_LL 0x0000000010000000LL + +static inline void set_bl_bit(void) +{ + unsigned long long __dummy0, __dummy1 = SR_BL_LL; + + __asm__ __volatile__("getcon " __SR ", %0\n\t" + "or %0, %1, %0\n\t" + "putcon %0, " __SR "\n\t" + : "=&r" (__dummy0) + : "r" (__dummy1)); + +} + +static inline void clear_bl_bit(void) +{ + unsigned long long __dummy0, __dummy1 = ~SR_BL_LL; + + __asm__ __volatile__("getcon " __SR ", %0\n\t" + "and %0, %1, %0\n\t" + "putcon %0, " __SR "\n\t" + : "=&r" (__dummy0) + : "r" (__dummy1)); +} + +#endif /* __ASM_SH_BL_BIT_64_H */ diff --git a/arch/sh/include/asm/bug.h b/arch/sh/include/asm/bug.h new file mode 100644 index 000000000..dcf278075 --- /dev/null +++ b/arch/sh/include/asm/bug.h @@ -0,0 +1,119 @@ +#ifndef __ASM_SH_BUG_H +#define __ASM_SH_BUG_H + +#include <linux/linkage.h> + +#define TRAPA_BUG_OPCODE 0xc33e /* trapa #0x3e */ +#define BUGFLAG_UNWINDER (1 << 1) + +#ifdef CONFIG_GENERIC_BUG +#define HAVE_ARCH_BUG +#define HAVE_ARCH_WARN_ON + +/** + * _EMIT_BUG_ENTRY + * %1 - __FILE__ + * %2 - __LINE__ + * %3 - trap type + * %4 - sizeof(struct bug_entry) + * + * The trapa opcode itself sits in %0. + * The %O notation is used to avoid # generation. + * + * The offending file and line are encoded in the __bug_table section. + */ +#ifdef CONFIG_DEBUG_BUGVERBOSE +#define _EMIT_BUG_ENTRY \ + "\t.pushsection __bug_table,\"a\"\n" \ + "2:\t.long 1b, %O1\n" \ + "\t.short %O2, %O3\n" \ + "\t.org 2b+%O4\n" \ + "\t.popsection\n" +#else +#define _EMIT_BUG_ENTRY \ + "\t.pushsection __bug_table,\"a\"\n" \ + "2:\t.long 1b\n" \ + "\t.short %O3\n" \ + "\t.org 2b+%O4\n" \ + "\t.popsection\n" +#endif + +#define BUG() \ +do { \ + __asm__ __volatile__ ( \ + "1:\t.short %O0\n" \ + _EMIT_BUG_ENTRY \ + : \ + : "n" (TRAPA_BUG_OPCODE), \ + "i" (__FILE__), \ + "i" (__LINE__), "i" (0), \ + "i" (sizeof(struct bug_entry))); \ +} while (0) + +#define __WARN_TAINT(taint) \ +do { \ + __asm__ __volatile__ ( \ + "1:\t.short %O0\n" \ + _EMIT_BUG_ENTRY \ + : \ + : "n" (TRAPA_BUG_OPCODE), \ + "i" (__FILE__), \ + "i" (__LINE__), \ + "i" (BUGFLAG_TAINT(taint)), \ + "i" (sizeof(struct bug_entry))); \ +} while (0) + +#define WARN_ON(x) ({ \ + int __ret_warn_on = !!(x); \ + if (__builtin_constant_p(__ret_warn_on)) { \ + if (__ret_warn_on) \ + __WARN(); \ + } else { \ + if (unlikely(__ret_warn_on)) \ + __WARN(); \ + } \ + unlikely(__ret_warn_on); \ +}) + +#define UNWINDER_BUG() \ +do { \ + __asm__ __volatile__ ( \ + "1:\t.short %O0\n" \ + _EMIT_BUG_ENTRY \ + : \ + : "n" (TRAPA_BUG_OPCODE), \ + "i" (__FILE__), \ + "i" (__LINE__), \ + "i" (BUGFLAG_UNWINDER), \ + "i" (sizeof(struct bug_entry))); \ +} while (0) + +#define UNWINDER_BUG_ON(x) ({ \ + int __ret_unwinder_on = !!(x); \ + if (__builtin_constant_p(__ret_unwinder_on)) { \ + if (__ret_unwinder_on) \ + UNWINDER_BUG(); \ + } else { \ + if (unlikely(__ret_unwinder_on)) \ + UNWINDER_BUG(); \ + } \ + unlikely(__ret_unwinder_on); \ +}) + +#else + +#define UNWINDER_BUG BUG +#define UNWINDER_BUG_ON BUG_ON + +#endif /* CONFIG_GENERIC_BUG */ + +#include <asm-generic/bug.h> + +struct pt_regs; + +/* arch/sh/kernel/traps.c */ +extern void die(const char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn)); +extern void die_if_kernel(const char *str, struct pt_regs *regs, long err); +extern void die_if_no_fixup(const char *str, struct pt_regs *regs, long err); + +#endif /* __ASM_SH_BUG_H */ diff --git a/arch/sh/include/asm/bugs.h b/arch/sh/include/asm/bugs.h new file mode 100644 index 000000000..02a19a1c0 --- /dev/null +++ b/arch/sh/include/asm/bugs.h @@ -0,0 +1,77 @@ +#ifndef __ASM_SH_BUGS_H +#define __ASM_SH_BUGS_H + +/* + * This is included by init/main.c to check for architecture-dependent bugs. + * + * Needs: + * void check_bugs(void); + */ + +/* + * I don't know of any Super-H bugs yet. + */ + +#include <asm/processor.h> + +extern void select_idle_routine(void); + +static void __init check_bugs(void) +{ + extern unsigned long loops_per_jiffy; + char *p = &init_utsname()->machine[2]; /* "sh" */ + + select_idle_routine(); + + current_cpu_data.loops_per_jiffy = loops_per_jiffy; + + switch (current_cpu_data.family) { + case CPU_FAMILY_SH2: + *p++ = '2'; + break; + case CPU_FAMILY_SH2A: + *p++ = '2'; + *p++ = 'a'; + break; + case CPU_FAMILY_SH3: + *p++ = '3'; + break; + case CPU_FAMILY_SH4: + *p++ = '4'; + break; + case CPU_FAMILY_SH4A: + *p++ = '4'; + *p++ = 'a'; + break; + case CPU_FAMILY_SH4AL_DSP: + *p++ = '4'; + *p++ = 'a'; + *p++ = 'l'; + *p++ = '-'; + *p++ = 'd'; + *p++ = 's'; + *p++ = 'p'; + break; + case CPU_FAMILY_SH5: + *p++ = '6'; + *p++ = '4'; + break; + case CPU_FAMILY_UNKNOWN: + /* + * Specifically use CPU_FAMILY_UNKNOWN rather than + * default:, so we're able to have the compiler whine + * about unhandled enumerations. + */ + break; + } + + printk("CPU: %s\n", get_cpu_subtype(¤t_cpu_data)); + +#ifndef __LITTLE_ENDIAN__ + /* 'eb' means 'Endian Big' */ + *p++ = 'e'; + *p++ = 'b'; +#endif + *p = '\0'; +} +#endif /* __ASM_SH_BUGS_H */ diff --git a/arch/sh/include/asm/cache.h b/arch/sh/include/asm/cache.h new file mode 100644 index 000000000..ef9e555aa --- /dev/null +++ b/arch/sh/include/asm/cache.h @@ -0,0 +1,47 @@ +/* $Id: cache.h,v 1.6 2004/03/11 18:08:05 lethal Exp $ + * + * include/asm-sh/cache.h + * + * Copyright 1999 (C) Niibe Yutaka + * Copyright 2002, 2003 (C) Paul Mundt + */ +#ifndef __ASM_SH_CACHE_H +#define __ASM_SH_CACHE_H +#ifdef __KERNEL__ + +#include <linux/init.h> +#include <cpu/cache.h> + +#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) + +#define __read_mostly __attribute__((__section__(".data..read_mostly"))) + +#ifndef __ASSEMBLY__ +struct cache_info { + unsigned int ways; /* Number of cache ways */ + unsigned int sets; /* Number of cache sets */ + unsigned int linesz; /* Cache line size (bytes) */ + + unsigned int way_size; /* sets * line size */ + + /* + * way_incr is the address offset for accessing the next way + * in memory mapped cache array ops. + */ + unsigned int way_incr; + unsigned int entry_shift; + unsigned int entry_mask; + + /* + * Compute a mask which selects the address bits which overlap between + * 1. those used to select the cache set during indexing + * 2. those in the physical page number. + */ + unsigned int alias_mask; + unsigned int n_aliases; /* Number of aliases */ + + unsigned long flags; +}; +#endif /* __ASSEMBLY__ */ +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_CACHE_H */ diff --git a/arch/sh/include/asm/cache_insns.h b/arch/sh/include/asm/cache_insns.h new file mode 100644 index 000000000..355cb06b7 --- /dev/null +++ b/arch/sh/include/asm/cache_insns.h @@ -0,0 +1,11 @@ +#ifndef __ASM_SH_CACHE_INSNS_H +#define __ASM_SH_CACHE_INSNS_H + + +#ifdef CONFIG_SUPERH32 +# include <asm/cache_insns_32.h> +#else +# include <asm/cache_insns_64.h> +#endif + +#endif /* __ASM_SH_CACHE_INSNS_H */ diff --git a/arch/sh/include/asm/cache_insns_32.h b/arch/sh/include/asm/cache_insns_32.h new file mode 100644 index 000000000..b92fe5416 --- /dev/null +++ b/arch/sh/include/asm/cache_insns_32.h @@ -0,0 +1,21 @@ +#ifndef __ASM_SH_CACHE_INSNS_32_H +#define __ASM_SH_CACHE_INSNS_32_H + +#include <linux/types.h> + +#if defined(CONFIG_CPU_SH4A) +#define __icbi(addr) __asm__ __volatile__ ( "icbi @%0\n\t" : : "r" (addr)) +#else +#define __icbi(addr) mb() +#endif + +#define __ocbp(addr) __asm__ __volatile__ ( "ocbp @%0\n\t" : : "r" (addr)) +#define __ocbi(addr) __asm__ __volatile__ ( "ocbi @%0\n\t" : : "r" (addr)) +#define __ocbwb(addr) __asm__ __volatile__ ( "ocbwb @%0\n\t" : : "r" (addr)) + +static inline reg_size_t register_align(void *val) +{ + return (unsigned long)(signed long)val; +} + +#endif /* __ASM_SH_CACHE_INSNS_32_H */ diff --git a/arch/sh/include/asm/cache_insns_64.h b/arch/sh/include/asm/cache_insns_64.h new file mode 100644 index 000000000..70b6357ea --- /dev/null +++ b/arch/sh/include/asm/cache_insns_64.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2004 Richard Curnow + * + * 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_CACHE_INSNS_64_H +#define __ASM_SH_CACHE_INSNS_64_H + +#define __icbi(addr) __asm__ __volatile__ ( "icbi %0, 0\n\t" : : "r" (addr)) +#define __ocbp(addr) __asm__ __volatile__ ( "ocbp %0, 0\n\t" : : "r" (addr)) +#define __ocbi(addr) __asm__ __volatile__ ( "ocbi %0, 0\n\t" : : "r" (addr)) +#define __ocbwb(addr) __asm__ __volatile__ ( "ocbwb %0, 0\n\t" : : "r" (addr)) + +static inline reg_size_t register_align(void *val) +{ + return (unsigned long long)(signed long long)(signed long)val; +} + +#endif /* __ASM_SH_CACHE_INSNS_64_H */ diff --git a/arch/sh/include/asm/cacheflush.h b/arch/sh/include/asm/cacheflush.h new file mode 100644 index 000000000..82e1eabea --- /dev/null +++ b/arch/sh/include/asm/cacheflush.h @@ -0,0 +1,104 @@ +#ifndef __ASM_SH_CACHEFLUSH_H +#define __ASM_SH_CACHEFLUSH_H + +#ifdef __KERNEL__ + +#include <linux/mm.h> + +/* + * Cache flushing: + * + * - flush_cache_all() flushes entire cache + * - flush_cache_mm(mm) flushes the specified mm context's cache lines + * - flush_cache_dup mm(mm) handles cache flushing when forking + * - flush_cache_page(mm, vmaddr, pfn) flushes a single page + * - flush_cache_range(vma, start, end) flushes a range of pages + * + * - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache + * - flush_icache_range(start, end) flushes(invalidates) a range for icache + * - flush_icache_page(vma, pg) flushes(invalidates) a page for icache + * - flush_cache_sigtramp(vaddr) flushes the signal trampoline + */ +extern void (*local_flush_cache_all)(void *args); +extern void (*local_flush_cache_mm)(void *args); +extern void (*local_flush_cache_dup_mm)(void *args); +extern void (*local_flush_cache_page)(void *args); +extern void (*local_flush_cache_range)(void *args); +extern void (*local_flush_dcache_page)(void *args); +extern void (*local_flush_icache_range)(void *args); +extern void (*local_flush_icache_page)(void *args); +extern void (*local_flush_cache_sigtramp)(void *args); + +static inline void cache_noop(void *args) { } + +extern void (*__flush_wback_region)(void *start, int size); +extern void (*__flush_purge_region)(void *start, int size); +extern void (*__flush_invalidate_region)(void *start, int size); + +extern void flush_cache_all(void); +extern void flush_cache_mm(struct mm_struct *mm); +extern void flush_cache_dup_mm(struct mm_struct *mm); +extern void flush_cache_page(struct vm_area_struct *vma, + unsigned long addr, unsigned long pfn); +extern void flush_cache_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end); +#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1 +extern void flush_dcache_page(struct page *page); +extern void flush_icache_range(unsigned long start, unsigned long end); +extern void flush_icache_page(struct vm_area_struct *vma, + struct page *page); +extern void flush_cache_sigtramp(unsigned long address); + +struct flusher_data { + struct vm_area_struct *vma; + unsigned long addr1, addr2; +}; + +#define ARCH_HAS_FLUSH_ANON_PAGE +extern void __flush_anon_page(struct page *page, unsigned long); + +static inline void flush_anon_page(struct vm_area_struct *vma, + struct page *page, unsigned long vmaddr) +{ + if (boot_cpu_data.dcache.n_aliases && PageAnon(page)) + __flush_anon_page(page, vmaddr); +} +static inline void flush_kernel_vmap_range(void *addr, int size) +{ + __flush_wback_region(addr, size); +} +static inline void invalidate_kernel_vmap_range(void *addr, int size) +{ + __flush_invalidate_region(addr, size); +} + +#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE +static inline void flush_kernel_dcache_page(struct page *page) +{ + flush_dcache_page(page); +} + +extern void copy_to_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, void *dst, const void *src, + unsigned long len); + +extern void copy_from_user_page(struct vm_area_struct *vma, + struct page *page, unsigned long vaddr, void *dst, const void *src, + unsigned long len); + +#define flush_cache_vmap(start, end) local_flush_cache_all(NULL) +#define flush_cache_vunmap(start, end) local_flush_cache_all(NULL) + +#define flush_dcache_mmap_lock(mapping) do { } while (0) +#define flush_dcache_mmap_unlock(mapping) do { } while (0) + +void kmap_coherent_init(void); +void *kmap_coherent(struct page *page, unsigned long addr); +void kunmap_coherent(void *kvaddr); + +#define PG_dcache_clean PG_arch_1 + +void cpu_cache_init(void); + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_CACHEFLUSH_H */ diff --git a/arch/sh/include/asm/checksum.h b/arch/sh/include/asm/checksum.h new file mode 100644 index 000000000..34ae26204 --- /dev/null +++ b/arch/sh/include/asm/checksum.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_SUPERH32 +# include <asm/checksum_32.h> +#else +# include <asm-generic/checksum.h> +#endif diff --git a/arch/sh/include/asm/checksum_32.h b/arch/sh/include/asm/checksum_32.h new file mode 100644 index 000000000..14b7ac2f0 --- /dev/null +++ b/arch/sh/include/asm/checksum_32.h @@ -0,0 +1,215 @@ +#ifndef __ASM_SH_CHECKSUM_H +#define __ASM_SH_CHECKSUM_H + +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999 by Kaz Kojima & Niibe Yutaka + */ + +#include <linux/in6.h> + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +asmlinkage __wsum csum_partial(const void *buff, int len, __wsum sum); + +/* + * the same as csum_partial, but copies from src while it + * checksums, and handles user-space pointer exceptions correctly, when needed. + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ + +asmlinkage __wsum csum_partial_copy_generic(const void *src, void *dst, + int len, __wsum sum, + int *src_err_ptr, int *dst_err_ptr); + +/* + * Note: when you get a NULL pointer exception here this means someone + * passed in an incorrect kernel address to one of these functions. + * + * If you use these functions directly please don't forget the + * access_ok(). + */ +static inline +__wsum csum_partial_copy_nocheck(const void *src, void *dst, + int len, __wsum sum) +{ + return csum_partial_copy_generic(src, dst, len, sum, NULL, NULL); +} + +static inline +__wsum csum_partial_copy_from_user(const void __user *src, void *dst, + int len, __wsum sum, int *err_ptr) +{ + return csum_partial_copy_generic((__force const void *)src, dst, + len, sum, err_ptr, NULL); +} + +/* + * Fold a partial checksum + */ + +static inline __sum16 csum_fold(__wsum sum) +{ + unsigned int __dummy; + __asm__("swap.w %0, %1\n\t" + "extu.w %0, %0\n\t" + "extu.w %1, %1\n\t" + "add %1, %0\n\t" + "swap.w %0, %1\n\t" + "add %1, %0\n\t" + "not %0, %0\n\t" + : "=r" (sum), "=&r" (__dummy) + : "0" (sum) + : "t"); + return (__force __sum16)sum; +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + * + * i386 version by Jorge Cwik <jorge@laser.satlink.net>, adapted + * for linux by * Arnt Gulbrandsen. + */ +static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl) +{ + unsigned int sum, __dummy0, __dummy1; + + __asm__ __volatile__( + "mov.l @%1+, %0\n\t" + "mov.l @%1+, %3\n\t" + "add #-2, %2\n\t" + "clrt\n\t" + "1:\t" + "addc %3, %0\n\t" + "movt %4\n\t" + "mov.l @%1+, %3\n\t" + "dt %2\n\t" + "bf/s 1b\n\t" + " cmp/eq #1, %4\n\t" + "addc %3, %0\n\t" + "addc %2, %0" /* Here %2 is 0, add carry-bit */ + /* Since the input registers which are loaded with iph and ihl + are modified, we must also specify them as outputs, or gcc + will assume they contain their original values. */ + : "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (__dummy0), "=&z" (__dummy1) + : "1" (iph), "2" (ihl) + : "t", "memory"); + + return csum_fold(sum); +} + +static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, + unsigned short len, + unsigned short proto, + __wsum sum) +{ +#ifdef __LITTLE_ENDIAN__ + unsigned long len_proto = (proto + len) << 8; +#else + unsigned long len_proto = proto + len; +#endif + __asm__("clrt\n\t" + "addc %0, %1\n\t" + "addc %2, %1\n\t" + "addc %3, %1\n\t" + "movt %0\n\t" + "add %1, %0" + : "=r" (sum), "=r" (len_proto) + : "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum) + : "t"); + + return sum; +} + +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ +static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, + unsigned short len, + unsigned short proto, + __wsum sum) +{ + return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); +} + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +static inline __sum16 ip_compute_csum(const void *buff, int len) +{ + return csum_fold(csum_partial(buff, len, 0)); +} + +#define _HAVE_ARCH_IPV6_CSUM +static inline __sum16 csum_ipv6_magic(const struct in6_addr *saddr, + const struct in6_addr *daddr, + __u32 len, unsigned short proto, + __wsum sum) +{ + unsigned int __dummy; + __asm__("clrt\n\t" + "mov.l @(0,%2), %1\n\t" + "addc %1, %0\n\t" + "mov.l @(4,%2), %1\n\t" + "addc %1, %0\n\t" + "mov.l @(8,%2), %1\n\t" + "addc %1, %0\n\t" + "mov.l @(12,%2), %1\n\t" + "addc %1, %0\n\t" + "mov.l @(0,%3), %1\n\t" + "addc %1, %0\n\t" + "mov.l @(4,%3), %1\n\t" + "addc %1, %0\n\t" + "mov.l @(8,%3), %1\n\t" + "addc %1, %0\n\t" + "mov.l @(12,%3), %1\n\t" + "addc %1, %0\n\t" + "addc %4, %0\n\t" + "addc %5, %0\n\t" + "movt %1\n\t" + "add %1, %0\n" + : "=r" (sum), "=&r" (__dummy) + : "r" (saddr), "r" (daddr), + "r" (htonl(len)), "r" (htonl(proto)), "0" (sum) + : "t"); + + return csum_fold(sum); +} + +/* + * Copy and checksum to user + */ +#define HAVE_CSUM_COPY_USER +static inline __wsum csum_and_copy_to_user(const void *src, + void __user *dst, + int len, __wsum sum, + int *err_ptr) +{ + if (access_ok(VERIFY_WRITE, dst, len)) + return csum_partial_copy_generic((__force const void *)src, + dst, len, sum, NULL, err_ptr); + + if (len) + *err_ptr = -EFAULT; + + return (__force __wsum)-1; /* invalid checksum */ +} +#endif /* __ASM_SH_CHECKSUM_H */ diff --git a/arch/sh/include/asm/clkdev.h b/arch/sh/include/asm/clkdev.h new file mode 100644 index 000000000..c41901465 --- /dev/null +++ b/arch/sh/include/asm/clkdev.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010 Paul Mundt <lethal@linux-sh.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Helper for the clk API to assist looking up a struct clk. + */ + +#ifndef __CLKDEV__H_ +#define __CLKDEV__H_ + +#include <linux/bootmem.h> +#include <linux/mm.h> +#include <linux/slab.h> + +#include <asm/clock.h> + +static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) +{ + if (!slab_is_available()) + return alloc_bootmem_low_pages(size); + else + return kzalloc(size, GFP_KERNEL); +} + +#ifndef CONFIG_COMMON_CLK +#define __clk_put(clk) +#define __clk_get(clk) ({ 1; }) +#endif + +#endif /* __CLKDEV_H__ */ diff --git a/arch/sh/include/asm/clock.h b/arch/sh/include/asm/clock.h new file mode 100644 index 000000000..0390a07e7 --- /dev/null +++ b/arch/sh/include/asm/clock.h @@ -0,0 +1,16 @@ +#ifndef __ASM_SH_CLOCK_H +#define __ASM_SH_CLOCK_H + +#include <linux/sh_clk.h> + +/* Should be defined by processor-specific code */ +void __deprecated arch_init_clk_ops(struct sh_clk_ops **, int type); +int __init arch_clk_init(void); + +/* arch/sh/kernel/cpu/clock-cpg.c */ +int __init __deprecated cpg_clk_init(void); + +/* arch/sh/kernel/cpu/clock.c */ +int clk_init(void); + +#endif /* __ASM_SH_CLOCK_H */ diff --git a/arch/sh/include/asm/cmpxchg-grb.h b/arch/sh/include/asm/cmpxchg-grb.h new file mode 100644 index 000000000..f848dec9e --- /dev/null +++ b/arch/sh/include/asm/cmpxchg-grb.h @@ -0,0 +1,72 @@ +#ifndef __ASM_SH_CMPXCHG_GRB_H +#define __ASM_SH_CMPXCHG_GRB_H + +static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val) +{ + unsigned long retval; + + __asm__ __volatile__ ( + " .align 2 \n\t" + " mova 1f, r0 \n\t" /* r0 = end point */ + " nop \n\t" + " mov r15, r1 \n\t" /* r1 = saved sp */ + " mov #-4, r15 \n\t" /* LOGIN */ + " mov.l @%1, %0 \n\t" /* load old value */ + " mov.l %2, @%1 \n\t" /* store new value */ + "1: mov r1, r15 \n\t" /* LOGOUT */ + : "=&r" (retval), + "+r" (m), + "+r" (val) /* inhibit r15 overloading */ + : + : "memory", "r0", "r1"); + + return retval; +} + +static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val) +{ + unsigned long retval; + + __asm__ __volatile__ ( + " .align 2 \n\t" + " mova 1f, r0 \n\t" /* r0 = end point */ + " mov r15, r1 \n\t" /* r1 = saved sp */ + " mov #-6, r15 \n\t" /* LOGIN */ + " mov.b @%1, %0 \n\t" /* load old value */ + " extu.b %0, %0 \n\t" /* extend as unsigned */ + " mov.b %2, @%1 \n\t" /* store new value */ + "1: mov r1, r15 \n\t" /* LOGOUT */ + : "=&r" (retval), + "+r" (m), + "+r" (val) /* inhibit r15 overloading */ + : + : "memory" , "r0", "r1"); + + return retval; +} + +static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old, + unsigned long new) +{ + unsigned long retval; + + __asm__ __volatile__ ( + " .align 2 \n\t" + " mova 1f, r0 \n\t" /* r0 = end point */ + " nop \n\t" + " mov r15, r1 \n\t" /* r1 = saved sp */ + " mov #-8, r15 \n\t" /* LOGIN */ + " mov.l @%3, %0 \n\t" /* load old value */ + " cmp/eq %0, %1 \n\t" + " bf 1f \n\t" /* if not equal */ + " mov.l %2, @%3 \n\t" /* store new value */ + "1: mov r1, r15 \n\t" /* LOGOUT */ + : "=&r" (retval), + "+r" (old), "+r" (new) /* old or new can be r15 */ + : "r" (m) + : "memory" , "r0", "r1", "t"); + + return retval; +} + +#endif /* __ASM_SH_CMPXCHG_GRB_H */ diff --git a/arch/sh/include/asm/cmpxchg-irq.h b/arch/sh/include/asm/cmpxchg-irq.h new file mode 100644 index 000000000..bd11f6304 --- /dev/null +++ b/arch/sh/include/asm/cmpxchg-irq.h @@ -0,0 +1,42 @@ +#ifndef __ASM_SH_CMPXCHG_IRQ_H +#define __ASM_SH_CMPXCHG_IRQ_H + +#include <linux/irqflags.h> + +static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val) +{ + unsigned long flags, retval; + + local_irq_save(flags); + retval = *m; + *m = val; + local_irq_restore(flags); + return retval; +} + +static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val) +{ + unsigned long flags, retval; + + local_irq_save(flags); + retval = *m; + *m = val & 0xff; + local_irq_restore(flags); + return retval; +} + +static inline unsigned long __cmpxchg_u32(volatile int *m, unsigned long old, + unsigned long new) +{ + __u32 retval; + unsigned long flags; + + local_irq_save(flags); + retval = *m; + if (retval == old) + *m = new; + local_irq_restore(flags); /* implies memory barrier */ + return retval; +} + +#endif /* __ASM_SH_CMPXCHG_IRQ_H */ diff --git a/arch/sh/include/asm/cmpxchg-llsc.h b/arch/sh/include/asm/cmpxchg-llsc.h new file mode 100644 index 000000000..47136661a --- /dev/null +++ b/arch/sh/include/asm/cmpxchg-llsc.h @@ -0,0 +1,71 @@ +#ifndef __ASM_SH_CMPXCHG_LLSC_H +#define __ASM_SH_CMPXCHG_LLSC_H + +static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val) +{ + unsigned long retval; + unsigned long tmp; + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%2, %0 ! xchg_u32 \n\t" + "mov %0, %1 \n\t" + "mov %3, %0 \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "synco \n\t" + : "=&z"(tmp), "=&r" (retval) + : "r" (m), "r" (val) + : "t", "memory" + ); + + return retval; +} + +static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val) +{ + unsigned long retval; + unsigned long tmp; + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%2, %0 ! xchg_u8 \n\t" + "mov %0, %1 \n\t" + "mov %3, %0 \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "synco \n\t" + : "=&z"(tmp), "=&r" (retval) + : "r" (m), "r" (val & 0xff) + : "t", "memory" + ); + + return retval; +} + +static inline unsigned long +__cmpxchg_u32(volatile int *m, unsigned long old, unsigned long new) +{ + unsigned long retval; + unsigned long tmp; + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%2, %0 ! __cmpxchg_u32 \n\t" + "mov %0, %1 \n\t" + "cmp/eq %1, %3 \n\t" + "bf 2f \n\t" + "mov %4, %0 \n\t" + "2: \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "synco \n\t" + : "=&z" (tmp), "=&r" (retval) + : "r" (m), "r" (old), "r" (new) + : "t", "memory" + ); + + return retval; +} + +#endif /* __ASM_SH_CMPXCHG_LLSC_H */ diff --git a/arch/sh/include/asm/cmpxchg.h b/arch/sh/include/asm/cmpxchg.h new file mode 100644 index 000000000..f6bd1406b --- /dev/null +++ b/arch/sh/include/asm/cmpxchg.h @@ -0,0 +1,70 @@ +#ifndef __ASM_SH_CMPXCHG_H +#define __ASM_SH_CMPXCHG_H + +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc.. + */ + +#include <linux/compiler.h> +#include <linux/types.h> + +#if defined(CONFIG_GUSA_RB) +#include <asm/cmpxchg-grb.h> +#elif defined(CONFIG_CPU_SH4A) +#include <asm/cmpxchg-llsc.h> +#else +#include <asm/cmpxchg-irq.h> +#endif + +extern void __xchg_called_with_bad_pointer(void); + +#define __xchg(ptr, x, size) \ +({ \ + unsigned long __xchg__res; \ + volatile void *__xchg_ptr = (ptr); \ + switch (size) { \ + case 4: \ + __xchg__res = xchg_u32(__xchg_ptr, x); \ + break; \ + case 1: \ + __xchg__res = xchg_u8(__xchg_ptr, x); \ + break; \ + default: \ + __xchg_called_with_bad_pointer(); \ + __xchg__res = x; \ + break; \ + } \ + \ + __xchg__res; \ +}) + +#define xchg(ptr,x) \ + ((__typeof__(*(ptr)))__xchg((ptr),(unsigned long)(x), sizeof(*(ptr)))) + +/* This function doesn't exist, so you'll get a linker error + * if something tries to do an invalid cmpxchg(). */ +extern void __cmpxchg_called_with_bad_pointer(void); + +#define __HAVE_ARCH_CMPXCHG 1 + +static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old, + unsigned long new, int size) +{ + switch (size) { + case 4: + return __cmpxchg_u32(ptr, old, new); + } + __cmpxchg_called_with_bad_pointer(); + return old; +} + +#define cmpxchg(ptr,o,n) \ + ({ \ + __typeof__(*(ptr)) _o_ = (o); \ + __typeof__(*(ptr)) _n_ = (n); \ + (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ + (unsigned long)_n_, sizeof(*(ptr))); \ + }) + +#endif /* __ASM_SH_CMPXCHG_H */ diff --git a/arch/sh/include/asm/device.h b/arch/sh/include/asm/device.h new file mode 100644 index 000000000..071bcb4d4 --- /dev/null +++ b/arch/sh/include/asm/device.h @@ -0,0 +1,18 @@ +/* + * Arch specific extensions to struct device + * + * This file is released under the GPLv2 + */ +#ifndef __ASM_SH_DEVICE_H +#define __ASM_SH_DEVICE_H + +#include <asm-generic/device.h> + +struct platform_device; +/* allocate contiguous memory chunk and fill in struct resource */ +int platform_resource_setup_memory(struct platform_device *pdev, + char *name, unsigned long memsize); + +void plat_early_device_setup(void); + +#endif /* __ASM_SH_DEVICE_H */ diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h new file mode 100644 index 000000000..b437f2c78 --- /dev/null +++ b/arch/sh/include/asm/dma-mapping.h @@ -0,0 +1,100 @@ +#ifndef __ASM_SH_DMA_MAPPING_H +#define __ASM_SH_DMA_MAPPING_H + +extern struct dma_map_ops *dma_ops; +extern void no_iommu_init(void); + +static inline struct dma_map_ops *get_dma_ops(struct device *dev) +{ + return dma_ops; +} + +#include <asm-generic/dma-coherent.h> +#include <asm-generic/dma-mapping-common.h> + +static inline int dma_supported(struct device *dev, u64 mask) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + + if (ops->dma_supported) + return ops->dma_supported(dev, mask); + + return 1; +} + +static inline int dma_set_mask(struct device *dev, u64 mask) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + + if (!dev->dma_mask || !dma_supported(dev, mask)) + return -EIO; + if (ops->set_dma_mask) + return ops->set_dma_mask(dev, mask); + + *dev->dma_mask = mask; + + return 0; +} + +void dma_cache_sync(struct device *dev, void *vaddr, size_t size, + enum dma_data_direction dir); + +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) + +static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + + debug_dma_mapping_error(dev, dma_addr); + if (ops->mapping_error) + return ops->mapping_error(dev, dma_addr); + + return dma_addr == 0; +} + +#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) + +static inline void *dma_alloc_attrs(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp, + struct dma_attrs *attrs) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + void *memory; + + if (dma_alloc_from_coherent(dev, size, dma_handle, &memory)) + return memory; + if (!ops->alloc) + return NULL; + + memory = ops->alloc(dev, size, dma_handle, gfp, attrs); + debug_dma_alloc_coherent(dev, size, *dma_handle, memory); + + return memory; +} + +#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) + +static inline void dma_free_attrs(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle, + struct dma_attrs *attrs) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + + if (dma_release_from_coherent(dev, get_order(size), vaddr)) + return; + + debug_dma_free_coherent(dev, size, vaddr, dma_handle); + if (ops->free) + ops->free(dev, size, vaddr, dma_handle, attrs); +} + +/* arch/sh/mm/consistent.c */ +extern void *dma_generic_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_addr, gfp_t flag, + struct dma_attrs *attrs); +extern void dma_generic_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle, + struct dma_attrs *attrs); + +#endif /* __ASM_SH_DMA_MAPPING_H */ diff --git a/arch/sh/include/asm/dma-register.h b/arch/sh/include/asm/dma-register.h new file mode 100644 index 000000000..c757b47e6 --- /dev/null +++ b/arch/sh/include/asm/dma-register.h @@ -0,0 +1,53 @@ +/* + * Common header for the legacy SH DMA driver and the new dmaengine driver + * + * extracted from arch/sh/include/asm/dma-sh.h: + * + * Copyright (C) 2000 Takashi YOSHII + * 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 DMA_REGISTER_H +#define DMA_REGISTER_H + +/* DMA registers */ +#define SAR 0x00 /* Source Address Register */ +#define DAR 0x04 /* Destination Address Register */ +#define TCR 0x08 /* Transfer Count Register */ +#define CHCR 0x0C /* Channel Control Register */ +#define DMAOR 0x40 /* DMA Operation Register */ + +/* DMAOR definitions */ +#define DMAOR_AE 0x00000004 /* Address Error Flag */ +#define DMAOR_NMIF 0x00000002 +#define DMAOR_DME 0x00000001 /* DMA Master Enable */ + +/* Definitions for the SuperH DMAC */ +#define REQ_L 0x00000000 +#define REQ_E 0x00080000 +#define RACK_H 0x00000000 +#define RACK_L 0x00040000 +#define ACK_R 0x00000000 +#define ACK_W 0x00020000 +#define ACK_H 0x00000000 +#define ACK_L 0x00010000 +#define DM_INC 0x00004000 /* Destination addresses are incremented */ +#define DM_DEC 0x00008000 /* Destination addresses are decremented */ +#define DM_FIX 0x0000c000 /* Destination address is fixed */ +#define SM_INC 0x00001000 /* Source addresses are incremented */ +#define SM_DEC 0x00002000 /* Source addresses are decremented */ +#define SM_FIX 0x00003000 /* Source address is fixed */ +#define RS_IN 0x00000200 +#define RS_OUT 0x00000300 +#define RS_AUTO 0x00000400 /* Auto Request */ +#define RS_ERS 0x00000800 /* DMA extended resource selector */ +#define TS_BLK 0x00000040 +#define TM_BUR 0x00000020 +#define CHCR_DE 0x00000001 /* DMA Enable */ +#define CHCR_TE 0x00000002 /* Transfer End Flag */ +#define CHCR_IE 0x00000004 /* Interrupt Enable */ + +#endif diff --git a/arch/sh/include/asm/dma.h b/arch/sh/include/asm/dma.h new file mode 100644 index 000000000..fb6e4f7b0 --- /dev/null +++ b/arch/sh/include/asm/dma.h @@ -0,0 +1,151 @@ +/* + * include/asm-sh/dma.h + * + * Copyright (C) 2003, 2004 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_DMA_H +#define __ASM_SH_DMA_H +#ifdef __KERNEL__ + +#include <linux/spinlock.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/device.h> +#include <asm-generic/dma.h> + +/* + * Read and write modes can mean drastically different things depending on the + * channel configuration. Consult your DMAC documentation and module + * implementation for further clues. + */ +#define DMA_MODE_READ 0x00 +#define DMA_MODE_WRITE 0x01 +#define DMA_MODE_MASK 0x01 + +#define DMA_AUTOINIT 0x10 + +/* + * DMAC (dma_info) flags + */ +enum { + DMAC_CHANNELS_CONFIGURED = 0x01, + DMAC_CHANNELS_TEI_CAPABLE = 0x02, /* Transfer end interrupt */ +}; + +/* + * DMA channel capabilities / flags + */ +enum { + DMA_CONFIGURED = 0x01, + + /* + * Transfer end interrupt, inherited from DMAC. + * wait_queue used in dma_wait_for_completion. + */ + DMA_TEI_CAPABLE = 0x02, +}; + +extern spinlock_t dma_spin_lock; + +struct dma_channel; + +struct dma_ops { + int (*request)(struct dma_channel *chan); + void (*free)(struct dma_channel *chan); + + int (*get_residue)(struct dma_channel *chan); + int (*xfer)(struct dma_channel *chan); + int (*configure)(struct dma_channel *chan, unsigned long flags); + int (*extend)(struct dma_channel *chan, unsigned long op, void *param); +}; + +struct dma_channel { + char dev_id[16]; /* unique name per DMAC of channel */ + + unsigned int chan; /* DMAC channel number */ + unsigned int vchan; /* Virtual channel number */ + + unsigned int mode; + unsigned int count; + + unsigned long sar; + unsigned long dar; + + const char **caps; + + unsigned long flags; + atomic_t busy; + + wait_queue_head_t wait_queue; + + struct device dev; + void *priv_data; +}; + +struct dma_info { + struct platform_device *pdev; + + const char *name; + unsigned int nr_channels; + unsigned long flags; + + struct dma_ops *ops; + struct dma_channel *channels; + + struct list_head list; + int first_channel_nr; + int first_vchannel_nr; +}; + +struct dma_chan_caps { + int ch_num; + const char **caplist; +}; + +#define to_dma_channel(channel) container_of(channel, struct dma_channel, dev) + +/* arch/sh/drivers/dma/dma-api.c */ +extern int dma_xfer(unsigned int chan, unsigned long from, + unsigned long to, size_t size, unsigned int mode); + +#define dma_write(chan, from, to, size) \ + dma_xfer(chan, from, to, size, DMA_MODE_WRITE) +#define dma_write_page(chan, from, to) \ + dma_write(chan, from, to, PAGE_SIZE) + +#define dma_read(chan, from, to, size) \ + dma_xfer(chan, from, to, size, DMA_MODE_READ) +#define dma_read_page(chan, from, to) \ + dma_read(chan, from, to, PAGE_SIZE) + +extern int request_dma_bycap(const char **dmac, const char **caps, + const char *dev_id); +extern int get_dma_residue(unsigned int chan); +extern struct dma_info *get_dma_info(unsigned int chan); +extern struct dma_channel *get_dma_channel(unsigned int chan); +extern void dma_wait_for_completion(unsigned int chan); +extern void dma_configure_channel(unsigned int chan, unsigned long flags); + +extern int register_dmac(struct dma_info *info); +extern void unregister_dmac(struct dma_info *info); +extern struct dma_info *get_dma_info_by_name(const char *dmac_name); + +extern int dma_extend(unsigned int chan, unsigned long op, void *param); +extern int register_chan_caps(const char *dmac, struct dma_chan_caps *capslist); + +/* arch/sh/drivers/dma/dma-sysfs.c */ +extern int dma_create_sysfs_files(struct dma_channel *, struct dma_info *); +extern void dma_remove_sysfs_files(struct dma_channel *, struct dma_info *); + +#ifdef CONFIG_PCI +extern int isa_dma_bridge_buggy; +#else +#define isa_dma_bridge_buggy (0) +#endif + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_DMA_H */ diff --git a/arch/sh/include/asm/dmabrg.h b/arch/sh/include/asm/dmabrg.h new file mode 100644 index 000000000..c5edba216 --- /dev/null +++ b/arch/sh/include/asm/dmabrg.h @@ -0,0 +1,23 @@ +/* + * SH7760 DMABRG (USB/Audio) support + */ + +#ifndef _DMABRG_H_ +#define _DMABRG_H_ + +/* IRQ sources */ +#define DMABRGIRQ_USBDMA 0 +#define DMABRGIRQ_USBDMAERR 1 +#define DMABRGIRQ_A0TXF 2 +#define DMABRGIRQ_A0TXH 3 +#define DMABRGIRQ_A0RXF 4 +#define DMABRGIRQ_A0RXH 5 +#define DMABRGIRQ_A1TXF 6 +#define DMABRGIRQ_A1TXH 7 +#define DMABRGIRQ_A1RXF 8 +#define DMABRGIRQ_A1RXH 9 + +extern int dmabrg_request_irq(unsigned int, void(*)(void *), void *); +extern void dmabrg_free_irq(unsigned int); + +#endif diff --git a/arch/sh/include/asm/dwarf.h b/arch/sh/include/asm/dwarf.h new file mode 100644 index 000000000..d62abd1d0 --- /dev/null +++ b/arch/sh/include/asm/dwarf.h @@ -0,0 +1,421 @@ +/* + * Copyright (C) 2009 Matt Fleming <matt@console-pimps.org> + * + * 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_DWARF_H +#define __ASM_SH_DWARF_H + +#ifdef CONFIG_DWARF_UNWINDER + +/* + * DWARF expression operations + */ +#define DW_OP_addr 0x03 +#define DW_OP_deref 0x06 +#define DW_OP_const1u 0x08 +#define DW_OP_const1s 0x09 +#define DW_OP_const2u 0x0a +#define DW_OP_const2s 0x0b +#define DW_OP_const4u 0x0c +#define DW_OP_const4s 0x0d +#define DW_OP_const8u 0x0e +#define DW_OP_const8s 0x0f +#define DW_OP_constu 0x10 +#define DW_OP_consts 0x11 +#define DW_OP_dup 0x12 +#define DW_OP_drop 0x13 +#define DW_OP_over 0x14 +#define DW_OP_pick 0x15 +#define DW_OP_swap 0x16 +#define DW_OP_rot 0x17 +#define DW_OP_xderef 0x18 +#define DW_OP_abs 0x19 +#define DW_OP_and 0x1a +#define DW_OP_div 0x1b +#define DW_OP_minus 0x1c +#define DW_OP_mod 0x1d +#define DW_OP_mul 0x1e +#define DW_OP_neg 0x1f +#define DW_OP_not 0x20 +#define DW_OP_or 0x21 +#define DW_OP_plus 0x22 +#define DW_OP_plus_uconst 0x23 +#define DW_OP_shl 0x24 +#define DW_OP_shr 0x25 +#define DW_OP_shra 0x26 +#define DW_OP_xor 0x27 +#define DW_OP_skip 0x2f +#define DW_OP_bra 0x28 +#define DW_OP_eq 0x29 +#define DW_OP_ge 0x2a +#define DW_OP_gt 0x2b +#define DW_OP_le 0x2c +#define DW_OP_lt 0x2d +#define DW_OP_ne 0x2e +#define DW_OP_lit0 0x30 +#define DW_OP_lit1 0x31 +#define DW_OP_lit2 0x32 +#define DW_OP_lit3 0x33 +#define DW_OP_lit4 0x34 +#define DW_OP_lit5 0x35 +#define DW_OP_lit6 0x36 +#define DW_OP_lit7 0x37 +#define DW_OP_lit8 0x38 +#define DW_OP_lit9 0x39 +#define DW_OP_lit10 0x3a +#define DW_OP_lit11 0x3b +#define DW_OP_lit12 0x3c +#define DW_OP_lit13 0x3d +#define DW_OP_lit14 0x3e +#define DW_OP_lit15 0x3f +#define DW_OP_lit16 0x40 +#define DW_OP_lit17 0x41 +#define DW_OP_lit18 0x42 +#define DW_OP_lit19 0x43 +#define DW_OP_lit20 0x44 +#define DW_OP_lit21 0x45 +#define DW_OP_lit22 0x46 +#define DW_OP_lit23 0x47 +#define DW_OP_lit24 0x48 +#define DW_OP_lit25 0x49 +#define DW_OP_lit26 0x4a +#define DW_OP_lit27 0x4b +#define DW_OP_lit28 0x4c +#define DW_OP_lit29 0x4d +#define DW_OP_lit30 0x4e +#define DW_OP_lit31 0x4f +#define DW_OP_reg0 0x50 +#define DW_OP_reg1 0x51 +#define DW_OP_reg2 0x52 +#define DW_OP_reg3 0x53 +#define DW_OP_reg4 0x54 +#define DW_OP_reg5 0x55 +#define DW_OP_reg6 0x56 +#define DW_OP_reg7 0x57 +#define DW_OP_reg8 0x58 +#define DW_OP_reg9 0x59 +#define DW_OP_reg10 0x5a +#define DW_OP_reg11 0x5b +#define DW_OP_reg12 0x5c +#define DW_OP_reg13 0x5d +#define DW_OP_reg14 0x5e +#define DW_OP_reg15 0x5f +#define DW_OP_reg16 0x60 +#define DW_OP_reg17 0x61 +#define DW_OP_reg18 0x62 +#define DW_OP_reg19 0x63 +#define DW_OP_reg20 0x64 +#define DW_OP_reg21 0x65 +#define DW_OP_reg22 0x66 +#define DW_OP_reg23 0x67 +#define DW_OP_reg24 0x68 +#define DW_OP_reg25 0x69 +#define DW_OP_reg26 0x6a +#define DW_OP_reg27 0x6b +#define DW_OP_reg28 0x6c +#define DW_OP_reg29 0x6d +#define DW_OP_reg30 0x6e +#define DW_OP_reg31 0x6f +#define DW_OP_breg0 0x70 +#define DW_OP_breg1 0x71 +#define DW_OP_breg2 0x72 +#define DW_OP_breg3 0x73 +#define DW_OP_breg4 0x74 +#define DW_OP_breg5 0x75 +#define DW_OP_breg6 0x76 +#define DW_OP_breg7 0x77 +#define DW_OP_breg8 0x78 +#define DW_OP_breg9 0x79 +#define DW_OP_breg10 0x7a +#define DW_OP_breg11 0x7b +#define DW_OP_breg12 0x7c +#define DW_OP_breg13 0x7d +#define DW_OP_breg14 0x7e +#define DW_OP_breg15 0x7f +#define DW_OP_breg16 0x80 +#define DW_OP_breg17 0x81 +#define DW_OP_breg18 0x82 +#define DW_OP_breg19 0x83 +#define DW_OP_breg20 0x84 +#define DW_OP_breg21 0x85 +#define DW_OP_breg22 0x86 +#define DW_OP_breg23 0x87 +#define DW_OP_breg24 0x88 +#define DW_OP_breg25 0x89 +#define DW_OP_breg26 0x8a +#define DW_OP_breg27 0x8b +#define DW_OP_breg28 0x8c +#define DW_OP_breg29 0x8d +#define DW_OP_breg30 0x8e +#define DW_OP_breg31 0x8f +#define DW_OP_regx 0x90 +#define DW_OP_fbreg 0x91 +#define DW_OP_bregx 0x92 +#define DW_OP_piece 0x93 +#define DW_OP_deref_size 0x94 +#define DW_OP_xderef_size 0x95 +#define DW_OP_nop 0x96 +#define DW_OP_push_object_address 0x97 +#define DW_OP_call2 0x98 +#define DW_OP_call4 0x99 +#define DW_OP_call_ref 0x9a +#define DW_OP_form_tls_address 0x9b +#define DW_OP_call_frame_cfa 0x9c +#define DW_OP_bit_piece 0x9d +#define DW_OP_lo_user 0xe0 +#define DW_OP_hi_user 0xff + +/* + * Addresses used in FDE entries in the .eh_frame section may be encoded + * using one of the following encodings. + */ +#define DW_EH_PE_absptr 0x00 +#define DW_EH_PE_omit 0xff +#define DW_EH_PE_uleb128 0x01 +#define DW_EH_PE_udata2 0x02 +#define DW_EH_PE_udata4 0x03 +#define DW_EH_PE_udata8 0x04 +#define DW_EH_PE_sleb128 0x09 +#define DW_EH_PE_sdata2 0x0a +#define DW_EH_PE_sdata4 0x0b +#define DW_EH_PE_sdata8 0x0c +#define DW_EH_PE_signed 0x09 + +#define DW_EH_PE_pcrel 0x10 + +/* + * The architecture-specific register number that contains the return + * address in the .debug_frame table. + */ +#define DWARF_ARCH_RA_REG 17 + +#ifndef __ASSEMBLY__ + +#include <linux/compiler.h> +#include <linux/bug.h> +#include <linux/list.h> +#include <linux/module.h> + +/* + * Read either the frame pointer (r14) or the stack pointer (r15). + * NOTE: this MUST be inlined. + */ +static __always_inline unsigned long dwarf_read_arch_reg(unsigned int reg) +{ + unsigned long value = 0; + + switch (reg) { + case 14: + __asm__ __volatile__("mov r14, %0\n" : "=r" (value)); + break; + case 15: + __asm__ __volatile__("mov r15, %0\n" : "=r" (value)); + break; + default: + BUG(); + } + + return value; +} + +/** + * dwarf_cie - Common Information Entry + */ +struct dwarf_cie { + unsigned long length; + unsigned long cie_id; + unsigned char version; + const char *augmentation; + unsigned int code_alignment_factor; + int data_alignment_factor; + + /* Which column in the rule table represents return addr of func. */ + unsigned int return_address_reg; + + unsigned char *initial_instructions; + unsigned char *instructions_end; + + unsigned char encoding; + + unsigned long cie_pointer; + + unsigned long flags; +#define DWARF_CIE_Z_AUGMENTATION (1 << 0) + + /* linked-list entry if this CIE is from a module */ + struct list_head link; + + struct rb_node node; +}; + +/** + * dwarf_fde - Frame Description Entry + */ +struct dwarf_fde { + unsigned long length; + unsigned long cie_pointer; + struct dwarf_cie *cie; + unsigned long initial_location; + unsigned long address_range; + unsigned char *instructions; + unsigned char *end; + + /* linked-list entry if this FDE is from a module */ + struct list_head link; + + struct rb_node node; +}; + +/** + * dwarf_frame - DWARF information for a frame in the call stack + */ +struct dwarf_frame { + struct dwarf_frame *prev, *next; + + unsigned long pc; + + struct list_head reg_list; + + unsigned long cfa; + + /* Valid when DW_FRAME_CFA_REG_OFFSET is set in flags */ + unsigned int cfa_register; + unsigned int cfa_offset; + + /* Valid when DW_FRAME_CFA_REG_EXP is set in flags */ + unsigned char *cfa_expr; + unsigned int cfa_expr_len; + + unsigned long flags; +#define DWARF_FRAME_CFA_REG_OFFSET (1 << 0) +#define DWARF_FRAME_CFA_REG_EXP (1 << 1) + + unsigned long return_addr; +}; + +/** + * dwarf_reg - DWARF register + * @flags: Describes how to calculate the value of this register + */ +struct dwarf_reg { + struct list_head link; + + unsigned int number; + + unsigned long addr; + unsigned long flags; +#define DWARF_REG_OFFSET (1 << 0) +#define DWARF_VAL_OFFSET (1 << 1) +#define DWARF_UNDEFINED (1 << 2) +}; + +/* + * Call Frame instruction opcodes. + */ +#define DW_CFA_advance_loc 0x40 +#define DW_CFA_offset 0x80 +#define DW_CFA_restore 0xc0 +#define DW_CFA_nop 0x00 +#define DW_CFA_set_loc 0x01 +#define DW_CFA_advance_loc1 0x02 +#define DW_CFA_advance_loc2 0x03 +#define DW_CFA_advance_loc4 0x04 +#define DW_CFA_offset_extended 0x05 +#define DW_CFA_restore_extended 0x06 +#define DW_CFA_undefined 0x07 +#define DW_CFA_same_value 0x08 +#define DW_CFA_register 0x09 +#define DW_CFA_remember_state 0x0a +#define DW_CFA_restore_state 0x0b +#define DW_CFA_def_cfa 0x0c +#define DW_CFA_def_cfa_register 0x0d +#define DW_CFA_def_cfa_offset 0x0e +#define DW_CFA_def_cfa_expression 0x0f +#define DW_CFA_expression 0x10 +#define DW_CFA_offset_extended_sf 0x11 +#define DW_CFA_def_cfa_sf 0x12 +#define DW_CFA_def_cfa_offset_sf 0x13 +#define DW_CFA_val_offset 0x14 +#define DW_CFA_val_offset_sf 0x15 +#define DW_CFA_val_expression 0x16 +#define DW_CFA_lo_user 0x1c +#define DW_CFA_hi_user 0x3f + +/* GNU extension opcodes */ +#define DW_CFA_GNU_args_size 0x2e +#define DW_CFA_GNU_negative_offset_extended 0x2f + +/* + * Some call frame instructions encode their operands in the opcode. We + * need some helper functions to extract both the opcode and operands + * from an instruction. + */ +static inline unsigned int DW_CFA_opcode(unsigned long insn) +{ + return (insn & 0xc0); +} + +static inline unsigned int DW_CFA_operand(unsigned long insn) +{ + return (insn & 0x3f); +} + +#define DW_EH_FRAME_CIE 0 /* .eh_frame CIE IDs are 0 */ +#define DW_CIE_ID 0xffffffff +#define DW64_CIE_ID 0xffffffffffffffffULL + +/* + * DWARF FDE/CIE length field values. + */ +#define DW_EXT_LO 0xfffffff0 +#define DW_EXT_HI 0xffffffff +#define DW_EXT_DWARF64 DW_EXT_HI + +extern struct dwarf_frame *dwarf_unwind_stack(unsigned long, + struct dwarf_frame *); +extern void dwarf_free_frame(struct dwarf_frame *); + +extern int module_dwarf_finalize(const Elf_Ehdr *, const Elf_Shdr *, + struct module *); +extern void module_dwarf_cleanup(struct module *); + +#endif /* !__ASSEMBLY__ */ + +#define CFI_STARTPROC .cfi_startproc +#define CFI_ENDPROC .cfi_endproc +#define CFI_DEF_CFA .cfi_def_cfa +#define CFI_REGISTER .cfi_register +#define CFI_REL_OFFSET .cfi_rel_offset +#define CFI_UNDEFINED .cfi_undefined + +#else + +/* + * Use the asm comment character to ignore the rest of the line. + */ +#define CFI_IGNORE ! + +#define CFI_STARTPROC CFI_IGNORE +#define CFI_ENDPROC CFI_IGNORE +#define CFI_DEF_CFA CFI_IGNORE +#define CFI_REGISTER CFI_IGNORE +#define CFI_REL_OFFSET CFI_IGNORE +#define CFI_UNDEFINED CFI_IGNORE + +#ifndef __ASSEMBLY__ +static inline void dwarf_unwinder_init(void) +{ +} + +#define module_dwarf_finalize(hdr, sechdrs, me) (0) +#define module_dwarf_cleanup(mod) do { } while (0) + +#endif + +#endif /* CONFIG_DWARF_UNWINDER */ + +#endif /* __ASM_SH_DWARF_H */ diff --git a/arch/sh/include/asm/elf.h b/arch/sh/include/asm/elf.h new file mode 100644 index 000000000..bf9f44f17 --- /dev/null +++ b/arch/sh/include/asm/elf.h @@ -0,0 +1,235 @@ +#ifndef __ASM_SH_ELF_H +#define __ASM_SH_ELF_H + +#include <linux/utsname.h> +#include <asm/auxvec.h> +#include <asm/ptrace.h> +#include <asm/user.h> + +/* ELF header e_flags defines */ +#define EF_SH_PIC 0x100 /* -fpic */ +#define EF_SH_FDPIC 0x8000 /* -mfdpic */ + +/* SH (particularly SHcompact) relocation types */ +#define R_SH_NONE 0 +#define R_SH_DIR32 1 +#define R_SH_REL32 2 +#define R_SH_DIR8WPN 3 +#define R_SH_IND12W 4 +#define R_SH_DIR8WPL 5 +#define R_SH_DIR8WPZ 6 +#define R_SH_DIR8BP 7 +#define R_SH_DIR8W 8 +#define R_SH_DIR8L 9 +#define R_SH_SWITCH16 25 +#define R_SH_SWITCH32 26 +#define R_SH_USES 27 +#define R_SH_COUNT 28 +#define R_SH_ALIGN 29 +#define R_SH_CODE 30 +#define R_SH_DATA 31 +#define R_SH_LABEL 32 +#define R_SH_SWITCH8 33 +#define R_SH_GNU_VTINHERIT 34 +#define R_SH_GNU_VTENTRY 35 +#define R_SH_TLS_GD_32 144 +#define R_SH_TLS_LD_32 145 +#define R_SH_TLS_LDO_32 146 +#define R_SH_TLS_IE_32 147 +#define R_SH_TLS_LE_32 148 +#define R_SH_TLS_DTPMOD32 149 +#define R_SH_TLS_DTPOFF32 150 +#define R_SH_TLS_TPOFF32 151 +#define R_SH_GOT32 160 +#define R_SH_PLT32 161 +#define R_SH_COPY 162 +#define R_SH_GLOB_DAT 163 +#define R_SH_JMP_SLOT 164 +#define R_SH_RELATIVE 165 +#define R_SH_GOTOFF 166 +#define R_SH_GOTPC 167 + +/* FDPIC relocs */ +#define R_SH_GOT20 201 +#define R_SH_GOTOFF20 202 +#define R_SH_GOTFUNCDESC 203 +#define R_SH_GOTFUNCDESC20 204 +#define R_SH_GOTOFFFUNCDESC 205 +#define R_SH_GOTOFFFUNCDESC20 206 +#define R_SH_FUNCDESC 207 +#define R_SH_FUNCDESC_VALUE 208 + +/* SHmedia relocs */ +#define R_SH_IMM_LOW16 246 +#define R_SH_IMM_LOW16_PCREL 247 +#define R_SH_IMM_MEDLOW16 248 +#define R_SH_IMM_MEDLOW16_PCREL 249 +/* Keep this the last entry. */ +#define R_SH_NUM 256 + +/* + * ELF register definitions.. + */ + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct user_fpu_struct elf_fpregset_t; + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#ifdef __LITTLE_ENDIAN__ +#define ELF_DATA ELFDATA2LSB +#else +#define ELF_DATA ELFDATA2MSB +#endif +#define ELF_ARCH EM_SH + +#ifdef __KERNEL__ +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ((x)->e_machine == EM_SH) +#define elf_check_fdpic(x) ((x)->e_flags & EF_SH_FDPIC) +#define elf_check_const_displacement(x) ((x)->e_flags & EF_SH_PIC) + +/* + * Enable dump using regset. + * This covers all of general/DSP/FPU regs. + */ +#define CORE_DUMP_USE_REGSET + +#define ELF_FDPIC_CORE_EFLAGS EF_SH_FDPIC +#define ELF_EXEC_PAGESIZE PAGE_SIZE + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) + +#define ELF_CORE_COPY_REGS(_dest,_regs) \ + memcpy((char *) &_dest, (char *) _regs, \ + sizeof(struct pt_regs)); + +/* This yields a mask that user programs can use to figure out what + instruction set this CPU supports. This could be done in user space, + but it's not easy, and we've already done it here. */ + +#define ELF_HWCAP (boot_cpu_data.flags) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. + + For the moment, we have only optimizations for the Intel generations, + but that could change... */ + +#define ELF_PLATFORM (utsname()->machine) + +#ifdef __SH5__ +#define ELF_PLAT_INIT(_r, load_addr) \ + do { _r->regs[0]=0; _r->regs[1]=0; _r->regs[2]=0; _r->regs[3]=0; \ + _r->regs[4]=0; _r->regs[5]=0; _r->regs[6]=0; _r->regs[7]=0; \ + _r->regs[8]=0; _r->regs[9]=0; _r->regs[10]=0; _r->regs[11]=0; \ + _r->regs[12]=0; _r->regs[13]=0; _r->regs[14]=0; _r->regs[15]=0; \ + _r->regs[16]=0; _r->regs[17]=0; _r->regs[18]=0; _r->regs[19]=0; \ + _r->regs[20]=0; _r->regs[21]=0; _r->regs[22]=0; _r->regs[23]=0; \ + _r->regs[24]=0; _r->regs[25]=0; _r->regs[26]=0; _r->regs[27]=0; \ + _r->regs[28]=0; _r->regs[29]=0; _r->regs[30]=0; _r->regs[31]=0; \ + _r->regs[32]=0; _r->regs[33]=0; _r->regs[34]=0; _r->regs[35]=0; \ + _r->regs[36]=0; _r->regs[37]=0; _r->regs[38]=0; _r->regs[39]=0; \ + _r->regs[40]=0; _r->regs[41]=0; _r->regs[42]=0; _r->regs[43]=0; \ + _r->regs[44]=0; _r->regs[45]=0; _r->regs[46]=0; _r->regs[47]=0; \ + _r->regs[48]=0; _r->regs[49]=0; _r->regs[50]=0; _r->regs[51]=0; \ + _r->regs[52]=0; _r->regs[53]=0; _r->regs[54]=0; _r->regs[55]=0; \ + _r->regs[56]=0; _r->regs[57]=0; _r->regs[58]=0; _r->regs[59]=0; \ + _r->regs[60]=0; _r->regs[61]=0; _r->regs[62]=0; \ + _r->tregs[0]=0; _r->tregs[1]=0; _r->tregs[2]=0; _r->tregs[3]=0; \ + _r->tregs[4]=0; _r->tregs[5]=0; _r->tregs[6]=0; _r->tregs[7]=0; \ + _r->sr = SR_FD | SR_MMU; } while (0) +#else +#define ELF_PLAT_INIT(_r, load_addr) \ + do { _r->regs[0]=0; _r->regs[1]=0; _r->regs[2]=0; _r->regs[3]=0; \ + _r->regs[4]=0; _r->regs[5]=0; _r->regs[6]=0; _r->regs[7]=0; \ + _r->regs[8]=0; _r->regs[9]=0; _r->regs[10]=0; _r->regs[11]=0; \ + _r->regs[12]=0; _r->regs[13]=0; _r->regs[14]=0; \ + _r->sr = SR_FD; } while (0) + +#define ELF_FDPIC_PLAT_INIT(_r, _exec_map_addr, _interp_map_addr, \ + _dynamic_addr) \ +do { \ + _r->regs[0] = 0; \ + _r->regs[1] = 0; \ + _r->regs[2] = 0; \ + _r->regs[3] = 0; \ + _r->regs[4] = 0; \ + _r->regs[5] = 0; \ + _r->regs[6] = 0; \ + _r->regs[7] = 0; \ + _r->regs[8] = _exec_map_addr; \ + _r->regs[9] = _interp_map_addr; \ + _r->regs[10] = _dynamic_addr; \ + _r->regs[11] = 0; \ + _r->regs[12] = 0; \ + _r->regs[13] = 0; \ + _r->regs[14] = 0; \ + _r->sr = SR_FD; \ +} while (0) +#endif + +#define SET_PERSONALITY(ex) \ + set_personality(PER_LINUX_32BIT | (current->personality & (~PER_MASK))) + +#ifdef CONFIG_VSYSCALL +/* vDSO has arch_setup_additional_pages */ +#define ARCH_HAS_SETUP_ADDITIONAL_PAGES +struct linux_binprm; +extern int arch_setup_additional_pages(struct linux_binprm *bprm, + int uses_interp); + +extern unsigned int vdso_enabled; +extern void __kernel_vsyscall; + +#define VDSO_BASE ((unsigned long)current->mm->context.vdso) +#define VDSO_SYM(x) (VDSO_BASE + (unsigned long)(x)) + +#define VSYSCALL_AUX_ENT \ + if (vdso_enabled) \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE); \ + else \ + NEW_AUX_ENT(AT_IGNORE, 0) +#else +#define VSYSCALL_AUX_ENT NEW_AUX_ENT(AT_IGNORE, 0) +#endif /* CONFIG_VSYSCALL */ + +#ifdef CONFIG_SH_FPU +#define FPU_AUX_ENT NEW_AUX_ENT(AT_FPUCW, FPSCR_INIT) +#else +#define FPU_AUX_ENT NEW_AUX_ENT(AT_IGNORE, 0) +#endif + +extern int l1i_cache_shape, l1d_cache_shape, l2_cache_shape; + +/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */ +#define ARCH_DLINFO \ +do { \ + /* Optional FPU initialization */ \ + FPU_AUX_ENT; \ + \ + /* Optional vsyscall entry */ \ + VSYSCALL_AUX_ENT; \ + \ + /* Cache desc */ \ + NEW_AUX_ENT(AT_L1I_CACHESHAPE, l1i_cache_shape); \ + NEW_AUX_ENT(AT_L1D_CACHESHAPE, l1d_cache_shape); \ + NEW_AUX_ENT(AT_L2_CACHESHAPE, l2_cache_shape); \ +} while (0) + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_ELF_H */ diff --git a/arch/sh/include/asm/entry-macros.S b/arch/sh/include/asm/entry-macros.S new file mode 100644 index 000000000..cc43a55e1 --- /dev/null +++ b/arch/sh/include/asm/entry-macros.S @@ -0,0 +1,122 @@ +! entry.S macro define + + .macro cli + stc sr, r0 + or #0xf0, r0 + ldc r0, sr + .endm + + .macro sti + mov #0xfffffff0, r11 + extu.b r11, r11 + not r11, r11 + stc sr, r10 + and r11, r10 +#ifdef CONFIG_CPU_HAS_SR_RB + stc k_g_imask, r11 + or r11, r10 +#endif + ldc r10, sr + .endm + + .macro get_current_thread_info, ti, tmp +#ifdef CONFIG_CPU_HAS_SR_RB + stc r7_bank, \ti +#else + mov #((THREAD_SIZE - 1) >> 10) ^ 0xff, \tmp + shll8 \tmp + shll2 \tmp + mov r15, \ti + and \tmp, \ti +#endif + .endm + +#ifdef CONFIG_TRACE_IRQFLAGS + + .macro TRACE_IRQS_ON + mov.l r0, @-r15 + mov.l r1, @-r15 + mov.l r2, @-r15 + mov.l r3, @-r15 + mov.l r4, @-r15 + mov.l r5, @-r15 + mov.l r6, @-r15 + mov.l r7, @-r15 + + mov.l 7834f, r0 + jsr @r0 + nop + + mov.l @r15+, r7 + mov.l @r15+, r6 + mov.l @r15+, r5 + mov.l @r15+, r4 + mov.l @r15+, r3 + mov.l @r15+, r2 + mov.l @r15+, r1 + mov.l @r15+, r0 + mov.l 7834f, r0 + + bra 7835f + nop + .balign 4 +7834: .long trace_hardirqs_on +7835: + .endm + .macro TRACE_IRQS_OFF + + mov.l r0, @-r15 + mov.l r1, @-r15 + mov.l r2, @-r15 + mov.l r3, @-r15 + mov.l r4, @-r15 + mov.l r5, @-r15 + mov.l r6, @-r15 + mov.l r7, @-r15 + + mov.l 7834f, r0 + jsr @r0 + nop + + mov.l @r15+, r7 + mov.l @r15+, r6 + mov.l @r15+, r5 + mov.l @r15+, r4 + mov.l @r15+, r3 + mov.l @r15+, r2 + mov.l @r15+, r1 + mov.l @r15+, r0 + mov.l 7834f, r0 + + bra 7835f + nop + .balign 4 +7834: .long trace_hardirqs_off +7835: + .endm + +#else + .macro TRACE_IRQS_ON + .endm + + .macro TRACE_IRQS_OFF + .endm +#endif + +#if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH4) +# define PREF(x) pref @x +#else +# define PREF(x) nop +#endif + + /* + * Macro for use within assembly. Because the DWARF unwinder + * needs to use the frame register to unwind the stack, we + * need to setup r14 with the value of the stack pointer as + * the return address is usually on the stack somewhere. + */ + .macro setup_frame_reg +#ifdef CONFIG_DWARF_UNWINDER + mov r15, r14 +#endif + .endm diff --git a/arch/sh/include/asm/fb.h b/arch/sh/include/asm/fb.h new file mode 100644 index 000000000..d92e99cd8 --- /dev/null +++ b/arch/sh/include/asm/fb.h @@ -0,0 +1,19 @@ +#ifndef _ASM_FB_H_ +#define _ASM_FB_H_ + +#include <linux/fb.h> +#include <linux/fs.h> +#include <asm/page.h> + +static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma, + unsigned long off) +{ + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); +} + +static inline int fb_is_primary_device(struct fb_info *info) +{ + return 0; +} + +#endif /* _ASM_FB_H_ */ diff --git a/arch/sh/include/asm/fixmap.h b/arch/sh/include/asm/fixmap.h new file mode 100644 index 000000000..4daf91c3b --- /dev/null +++ b/arch/sh/include/asm/fixmap.h @@ -0,0 +1,101 @@ +/* + * fixmap.h: compile-time virtual memory allocation + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1998 Ingo Molnar + * + * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 + */ + +#ifndef _ASM_FIXMAP_H +#define _ASM_FIXMAP_H + +#include <linux/kernel.h> +#include <linux/threads.h> +#include <asm/page.h> +#ifdef CONFIG_HIGHMEM +#include <asm/kmap_types.h> +#endif + +/* + * Here we define all the compile-time 'special' virtual + * addresses. The point is to have a constant address at + * compile time, but to set the physical address only + * in the boot process. We allocate these special addresses + * from the end of P3 backwards. + * Also this lets us do fail-safe vmalloc(), we + * can guarantee that these special addresses and + * vmalloc()-ed addresses never overlap. + * + * these 'compile-time allocated' memory buffers are + * fixed-size 4k pages. (or larger if used with an increment + * highger than 1) use fixmap_set(idx,phys) to associate + * physical memory with fixmap indices. + * + * TLB entries of such buffers will not be flushed across + * task switches. + */ + +/* + * on UP currently we will have no trace of the fixmap mechanizm, + * no page table allocations, etc. This might change in the + * future, say framebuffers for the console driver(s) could be + * fix-mapped? + */ +enum fixed_addresses { + /* + * The FIX_CMAP entries are used by kmap_coherent() to get virtual + * addresses which are of a known color, and so their values are + * important. __fix_to_virt(FIX_CMAP_END - n) must give an address + * which is the same color as a page (n<<PAGE_SHIFT). + */ +#define FIX_N_COLOURS 8 + FIX_CMAP_BEGIN, + FIX_CMAP_END = FIX_CMAP_BEGIN + (FIX_N_COLOURS * NR_CPUS) - 1, + +#ifdef CONFIG_HIGHMEM + FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ + FIX_KMAP_END = FIX_KMAP_BEGIN + (KM_TYPE_NR * NR_CPUS) - 1, +#endif + +#ifdef CONFIG_IOREMAP_FIXED + /* + * FIX_IOREMAP entries are useful for mapping physical address + * space before ioremap() is useable, e.g. really early in boot + * before kmalloc() is working. + */ +#define FIX_N_IOREMAPS 32 + FIX_IOREMAP_BEGIN, + FIX_IOREMAP_END = FIX_IOREMAP_BEGIN + FIX_N_IOREMAPS - 1, +#endif + + __end_of_fixed_addresses +}; + +extern void __set_fixmap(enum fixed_addresses idx, + unsigned long phys, pgprot_t flags); +extern void __clear_fixmap(enum fixed_addresses idx, pgprot_t flags); + +/* + * used by vmalloc.c. + * + * Leave one empty page between vmalloc'ed areas and + * the start of the fixmap, and leave one page empty + * at the top of mem.. + */ +#ifdef CONFIG_SUPERH32 +#define FIXADDR_TOP (P4SEG - PAGE_SIZE) +#else +#define FIXADDR_TOP ((unsigned long)(-PAGE_SIZE)) +#endif +#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) +#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) + +#define FIXMAP_PAGE_NOCACHE PAGE_KERNEL_NOCACHE + +#include <asm-generic/fixmap.h> + +#endif diff --git a/arch/sh/include/asm/flat.h b/arch/sh/include/asm/flat.h new file mode 100644 index 000000000..5d84df5e2 --- /dev/null +++ b/arch/sh/include/asm/flat.h @@ -0,0 +1,30 @@ +/* + * include/asm-sh/flat.h + * + * uClinux flat-format executables + * + * 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_SH_FLAT_H +#define __ASM_SH_FLAT_H + +#define flat_argvp_envp_on_stack() 0 +#define flat_old_ram_flag(flags) (flags) +#define flat_reloc_valid(reloc, size) ((reloc) <= (size)) +#define flat_get_addr_from_rp(rp, relval, flags, p) get_unaligned(rp) +#define flat_put_addr_at_rp(rp, val, relval) put_unaligned(val,rp) +#define flat_get_relocate_addr(rel) (rel) +#define flat_set_persistent(relval, p) ({ (void)p; 0; }) + +#define FLAT_PLAT_INIT(_r) \ + do { _r->regs[0]=0; _r->regs[1]=0; _r->regs[2]=0; _r->regs[3]=0; \ + _r->regs[4]=0; _r->regs[5]=0; _r->regs[6]=0; _r->regs[7]=0; \ + _r->regs[8]=0; _r->regs[9]=0; _r->regs[10]=0; _r->regs[11]=0; \ + _r->regs[12]=0; _r->regs[13]=0; _r->regs[14]=0; \ + _r->sr = SR_FD; } while (0) + +#endif /* __ASM_SH_FLAT_H */ diff --git a/arch/sh/include/asm/fpu.h b/arch/sh/include/asm/fpu.h new file mode 100644 index 000000000..09fc2bc8a --- /dev/null +++ b/arch/sh/include/asm/fpu.h @@ -0,0 +1,71 @@ +#ifndef __ASM_SH_FPU_H +#define __ASM_SH_FPU_H + +#ifndef __ASSEMBLY__ + +struct task_struct; + +#ifdef CONFIG_SH_FPU +static inline void release_fpu(struct pt_regs *regs) +{ + regs->sr |= SR_FD; +} + +static inline void grab_fpu(struct pt_regs *regs) +{ + regs->sr &= ~SR_FD; +} + +extern void save_fpu(struct task_struct *__tsk); +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 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, + unsigned int pos, unsigned int count, + void *kbuf, void __user *ubuf); + +static inline void __unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs) +{ + if (task_thread_info(tsk)->status & TS_USEDFPU) { + task_thread_info(tsk)->status &= ~TS_USEDFPU; + save_fpu(tsk); + release_fpu(regs); + } else + tsk->thread.fpu_counter = 0; +} + +static inline void unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs) +{ + preempt_disable(); + __unlazy_fpu(tsk, regs); + preempt_enable(); +} + +static inline void clear_fpu(struct task_struct *tsk, struct pt_regs *regs) +{ + preempt_disable(); + if (task_thread_info(tsk)->status & TS_USEDFPU) { + task_thread_info(tsk)->status &= ~TS_USEDFPU; + release_fpu(regs); + } + preempt_enable(); +} + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_SH_FPU_H */ diff --git a/arch/sh/include/asm/freq.h b/arch/sh/include/asm/freq.h new file mode 100644 index 000000000..4ece90b09 --- /dev/null +++ b/arch/sh/include/asm/freq.h @@ -0,0 +1,18 @@ +/* + * include/asm-sh/freq.h + * + * Copyright (C) 2002, 2003 Paul Mundt + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef __ASM_SH_FREQ_H +#define __ASM_SH_FREQ_H +#ifdef __KERNEL__ + +#include <cpu/freq.h> + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_FREQ_H */ diff --git a/arch/sh/include/asm/ftrace.h b/arch/sh/include/asm/ftrace.h new file mode 100644 index 000000000..e79fb6eba --- /dev/null +++ b/arch/sh/include/asm/ftrace.h @@ -0,0 +1,47 @@ +#ifndef __ASM_SH_FTRACE_H +#define __ASM_SH_FTRACE_H + +#ifdef CONFIG_FUNCTION_TRACER + +#define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ +#define FTRACE_SYSCALL_MAX NR_syscalls + +#ifndef __ASSEMBLY__ +extern void mcount(void); + +#define MCOUNT_ADDR ((long)(mcount)) + +#ifdef CONFIG_DYNAMIC_FTRACE +#define CALL_ADDR ((long)(ftrace_call)) +#define STUB_ADDR ((long)(ftrace_stub)) +#define GRAPH_ADDR ((long)(ftrace_graph_call)) +#define CALLER_ADDR ((long)(ftrace_caller)) + +#define MCOUNT_INSN_OFFSET ((STUB_ADDR - CALL_ADDR) - 4) +#define GRAPH_INSN_OFFSET ((CALLER_ADDR - GRAPH_ADDR) - 4) + +struct dyn_arch_ftrace { + /* No extra data needed on sh */ +}; + +#endif /* CONFIG_DYNAMIC_FTRACE */ + +static inline unsigned long ftrace_call_adjust(unsigned long addr) +{ + /* 'addr' is the memory table address. */ + return addr; +} + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_FUNCTION_TRACER */ + +#ifndef __ASSEMBLY__ + +/* arch/sh/kernel/return_address.c */ +extern void *return_address(unsigned int); + +#define ftrace_return_address(n) return_address(n) + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_SH_FTRACE_H */ diff --git a/arch/sh/include/asm/futex-irq.h b/arch/sh/include/asm/futex-irq.h new file mode 100644 index 000000000..63d33129e --- /dev/null +++ b/arch/sh/include/asm/futex-irq.h @@ -0,0 +1,110 @@ +#ifndef __ASM_SH_FUTEX_IRQ_H +#define __ASM_SH_FUTEX_IRQ_H + + +static inline int atomic_futex_op_xchg_set(int oparg, u32 __user *uaddr, + int *oldval) +{ + unsigned long flags; + int ret; + + local_irq_save(flags); + + ret = get_user(*oldval, uaddr); + if (!ret) + ret = put_user(oparg, uaddr); + + local_irq_restore(flags); + + return ret; +} + +static inline int atomic_futex_op_xchg_add(int oparg, u32 __user *uaddr, + int *oldval) +{ + unsigned long flags; + int ret; + + local_irq_save(flags); + + ret = get_user(*oldval, uaddr); + if (!ret) + ret = put_user(*oldval + oparg, uaddr); + + local_irq_restore(flags); + + return ret; +} + +static inline int atomic_futex_op_xchg_or(int oparg, u32 __user *uaddr, + int *oldval) +{ + unsigned long flags; + int ret; + + local_irq_save(flags); + + ret = get_user(*oldval, uaddr); + if (!ret) + ret = put_user(*oldval | oparg, uaddr); + + local_irq_restore(flags); + + return ret; +} + +static inline int atomic_futex_op_xchg_and(int oparg, u32 __user *uaddr, + int *oldval) +{ + unsigned long flags; + int ret; + + local_irq_save(flags); + + ret = get_user(*oldval, uaddr); + if (!ret) + ret = put_user(*oldval & oparg, uaddr); + + local_irq_restore(flags); + + return ret; +} + +static inline int atomic_futex_op_xchg_xor(int oparg, u32 __user *uaddr, + int *oldval) +{ + unsigned long flags; + int ret; + + local_irq_save(flags); + + ret = get_user(*oldval, uaddr); + if (!ret) + ret = put_user(*oldval ^ oparg, uaddr); + + local_irq_restore(flags); + + return ret; +} + +static inline int atomic_futex_op_cmpxchg_inatomic(u32 *uval, + u32 __user *uaddr, + u32 oldval, u32 newval) +{ + unsigned long flags; + int ret; + u32 prev = 0; + + local_irq_save(flags); + + ret = get_user(prev, uaddr); + if (!ret && oldval == prev) + ret = put_user(newval, uaddr); + + local_irq_restore(flags); + + *uval = prev; + return ret; +} + +#endif /* __ASM_SH_FUTEX_IRQ_H */ diff --git a/arch/sh/include/asm/futex.h b/arch/sh/include/asm/futex.h new file mode 100644 index 000000000..7be39a646 --- /dev/null +++ b/arch/sh/include/asm/futex.h @@ -0,0 +1,78 @@ +#ifndef __ASM_SH_FUTEX_H +#define __ASM_SH_FUTEX_H + +#ifdef __KERNEL__ + +#include <linux/futex.h> +#include <linux/uaccess.h> +#include <asm/errno.h> + +/* XXX: UP variants, fix for SH-4A and SMP.. */ +#include <asm/futex-irq.h> + +static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) +{ + int op = (encoded_op >> 28) & 7; + int cmp = (encoded_op >> 24) & 15; + int oparg = (encoded_op << 8) >> 20; + int cmparg = (encoded_op << 20) >> 20; + int oldval = 0, ret; + + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) + oparg = 1 << oparg; + + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) + return -EFAULT; + + pagefault_disable(); + + switch (op) { + case FUTEX_OP_SET: + ret = atomic_futex_op_xchg_set(oparg, uaddr, &oldval); + break; + case FUTEX_OP_ADD: + ret = atomic_futex_op_xchg_add(oparg, uaddr, &oldval); + break; + case FUTEX_OP_OR: + ret = atomic_futex_op_xchg_or(oparg, uaddr, &oldval); + break; + case FUTEX_OP_ANDN: + ret = atomic_futex_op_xchg_and(~oparg, uaddr, &oldval); + break; + case FUTEX_OP_XOR: + ret = atomic_futex_op_xchg_xor(oparg, uaddr, &oldval); + break; + default: + ret = -ENOSYS; + break; + } + + pagefault_enable(); + + if (!ret) { + switch (cmp) { + case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; + case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; + case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; + case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; + case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; + case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; + default: ret = -ENOSYS; + } + } + + return ret; +} + +static inline int +futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, + u32 oldval, u32 newval) +{ + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) + return -EFAULT; + + return atomic_futex_op_cmpxchg_inatomic(uval, uaddr, oldval, newval); +} + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_FUTEX_H */ diff --git a/arch/sh/include/asm/gpio.h b/arch/sh/include/asm/gpio.h new file mode 100644 index 000000000..7dfe15e2e --- /dev/null +++ b/arch/sh/include/asm/gpio.h @@ -0,0 +1,54 @@ +/* + * include/asm-sh/gpio.h + * + * Generic GPIO API and pinmux table support for SuperH. + * + * Copyright (c) 2008 Magnus Damm + * + * 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_GPIO_H +#define __ASM_SH_GPIO_H + +#include <linux/kernel.h> +#include <linux/errno.h> + +#if defined(CONFIG_CPU_SH3) +#include <cpu/gpio.h> +#endif + +#define ARCH_NR_GPIOS 512 +#include <asm-generic/gpio.h> + +#ifdef CONFIG_GPIOLIB + +static inline int gpio_get_value(unsigned gpio) +{ + return __gpio_get_value(gpio); +} + +static inline void gpio_set_value(unsigned gpio, int value) +{ + __gpio_set_value(gpio, value); +} + +static inline int gpio_cansleep(unsigned gpio) +{ + return __gpio_cansleep(gpio); +} + +static inline int gpio_to_irq(unsigned gpio) +{ + return __gpio_to_irq(gpio); +} + +static inline int irq_to_gpio(unsigned int irq) +{ + return -ENOSYS; +} + +#endif /* CONFIG_GPIOLIB */ + +#endif /* __ASM_SH_GPIO_H */ diff --git a/arch/sh/include/asm/hardirq.h b/arch/sh/include/asm/hardirq.h new file mode 100644 index 000000000..48b191313 --- /dev/null +++ b/arch/sh/include/asm/hardirq.h @@ -0,0 +1,16 @@ +#ifndef __ASM_SH_HARDIRQ_H +#define __ASM_SH_HARDIRQ_H + +#include <linux/threads.h> +#include <linux/irq.h> + +typedef struct { + unsigned int __softirq_pending; + unsigned int __nmi_count; /* arch dependent */ +} ____cacheline_aligned irq_cpustat_t; + +#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ + +extern void ack_bad_irq(unsigned int irq); + +#endif /* __ASM_SH_HARDIRQ_H */ diff --git a/arch/sh/include/asm/hd64461.h b/arch/sh/include/asm/hd64461.h new file mode 100644 index 000000000..977355f0a --- /dev/null +++ b/arch/sh/include/asm/hd64461.h @@ -0,0 +1,251 @@ +#ifndef __ASM_SH_HD64461 +#define __ASM_SH_HD64461 +/* + * Copyright (C) 2007 Kristoffer Ericson <Kristoffer.Ericson@gmail.com> + * Copyright (C) 2004 Paul Mundt + * Copyright (C) 2000 YAEGASHI Takeshi + * + * Hitachi HD64461 companion chip support + * (please note manual reference 0x10000000 = 0xb0000000) + */ + +/* Constants for PCMCIA mappings */ +#define HD64461_PCC_WINDOW 0x01000000 + +/* Area 6 - Slot 0 - memory and/or IO card */ +#define HD64461_IOBASE 0xb0000000 +#define HD64461_IO_OFFSET(x) (HD64461_IOBASE + (x)) +#define HD64461_PCC0_BASE HD64461_IO_OFFSET(0x8000000) +#define HD64461_PCC0_ATTR (HD64461_PCC0_BASE) /* 0xb80000000 */ +#define HD64461_PCC0_COMM (HD64461_PCC0_BASE+HD64461_PCC_WINDOW) /* 0xb90000000 */ +#define HD64461_PCC0_IO (HD64461_PCC0_BASE+2*HD64461_PCC_WINDOW) /* 0xba0000000 */ + +/* Area 5 - Slot 1 - memory card only */ +#define HD64461_PCC1_BASE HD64461_IO_OFFSET(0x4000000) +#define HD64461_PCC1_ATTR (HD64461_PCC1_BASE) /* 0xb4000000 */ +#define HD64461_PCC1_COMM (HD64461_PCC1_BASE+HD64461_PCC_WINDOW) /* 0xb5000000 */ + +/* Standby Control Register for HD64461 */ +#define HD64461_STBCR HD64461_IO_OFFSET(0x00000000) +#define HD64461_STBCR_CKIO_STBY 0x2000 +#define HD64461_STBCR_SAFECKE_IST 0x1000 +#define HD64461_STBCR_SLCKE_IST 0x0800 +#define HD64461_STBCR_SAFECKE_OST 0x0400 +#define HD64461_STBCR_SLCKE_OST 0x0200 +#define HD64461_STBCR_SMIAST 0x0100 +#define HD64461_STBCR_SLCDST 0x0080 +#define HD64461_STBCR_SPC0ST 0x0040 +#define HD64461_STBCR_SPC1ST 0x0020 +#define HD64461_STBCR_SAFEST 0x0010 +#define HD64461_STBCR_STM0ST 0x0008 +#define HD64461_STBCR_STM1ST 0x0004 +#define HD64461_STBCR_SIRST 0x0002 +#define HD64461_STBCR_SURTST 0x0001 + +/* System Configuration Register */ +#define HD64461_SYSCR HD64461_IO_OFFSET(0x02) + +/* CPU Data Bus Control Register */ +#define HD64461_SCPUCR HD64461_IO_OFFSET(0x04) + +/* Base Address Register */ +#define HD64461_LCDCBAR HD64461_IO_OFFSET(0x1000) + +/* Line increment address */ +#define HD64461_LCDCLOR HD64461_IO_OFFSET(0x1002) + +/* Controls LCD controller */ +#define HD64461_LCDCCR HD64461_IO_OFFSET(0x1004) + +/* LCCDR control bits */ +#define HD64461_LCDCCR_STBACK 0x0400 /* Standby Back */ +#define HD64461_LCDCCR_STREQ 0x0100 /* Standby Request */ +#define HD64461_LCDCCR_MOFF 0x0080 /* Memory Off */ +#define HD64461_LCDCCR_REFSEL 0x0040 /* Refresh Select */ +#define HD64461_LCDCCR_EPON 0x0020 /* End Power On */ +#define HD64461_LCDCCR_SPON 0x0010 /* Start Power On */ + +/* Controls LCD (1) */ +#define HD64461_LDR1 HD64461_IO_OFFSET(0x1010) +#define HD64461_LDR1_DON 0x01 /* Display On */ +#define HD64461_LDR1_DINV 0x80 /* Display Invert */ + +/* Controls LCD (2) */ +#define HD64461_LDR2 HD64461_IO_OFFSET(0x1012) +#define HD64461_LDHNCR HD64461_IO_OFFSET(0x1014) /* Number of horizontal characters */ +#define HD64461_LDHNSR HD64461_IO_OFFSET(0x1016) /* Specify output start position + width of CL1 */ +#define HD64461_LDVNTR HD64461_IO_OFFSET(0x1018) /* Specify total vertical lines */ +#define HD64461_LDVNDR HD64461_IO_OFFSET(0x101a) /* specify number of display vertical lines */ +#define HD64461_LDVSPR HD64461_IO_OFFSET(0x101c) /* specify vertical synchronization pos and AC nr */ + +/* Controls LCD (3) */ +#define HD64461_LDR3 HD64461_IO_OFFSET(0x101e) + +/* Palette Registers */ +#define HD64461_CPTWAR HD64461_IO_OFFSET(0x1030) /* Color Palette Write Address Register */ +#define HD64461_CPTWDR HD64461_IO_OFFSET(0x1032) /* Color Palette Write Data Register */ +#define HD64461_CPTRAR HD64461_IO_OFFSET(0x1034) /* Color Palette Read Address Register */ +#define HD64461_CPTRDR HD64461_IO_OFFSET(0x1036) /* Color Palette Read Data Register */ + +#define HD64461_GRDOR HD64461_IO_OFFSET(0x1040) /* Display Resolution Offset Register */ +#define HD64461_GRSCR HD64461_IO_OFFSET(0x1042) /* Solid Color Register */ +#define HD64461_GRCFGR HD64461_IO_OFFSET(0x1044) /* Accelerator Configuration Register */ + +#define HD64461_GRCFGR_ACCSTATUS 0x10 /* Accelerator Status */ +#define HD64461_GRCFGR_ACCRESET 0x08 /* Accelerator Reset */ +#define HD64461_GRCFGR_ACCSTART_BITBLT 0x06 /* Accelerator Start BITBLT */ +#define HD64461_GRCFGR_ACCSTART_LINE 0x04 /* Accelerator Start Line Drawing */ +#define HD64461_GRCFGR_COLORDEPTH16 0x01 /* Sets Colordepth 16 for Accelerator */ +#define HD64461_GRCFGR_COLORDEPTH8 0x01 /* Sets Colordepth 8 for Accelerator */ + +/* Line Drawing Registers */ +#define HD64461_LNSARH HD64461_IO_OFFSET(0x1046) /* Line Start Address Register (H) */ +#define HD64461_LNSARL HD64461_IO_OFFSET(0x1048) /* Line Start Address Register (L) */ +#define HD64461_LNAXLR HD64461_IO_OFFSET(0x104a) /* Axis Pixel Length Register */ +#define HD64461_LNDGR HD64461_IO_OFFSET(0x104c) /* Diagonal Register */ +#define HD64461_LNAXR HD64461_IO_OFFSET(0x104e) /* Axial Register */ +#define HD64461_LNERTR HD64461_IO_OFFSET(0x1050) /* Start Error Term Register */ +#define HD64461_LNMDR HD64461_IO_OFFSET(0x1052) /* Line Mode Register */ + +/* BitBLT Registers */ +#define HD64461_BBTSSARH HD64461_IO_OFFSET(0x1054) /* Source Start Address Register (H) */ +#define HD64461_BBTSSARL HD64461_IO_OFFSET(0x1056) /* Source Start Address Register (L) */ +#define HD64461_BBTDSARH HD64461_IO_OFFSET(0x1058) /* Destination Start Address Register (H) */ +#define HD64461_BBTDSARL HD64461_IO_OFFSET(0x105a) /* Destination Start Address Register (L) */ +#define HD64461_BBTDWR HD64461_IO_OFFSET(0x105c) /* Destination Block Width Register */ +#define HD64461_BBTDHR HD64461_IO_OFFSET(0x105e) /* Destination Block Height Register */ +#define HD64461_BBTPARH HD64461_IO_OFFSET(0x1060) /* Pattern Start Address Register (H) */ +#define HD64461_BBTPARL HD64461_IO_OFFSET(0x1062) /* Pattern Start Address Register (L) */ +#define HD64461_BBTMARH HD64461_IO_OFFSET(0x1064) /* Mask Start Address Register (H) */ +#define HD64461_BBTMARL HD64461_IO_OFFSET(0x1066) /* Mask Start Address Register (L) */ +#define HD64461_BBTROPR HD64461_IO_OFFSET(0x1068) /* ROP Register */ +#define HD64461_BBTMDR HD64461_IO_OFFSET(0x106a) /* BitBLT Mode Register */ + +/* PC Card Controller Registers */ +/* Maps to Physical Area 6 */ +#define HD64461_PCC0ISR HD64461_IO_OFFSET(0x2000) /* socket 0 interface status */ +#define HD64461_PCC0GCR HD64461_IO_OFFSET(0x2002) /* socket 0 general control */ +#define HD64461_PCC0CSCR HD64461_IO_OFFSET(0x2004) /* socket 0 card status change */ +#define HD64461_PCC0CSCIER HD64461_IO_OFFSET(0x2006) /* socket 0 card status change interrupt enable */ +#define HD64461_PCC0SCR HD64461_IO_OFFSET(0x2008) /* socket 0 software control */ +/* Maps to Physical Area 5 */ +#define HD64461_PCC1ISR HD64461_IO_OFFSET(0x2010) /* socket 1 interface status */ +#define HD64461_PCC1GCR HD64461_IO_OFFSET(0x2012) /* socket 1 general control */ +#define HD64461_PCC1CSCR HD64461_IO_OFFSET(0x2014) /* socket 1 card status change */ +#define HD64461_PCC1CSCIER HD64461_IO_OFFSET(0x2016) /* socket 1 card status change interrupt enable */ +#define HD64461_PCC1SCR HD64461_IO_OFFSET(0x2018) /* socket 1 software control */ + +/* PCC Interface Status Register */ +#define HD64461_PCCISR_READY 0x80 /* card ready */ +#define HD64461_PCCISR_MWP 0x40 /* card write-protected */ +#define HD64461_PCCISR_VS2 0x20 /* voltage select pin 2 */ +#define HD64461_PCCISR_VS1 0x10 /* voltage select pin 1 */ +#define HD64461_PCCISR_CD2 0x08 /* card detect 2 */ +#define HD64461_PCCISR_CD1 0x04 /* card detect 1 */ +#define HD64461_PCCISR_BVD2 0x02 /* battery 1 */ +#define HD64461_PCCISR_BVD1 0x01 /* battery 1 */ + +#define HD64461_PCCISR_PCD_MASK 0x0c /* card detect */ +#define HD64461_PCCISR_BVD_MASK 0x03 /* battery voltage */ +#define HD64461_PCCISR_BVD_BATGOOD 0x03 /* battery good */ +#define HD64461_PCCISR_BVD_BATWARN 0x01 /* battery low warning */ +#define HD64461_PCCISR_BVD_BATDEAD1 0x02 /* battery dead */ +#define HD64461_PCCISR_BVD_BATDEAD2 0x00 /* battery dead */ + +/* PCC General Control Register */ +#define HD64461_PCCGCR_DRVE 0x80 /* output drive */ +#define HD64461_PCCGCR_PCCR 0x40 /* PC card reset */ +#define HD64461_PCCGCR_PCCT 0x20 /* PC card type, 1=IO&mem, 0=mem */ +#define HD64461_PCCGCR_VCC0 0x10 /* voltage control pin VCC0SEL0 */ +#define HD64461_PCCGCR_PMMOD 0x08 /* memory mode */ +#define HD64461_PCCGCR_PA25 0x04 /* pin A25 */ +#define HD64461_PCCGCR_PA24 0x02 /* pin A24 */ +#define HD64461_PCCGCR_REG 0x01 /* pin PCC0REG# */ + +/* PCC Card Status Change Register */ +#define HD64461_PCCCSCR_SCDI 0x80 /* sw card detect intr */ +#define HD64461_PCCCSCR_SRV1 0x40 /* reserved */ +#define HD64461_PCCCSCR_IREQ 0x20 /* IREQ intr req */ +#define HD64461_PCCCSCR_SC 0x10 /* STSCHG (status change) pin */ +#define HD64461_PCCCSCR_CDC 0x08 /* CD (card detect) change */ +#define HD64461_PCCCSCR_RC 0x04 /* READY change */ +#define HD64461_PCCCSCR_BW 0x02 /* battery warning change */ +#define HD64461_PCCCSCR_BD 0x01 /* battery dead change */ + +/* PCC Card Status Change Interrupt Enable Register */ +#define HD64461_PCCCSCIER_CRE 0x80 /* change reset enable */ +#define HD64461_PCCCSCIER_IREQE_MASK 0x60 /* IREQ enable */ +#define HD64461_PCCCSCIER_IREQE_DISABLED 0x00 /* IREQ disabled */ +#define HD64461_PCCCSCIER_IREQE_LEVEL 0x20 /* IREQ level-triggered */ +#define HD64461_PCCCSCIER_IREQE_FALLING 0x40 /* IREQ falling-edge-trig */ +#define HD64461_PCCCSCIER_IREQE_RISING 0x60 /* IREQ rising-edge-trig */ + +#define HD64461_PCCCSCIER_SCE 0x10 /* status change enable */ +#define HD64461_PCCCSCIER_CDE 0x08 /* card detect change enable */ +#define HD64461_PCCCSCIER_RE 0x04 /* ready change enable */ +#define HD64461_PCCCSCIER_BWE 0x02 /* battery warn change enable */ +#define HD64461_PCCCSCIER_BDE 0x01 /* battery dead change enable*/ + +/* PCC Software Control Register */ +#define HD64461_PCCSCR_VCC1 0x02 /* voltage control pin 1 */ +#define HD64461_PCCSCR_SWP 0x01 /* write protect */ + +/* PCC0 Output Pins Control Register */ +#define HD64461_P0OCR HD64461_IO_OFFSET(0x202a) + +/* PCC1 Output Pins Control Register */ +#define HD64461_P1OCR HD64461_IO_OFFSET(0x202c) + +/* PC Card General Control Register */ +#define HD64461_PGCR HD64461_IO_OFFSET(0x202e) + +/* Port Control Registers */ +#define HD64461_GPACR HD64461_IO_OFFSET(0x4000) /* Port A - Handles IRDA/TIMER */ +#define HD64461_GPBCR HD64461_IO_OFFSET(0x4002) /* Port B - Handles UART */ +#define HD64461_GPCCR HD64461_IO_OFFSET(0x4004) /* Port C - Handles PCMCIA 1 */ +#define HD64461_GPDCR HD64461_IO_OFFSET(0x4006) /* Port D - Handles PCMCIA 1 */ + +/* Port Control Data Registers */ +#define HD64461_GPADR HD64461_IO_OFFSET(0x4010) /* A */ +#define HD64461_GPBDR HD64461_IO_OFFSET(0x4012) /* B */ +#define HD64461_GPCDR HD64461_IO_OFFSET(0x4014) /* C */ +#define HD64461_GPDDR HD64461_IO_OFFSET(0x4016) /* D */ + +/* Interrupt Control Registers */ +#define HD64461_GPAICR HD64461_IO_OFFSET(0x4020) /* A */ +#define HD64461_GPBICR HD64461_IO_OFFSET(0x4022) /* B */ +#define HD64461_GPCICR HD64461_IO_OFFSET(0x4024) /* C */ +#define HD64461_GPDICR HD64461_IO_OFFSET(0x4026) /* D */ + +/* Interrupt Status Registers */ +#define HD64461_GPAISR HD64461_IO_OFFSET(0x4040) /* A */ +#define HD64461_GPBISR HD64461_IO_OFFSET(0x4042) /* B */ +#define HD64461_GPCISR HD64461_IO_OFFSET(0x4044) /* C */ +#define HD64461_GPDISR HD64461_IO_OFFSET(0x4046) /* D */ + +/* Interrupt Request Register & Interrupt Mask Register */ +#define HD64461_NIRR HD64461_IO_OFFSET(0x5000) +#define HD64461_NIMR HD64461_IO_OFFSET(0x5002) + +#define HD64461_IRQBASE OFFCHIP_IRQ_BASE +#define OFFCHIP_IRQ_BASE 64 +#define HD64461_IRQ_NUM 16 + +#define HD64461_IRQ_UART (HD64461_IRQBASE+5) +#define HD64461_IRQ_IRDA (HD64461_IRQBASE+6) +#define HD64461_IRQ_TMU1 (HD64461_IRQBASE+9) +#define HD64461_IRQ_TMU0 (HD64461_IRQBASE+10) +#define HD64461_IRQ_GPIO (HD64461_IRQBASE+11) +#define HD64461_IRQ_AFE (HD64461_IRQBASE+12) +#define HD64461_IRQ_PCC1 (HD64461_IRQBASE+13) +#define HD64461_IRQ_PCC0 (HD64461_IRQBASE+14) + +#define __IO_PREFIX hd64461 +#include <asm/io_generic.h> + +/* arch/sh/cchips/hd6446x/hd64461/setup.c */ +void hd64461_register_irq_demux(int irq, + int (*demux) (int irq, void *dev), void *dev); +void hd64461_unregister_irq_demux(int irq); + +#endif diff --git a/arch/sh/include/asm/heartbeat.h b/arch/sh/include/asm/heartbeat.h new file mode 100644 index 000000000..caaafe5a3 --- /dev/null +++ b/arch/sh/include/asm/heartbeat.h @@ -0,0 +1,18 @@ +#ifndef __ASM_SH_HEARTBEAT_H +#define __ASM_SH_HEARTBEAT_H + +#include <linux/timer.h> + +#define HEARTBEAT_INVERTED (1 << 0) + +struct heartbeat_data { + void __iomem *base; + unsigned char *bit_pos; + unsigned int nr_bits; + struct timer_list timer; + unsigned int regsize; + unsigned int mask; + unsigned long flags; +}; + +#endif /* __ASM_SH_HEARTBEAT_H */ diff --git a/arch/sh/include/asm/hugetlb.h b/arch/sh/include/asm/hugetlb.h new file mode 100644 index 000000000..699255d6d --- /dev/null +++ b/arch/sh/include/asm/hugetlb.h @@ -0,0 +1,99 @@ +#ifndef _ASM_SH_HUGETLB_H +#define _ASM_SH_HUGETLB_H + +#include <asm/cacheflush.h> +#include <asm/page.h> +#include <asm-generic/hugetlb.h> + + +static inline int is_hugepage_only_range(struct mm_struct *mm, + unsigned long addr, + unsigned long len) { + return 0; +} + +/* + * If the arch doesn't supply something else, assume that hugepage + * size aligned regions are ok without further preparation. + */ +static inline int prepare_hugepage_range(struct file *file, + unsigned long addr, unsigned long len) +{ + if (len & ~HPAGE_MASK) + return -EINVAL; + if (addr & ~HPAGE_MASK) + return -EINVAL; + return 0; +} + +static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm) { +} + +static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb, + unsigned long addr, unsigned long end, + unsigned long floor, + unsigned long ceiling) +{ + free_pgd_range(tlb, addr, end, floor, ceiling); +} + +static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, + pte_t *ptep, pte_t pte) +{ + set_pte_at(mm, addr, ptep, pte); +} + +static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + return ptep_get_and_clear(mm, addr, ptep); +} + +static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) +{ +} + +static inline int huge_pte_none(pte_t pte) +{ + return pte_none(pte); +} + +static inline pte_t huge_pte_wrprotect(pte_t pte) +{ + return pte_wrprotect(pte); +} + +static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, + unsigned long addr, pte_t *ptep) +{ + ptep_set_wrprotect(mm, addr, ptep); +} + +static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep, + pte_t pte, int dirty) +{ + return ptep_set_access_flags(vma, addr, ptep, pte, dirty); +} + +static inline pte_t huge_ptep_get(pte_t *ptep) +{ + return *ptep; +} + +static inline int arch_prepare_hugepage(struct page *page) +{ + return 0; +} + +static inline void arch_release_hugepage(struct page *page) +{ +} + +static inline void arch_clear_hugepage_flags(struct page *page) +{ + clear_bit(PG_dcache_clean, &page->flags); +} + +#endif /* _ASM_SH_HUGETLB_H */ diff --git a/arch/sh/include/asm/hw_breakpoint.h b/arch/sh/include/asm/hw_breakpoint.h new file mode 100644 index 000000000..ec9ad593c --- /dev/null +++ b/arch/sh/include/asm/hw_breakpoint.h @@ -0,0 +1,70 @@ +#ifndef __ASM_SH_HW_BREAKPOINT_H +#define __ASM_SH_HW_BREAKPOINT_H + +#include <uapi/asm/hw_breakpoint.h> + +#define __ARCH_HW_BREAKPOINT_H + +#include <linux/kdebug.h> +#include <linux/types.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 + +static inline int hw_breakpoint_slots(int type) +{ + return HBP_NUM; +} + +/* arch/sh/kernel/hw_breakpoint.c */ +extern int arch_check_bp_in_kernelspace(struct perf_event *bp); +extern int arch_validate_hwbkpt_settings(struct perf_event *bp); +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); + +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 /* __ASM_SH_HW_BREAKPOINT_H */ diff --git a/arch/sh/include/asm/hw_irq.h b/arch/sh/include/asm/hw_irq.h new file mode 100644 index 000000000..693d44184 --- /dev/null +++ b/arch/sh/include/asm/hw_irq.h @@ -0,0 +1,35 @@ +#ifndef __ASM_SH_HW_IRQ_H +#define __ASM_SH_HW_IRQ_H + +#include <linux/init.h> +#include <linux/sh_intc.h> +#include <linux/atomic.h> + +extern atomic_t irq_err_count; + +struct ipr_data { + unsigned char irq; + unsigned char ipr_idx; /* Index for the IPR registered */ + unsigned char shift; /* Number of bits to shift the data */ + unsigned char priority; /* The priority */ +}; + +struct ipr_desc { + unsigned long *ipr_offsets; + unsigned int nr_offsets; + struct ipr_data *ipr_data; + unsigned int nr_irqs; + struct irq_chip chip; +}; + +void register_ipr_controller(struct ipr_desc *); + +void __init plat_irq_setup(void); +void __init plat_irq_setup_sh3(void); +void __init plat_irq_setup_pins(int mode); + +enum { IRQ_MODE_IRQ, IRQ_MODE_IRQ7654, IRQ_MODE_IRQ3210, + IRQ_MODE_IRL7654_MASK, IRQ_MODE_IRL3210_MASK, + IRQ_MODE_IRL7654, IRQ_MODE_IRL3210 }; + +#endif /* __ASM_SH_HW_IRQ_H */ diff --git a/arch/sh/include/asm/i2c-sh7760.h b/arch/sh/include/asm/i2c-sh7760.h new file mode 100644 index 000000000..69fee1239 --- /dev/null +++ b/arch/sh/include/asm/i2c-sh7760.h @@ -0,0 +1,20 @@ +/* + * MMIO/IRQ and platform data for SH7760 I2C channels + */ + +#ifndef _I2C_SH7760_H_ +#define _I2C_SH7760_H_ + +#define SH7760_I2C_DEVNAME "sh7760-i2c" + +#define SH7760_I2C0_MMIO 0xFE140000 +#define SH7760_I2C0_MMIOEND 0xFE14003B + +#define SH7760_I2C1_MMIO 0xFE150000 +#define SH7760_I2C1_MMIOEND 0xFE15003B + +struct sh7760_i2c_platdata { + unsigned int speed_khz; +}; + +#endif diff --git a/arch/sh/include/asm/io.h b/arch/sh/include/asm/io.h new file mode 100644 index 000000000..728c4c571 --- /dev/null +++ b/arch/sh/include/asm/io.h @@ -0,0 +1,390 @@ +#ifndef __ASM_SH_IO_H +#define __ASM_SH_IO_H + +/* + * Convention: + * read{b,w,l,q}/write{b,w,l,q} are for PCI, + * while in{b,w,l}/out{b,w,l} are for ISA + * + * In addition we have 'pausing' versions: in{b,w,l}_p/out{b,w,l}_p + * and 'string' versions: ins{b,w,l}/outs{b,w,l} + * + * While read{b,w,l,q} and write{b,w,l,q} contain memory barriers + * automatically, there are also __raw versions, which do not. + */ +#include <linux/errno.h> +#include <asm/cache.h> +#include <asm/addrspace.h> +#include <asm/machvec.h> +#include <asm/pgtable.h> +#include <asm-generic/iomap.h> + +#ifdef __KERNEL__ +#define __IO_PREFIX generic +#include <asm/io_generic.h> +#include <asm/io_trapped.h> +#include <mach/mangle-port.h> + +#define __raw_writeb(v,a) (__chk_io_ptr(a), *(volatile u8 __force *)(a) = (v)) +#define __raw_writew(v,a) (__chk_io_ptr(a), *(volatile u16 __force *)(a) = (v)) +#define __raw_writel(v,a) (__chk_io_ptr(a), *(volatile u32 __force *)(a) = (v)) +#define __raw_writeq(v,a) (__chk_io_ptr(a), *(volatile u64 __force *)(a) = (v)) + +#define __raw_readb(a) (__chk_io_ptr(a), *(volatile u8 __force *)(a)) +#define __raw_readw(a) (__chk_io_ptr(a), *(volatile u16 __force *)(a)) +#define __raw_readl(a) (__chk_io_ptr(a), *(volatile u32 __force *)(a)) +#define __raw_readq(a) (__chk_io_ptr(a), *(volatile u64 __force *)(a)) + +#define readb_relaxed(c) ({ u8 __v = ioswabb(__raw_readb(c)); __v; }) +#define readw_relaxed(c) ({ u16 __v = ioswabw(__raw_readw(c)); __v; }) +#define readl_relaxed(c) ({ u32 __v = ioswabl(__raw_readl(c)); __v; }) +#define readq_relaxed(c) ({ u64 __v = ioswabq(__raw_readq(c)); __v; }) + +#define writeb_relaxed(v,c) ((void)__raw_writeb((__force u8)ioswabb(v),c)) +#define writew_relaxed(v,c) ((void)__raw_writew((__force u16)ioswabw(v),c)) +#define writel_relaxed(v,c) ((void)__raw_writel((__force u32)ioswabl(v),c)) +#define writeq_relaxed(v,c) ((void)__raw_writeq((__force u64)ioswabq(v),c)) + +#define readb(a) ({ u8 r_ = readb_relaxed(a); rmb(); r_; }) +#define readw(a) ({ u16 r_ = readw_relaxed(a); rmb(); r_; }) +#define readl(a) ({ u32 r_ = readl_relaxed(a); rmb(); r_; }) +#define readq(a) ({ u64 r_ = readq_relaxed(a); rmb(); r_; }) + +#define writeb(v,a) ({ wmb(); writeb_relaxed((v),(a)); }) +#define writew(v,a) ({ wmb(); writew_relaxed((v),(a)); }) +#define writel(v,a) ({ wmb(); writel_relaxed((v),(a)); }) +#define writeq(v,a) ({ wmb(); writeq_relaxed((v),(a)); }) + +#define readsb(p,d,l) __raw_readsb(p,d,l) +#define readsw(p,d,l) __raw_readsw(p,d,l) +#define readsl(p,d,l) __raw_readsl(p,d,l) + +#define writesb(p,d,l) __raw_writesb(p,d,l) +#define writesw(p,d,l) __raw_writesw(p,d,l) +#define writesl(p,d,l) __raw_writesl(p,d,l) + +#define __BUILD_UNCACHED_IO(bwlq, type) \ +static inline type read##bwlq##_uncached(unsigned long addr) \ +{ \ + type ret; \ + jump_to_uncached(); \ + ret = __raw_read##bwlq(addr); \ + back_to_cached(); \ + return ret; \ +} \ + \ +static inline void write##bwlq##_uncached(type v, unsigned long addr) \ +{ \ + jump_to_uncached(); \ + __raw_write##bwlq(v, addr); \ + back_to_cached(); \ +} + +__BUILD_UNCACHED_IO(b, u8) +__BUILD_UNCACHED_IO(w, u16) +__BUILD_UNCACHED_IO(l, u32) +__BUILD_UNCACHED_IO(q, u64) + +#define __BUILD_MEMORY_STRING(pfx, bwlq, type) \ + \ +static inline void \ +pfx##writes##bwlq(volatile void __iomem *mem, const void *addr, \ + unsigned int count) \ +{ \ + const volatile type *__addr = addr; \ + \ + while (count--) { \ + __raw_write##bwlq(*__addr, mem); \ + __addr++; \ + } \ +} \ + \ +static inline void pfx##reads##bwlq(volatile void __iomem *mem, \ + void *addr, unsigned int count) \ +{ \ + volatile type *__addr = addr; \ + \ + while (count--) { \ + *__addr = __raw_read##bwlq(mem); \ + __addr++; \ + } \ +} + +__BUILD_MEMORY_STRING(__raw_, b, u8) +__BUILD_MEMORY_STRING(__raw_, w, u16) + +#ifdef CONFIG_SUPERH32 +void __raw_writesl(void __iomem *addr, const void *data, int longlen); +void __raw_readsl(const void __iomem *addr, void *data, int longlen); +#else +__BUILD_MEMORY_STRING(__raw_, l, u32) +#endif + +__BUILD_MEMORY_STRING(__raw_, q, u64) + +#ifdef CONFIG_HAS_IOPORT_MAP + +/* + * Slowdown I/O port space accesses for antique hardware. + */ +#undef CONF_SLOWDOWN_IO + +/* + * On SuperH I/O ports are memory mapped, so we access them using normal + * load/store instructions. sh_io_port_base is the virtual address to + * which all ports are being mapped. + */ +extern unsigned long sh_io_port_base; + +static inline void __set_io_port_base(unsigned long pbase) +{ + *(unsigned long *)&sh_io_port_base = pbase; + barrier(); +} + +#ifdef CONFIG_GENERIC_IOMAP +#define __ioport_map ioport_map +#else +extern void __iomem *__ioport_map(unsigned long addr, unsigned int size); +#endif + +#ifdef CONF_SLOWDOWN_IO +#define SLOW_DOWN_IO __raw_readw(sh_io_port_base) +#else +#define SLOW_DOWN_IO +#endif + +#define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, p, slow) \ + \ +static inline void pfx##out##bwlq##p(type val, unsigned long port) \ +{ \ + volatile type *__addr; \ + \ + __addr = __ioport_map(port, sizeof(type)); \ + *__addr = val; \ + slow; \ +} \ + \ +static inline type pfx##in##bwlq##p(unsigned long port) \ +{ \ + volatile type *__addr; \ + type __val; \ + \ + __addr = __ioport_map(port, sizeof(type)); \ + __val = *__addr; \ + slow; \ + \ + return __val; \ +} + +#define __BUILD_IOPORT_PFX(bus, bwlq, type) \ + __BUILD_IOPORT_SINGLE(bus, bwlq, type, ,) \ + __BUILD_IOPORT_SINGLE(bus, bwlq, type, _p, SLOW_DOWN_IO) + +#define BUILDIO_IOPORT(bwlq, type) \ + __BUILD_IOPORT_PFX(, bwlq, type) + +BUILDIO_IOPORT(b, u8) +BUILDIO_IOPORT(w, u16) +BUILDIO_IOPORT(l, u32) +BUILDIO_IOPORT(q, u64) + +#define __BUILD_IOPORT_STRING(bwlq, type) \ + \ +static inline void outs##bwlq(unsigned long port, const void *addr, \ + unsigned int count) \ +{ \ + const volatile type *__addr = addr; \ + \ + while (count--) { \ + out##bwlq(*__addr, port); \ + __addr++; \ + } \ +} \ + \ +static inline void ins##bwlq(unsigned long port, void *addr, \ + unsigned int count) \ +{ \ + volatile type *__addr = addr; \ + \ + while (count--) { \ + *__addr = in##bwlq(port); \ + __addr++; \ + } \ +} + +__BUILD_IOPORT_STRING(b, u8) +__BUILD_IOPORT_STRING(w, u16) +__BUILD_IOPORT_STRING(l, u32) +__BUILD_IOPORT_STRING(q, u64) + +#else /* !CONFIG_HAS_IOPORT_MAP */ + +#include <asm/io_noioport.h> + +#endif + + +#define IO_SPACE_LIMIT 0xffffffff + +/* synco on SH-4A, otherwise a nop */ +#define mmiowb() wmb() + +/* We really want to try and get these to memcpy etc */ +void memcpy_fromio(void *, const volatile void __iomem *, unsigned long); +void memcpy_toio(volatile void __iomem *, const void *, unsigned long); +void memset_io(volatile void __iomem *, int, unsigned long); + +/* Quad-word real-mode I/O, don't ask.. */ +unsigned long long peek_real_address_q(unsigned long long addr); +unsigned long long poke_real_address_q(unsigned long long addr, + unsigned long long val); + +#if !defined(CONFIG_MMU) +#define virt_to_phys(address) ((unsigned long)(address)) +#define phys_to_virt(address) ((void *)(address)) +#else +#define virt_to_phys(address) (__pa(address)) +#define phys_to_virt(address) (__va(address)) +#endif + +/* + * On 32-bit SH, we traditionally have the whole physical address space + * mapped at all times (as MIPS does), so "ioremap()" and "iounmap()" do + * not need to do anything but place the address in the proper segment. + * This is true for P1 and P2 addresses, as well as some P3 ones. + * However, most of the P3 addresses and newer cores using extended + * addressing need to map through page tables, so the ioremap() + * implementation becomes a bit more complicated. + * + * See arch/sh/mm/ioremap.c for additional notes on this. + * + * We cheat a bit and always return uncachable areas until we've fixed + * the drivers to handle caching properly. + * + * On the SH-5 the concept of segmentation in the 1:1 PXSEG sense simply + * doesn't exist, so everything must go through page tables. + */ +#ifdef CONFIG_MMU +void __iomem *__ioremap_caller(phys_addr_t offset, unsigned long size, + pgprot_t prot, void *caller); +void __iounmap(void __iomem *addr); + +static inline void __iomem * +__ioremap(phys_addr_t offset, unsigned long size, pgprot_t prot) +{ + return __ioremap_caller(offset, size, prot, __builtin_return_address(0)); +} + +static inline void __iomem * +__ioremap_29bit(phys_addr_t offset, unsigned long size, pgprot_t prot) +{ +#ifdef CONFIG_29BIT + phys_addr_t last_addr = offset + size - 1; + + /* + * For P1 and P2 space this is trivial, as everything is already + * mapped. Uncached access for P1 addresses are done through P2. + * In the P3 case or for addresses outside of the 29-bit space, + * mapping must be done by the PMB or by using page tables. + */ + if (likely(PXSEG(offset) < P3SEG && PXSEG(last_addr) < P3SEG)) { + u64 flags = pgprot_val(prot); + + /* + * Anything using the legacy PTEA space attributes needs + * to be kicked down to page table mappings. + */ + if (unlikely(flags & _PAGE_PCC_MASK)) + return NULL; + if (unlikely(flags & _PAGE_CACHABLE)) + return (void __iomem *)P1SEGADDR(offset); + + return (void __iomem *)P2SEGADDR(offset); + } + + /* P4 above the store queues are always mapped. */ + if (unlikely(offset >= P3_ADDR_MAX)) + return (void __iomem *)P4SEGADDR(offset); +#endif + + return NULL; +} + +static inline void __iomem * +__ioremap_mode(phys_addr_t offset, unsigned long size, pgprot_t prot) +{ + void __iomem *ret; + + ret = __ioremap_trapped(offset, size); + if (ret) + return ret; + + ret = __ioremap_29bit(offset, size, prot); + if (ret) + return ret; + + return __ioremap(offset, size, prot); +} +#else +#define __ioremap(offset, size, prot) ((void __iomem *)(offset)) +#define __ioremap_mode(offset, size, prot) ((void __iomem *)(offset)) +#define __iounmap(addr) do { } while (0) +#endif /* CONFIG_MMU */ + +static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size) +{ + return __ioremap_mode(offset, size, PAGE_KERNEL_NOCACHE); +} + +static inline void __iomem * +ioremap_cache(phys_addr_t offset, unsigned long size) +{ + return __ioremap_mode(offset, size, PAGE_KERNEL); +} + +#ifdef CONFIG_HAVE_IOREMAP_PROT +static inline void __iomem * +ioremap_prot(phys_addr_t offset, unsigned long size, unsigned long flags) +{ + return __ioremap_mode(offset, size, __pgprot(flags)); +} +#endif + +#ifdef CONFIG_IOREMAP_FIXED +extern void __iomem *ioremap_fixed(phys_addr_t, unsigned long, pgprot_t); +extern int iounmap_fixed(void __iomem *); +extern void ioremap_fixed_init(void); +#else +static inline void __iomem * +ioremap_fixed(phys_addr_t phys_addr, unsigned long size, pgprot_t prot) +{ + BUG(); + return NULL; +} + +static inline void ioremap_fixed_init(void) { } +static inline int iounmap_fixed(void __iomem *addr) { return -EINVAL; } +#endif + +#define ioremap_nocache ioremap +#define iounmap __iounmap + +/* + * Convert a physical pointer to a virtual kernel pointer for /dev/mem + * access + */ +#define xlate_dev_mem_ptr(p) __va(p) + +/* + * Convert a virtual cached pointer to an uncached pointer + */ +#define xlate_dev_kmem_ptr(p) p + +#define ARCH_HAS_VALID_PHYS_ADDR_RANGE +int valid_phys_addr_range(phys_addr_t addr, size_t size); +int valid_mmap_phys_addr_range(unsigned long pfn, size_t size); + +#endif /* __KERNEL__ */ + +#endif /* __ASM_SH_IO_H */ diff --git a/arch/sh/include/asm/io_generic.h b/arch/sh/include/asm/io_generic.h new file mode 100644 index 000000000..b5f6956f1 --- /dev/null +++ b/arch/sh/include/asm/io_generic.h @@ -0,0 +1,18 @@ +/* + * Trivial I/O routine definitions, intentionally meant to be included + * multiple times. Ugly I/O routine concatenation helpers taken from + * alpha. Must be included _before_ io.h to avoid preprocessor-induced + * routine mismatch. + */ +#define IO_CONCAT(a,b) _IO_CONCAT(a,b) +#define _IO_CONCAT(a,b) a ## _ ## b + +#ifndef __IO_PREFIX +#error "Don't include this header without a valid system prefix" +#endif + +void __iomem *IO_CONCAT(__IO_PREFIX,ioport_map)(unsigned long addr, unsigned int size); +void IO_CONCAT(__IO_PREFIX,ioport_unmap)(void __iomem *addr); +void IO_CONCAT(__IO_PREFIX,mem_init)(void); + +#undef __IO_PREFIX diff --git a/arch/sh/include/asm/io_noioport.h b/arch/sh/include/asm/io_noioport.h new file mode 100644 index 000000000..c727e6ddf --- /dev/null +++ b/arch/sh/include/asm/io_noioport.h @@ -0,0 +1,63 @@ +#ifndef __ASM_SH_IO_NOIOPORT_H +#define __ASM_SH_IO_NOIOPORT_H + +static inline u8 inb(unsigned long addr) +{ + BUG(); + return -1; +} + +static inline u16 inw(unsigned long addr) +{ + BUG(); + return -1; +} + +static inline u32 inl(unsigned long addr) +{ + BUG(); + return -1; +} + +static inline void outb(unsigned char x, unsigned long port) +{ + BUG(); +} + +static inline void outw(unsigned short x, unsigned long port) +{ + BUG(); +} + +static inline void outl(unsigned int x, unsigned long port) +{ + BUG(); +} + +static inline void __iomem *ioport_map(unsigned long port, unsigned int size) +{ + BUG(); + return NULL; +} + +static inline void ioport_unmap(void __iomem *addr) +{ + BUG(); +} + +#define inb_p(addr) inb(addr) +#define inw_p(addr) inw(addr) +#define inl_p(addr) inl(addr) +#define outb_p(x, addr) outb((x), (addr)) +#define outw_p(x, addr) outw((x), (addr)) +#define outl_p(x, addr) outl((x), (addr)) + +#define insb(a, b, c) BUG() +#define insw(a, b, c) BUG() +#define insl(a, b, c) BUG() + +#define outsb(a, b, c) BUG() +#define outsw(a, b, c) BUG() +#define outsl(a, b, c) BUG() + +#endif /* __ASM_SH_IO_NOIOPORT_H */ diff --git a/arch/sh/include/asm/io_trapped.h b/arch/sh/include/asm/io_trapped.h new file mode 100644 index 000000000..4ab94ef51 --- /dev/null +++ b/arch/sh/include/asm/io_trapped.h @@ -0,0 +1,58 @@ +#ifndef __ASM_SH_IO_TRAPPED_H +#define __ASM_SH_IO_TRAPPED_H + +#include <linux/list.h> +#include <linux/ioport.h> +#include <asm/page.h> + +#define IO_TRAPPED_MAGIC 0xfeedbeef + +struct trapped_io { + unsigned int magic; + struct resource *resource; + unsigned int num_resources; + unsigned int minimum_bus_width; + struct list_head list; + void __iomem *virt_base; +} __aligned(PAGE_SIZE); + +#ifdef CONFIG_IO_TRAPPED +int register_trapped_io(struct trapped_io *tiop); +int handle_trapped_io(struct pt_regs *regs, unsigned long address); + +void __iomem *match_trapped_io_handler(struct list_head *list, + unsigned long offset, + unsigned long size); + +#ifdef CONFIG_HAS_IOMEM +extern struct list_head trapped_mem; + +static inline void __iomem * +__ioremap_trapped(unsigned long offset, unsigned long size) +{ + return match_trapped_io_handler(&trapped_mem, offset, size); +} +#else +#define __ioremap_trapped(offset, size) NULL +#endif + +#ifdef CONFIG_HAS_IOPORT_MAP +extern struct list_head trapped_io; + +static inline void __iomem * +__ioport_map_trapped(unsigned long offset, unsigned long size) +{ + return match_trapped_io_handler(&trapped_io, offset, size); +} +#else +#define __ioport_map_trapped(offset, size) NULL +#endif + +#else +#define register_trapped_io(tiop) (-1) +#define handle_trapped_io(tiop, address) 0 +#define __ioremap_trapped(offset, size) NULL +#define __ioport_map_trapped(offset, size) NULL +#endif + +#endif /* __ASM_SH_IO_TRAPPED_H */ diff --git a/arch/sh/include/asm/irq.h b/arch/sh/include/asm/irq.h new file mode 100644 index 000000000..0e4f532e4 --- /dev/null +++ b/arch/sh/include/asm/irq.h @@ -0,0 +1,72 @@ +#ifndef __ASM_SH_IRQ_H +#define __ASM_SH_IRQ_H + +#include <linux/cpumask.h> +#include <asm/machvec.h> + +/* + * Only legacy non-sparseirq platforms have to set a reasonably sane + * value here. sparseirq platforms allocate their irq_descs on the fly, + * so will expand automatically based on the number of registered IRQs. + */ +#ifdef CONFIG_SPARSE_IRQ +# define NR_IRQS 8 +#else +# define NR_IRQS 512 +#endif + +/* + * This is a special IRQ number for indicating that no IRQ has been + * triggered and to simply ignore the IRQ dispatch. This is a special + * case that can happen with IRQ auto-distribution when multiple CPUs + * are woken up and signalled in parallel. + */ +#define NO_IRQ_IGNORE ((unsigned int)-1) + +/* + * Simple Mask Register Support + */ +extern void make_maskreg_irq(unsigned int irq); +extern unsigned short *irq_mask_register; + +/* + * PINT IRQs + */ +void init_IRQ_pint(void); +void make_imask_irq(unsigned int irq); + +static inline int generic_irq_demux(int irq) +{ + return irq; +} + +#define irq_demux(irq) sh_mv.mv_irq_demux(irq) + +void init_IRQ(void); +void migrate_irqs(void); + +asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs); + +#ifdef CONFIG_IRQSTACKS +extern void irq_ctx_init(int cpu); +extern void irq_ctx_exit(int cpu); +# define __ARCH_HAS_DO_SOFTIRQ +#else +# define irq_ctx_init(cpu) do { } while (0) +# define irq_ctx_exit(cpu) do { } while (0) +#endif + +#ifdef CONFIG_INTC_BALANCING +extern unsigned int irq_lookup(unsigned int irq); +extern void irq_finish(unsigned int irq); +#else +#define irq_lookup(irq) (irq) +#define irq_finish(irq) do { } while (0) +#endif + +#include <asm-generic/irq.h> +#ifdef CONFIG_CPU_SH5 +#include <cpu/irq.h> +#endif + +#endif /* __ASM_SH_IRQ_H */ diff --git a/arch/sh/include/asm/irqflags.h b/arch/sh/include/asm/irqflags.h new file mode 100644 index 000000000..43b760860 --- /dev/null +++ b/arch/sh/include/asm/irqflags.h @@ -0,0 +1,9 @@ +#ifndef __ASM_SH_IRQFLAGS_H +#define __ASM_SH_IRQFLAGS_H + +#define ARCH_IRQ_DISABLED 0xf0 +#define ARCH_IRQ_ENABLED 0x00 + +#include <asm-generic/irqflags.h> + +#endif /* __ASM_SH_IRQFLAGS_H */ diff --git a/arch/sh/include/asm/kdebug.h b/arch/sh/include/asm/kdebug.h new file mode 100644 index 000000000..8d6a831e7 --- /dev/null +++ b/arch/sh/include/asm/kdebug.h @@ -0,0 +1,17 @@ +#ifndef __ASM_SH_KDEBUG_H +#define __ASM_SH_KDEBUG_H + +/* Grossly misnamed. */ +enum die_val { + DIE_TRAP, + DIE_NMI, + DIE_OOPS, + DIE_BREAKPOINT, + DIE_SSTEP, +}; + +/* arch/sh/kernel/dumpstack.c */ +extern void printk_address(unsigned long address, int reliable); +extern void dump_mem(const char *str, unsigned long bottom, unsigned long top); + +#endif /* __ASM_SH_KDEBUG_H */ diff --git a/arch/sh/include/asm/kexec.h b/arch/sh/include/asm/kexec.h new file mode 100644 index 000000000..ad6ef8a27 --- /dev/null +++ b/arch/sh/include/asm/kexec.h @@ -0,0 +1,70 @@ +#ifndef __ASM_SH_KEXEC_H +#define __ASM_SH_KEXEC_H + +#include <asm/ptrace.h> +#include <asm/string.h> + +/* + * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return. + * I.e. Maximum page that is mapped directly into kernel memory, + * and kmap is not required. + * + * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct + * calculation for the amount of memory directly mappable into the + * kernel memory space. + */ + +/* Maximum physical address we can use pages from */ +#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL) +/* Maximum address we can reach in physical address mode */ +#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL) +/* Maximum address we can use for the control code buffer */ +#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE + +#define KEXEC_CONTROL_PAGE_SIZE 4096 + +/* The native architecture */ +#define KEXEC_ARCH KEXEC_ARCH_SH + +#ifdef CONFIG_KEXEC +/* arch/sh/kernel/machine_kexec.c */ +void reserve_crashkernel(void); + +static inline void crash_setup_regs(struct pt_regs *newregs, + struct pt_regs *oldregs) +{ + if (oldregs) + memcpy(newregs, oldregs, sizeof(*newregs)); + else { + __asm__ __volatile__ ("mov r0, %0" : "=r" (newregs->regs[0])); + __asm__ __volatile__ ("mov r1, %0" : "=r" (newregs->regs[1])); + __asm__ __volatile__ ("mov r2, %0" : "=r" (newregs->regs[2])); + __asm__ __volatile__ ("mov r3, %0" : "=r" (newregs->regs[3])); + __asm__ __volatile__ ("mov r4, %0" : "=r" (newregs->regs[4])); + __asm__ __volatile__ ("mov r5, %0" : "=r" (newregs->regs[5])); + __asm__ __volatile__ ("mov r6, %0" : "=r" (newregs->regs[6])); + __asm__ __volatile__ ("mov r7, %0" : "=r" (newregs->regs[7])); + __asm__ __volatile__ ("mov r8, %0" : "=r" (newregs->regs[8])); + __asm__ __volatile__ ("mov r9, %0" : "=r" (newregs->regs[9])); + __asm__ __volatile__ ("mov r10, %0" : "=r" (newregs->regs[10])); + __asm__ __volatile__ ("mov r11, %0" : "=r" (newregs->regs[11])); + __asm__ __volatile__ ("mov r12, %0" : "=r" (newregs->regs[12])); + __asm__ __volatile__ ("mov r13, %0" : "=r" (newregs->regs[13])); + __asm__ __volatile__ ("mov r14, %0" : "=r" (newregs->regs[14])); + __asm__ __volatile__ ("mov r15, %0" : "=r" (newregs->regs[15])); + + __asm__ __volatile__ ("sts pr, %0" : "=r" (newregs->pr)); + __asm__ __volatile__ ("sts macl, %0" : "=r" (newregs->macl)); + __asm__ __volatile__ ("sts mach, %0" : "=r" (newregs->mach)); + + __asm__ __volatile__ ("stc gbr, %0" : "=r" (newregs->gbr)); + __asm__ __volatile__ ("stc sr, %0" : "=r" (newregs->sr)); + + newregs->pc = (unsigned long)current_text_addr(); + } +} +#else +static inline void reserve_crashkernel(void) { } +#endif /* CONFIG_KEXEC */ + +#endif /* __ASM_SH_KEXEC_H */ diff --git a/arch/sh/include/asm/kgdb.h b/arch/sh/include/asm/kgdb.h new file mode 100644 index 000000000..9e7d2d1b0 --- /dev/null +++ b/arch/sh/include/asm/kgdb.h @@ -0,0 +1,37 @@ +#ifndef __ASM_SH_KGDB_H +#define __ASM_SH_KGDB_H + +#include <asm/cacheflush.h> +#include <asm/ptrace.h> + +enum regnames { + GDB_R0, GDB_R1, GDB_R2, GDB_R3, GDB_R4, GDB_R5, GDB_R6, GDB_R7, + GDB_R8, GDB_R9, GDB_R10, GDB_R11, GDB_R12, GDB_R13, GDB_R14, GDB_R15, + + GDB_PC, GDB_PR, GDB_SR, GDB_GBR, GDB_MACH, GDB_MACL, GDB_VBR, +}; + +#define _GP_REGS 16 +#define _EXTRA_REGS 7 +#define GDB_SIZEOF_REG sizeof(u32) + +#define DBG_MAX_REG_NUM (_GP_REGS + _EXTRA_REGS) +#define NUMREGBYTES (DBG_MAX_REG_NUM * sizeof(GDB_SIZEOF_REG)) + +static inline void arch_kgdb_breakpoint(void) +{ + __asm__ __volatile__ ("trapa #0x3c\n"); +} + +#define BREAK_INSTR_SIZE 2 +#define BUFMAX 2048 + +#ifdef CONFIG_SMP +# define CACHE_FLUSH_IS_SAFE 0 +#else +# define CACHE_FLUSH_IS_SAFE 1 +#endif + +#define GDB_ADJUSTS_BREAK_OFFSET + +#endif /* __ASM_SH_KGDB_H */ diff --git a/arch/sh/include/asm/kmap_types.h b/arch/sh/include/asm/kmap_types.h new file mode 100644 index 000000000..5962b08b6 --- /dev/null +++ b/arch/sh/include/asm/kmap_types.h @@ -0,0 +1,14 @@ +#ifndef __SH_KMAP_TYPES_H +#define __SH_KMAP_TYPES_H + +/* Dummy header just to define km_type. */ + +#ifdef CONFIG_DEBUG_HIGHMEM +#define __WITH_KM_FENCE +#endif + +#include <asm-generic/kmap_types.h> + +#undef __WITH_KM_FENCE + +#endif diff --git a/arch/sh/include/asm/kprobes.h b/arch/sh/include/asm/kprobes.h new file mode 100644 index 000000000..134f3980e --- /dev/null +++ b/arch/sh/include/asm/kprobes.h @@ -0,0 +1,57 @@ +#ifndef __ASM_SH_KPROBES_H +#define __ASM_SH_KPROBES_H + +#ifdef CONFIG_KPROBES + +#include <linux/types.h> +#include <linux/ptrace.h> + +typedef insn_size_t kprobe_opcode_t; +#define BREAKPOINT_INSTRUCTION 0xc33a + +#define MAX_INSN_SIZE 16 +#define MAX_STACK_SIZE 64 +#define MIN_STACK_SIZE(ADDR) (((MAX_STACK_SIZE) < \ + (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR))) \ + ? (MAX_STACK_SIZE) \ + : (((unsigned long)current_thread_info()) + THREAD_SIZE - (ADDR))) + +#define flush_insn_slot(p) do { } while (0) +#define kretprobe_blacklist_size 0 + +struct kprobe; + +void arch_remove_kprobe(struct kprobe *); +void kretprobe_trampoline(void); +void jprobe_return_end(void); + +/* Architecture specific copy of original instruction*/ +struct arch_specific_insn { + /* copy of the original instruction */ + kprobe_opcode_t insn[MAX_INSN_SIZE]; +}; + +struct prev_kprobe { + struct kprobe *kp; + unsigned long status; +}; + +/* per-cpu kprobe control block */ +struct kprobe_ctlblk { + unsigned long kprobe_status; + unsigned long jprobe_saved_r15; + struct pt_regs jprobe_saved_regs; + kprobe_opcode_t jprobes_stack[MAX_STACK_SIZE]; + struct prev_kprobe prev_kprobe; +}; + +extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr); +extern int kprobe_exceptions_notify(struct notifier_block *self, + unsigned long val, void *data); +extern int kprobe_handle_illslot(unsigned long pc); +#else + +#define kprobe_handle_illslot(pc) (-1) + +#endif /* CONFIG_KPROBES */ +#endif /* __ASM_SH_KPROBES_H */ diff --git a/arch/sh/include/asm/linkage.h b/arch/sh/include/asm/linkage.h new file mode 100644 index 000000000..3565a4f40 --- /dev/null +++ b/arch/sh/include/asm/linkage.h @@ -0,0 +1,7 @@ +#ifndef __ASM_LINKAGE_H +#define __ASM_LINKAGE_H + +#define __ALIGN .balign 4 +#define __ALIGN_STR ".balign 4" + +#endif diff --git a/arch/sh/include/asm/machvec.h b/arch/sh/include/asm/machvec.h new file mode 100644 index 000000000..d3324e4f3 --- /dev/null +++ b/arch/sh/include/asm/machvec.h @@ -0,0 +1,43 @@ +/* + * include/asm-sh/machvec.h + * + * Copyright 2000 Stuart Menefy (stuart.menefy@st.com) + * + * May be copied or modified under the terms of the GNU General Public + * License. See linux/COPYING for more information. + */ + +#ifndef _ASM_SH_MACHVEC_H +#define _ASM_SH_MACHVEC_H + +#include <linux/types.h> +#include <linux/time.h> +#include <generated/machtypes.h> + +struct sh_machine_vector { + void (*mv_setup)(char **cmdline_p); + const char *mv_name; + + int (*mv_irq_demux)(int irq); + void (*mv_init_irq)(void); + +#ifdef CONFIG_HAS_IOPORT_MAP + void __iomem *(*mv_ioport_map)(unsigned long port, unsigned int size); + void (*mv_ioport_unmap)(void __iomem *); +#endif + + int (*mv_clk_init)(void); + int (*mv_mode_pins)(void); + + void (*mv_mem_init)(void); + void (*mv_mem_reserve)(void); +}; + +extern struct sh_machine_vector sh_mv; + +#define get_system_type() sh_mv.mv_name + +#define __initmv \ + __used __section(.machvec.init) + +#endif /* _ASM_SH_MACHVEC_H */ diff --git a/arch/sh/include/asm/mc146818rtc.h b/arch/sh/include/asm/mc146818rtc.h new file mode 100644 index 000000000..0aee96a97 --- /dev/null +++ b/arch/sh/include/asm/mc146818rtc.h @@ -0,0 +1,7 @@ +/* + * Machine dependent access functions for RTC registers. + */ +#ifndef _ASM_MC146818RTC_H +#define _ASM_MC146818RTC_H + +#endif /* _ASM_MC146818RTC_H */ diff --git a/arch/sh/include/asm/mmu.h b/arch/sh/include/asm/mmu.h new file mode 100644 index 000000000..56e4418c1 --- /dev/null +++ b/arch/sh/include/asm/mmu.h @@ -0,0 +1,106 @@ +#ifndef __MMU_H +#define __MMU_H + +/* + * Privileged Space Mapping Buffer (PMB) definitions + */ +#define PMB_PASCR 0xff000070 +#define PMB_IRMCR 0xff000078 + +#define PASCR_SE 0x80000000 + +#define PMB_ADDR 0xf6100000 +#define PMB_DATA 0xf7100000 + +#define NR_PMB_ENTRIES 16 + +#define PMB_E_MASK 0x0000000f +#define PMB_E_SHIFT 8 + +#define PMB_PFN_MASK 0xff000000 + +#define PMB_SZ_16M 0x00000000 +#define PMB_SZ_64M 0x00000010 +#define PMB_SZ_128M 0x00000080 +#define PMB_SZ_512M 0x00000090 +#define PMB_SZ_MASK PMB_SZ_512M +#define PMB_C 0x00000008 +#define PMB_WT 0x00000001 +#define PMB_UB 0x00000200 +#define PMB_CACHE_MASK (PMB_C | PMB_WT | PMB_UB) +#define PMB_V 0x00000100 + +#define PMB_NO_ENTRY (-1) + +#ifndef __ASSEMBLY__ +#include <linux/errno.h> +#include <linux/threads.h> +#include <asm/page.h> + +/* Default "unsigned long" context */ +typedef unsigned long mm_context_id_t[NR_CPUS]; + +typedef struct { +#ifdef CONFIG_MMU + mm_context_id_t id; + void *vdso; +#else + unsigned long end_brk; +#endif +#ifdef CONFIG_BINFMT_ELF_FDPIC + unsigned long exec_fdpic_loadmap; + unsigned long interp_fdpic_loadmap; +#endif +} mm_context_t; + +#ifdef CONFIG_PMB +/* arch/sh/mm/pmb.c */ +bool __in_29bit_mode(void); + +void pmb_init(void); +int pmb_bolt_mapping(unsigned long virt, phys_addr_t phys, + unsigned long size, pgprot_t prot); +void __iomem *pmb_remap_caller(phys_addr_t phys, unsigned long size, + pgprot_t prot, void *caller); +int pmb_unmap(void __iomem *addr); + +#else + +static inline int +pmb_bolt_mapping(unsigned long virt, phys_addr_t phys, + unsigned long size, pgprot_t prot) +{ + return -EINVAL; +} + +static inline void __iomem * +pmb_remap_caller(phys_addr_t phys, unsigned long size, + pgprot_t prot, void *caller) +{ + return NULL; +} + +static inline int pmb_unmap(void __iomem *addr) +{ + return -EINVAL; +} + +#define pmb_init(addr) do { } while (0) + +#ifdef CONFIG_29BIT +#define __in_29bit_mode() (1) +#else +#define __in_29bit_mode() (0) +#endif + +#endif /* CONFIG_PMB */ + +static inline void __iomem * +pmb_remap(phys_addr_t phys, unsigned long size, pgprot_t prot) +{ + return pmb_remap_caller(phys, size, prot, __builtin_return_address(0)); +} + +#endif /* __ASSEMBLY__ */ + +#endif /* __MMU_H */ diff --git a/arch/sh/include/asm/mmu_context.h b/arch/sh/include/asm/mmu_context.h new file mode 100644 index 000000000..9f417feaf --- /dev/null +++ b/arch/sh/include/asm/mmu_context.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 1999 Niibe Yutaka + * Copyright (C) 2003 - 2007 Paul Mundt + * + * ASID handling idea taken from MIPS implementation. + */ +#ifndef __ASM_SH_MMU_CONTEXT_H +#define __ASM_SH_MMU_CONTEXT_H + +#ifdef __KERNEL__ +#include <cpu/mmu_context.h> +#include <asm/tlbflush.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm-generic/mm_hooks.h> + +/* + * The MMU "context" consists of two things: + * (a) TLB cache version (or round, cycle whatever expression you like) + * (b) ASID (Address Space IDentifier) + */ +#ifdef CONFIG_CPU_HAS_PTEAEX +#define MMU_CONTEXT_ASID_MASK 0x0000ffff +#else +#define MMU_CONTEXT_ASID_MASK 0x000000ff +#endif + +#define MMU_CONTEXT_VERSION_MASK (~0UL & ~MMU_CONTEXT_ASID_MASK) +#define MMU_CONTEXT_FIRST_VERSION (MMU_CONTEXT_ASID_MASK + 1) + +/* Impossible ASID value, to differentiate from NO_CONTEXT. */ +#define MMU_NO_ASID MMU_CONTEXT_FIRST_VERSION +#define NO_CONTEXT 0UL + +#define asid_cache(cpu) (cpu_data[cpu].asid_cache) + +#ifdef CONFIG_MMU +#define cpu_context(cpu, mm) ((mm)->context.id[cpu]) + +#define cpu_asid(cpu, mm) \ + (cpu_context((cpu), (mm)) & MMU_CONTEXT_ASID_MASK) + +/* + * Virtual Page Number mask + */ +#define MMU_VPN_MASK 0xfffff000 + +#if defined(CONFIG_SUPERH32) +#include <asm/mmu_context_32.h> +#else +#include <asm/mmu_context_64.h> +#endif + +/* + * Get MMU context if needed. + */ +static inline void get_mmu_context(struct mm_struct *mm, unsigned int cpu) +{ + unsigned long asid = asid_cache(cpu); + + /* Check if we have old version of context. */ + if (((cpu_context(cpu, mm) ^ asid) & MMU_CONTEXT_VERSION_MASK) == 0) + /* It's up to date, do nothing */ + return; + + /* It's old, we need to get new context with new version. */ + if (!(++asid & MMU_CONTEXT_ASID_MASK)) { + /* + * We exhaust ASID of this version. + * Flush all TLB and start new cycle. + */ + local_flush_tlb_all(); + +#ifdef CONFIG_SUPERH64 + /* + * The SH-5 cache uses the ASIDs, requiring both the I and D + * cache to be flushed when the ASID is exhausted. Weak. + */ + flush_cache_all(); +#endif + + /* + * Fix version; Note that we avoid version #0 + * to distinguish NO_CONTEXT. + */ + if (!asid) + asid = MMU_CONTEXT_FIRST_VERSION; + } + + cpu_context(cpu, mm) = asid_cache(cpu) = asid; +} + +/* + * Initialize the context related info for a new mm_struct + * instance. + */ +static inline int init_new_context(struct task_struct *tsk, + struct mm_struct *mm) +{ + int i; + + for_each_online_cpu(i) + cpu_context(i, mm) = NO_CONTEXT; + + return 0; +} + +/* + * After we have set current->mm to a new value, this activates + * the context for the new mm so we see the new mappings. + */ +static inline void activate_context(struct mm_struct *mm, unsigned int cpu) +{ + get_mmu_context(mm, cpu); + set_asid(cpu_asid(cpu, mm)); +} + +static inline void switch_mm(struct mm_struct *prev, + struct mm_struct *next, + struct task_struct *tsk) +{ + unsigned int cpu = smp_processor_id(); + + if (likely(prev != next)) { + cpumask_set_cpu(cpu, mm_cpumask(next)); + set_TTB(next->pgd); + activate_context(next, cpu); + } else + if (!cpumask_test_and_set_cpu(cpu, mm_cpumask(next))) + activate_context(next, cpu); +} + +#define activate_mm(prev, next) switch_mm((prev),(next),NULL) +#define deactivate_mm(tsk,mm) do { } while (0) +#define enter_lazy_tlb(mm,tsk) do { } while (0) + +#else + +#define set_asid(asid) do { } while (0) +#define get_asid() (0) +#define cpu_asid(cpu, mm) ({ (void)cpu; NO_CONTEXT; }) +#define switch_and_save_asid(asid) (0) +#define set_TTB(pgd) do { } while (0) +#define get_TTB() (0) + +#include <asm-generic/mmu_context.h> + +#endif /* CONFIG_MMU */ + +#if defined(CONFIG_CPU_SH3) || defined(CONFIG_CPU_SH4) +/* + * If this processor has an MMU, we need methods to turn it off/on .. + * paging_init() will also have to be updated for the processor in + * question. + */ +static inline void enable_mmu(void) +{ + unsigned int cpu = smp_processor_id(); + + /* Enable MMU */ + __raw_writel(MMU_CONTROL_INIT, MMUCR); + ctrl_barrier(); + + if (asid_cache(cpu) == NO_CONTEXT) + asid_cache(cpu) = MMU_CONTEXT_FIRST_VERSION; + + set_asid(asid_cache(cpu) & MMU_CONTEXT_ASID_MASK); +} + +static inline void disable_mmu(void) +{ + unsigned long cr; + + cr = __raw_readl(MMUCR); + cr &= ~MMU_CONTROL_INIT; + __raw_writel(cr, MMUCR); + + ctrl_barrier(); +} +#else +/* + * MMU control handlers for processors lacking memory + * management hardware. + */ +#define enable_mmu() do { } while (0) +#define disable_mmu() do { } while (0) +#endif + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_MMU_CONTEXT_H */ diff --git a/arch/sh/include/asm/mmu_context_32.h b/arch/sh/include/asm/mmu_context_32.h new file mode 100644 index 000000000..10e2e1721 --- /dev/null +++ b/arch/sh/include/asm/mmu_context_32.h @@ -0,0 +1,59 @@ +#ifndef __ASM_SH_MMU_CONTEXT_32_H +#define __ASM_SH_MMU_CONTEXT_32_H + +/* + * Destroy context related info for an mm_struct that is about + * to be put to rest. + */ +static inline void destroy_context(struct mm_struct *mm) +{ + /* Do nothing */ +} + +#ifdef CONFIG_CPU_HAS_PTEAEX +static inline void set_asid(unsigned long asid) +{ + __raw_writel(asid, MMU_PTEAEX); +} + +static inline unsigned long get_asid(void) +{ + return __raw_readl(MMU_PTEAEX) & MMU_CONTEXT_ASID_MASK; +} +#else +static inline void set_asid(unsigned long asid) +{ + unsigned long __dummy; + + __asm__ __volatile__ ("mov.l %2, %0\n\t" + "and %3, %0\n\t" + "or %1, %0\n\t" + "mov.l %0, %2" + : "=&r" (__dummy) + : "r" (asid), "m" (__m(MMU_PTEH)), + "r" (0xffffff00)); +} + +static inline unsigned long get_asid(void) +{ + unsigned long asid; + + __asm__ __volatile__ ("mov.l %1, %0" + : "=r" (asid) + : "m" (__m(MMU_PTEH))); + asid &= MMU_CONTEXT_ASID_MASK; + return asid; +} +#endif /* CONFIG_CPU_HAS_PTEAEX */ + +/* MMU_TTB is used for optimizing the fault handling. */ +static inline void set_TTB(pgd_t *pgd) +{ + __raw_writel((unsigned long)pgd, MMU_TTB); +} + +static inline pgd_t *get_TTB(void) +{ + return (pgd_t *)__raw_readl(MMU_TTB); +} +#endif /* __ASM_SH_MMU_CONTEXT_32_H */ diff --git a/arch/sh/include/asm/mmu_context_64.h b/arch/sh/include/asm/mmu_context_64.h new file mode 100644 index 000000000..de121025d --- /dev/null +++ b/arch/sh/include/asm/mmu_context_64.h @@ -0,0 +1,78 @@ +#ifndef __ASM_SH_MMU_CONTEXT_64_H +#define __ASM_SH_MMU_CONTEXT_64_H + +/* + * sh64-specific mmu_context interface. + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 - 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 <cpu/registers.h> +#include <asm/cacheflush.h> + +#define SR_ASID_MASK 0xffffffffff00ffffULL +#define SR_ASID_SHIFT 16 + +/* + * Destroy context related info for an mm_struct that is about + * to be put to rest. + */ +static inline void destroy_context(struct mm_struct *mm) +{ + /* Well, at least free TLB entries */ + flush_tlb_mm(mm); +} + +static inline unsigned long get_asid(void) +{ + unsigned long long sr; + + asm volatile ("getcon " __SR ", %0\n\t" + : "=r" (sr)); + + sr = (sr >> SR_ASID_SHIFT) & MMU_CONTEXT_ASID_MASK; + return (unsigned long) sr; +} + +/* Set ASID into SR */ +static inline void set_asid(unsigned long asid) +{ + unsigned long long sr, pc; + + asm volatile ("getcon " __SR ", %0" : "=r" (sr)); + + sr = (sr & SR_ASID_MASK) | (asid << SR_ASID_SHIFT); + + /* + * It is possible that this function may be inlined and so to avoid + * the assembler reporting duplicate symbols we make use of the + * gas trick of generating symbols using numerics and forward + * reference. + */ + asm volatile ("movi 1, %1\n\t" + "shlli %1, 28, %1\n\t" + "or %0, %1, %1\n\t" + "putcon %1, " __SR "\n\t" + "putcon %0, " __SSR "\n\t" + "movi 1f, %1\n\t" + "ori %1, 1 , %1\n\t" + "putcon %1, " __SPC "\n\t" + "rte\n" + "1:\n\t" + : "=r" (sr), "=r" (pc) : "0" (sr)); +} + +/* arch/sh/kernel/cpu/sh5/entry.S */ +extern unsigned long switch_and_save_asid(unsigned long new_asid); + +/* No spare register to twiddle, so use a software cache */ +extern pgd_t *mmu_pdtp_cache; + +#define set_TTB(pgd) (mmu_pdtp_cache = (pgd)) +#define get_TTB() (mmu_pdtp_cache) + +#endif /* __ASM_SH_MMU_CONTEXT_64_H */ diff --git a/arch/sh/include/asm/mmzone.h b/arch/sh/include/asm/mmzone.h new file mode 100644 index 000000000..15a849696 --- /dev/null +++ b/arch/sh/include/asm/mmzone.h @@ -0,0 +1,47 @@ +#ifndef __ASM_SH_MMZONE_H +#define __ASM_SH_MMZONE_H + +#ifdef __KERNEL__ + +#ifdef CONFIG_NEED_MULTIPLE_NODES +#include <linux/numa.h> + +extern struct pglist_data *node_data[]; +#define NODE_DATA(nid) (node_data[nid]) + +static inline int pfn_to_nid(unsigned long pfn) +{ + int nid; + + for (nid = 0; nid < MAX_NUMNODES; nid++) + if (pfn >= node_start_pfn(nid) && pfn <= node_end_pfn(nid)) + break; + + return nid; +} + +static inline struct pglist_data *pfn_to_pgdat(unsigned long pfn) +{ + return NODE_DATA(pfn_to_nid(pfn)); +} + +/* arch/sh/mm/numa.c */ +void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end); +#else +static inline void +setup_bootmem_node(int nid, unsigned long start, unsigned long end) +{ +} +#endif /* CONFIG_NEED_MULTIPLE_NODES */ + +/* Platform specific mem init */ +void __init plat_mem_setup(void); + +/* arch/sh/kernel/setup.c */ +void __init __add_active_range(unsigned int nid, unsigned long start_pfn, + unsigned long end_pfn); +/* arch/sh/mm/init.c */ +void __init allocate_pgdat(unsigned int nid); + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_MMZONE_H */ diff --git a/arch/sh/include/asm/module.h b/arch/sh/include/asm/module.h new file mode 100644 index 000000000..81300d8b5 --- /dev/null +++ b/arch/sh/include/asm/module.h @@ -0,0 +1,41 @@ +#ifndef _ASM_SH_MODULE_H +#define _ASM_SH_MODULE_H + +#include <asm-generic/module.h> + +#ifdef CONFIG_DWARF_UNWINDER +struct mod_arch_specific { + struct list_head fde_list; + struct list_head cie_list; +}; +#endif + +#ifdef CONFIG_CPU_LITTLE_ENDIAN +# ifdef CONFIG_CPU_SH2 +# define MODULE_PROC_FAMILY "SH2LE " +# elif defined CONFIG_CPU_SH3 +# define MODULE_PROC_FAMILY "SH3LE " +# elif defined CONFIG_CPU_SH4 +# define MODULE_PROC_FAMILY "SH4LE " +# elif defined CONFIG_CPU_SH5 +# define MODULE_PROC_FAMILY "SH5LE " +# else +# error unknown processor family +# endif +#else +# ifdef CONFIG_CPU_SH2 +# define MODULE_PROC_FAMILY "SH2BE " +# elif defined CONFIG_CPU_SH3 +# define MODULE_PROC_FAMILY "SH3BE " +# elif defined CONFIG_CPU_SH4 +# define MODULE_PROC_FAMILY "SH4BE " +# elif defined CONFIG_CPU_SH5 +# define MODULE_PROC_FAMILY "SH5BE " +# else +# error unknown processor family +# endif +#endif + +#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY + +#endif /* _ASM_SH_MODULE_H */ diff --git a/arch/sh/include/asm/mutex-llsc.h b/arch/sh/include/asm/mutex-llsc.h new file mode 100644 index 000000000..dad29b687 --- /dev/null +++ b/arch/sh/include/asm/mutex-llsc.h @@ -0,0 +1,109 @@ +/* + * arch/sh/include/asm/mutex-llsc.h + * + * SH-4A optimized mutex locking primitives + * + * Please look into asm-generic/mutex-xchg.h for a formal definition. + */ +#ifndef __ASM_SH_MUTEX_LLSC_H +#define __ASM_SH_MUTEX_LLSC_H + +/* + * Attempting to lock a mutex on SH4A is done like in ARMv6+ architecure. + * with a bastardized atomic decrement (it is not a reliable atomic decrement + * but it satisfies the defined semantics for our purpose, while being + * smaller and faster than a real atomic decrement or atomic swap. + * The idea is to attempt decrementing the lock value only once. If once + * decremented it isn't zero, or if its store-back fails due to a dispute + * on the exclusive store, we simply bail out immediately through the slow + * path where the lock will be reattempted until it succeeds. + */ +static inline void +__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *)) +{ + int __done, __res; + + __asm__ __volatile__ ( + "movli.l @%2, %0 \n" + "add #-1, %0 \n" + "movco.l %0, @%2 \n" + "movt %1 \n" + : "=&z" (__res), "=&r" (__done) + : "r" (&(count)->counter) + : "t"); + + if (unlikely(!__done || __res != 0)) + fail_fn(count); +} + +static inline int +__mutex_fastpath_lock_retval(atomic_t *count) +{ + int __done, __res; + + __asm__ __volatile__ ( + "movli.l @%2, %0 \n" + "add #-1, %0 \n" + "movco.l %0, @%2 \n" + "movt %1 \n" + : "=&z" (__res), "=&r" (__done) + : "r" (&(count)->counter) + : "t"); + + if (unlikely(!__done || __res != 0)) + __res = -1; + + return __res; +} + +static inline void +__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) +{ + int __done, __res; + + __asm__ __volatile__ ( + "movli.l @%2, %0 \n\t" + "add #1, %0 \n\t" + "movco.l %0, @%2 \n\t" + "movt %1 \n\t" + : "=&z" (__res), "=&r" (__done) + : "r" (&(count)->counter) + : "t"); + + if (unlikely(!__done || __res <= 0)) + fail_fn(count); +} + +/* + * If the unlock was done on a contended lock, or if the unlock simply fails + * then the mutex remains locked. + */ +#define __mutex_slowpath_needs_to_unlock() 1 + +/* + * For __mutex_fastpath_trylock we do an atomic decrement and check the + * result and put it in the __res variable. + */ +static inline int +__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) +{ + int __res, __orig; + + __asm__ __volatile__ ( + "1: movli.l @%2, %0 \n\t" + "dt %0 \n\t" + "movco.l %0,@%2 \n\t" + "bf 1b \n\t" + "cmp/eq #0,%0 \n\t" + "bt 2f \n\t" + "mov #0, %1 \n\t" + "bf 3f \n\t" + "2: mov #1, %1 \n\t" + "3: " + : "=&z" (__orig), "=&r" (__res) + : "r" (&count->counter) + : "t"); + + return __res; +} +#endif /* __ASM_SH_MUTEX_LLSC_H */ diff --git a/arch/sh/include/asm/mutex.h b/arch/sh/include/asm/mutex.h new file mode 100644 index 000000000..d8e37716a --- /dev/null +++ b/arch/sh/include/asm/mutex.h @@ -0,0 +1,12 @@ +/* + * Pull in the generic implementation for the mutex fastpath. + * + * TODO: implement optimized primitives instead, or leave the generic + * implementation in place, or pick the atomic_xchg() based generic + * implementation. (see asm-generic/mutex-xchg.h for details) + */ +#if defined(CONFIG_CPU_SH4A) +#include <asm/mutex-llsc.h> +#else +#include <asm-generic/mutex-dec.h> +#endif diff --git a/arch/sh/include/asm/page.h b/arch/sh/include/asm/page.h new file mode 100644 index 000000000..fe20d14ae --- /dev/null +++ b/arch/sh/include/asm/page.h @@ -0,0 +1,206 @@ +#ifndef __ASM_SH_PAGE_H +#define __ASM_SH_PAGE_H + +/* + * Copyright (C) 1999 Niibe Yutaka + */ + +#include <linux/const.h> + +/* PAGE_SHIFT determines the page size */ +#if defined(CONFIG_PAGE_SIZE_4KB) +# define PAGE_SHIFT 12 +#elif defined(CONFIG_PAGE_SIZE_8KB) +# define PAGE_SHIFT 13 +#elif defined(CONFIG_PAGE_SIZE_16KB) +# define PAGE_SHIFT 14 +#elif defined(CONFIG_PAGE_SIZE_64KB) +# define PAGE_SHIFT 16 +#else +# error "Bogus kernel page size?" +#endif + +#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) +#define PTE_MASK PAGE_MASK + +#if defined(CONFIG_HUGETLB_PAGE_SIZE_64K) +#define HPAGE_SHIFT 16 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K) +#define HPAGE_SHIFT 18 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB) +#define HPAGE_SHIFT 20 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_4MB) +#define HPAGE_SHIFT 22 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_64MB) +#define HPAGE_SHIFT 26 +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512MB) +#define HPAGE_SHIFT 29 +#endif + +#ifdef CONFIG_HUGETLB_PAGE +#define HPAGE_SIZE (1UL << HPAGE_SHIFT) +#define HPAGE_MASK (~(HPAGE_SIZE-1)) +#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT-PAGE_SHIFT) +#endif + +#ifndef __ASSEMBLY__ +#include <asm/uncached.h> + +extern unsigned long shm_align_mask; +extern unsigned long max_low_pfn, min_low_pfn; +extern unsigned long memory_start, memory_end, memory_limit; + +static inline unsigned long +pages_do_alias(unsigned long addr1, unsigned long addr2) +{ + return (addr1 ^ addr2) & shm_align_mask; +} + +#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) +extern void copy_page(void *to, void *from); + +struct page; +struct vm_area_struct; + +extern void copy_user_highpage(struct page *to, struct page *from, + unsigned long vaddr, struct vm_area_struct *vma); +#define __HAVE_ARCH_COPY_USER_HIGHPAGE +extern void clear_user_highpage(struct page *page, unsigned long vaddr); +#define clear_user_highpage clear_user_highpage + +/* + * These are used to make use of C type-checking.. + */ +#ifdef CONFIG_X2TLB +typedef struct { unsigned long pte_low, pte_high; } pte_t; +typedef struct { unsigned long long pgprot; } pgprot_t; +typedef struct { unsigned long long pgd; } pgd_t; +#define pte_val(x) \ + ((x).pte_low | ((unsigned long long)(x).pte_high << 32)) +#define __pte(x) \ + ({ pte_t __pte = {(x), ((unsigned long long)(x)) >> 32}; __pte; }) +#elif defined(CONFIG_SUPERH32) +typedef struct { unsigned long pte_low; } pte_t; +typedef struct { unsigned long pgprot; } pgprot_t; +typedef struct { unsigned long pgd; } pgd_t; +#define pte_val(x) ((x).pte_low) +#define __pte(x) ((pte_t) { (x) } ) +#else +typedef struct { unsigned long long pte_low; } pte_t; +typedef struct { unsigned long long pgprot; } pgprot_t; +typedef struct { unsigned long pgd; } pgd_t; +#define pte_val(x) ((x).pte_low) +#define __pte(x) ((pte_t) { (x) } ) +#endif + +#define pgd_val(x) ((x).pgd) +#define pgprot_val(x) ((x).pgprot) + +#define __pgd(x) ((pgd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +typedef struct page *pgtable_t; + +#define pte_pgprot(x) __pgprot(pte_val(x) & PTE_FLAGS_MASK) + +#endif /* !__ASSEMBLY__ */ + +/* + * __MEMORY_START and SIZE are the physical addresses and size of RAM. + */ +#define __MEMORY_START CONFIG_MEMORY_START +#define __MEMORY_SIZE CONFIG_MEMORY_SIZE + +/* + * PHYSICAL_OFFSET is the offset in physical memory where the base + * of the kernel is loaded. + */ +#ifdef CONFIG_PHYSICAL_START +#define PHYSICAL_OFFSET (CONFIG_PHYSICAL_START - __MEMORY_START) +#else +#define PHYSICAL_OFFSET 0 +#endif + +/* + * PAGE_OFFSET is the virtual address of the start of kernel address + * space. + */ +#define PAGE_OFFSET CONFIG_PAGE_OFFSET + +/* + * Virtual to physical RAM address translation. + * + * In 29 bit mode, the physical offset of RAM from address 0 is visible in + * the kernel virtual address space, and thus we don't have to take + * this into account when translating. However in 32 bit mode this offset + * is not visible (it is part of the PMB mapping) and so needs to be + * added or subtracted as required. + */ +#ifdef CONFIG_PMB +#define ___pa(x) ((x)-PAGE_OFFSET+__MEMORY_START) +#define ___va(x) ((x)+PAGE_OFFSET-__MEMORY_START) +#else +#define ___pa(x) ((x)-PAGE_OFFSET) +#define ___va(x) ((x)+PAGE_OFFSET) +#endif + +#ifndef __ASSEMBLY__ +#define __pa(x) ___pa((unsigned long)x) +#define __va(x) (void *)___va((unsigned long)x) +#endif /* !__ASSEMBLY__ */ + +#ifdef CONFIG_UNCACHED_MAPPING +#if defined(CONFIG_29BIT) +#define UNCAC_ADDR(addr) P2SEGADDR(addr) +#define CAC_ADDR(addr) P1SEGADDR(addr) +#else +#define UNCAC_ADDR(addr) ((addr) - PAGE_OFFSET + uncached_start) +#define CAC_ADDR(addr) ((addr) - uncached_start + PAGE_OFFSET) +#endif +#else +#define UNCAC_ADDR(addr) ((addr)) +#define CAC_ADDR(addr) ((addr)) +#endif + +#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) +#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) + +/* + * PFN = physical frame number (ie PFN 0 == physical address 0) + * PFN_START is the PFN of the first page of RAM. By defining this we + * don't have struct page entries for the portion of address space + * between physical address 0 and the start of RAM. + */ +#define PFN_START (__MEMORY_START >> PAGE_SHIFT) +#define ARCH_PFN_OFFSET (PFN_START) +#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT) +#ifdef CONFIG_FLATMEM +#define pfn_valid(pfn) ((pfn) >= min_low_pfn && (pfn) < max_low_pfn) +#endif +#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT) + +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +#include <asm-generic/memory_model.h> +#include <asm-generic/getorder.h> + +/* + * Some drivers need to perform DMA into kmalloc'ed buffers + * and so we have to increase the kmalloc minalign for this. + */ +#define ARCH_DMA_MINALIGN L1_CACHE_BYTES + +#ifdef CONFIG_SUPERH64 +/* + * While BYTES_PER_WORD == 4 on the current sh64 ABI, GCC will still + * happily generate {ld/st}.q pairs, requiring us to have 8-byte + * alignment to avoid traps. The kmalloc alignment is guaranteed by + * virtue of L1_CACHE_BYTES, requiring this to only be special cased + * for slab caches. + */ +#define ARCH_SLAB_MINALIGN 8 +#endif + +#endif /* __ASM_SH_PAGE_H */ diff --git a/arch/sh/include/asm/pci.h b/arch/sh/include/asm/pci.h new file mode 100644 index 000000000..5b4511552 --- /dev/null +++ b/arch/sh/include/asm/pci.h @@ -0,0 +1,131 @@ +#ifndef __ASM_SH_PCI_H +#define __ASM_SH_PCI_H + +#ifdef __KERNEL__ + +/* Can be used to override the logic in pci_scan_bus for skipping + already-configured bus numbers - to be used for buggy BIOSes + or architectures with incomplete PCI setup by the loader */ + +#define pcibios_assign_all_busses() 1 + +/* + * A board can define one or more PCI channels that represent built-in (or + * external) PCI controllers. + */ +struct pci_channel { + struct pci_channel *next; + struct pci_bus *bus; + + struct pci_ops *pci_ops; + + struct resource *resources; + unsigned int nr_resources; + + unsigned long io_offset; + unsigned long mem_offset; + + unsigned long reg_base; + unsigned long io_map_base; + + unsigned int index; + unsigned int need_domain_info; + + /* Optional error handling */ + struct timer_list err_timer, serr_timer; + unsigned int err_irq, serr_irq; +}; + +/* arch/sh/drivers/pci/pci.c */ +extern raw_spinlock_t pci_config_lock; + +extern int register_pci_controller(struct pci_channel *hose); +extern void pcibios_report_status(unsigned int status_mask, int warn); + +/* arch/sh/drivers/pci/common.c */ +extern int early_read_config_byte(struct pci_channel *hose, int top_bus, + int bus, int devfn, int offset, u8 *value); +extern int early_read_config_word(struct pci_channel *hose, int top_bus, + int bus, int devfn, int offset, u16 *value); +extern int early_read_config_dword(struct pci_channel *hose, int top_bus, + int bus, int devfn, int offset, u32 *value); +extern int early_write_config_byte(struct pci_channel *hose, int top_bus, + int bus, int devfn, int offset, u8 value); +extern int early_write_config_word(struct pci_channel *hose, int top_bus, + int bus, int devfn, int offset, u16 value); +extern int early_write_config_dword(struct pci_channel *hose, int top_bus, + int bus, int devfn, int offset, u32 value); +extern void pcibios_enable_timers(struct pci_channel *hose); +extern unsigned int pcibios_handle_status_errors(unsigned long addr, + unsigned int status, struct pci_channel *hose); +extern int pci_is_66mhz_capable(struct pci_channel *hose, + int top_bus, int current_bus); + +extern unsigned long PCIBIOS_MIN_IO, PCIBIOS_MIN_MEM; + +struct pci_dev; + +#define HAVE_PCI_MMAP +extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, + enum pci_mmap_state mmap_state, int write_combine); +extern void pcibios_set_master(struct pci_dev *dev); + +/* Dynamic DMA mapping stuff. + * SuperH has everything mapped statically like x86. + */ + +/* The PCI address space does equal the physical memory + * address space. The networking and block device layers use + * this boolean for bounce buffer decisions. + */ +#define PCI_DMA_BUS_IS_PHYS (dma_ops->is_phys) + +#ifdef CONFIG_PCI +/* + * None of the SH PCI controllers support MWI, it is always treated as a + * direct memory write. + */ +#define PCI_DISABLE_MWI + +static inline void pci_dma_burst_advice(struct pci_dev *pdev, + enum pci_dma_burst_strategy *strat, + unsigned long *strategy_parameter) +{ + unsigned long cacheline_size; + u8 byte; + + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte); + + if (byte == 0) + cacheline_size = L1_CACHE_BYTES; + else + cacheline_size = byte << 2; + + *strat = PCI_DMA_BURST_MULTIPLE; + *strategy_parameter = cacheline_size; +} +#endif + +/* Board-specific fixup routines. */ +int pcibios_map_platform_irq(const struct pci_dev *dev, u8 slot, u8 pin); + +#define pci_domain_nr(bus) ((struct pci_channel *)(bus)->sysdata)->index + +static inline int pci_proc_domain(struct pci_bus *bus) +{ + struct pci_channel *hose = bus->sysdata; + return hose->need_domain_info; +} + +/* Chances are this interrupt is wired PC-style ... */ +static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) +{ + return channel ? 15 : 14; +} + +/* generic DMA-mapping stuff */ +#include <asm-generic/pci-dma-compat.h> + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_PCI_H */ + diff --git a/arch/sh/include/asm/perf_event.h b/arch/sh/include/asm/perf_event.h new file mode 100644 index 000000000..14308bed7 --- /dev/null +++ b/arch/sh/include/asm/perf_event.h @@ -0,0 +1,29 @@ +#ifndef __ASM_SH_PERF_EVENT_H +#define __ASM_SH_PERF_EVENT_H + +struct hw_perf_event; + +#define MAX_HWEVENTS 2 + +struct sh_pmu { + const char *name; + unsigned int num_events; + void (*disable_all)(void); + void (*enable_all)(void); + void (*enable)(struct hw_perf_event *, int); + void (*disable)(struct hw_perf_event *, int); + u64 (*read)(int); + int (*event_map)(int); + unsigned int max_events; + unsigned long raw_event_mask; + const int (*cache_events)[PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX]; +}; + +/* arch/sh/kernel/perf_event.c */ +extern int register_sh_pmu(struct sh_pmu *); +extern int reserve_pmc_hardware(void); +extern void release_pmc_hardware(void); + +#endif /* __ASM_SH_PERF_EVENT_H */ diff --git a/arch/sh/include/asm/pgalloc.h b/arch/sh/include/asm/pgalloc.h new file mode 100644 index 000000000..a33673b36 --- /dev/null +++ b/arch/sh/include/asm/pgalloc.h @@ -0,0 +1,79 @@ +#ifndef __ASM_SH_PGALLOC_H +#define __ASM_SH_PGALLOC_H + +#include <linux/quicklist.h> +#include <asm/page.h> + +#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); + +#if PAGETABLE_LEVELS > 2 +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) +{ + set_pmd(pmd, __pmd((unsigned long)pte)); +} + +static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, + pgtable_t pte) +{ + set_pmd(pmd, __pmd((unsigned long)page_address(pte))); +} +#define pmd_pgtable(pmd) pmd_page(pmd) + +/* + * Allocate and free page tables. + */ +static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, + unsigned long address) +{ + return quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL); +} + +static inline pgtable_t pte_alloc_one(struct mm_struct *mm, + unsigned long address) +{ + struct page *page; + void *pg; + + pg = quicklist_alloc(QUICK_PT, GFP_KERNEL | __GFP_REPEAT, NULL); + if (!pg) + return NULL; + page = virt_to_page(pg); + if (!pgtable_page_ctor(page)) { + quicklist_free(QUICK_PT, NULL, pg); + return NULL; + } + return page; +} + +static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) +{ + quicklist_free(QUICK_PT, NULL, pte); +} + +static inline void pte_free(struct mm_struct *mm, pgtable_t pte) +{ + pgtable_page_dtor(pte); + quicklist_free_page(QUICK_PT, NULL, pte); +} + +#define __pte_free_tlb(tlb,pte,addr) \ +do { \ + pgtable_page_dtor(pte); \ + tlb_remove_page((tlb), (pte)); \ +} while (0) + +static inline void check_pgt_cache(void) +{ + quicklist_trim(QUICK_PT, NULL, 25, 16); +} + +#endif /* __ASM_SH_PGALLOC_H */ diff --git a/arch/sh/include/asm/pgtable-2level.h b/arch/sh/include/asm/pgtable-2level.h new file mode 100644 index 000000000..19bd89db1 --- /dev/null +++ b/arch/sh/include/asm/pgtable-2level.h @@ -0,0 +1,23 @@ +#ifndef __ASM_SH_PGTABLE_2LEVEL_H +#define __ASM_SH_PGTABLE_2LEVEL_H + +#include <asm-generic/pgtable-nopmd.h> + +/* + * traditional two-level paging structure + */ +#define PAGETABLE_LEVELS 2 + +/* 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_2LEVEL_H */ diff --git a/arch/sh/include/asm/pgtable-3level.h b/arch/sh/include/asm/pgtable-3level.h new file mode 100644 index 000000000..249a985d9 --- /dev/null +++ b/arch/sh/include/asm/pgtable-3level.h @@ -0,0 +1,56 @@ +#ifndef __ASM_SH_PGTABLE_3LEVEL_H +#define __ASM_SH_PGTABLE_3LEVEL_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 PAGETABLE_LEVELS 3 + +#define PTE_MAGNITUDE 3 /* 64-bit PTEs on 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_3LEVEL_H */ diff --git a/arch/sh/include/asm/pgtable.h b/arch/sh/include/asm/pgtable.h new file mode 100644 index 000000000..89c513a98 --- /dev/null +++ b/arch/sh/include/asm/pgtable.h @@ -0,0 +1,163 @@ +/* + * This file contains the functions and defines necessary to modify and + * use the SuperH page table tree. + * + * Copyright (C) 1999 Niibe Yutaka + * Copyright (C) 2002 - 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. + */ +#ifndef __ASM_SH_PGTABLE_H +#define __ASM_SH_PGTABLE_H + +#ifdef CONFIG_X2TLB +#include <asm/pgtable-3level.h> +#else +#include <asm/pgtable-2level.h> +#endif +#include <asm/page.h> +#include <asm/mmu.h> + +#ifndef __ASSEMBLY__ +#include <asm/addrspace.h> +#include <asm/fixmap.h> + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)]; +#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) + +#endif /* !__ASSEMBLY__ */ + +/* + * Effective and physical address definitions, to aid with sign + * extension. + */ +#define NEFF 32 +#define NEFF_SIGN (1LL << (NEFF - 1)) +#define NEFF_MASK (-1LL << NEFF) + +static inline unsigned long long neff_sign_extend(unsigned long val) +{ + unsigned long long extended = val; + return (extended & NEFF_SIGN) ? (extended | NEFF_MASK) : extended; +} + +#ifdef CONFIG_29BIT +#define NPHYS 29 +#else +#define NPHYS 32 +#endif + +#define NPHYS_SIGN (1LL << (NPHYS - 1)) +#define NPHYS_MASK (-1LL << NPHYS) + +#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 FIRST_USER_ADDRESS 0UL + +#define PHYS_ADDR_MASK29 0x1fffffff +#define PHYS_ADDR_MASK32 0xffffffff + +static inline unsigned long phys_addr_mask(void) +{ + /* Is the MMU in 29bit mode? */ + if (__in_29bit_mode()) + return PHYS_ADDR_MASK29; + + return PHYS_ADDR_MASK32; +} + +#define PTE_PHYS_MASK (phys_addr_mask() & PAGE_MASK) +#define PTE_FLAGS_MASK (~(PTE_PHYS_MASK) << PAGE_SHIFT) + +#ifdef CONFIG_SUPERH32 +#define VMALLOC_START (P3SEG) +#else +#define VMALLOC_START (0xf0000000) +#endif +#define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE) + +#if defined(CONFIG_SUPERH32) +#include <asm/pgtable_32.h> +#else +#include <asm/pgtable_64.h> +#endif + +/* + * SH-X and lower (legacy) SuperH parts (SH-3, SH-4, some SH-4A) can't do page + * protection for execute, and considers it the same as a read. Also, write + * permission implies read permission. This is the closest we can get.. + * + * SH-X2 (SH7785) and later parts take this to the opposite end of the extreme, + * not only supporting separate execute, read, and write bits, but having + * completely separate permission bits for user and kernel space. + */ + /*xwr*/ +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY +#define __P010 PAGE_COPY +#define __P011 PAGE_COPY +#define __P100 PAGE_EXECREAD +#define __P101 PAGE_EXECREAD +#define __P110 PAGE_COPY +#define __P111 PAGE_COPY + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY +#define __S010 PAGE_WRITEONLY +#define __S011 PAGE_SHARED +#define __S100 PAGE_EXECREAD +#define __S101 PAGE_EXECREAD +#define __S110 PAGE_RWX +#define __S111 PAGE_RWX + +typedef pte_t *pte_addr_t; + +#define kern_addr_valid(addr) (1) + +#define pte_pfn(x) ((unsigned long)(((x).pte_low >> PAGE_SHIFT))) + +/* + * Initialise the page table caches + */ +extern void pgtable_cache_init(void); + +struct vm_area_struct; +struct mm_struct; + +extern void __update_cache(struct vm_area_struct *vma, + unsigned long address, pte_t pte); +extern void __update_tlb(struct vm_area_struct *vma, + unsigned long address, pte_t pte); + +static inline void +update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t *ptep) +{ + pte_t pte = *ptep; + __update_cache(vma, address, pte); + __update_tlb(vma, address, pte); +} + +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; +extern void paging_init(void); +extern void page_table_range_init(unsigned long start, unsigned long end, + pgd_t *pgd); + +/* arch/sh/mm/mmap.c */ +#define HAVE_ARCH_UNMAPPED_AREA +#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN + +#define __HAVE_ARCH_PTE_SPECIAL + +#include <asm-generic/pgtable.h> + +#endif /* __ASM_SH_PGTABLE_H */ diff --git a/arch/sh/include/asm/pgtable_32.h b/arch/sh/include/asm/pgtable_32.h new file mode 100644 index 000000000..c646e563a --- /dev/null +++ b/arch/sh/include/asm/pgtable_32.h @@ -0,0 +1,476 @@ +#ifndef __ASM_SH_PGTABLE_32_H +#define __ASM_SH_PGTABLE_32_H + +/* + * Linux PTEL encoding. + * + * Hardware and software bit definitions for the PTEL value (see below for + * notes on SH-X2 MMUs and 64-bit PTEs): + * + * - Bits 0 and 7 are reserved on SH-3 (_PAGE_WT and _PAGE_SZ1 on SH-4). + * + * - Bit 1 is the SH-bit, but is unused on SH-3 due to an MMU bug (the + * hardware PTEL value can't have the SH-bit set when MMUCR.IX is set, + * which is the default in cpu-sh3/mmu_context.h:MMU_CONTROL_INIT). + * + * In order to keep this relatively clean, do not use these for defining + * SH-3 specific flags until all of the other unused bits have been + * exhausted. + * + * - Bit 9 is reserved by everyone and used by _PAGE_PROTNONE. + * + * - Bits 10 and 11 are low bits of the PPN that are reserved on >= 4K pages. + * Bit 10 is used for _PAGE_ACCESSED, and bit 11 is used for _PAGE_SPECIAL. + * + * - On 29 bit platforms, bits 31 to 29 are used for the space attributes + * and timing control which (together with bit 0) are moved into the + * old-style PTEA on the parts that support it. + * + * SH-X2 MMUs and extended PTEs + * + * SH-X2 supports an extended mode TLB with split data arrays due to the + * number of bits needed for PR and SZ (now EPR and ESZ) encodings. The PR and + * SZ bit placeholders still exist in data array 1, but are implemented as + * reserved bits, with the real logic existing in data array 2. + * + * The downside to this is that we can no longer fit everything in to a 32-bit + * PTE encoding, so a 64-bit pte_t is necessary for these parts. On the plus + * side, this gives us quite a few spare bits to play with for future usage. + */ +/* Legacy and compat mode bits */ +#define _PAGE_WT 0x001 /* WT-bit on SH-4, 0 on SH-3 */ +#define _PAGE_HW_SHARED 0x002 /* SH-bit : shared among processes */ +#define _PAGE_DIRTY 0x004 /* D-bit : page changed */ +#define _PAGE_CACHABLE 0x008 /* C-bit : cachable */ +#define _PAGE_SZ0 0x010 /* SZ0-bit : Size of page */ +#define _PAGE_RW 0x020 /* PR0-bit : write access allowed */ +#define _PAGE_USER 0x040 /* PR1-bit : user space access allowed*/ +#define _PAGE_SZ1 0x080 /* SZ1-bit : Size of page (on SH-4) */ +#define _PAGE_PRESENT 0x100 /* V-bit : page is valid */ +#define _PAGE_PROTNONE 0x200 /* software: if not present */ +#define _PAGE_ACCESSED 0x400 /* software: page referenced */ +#define _PAGE_SPECIAL 0x800 /* software: special page */ + +#define _PAGE_SZ_MASK (_PAGE_SZ0 | _PAGE_SZ1) +#define _PAGE_PR_MASK (_PAGE_RW | _PAGE_USER) + +/* Extended mode bits */ +#define _PAGE_EXT_ESZ0 0x0010 /* ESZ0-bit: Size of page */ +#define _PAGE_EXT_ESZ1 0x0020 /* ESZ1-bit: Size of page */ +#define _PAGE_EXT_ESZ2 0x0040 /* ESZ2-bit: Size of page */ +#define _PAGE_EXT_ESZ3 0x0080 /* ESZ3-bit: Size of page */ + +#define _PAGE_EXT_USER_EXEC 0x0100 /* EPR0-bit: User space executable */ +#define _PAGE_EXT_USER_WRITE 0x0200 /* EPR1-bit: User space writable */ +#define _PAGE_EXT_USER_READ 0x0400 /* EPR2-bit: User space readable */ + +#define _PAGE_EXT_KERN_EXEC 0x0800 /* EPR3-bit: Kernel space executable */ +#define _PAGE_EXT_KERN_WRITE 0x1000 /* EPR4-bit: Kernel space writable */ +#define _PAGE_EXT_KERN_READ 0x2000 /* EPR5-bit: Kernel space readable */ + +#define _PAGE_EXT_WIRED 0x4000 /* software: Wire TLB entry */ + +/* Wrapper for extended mode pgprot twiddling */ +#define _PAGE_EXT(x) ((unsigned long long)(x) << 32) + +#ifdef CONFIG_X2TLB +#define _PAGE_PCC_MASK 0x00000000 /* No legacy PTEA support */ +#else + +/* software: moves to PTEA.TC (Timing Control) */ +#define _PAGE_PCC_AREA5 0x00000000 /* use BSC registers for area5 */ +#define _PAGE_PCC_AREA6 0x80000000 /* use BSC registers for area6 */ + +/* software: moves to PTEA.SA[2:0] (Space Attributes) */ +#define _PAGE_PCC_IODYN 0x00000001 /* IO space, dynamically sized bus */ +#define _PAGE_PCC_IO8 0x20000000 /* IO space, 8 bit bus */ +#define _PAGE_PCC_IO16 0x20000001 /* IO space, 16 bit bus */ +#define _PAGE_PCC_COM8 0x40000000 /* Common Memory space, 8 bit bus */ +#define _PAGE_PCC_COM16 0x40000001 /* Common Memory space, 16 bit bus */ +#define _PAGE_PCC_ATR8 0x60000000 /* Attribute Memory space, 8 bit bus */ +#define _PAGE_PCC_ATR16 0x60000001 /* Attribute Memory space, 6 bit bus */ + +#define _PAGE_PCC_MASK 0xe0000001 + +/* copy the ptea attributes */ +static inline unsigned long copy_ptea_attributes(unsigned long x) +{ + return ((x >> 28) & 0xe) | (x & 0x1); +} +#endif + +/* Mask which drops unused bits from the PTEL value */ +#if defined(CONFIG_CPU_SH3) +#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED| \ + _PAGE_SZ1 | _PAGE_HW_SHARED) +#elif defined(CONFIG_X2TLB) +/* Get rid of the legacy PR/SZ bits when using extended mode */ +#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | \ + _PAGE_PR_MASK | _PAGE_SZ_MASK) +#else +#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED) +#endif + +#define _PAGE_FLAGS_HARDWARE_MASK (phys_addr_mask() & ~(_PAGE_CLEAR_FLAGS)) + +/* Hardware flags, page size encoding */ +#if !defined(CONFIG_MMU) +# define _PAGE_FLAGS_HARD 0ULL +#elif defined(CONFIG_X2TLB) +# if defined(CONFIG_PAGE_SIZE_4KB) +# define _PAGE_FLAGS_HARD _PAGE_EXT(_PAGE_EXT_ESZ0) +# elif defined(CONFIG_PAGE_SIZE_8KB) +# define _PAGE_FLAGS_HARD _PAGE_EXT(_PAGE_EXT_ESZ1) +# elif defined(CONFIG_PAGE_SIZE_64KB) +# define _PAGE_FLAGS_HARD _PAGE_EXT(_PAGE_EXT_ESZ2) +# endif +#else +# if defined(CONFIG_PAGE_SIZE_4KB) +# define _PAGE_FLAGS_HARD _PAGE_SZ0 +# elif defined(CONFIG_PAGE_SIZE_64KB) +# define _PAGE_FLAGS_HARD _PAGE_SZ1 +# endif +#endif + +#if defined(CONFIG_X2TLB) +# if defined(CONFIG_HUGETLB_PAGE_SIZE_64K) +# define _PAGE_SZHUGE (_PAGE_EXT_ESZ2) +# elif defined(CONFIG_HUGETLB_PAGE_SIZE_256K) +# define _PAGE_SZHUGE (_PAGE_EXT_ESZ0 | _PAGE_EXT_ESZ2) +# elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB) +# define _PAGE_SZHUGE (_PAGE_EXT_ESZ0 | _PAGE_EXT_ESZ1 | _PAGE_EXT_ESZ2) +# elif defined(CONFIG_HUGETLB_PAGE_SIZE_4MB) +# define _PAGE_SZHUGE (_PAGE_EXT_ESZ3) +# elif defined(CONFIG_HUGETLB_PAGE_SIZE_64MB) +# define _PAGE_SZHUGE (_PAGE_EXT_ESZ2 | _PAGE_EXT_ESZ3) +# endif +# define _PAGE_WIRED (_PAGE_EXT(_PAGE_EXT_WIRED)) +#else +# if defined(CONFIG_HUGETLB_PAGE_SIZE_64K) +# define _PAGE_SZHUGE (_PAGE_SZ1) +# elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB) +# define _PAGE_SZHUGE (_PAGE_SZ0 | _PAGE_SZ1) +# endif +# define _PAGE_WIRED (0) +#endif + +/* + * Stub out _PAGE_SZHUGE if we don't have a good definition for it, + * to make pte_mkhuge() happy. + */ +#ifndef _PAGE_SZHUGE +# define _PAGE_SZHUGE (_PAGE_FLAGS_HARD) +#endif + +/* + * Mask of bits that are to be preserved across pgprot changes. + */ +#define _PAGE_CHG_MASK \ + (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | \ + _PAGE_DIRTY | _PAGE_SPECIAL) + +#ifndef __ASSEMBLY__ + +#if defined(CONFIG_X2TLB) /* SH-X2 TLB */ +#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \ + _PAGE_ACCESSED | _PAGE_FLAGS_HARD) + +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ + _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_KERN_READ | \ + _PAGE_EXT_KERN_WRITE | \ + _PAGE_EXT_USER_READ | \ + _PAGE_EXT_USER_WRITE)) + +#define PAGE_EXECREAD __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ + _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_KERN_EXEC | \ + _PAGE_EXT_KERN_READ | \ + _PAGE_EXT_USER_EXEC | \ + _PAGE_EXT_USER_READ)) + +#define PAGE_COPY PAGE_EXECREAD + +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ + _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_KERN_READ | \ + _PAGE_EXT_USER_READ)) + +#define PAGE_WRITEONLY __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ + _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_KERN_WRITE | \ + _PAGE_EXT_USER_WRITE)) + +#define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | \ + _PAGE_CACHABLE | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_KERN_WRITE | \ + _PAGE_EXT_KERN_READ | \ + _PAGE_EXT_KERN_EXEC | \ + _PAGE_EXT_USER_WRITE | \ + _PAGE_EXT_USER_READ | \ + _PAGE_EXT_USER_EXEC)) + +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \ + _PAGE_DIRTY | _PAGE_ACCESSED | \ + _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_KERN_READ | \ + _PAGE_EXT_KERN_WRITE | \ + _PAGE_EXT_KERN_EXEC)) + +#define PAGE_KERNEL_NOCACHE \ + __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | \ + _PAGE_ACCESSED | _PAGE_HW_SHARED | \ + _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_KERN_READ | \ + _PAGE_EXT_KERN_WRITE | \ + _PAGE_EXT_KERN_EXEC)) + +#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \ + _PAGE_DIRTY | _PAGE_ACCESSED | \ + _PAGE_HW_SHARED | _PAGE_FLAGS_HARD | \ + _PAGE_EXT(_PAGE_EXT_KERN_READ | \ + _PAGE_EXT_KERN_EXEC)) + +#define PAGE_KERNEL_PCC(slot, type) \ + __pgprot(0) + +#elif defined(CONFIG_MMU) /* SH-X TLB */ +#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE | \ + _PAGE_ACCESSED | _PAGE_FLAGS_HARD) + +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \ + _PAGE_CACHABLE | _PAGE_ACCESSED | \ + _PAGE_FLAGS_HARD) + +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | \ + _PAGE_ACCESSED | _PAGE_FLAGS_HARD) + +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | \ + _PAGE_ACCESSED | _PAGE_FLAGS_HARD) + +#define PAGE_EXECREAD PAGE_READONLY +#define PAGE_RWX PAGE_SHARED +#define PAGE_WRITEONLY PAGE_SHARED + +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | \ + _PAGE_DIRTY | _PAGE_ACCESSED | \ + _PAGE_HW_SHARED | _PAGE_FLAGS_HARD) + +#define PAGE_KERNEL_NOCACHE \ + __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \ + _PAGE_ACCESSED | _PAGE_HW_SHARED | \ + _PAGE_FLAGS_HARD) + +#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_CACHABLE | \ + _PAGE_DIRTY | _PAGE_ACCESSED | \ + _PAGE_HW_SHARED | _PAGE_FLAGS_HARD) + +#define PAGE_KERNEL_PCC(slot, type) \ + __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \ + _PAGE_ACCESSED | _PAGE_FLAGS_HARD | \ + (slot ? _PAGE_PCC_AREA5 : _PAGE_PCC_AREA6) | \ + (type)) +#else /* no mmu */ +#define PAGE_NONE __pgprot(0) +#define PAGE_SHARED __pgprot(0) +#define PAGE_COPY __pgprot(0) +#define PAGE_EXECREAD __pgprot(0) +#define PAGE_RWX __pgprot(0) +#define PAGE_READONLY __pgprot(0) +#define PAGE_WRITEONLY __pgprot(0) +#define PAGE_KERNEL __pgprot(0) +#define PAGE_KERNEL_NOCACHE __pgprot(0) +#define PAGE_KERNEL_RO __pgprot(0) + +#define PAGE_KERNEL_PCC(slot, type) \ + __pgprot(0) +#endif + +#endif /* __ASSEMBLY__ */ + +#ifndef __ASSEMBLY__ + +/* + * Certain architectures need to do special things when PTEs + * within a page table are directly modified. Thus, the following + * hook is made available. + */ +#ifdef CONFIG_X2TLB +static inline void set_pte(pte_t *ptep, pte_t pte) +{ + ptep->pte_high = pte.pte_high; + smp_wmb(); + ptep->pte_low = pte.pte_low; +} +#else +#define set_pte(pteptr, pteval) (*(pteptr) = pteval) +#endif + +#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) + +/* + * (pmds are folded into pgds so this doesn't get actually called, + * but the define is needed for a generic inline function.) + */ +#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) + +#define pfn_pte(pfn, prot) \ + __pte(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot)) +#define pfn_pmd(pfn, prot) \ + __pmd(((unsigned long long)(pfn) << PAGE_SHIFT) | pgprot_val(prot)) + +#define pte_none(x) (!pte_val(x)) +#define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE)) + +#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0) + +#define pmd_none(x) (!pmd_val(x)) +#define pmd_present(x) (pmd_val(x)) +#define pmd_clear(xp) do { set_pmd(xp, __pmd(0)); } while (0) +#define pmd_bad(x) (pmd_val(x) & ~PAGE_MASK) + +#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) +#define pte_page(x) pfn_to_page(pte_pfn(x)) + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ +#define pte_not_present(pte) (!((pte).pte_low & _PAGE_PRESENT)) +#define pte_dirty(pte) ((pte).pte_low & _PAGE_DIRTY) +#define pte_young(pte) ((pte).pte_low & _PAGE_ACCESSED) +#define pte_special(pte) ((pte).pte_low & _PAGE_SPECIAL) + +#ifdef CONFIG_X2TLB +#define pte_write(pte) \ + ((pte).pte_high & (_PAGE_EXT_USER_WRITE | _PAGE_EXT_KERN_WRITE)) +#else +#define pte_write(pte) ((pte).pte_low & _PAGE_RW) +#endif + +#define PTE_BIT_FUNC(h,fn,op) \ +static inline pte_t pte_##fn(pte_t pte) { pte.pte_##h op; return pte; } + +#ifdef CONFIG_X2TLB +/* + * We cheat a bit in the SH-X2 TLB case. As the permission bits are + * individually toggled (and user permissions are entirely decoupled from + * kernel permissions), we attempt to couple them a bit more sanely here. + */ +PTE_BIT_FUNC(high, wrprotect, &= ~(_PAGE_EXT_USER_WRITE | _PAGE_EXT_KERN_WRITE)); +PTE_BIT_FUNC(high, mkwrite, |= _PAGE_EXT_USER_WRITE | _PAGE_EXT_KERN_WRITE); +PTE_BIT_FUNC(high, mkhuge, |= _PAGE_SZHUGE); +#else +PTE_BIT_FUNC(low, wrprotect, &= ~_PAGE_RW); +PTE_BIT_FUNC(low, mkwrite, |= _PAGE_RW); +PTE_BIT_FUNC(low, mkhuge, |= _PAGE_SZHUGE); +#endif + +PTE_BIT_FUNC(low, mkclean, &= ~_PAGE_DIRTY); +PTE_BIT_FUNC(low, mkdirty, |= _PAGE_DIRTY); +PTE_BIT_FUNC(low, mkold, &= ~_PAGE_ACCESSED); +PTE_BIT_FUNC(low, mkyoung, |= _PAGE_ACCESSED); +PTE_BIT_FUNC(low, mkspecial, |= _PAGE_SPECIAL); + +/* + * Macro and implementation to make a page protection as uncachable. + */ +#define pgprot_writecombine(prot) \ + __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE) + +#define pgprot_noncached pgprot_writecombine + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + * + * extern pte_t mk_pte(struct page *page, pgprot_t pgprot) + */ +#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) + +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + pte.pte_low &= _PAGE_CHG_MASK; + pte.pte_low |= pgprot_val(newprot); + +#ifdef CONFIG_X2TLB + pte.pte_high |= pgprot_val(newprot) >> 32; +#endif + + return pte; +} + +#define pmd_page_vaddr(pmd) ((unsigned long)pmd_val(pmd)) +#define pmd_page(pmd) (virt_to_page(pmd_val(pmd))) + +/* to find an entry in a page-table-directory. */ +#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) +#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) +#define __pgd_offset(address) pgd_index(address) + +/* to find an entry in a kernel page-table-directory */ +#define pgd_offset_k(address) pgd_offset(&init_mm, address) + +#define __pud_offset(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) +#define __pmd_offset(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) + +/* Find an entry in the third-level page table.. */ +#define pte_index(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +#define __pte_offset(address) pte_index(address) + +#define pte_offset_kernel(dir, address) \ + ((pte_t *) pmd_page_vaddr(*(dir)) + pte_index(address)) +#define pte_offset_map(dir, address) pte_offset_kernel(dir, address) +#define pte_unmap(pte) do { } while (0) + +#ifdef CONFIG_X2TLB +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %p(%08lx%08lx).\n", __FILE__, __LINE__, \ + &(e), (e).pte_high, (e).pte_low) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %016llx.\n", __FILE__, __LINE__, pgd_val(e)) +#else +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e)) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) +#endif + +/* + * Encode and de-code a swap entry + * + * Constraints: + * _PAGE_PRESENT at bit 8 + * _PAGE_PROTNONE at bit 9 + * + * For the normal case, we encode the swap type into bits 0:7 and the + * swap offset into bits 10:30. For the 64-bit PTE case, we keep the + * preserved bits in the low 32-bits and use the upper 32 as the swap + * offset (along with a 5-bit type), following the same approach as x86 + * PAE. This keeps the logic quite simple. + * + * As is evident by the Alpha code, if we ever get a 64-bit unsigned + * long (swp_entry_t) to match up with the 64-bit PTEs, this all becomes + * much cleaner.. + * + * NOTE: We should set ZEROs at the position of _PAGE_PRESENT + * and _PAGE_PROTNONE bits + */ +#ifdef CONFIG_X2TLB +#define __swp_type(x) ((x).val & 0x1f) +#define __swp_offset(x) ((x).val >> 5) +#define __swp_entry(type, offset) ((swp_entry_t){ (type) | (offset) << 5}) +#define __pte_to_swp_entry(pte) ((swp_entry_t){ (pte).pte_high }) +#define __swp_entry_to_pte(x) ((pte_t){ 0, (x).val }) + +#else +#define __swp_type(x) ((x).val & 0xff) +#define __swp_offset(x) ((x).val >> 10) +#define __swp_entry(type, offset) ((swp_entry_t){(type) | (offset) <<10}) + +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) >> 1 }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val << 1 }) +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_SH_PGTABLE_32_H */ diff --git a/arch/sh/include/asm/pgtable_64.h b/arch/sh/include/asm/pgtable_64.h new file mode 100644 index 000000000..07424968d --- /dev/null +++ b/arch/sh/include/asm/pgtable_64.h @@ -0,0 +1,310 @@ +#ifndef __ASM_SH_PGTABLE_64_H +#define __ASM_SH_PGTABLE_64_H + +/* + * include/asm-sh/pgtable_64.h + * + * This file contains the functions and defines necessary to modify and use + * the SuperH page table tree. + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * Copyright (C) 2003, 2004 Richard Curnow + * + * 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/threads.h> +#include <asm/processor.h> +#include <asm/page.h> + +/* + * Error outputs. + */ +#define pte_ERROR(e) \ + printk("%s:%d: bad pte %016Lx.\n", __FILE__, __LINE__, pte_val(e)) +#define pgd_ERROR(e) \ + printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) + +/* + * Table setting routines. Used within arch/mm only. + */ +#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) + +static __inline__ void set_pte(pte_t *pteptr, pte_t pteval) +{ + unsigned long long x = ((unsigned long long) pteval.pte_low); + unsigned long long *xp = (unsigned long long *) pteptr; + /* + * Sign-extend based on NPHYS. + */ + *(xp) = (x & NPHYS_SIGN) ? (x | NPHYS_MASK) : x; +} +#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval) + +/* + * PGD defines. Top level. + */ + +/* To find an entry in a generic PGD. */ +#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) +#define __pgd_offset(address) pgd_index(address) +#define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) + +/* To find an entry in a kernel PGD. */ +#define pgd_offset_k(address) pgd_offset(&init_mm, address) + +#define __pud_offset(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD-1)) +#define __pmd_offset(address) (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) + +/* + * PMD level access routines. Same notes as above. + */ +#define _PMD_EMPTY 0x0 +/* Either the PMD is empty or present, it's not paged out */ +#define pmd_present(pmd_entry) (pmd_val(pmd_entry) & _PAGE_PRESENT) +#define pmd_clear(pmd_entry_p) (set_pmd((pmd_entry_p), __pmd(_PMD_EMPTY))) +#define pmd_none(pmd_entry) (pmd_val((pmd_entry)) == _PMD_EMPTY) +#define pmd_bad(pmd_entry) ((pmd_val(pmd_entry) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) + +#define pmd_page_vaddr(pmd_entry) \ + ((unsigned long) __va(pmd_val(pmd_entry) & PAGE_MASK)) + +#define pmd_page(pmd) \ + (virt_to_page(pmd_val(pmd))) + +/* PMD to PTE dereferencing */ +#define pte_index(address) \ + ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) + +#define __pte_offset(address) pte_index(address) + +#define pte_offset_kernel(dir, addr) \ + ((pte_t *) ((pmd_val(*(dir))) & PAGE_MASK) + pte_index((addr))) + +#define pte_offset_map(dir,addr) pte_offset_kernel(dir, addr) +#define pte_unmap(pte) do { } while (0) + +#ifndef __ASSEMBLY__ +/* + * PTEL coherent flags. + * See Chapter 17 ST50 CPU Core Volume 1, Architecture. + */ +/* The bits that are required in the SH-5 TLB are placed in the h/w-defined + positions, to avoid expensive bit shuffling on every refill. The remaining + bits are used for s/w purposes and masked out on each refill. + + Note, the PTE slots are used to hold data of type swp_entry_t when a page is + swapped out. Only the _PAGE_PRESENT flag is significant when the page is + swapped out, and it must be placed so that it doesn't overlap either the + type or offset fields of swp_entry_t. For x86, offset is at [31:8] and type + at [6:1], with _PAGE_PRESENT at bit 0 for both pte_t and swp_entry_t. This + scheme doesn't map to SH-5 because bit [0] controls cacheability. So bit + [2] is used for _PAGE_PRESENT and the type field of swp_entry_t is split + into 2 pieces. That is handled by SWP_ENTRY and SWP_TYPE below. */ +#define _PAGE_WT 0x001 /* CB0: if cacheable, 1->write-thru, 0->write-back */ +#define _PAGE_DEVICE 0x001 /* CB0: if uncacheable, 1->device (i.e. no write-combining or reordering at bus level) */ +#define _PAGE_CACHABLE 0x002 /* CB1: uncachable/cachable */ +#define _PAGE_PRESENT 0x004 /* software: page referenced */ +#define _PAGE_SIZE0 0x008 /* SZ0-bit : size of page */ +#define _PAGE_SIZE1 0x010 /* SZ1-bit : size of page */ +#define _PAGE_SHARED 0x020 /* software: reflects PTEH's SH */ +#define _PAGE_READ 0x040 /* PR0-bit : read access allowed */ +#define _PAGE_EXECUTE 0x080 /* PR1-bit : execute access allowed */ +#define _PAGE_WRITE 0x100 /* PR2-bit : write access allowed */ +#define _PAGE_USER 0x200 /* PR3-bit : user space access allowed */ +#define _PAGE_DIRTY 0x400 /* software: page accessed in write */ +#define _PAGE_ACCESSED 0x800 /* software: page referenced */ + +/* Wrapper for extended mode pgprot twiddling */ +#define _PAGE_EXT(x) ((unsigned long long)(x) << 32) + +/* + * We can use the sign-extended bits in the PTEL to get 32 bits of + * software flags. This works for now because no implementations uses + * anything above the PPN field. + */ +#define _PAGE_WIRED _PAGE_EXT(0x001) /* software: wire the tlb entry */ +#define _PAGE_SPECIAL _PAGE_EXT(0x002) + +#define _PAGE_CLEAR_FLAGS (_PAGE_PRESENT | _PAGE_SHARED | \ + _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_WIRED) + +/* Mask which drops software flags */ +#define _PAGE_FLAGS_HARDWARE_MASK (NEFF_MASK & ~(_PAGE_CLEAR_FLAGS)) + +/* + * HugeTLB support + */ +#if defined(CONFIG_HUGETLB_PAGE_SIZE_64K) +#define _PAGE_SZHUGE (_PAGE_SIZE0) +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_1MB) +#define _PAGE_SZHUGE (_PAGE_SIZE1) +#elif defined(CONFIG_HUGETLB_PAGE_SIZE_512MB) +#define _PAGE_SZHUGE (_PAGE_SIZE0 | _PAGE_SIZE1) +#endif + +/* + * Stub out _PAGE_SZHUGE if we don't have a good definition for it, + * to make pte_mkhuge() happy. + */ +#ifndef _PAGE_SZHUGE +# define _PAGE_SZHUGE (0) +#endif + +/* + * Default flags for a Kernel page. + * This is fundametally also SHARED because the main use of this define + * (other than for PGD/PMD entries) is for the VMALLOC pool which is + * contextless. + * + * _PAGE_EXECUTE is required for modules + * + */ +#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ + _PAGE_EXECUTE | \ + _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_DIRTY | \ + _PAGE_SHARED) + +/* Default flags for a User page */ +#define _PAGE_TABLE (_KERNPG_TABLE | _PAGE_USER) + +#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | \ + _PAGE_SPECIAL) + +/* + * We have full permissions (Read/Write/Execute/Shared). + */ +#define _PAGE_COMMON (_PAGE_PRESENT | _PAGE_USER | \ + _PAGE_CACHABLE | _PAGE_ACCESSED) + +#define PAGE_NONE __pgprot(_PAGE_CACHABLE | _PAGE_ACCESSED) +#define PAGE_SHARED __pgprot(_PAGE_COMMON | _PAGE_READ | _PAGE_WRITE | \ + _PAGE_SHARED) +#define PAGE_EXECREAD __pgprot(_PAGE_COMMON | _PAGE_READ | _PAGE_EXECUTE) + +/* + * We need to include PAGE_EXECUTE in PAGE_COPY because it is the default + * protection mode for the stack. + */ +#define PAGE_COPY PAGE_EXECREAD + +#define PAGE_READONLY __pgprot(_PAGE_COMMON | _PAGE_READ) +#define PAGE_WRITEONLY __pgprot(_PAGE_COMMON | _PAGE_WRITE) +#define PAGE_RWX __pgprot(_PAGE_COMMON | _PAGE_READ | \ + _PAGE_WRITE | _PAGE_EXECUTE) +#define PAGE_KERNEL __pgprot(_KERNPG_TABLE) + +#define PAGE_KERNEL_NOCACHE \ + __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | \ + _PAGE_EXECUTE | _PAGE_ACCESSED | \ + _PAGE_DIRTY | _PAGE_SHARED) + +/* Make it a device mapping for maximum safety (e.g. for mapping device + registers into user-space via /dev/map). */ +#define pgprot_noncached(x) __pgprot(((x).pgprot & ~(_PAGE_CACHABLE)) | _PAGE_DEVICE) +#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~_PAGE_CACHABLE) + +/* + * PTE level access routines. + * + * Note1: + * It's the tree walk leaf. This is physical address to be stored. + * + * Note 2: + * Regarding the choice of _PTE_EMPTY: + + We must choose a bit pattern that cannot be valid, whether or not the page + is present. bit[2]==1 => present, bit[2]==0 => swapped out. If swapped + out, bits [31:8], [6:3], [1:0] are under swapper control, so only bit[7] is + left for us to select. If we force bit[7]==0 when swapped out, we could use + the combination bit[7,2]=2'b10 to indicate an empty PTE. Alternatively, if + we force bit[7]==1 when swapped out, we can use all zeroes to indicate + empty. This is convenient, because the page tables get cleared to zero + when they are allocated. + + */ +#define _PTE_EMPTY 0x0 +#define pte_present(x) (pte_val(x) & _PAGE_PRESENT) +#define pte_clear(mm,addr,xp) (set_pte_at(mm, addr, xp, __pte(_PTE_EMPTY))) +#define pte_none(x) (pte_val(x) == _PTE_EMPTY) + +/* + * Some definitions to translate between mem_map, PTEs, and page + * addresses: + */ + +/* + * Given a PTE, return the index of the mem_map[] entry corresponding + * to the page frame the PTE. Get the absolute physical address, make + * a relative physical address and translate it to an index. + */ +#define pte_pagenr(x) (((unsigned long) (pte_val(x)) - \ + __MEMORY_START) >> PAGE_SHIFT) + +/* + * Given a PTE, return the "struct page *". + */ +#define pte_page(x) (mem_map + pte_pagenr(x)) + +/* + * Return number of (down rounded) MB corresponding to x pages. + */ +#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) + + +/* + * The following have defined behavior only work if pte_present() is true. + */ +static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } +static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } +static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; } +static inline int pte_special(pte_t pte){ return pte_val(pte) & _PAGE_SPECIAL; } + +static inline pte_t pte_wrprotect(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_WRITE)); return pte; } +static inline pte_t pte_mkclean(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_DIRTY)); return pte; } +static inline pte_t pte_mkold(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) & ~_PAGE_ACCESSED)); return pte; } +static inline pte_t pte_mkwrite(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_WRITE)); return pte; } +static inline pte_t pte_mkdirty(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_DIRTY)); return pte; } +static inline pte_t pte_mkyoung(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_ACCESSED)); return pte; } +static inline pte_t pte_mkhuge(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_SZHUGE)); return pte; } +static inline pte_t pte_mkspecial(pte_t pte) { set_pte(&pte, __pte(pte_val(pte) | _PAGE_SPECIAL)); return pte; } + +/* + * Conversion functions: convert a page and protection to a page entry. + * + * extern pte_t mk_pte(struct page *page, pgprot_t pgprot) + */ +#define mk_pte(page,pgprot) \ +({ \ + pte_t __pte; \ + \ + set_pte(&__pte, __pte((((page)-mem_map) << PAGE_SHIFT) | \ + __MEMORY_START | pgprot_val((pgprot)))); \ + __pte; \ +}) + +/* + * This takes a (absolute) physical page address that is used + * by the remapping functions + */ +#define mk_pte_phys(physpage, pgprot) \ +({ pte_t __pte; set_pte(&__pte, __pte(physpage | pgprot_val(pgprot))); __pte; }) + +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ set_pte(&pte, __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot))); return pte; } + +/* Encode and decode a swap entry */ +#define __swp_type(x) (((x).val & 3) + (((x).val >> 1) & 0x3c)) +#define __swp_offset(x) ((x).val >> 8) +#define __swp_entry(type, offset) ((swp_entry_t) { ((offset << 8) + ((type & 0x3c) << 1) + (type & 3)) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) + +#endif /* !__ASSEMBLY__ */ + +#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) +#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) + +#endif /* __ASM_SH_PGTABLE_64_H */ diff --git a/arch/sh/include/asm/posix_types.h b/arch/sh/include/asm/posix_types.h new file mode 100644 index 000000000..1aa781079 --- /dev/null +++ b/arch/sh/include/asm/posix_types.h @@ -0,0 +1,5 @@ +# ifdef CONFIG_SUPERH32 +# include <asm/posix_types_32.h> +# else +# include <asm/posix_types_64.h> +# endif diff --git a/arch/sh/include/asm/processor.h b/arch/sh/include/asm/processor.h new file mode 100644 index 000000000..150689764 --- /dev/null +++ b/arch/sh/include/asm/processor.h @@ -0,0 +1,184 @@ +#ifndef __ASM_SH_PROCESSOR_H +#define __ASM_SH_PROCESSOR_H + +#include <asm/cpu-features.h> +#include <asm/segment.h> +#include <asm/cache.h> + +#ifndef __ASSEMBLY__ +/* + * CPU type and hardware bug flags. Kept separately for each CPU. + * + * Each one of these also needs a CONFIG_CPU_SUBTYPE_xxx entry + * in arch/sh/mm/Kconfig, as well as an entry in arch/sh/kernel/setup.c + * for parsing the subtype in get_cpu_subtype(). + */ +enum cpu_type { + /* SH-2 types */ + CPU_SH7619, + + /* SH-2A types */ + CPU_SH7201, CPU_SH7203, CPU_SH7206, CPU_SH7263, CPU_SH7264, CPU_SH7269, + CPU_MXG, + + /* SH-3 types */ + CPU_SH7705, CPU_SH7706, CPU_SH7707, + CPU_SH7708, CPU_SH7708S, CPU_SH7708R, + CPU_SH7709, CPU_SH7709A, CPU_SH7710, CPU_SH7712, + CPU_SH7720, CPU_SH7721, CPU_SH7729, + + /* SH-4 types */ + CPU_SH7750, CPU_SH7750S, CPU_SH7750R, CPU_SH7751, CPU_SH7751R, + CPU_SH7760, CPU_SH4_202, CPU_SH4_501, + + /* SH-4A types */ + CPU_SH7763, CPU_SH7770, CPU_SH7780, CPU_SH7781, CPU_SH7785, CPU_SH7786, + CPU_SH7723, CPU_SH7724, CPU_SH7757, CPU_SH7734, CPU_SHX3, + + /* SH4AL-DSP types */ + CPU_SH7343, CPU_SH7722, CPU_SH7366, CPU_SH7372, + + /* SH-5 types */ + CPU_SH5_101, CPU_SH5_103, + + /* Unknown subtype */ + CPU_SH_NONE +}; + +enum cpu_family { + CPU_FAMILY_SH2, + CPU_FAMILY_SH2A, + CPU_FAMILY_SH3, + CPU_FAMILY_SH4, + CPU_FAMILY_SH4A, + CPU_FAMILY_SH4AL_DSP, + CPU_FAMILY_SH5, + CPU_FAMILY_UNKNOWN, +}; + +/* + * TLB information structure + * + * Defined for both I and D tlb, per-processor. + */ +struct tlb_info { + unsigned long long next; + unsigned long long first; + unsigned long long last; + + unsigned int entries; + unsigned int step; + + unsigned long flags; +}; + +struct sh_cpuinfo { + unsigned int type, family; + int cut_major, cut_minor; + unsigned long loops_per_jiffy; + unsigned long asid_cache; + + struct cache_info icache; /* Primary I-cache */ + struct cache_info dcache; /* Primary D-cache */ + struct cache_info scache; /* Secondary cache */ + + /* TLB info */ + struct tlb_info itlb; + struct tlb_info dtlb; + + unsigned int phys_bits; + unsigned long flags; +} __attribute__ ((aligned(L1_CACHE_BYTES))); + +extern struct sh_cpuinfo cpu_data[]; +#define boot_cpu_data cpu_data[0] +#define current_cpu_data cpu_data[smp_processor_id()] +#define raw_current_cpu_data cpu_data[raw_smp_processor_id()] + +#define cpu_sleep() __asm__ __volatile__ ("sleep" : : : "memory") +#define cpu_relax() barrier() +#define cpu_relax_lowlatency() cpu_relax() + +void default_idle(void); +void stop_this_cpu(void *); + +/* Forward decl */ +struct seq_operations; +struct task_struct; + +extern struct pt_regs fake_swapper_regs; + +extern void cpu_init(void); +extern void cpu_probe(void); + +/* arch/sh/kernel/process.c */ +extern unsigned int xstate_size; +extern void free_thread_xstate(struct task_struct *); +extern struct kmem_cache *task_xstate_cachep; + +/* arch/sh/mm/alignment.c */ +extern int get_unalign_ctl(struct task_struct *, unsigned long addr); +extern int set_unalign_ctl(struct task_struct *, unsigned int val); + +#define GET_UNALIGN_CTL(tsk, addr) get_unalign_ctl((tsk), (addr)) +#define SET_UNALIGN_CTL(tsk, val) set_unalign_ctl((tsk), (val)) + +/* arch/sh/mm/init.c */ +extern unsigned int mem_init_done; + +/* arch/sh/kernel/setup.c */ +const char *get_cpu_subtype(struct sh_cpuinfo *c); +extern const struct seq_operations cpuinfo_op; + +/* thread_struct flags */ +#define SH_THREAD_UAC_NOPRINT (1 << 0) +#define SH_THREAD_UAC_SIGBUS (1 << 1) +#define SH_THREAD_UAC_MASK (SH_THREAD_UAC_NOPRINT | SH_THREAD_UAC_SIGBUS) + +/* processor boot mode configuration */ +#define MODE_PIN0 (1 << 0) +#define MODE_PIN1 (1 << 1) +#define MODE_PIN2 (1 << 2) +#define MODE_PIN3 (1 << 3) +#define MODE_PIN4 (1 << 4) +#define MODE_PIN5 (1 << 5) +#define MODE_PIN6 (1 << 6) +#define MODE_PIN7 (1 << 7) +#define MODE_PIN8 (1 << 8) +#define MODE_PIN9 (1 << 9) +#define MODE_PIN10 (1 << 10) +#define MODE_PIN11 (1 << 11) +#define MODE_PIN12 (1 << 12) +#define MODE_PIN13 (1 << 13) +#define MODE_PIN14 (1 << 14) +#define MODE_PIN15 (1 << 15) + +int generic_mode_pins(void); +int test_mode_pin(int pin); + +#ifdef CONFIG_VSYSCALL +int vsyscall_init(void); +#else +#define vsyscall_init() do { } while (0) +#endif + +/* + * SH-2A has both 16 and 32-bit opcodes, do lame encoding checks. + */ +#ifdef CONFIG_CPU_SH2A +extern unsigned int instruction_size(unsigned int insn); +#elif defined(CONFIG_SUPERH32) +#define instruction_size(insn) (2) +#else +#define instruction_size(insn) (4) +#endif + +#endif /* __ASSEMBLY__ */ + +#ifdef CONFIG_SUPERH32 +# include <asm/processor_32.h> +#else +# include <asm/processor_64.h> +#endif + +#endif /* __ASM_SH_PROCESSOR_H */ diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h new file mode 100644 index 000000000..18e0377f7 --- /dev/null +++ b/arch/sh/include/asm/processor_32.h @@ -0,0 +1,216 @@ +/* + * include/asm-sh/processor.h + * + * Copyright (C) 1999, 2000 Niibe Yutaka + * Copyright (C) 2002, 2003 Paul Mundt + */ + +#ifndef __ASM_SH_PROCESSOR_32_H +#define __ASM_SH_PROCESSOR_32_H +#ifdef __KERNEL__ + +#include <linux/compiler.h> +#include <linux/linkage.h> +#include <asm/page.h> +#include <asm/types.h> +#include <asm/hw_breakpoint.h> + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ void *pc; __asm__("mova 1f, %0\n.align 2\n1:":"=z" (pc)); pc; }) + +/* Core Processor Version Register */ +#define CCN_PVR 0xff000030 +#define CCN_CVR 0xff000040 +#define CCN_PRR 0xff000044 + +/* + * User space process size: 2GB. + * + * Since SH7709 and SH7750 have "area 7", we can't use 0x7c000000--0x7fffffff + */ +#define TASK_SIZE 0x7c000000UL + +#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE / 3) + +/* + * Bit of SR register + * + * FD-bit: + * When it's set, it means the processor doesn't have right to use FPU, + * and it results exception when the floating operation is executed. + * + * IMASK-bit: + * Interrupt level mask + */ +#define SR_DSP 0x00001000 +#define SR_IMASK 0x000000f0 +#define SR_FD 0x00008000 +#define SR_MD 0x40000000 + +/* + * DSP structure and data + */ +struct sh_dsp_struct { + unsigned long dsp_regs[14]; + long status; +}; + +/* + * FPU structure and data + */ + +struct sh_fpu_hard_struct { + unsigned long fp_regs[16]; + unsigned long xfp_regs[16]; + unsigned long fpscr; + unsigned long fpul; + + long status; /* software status information */ +}; + +/* Dummy fpu emulator */ +struct sh_fpu_soft_struct { + unsigned long fp_regs[16]; + unsigned long xfp_regs[16]; + unsigned long fpscr; + unsigned long fpul; + + unsigned char lookahead; + unsigned long entry_pc; +}; + +union thread_xstate { + struct sh_fpu_hard_struct hardfpu; + struct sh_fpu_soft_struct softfpu; +}; + +struct thread_struct { + /* Saved registers when thread is descheduled */ + unsigned long sp; + unsigned long pc; + + /* Various thread flags, see SH_THREAD_xxx */ + unsigned long flags; + + /* 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 + + /* Extended processor state */ + union thread_xstate *xstate; + + /* + * fpu_counter contains the number of consecutive context switches + * that the FPU is used. If this is over a threshold, the lazy fpu + * saving becomes unlazy to save the trap. This is an unsigned char + * so that after 256 times the counter wraps and the behavior turns + * lazy again; this to deal with bursty apps that only use FPU for + * a short time + */ + unsigned char fpu_counter; +}; + +#define INIT_THREAD { \ + .sp = sizeof(init_stack) + (long) &init_stack, \ + .flags = 0, \ +} + +/* Forward declaration, a strange C thing */ +struct task_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 *); + +/* Copy and release all segment info associated with a VM */ +#define copy_segments(p, mm) do { } while(0) +#define release_segments(mm) do { } while(0) + +/* + * FPU lazy state save handling. + */ + +static __inline__ void disable_fpu(void) +{ + unsigned long __dummy; + + /* Set FD flag in SR */ + __asm__ __volatile__("stc sr, %0\n\t" + "or %1, %0\n\t" + "ldc %0, sr" + : "=&r" (__dummy) + : "r" (SR_FD)); +} + +static __inline__ void enable_fpu(void) +{ + unsigned long __dummy; + + /* Clear out FD flag in SR */ + __asm__ __volatile__("stc sr, %0\n\t" + "and %1, %0\n\t" + "ldc %0, sr" + : "=&r" (__dummy) + : "r" (~SR_FD)); +} + +/* Double presision, NANS as NANS, rounding to nearest, no exceptions */ +#define FPSCR_INIT 0x00080000 + +#define FPSCR_CAUSE_MASK 0x0001f000 /* Cause bits */ +#define FPSCR_FLAG_MASK 0x0000007c /* Flag bits */ + +/* + * Return saved PC of a blocked thread. + */ +#define thread_saved_pc(tsk) (tsk->thread.pc) + +void show_trace(struct task_struct *tsk, unsigned long *sp, + struct pt_regs *regs); + +#ifdef CONFIG_DUMP_CODE +void show_code(struct pt_regs *regs); +#else +static inline void show_code(struct pt_regs *regs) +{ +} +#endif + +extern unsigned long get_wchan(struct task_struct *p); + +#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc) +#define KSTK_ESP(tsk) (task_pt_regs(tsk)->regs[15]) + +#if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH4) + +#define PREFETCH_STRIDE L1_CACHE_BYTES +#define ARCH_HAS_PREFETCH +#define ARCH_HAS_PREFETCHW + +static inline void prefetch(const void *x) +{ + __builtin_prefetch(x, 0, 3); +} + +static inline void prefetchw(const void *x) +{ + __builtin_prefetch(x, 1, 3); +} +#endif + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_PROCESSOR_32_H */ diff --git a/arch/sh/include/asm/processor_64.h b/arch/sh/include/asm/processor_64.h new file mode 100644 index 000000000..eedd4f625 --- /dev/null +++ b/arch/sh/include/asm/processor_64.h @@ -0,0 +1,234 @@ +#ifndef __ASM_SH_PROCESSOR_64_H +#define __ASM_SH_PROCESSOR_64_H + +/* + * include/asm-sh/processor_64.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2004 Richard Curnow + * + * 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 __ASSEMBLY__ + +#include <linux/compiler.h> +#include <asm/page.h> +#include <asm/types.h> +#include <cpu/registers.h> + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ \ +void *pc; \ +unsigned long long __dummy = 0; \ +__asm__("gettr tr0, %1\n\t" \ + "pta 4, tr0\n\t" \ + "gettr tr0, %0\n\t" \ + "ptabs %1, tr0\n\t" \ + :"=r" (pc), "=r" (__dummy) \ + : "1" (__dummy)); \ +pc; }) + +#endif + +/* + * User space process size: 2GB - 4k. + */ +#define TASK_SIZE 0x7ffff000UL + +#define STACK_TOP TASK_SIZE +#define STACK_TOP_MAX STACK_TOP + +/* This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE / 3) + +/* + * Bit of SR register + * + * FD-bit: + * When it's set, it means the processor doesn't have right to use FPU, + * and it results exception when the floating operation is executed. + * + * IMASK-bit: + * Interrupt level mask + * + * STEP-bit: + * Single step bit + * + */ +#if defined(CONFIG_SH64_SR_WATCH) +#define SR_MMU 0x84000000 +#else +#define SR_MMU 0x80000000 +#endif + +#define SR_IMASK 0x000000f0 +#define SR_FD 0x00008000 +#define SR_SSTEP 0x08000000 + +#ifndef __ASSEMBLY__ + +/* + * FPU structure and data : require 8-byte alignment as we need to access it + with fld.p, fst.p + */ + +struct sh_fpu_hard_struct { + unsigned long fp_regs[64]; + unsigned int fpscr; + /* long status; * software status information */ +}; + +/* Dummy fpu emulator */ +struct sh_fpu_soft_struct { + unsigned long fp_regs[64]; + unsigned int fpscr; + unsigned char lookahead; + unsigned long entry_pc; +}; + +union thread_xstate { + struct sh_fpu_hard_struct hardfpu; + struct sh_fpu_soft_struct softfpu; + /* + * The structure definitions only produce 32 bit alignment, yet we need + * to access them using 64 bit load/store as well. + */ + unsigned long long alignment_dummy; +}; + +struct thread_struct { + unsigned long sp; + unsigned long pc; + + /* Various thread flags, see SH_THREAD_xxx */ + unsigned long flags; + + /* This stores the address of the pt_regs built during a context + switch, or of the register save area built for a kernel mode + exception. It is used for backtracing the stack of a sleeping task + or one that traps in kernel mode. */ + struct pt_regs *kregs; + /* This stores the address of the pt_regs constructed on entry from + user mode. It is a fixed value over the lifetime of a process, or + NULL for a kernel thread. */ + struct pt_regs *uregs; + + unsigned long address; + /* Hardware debugging registers may come here */ + + /* floating point info */ + union thread_xstate *xstate; + + /* + * fpu_counter contains the number of consecutive context switches + * that the FPU is used. If this is over a threshold, the lazy fpu + * saving becomes unlazy to save the trap. This is an unsigned char + * so that after 256 times the counter wraps and the behavior turns + * lazy again; this to deal with bursty apps that only use FPU for + * a short time + */ + unsigned char fpu_counter; +}; + +#define INIT_MMAP \ +{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL } + +#define INIT_THREAD { \ + .sp = sizeof(init_stack) + \ + (long) &init_stack, \ + .pc = 0, \ + .kregs = &fake_swapper_regs, \ + .uregs = NULL, \ + .address = 0, \ + .flags = 0, \ +} + +/* + * Do necessary setup to start up a newly executed thread. + */ +#define SR_USER (SR_MMU | SR_FD) + +#define start_thread(_regs, new_pc, new_sp) \ + _regs->sr = SR_USER; /* User mode. */ \ + _regs->pc = new_pc - 4; /* Compensate syscall exit */ \ + _regs->pc |= 1; /* Set SHmedia ! */ \ + _regs->regs[18] = 0; \ + _regs->regs[15] = new_sp + +/* Forward declaration, a strange C thing */ +struct task_struct; +struct mm_struct; + +/* Free all resources held by a thread. */ +extern void release_thread(struct task_struct *); + +/* Copy and release all segment info associated with a VM */ +#define copy_segments(p, mm) do { } while (0) +#define release_segments(mm) do { } while (0) +#define forget_segments() do { } while (0) +/* + * FPU lazy state save handling. + */ + +static inline void disable_fpu(void) +{ + unsigned long long __dummy; + + /* Set FD flag in SR */ + __asm__ __volatile__("getcon " __SR ", %0\n\t" + "or %0, %1, %0\n\t" + "putcon %0, " __SR "\n\t" + : "=&r" (__dummy) + : "r" (SR_FD)); +} + +static inline void enable_fpu(void) +{ + unsigned long long __dummy; + + /* Clear out FD flag in SR */ + __asm__ __volatile__("getcon " __SR ", %0\n\t" + "and %0, %1, %0\n\t" + "putcon %0, " __SR "\n\t" + : "=&r" (__dummy) + : "r" (~SR_FD)); +} + +/* Round to nearest, no exceptions on inexact, overflow, underflow, + zero-divide, invalid. Configure option for whether to flush denorms to + zero, or except if a denorm is encountered. */ +#if defined(CONFIG_SH64_FPU_DENORM_FLUSH) +#define FPSCR_INIT 0x00040000 +#else +#define FPSCR_INIT 0x00000000 +#endif + +#ifdef CONFIG_SH_FPU +/* Initialise the FP state of a task */ +void fpinit(struct sh_fpu_hard_struct *fpregs); +#else +#define fpinit(fpregs) do { } while (0) +#endif + +extern struct task_struct *last_task_used_math; + +/* + * Return saved PC of a blocked thread. + */ +#define thread_saved_pc(tsk) (tsk->thread.pc) + +extern unsigned long get_wchan(struct task_struct *p); + +#define KSTK_EIP(tsk) ((tsk)->thread.pc) +#define KSTK_ESP(tsk) ((tsk)->thread.sp) + +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_SH_PROCESSOR_64_H */ diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h new file mode 100644 index 000000000..2506c7db7 --- /dev/null +++ b/arch/sh/include/asm/ptrace.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 1999, 2000 Niibe Yutaka + */ +#ifndef __ASM_SH_PTRACE_H +#define __ASM_SH_PTRACE_H + + +#include <linux/stringify.h> +#include <linux/stddef.h> +#include <linux/thread_info.h> +#include <asm/addrspace.h> +#include <asm/page.h> +#include <uapi/asm/ptrace.h> + +#define user_mode(regs) (((regs)->sr & 0x40000000)==0) +#define kernel_stack_pointer(_regs) ((unsigned long)(_regs)->regs[15]) + +#define GET_FP(regs) ((regs)->regs[14]) +#define GET_USP(regs) ((regs)->regs[15]) + +#define arch_has_single_step() (1) + +/* + * kprobe-based event tracer support + */ +struct pt_regs_offset { + const char *name; + int offset; +}; + +#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)} +#define REGS_OFFSET_NAME(num) \ + {.name = __stringify(r##num), .offset = offsetof(struct pt_regs, regs[num])} +#define TREGS_OFFSET_NAME(num) \ + {.name = __stringify(tr##num), .offset = offsetof(struct pt_regs, tregs[num])} +#define REG_OFFSET_END {.name = NULL, .offset = 0} + +/* Query offset/name of register from its name/offset */ +extern int regs_query_register_offset(const char *name); +extern const char *regs_query_register_name(unsigned int offset); + +extern const struct pt_regs_offset regoffset_table[]; + +/** + * regs_get_register() - get register value from its offset + * @regs: pt_regs from which register value is gotten. + * @offset: offset number of the register. + * + * regs_get_register returns the value of a register. The @offset is the + * offset of the register in struct pt_regs address which specified by @regs. + * If @offset is bigger than MAX_REG_OFFSET, this returns 0. + */ +static inline unsigned long regs_get_register(struct pt_regs *regs, + unsigned int offset) +{ + if (unlikely(offset > MAX_REG_OFFSET)) + return 0; + return *(unsigned long *)((unsigned long)regs + offset); +} + +/** + * regs_within_kernel_stack() - check the address in the stack + * @regs: pt_regs which contains kernel stack pointer. + * @addr: address which is checked. + * + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). + * If @addr is within the kernel stack, it returns true. If not, returns false. + */ +static inline int regs_within_kernel_stack(struct pt_regs *regs, + unsigned long addr) +{ + return ((addr & ~(THREAD_SIZE - 1)) == + (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); +} + +/** + * regs_get_kernel_stack_nth() - get Nth entry of the stack + * @regs: pt_regs which contains kernel stack pointer. + * @n: stack entry number. + * + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which + * is specified by @regs. If the @n th entry is NOT in the kernel stack, + * this returns 0. + */ +static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, + unsigned int n) +{ + unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); + addr += n; + if (regs_within_kernel_stack(regs, (unsigned long)addr)) + return *addr; + else + return 0; +} + +struct perf_event; +struct perf_sample_data; + +extern void ptrace_triggered(struct perf_event *bp, + struct perf_sample_data *data, struct pt_regs *regs); + +#define task_pt_regs(task) \ + ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE) - 1) + +static inline unsigned long profile_pc(struct pt_regs *regs) +{ + unsigned long pc = regs->pc; + + if (virt_addr_uncached(pc)) + return CAC_ADDR(pc); + + return pc; +} +#define profile_pc profile_pc + +#include <asm-generic/ptrace.h> +#endif /* __ASM_SH_PTRACE_H */ diff --git a/arch/sh/include/asm/ptrace_32.h b/arch/sh/include/asm/ptrace_32.h new file mode 100644 index 000000000..1dd4480c5 --- /dev/null +++ b/arch/sh/include/asm/ptrace_32.h @@ -0,0 +1,13 @@ +#ifndef __ASM_SH_PTRACE_32_H +#define __ASM_SH_PTRACE_32_H + +#include <uapi/asm/ptrace_32.h> + + +#define MAX_REG_OFFSET offsetof(struct pt_regs, tra) +static inline long regs_return_value(struct pt_regs *regs) +{ + return regs->regs[0]; +} + +#endif /* __ASM_SH_PTRACE_32_H */ diff --git a/arch/sh/include/asm/ptrace_64.h b/arch/sh/include/asm/ptrace_64.h new file mode 100644 index 000000000..97f4b5660 --- /dev/null +++ b/arch/sh/include/asm/ptrace_64.h @@ -0,0 +1,13 @@ +#ifndef __ASM_SH_PTRACE_64_H +#define __ASM_SH_PTRACE_64_H + +#include <uapi/asm/ptrace_64.h> + + +#define MAX_REG_OFFSET offsetof(struct pt_regs, tregs[7]) +static inline long regs_return_value(struct pt_regs *regs) +{ + return regs->regs[3]; +} + +#endif /* __ASM_SH_PTRACE_64_H */ diff --git a/arch/sh/include/asm/push-switch.h b/arch/sh/include/asm/push-switch.h new file mode 100644 index 000000000..4903f9e52 --- /dev/null +++ b/arch/sh/include/asm/push-switch.h @@ -0,0 +1,31 @@ +#ifndef __ASM_SH_PUSH_SWITCH_H +#define __ASM_SH_PUSH_SWITCH_H + +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> + +struct push_switch { + /* switch state */ + unsigned int state:1; + /* debounce timer */ + struct timer_list debounce; + /* workqueue */ + struct work_struct work; + /* platform device, for workqueue handler */ + struct platform_device *pdev; +}; + +struct push_switch_platform_info { + /* IRQ handler */ + irqreturn_t (*irq_handler)(int irq, void *data); + /* Special IRQ flags */ + unsigned int irq_flags; + /* Bit location of switch */ + unsigned int bit; + /* Symbolic switch name */ + const char *name; +}; + +#endif /* __ASM_SH_PUSH_SWITCH_H */ diff --git a/arch/sh/include/asm/reboot.h b/arch/sh/include/asm/reboot.h new file mode 100644 index 000000000..b3da0c63f --- /dev/null +++ b/arch/sh/include/asm/reboot.h @@ -0,0 +1,21 @@ +#ifndef __ASM_SH_REBOOT_H +#define __ASM_SH_REBOOT_H + +#include <linux/kdebug.h> + +struct pt_regs; + +struct machine_ops { + void (*restart)(char *cmd); + void (*halt)(void); + void (*power_off)(void); + void (*shutdown)(void); + void (*crash_shutdown)(struct pt_regs *); +}; + +extern struct machine_ops machine_ops; + +/* arch/sh/kernel/machine_kexec.c */ +void native_machine_crash_shutdown(struct pt_regs *regs); + +#endif /* __ASM_SH_REBOOT_H */ diff --git a/arch/sh/include/asm/romimage-macros.h b/arch/sh/include/asm/romimage-macros.h new file mode 100644 index 000000000..ae17a150b --- /dev/null +++ b/arch/sh/include/asm/romimage-macros.h @@ -0,0 +1,73 @@ +#ifndef __ROMIMAGE_MACRO_H +#define __ROMIMAGE_MACRO_H + +/* The LIST command is used to include comments in the script */ +.macro LIST comment +.endm + +/* The ED command is used to write a 32-bit word */ +.macro ED, addr, data + mov.l 1f, r1 + mov.l 2f, r0 + mov.l r0, @r1 + bra 3f + nop + .align 2 +1 : .long \addr +2 : .long \data +3 : +.endm + +/* The EW command is used to write a 16-bit word */ +.macro EW, addr, data + mov.l 1f, r1 + mov.l 2f, r0 + mov.w r0, @r1 + bra 3f + nop + .align 2 +1 : .long \addr +2 : .long \data +3 : +.endm + +/* The EB command is used to write an 8-bit word */ +.macro EB, addr, data + mov.l 1f, r1 + mov.l 2f, r0 + mov.b r0, @r1 + bra 3f + nop + .align 2 +1 : .long \addr +2 : .long \data +3 : +.endm + +/* The WAIT command is used to delay the execution */ +.macro WAIT, time + mov.l 2f, r3 +1 : + nop + tst r3, r3 + bf/s 1b + dt r3 + bra 3f + nop + .align 2 +2 : .long \time * 100 +3 : +.endm + +/* The DD command is used to read a 32-bit word */ +.macro DD, addr, addr2, nr + mov.l 1f, r1 + mov.l @r1, r0 + bra 2f + nop + .align 2 +1 : .long \addr +2 : +.endm + +#endif /* __ROMIMAGE_MACRO_H */ diff --git a/arch/sh/include/asm/rtc.h b/arch/sh/include/asm/rtc.h new file mode 100644 index 000000000..52b0c2dba --- /dev/null +++ b/arch/sh/include/asm/rtc.h @@ -0,0 +1,28 @@ +#ifndef _ASM_RTC_H +#define _ASM_RTC_H + +void time_init(void); +extern void (*board_time_init)(void); +extern void (*rtc_sh_get_time)(struct timespec *); +extern int (*rtc_sh_set_time)(const time_t); + +/* some dummy definitions */ +#define RTC_BATT_BAD 0x100 /* battery bad */ +#define RTC_SQWE 0x08 /* enable square-wave output */ +#define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */ +#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */ +#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */ + +struct rtc_time; +unsigned int get_rtc_time(struct rtc_time *); +int set_rtc_time(struct rtc_time *); + +#define RTC_CAP_4_DIGIT_YEAR (1 << 0) + +struct sh_rtc_platform_info { + unsigned long capabilities; +}; + +#include <cpu/rtc.h> + +#endif /* _ASM_RTC_H */ diff --git a/arch/sh/include/asm/rwsem.h b/arch/sh/include/asm/rwsem.h new file mode 100644 index 000000000..edab57265 --- /dev/null +++ b/arch/sh/include/asm/rwsem.h @@ -0,0 +1,132 @@ +/* + * include/asm-sh/rwsem.h: R/W semaphores for SH using the stuff + * in lib/rwsem.c. + */ + +#ifndef _ASM_SH_RWSEM_H +#define _ASM_SH_RWSEM_H + +#ifndef _LINUX_RWSEM_H +#error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead" +#endif + +#ifdef __KERNEL__ + +#define RWSEM_UNLOCKED_VALUE 0x00000000 +#define RWSEM_ACTIVE_BIAS 0x00000001 +#define RWSEM_ACTIVE_MASK 0x0000ffff +#define RWSEM_WAITING_BIAS (-0x00010000) +#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS +#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS) + +/* + * lock for reading + */ +static inline void __down_read(struct rw_semaphore *sem) +{ + if (atomic_inc_return((atomic_t *)(&sem->count)) > 0) + smp_wmb(); + else + rwsem_down_read_failed(sem); +} + +static inline int __down_read_trylock(struct rw_semaphore *sem) +{ + int tmp; + + while ((tmp = sem->count) >= 0) { + if (tmp == cmpxchg(&sem->count, tmp, + tmp + RWSEM_ACTIVE_READ_BIAS)) { + smp_wmb(); + return 1; + } + } + return 0; +} + +/* + * lock for writing + */ +static inline void __down_write(struct rw_semaphore *sem) +{ + int tmp; + + tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic_t *)(&sem->count)); + if (tmp == RWSEM_ACTIVE_WRITE_BIAS) + smp_wmb(); + else + rwsem_down_write_failed(sem); +} + +static inline int __down_write_trylock(struct rw_semaphore *sem) +{ + int tmp; + + tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE, + RWSEM_ACTIVE_WRITE_BIAS); + smp_wmb(); + return tmp == RWSEM_UNLOCKED_VALUE; +} + +/* + * unlock after reading + */ +static inline void __up_read(struct rw_semaphore *sem) +{ + int tmp; + + smp_wmb(); + tmp = atomic_dec_return((atomic_t *)(&sem->count)); + if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0) + rwsem_wake(sem); +} + +/* + * unlock after writing + */ +static inline void __up_write(struct rw_semaphore *sem) +{ + smp_wmb(); + if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS, + (atomic_t *)(&sem->count)) < 0) + rwsem_wake(sem); +} + +/* + * implement atomic add functionality + */ +static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) +{ + atomic_add(delta, (atomic_t *)(&sem->count)); +} + +/* + * downgrade write lock to read lock + */ +static inline void __downgrade_write(struct rw_semaphore *sem) +{ + int tmp; + + smp_wmb(); + tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count)); + if (tmp < 0) + rwsem_downgrade_wake(sem); +} + +static inline void __down_write_nested(struct rw_semaphore *sem, int subclass) +{ + __down_write(sem); +} + +/* + * implement exchange and add functionality + */ +static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem) +{ + smp_mb(); + return atomic_add_return(delta, (atomic_t *)(&sem->count)); +} + +#endif /* __KERNEL__ */ +#endif /* _ASM_SH_RWSEM_H */ diff --git a/arch/sh/include/asm/seccomp.h b/arch/sh/include/asm/seccomp.h new file mode 100644 index 000000000..3280ed380 --- /dev/null +++ b/arch/sh/include/asm/seccomp.h @@ -0,0 +1,10 @@ +#ifndef __ASM_SECCOMP_H + +#include <linux/unistd.h> + +#define __NR_seccomp_read __NR_read +#define __NR_seccomp_write __NR_write +#define __NR_seccomp_exit __NR_exit +#define __NR_seccomp_sigreturn __NR_rt_sigreturn + +#endif /* __ASM_SECCOMP_H */ diff --git a/arch/sh/include/asm/sections.h b/arch/sh/include/asm/sections.h new file mode 100644 index 000000000..7a99e6af6 --- /dev/null +++ b/arch/sh/include/asm/sections.h @@ -0,0 +1,11 @@ +#ifndef __ASM_SH_SECTIONS_H +#define __ASM_SH_SECTIONS_H + +#include <asm-generic/sections.h> + +extern long __machvec_start, __machvec_end; +extern char __uncached_start, __uncached_end; +extern char __start_eh_frame[], __stop_eh_frame[]; + +#endif /* __ASM_SH_SECTIONS_H */ + diff --git a/arch/sh/include/asm/segment.h b/arch/sh/include/asm/segment.h new file mode 100644 index 000000000..ff795d3a6 --- /dev/null +++ b/arch/sh/include/asm/segment.h @@ -0,0 +1,34 @@ +#ifndef __ASM_SH_SEGMENT_H +#define __ASM_SH_SEGMENT_H + +#ifndef __ASSEMBLY__ + +typedef struct { + unsigned long seg; +} mm_segment_t; + +#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) + +/* + * The fs value determines whether argument validity checking should be + * performed or not. If get_fs() == USER_DS, checking is performed, with + * get_fs() == KERNEL_DS, checking is bypassed. + * + * For historical reasons, these macros are grossly misnamed. + */ +#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFUL) +#ifdef CONFIG_MMU +#define USER_DS MAKE_MM_SEG(PAGE_OFFSET) +#else +#define USER_DS KERNEL_DS +#endif + +#define segment_eq(a, b) ((a).seg == (b).seg) + +#define get_ds() (KERNEL_DS) + +#define get_fs() (current_thread_info()->addr_limit) +#define set_fs(x) (current_thread_info()->addr_limit = (x)) + +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_SH_SEGMENT_H */ diff --git a/arch/sh/include/asm/setup.h b/arch/sh/include/asm/setup.h new file mode 100644 index 000000000..99238108e --- /dev/null +++ b/arch/sh/include/asm/setup.h @@ -0,0 +1,24 @@ +#ifndef _SH_SETUP_H +#define _SH_SETUP_H + +#include <uapi/asm/setup.h> + +/* + * This is set up by the setup-routine at boot-time + */ +#define PARAM ((unsigned char *)empty_zero_page) + +#define MOUNT_ROOT_RDONLY (*(unsigned long *) (PARAM+0x000)) +#define RAMDISK_FLAGS (*(unsigned long *) (PARAM+0x004)) +#define ORIG_ROOT_DEV (*(unsigned long *) (PARAM+0x008)) +#define LOADER_TYPE (*(unsigned long *) (PARAM+0x00c)) +#define INITRD_START (*(unsigned long *) (PARAM+0x010)) +#define INITRD_SIZE (*(unsigned long *) (PARAM+0x014)) +/* ... */ +#define COMMAND_LINE ((char *) (PARAM+0x100)) + +void sh_mv_setup(void); +void check_for_initrd(void); +void per_cpu_trap_init(void); + +#endif /* _SH_SETUP_H */ diff --git a/arch/sh/include/asm/sfp-machine.h b/arch/sh/include/asm/sfp-machine.h new file mode 100644 index 000000000..d3c548443 --- /dev/null +++ b/arch/sh/include/asm/sfp-machine.h @@ -0,0 +1,84 @@ +/* Machine-dependent software floating-point definitions. + SuperH kernel version. + Copyright (C) 1997,1998,1999 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Richard Henderson (rth@cygnus.com), + Jakub Jelinek (jj@ultra.linux.cz), + David S. Miller (davem@redhat.com) and + Peter Maydell (pmaydell@chiark.greenend.org.uk). + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If + not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _SFP_MACHINE_H +#define _SFP_MACHINE_H + +#define _FP_W_TYPE_SIZE 32 +#define _FP_W_TYPE unsigned long +#define _FP_WS_TYPE signed long +#define _FP_I_TYPE long + +#define _FP_MUL_MEAT_S(R,X,Y) \ + _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm) +#define _FP_MUL_MEAT_D(R,X,Y) \ + _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm) +#define _FP_MUL_MEAT_Q(R,X,Y) \ + _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm) + +#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y) +#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y) +#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y) + +#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1) +#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1 +#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1 +#define _FP_NANSIGN_S 0 +#define _FP_NANSIGN_D 0 +#define _FP_NANSIGN_Q 0 + +#define _FP_KEEPNANFRACP 1 + +/* + * If one NaN is signaling and the other is not, + * we choose that one, otherwise we choose X. + */ +#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \ + do { \ + if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs) \ + && !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)) \ + { \ + R##_s = Y##_s; \ + _FP_FRAC_COPY_##wc(R,Y); \ + } \ + else \ + { \ + R##_s = X##_s; \ + _FP_FRAC_COPY_##wc(R,X); \ + } \ + R##_c = FP_CLS_NAN; \ + } while (0) + +//#define FP_ROUNDMODE FPSCR_RM +#define FP_DENORM_ZERO 1/*FPSCR_DN*/ + +/* Exception flags. */ +#define FP_EX_INVALID (1<<4) +#define FP_EX_DIVZERO (1<<3) +#define FP_EX_OVERFLOW (1<<2) +#define FP_EX_UNDERFLOW (1<<1) +#define FP_EX_INEXACT (1<<0) + +#endif + diff --git a/arch/sh/include/asm/sh7760fb.h b/arch/sh/include/asm/sh7760fb.h new file mode 100644 index 000000000..8767f61ac --- /dev/null +++ b/arch/sh/include/asm/sh7760fb.h @@ -0,0 +1,197 @@ +/* + * sh7760fb.h -- platform data for SH7760/SH7763 LCDC framebuffer driver. + * + * (c) 2006-2008 MSC Vertriebsges.m.b.H., + * Manuel Lauss <mano@roarinelk.homelinux.net> + * (c) 2008 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com> + */ + +#ifndef _ASM_SH_SH7760FB_H +#define _ASM_SH_SH7760FB_H + +/* + * some bits of the colormap registers should be written as zero. + * create a mask for that. + */ +#define SH7760FB_PALETTE_MASK 0x00f8fcf8 + +/* The LCDC dma engine always sets bits 27-26 to 1: this is Area3 */ +#define SH7760FB_DMA_MASK 0x0C000000 + +/* palette */ +#define LDPR(x) (((x) << 2)) + +/* framebuffer registers and bits */ +#define LDICKR 0x400 +#define LDMTR 0x402 +/* see sh7760fb.h for LDMTR bits */ +#define LDDFR 0x404 +#define LDDFR_PABD (1 << 8) +#define LDDFR_COLOR_MASK 0x7F +#define LDSMR 0x406 +#define LDSMR_ROT (1 << 13) +#define LDSARU 0x408 +#define LDSARL 0x40c +#define LDLAOR 0x410 +#define LDPALCR 0x412 +#define LDPALCR_PALS (1 << 4) +#define LDPALCR_PALEN (1 << 0) +#define LDHCNR 0x414 +#define LDHSYNR 0x416 +#define LDVDLNR 0x418 +#define LDVTLNR 0x41a +#define LDVSYNR 0x41c +#define LDACLNR 0x41e +#define LDINTR 0x420 +#define LDPMMR 0x424 +#define LDPSPR 0x426 +#define LDCNTR 0x428 +#define LDCNTR_DON (1 << 0) +#define LDCNTR_DON2 (1 << 4) + +#ifdef CONFIG_CPU_SUBTYPE_SH7763 +# define LDLIRNR 0x440 +/* LDINTR bit */ +# define LDINTR_MINTEN (1 << 15) +# define LDINTR_FINTEN (1 << 14) +# define LDINTR_VSINTEN (1 << 13) +# define LDINTR_VEINTEN (1 << 12) +# define LDINTR_MINTS (1 << 11) +# define LDINTR_FINTS (1 << 10) +# define LDINTR_VSINTS (1 << 9) +# define LDINTR_VEINTS (1 << 8) +# define VINT_START (LDINTR_VSINTEN) +# define VINT_CHECK (LDINTR_VSINTS) +#else +/* LDINTR bit */ +# define LDINTR_VINTSEL (1 << 12) +# define LDINTR_VINTE (1 << 8) +# define LDINTR_VINTS (1 << 0) +# define VINT_START (LDINTR_VINTSEL) +# define VINT_CHECK (LDINTR_VINTS) +#endif + +/* HSYNC polarity inversion */ +#define LDMTR_FLMPOL (1 << 15) + +/* VSYNC polarity inversion */ +#define LDMTR_CL1POL (1 << 14) + +/* DISPLAY-ENABLE polarity inversion */ +#define LDMTR_DISPEN_LOWACT (1 << 13) + +/* DISPLAY DATA BUS polarity inversion */ +#define LDMTR_DPOL_LOWACT (1 << 12) + +/* AC modulation signal enable */ +#define LDMTR_MCNT (1 << 10) + +/* Disable output of HSYNC during VSYNC period */ +#define LDMTR_CL1CNT (1 << 9) + +/* Disable output of VSYNC during VSYNC period */ +#define LDMTR_CL2CNT (1 << 8) + +/* Display types supported by the LCDC */ +#define LDMTR_STN_MONO_4 0x00 +#define LDMTR_STN_MONO_8 0x01 +#define LDMTR_STN_COLOR_4 0x08 +#define LDMTR_STN_COLOR_8 0x09 +#define LDMTR_STN_COLOR_12 0x0A +#define LDMTR_STN_COLOR_16 0x0B +#define LDMTR_DSTN_MONO_8 0x11 +#define LDMTR_DSTN_MONO_16 0x13 +#define LDMTR_DSTN_COLOR_8 0x19 +#define LDMTR_DSTN_COLOR_12 0x1A +#define LDMTR_DSTN_COLOR_16 0x1B +#define LDMTR_TFT_COLOR_16 0x2B + +/* framebuffer color layout */ +#define LDDFR_1BPP_MONO 0x00 +#define LDDFR_2BPP_MONO 0x01 +#define LDDFR_4BPP_MONO 0x02 +#define LDDFR_6BPP_MONO 0x04 +#define LDDFR_4BPP 0x0A +#define LDDFR_8BPP 0x0C +#define LDDFR_16BPP_RGB555 0x1D +#define LDDFR_16BPP_RGB565 0x2D + +/* LCDC Pixclock sources */ +#define LCDC_CLKSRC_BUSCLOCK 0 +#define LCDC_CLKSRC_PERIPHERAL 1 +#define LCDC_CLKSRC_EXTERNAL 2 + +#define LDICKR_CLKSRC(x) \ + (((x) & 3) << 12) + +/* LCDC pixclock input divider. Set to 1 at a minimum! */ +#define LDICKR_CLKDIV(x) \ + ((x) & 0x1f) + +struct sh7760fb_platdata { + + /* Set this member to a valid fb_videmode for the display you + * wish to use. The following members must be initialized: + * xres, yres, hsync_len, vsync_len, sync, + * {left,right,upper,lower}_margin. + * The driver uses the above members to calculate register values + * and memory requirements. Other members are ignored but may + * be used by other framebuffer layer components. + */ + struct fb_videomode *def_mode; + + /* LDMTR includes display type and signal polarity. The + * HSYNC/VSYNC polarities are derived from the fb_var_screeninfo + * data above; however the polarities of the following signals + * must be encoded in the ldmtr member: + * Display Enable signal (default high-active) DISPEN_LOWACT + * Display Data signals (default high-active) DPOL_LOWACT + * AC Modulation signal (default off) MCNT + * Hsync-During-Vsync suppression (default off) CL1CNT + * Vsync-during-vsync suppression (default off) CL2CNT + * NOTE: also set a display type! + * (one of LDMTR_{STN,DSTN,TFT}_{MONO,COLOR}_{4,8,12,16}) + */ + u16 ldmtr; + + /* LDDFR controls framebuffer image format (depth, organization) + * Use ONE of the LDDFR_?BPP_* macros! + */ + u16 lddfr; + + /* LDPMMR and LDPSPR control the timing of the power signals + * for the display. Please read the SH7760 Hardware Manual, + * Chapters 30.3.17, 30.3.18 and 30.4.6! + */ + u16 ldpmmr; + u16 ldpspr; + + /* LDACLNR contains the line numbers after which the AC modulation + * signal is to toggle. Set to ZERO for TFTs or displays which + * do not need it. (Chapter 30.3.15 in SH7760 Hardware Manual). + */ + u16 ldaclnr; + + /* LDICKR contains information on pixelclock source and config. + * Please use the LDICKR_CLKSRC() and LDICKR_CLKDIV() macros. + * minimal value for CLKDIV() must be 1!. + */ + u16 ldickr; + + /* set this member to 1 if you wish to use the LCDC's hardware + * rotation function. This is limited to displays <= 320x200 + * pixels resolution! + */ + int rotate; /* set to 1 to rotate 90 CCW */ + + /* set this to 1 to suppress vsync irq use. */ + int novsync; + + /* blanking hook for platform. Set this if your platform can do + * more than the LCDC in terms of blanking (e.g. disable clock + * generator / backlight power supply / etc. + */ + void (*blank) (int); +}; + +#endif /* _ASM_SH_SH7760FB_H */ diff --git a/arch/sh/include/asm/sh_bios.h b/arch/sh/include/asm/sh_bios.h new file mode 100644 index 000000000..95714c284 --- /dev/null +++ b/arch/sh/include/asm/sh_bios.h @@ -0,0 +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_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 */ diff --git a/arch/sh/include/asm/shmparam.h b/arch/sh/include/asm/shmparam.h new file mode 100644 index 000000000..ba1758d90 --- /dev/null +++ b/arch/sh/include/asm/shmparam.h @@ -0,0 +1,22 @@ +/* + * include/asm-sh/shmparam.h + * + * Copyright (C) 1999 Niibe Yutaka + * Copyright (C) 2006 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_SHMPARAM_H +#define __ASM_SH_SHMPARAM_H + +/* + * SH-4 and SH-3 7705 have an aliasing dcache. Bump this up to a sensible value + * for everyone, and work out the specifics from the probed cache descriptor. + */ +#define SHMLBA 0x4000 /* attach addr a multiple of this */ + +#define __ARCH_FORCE_SHMLBA + +#endif /* __ASM_SH_SHMPARAM_H */ diff --git a/arch/sh/include/asm/siu.h b/arch/sh/include/asm/siu.h new file mode 100644 index 000000000..580b7ac22 --- /dev/null +++ b/arch/sh/include/asm/siu.h @@ -0,0 +1,23 @@ +/* + * platform header for the SIU ASoC driver + * + * Copyright (C) 2009-2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef ASM_SIU_H +#define ASM_SIU_H + +struct device; + +struct siu_platform { + unsigned int dma_slave_tx_a; + unsigned int dma_slave_rx_a; + unsigned int dma_slave_tx_b; + unsigned int dma_slave_rx_b; +}; + +#endif /* ASM_SIU_H */ diff --git a/arch/sh/include/asm/smc37c93x.h b/arch/sh/include/asm/smc37c93x.h new file mode 100644 index 000000000..585da2a8f --- /dev/null +++ b/arch/sh/include/asm/smc37c93x.h @@ -0,0 +1,190 @@ +#ifndef __ASM_SH_SMC37C93X_H +#define __ASM_SH_SMC37C93X_H + +/* + * linux/include/asm-sh/smc37c93x.h + * + * Copyright (C) 2000 Kazumoto Kojima + * + * SMSC 37C93x Super IO Chip support + */ + +/* Default base I/O address */ +#define FDC_PRIMARY_BASE 0x3f0 +#define IDE1_PRIMARY_BASE 0x1f0 +#define IDE1_SECONDARY_BASE 0x170 +#define PARPORT_PRIMARY_BASE 0x378 +#define COM1_PRIMARY_BASE 0x2f8 +#define COM2_PRIMARY_BASE 0x3f8 +#define RTC_PRIMARY_BASE 0x070 +#define KBC_PRIMARY_BASE 0x060 +#define AUXIO_PRIMARY_BASE 0x000 /* XXX */ + +/* Logical device number */ +#define LDN_FDC 0 +#define LDN_IDE1 1 +#define LDN_IDE2 2 +#define LDN_PARPORT 3 +#define LDN_COM1 4 +#define LDN_COM2 5 +#define LDN_RTC 6 +#define LDN_KBC 7 +#define LDN_AUXIO 8 + +/* Configuration port and key */ +#define CONFIG_PORT 0x3f0 +#define INDEX_PORT CONFIG_PORT +#define DATA_PORT 0x3f1 +#define CONFIG_ENTER 0x55 +#define CONFIG_EXIT 0xaa + +/* Configuration index */ +#define CURRENT_LDN_INDEX 0x07 +#define POWER_CONTROL_INDEX 0x22 +#define ACTIVATE_INDEX 0x30 +#define IO_BASE_HI_INDEX 0x60 +#define IO_BASE_LO_INDEX 0x61 +#define IRQ_SELECT_INDEX 0x70 +#define DMA_SELECT_INDEX 0x74 + +#define GPIO46_INDEX 0xc6 +#define GPIO47_INDEX 0xc7 + +/* UART stuff. Only for debugging. */ +/* UART Register */ + +#define UART_RBR 0x0 /* Receiver Buffer Register (Read Only) */ +#define UART_THR 0x0 /* Transmitter Holding Register (Write Only) */ +#define UART_IER 0x2 /* Interrupt Enable Register */ +#define UART_IIR 0x4 /* Interrupt Ident Register (Read Only) */ +#define UART_FCR 0x4 /* FIFO Control Register (Write Only) */ +#define UART_LCR 0x6 /* Line Control Register */ +#define UART_MCR 0x8 /* MODEM Control Register */ +#define UART_LSR 0xa /* Line Status Register */ +#define UART_MSR 0xc /* MODEM Status Register */ +#define UART_SCR 0xe /* Scratch Register */ +#define UART_DLL 0x0 /* Divisor Latch (LS) */ +#define UART_DLM 0x2 /* Divisor Latch (MS) */ + +#ifndef __ASSEMBLY__ +typedef struct uart_reg { + volatile __u16 rbr; + volatile __u16 ier; + volatile __u16 iir; + volatile __u16 lcr; + volatile __u16 mcr; + volatile __u16 lsr; + volatile __u16 msr; + volatile __u16 scr; +} uart_reg; +#endif /* ! __ASSEMBLY__ */ + +/* Alias for Write Only Register */ + +#define thr rbr +#define tcr iir + +/* Alias for Divisor Latch Register */ + +#define dll rbr +#define dlm ier +#define fcr iir + +/* Interrupt Enable Register */ + +#define IER_ERDAI 0x0100 /* Enable Received Data Available Interrupt */ +#define IER_ETHREI 0x0200 /* Enable Transmitter Holding Register Empty Interrupt */ +#define IER_ELSI 0x0400 /* Enable Receiver Line Status Interrupt */ +#define IER_EMSI 0x0800 /* Enable MODEM Status Interrupt */ + +/* Interrupt Ident Register */ + +#define IIR_IP 0x0100 /* "0" if Interrupt Pending */ +#define IIR_IIB0 0x0200 /* Interrupt ID Bit 0 */ +#define IIR_IIB1 0x0400 /* Interrupt ID Bit 1 */ +#define IIR_IIB2 0x0800 /* Interrupt ID Bit 2 */ +#define IIR_FIFO 0xc000 /* FIFOs enabled */ + +/* FIFO Control Register */ + +#define FCR_FEN 0x0100 /* FIFO enable */ +#define FCR_RFRES 0x0200 /* Receiver FIFO reset */ +#define FCR_TFRES 0x0400 /* Transmitter FIFO reset */ +#define FCR_DMA 0x0800 /* DMA mode select */ +#define FCR_RTL 0x4000 /* Receiver triger (LSB) */ +#define FCR_RTM 0x8000 /* Receiver triger (MSB) */ + +/* Line Control Register */ + +#define LCR_WLS0 0x0100 /* Word Length Select Bit 0 */ +#define LCR_WLS1 0x0200 /* Word Length Select Bit 1 */ +#define LCR_STB 0x0400 /* Number of Stop Bits */ +#define LCR_PEN 0x0800 /* Parity Enable */ +#define LCR_EPS 0x1000 /* Even Parity Select */ +#define LCR_SP 0x2000 /* Stick Parity */ +#define LCR_SB 0x4000 /* Set Break */ +#define LCR_DLAB 0x8000 /* Divisor Latch Access Bit */ + +/* MODEM Control Register */ + +#define MCR_DTR 0x0100 /* Data Terminal Ready */ +#define MCR_RTS 0x0200 /* Request to Send */ +#define MCR_OUT1 0x0400 /* Out 1 */ +#define MCR_IRQEN 0x0800 /* IRQ Enable */ +#define MCR_LOOP 0x1000 /* Loop */ + +/* Line Status Register */ + +#define LSR_DR 0x0100 /* Data Ready */ +#define LSR_OE 0x0200 /* Overrun Error */ +#define LSR_PE 0x0400 /* Parity Error */ +#define LSR_FE 0x0800 /* Framing Error */ +#define LSR_BI 0x1000 /* Break Interrupt */ +#define LSR_THRE 0x2000 /* Transmitter Holding Register Empty */ +#define LSR_TEMT 0x4000 /* Transmitter Empty */ +#define LSR_FIFOE 0x8000 /* Receiver FIFO error */ + +/* MODEM Status Register */ + +#define MSR_DCTS 0x0100 /* Delta Clear to Send */ +#define MSR_DDSR 0x0200 /* Delta Data Set Ready */ +#define MSR_TERI 0x0400 /* Trailing Edge Ring Indicator */ +#define MSR_DDCD 0x0800 /* Delta Data Carrier Detect */ +#define MSR_CTS 0x1000 /* Clear to Send */ +#define MSR_DSR 0x2000 /* Data Set Ready */ +#define MSR_RI 0x4000 /* Ring Indicator */ +#define MSR_DCD 0x8000 /* Data Carrier Detect */ + +/* Baud Rate Divisor */ + +#define UART_CLK (1843200) /* 1.8432 MHz */ +#define UART_BAUD(x) (UART_CLK / (16 * (x))) + +/* RTC register definition */ +#define RTC_SECONDS 0 +#define RTC_SECONDS_ALARM 1 +#define RTC_MINUTES 2 +#define RTC_MINUTES_ALARM 3 +#define RTC_HOURS 4 +#define RTC_HOURS_ALARM 5 +#define RTC_DAY_OF_WEEK 6 +#define RTC_DAY_OF_MONTH 7 +#define RTC_MONTH 8 +#define RTC_YEAR 9 +#define RTC_FREQ_SELECT 10 +# define RTC_UIP 0x80 +# define RTC_DIV_CTL 0x70 +/* This RTC can work under 32.768KHz clock only. */ +# define RTC_OSC_ENABLE 0x20 +# define RTC_OSC_DISABLE 0x00 +#define RTC_CONTROL 11 +# define RTC_SET 0x80 +# define RTC_PIE 0x40 +# define RTC_AIE 0x20 +# define RTC_UIE 0x10 +# define RTC_SQWE 0x08 +# define RTC_DM_BINARY 0x04 +# define RTC_24H 0x02 +# define RTC_DST_EN 0x01 + +#endif /* __ASM_SH_SMC37C93X_H */ diff --git a/arch/sh/include/asm/smp-ops.h b/arch/sh/include/asm/smp-ops.h new file mode 100644 index 000000000..c590f7685 --- /dev/null +++ b/arch/sh/include/asm/smp-ops.h @@ -0,0 +1,51 @@ +#ifndef __ASM_SH_SMP_OPS_H +#define __ASM_SH_SMP_OPS_H + +struct plat_smp_ops { + void (*smp_setup)(void); + unsigned int (*smp_processor_id)(void); + void (*prepare_cpus)(unsigned int max_cpus); + void (*start_cpu)(unsigned int cpu, unsigned long entry_point); + void (*send_ipi)(unsigned int cpu, unsigned int message); + int (*cpu_disable)(unsigned int cpu); + void (*cpu_die)(unsigned int cpu); + void (*play_dead)(void); +}; + +extern struct plat_smp_ops *mp_ops; +extern struct plat_smp_ops shx3_smp_ops; + +#ifdef CONFIG_SMP + +static inline void plat_smp_setup(void) +{ + BUG_ON(!mp_ops); + mp_ops->smp_setup(); +} + +static inline void play_dead(void) +{ + mp_ops->play_dead(); +} + +extern void register_smp_ops(struct plat_smp_ops *ops); + +#else + +static inline void plat_smp_setup(void) +{ + /* UP, nothing to do ... */ +} + +static inline void register_smp_ops(struct plat_smp_ops *ops) +{ +} + +static inline void play_dead(void) +{ + BUG(); +} + +#endif /* CONFIG_SMP */ + +#endif /* __ASM_SH_SMP_OPS_H */ diff --git a/arch/sh/include/asm/smp.h b/arch/sh/include/asm/smp.h new file mode 100644 index 000000000..78b0d0f4b --- /dev/null +++ b/arch/sh/include/asm/smp.h @@ -0,0 +1,78 @@ +#ifndef __ASM_SH_SMP_H +#define __ASM_SH_SMP_H + +#include <linux/bitops.h> +#include <linux/cpumask.h> +#include <asm/smp-ops.h> + +#ifdef CONFIG_SMP + +#include <linux/spinlock.h> +#include <linux/atomic.h> +#include <asm/current.h> +#include <asm/percpu.h> + +#define raw_smp_processor_id() (current_thread_info()->cpu) + +/* Map from cpu id to sequential logical cpu number. */ +extern int __cpu_number_map[NR_CPUS]; +#define cpu_number_map(cpu) __cpu_number_map[cpu] + +/* The reverse map from sequential logical cpu number to cpu id. */ +extern int __cpu_logical_map[NR_CPUS]; +#define cpu_logical_map(cpu) __cpu_logical_map[cpu] + +enum { + SMP_MSG_FUNCTION, + SMP_MSG_RESCHEDULE, + SMP_MSG_FUNCTION_SINGLE, + SMP_MSG_TIMER, + + SMP_MSG_NR, /* must be last */ +}; + +DECLARE_PER_CPU(int, cpu_state); + +void smp_message_recv(unsigned int msg); +void smp_timer_broadcast(const struct cpumask *mask); + +void local_timer_interrupt(void); +void local_timer_setup(unsigned int cpu); +void local_timer_stop(unsigned int cpu); + +void arch_send_call_function_single_ipi(int cpu); +void arch_send_call_function_ipi_mask(const struct cpumask *mask); + +void native_play_dead(void); +void native_cpu_die(unsigned int cpu); +int native_cpu_disable(unsigned int cpu); + +#ifdef CONFIG_HOTPLUG_CPU +void play_dead_common(void); +extern int __cpu_disable(void); + +static inline void __cpu_die(unsigned int cpu) +{ + extern struct plat_smp_ops *mp_ops; /* private */ + + mp_ops->cpu_die(cpu); +} +#endif + +static inline int hard_smp_processor_id(void) +{ + extern struct plat_smp_ops *mp_ops; /* private */ + + if (!mp_ops) + return 0; /* boot CPU */ + + return mp_ops->smp_processor_id(); +} + +#else + +#define hard_smp_processor_id() (0) + +#endif /* CONFIG_SMP */ + +#endif /* __ASM_SH_SMP_H */ diff --git a/arch/sh/include/asm/sparsemem.h b/arch/sh/include/asm/sparsemem.h new file mode 100644 index 000000000..547a540b6 --- /dev/null +++ b/arch/sh/include/asm/sparsemem.h @@ -0,0 +1,16 @@ +#ifndef __ASM_SH_SPARSEMEM_H +#define __ASM_SH_SPARSEMEM_H + +#ifdef __KERNEL__ +/* + * SECTION_SIZE_BITS 2^N: how big each section will be + * MAX_PHYSADDR_BITS 2^N: how much physical address space we have + * MAX_PHYSMEM_BITS 2^N: how much memory we can have in that space + */ +#define SECTION_SIZE_BITS 26 +#define MAX_PHYSADDR_BITS 32 +#define MAX_PHYSMEM_BITS 32 + +#endif + +#endif /* __ASM_SH_SPARSEMEM_H */ diff --git a/arch/sh/include/asm/spi.h b/arch/sh/include/asm/spi.h new file mode 100644 index 000000000..e96f5b095 --- /dev/null +++ b/arch/sh/include/asm/spi.h @@ -0,0 +1,13 @@ +#ifndef __ASM_SPI_H__ +#define __ASM_SPI_H__ + +struct sh_spi_info; + +struct sh_spi_info { + int bus_num; + int num_chipselect; + + void (*chip_select)(struct sh_spi_info *spi, int cs, int state); +}; + +#endif /* __ASM_SPI_H__ */ diff --git a/arch/sh/include/asm/spinlock.h b/arch/sh/include/asm/spinlock.h new file mode 100644 index 000000000..bdc0f3b6c --- /dev/null +++ b/arch/sh/include/asm/spinlock.h @@ -0,0 +1,226 @@ +/* + * include/asm-sh/spinlock.h + * + * Copyright (C) 2002, 2003 Paul Mundt + * Copyright (C) 2006, 2007 Akio Idehara + * + * 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_SPINLOCK_H +#define __ASM_SH_SPINLOCK_H + +/* + * The only locking implemented here uses SH-4A opcodes. For others, + * split this out as per atomic-*.h. + */ +#ifndef CONFIG_CPU_SH4A +#error "Need movli.l/movco.l for spinlocks" +#endif + +/* + * Your basic SMP spinlocks, allowing only a single CPU anywhere + */ + +#define arch_spin_is_locked(x) ((x)->lock <= 0) +#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) +#define arch_spin_unlock_wait(x) \ + do { while (arch_spin_is_locked(x)) cpu_relax(); } while (0) + +/* + * Simple spin lock operations. There are two variants, one clears IRQ's + * on the local processor, one does not. + * + * We make no fairness assumptions. They have a cost. + */ +static inline void arch_spin_lock(arch_spinlock_t *lock) +{ + unsigned long tmp; + unsigned long oldval; + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%2, %0 ! arch_spin_lock \n\t" + "mov %0, %1 \n\t" + "mov #0, %0 \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "cmp/pl %1 \n\t" + "bf 1b \n\t" + : "=&z" (tmp), "=&r" (oldval) + : "r" (&lock->lock) + : "t", "memory" + ); +} + +static inline void arch_spin_unlock(arch_spinlock_t *lock) +{ + unsigned long tmp; + + __asm__ __volatile__ ( + "mov #1, %0 ! arch_spin_unlock \n\t" + "mov.l %0, @%1 \n\t" + : "=&z" (tmp) + : "r" (&lock->lock) + : "t", "memory" + ); +} + +static inline int arch_spin_trylock(arch_spinlock_t *lock) +{ + unsigned long tmp, oldval; + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%2, %0 ! arch_spin_trylock \n\t" + "mov %0, %1 \n\t" + "mov #0, %0 \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "synco \n\t" + : "=&z" (tmp), "=&r" (oldval) + : "r" (&lock->lock) + : "t", "memory" + ); + + return oldval; +} + +/* + * Read-write spinlocks, allowing multiple readers but only one writer. + * + * NOTE! it is quite common to have readers in interrupts but no interrupt + * writers. For those circumstances we can "mix" irq-safe locks - any writer + * needs to get a irq-safe write-lock, but readers can get non-irqsafe + * read-locks. + */ + +/** + * read_can_lock - would read_trylock() succeed? + * @lock: the rwlock in question. + */ +#define arch_read_can_lock(x) ((x)->lock > 0) + +/** + * write_can_lock - would write_trylock() succeed? + * @lock: the rwlock in question. + */ +#define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS) + +static inline void arch_read_lock(arch_rwlock_t *rw) +{ + unsigned long tmp; + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%1, %0 ! arch_read_lock \n\t" + "cmp/pl %0 \n\t" + "bf 1b \n\t" + "add #-1, %0 \n\t" + "movco.l %0, @%1 \n\t" + "bf 1b \n\t" + : "=&z" (tmp) + : "r" (&rw->lock) + : "t", "memory" + ); +} + +static inline void arch_read_unlock(arch_rwlock_t *rw) +{ + unsigned long tmp; + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%1, %0 ! arch_read_unlock \n\t" + "add #1, %0 \n\t" + "movco.l %0, @%1 \n\t" + "bf 1b \n\t" + : "=&z" (tmp) + : "r" (&rw->lock) + : "t", "memory" + ); +} + +static inline void arch_write_lock(arch_rwlock_t *rw) +{ + unsigned long tmp; + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%1, %0 ! arch_write_lock \n\t" + "cmp/hs %2, %0 \n\t" + "bf 1b \n\t" + "sub %2, %0 \n\t" + "movco.l %0, @%1 \n\t" + "bf 1b \n\t" + : "=&z" (tmp) + : "r" (&rw->lock), "r" (RW_LOCK_BIAS) + : "t", "memory" + ); +} + +static inline void arch_write_unlock(arch_rwlock_t *rw) +{ + __asm__ __volatile__ ( + "mov.l %1, @%0 ! arch_write_unlock \n\t" + : + : "r" (&rw->lock), "r" (RW_LOCK_BIAS) + : "t", "memory" + ); +} + +static inline int arch_read_trylock(arch_rwlock_t *rw) +{ + unsigned long tmp, oldval; + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%2, %0 ! arch_read_trylock \n\t" + "mov %0, %1 \n\t" + "cmp/pl %0 \n\t" + "bf 2f \n\t" + "add #-1, %0 \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "2: \n\t" + "synco \n\t" + : "=&z" (tmp), "=&r" (oldval) + : "r" (&rw->lock) + : "t", "memory" + ); + + return (oldval > 0); +} + +static inline int arch_write_trylock(arch_rwlock_t *rw) +{ + unsigned long tmp, oldval; + + __asm__ __volatile__ ( + "1: \n\t" + "movli.l @%2, %0 ! arch_write_trylock \n\t" + "mov %0, %1 \n\t" + "cmp/hs %3, %0 \n\t" + "bf 2f \n\t" + "sub %3, %0 \n\t" + "2: \n\t" + "movco.l %0, @%2 \n\t" + "bf 1b \n\t" + "synco \n\t" + : "=&z" (tmp), "=&r" (oldval) + : "r" (&rw->lock), "r" (RW_LOCK_BIAS) + : "t", "memory" + ); + + return (oldval > (RW_LOCK_BIAS - 1)); +} + +#define arch_read_lock_flags(lock, flags) arch_read_lock(lock) +#define arch_write_lock_flags(lock, flags) arch_write_lock(lock) + +#define arch_spin_relax(lock) cpu_relax() +#define arch_read_relax(lock) cpu_relax() +#define arch_write_relax(lock) cpu_relax() + +#endif /* __ASM_SH_SPINLOCK_H */ diff --git a/arch/sh/include/asm/spinlock_types.h b/arch/sh/include/asm/spinlock_types.h new file mode 100644 index 000000000..9b7560db0 --- /dev/null +++ b/arch/sh/include/asm/spinlock_types.h @@ -0,0 +1,21 @@ +#ifndef __ASM_SH_SPINLOCK_TYPES_H +#define __ASM_SH_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +typedef struct { + volatile unsigned int lock; +} arch_spinlock_t; + +#define __ARCH_SPIN_LOCK_UNLOCKED { 1 } + +typedef struct { + volatile unsigned int lock; +} arch_rwlock_t; + +#define RW_LOCK_BIAS 0x01000000 +#define __ARCH_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } + +#endif diff --git a/arch/sh/include/asm/sram.h b/arch/sh/include/asm/sram.h new file mode 100644 index 000000000..a2808ce4c --- /dev/null +++ b/arch/sh/include/asm/sram.h @@ -0,0 +1,38 @@ +#ifndef __ASM_SRAM_H +#define __ASM_SRAM_H + +#ifdef CONFIG_HAVE_SRAM_POOL + +#include <linux/spinlock.h> +#include <linux/genalloc.h> + +/* arch/sh/mm/sram.c */ +extern struct gen_pool *sram_pool; + +static inline unsigned long sram_alloc(size_t len) +{ + if (!sram_pool) + return 0UL; + + return gen_pool_alloc(sram_pool, len); +} + +static inline void sram_free(unsigned long addr, size_t len) +{ + return gen_pool_free(sram_pool, addr, len); +} + +#else + +static inline unsigned long sram_alloc(size_t len) +{ + return 0; +} + +static inline void sram_free(unsigned long addr, size_t len) +{ +} + +#endif /* CONFIG_HAVE_SRAM_POOL */ + +#endif /* __ASM_SRAM_H */ diff --git a/arch/sh/include/asm/stackprotector.h b/arch/sh/include/asm/stackprotector.h new file mode 100644 index 000000000..d9df3a768 --- /dev/null +++ b/arch/sh/include/asm/stackprotector.h @@ -0,0 +1,27 @@ +#ifndef __ASM_SH_STACKPROTECTOR_H +#define __ASM_SH_STACKPROTECTOR_H + +#include <linux/random.h> +#include <linux/version.h> + +extern unsigned long __stack_chk_guard; + +/* + * Initialize the stackprotector canary value. + * + * NOTE: this must only be called from functions that never return, + * and it must always be inlined. + */ +static __always_inline void boot_init_stack_canary(void) +{ + unsigned long canary; + + /* Try to get a semi random initial value. */ + get_random_bytes(&canary, sizeof(canary)); + canary ^= LINUX_VERSION_CODE; + + current->stack_canary = canary; + __stack_chk_guard = current->stack_canary; +} + +#endif /* __ASM_SH_STACKPROTECTOR_H */ diff --git a/arch/sh/include/asm/stacktrace.h b/arch/sh/include/asm/stacktrace.h new file mode 100644 index 000000000..a7e2d4dfd --- /dev/null +++ b/arch/sh/include/asm/stacktrace.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2009 Matt Fleming + * + * Based on: + * The x86 implementation - arch/x86/include/asm/stacktrace.h + */ +#ifndef _ASM_SH_STACKTRACE_H +#define _ASM_SH_STACKTRACE_H + +/* Generic stack tracer with callbacks */ + +struct stacktrace_ops { + void (*address)(void *data, unsigned long address, int reliable); + /* On negative return stop dumping */ + int (*stack)(void *data, char *name); +}; + +void dump_trace(struct task_struct *tsk, struct pt_regs *regs, + unsigned long *stack, + const struct stacktrace_ops *ops, void *data); + +#endif /* _ASM_SH_STACKTRACE_H */ diff --git a/arch/sh/include/asm/string.h b/arch/sh/include/asm/string.h new file mode 100644 index 000000000..114011fa0 --- /dev/null +++ b/arch/sh/include/asm/string.h @@ -0,0 +1,5 @@ +#ifdef CONFIG_SUPERH32 +# include <asm/string_32.h> +#else +# include <asm/string_64.h> +#endif diff --git a/arch/sh/include/asm/string_32.h b/arch/sh/include/asm/string_32.h new file mode 100644 index 000000000..55f8db6bc --- /dev/null +++ b/arch/sh/include/asm/string_32.h @@ -0,0 +1,131 @@ +#ifndef __ASM_SH_STRING_H +#define __ASM_SH_STRING_H + +#ifdef __KERNEL__ + +/* + * Copyright (C) 1999 Niibe Yutaka + * But consider these trivial functions to be public domain. + */ + +#define __HAVE_ARCH_STRCPY +static inline char *strcpy(char *__dest, const char *__src) +{ + register char *__xdest = __dest; + unsigned long __dummy; + + __asm__ __volatile__("1:\n\t" + "mov.b @%1+, %2\n\t" + "mov.b %2, @%0\n\t" + "cmp/eq #0, %2\n\t" + "bf/s 1b\n\t" + " add #1, %0\n\t" + : "=r" (__dest), "=r" (__src), "=&z" (__dummy) + : "0" (__dest), "1" (__src) + : "memory", "t"); + + return __xdest; +} + +#define __HAVE_ARCH_STRNCPY +static inline char *strncpy(char *__dest, const char *__src, size_t __n) +{ + register char *__xdest = __dest; + unsigned long __dummy; + + if (__n == 0) + return __xdest; + + __asm__ __volatile__( + "1:\n" + "mov.b @%1+, %2\n\t" + "mov.b %2, @%0\n\t" + "cmp/eq #0, %2\n\t" + "bt/s 2f\n\t" + " cmp/eq %5,%1\n\t" + "bf/s 1b\n\t" + " add #1, %0\n" + "2:" + : "=r" (__dest), "=r" (__src), "=&z" (__dummy) + : "0" (__dest), "1" (__src), "r" (__src+__n) + : "memory", "t"); + + return __xdest; +} + +#define __HAVE_ARCH_STRCMP +static inline int strcmp(const char *__cs, const char *__ct) +{ + register int __res; + unsigned long __dummy; + + __asm__ __volatile__( + "mov.b @%1+, %3\n" + "1:\n\t" + "mov.b @%0+, %2\n\t" + "cmp/eq #0, %3\n\t" + "bt 2f\n\t" + "cmp/eq %2, %3\n\t" + "bt/s 1b\n\t" + " mov.b @%1+, %3\n\t" + "add #-2, %1\n\t" + "mov.b @%1, %3\n\t" + "sub %3, %2\n" + "2:" + : "=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy) + : "0" (__cs), "1" (__ct) + : "t"); + + return __res; +} + +#define __HAVE_ARCH_STRNCMP +static inline int strncmp(const char *__cs, const char *__ct, size_t __n) +{ + register int __res; + unsigned long __dummy; + + if (__n == 0) + return 0; + + __asm__ __volatile__( + "mov.b @%1+, %3\n" + "1:\n\t" + "mov.b @%0+, %2\n\t" + "cmp/eq %6, %0\n\t" + "bt/s 2f\n\t" + " cmp/eq #0, %3\n\t" + "bt/s 3f\n\t" + " cmp/eq %3, %2\n\t" + "bt/s 1b\n\t" + " mov.b @%1+, %3\n\t" + "add #-2, %1\n\t" + "mov.b @%1, %3\n" + "2:\n\t" + "sub %3, %2\n" + "3:" + :"=r" (__cs), "=r" (__ct), "=&r" (__res), "=&z" (__dummy) + : "0" (__cs), "1" (__ct), "r" (__cs+__n) + : "t"); + + return __res; +} + +#define __HAVE_ARCH_MEMSET +extern void *memset(void *__s, int __c, size_t __count); + +#define __HAVE_ARCH_MEMCPY +extern void *memcpy(void *__to, __const__ void *__from, size_t __n); + +#define __HAVE_ARCH_MEMMOVE +extern void *memmove(void *__dest, __const__ void *__src, size_t __n); + +#define __HAVE_ARCH_MEMCHR +extern void *memchr(const void *__s, int __c, size_t __n); + +#define __HAVE_ARCH_STRLEN +extern size_t strlen(const char *); + +#endif /* __KERNEL__ */ + +#endif /* __ASM_SH_STRING_H */ diff --git a/arch/sh/include/asm/string_64.h b/arch/sh/include/asm/string_64.h new file mode 100644 index 000000000..742007172 --- /dev/null +++ b/arch/sh/include/asm/string_64.h @@ -0,0 +1,20 @@ +#ifndef __ASM_SH_STRING_64_H +#define __ASM_SH_STRING_64_H + +#ifdef __KERNEL__ + +#define __HAVE_ARCH_MEMSET +extern void *memset(void *__s, int __c, size_t __count); + +#define __HAVE_ARCH_MEMCPY +extern void *memcpy(void *dest, const void *src, size_t count); + +#define __HAVE_ARCH_STRLEN +extern size_t strlen(const char *); + +#define __HAVE_ARCH_STRCPY +extern char *strcpy(char *__dest, const char *__src); + +#endif /* __KERNEL__ */ + +#endif /* __ASM_SH_STRING_64_H */ diff --git a/arch/sh/include/asm/suspend.h b/arch/sh/include/asm/suspend.h new file mode 100644 index 000000000..70ae0b288 --- /dev/null +++ b/arch/sh/include/asm/suspend.h @@ -0,0 +1,96 @@ +#ifndef _ASM_SH_SUSPEND_H +#define _ASM_SH_SUSPEND_H + +#ifndef __ASSEMBLY__ +#include <linux/notifier.h> + +#include <asm/ptrace.h> + +struct swsusp_arch_regs { + struct pt_regs user_regs; + unsigned long bank1_regs[8]; +}; + +void sh_mobile_call_standby(unsigned long mode); + +#ifdef CONFIG_CPU_IDLE +int sh_mobile_setup_cpuidle(void); +#else +static inline int sh_mobile_setup_cpuidle(void) { return 0; } +#endif + +/* notifier chains for pre/post sleep hooks */ +extern struct atomic_notifier_head sh_mobile_pre_sleep_notifier_list; +extern struct atomic_notifier_head sh_mobile_post_sleep_notifier_list; + +/* priority levels for notifiers */ +#define SH_MOBILE_SLEEP_BOARD 0 +#define SH_MOBILE_SLEEP_CPU 1 +#define SH_MOBILE_PRE(x) (x) +#define SH_MOBILE_POST(x) (-(x)) + +/* board code registration function for self-refresh assembly snippets */ +void sh_mobile_register_self_refresh(unsigned long flags, + void *pre_start, void *pre_end, + void *post_start, void *post_end); + +/* register structure for address/data information */ +struct sh_sleep_regs { + unsigned long stbcr; + unsigned long bar; + + /* MMU */ + unsigned long pteh; + unsigned long ptel; + unsigned long ttb; + unsigned long tea; + unsigned long mmucr; + unsigned long ptea; + unsigned long pascr; + unsigned long irmcr; + + /* Cache */ + unsigned long ccr; + unsigned long ramcr; +}; + +/* data area for low-level sleep code */ +struct sh_sleep_data { + /* current sleep mode (SUSP_SH_...) */ + unsigned long mode; + + /* addresses of board specific self-refresh snippets */ + unsigned long sf_pre; + unsigned long sf_post; + + /* address of resume code */ + unsigned long resume; + + /* register state saved and restored by the assembly code */ + unsigned long vbr; + unsigned long spc; + unsigned long sr; + unsigned long sp; + + /* structure for keeping register addresses */ + struct sh_sleep_regs addr; + + /* structure for saving/restoring register state */ + struct sh_sleep_regs data; +}; + +/* a bitmap of supported sleep modes (SUSP_SH..) */ +extern unsigned long sh_mobile_sleep_supported; + +#endif + +/* flags passed to assembly suspend code */ +#define SUSP_SH_SLEEP (1 << 0) /* Regular sleep mode */ +#define SUSP_SH_STANDBY (1 << 1) /* SH-Mobile Software standby mode */ +#define SUSP_SH_RSTANDBY (1 << 2) /* SH-Mobile R-standby mode */ +#define SUSP_SH_USTANDBY (1 << 3) /* SH-Mobile U-standby mode */ +#define SUSP_SH_SF (1 << 4) /* Enable self-refresh */ +#define SUSP_SH_MMU (1 << 5) /* Save/restore MMU and cache */ +#define SUSP_SH_REGS (1 << 6) /* Save/restore registers */ + +#endif /* _ASM_SH_SUSPEND_H */ diff --git a/arch/sh/include/asm/switch_to.h b/arch/sh/include/asm/switch_to.h new file mode 100644 index 000000000..bcd722fc8 --- /dev/null +++ b/arch/sh/include/asm/switch_to.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2004 Richard Curnow + * + * 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_SWITCH_TO_H +#define __ASM_SH_SWITCH_TO_H + +#ifdef CONFIG_SUPERH32 +# include <asm/switch_to_32.h> +#else +# include <asm/switch_to_64.h> +#endif + +#endif /* __ASM_SH_SWITCH_TO_H */ diff --git a/arch/sh/include/asm/switch_to_32.h b/arch/sh/include/asm/switch_to_32.h new file mode 100644 index 000000000..0c065513e --- /dev/null +++ b/arch/sh/include/asm/switch_to_32.h @@ -0,0 +1,134 @@ +#ifndef __ASM_SH_SWITCH_TO_32_H +#define __ASM_SH_SWITCH_TO_32_H + +#ifdef CONFIG_SH_DSP + +#define is_dsp_enabled(tsk) \ + (!!(tsk->thread.dsp_status.status & SR_DSP)) + +#define __restore_dsp(tsk) \ +do { \ + register u32 *__ts2 __asm__ ("r2") = \ + (u32 *)&tsk->thread.dsp_status; \ + __asm__ __volatile__ ( \ + ".balign 4\n\t" \ + "movs.l @r2+, a0\n\t" \ + "movs.l @r2+, a1\n\t" \ + "movs.l @r2+, a0g\n\t" \ + "movs.l @r2+, a1g\n\t" \ + "movs.l @r2+, m0\n\t" \ + "movs.l @r2+, m1\n\t" \ + "movs.l @r2+, x0\n\t" \ + "movs.l @r2+, x1\n\t" \ + "movs.l @r2+, y0\n\t" \ + "movs.l @r2+, y1\n\t" \ + "lds.l @r2+, dsr\n\t" \ + "ldc.l @r2+, rs\n\t" \ + "ldc.l @r2+, re\n\t" \ + "ldc.l @r2+, mod\n\t" \ + : : "r" (__ts2)); \ +} while (0) + +#define __save_dsp(tsk) \ +do { \ + register u32 *__ts2 __asm__ ("r2") = \ + (u32 *)&tsk->thread.dsp_status + 14; \ + \ + __asm__ __volatile__ ( \ + ".balign 4\n\t" \ + "stc.l mod, @-r2\n\t" \ + "stc.l re, @-r2\n\t" \ + "stc.l rs, @-r2\n\t" \ + "sts.l dsr, @-r2\n\t" \ + "movs.l y1, @-r2\n\t" \ + "movs.l y0, @-r2\n\t" \ + "movs.l x1, @-r2\n\t" \ + "movs.l x0, @-r2\n\t" \ + "movs.l m1, @-r2\n\t" \ + "movs.l m0, @-r2\n\t" \ + "movs.l a1g, @-r2\n\t" \ + "movs.l a0g, @-r2\n\t" \ + "movs.l a1, @-r2\n\t" \ + "movs.l a0, @-r2\n\t" \ + : : "r" (__ts2)); \ +} while (0) + +#else + +#define is_dsp_enabled(tsk) (0) +#define __save_dsp(tsk) do { } while (0) +#define __restore_dsp(tsk) do { } while (0) +#endif + +struct task_struct *__switch_to(struct task_struct *prev, + struct task_struct *next); + +/* + * switch_to() should switch tasks to task nr n, first + */ +#define switch_to(prev, next, last) \ +do { \ + register u32 *__ts1 __asm__ ("r1"); \ + register u32 *__ts2 __asm__ ("r2"); \ + register u32 *__ts4 __asm__ ("r4"); \ + register u32 *__ts5 __asm__ ("r5"); \ + register u32 *__ts6 __asm__ ("r6"); \ + register u32 __ts7 __asm__ ("r7"); \ + struct task_struct *__last; \ + \ + if (is_dsp_enabled(prev)) \ + __save_dsp(prev); \ + \ + __ts1 = (u32 *)&prev->thread.sp; \ + __ts2 = (u32 *)&prev->thread.pc; \ + __ts4 = (u32 *)prev; \ + __ts5 = (u32 *)next; \ + __ts6 = (u32 *)&next->thread.sp; \ + __ts7 = next->thread.pc; \ + \ + __asm__ __volatile__ ( \ + ".balign 4\n\t" \ + "stc.l gbr, @-r15\n\t" \ + "sts.l pr, @-r15\n\t" \ + "mov.l r8, @-r15\n\t" \ + "mov.l r9, @-r15\n\t" \ + "mov.l r10, @-r15\n\t" \ + "mov.l r11, @-r15\n\t" \ + "mov.l r12, @-r15\n\t" \ + "mov.l r13, @-r15\n\t" \ + "mov.l r14, @-r15\n\t" \ + "mov.l r15, @r1\t! save SP\n\t" \ + "mov.l @r6, r15\t! change to new stack\n\t" \ + "mova 1f, %0\n\t" \ + "mov.l %0, @r2\t! save PC\n\t" \ + "mov.l 2f, %0\n\t" \ + "jmp @%0\t! call __switch_to\n\t" \ + " lds r7, pr\t! with return to new PC\n\t" \ + ".balign 4\n" \ + "2:\n\t" \ + ".long __switch_to\n" \ + "1:\n\t" \ + "mov.l @r15+, r14\n\t" \ + "mov.l @r15+, r13\n\t" \ + "mov.l @r15+, r12\n\t" \ + "mov.l @r15+, r11\n\t" \ + "mov.l @r15+, r10\n\t" \ + "mov.l @r15+, r9\n\t" \ + "mov.l @r15+, r8\n\t" \ + "lds.l @r15+, pr\n\t" \ + "ldc.l @r15+, gbr\n\t" \ + : "=z" (__last) \ + : "r" (__ts1), "r" (__ts2), "r" (__ts4), \ + "r" (__ts5), "r" (__ts6), "r" (__ts7) \ + : "r3", "t"); \ + \ + last = __last; \ +} while (0) + +#define finish_arch_switch(prev) \ +do { \ + if (is_dsp_enabled(prev)) \ + __restore_dsp(prev); \ +} while (0) + +#endif /* __ASM_SH_SWITCH_TO_32_H */ diff --git a/arch/sh/include/asm/switch_to_64.h b/arch/sh/include/asm/switch_to_64.h new file mode 100644 index 000000000..ba3129d6b --- /dev/null +++ b/arch/sh/include/asm/switch_to_64.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2004 Richard Curnow + * + * 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_SWITCH_TO_64_H +#define __ASM_SH_SWITCH_TO_64_H + +struct thread_struct; +struct task_struct; + +/* + * switch_to() should switch tasks to task nr n, first + */ +struct task_struct *sh64_switch_to(struct task_struct *prev, + struct thread_struct *prev_thread, + struct task_struct *next, + struct thread_struct *next_thread); + +#define switch_to(prev,next,last) \ +do { \ + if (last_task_used_math != next) { \ + struct pt_regs *regs = next->thread.uregs; \ + if (regs) regs->sr |= SR_FD; \ + } \ + last = sh64_switch_to(prev, &prev->thread, next, \ + &next->thread); \ +} while (0) + + +#endif /* __ASM_SH_SWITCH_TO_64_H */ diff --git a/arch/sh/include/asm/syscall.h b/arch/sh/include/asm/syscall.h new file mode 100644 index 000000000..847128da6 --- /dev/null +++ b/arch/sh/include/asm/syscall.h @@ -0,0 +1,12 @@ +#ifndef __ASM_SH_SYSCALL_H +#define __ASM_SH_SYSCALL_H + +extern const unsigned long sys_call_table[]; + +#ifdef CONFIG_SUPERH32 +# include <asm/syscall_32.h> +#else +# include <asm/syscall_64.h> +#endif + +#endif /* __ASM_SH_SYSCALL_H */ diff --git a/arch/sh/include/asm/syscall_32.h b/arch/sh/include/asm/syscall_32.h new file mode 100644 index 000000000..95be3b0ce --- /dev/null +++ b/arch/sh/include/asm/syscall_32.h @@ -0,0 +1,106 @@ +#ifndef __ASM_SH_SYSCALL_32_H +#define __ASM_SH_SYSCALL_32_H + +#include <uapi/linux/audit.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/err.h> +#include <asm/ptrace.h> + +/* The system call number is given by the user in R3 */ +static inline long syscall_get_nr(struct task_struct *task, + struct pt_regs *regs) +{ + return (regs->tra >= 0) ? regs->regs[3] : -1L; +} + +static inline void syscall_rollback(struct task_struct *task, + struct pt_regs *regs) +{ + /* + * XXX: This needs some thought. On SH we don't + * save away the original r0 value anywhere. + */ +} + +static inline long syscall_get_error(struct task_struct *task, + struct pt_regs *regs) +{ + return IS_ERR_VALUE(regs->regs[0]) ? regs->regs[0] : 0; +} + +static inline long syscall_get_return_value(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->regs[0]; +} + +static inline void syscall_set_return_value(struct task_struct *task, + struct pt_regs *regs, + int error, long val) +{ + if (error) + regs->regs[0] = -error; + else + regs->regs[0] = val; +} + +static inline void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + unsigned long *args) +{ + /* + * Do this simply for now. If we need to start supporting + * fetching arguments from arbitrary indices, this will need some + * extra logic. Presently there are no in-tree users that depend + * on this behaviour. + */ + BUG_ON(i); + + /* Argument pattern is: R4, R5, R6, R7, R0, R1 */ + switch (n) { + case 6: args[5] = regs->regs[1]; + case 5: args[4] = regs->regs[0]; + case 4: args[3] = regs->regs[7]; + case 3: args[2] = regs->regs[6]; + case 2: args[1] = regs->regs[5]; + case 1: args[0] = regs->regs[4]; + case 0: + break; + default: + BUG(); + } +} + +static inline void syscall_set_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + const unsigned long *args) +{ + /* Same note as above applies */ + BUG_ON(i); + + switch (n) { + case 6: regs->regs[1] = args[5]; + case 5: regs->regs[0] = args[4]; + case 4: regs->regs[7] = args[3]; + case 3: regs->regs[6] = args[2]; + case 2: regs->regs[5] = args[1]; + case 1: regs->regs[4] = args[0]; + break; + default: + BUG(); + } +} + +static inline int syscall_get_arch(void) +{ + int arch = AUDIT_ARCH_SH; + +#ifdef CONFIG_CPU_LITTLE_ENDIAN + arch |= __AUDIT_ARCH_LE; +#endif + return arch; +} +#endif /* __ASM_SH_SYSCALL_32_H */ diff --git a/arch/sh/include/asm/syscall_64.h b/arch/sh/include/asm/syscall_64.h new file mode 100644 index 000000000..c6a797b90 --- /dev/null +++ b/arch/sh/include/asm/syscall_64.h @@ -0,0 +1,78 @@ +#ifndef __ASM_SH_SYSCALL_64_H +#define __ASM_SH_SYSCALL_64_H + +#include <uapi/linux/audit.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <asm/ptrace.h> + +/* The system call number is given by the user in R9 */ +static inline long syscall_get_nr(struct task_struct *task, + struct pt_regs *regs) +{ + return (regs->syscall_nr >= 0) ? regs->regs[9] : -1L; +} + +static inline void syscall_rollback(struct task_struct *task, + struct pt_regs *regs) +{ + /* + * XXX: This needs some thought. On SH we don't + * save away the original R9 value anywhere. + */ +} + +static inline long syscall_get_error(struct task_struct *task, + struct pt_regs *regs) +{ + return IS_ERR_VALUE(regs->regs[9]) ? regs->regs[9] : 0; +} + +static inline long syscall_get_return_value(struct task_struct *task, + struct pt_regs *regs) +{ + return regs->regs[9]; +} + +static inline void syscall_set_return_value(struct task_struct *task, + struct pt_regs *regs, + int error, long val) +{ + if (error) + regs->regs[9] = -error; + else + regs->regs[9] = val; +} + +static inline void syscall_get_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + unsigned long *args) +{ + BUG_ON(i + n > 6); + memcpy(args, ®s->regs[2 + i], n * sizeof(args[0])); +} + +static inline void syscall_set_arguments(struct task_struct *task, + struct pt_regs *regs, + unsigned int i, unsigned int n, + const unsigned long *args) +{ + BUG_ON(i + n > 6); + memcpy(®s->regs[2 + i], args, n * sizeof(args[0])); +} + +static inline int syscall_get_arch(void) +{ + int arch = AUDIT_ARCH_SH; + +#ifdef CONFIG_64BIT + arch |= __AUDIT_ARCH_64BIT; +#endif +#ifdef CONFIG_CPU_LITTLE_ENDIAN + arch |= __AUDIT_ARCH_LE; +#endif + + return arch; +} +#endif /* __ASM_SH_SYSCALL_64_H */ diff --git a/arch/sh/include/asm/syscalls.h b/arch/sh/include/asm/syscalls.h new file mode 100644 index 000000000..3dbfef06f --- /dev/null +++ b/arch/sh/include/asm/syscalls.h @@ -0,0 +1,20 @@ +#ifndef __ASM_SH_SYSCALLS_H +#define __ASM_SH_SYSCALLS_H + +#ifdef __KERNEL__ + +asmlinkage int old_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + int fd, unsigned long off); +asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff); + +#ifdef CONFIG_SUPERH32 +# include <asm/syscalls_32.h> +#else +# include <asm/syscalls_64.h> +#endif + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_SYSCALLS_H */ diff --git a/arch/sh/include/asm/syscalls_32.h b/arch/sh/include/asm/syscalls_32.h new file mode 100644 index 000000000..4f643aa71 --- /dev/null +++ b/arch/sh/include/asm/syscalls_32.h @@ -0,0 +1,29 @@ +#ifndef __ASM_SH_SYSCALLS_32_H +#define __ASM_SH_SYSCALLS_32_H + +#ifdef __KERNEL__ + +#include <linux/compiler.h> +#include <linux/linkage.h> +#include <linux/types.h> + +struct pt_regs; + +asmlinkage int sys_sigreturn(void); +asmlinkage int sys_rt_sigreturn(void); +asmlinkage int sys_sh_pipe(void); +asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char __user *buf, + size_t count, long dummy, loff_t pos); +asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char __user *buf, + size_t count, long dummy, loff_t pos); +asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1, + u32 len0, u32 len1, int advice); + +/* Misc syscall related bits */ +asmlinkage long do_syscall_trace_enter(struct pt_regs *regs); +asmlinkage void do_syscall_trace_leave(struct pt_regs *regs); +asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0, + unsigned long thread_info_flags); + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_SYSCALLS_32_H */ diff --git a/arch/sh/include/asm/syscalls_64.h b/arch/sh/include/asm/syscalls_64.h new file mode 100644 index 000000000..d62e8eb22 --- /dev/null +++ b/arch/sh/include/asm/syscalls_64.h @@ -0,0 +1,17 @@ +#ifndef __ASM_SH_SYSCALLS_64_H +#define __ASM_SH_SYSCALLS_64_H + +#ifdef __KERNEL__ + +#include <linux/compiler.h> +#include <linux/linkage.h> +#include <linux/types.h> + +struct pt_regs; + +/* Misc syscall related bits */ +asmlinkage long long do_syscall_trace_enter(struct pt_regs *regs); +asmlinkage void do_syscall_trace_leave(struct pt_regs *regs); + +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_SYSCALLS_64_H */ diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h new file mode 100644 index 000000000..2afa32115 --- /dev/null +++ b/arch/sh/include/asm/thread_info.h @@ -0,0 +1,206 @@ +#ifndef __ASM_SH_THREAD_INFO_H +#define __ASM_SH_THREAD_INFO_H + +/* SuperH version + * Copyright (C) 2002 Niibe Yutaka + * + * The copyright of original i386 version is: + * + * Copyright (C) 2002 David Howells (dhowells@redhat.com) + * - Incorporating suggestions made by Linus Torvalds and Dave Miller + */ +#ifdef __KERNEL__ + +#include <asm/page.h> + +/* + * Page fault error code bits + */ +#define FAULT_CODE_WRITE (1 << 0) /* write access */ +#define FAULT_CODE_INITIAL (1 << 1) /* initial page write */ +#define FAULT_CODE_ITLB (1 << 2) /* ITLB miss */ +#define FAULT_CODE_PROT (1 << 3) /* protection fault */ +#define FAULT_CODE_USER (1 << 4) /* user-mode access */ + +#ifndef __ASSEMBLY__ +#include <asm/processor.h> + +struct thread_info { + struct task_struct *task; /* main task structure */ + unsigned long flags; /* low level flags */ + __u32 status; /* thread synchronous flags */ + __u32 cpu; + int preempt_count; /* 0 => preemptable, <0 => BUG */ + mm_segment_t addr_limit; /* thread address space */ + unsigned long previous_sp; /* sp of previous stack in case + of nested IRQ stacks */ + __u8 supervisor_stack[0]; +}; + +#endif + +#if defined(CONFIG_4KSTACKS) +#define THREAD_SHIFT 12 +#else +#define THREAD_SHIFT 13 +#endif + +#define THREAD_SIZE (1 << THREAD_SHIFT) +#define STACK_WARN (THREAD_SIZE >> 3) + +/* + * macros/functions for gaining access to the thread information structure + */ +#ifndef __ASSEMBLY__ +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task = &tsk, \ + .flags = 0, \ + .status = 0, \ + .cpu = 0, \ + .preempt_count = INIT_PREEMPT_COUNT, \ + .addr_limit = KERNEL_DS, \ +} + +#define init_thread_info (init_thread_union.thread_info) +#define init_stack (init_thread_union.stack) + +/* how to get the current stack pointer from C */ +register unsigned long current_stack_pointer asm("r15") __used; + +/* how to get the thread information struct from C */ +static inline struct thread_info *current_thread_info(void) +{ + struct thread_info *ti; +#if defined(CONFIG_SUPERH64) + __asm__ __volatile__ ("getcon cr17, %0" : "=r" (ti)); +#elif defined(CONFIG_CPU_HAS_SR_RB) + __asm__ __volatile__ ("stc r7_bank, %0" : "=r" (ti)); +#else + unsigned long __dummy; + + __asm__ __volatile__ ( + "mov r15, %0\n\t" + "and %1, %0\n\t" + : "=&r" (ti), "=r" (__dummy) + : "1" (~(THREAD_SIZE - 1)) + : "memory"); +#endif + + return ti; +} + +#define THREAD_SIZE_ORDER (THREAD_SHIFT - PAGE_SHIFT) + +extern void arch_task_cache_init(void); +extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src); +extern void arch_release_task_struct(struct task_struct *tsk); +extern void init_thread_xstate(void); + +#endif /* __ASSEMBLY__ */ + +/* + * Thread information flags + * + * - Limited to 24 bits, upper byte used for fault code encoding. + * + * - _TIF_ALLWORK_MASK and _TIF_WORK_MASK need to fit within 2 bytes, or + * we blow the tst immediate size constraints and need to fix up + * arch/sh/kernel/entry-common.S. + */ +#define TIF_SYSCALL_TRACE 0 /* syscall trace active */ +#define TIF_SIGPENDING 1 /* signal pending */ +#define TIF_NEED_RESCHED 2 /* rescheduling necessary */ +#define TIF_SINGLESTEP 4 /* singlestepping active */ +#define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */ +#define TIF_SECCOMP 6 /* secure computing */ +#define TIF_NOTIFY_RESUME 7 /* callback before returning to user */ +#define TIF_SYSCALL_TRACEPOINT 8 /* for ftrace syscall instrumentation */ +#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ +#define TIF_MEMDIE 18 /* is terminating due to OOM killer */ + +#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) +#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) +#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) +#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP) +#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT) +#define _TIF_SECCOMP (1 << TIF_SECCOMP) +#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) +#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) +#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) + +/* work to do in syscall trace */ +#define _TIF_WORK_SYSCALL_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \ + _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \ + _TIF_SYSCALL_TRACEPOINT) + +/* work to do on any return to u-space */ +#define _TIF_ALLWORK_MASK (_TIF_SYSCALL_TRACE | _TIF_SIGPENDING | \ + _TIF_NEED_RESCHED | _TIF_SYSCALL_AUDIT | \ + _TIF_SINGLESTEP | _TIF_NOTIFY_RESUME | \ + _TIF_SYSCALL_TRACEPOINT) + +/* work to do on interrupt/exception return */ +#define _TIF_WORK_MASK (_TIF_ALLWORK_MASK & ~(_TIF_SYSCALL_TRACE | \ + _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP)) + +/* + * Thread-synchronous status. + * + * This is different from the flags in that nobody else + * ever touches our thread-synchronous status, so we don't + * have to worry about atomic accesses. + */ +#define TS_RESTORE_SIGMASK 0x0001 /* restore signal mask in do_signal() */ +#define TS_USEDFPU 0x0002 /* FPU used by this task this quantum */ + +#ifndef __ASSEMBLY__ + +#define HAVE_SET_RESTORE_SIGMASK 1 +static inline void set_restore_sigmask(void) +{ + struct thread_info *ti = current_thread_info(); + ti->status |= TS_RESTORE_SIGMASK; + WARN_ON(!test_bit(TIF_SIGPENDING, (unsigned long *)&ti->flags)); +} + +#define TI_FLAG_FAULT_CODE_SHIFT 24 + +/* + * Additional thread flag encoding + */ +static inline void set_thread_fault_code(unsigned int val) +{ + struct thread_info *ti = current_thread_info(); + ti->flags = (ti->flags & (~0 >> (32 - TI_FLAG_FAULT_CODE_SHIFT))) + | (val << TI_FLAG_FAULT_CODE_SHIFT); +} + +static inline unsigned int get_thread_fault_code(void) +{ + struct thread_info *ti = current_thread_info(); + return ti->flags >> TI_FLAG_FAULT_CODE_SHIFT; +} + +static inline void clear_restore_sigmask(void) +{ + current_thread_info()->status &= ~TS_RESTORE_SIGMASK; +} +static inline bool test_restore_sigmask(void) +{ + return current_thread_info()->status & TS_RESTORE_SIGMASK; +} +static inline bool test_and_clear_restore_sigmask(void) +{ + struct thread_info *ti = current_thread_info(); + if (!(ti->status & TS_RESTORE_SIGMASK)) + return false; + ti->status &= ~TS_RESTORE_SIGMASK; + return true; +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + +#endif /* __ASM_SH_THREAD_INFO_H */ diff --git a/arch/sh/include/asm/timex.h b/arch/sh/include/asm/timex.h new file mode 100644 index 000000000..18bf06d9c --- /dev/null +++ b/arch/sh/include/asm/timex.h @@ -0,0 +1,23 @@ +/* + * linux/include/asm-sh/timex.h + * + * sh architecture timex specifications + */ +#ifndef __ASM_SH_TIMEX_H +#define __ASM_SH_TIMEX_H + +/* + * Only parts using the legacy CPG code for their clock framework + * implementation need to define their own Pclk value. If provided, this + * can be used for accurately setting CLOCK_TICK_RATE, otherwise we + * simply fall back on the i8253 PIT value. + */ +#ifdef CONFIG_SH_PCLK_FREQ +#define CLOCK_TICK_RATE (CONFIG_SH_PCLK_FREQ / 4) /* Underlying HZ */ +#else +#define CLOCK_TICK_RATE 1193180 +#endif + +#include <asm-generic/timex.h> + +#endif /* __ASM_SH_TIMEX_H */ diff --git a/arch/sh/include/asm/tlb.h b/arch/sh/include/asm/tlb.h new file mode 100644 index 000000000..62f80d2a9 --- /dev/null +++ b/arch/sh/include/asm/tlb.h @@ -0,0 +1,145 @@ +#ifndef __ASM_SH_TLB_H +#define __ASM_SH_TLB_H + +#ifdef CONFIG_SUPERH64 +# include <asm/tlb_64.h> +#endif + +#ifndef __ASSEMBLY__ +#include <linux/pagemap.h> + +#ifdef CONFIG_MMU +#include <linux/swap.h> +#include <asm/pgalloc.h> +#include <asm/tlbflush.h> +#include <asm/mmu_context.h> + +/* + * TLB handling. This allows us to remove pages from the page + * tables, and efficiently handle the TLB issues. + */ +struct mmu_gather { + struct mm_struct *mm; + unsigned int fullmm; + unsigned long start, end; +}; + +static inline void init_tlb_gather(struct mmu_gather *tlb) +{ + tlb->start = TASK_SIZE; + tlb->end = 0; + + if (tlb->fullmm) { + tlb->start = 0; + tlb->end = TASK_SIZE; + } +} + +static inline void +tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end) +{ + tlb->mm = mm; + tlb->start = start; + tlb->end = end; + tlb->fullmm = !(start | (end+1)); + + init_tlb_gather(tlb); +} + +static inline void +tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) +{ + if (tlb->fullmm) + flush_tlb_mm(tlb->mm); + + /* keep the page table cache within bounds */ + check_pgt_cache(); +} + +static inline void +tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep, unsigned long address) +{ + if (tlb->start > address) + tlb->start = address; + if (tlb->end < address + PAGE_SIZE) + tlb->end = address + PAGE_SIZE; +} + +/* + * In the case of tlb vma handling, we can optimise these away in the + * case where we're doing a full MM flush. When we're doing a munmap, + * the vmas are adjusted to only cover the region to be torn down. + */ +static inline void +tlb_start_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) +{ + if (!tlb->fullmm) + flush_cache_range(vma, vma->vm_start, vma->vm_end); +} + +static inline void +tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma) +{ + if (!tlb->fullmm && tlb->end) { + flush_tlb_range(vma, tlb->start, tlb->end); + init_tlb_gather(tlb); + } +} + +static inline void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb) +{ +} + +static inline void tlb_flush_mmu_free(struct mmu_gather *tlb) +{ +} + +static inline void tlb_flush_mmu(struct mmu_gather *tlb) +{ +} + +static inline int __tlb_remove_page(struct mmu_gather *tlb, struct page *page) +{ + free_page_and_swap_cache(page); + return 1; /* avoid calling tlb_flush_mmu */ +} + +static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) +{ + __tlb_remove_page(tlb, page); +} + +#define pte_free_tlb(tlb, ptep, addr) pte_free((tlb)->mm, ptep) +#define pmd_free_tlb(tlb, pmdp, addr) pmd_free((tlb)->mm, pmdp) +#define pud_free_tlb(tlb, pudp, addr) pud_free((tlb)->mm, pudp) + +#define tlb_migrate_finish(mm) do { } while (0) + +#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SUPERH64) +extern void tlb_wire_entry(struct vm_area_struct *, unsigned long, pte_t); +extern void tlb_unwire_entry(void); +#else +static inline void tlb_wire_entry(struct vm_area_struct *vma , + unsigned long addr, pte_t pte) +{ + BUG(); +} + +static inline void tlb_unwire_entry(void) +{ + BUG(); +} +#endif + +#else /* CONFIG_MMU */ + +#define tlb_start_vma(tlb, vma) do { } while (0) +#define tlb_end_vma(tlb, vma) do { } while (0) +#define __tlb_remove_tlb_entry(tlb, pte, address) do { } while (0) +#define tlb_flush(tlb) do { } while (0) + +#include <asm-generic/tlb.h> + +#endif /* CONFIG_MMU */ +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_SH_TLB_H */ diff --git a/arch/sh/include/asm/tlb_64.h b/arch/sh/include/asm/tlb_64.h new file mode 100644 index 000000000..ef0ae2a28 --- /dev/null +++ b/arch/sh/include/asm/tlb_64.h @@ -0,0 +1,71 @@ +/* + * include/asm-sh/tlb_64.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_SH_TLB_64_H +#define __ASM_SH_TLB_64_H + +/* ITLB defines */ +#define ITLB_FIXED 0x00000000 /* First fixed ITLB, see head.S */ +#define ITLB_LAST_VAR_UNRESTRICTED 0x000003F0 /* Last ITLB */ + +/* DTLB defines */ +#define DTLB_FIXED 0x00800000 /* First fixed DTLB, see head.S */ +#define DTLB_LAST_VAR_UNRESTRICTED 0x008003F0 /* Last DTLB */ + +#ifndef __ASSEMBLY__ + +/** + * for_each_dtlb_entry - Iterate over free (non-wired) DTLB entries + * + * @tlb: TLB entry + */ +#define for_each_dtlb_entry(tlb) \ + for (tlb = cpu_data->dtlb.first; \ + tlb <= cpu_data->dtlb.last; \ + tlb += cpu_data->dtlb.step) + +/** + * for_each_itlb_entry - Iterate over free (non-wired) ITLB entries + * + * @tlb: TLB entry + */ +#define for_each_itlb_entry(tlb) \ + for (tlb = cpu_data->itlb.first; \ + tlb <= cpu_data->itlb.last; \ + tlb += cpu_data->itlb.step) + +/** + * __flush_tlb_slot - Flushes TLB slot @slot. + * + * @slot: Address of TLB slot. + */ +static inline void __flush_tlb_slot(unsigned long long slot) +{ + __asm__ __volatile__ ("putcfg %0, 0, r63\n" : : "r" (slot)); +} + +#ifdef CONFIG_MMU +/* arch/sh64/mm/tlb.c */ +int sh64_tlb_init(void); +unsigned long long sh64_next_free_dtlb_entry(void); +unsigned long long sh64_get_wired_dtlb_entry(void); +int sh64_put_wired_dtlb_entry(unsigned long long entry); +void sh64_setup_tlb_slot(unsigned long long config_addr, unsigned long eaddr, + unsigned long asid, unsigned long paddr); +void sh64_teardown_tlb_slot(unsigned long long config_addr); +#else +#define sh64_tlb_init() do { } while (0) +#define sh64_next_free_dtlb_entry() (0) +#define sh64_get_wired_dtlb_entry() (0) +#define sh64_put_wired_dtlb_entry(entry) do { } while (0) +#define sh64_setup_tlb_slot(conf, virt, asid, phys) do { } while (0) +#define sh64_teardown_tlb_slot(addr) do { } while (0) +#endif /* CONFIG_MMU */ +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_SH_TLB_64_H */ diff --git a/arch/sh/include/asm/tlbflush.h b/arch/sh/include/asm/tlbflush.h new file mode 100644 index 000000000..0df66f0c7 --- /dev/null +++ b/arch/sh/include/asm/tlbflush.h @@ -0,0 +1,51 @@ +#ifndef __ASM_SH_TLBFLUSH_H +#define __ASM_SH_TLBFLUSH_H + +/* + * TLB flushing: + * + * - flush_tlb_all() flushes all processes TLBs + * - flush_tlb_mm(mm) flushes the specified mm context TLB's + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(vma, start, end) flushes a range of pages + * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages + */ +extern void local_flush_tlb_all(void); +extern void local_flush_tlb_mm(struct mm_struct *mm); +extern void local_flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, + unsigned long end); +extern void local_flush_tlb_page(struct vm_area_struct *vma, + unsigned long page); +extern void local_flush_tlb_kernel_range(unsigned long start, + unsigned long end); +extern void local_flush_tlb_one(unsigned long asid, unsigned long page); + +extern void __flush_tlb_global(void); + +#ifdef CONFIG_SMP + +extern void flush_tlb_all(void); +extern void flush_tlb_mm(struct mm_struct *mm); +extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, + unsigned long end); +extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long page); +extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); +extern void flush_tlb_one(unsigned long asid, unsigned long page); + +#else + +#define flush_tlb_all() local_flush_tlb_all() +#define flush_tlb_mm(mm) local_flush_tlb_mm(mm) +#define flush_tlb_page(vma, page) local_flush_tlb_page(vma, page) +#define flush_tlb_one(asid, page) local_flush_tlb_one(asid, page) + +#define flush_tlb_range(vma, start, end) \ + local_flush_tlb_range(vma, start, end) + +#define flush_tlb_kernel_range(start, end) \ + local_flush_tlb_kernel_range(start, end) + +#endif /* CONFIG_SMP */ + +#endif /* __ASM_SH_TLBFLUSH_H */ diff --git a/arch/sh/include/asm/topology.h b/arch/sh/include/asm/topology.h new file mode 100644 index 000000000..b0a282d65 --- /dev/null +++ b/arch/sh/include/asm/topology.h @@ -0,0 +1,28 @@ +#ifndef _ASM_SH_TOPOLOGY_H +#define _ASM_SH_TOPOLOGY_H + +#ifdef CONFIG_NUMA + +#define cpu_to_node(cpu) ((void)(cpu),0) +#define parent_node(node) ((void)(node),0) + +#define cpumask_of_node(node) ((void)node, cpu_online_mask) + +#define pcibus_to_node(bus) ((void)(bus), -1) +#define cpumask_of_pcibus(bus) (pcibus_to_node(bus) == -1 ? \ + cpu_all_mask : \ + cpumask_of_node(pcibus_to_node(bus))) + +#endif + +#define mc_capable() (1) + +const struct cpumask *cpu_coregroup_mask(unsigned int cpu); + +extern cpumask_t cpu_core_map[NR_CPUS]; + +#define topology_core_cpumask(cpu) (&cpu_core_map[cpu]) + +#include <asm-generic/topology.h> + +#endif /* _ASM_SH_TOPOLOGY_H */ diff --git a/arch/sh/include/asm/traps.h b/arch/sh/include/asm/traps.h new file mode 100644 index 000000000..9cc149a0d --- /dev/null +++ b/arch/sh/include/asm/traps.h @@ -0,0 +1,21 @@ +#ifndef __ASM_SH_TRAPS_H +#define __ASM_SH_TRAPS_H + +#include <linux/compiler.h> + +#ifdef CONFIG_SUPERH32 +# include <asm/traps_32.h> +#else +# include <asm/traps_64.h> +#endif + +BUILD_TRAP_HANDLER(address_error); +BUILD_TRAP_HANDLER(debug); +BUILD_TRAP_HANDLER(bug); +BUILD_TRAP_HANDLER(breakpoint); +BUILD_TRAP_HANDLER(singlestep); +BUILD_TRAP_HANDLER(fpu_error); +BUILD_TRAP_HANDLER(fpu_state_restore); +BUILD_TRAP_HANDLER(nmi); + +#endif /* __ASM_SH_TRAPS_H */ diff --git a/arch/sh/include/asm/traps_32.h b/arch/sh/include/asm/traps_32.h new file mode 100644 index 000000000..17e129fe4 --- /dev/null +++ b/arch/sh/include/asm/traps_32.h @@ -0,0 +1,60 @@ +#ifndef __ASM_SH_TRAPS_32_H +#define __ASM_SH_TRAPS_32_H + +#include <linux/types.h> +#include <asm/mmu.h> + +#ifdef CONFIG_CPU_HAS_SR_RB +#define lookup_exception_vector() \ +({ \ + unsigned long _vec; \ + \ + __asm__ __volatile__ ( \ + "stc r2_bank, %0\n\t" \ + : "=r" (_vec) \ + ); \ + \ + _vec; \ +}) +#else +#define lookup_exception_vector() \ +({ \ + unsigned long _vec; \ + __asm__ __volatile__ ( \ + "mov r4, %0\n\t" \ + : "=r" (_vec) \ + ); \ + \ + _vec; \ +}) +#endif + +static inline void trigger_address_error(void) +{ + __asm__ __volatile__ ( + "ldc %0, sr\n\t" + "mov.l @%1, %0" + : + : "r" (0x10000000), "r" (0x80000001) + ); +} + +asmlinkage void do_address_error(struct pt_regs *regs, + unsigned long writeaccess, + unsigned long address); +asmlinkage void do_divide_error(unsigned long r4); +asmlinkage void do_reserved_inst(void); +asmlinkage void do_illegal_slot_inst(void); +asmlinkage void do_exception_error(void); + +#define BUILD_TRAP_HANDLER(name) \ +asmlinkage void name##_trap_handler(unsigned long r4, unsigned long r5, \ + unsigned long r6, unsigned long r7, \ + struct pt_regs __regs) + +#define TRAP_HANDLER_DECL \ + struct pt_regs *regs = RELOC_HIDE(&__regs, 0); \ + unsigned int vec = regs->tra; \ + (void)vec; + +#endif /* __ASM_SH_TRAPS_32_H */ diff --git a/arch/sh/include/asm/traps_64.h b/arch/sh/include/asm/traps_64.h new file mode 100644 index 000000000..ef5eff919 --- /dev/null +++ b/arch/sh/include/asm/traps_64.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003 Paul Mundt + * Copyright (C) 2004 Richard Curnow + * + * 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_TRAPS_64_H +#define __ASM_SH_TRAPS_64_H + +#include <cpu/registers.h> + +extern void phys_stext(void); + +#define lookup_exception_vector() \ +({ \ + unsigned long _vec; \ + \ + __asm__ __volatile__ ( \ + "getcon " __EXPEVT ", %0\n\t" \ + : "=r" (_vec) \ + ); \ + \ + _vec; \ +}) + +static inline void trigger_address_error(void) +{ + phys_stext(); +} + +#define BUILD_TRAP_HANDLER(name) \ +asmlinkage void name##_trap_handler(unsigned int vec, struct pt_regs *regs) +#define TRAP_HANDLER_DECL + +#endif /* __ASM_SH_TRAPS_64_H */ diff --git a/arch/sh/include/asm/types.h b/arch/sh/include/asm/types.h new file mode 100644 index 000000000..6a31053fa --- /dev/null +++ b/arch/sh/include/asm/types.h @@ -0,0 +1,20 @@ +#ifndef __ASM_SH_TYPES_H +#define __ASM_SH_TYPES_H + +#include <uapi/asm/types.h> + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifndef __ASSEMBLY__ + +#ifdef CONFIG_SUPERH32 +typedef u16 insn_size_t; +typedef u32 reg_size_t; +#else +typedef u32 insn_size_t; +typedef u64 reg_size_t; +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* __ASM_SH_TYPES_H */ diff --git a/arch/sh/include/asm/uaccess.h b/arch/sh/include/asm/uaccess.h new file mode 100644 index 000000000..a49635c51 --- /dev/null +++ b/arch/sh/include/asm/uaccess.h @@ -0,0 +1,211 @@ +#ifndef __ASM_SH_UACCESS_H +#define __ASM_SH_UACCESS_H + +#include <linux/errno.h> +#include <linux/sched.h> +#include <asm/segment.h> + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +#define __addr_ok(addr) \ + ((unsigned long __force)(addr) < current_thread_info()->addr_limit.seg) + +/* + * __access_ok: Check if address with size is OK or not. + * + * Uhhuh, this needs 33-bit arithmetic. We have a carry.. + * + * sum := addr + size; carry? --> flag = true; + * if (sum >= addr_limit) flag = true; + */ +#define __access_ok(addr, size) \ + (__addr_ok((addr) + (size))) +#define access_ok(type, addr, size) \ + (__chk_user_ptr(addr), \ + __access_ok((unsigned long __force)(addr), (size))) + +#define user_addr_max() (current_thread_info()->addr_limit.seg) + +/* + * Uh, these should become the main single-value transfer routines ... + * They automatically use the right size if we just have the right + * pointer type ... + * + * As SuperH uses the same address space for kernel and user data, we + * can just do these as direct assignments. + * + * Careful to not + * (a) re-use the arguments for side effects (sizeof is ok) + * (b) require any knowledge of processes at this stage + */ +#define put_user(x,ptr) __put_user_check((x), (ptr), sizeof(*(ptr))) +#define get_user(x,ptr) __get_user_check((x), (ptr), sizeof(*(ptr))) + +/* + * The "__xxx" versions do not do address space checking, useful when + * doing multiple accesses to the same area (the user has to do the + * checks by hand with "access_ok()") + */ +#define __put_user(x,ptr) __put_user_nocheck((x), (ptr), sizeof(*(ptr))) +#define __get_user(x,ptr) __get_user_nocheck((x), (ptr), sizeof(*(ptr))) + +struct __large_struct { unsigned long buf[100]; }; +#define __m(x) (*(struct __large_struct __user *)(x)) + +#define __get_user_nocheck(x,ptr,size) \ +({ \ + long __gu_err; \ + unsigned long __gu_val; \ + const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \ + __chk_user_ptr(ptr); \ + __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ + (x) = (__force __typeof__(*(ptr)))__gu_val; \ + __gu_err; \ +}) + +#define __get_user_check(x,ptr,size) \ +({ \ + long __gu_err = -EFAULT; \ + unsigned long __gu_val = 0; \ + const __typeof__(*(ptr)) *__gu_addr = (ptr); \ + if (likely(access_ok(VERIFY_READ, __gu_addr, (size)))) \ + __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \ + (x) = (__force __typeof__(*(ptr)))__gu_val; \ + __gu_err; \ +}) + +#define __put_user_nocheck(x,ptr,size) \ +({ \ + long __pu_err; \ + __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ + __typeof__(*(ptr)) __pu_val = x; \ + __chk_user_ptr(ptr); \ + __put_user_size(__pu_val, __pu_addr, (size), __pu_err); \ + __pu_err; \ +}) + +#define __put_user_check(x,ptr,size) \ +({ \ + long __pu_err = -EFAULT; \ + __typeof__(*(ptr)) __user *__pu_addr = (ptr); \ + __typeof__(*(ptr)) __pu_val = x; \ + if (likely(access_ok(VERIFY_WRITE, __pu_addr, size))) \ + __put_user_size(__pu_val, __pu_addr, (size), \ + __pu_err); \ + __pu_err; \ +}) + +#ifdef CONFIG_SUPERH32 +# include <asm/uaccess_32.h> +#else +# include <asm/uaccess_64.h> +#endif + +extern long strncpy_from_user(char *dest, const char __user *src, long count); + +extern __must_check long strlen_user(const char __user *str); +extern __must_check long strnlen_user(const char __user *str, long n); + +/* Generic arbitrary sized copy. */ +/* Return the number of bytes NOT copied */ +__kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n); + +static __always_inline unsigned long +__copy_from_user(void *to, const void __user *from, unsigned long n) +{ + return __copy_user(to, (__force void *)from, n); +} + +static __always_inline unsigned long __must_check +__copy_to_user(void __user *to, const void *from, unsigned long n) +{ + return __copy_user((__force void *)to, from, n); +} + +#define __copy_to_user_inatomic __copy_to_user +#define __copy_from_user_inatomic __copy_from_user + +/* + * Clear the area and return remaining number of bytes + * (on failure. Usually it's 0.) + */ +__kernel_size_t __clear_user(void *addr, __kernel_size_t size); + +#define clear_user(addr,n) \ +({ \ + void __user * __cl_addr = (addr); \ + unsigned long __cl_size = (n); \ + \ + if (__cl_size && access_ok(VERIFY_WRITE, \ + ((unsigned long)(__cl_addr)), __cl_size)) \ + __cl_size = __clear_user(__cl_addr, __cl_size); \ + \ + __cl_size; \ +}) + +static inline unsigned long +copy_from_user(void *to, const void __user *from, unsigned long n) +{ + unsigned long __copy_from = (unsigned long) from; + __kernel_size_t __copy_size = (__kernel_size_t) n; + + if (__copy_size && __access_ok(__copy_from, __copy_size)) + return __copy_user(to, from, __copy_size); + + return __copy_size; +} + +static inline unsigned long +copy_to_user(void __user *to, const void *from, unsigned long n) +{ + unsigned long __copy_to = (unsigned long) to; + __kernel_size_t __copy_size = (__kernel_size_t) n; + + if (__copy_size && __access_ok(__copy_to, __copy_size)) + return __copy_user(to, from, __copy_size); + + return __copy_size; +} + +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ +struct exception_table_entry { + unsigned long insn, fixup; +}; + +#if defined(CONFIG_SUPERH64) && defined(CONFIG_MMU) +#define ARCH_HAS_SEARCH_EXTABLE +#endif + +int fixup_exception(struct pt_regs *regs); +/* Returns 0 if exception not found and fixup.unit otherwise. */ +unsigned long search_exception_table(unsigned long addr); +const struct exception_table_entry *search_exception_tables(unsigned long addr); + +extern void *set_exception_table_vec(unsigned int vec, void *handler); + +static inline void *set_exception_table_evt(unsigned int evt, void *handler) +{ + return set_exception_table_vec(evt >> 5, handler); +} + +struct mem_access { + unsigned long (*from)(void *dst, const void __user *src, unsigned long cnt); + unsigned long (*to)(void __user *dst, const void *src, unsigned long cnt); +}; + +int handle_unaligned_access(insn_size_t instruction, struct pt_regs *regs, + struct mem_access *ma, int, unsigned long address); + +#endif /* __ASM_SH_UACCESS_H */ diff --git a/arch/sh/include/asm/uaccess_32.h b/arch/sh/include/asm/uaccess_32.h new file mode 100644 index 000000000..c0de7ee35 --- /dev/null +++ b/arch/sh/include/asm/uaccess_32.h @@ -0,0 +1,173 @@ +/* + * User space memory access functions + * + * Copyright (C) 1999, 2002 Niibe Yutaka + * Copyright (C) 2003 - 2008 Paul Mundt + * + * Based on: + * MIPS implementation version 1.15 by + * Copyright (C) 1996, 1997, 1998 by Ralf Baechle + * and i386 version. + */ +#ifndef __ASM_SH_UACCESS_32_H +#define __ASM_SH_UACCESS_32_H + +#define __get_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: \ + __get_user_asm(x, ptr, retval, "b"); \ + break; \ + case 2: \ + __get_user_asm(x, ptr, retval, "w"); \ + break; \ + case 4: \ + __get_user_asm(x, ptr, retval, "l"); \ + break; \ + default: \ + __get_user_unknown(); \ + break; \ + } \ +} while (0) + +#ifdef CONFIG_MMU +#define __get_user_asm(x, addr, err, insn) \ +({ \ +__asm__ __volatile__( \ + "1:\n\t" \ + "mov." insn " %2, %1\n\t" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3:\n\t" \ + "mov #0, %1\n\t" \ + "mov.l 4f, %0\n\t" \ + "jmp @%0\n\t" \ + " mov %3, %0\n\t" \ + ".balign 4\n" \ + "4: .long 2b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n\t" \ + ".long 1b, 3b\n\t" \ + ".previous" \ + :"=&r" (err), "=&r" (x) \ + :"m" (__m(addr)), "i" (-EFAULT), "0" (err)); }) +#else +#define __get_user_asm(x, addr, err, insn) \ +do { \ + __asm__ __volatile__ ( \ + "mov." insn " %1, %0\n\t" \ + : "=&r" (x) \ + : "m" (__m(addr)) \ + ); \ +} while (0) +#endif /* CONFIG_MMU */ + +extern void __get_user_unknown(void); + +#define __put_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: \ + __put_user_asm(x, ptr, retval, "b"); \ + break; \ + case 2: \ + __put_user_asm(x, ptr, retval, "w"); \ + break; \ + case 4: \ + __put_user_asm(x, ptr, retval, "l"); \ + break; \ + case 8: \ + __put_user_u64(x, ptr, retval); \ + break; \ + default: \ + __put_user_unknown(); \ + } \ +} while (0) + +#ifdef CONFIG_MMU +#define __put_user_asm(x, addr, err, insn) \ +do { \ + __asm__ __volatile__ ( \ + "1:\n\t" \ + "mov." insn " %1, %2\n\t" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3:\n\t" \ + "mov.l 4f, %0\n\t" \ + "jmp @%0\n\t" \ + " mov %3, %0\n\t" \ + ".balign 4\n" \ + "4: .long 2b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n\t" \ + ".long 1b, 3b\n\t" \ + ".previous" \ + : "=&r" (err) \ + : "r" (x), "m" (__m(addr)), "i" (-EFAULT), \ + "0" (err) \ + : "memory" \ + ); \ +} while (0) +#else +#define __put_user_asm(x, addr, err, insn) \ +do { \ + __asm__ __volatile__ ( \ + "mov." insn " %0, %1\n\t" \ + : /* no outputs */ \ + : "r" (x), "m" (__m(addr)) \ + : "memory" \ + ); \ +} while (0) +#endif /* CONFIG_MMU */ + +#if defined(CONFIG_CPU_LITTLE_ENDIAN) +#define __put_user_u64(val,addr,retval) \ +({ \ +__asm__ __volatile__( \ + "1:\n\t" \ + "mov.l %R1,%2\n\t" \ + "mov.l %S1,%T2\n\t" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3:\n\t" \ + "mov.l 4f,%0\n\t" \ + "jmp @%0\n\t" \ + " mov %3,%0\n\t" \ + ".balign 4\n" \ + "4: .long 2b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n\t" \ + ".long 1b, 3b\n\t" \ + ".previous" \ + : "=r" (retval) \ + : "r" (val), "m" (__m(addr)), "i" (-EFAULT), "0" (retval) \ + : "memory"); }) +#else +#define __put_user_u64(val,addr,retval) \ +({ \ +__asm__ __volatile__( \ + "1:\n\t" \ + "mov.l %S1,%2\n\t" \ + "mov.l %R1,%T2\n\t" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3:\n\t" \ + "mov.l 4f,%0\n\t" \ + "jmp @%0\n\t" \ + " mov %3,%0\n\t" \ + ".balign 4\n" \ + "4: .long 2b\n\t" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n\t" \ + ".long 1b, 3b\n\t" \ + ".previous" \ + : "=r" (retval) \ + : "r" (val), "m" (__m(addr)), "i" (-EFAULT), "0" (retval) \ + : "memory"); }) +#endif + +extern void __put_user_unknown(void); + +#endif /* __ASM_SH_UACCESS_32_H */ diff --git a/arch/sh/include/asm/uaccess_64.h b/arch/sh/include/asm/uaccess_64.h new file mode 100644 index 000000000..c01376c76 --- /dev/null +++ b/arch/sh/include/asm/uaccess_64.h @@ -0,0 +1,87 @@ +#ifndef __ASM_SH_UACCESS_64_H +#define __ASM_SH_UACCESS_64_H + +/* + * include/asm-sh/uaccess_64.h + * + * Copyright (C) 2000, 2001 Paolo Alberelli + * Copyright (C) 2003, 2004 Paul Mundt + * + * User space memory access functions + * + * Copyright (C) 1999 Niibe Yutaka + * + * Based on: + * MIPS implementation version 1.15 by + * Copyright (C) 1996, 1997, 1998 by Ralf Baechle + * and i386 version. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#define __get_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: \ + retval = __get_user_asm_b((void *)&x, \ + (long)ptr); \ + break; \ + case 2: \ + retval = __get_user_asm_w((void *)&x, \ + (long)ptr); \ + break; \ + case 4: \ + retval = __get_user_asm_l((void *)&x, \ + (long)ptr); \ + break; \ + case 8: \ + retval = __get_user_asm_q((void *)&x, \ + (long)ptr); \ + break; \ + default: \ + __get_user_unknown(); \ + break; \ + } \ +} while (0) + +extern long __get_user_asm_b(void *, long); +extern long __get_user_asm_w(void *, long); +extern long __get_user_asm_l(void *, long); +extern long __get_user_asm_q(void *, long); +extern void __get_user_unknown(void); + +#define __put_user_size(x,ptr,size,retval) \ +do { \ + retval = 0; \ + switch (size) { \ + case 1: \ + retval = __put_user_asm_b((void *)&x, \ + (__force long)ptr); \ + break; \ + case 2: \ + retval = __put_user_asm_w((void *)&x, \ + (__force long)ptr); \ + break; \ + case 4: \ + retval = __put_user_asm_l((void *)&x, \ + (__force long)ptr); \ + break; \ + case 8: \ + retval = __put_user_asm_q((void *)&x, \ + (__force long)ptr); \ + break; \ + default: \ + __put_user_unknown(); \ + } \ +} while (0) + +extern long __put_user_asm_b(void *, long); +extern long __put_user_asm_w(void *, long); +extern long __put_user_asm_l(void *, long); +extern long __put_user_asm_q(void *, long); +extern void __put_user_unknown(void); + +#endif /* __ASM_SH_UACCESS_64_H */ diff --git a/arch/sh/include/asm/unaligned-sh4a.h b/arch/sh/include/asm/unaligned-sh4a.h new file mode 100644 index 000000000..95adc500c --- /dev/null +++ b/arch/sh/include/asm/unaligned-sh4a.h @@ -0,0 +1,198 @@ +#ifndef __ASM_SH_UNALIGNED_SH4A_H +#define __ASM_SH_UNALIGNED_SH4A_H + +/* + * SH-4A has support for unaligned 32-bit loads, and 32-bit loads only. + * Support for 64-bit accesses are done through shifting and masking + * relative to the endianness. Unaligned stores are not supported by the + * instruction encoding, so these continue to use the packed + * struct. + * + * The same note as with the movli.l/movco.l pair applies here, as long + * as the load is guaranteed to be inlined, nothing else will hook in to + * r0 and we get the return value for free. + * + * NOTE: Due to the fact we require r0 encoding, care should be taken to + * avoid mixing these heavily with other r0 consumers, such as the atomic + * ops. Failure to adhere to this can result in the compiler running out + * of spill registers and blowing up when building at low optimization + * levels. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34777. + */ +#include <linux/unaligned/packed_struct.h> +#include <linux/types.h> +#include <asm/byteorder.h> + +static inline u16 sh4a_get_unaligned_cpu16(const u8 *p) +{ +#ifdef __LITTLE_ENDIAN + return p[0] | p[1] << 8; +#else + return p[0] << 8 | p[1]; +#endif +} + +static __always_inline u32 sh4a_get_unaligned_cpu32(const u8 *p) +{ + unsigned long unaligned; + + __asm__ __volatile__ ( + "movua.l @%1, %0\n\t" + : "=z" (unaligned) + : "r" (p) + ); + + return unaligned; +} + +/* + * Even though movua.l supports auto-increment on the read side, it can + * only store to r0 due to instruction encoding constraints, so just let + * the compiler sort it out on its own. + */ +static inline u64 sh4a_get_unaligned_cpu64(const u8 *p) +{ +#ifdef __LITTLE_ENDIAN + return (u64)sh4a_get_unaligned_cpu32(p + 4) << 32 | + sh4a_get_unaligned_cpu32(p); +#else + return (u64)sh4a_get_unaligned_cpu32(p) << 32 | + sh4a_get_unaligned_cpu32(p + 4); +#endif +} + +static inline u16 get_unaligned_le16(const void *p) +{ + return le16_to_cpu(sh4a_get_unaligned_cpu16(p)); +} + +static inline u32 get_unaligned_le32(const void *p) +{ + return le32_to_cpu(sh4a_get_unaligned_cpu32(p)); +} + +static inline u64 get_unaligned_le64(const void *p) +{ + return le64_to_cpu(sh4a_get_unaligned_cpu64(p)); +} + +static inline u16 get_unaligned_be16(const void *p) +{ + return be16_to_cpu(sh4a_get_unaligned_cpu16(p)); +} + +static inline u32 get_unaligned_be32(const void *p) +{ + return be32_to_cpu(sh4a_get_unaligned_cpu32(p)); +} + +static inline u64 get_unaligned_be64(const void *p) +{ + return be64_to_cpu(sh4a_get_unaligned_cpu64(p)); +} + +static inline void nonnative_put_le16(u16 val, u8 *p) +{ + *p++ = val; + *p++ = val >> 8; +} + +static inline void nonnative_put_le32(u32 val, u8 *p) +{ + nonnative_put_le16(val, p); + nonnative_put_le16(val >> 16, p + 2); +} + +static inline void nonnative_put_le64(u64 val, u8 *p) +{ + nonnative_put_le32(val, p); + nonnative_put_le32(val >> 32, p + 4); +} + +static inline void nonnative_put_be16(u16 val, u8 *p) +{ + *p++ = val >> 8; + *p++ = val; +} + +static inline void nonnative_put_be32(u32 val, u8 *p) +{ + nonnative_put_be16(val >> 16, p); + nonnative_put_be16(val, p + 2); +} + +static inline void nonnative_put_be64(u64 val, u8 *p) +{ + nonnative_put_be32(val >> 32, p); + nonnative_put_be32(val, p + 4); +} + +static inline void put_unaligned_le16(u16 val, void *p) +{ +#ifdef __LITTLE_ENDIAN + __put_unaligned_cpu16(val, p); +#else + nonnative_put_le16(val, p); +#endif +} + +static inline void put_unaligned_le32(u32 val, void *p) +{ +#ifdef __LITTLE_ENDIAN + __put_unaligned_cpu32(val, p); +#else + nonnative_put_le32(val, p); +#endif +} + +static inline void put_unaligned_le64(u64 val, void *p) +{ +#ifdef __LITTLE_ENDIAN + __put_unaligned_cpu64(val, p); +#else + nonnative_put_le64(val, p); +#endif +} + +static inline void put_unaligned_be16(u16 val, void *p) +{ +#ifdef __BIG_ENDIAN + __put_unaligned_cpu16(val, p); +#else + nonnative_put_be16(val, p); +#endif +} + +static inline void put_unaligned_be32(u32 val, void *p) +{ +#ifdef __BIG_ENDIAN + __put_unaligned_cpu32(val, p); +#else + nonnative_put_be32(val, p); +#endif +} + +static inline void put_unaligned_be64(u64 val, void *p) +{ +#ifdef __BIG_ENDIAN + __put_unaligned_cpu64(val, p); +#else + nonnative_put_be64(val, p); +#endif +} + +/* + * While it's a bit non-obvious, even though the generic le/be wrappers + * use the __get/put_xxx prefixing, they actually wrap in to the + * non-prefixed get/put_xxx variants as provided above. + */ +#include <linux/unaligned/generic.h> + +#ifdef __LITTLE_ENDIAN +# define get_unaligned __get_unaligned_le +# define put_unaligned __put_unaligned_le +#else +# define get_unaligned __get_unaligned_be +# define put_unaligned __put_unaligned_be +#endif + +#endif /* __ASM_SH_UNALIGNED_SH4A_H */ diff --git a/arch/sh/include/asm/unaligned.h b/arch/sh/include/asm/unaligned.h new file mode 100644 index 000000000..7d14e0669 --- /dev/null +++ b/arch/sh/include/asm/unaligned.h @@ -0,0 +1,12 @@ +#ifndef _ASM_SH_UNALIGNED_H +#define _ASM_SH_UNALIGNED_H + +#ifdef CONFIG_CPU_SH4A +/* SH-4A can handle unaligned loads in a relatively neutered fashion. */ +#include <asm/unaligned-sh4a.h> +#else +/* Otherwise, SH can't handle unaligned accesses. */ +#include <asm-generic/unaligned.h> +#endif + +#endif /* _ASM_SH_UNALIGNED_H */ diff --git a/arch/sh/include/asm/uncached.h b/arch/sh/include/asm/uncached.h new file mode 100644 index 000000000..6f8816b79 --- /dev/null +++ b/arch/sh/include/asm/uncached.h @@ -0,0 +1,58 @@ +#ifndef __ASM_SH_UNCACHED_H +#define __ASM_SH_UNCACHED_H + +#include <linux/bug.h> + +#ifdef CONFIG_UNCACHED_MAPPING +extern unsigned long cached_to_uncached; +extern unsigned long uncached_size; +extern unsigned long uncached_start, uncached_end; + +extern int virt_addr_uncached(unsigned long kaddr); +extern void uncached_init(void); +extern void uncached_resize(unsigned long size); + +/* + * Jump to uncached area. + * When handling TLB or caches, we need to do it from an uncached area. + */ +#define jump_to_uncached() \ +do { \ + unsigned long __dummy; \ + \ + __asm__ __volatile__( \ + "mova 1f, %0\n\t" \ + "add %1, %0\n\t" \ + "jmp @%0\n\t" \ + " nop\n\t" \ + ".balign 4\n" \ + "1:" \ + : "=&z" (__dummy) \ + : "r" (cached_to_uncached)); \ +} while (0) + +/* + * Back to cached area. + */ +#define back_to_cached() \ +do { \ + unsigned long __dummy; \ + ctrl_barrier(); \ + __asm__ __volatile__( \ + "mov.l 1f, %0\n\t" \ + "jmp @%0\n\t" \ + " nop\n\t" \ + ".balign 4\n" \ + "1: .long 2f\n" \ + "2:" \ + : "=&r" (__dummy)); \ +} while (0) +#else +#define virt_addr_uncached(kaddr) (0) +#define uncached_init() do { } while (0) +#define uncached_resize(size) BUG() +#define jump_to_uncached() do { } while (0) +#define back_to_cached() do { } while (0) +#endif + +#endif /* __ASM_SH_UNCACHED_H */ diff --git a/arch/sh/include/asm/unistd.h b/arch/sh/include/asm/unistd.h new file mode 100644 index 000000000..126fe8340 --- /dev/null +++ b/arch/sh/include/asm/unistd.h @@ -0,0 +1,32 @@ +# ifdef CONFIG_SUPERH32 +# include <asm/unistd_32.h> +# else +# include <asm/unistd_64.h> +# endif + +# define __ARCH_WANT_OLD_READDIR +# define __ARCH_WANT_OLD_STAT +# define __ARCH_WANT_STAT64 +# define __ARCH_WANT_SYS_ALARM +# define __ARCH_WANT_SYS_GETHOSTNAME +# define __ARCH_WANT_SYS_IPC +# define __ARCH_WANT_SYS_PAUSE +# define __ARCH_WANT_SYS_SIGNAL +# define __ARCH_WANT_SYS_TIME +# define __ARCH_WANT_SYS_UTIME +# define __ARCH_WANT_SYS_WAITPID +# define __ARCH_WANT_SYS_SOCKETCALL +# define __ARCH_WANT_SYS_FADVISE64 +# define __ARCH_WANT_SYS_GETPGRP +# define __ARCH_WANT_SYS_LLSEEK +# define __ARCH_WANT_SYS_NICE +# define __ARCH_WANT_SYS_OLD_GETRLIMIT +# define __ARCH_WANT_SYS_OLD_UNAME +# define __ARCH_WANT_SYS_OLDUMOUNT +# define __ARCH_WANT_SYS_SIGPENDING +# define __ARCH_WANT_SYS_SIGPROCMASK +# define __ARCH_WANT_SYS_FORK +# define __ARCH_WANT_SYS_VFORK +# define __ARCH_WANT_SYS_CLONE + +#include <uapi/asm/unistd.h> diff --git a/arch/sh/include/asm/unwinder.h b/arch/sh/include/asm/unwinder.h new file mode 100644 index 000000000..1e65c07b3 --- /dev/null +++ b/arch/sh/include/asm/unwinder.h @@ -0,0 +1,31 @@ +#ifndef _LINUX_UNWINDER_H +#define _LINUX_UNWINDER_H + +#include <asm/stacktrace.h> + +struct unwinder { + const char *name; + struct list_head list; + int rating; + void (*dump)(struct task_struct *, struct pt_regs *, + unsigned long *, const struct stacktrace_ops *, void *); +}; + +extern int unwinder_init(void); +extern int unwinder_register(struct unwinder *); + +extern void unwind_stack(struct task_struct *, struct pt_regs *, + unsigned long *, const struct stacktrace_ops *, + void *); + +extern void stack_reader_dump(struct task_struct *, struct pt_regs *, + unsigned long *, const struct stacktrace_ops *, + void *); + +/* + * Used by fault handling code to signal to the unwinder code that it + * should switch to a different unwinder. + */ +extern int unwinder_faulted; + +#endif /* _LINUX_UNWINDER_H */ diff --git a/arch/sh/include/asm/user.h b/arch/sh/include/asm/user.h new file mode 100644 index 000000000..8fd3cf6c5 --- /dev/null +++ b/arch/sh/include/asm/user.h @@ -0,0 +1,67 @@ +#ifndef __ASM_SH_USER_H +#define __ASM_SH_USER_H + +#include <asm/ptrace.h> +#include <asm/page.h> + +/* + * Core file format: The core file is written in such a way that gdb + * can understand it and provide useful information to the user (under + * linux we use the `trad-core' bfd). The file contents are as follows: + * + * upage: 1 page consisting of a user struct that tells gdb + * what is present in the file. Directly after this is a + * copy of the task_struct, which is currently not used by gdb, + * but it may come in handy at some point. All of the registers + * are stored as part of the upage. The upage should always be + * only one page long. + * data: The data segment follows next. We use current->end_text to + * current->brk to pick up all of the user variables, plus any memory + * that may have been sbrk'ed. No attempt is made to determine if a + * page is demand-zero or if a page is totally unused, we just cover + * the entire range. All of the addresses are rounded in such a way + * that an integral number of pages is written. + * stack: We need the stack information in order to get a meaningful + * backtrace. We need to write the data from usp to + * current->start_stack, so we round each of these in order to be able + * to write an integer number of pages. + */ + +#if defined(__SH5__) || defined(CONFIG_CPU_SH5) +struct user_fpu_struct { + unsigned long fp_regs[32]; + unsigned int fpscr; +}; +#else +struct user_fpu_struct { + unsigned long fp_regs[16]; + unsigned long xfp_regs[16]; + unsigned long fpscr; + unsigned long fpul; +}; +#endif + +struct user { + struct pt_regs regs; /* entire machine state */ + struct user_fpu_struct fpu; /* Math Co-processor registers */ + int u_fpvalid; /* True if math co-processor being used */ + size_t u_tsize; /* text size (pages) */ + size_t u_dsize; /* data size (pages) */ + size_t u_ssize; /* stack size (pages) */ + unsigned long start_code; /* text starting address */ + unsigned long start_data; /* data starting address */ + unsigned long start_stack; /* stack starting address */ + long int signal; /* signal causing core dump */ + unsigned long u_ar0; /* help gdb find registers */ + struct user_fpu_struct* u_fpstate; /* Math Co-processor pointer */ + unsigned long magic; /* identifies a core file */ + char u_comm[32]; /* user command name */ +}; + +#define NBPG PAGE_SIZE +#define UPAGES 1 +#define HOST_TEXT_START_ADDR (u.start_code) +#define HOST_DATA_START_ADDR (u.start_data) +#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) + +#endif /* __ASM_SH_USER_H */ diff --git a/arch/sh/include/asm/vga.h b/arch/sh/include/asm/vga.h new file mode 100644 index 000000000..06a5de8ac --- /dev/null +++ b/arch/sh/include/asm/vga.h @@ -0,0 +1,6 @@ +#ifndef __ASM_SH_VGA_H +#define __ASM_SH_VGA_H + +/* Stupid drivers. */ + +#endif /* __ASM_SH_VGA_H */ diff --git a/arch/sh/include/asm/vmlinux.lds.h b/arch/sh/include/asm/vmlinux.lds.h new file mode 100644 index 000000000..d58ad493b --- /dev/null +++ b/arch/sh/include/asm/vmlinux.lds.h @@ -0,0 +1,25 @@ +#ifndef __ASM_SH_VMLINUX_LDS_H +#define __ASM_SH_VMLINUX_LDS_H + +#include <asm-generic/vmlinux.lds.h> + +#ifdef CONFIG_DWARF_UNWINDER +#define DWARF_EH_FRAME \ + .eh_frame : AT(ADDR(.eh_frame) - LOAD_OFFSET) { \ + VMLINUX_SYMBOL(__start_eh_frame) = .; \ + *(.eh_frame) \ + VMLINUX_SYMBOL(__stop_eh_frame) = .; \ + } +#else +#define DWARF_EH_FRAME +#endif + +#ifdef CONFIG_SUPERH64 +#define EXTRA_TEXT \ + *(.text64) \ + *(.text..SHmedia32) +#else +#define EXTRA_TEXT +#endif + +#endif /* __ASM_SH_VMLINUX_LDS_H */ diff --git a/arch/sh/include/asm/watchdog.h b/arch/sh/include/asm/watchdog.h new file mode 100644 index 000000000..85a7aca7f --- /dev/null +++ b/arch/sh/include/asm/watchdog.h @@ -0,0 +1,165 @@ +/* + * include/asm-sh/watchdog.h + * + * Copyright (C) 2002, 2003 Paul Mundt + * Copyright (C) 2009 Siemens AG + * Copyright (C) 2009 Valentin Sitdikov + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ +#ifndef __ASM_SH_WATCHDOG_H +#define __ASM_SH_WATCHDOG_H +#ifdef __KERNEL__ + +#include <linux/types.h> +#include <linux/io.h> + +#define WTCNT_HIGH 0x5a +#define WTCSR_HIGH 0xa5 + +#define WTCSR_CKS2 0x04 +#define WTCSR_CKS1 0x02 +#define WTCSR_CKS0 0x01 + +#include <cpu/watchdog.h> + +/* + * See cpu-sh2/watchdog.h for explanation of this stupidity.. + */ +#ifndef WTCNT_R +# define WTCNT_R WTCNT +#endif + +#ifndef WTCSR_R +# define WTCSR_R WTCSR +#endif + +/* + * CKS0-2 supports a number of clock division ratios. At the time the watchdog + * is enabled, it defaults to a 41 usec overflow period .. we overload this to + * something a little more reasonable, and really can't deal with anything + * lower than WTCSR_CKS_1024, else we drop back into the usec range. + * + * Clock Division Ratio Overflow Period + * -------------------------------------------- + * 1/32 (initial value) 41 usecs + * 1/64 82 usecs + * 1/128 164 usecs + * 1/256 328 usecs + * 1/512 656 usecs + * 1/1024 1.31 msecs + * 1/2048 2.62 msecs + * 1/4096 5.25 msecs + */ +#define WTCSR_CKS_32 0x00 +#define WTCSR_CKS_64 0x01 +#define WTCSR_CKS_128 0x02 +#define WTCSR_CKS_256 0x03 +#define WTCSR_CKS_512 0x04 +#define WTCSR_CKS_1024 0x05 +#define WTCSR_CKS_2048 0x06 +#define WTCSR_CKS_4096 0x07 + +#if defined(CONFIG_CPU_SUBTYPE_SH7785) || defined(CONFIG_CPU_SUBTYPE_SH7780) +/** + * sh_wdt_read_cnt - Read from Counter + * Reads back the WTCNT value. + */ +static inline __u32 sh_wdt_read_cnt(void) +{ + return __raw_readl(WTCNT_R); +} + +/** + * sh_wdt_write_cnt - Write to Counter + * @val: Value to write + * + * Writes the given value @val to the lower byte of the timer counter. + * The upper byte is set manually on each write. + */ +static inline void sh_wdt_write_cnt(__u32 val) +{ + __raw_writel((WTCNT_HIGH << 24) | (__u32)val, WTCNT); +} + +/** + * sh_wdt_write_bst - Write to Counter + * @val: Value to write + * + * Writes the given value @val to the lower byte of the timer counter. + * The upper byte is set manually on each write. + */ +static inline void sh_wdt_write_bst(__u32 val) +{ + __raw_writel((WTBST_HIGH << 24) | (__u32)val, WTBST); +} +/** + * sh_wdt_read_csr - Read from Control/Status Register + * + * Reads back the WTCSR value. + */ +static inline __u32 sh_wdt_read_csr(void) +{ + return __raw_readl(WTCSR_R); +} + +/** + * sh_wdt_write_csr - Write to Control/Status Register + * @val: Value to write + * + * Writes the given value @val to the lower byte of the control/status + * register. The upper byte is set manually on each write. + */ +static inline void sh_wdt_write_csr(__u32 val) +{ + __raw_writel((WTCSR_HIGH << 24) | (__u32)val, WTCSR); +} +#else +/** + * sh_wdt_read_cnt - Read from Counter + * Reads back the WTCNT value. + */ +static inline __u8 sh_wdt_read_cnt(void) +{ + return __raw_readb(WTCNT_R); +} + +/** + * sh_wdt_write_cnt - Write to Counter + * @val: Value to write + * + * Writes the given value @val to the lower byte of the timer counter. + * The upper byte is set manually on each write. + */ +static inline void sh_wdt_write_cnt(__u8 val) +{ + __raw_writew((WTCNT_HIGH << 8) | (__u16)val, WTCNT); +} + +/** + * sh_wdt_read_csr - Read from Control/Status Register + * + * Reads back the WTCSR value. + */ +static inline __u8 sh_wdt_read_csr(void) +{ + return __raw_readb(WTCSR_R); +} + +/** + * sh_wdt_write_csr - Write to Control/Status Register + * @val: Value to write + * + * Writes the given value @val to the lower byte of the control/status + * register. The upper byte is set manually on each write. + */ +static inline void sh_wdt_write_csr(__u8 val) +{ + __raw_writew((WTCSR_HIGH << 8) | (__u16)val, WTCSR); +} +#endif /* CONFIG_CPU_SUBTYPE_SH7785 || CONFIG_CPU_SUBTYPE_SH7780 */ +#endif /* __KERNEL__ */ +#endif /* __ASM_SH_WATCHDOG_H */ diff --git a/arch/sh/include/asm/word-at-a-time.h b/arch/sh/include/asm/word-at-a-time.h new file mode 100644 index 000000000..6e38953ff --- /dev/null +++ b/arch/sh/include/asm/word-at-a-time.h @@ -0,0 +1,53 @@ +#ifndef __ASM_SH_WORD_AT_A_TIME_H +#define __ASM_SH_WORD_AT_A_TIME_H + +#ifdef CONFIG_CPU_BIG_ENDIAN +# include <asm-generic/word-at-a-time.h> +#else +/* + * Little-endian version cribbed from x86. + */ +struct word_at_a_time { + const unsigned long one_bits, high_bits; +}; + +#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) } + +/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */ +static inline long count_masked_bytes(long mask) +{ + /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */ + long a = (0x0ff0001+mask) >> 23; + /* Fix the 1 for 00 case */ + return a & mask; +} + +/* Return nonzero if it has a zero */ +static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c) +{ + unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits; + *bits = mask; + return mask; +} + +static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c) +{ + return bits; +} + +static inline unsigned long create_zero_mask(unsigned long bits) +{ + bits = (bits - 1) & ~bits; + return bits >> 7; +} + +/* The mask we created is directly usable as a bytemask */ +#define zero_bytemask(mask) (mask) + +static inline unsigned long find_zero(unsigned long mask) +{ + return count_masked_bytes(mask); +} +#endif + +#endif |