From ea435467500612636f8f4fb639ff6e76b2496e4b Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 6 Jan 2009 14:40:39 -0800 Subject: atomic_t: unify all arch definitions The atomic_t type cannot currently be used in some header files because it would create an include loop with asm/atomic.h. Move the type definition to linux/types.h to break the loop. Signed-off-by: Matthew Wilcox Cc: Huang Ying Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/blackfin/include/asm/atomic.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'arch/blackfin/include/asm/atomic.h') diff --git a/arch/blackfin/include/asm/atomic.h b/arch/blackfin/include/asm/atomic.h index 7cf508718605..25776c19064b 100644 --- a/arch/blackfin/include/asm/atomic.h +++ b/arch/blackfin/include/asm/atomic.h @@ -1,6 +1,7 @@ #ifndef __ARCH_BLACKFIN_ATOMIC__ #define __ARCH_BLACKFIN_ATOMIC__ +#include #include /* local_irq_XXX() */ /* @@ -13,9 +14,6 @@ * Tony Kou (tonyko@lineo.ca) Lineo Inc. 2001 */ -typedef struct { - int counter; -} atomic_t; #define ATOMIC_INIT(i) { (i) } #define atomic_read(v) ((v)->counter) -- cgit v1.2.3 From 6b3087c64a92a36ae20d33479b4df6d7afc910d4 Mon Sep 17 00:00:00 2001 From: Graf Yang Date: Wed, 7 Jan 2009 23:14:39 +0800 Subject: Blackfin arch: SMP supporting patchset: Blackfin header files and machine common code Blackfin dual core BF561 processor can support SMP like features. https://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:smp-like In this patch, we provide SMP extend to Blackfin header files and machine common code Signed-off-by: Graf Yang Signed-off-by: Bryan Wu --- arch/blackfin/include/asm/atomic.h | 119 ++++++-- arch/blackfin/include/asm/bfin-global.h | 5 +- arch/blackfin/include/asm/bitops.h | 189 ++++++++---- arch/blackfin/include/asm/cache.h | 29 ++ arch/blackfin/include/asm/cacheflush.h | 20 +- arch/blackfin/include/asm/context.S | 6 +- arch/blackfin/include/asm/cpu.h | 42 +++ arch/blackfin/include/asm/l1layout.h | 3 +- arch/blackfin/include/asm/mutex-dec.h | 112 +++++++ arch/blackfin/include/asm/mutex.h | 63 ++++ arch/blackfin/include/asm/pda.h | 70 +++++ arch/blackfin/include/asm/percpu.h | 12 +- arch/blackfin/include/asm/processor.h | 7 +- arch/blackfin/include/asm/rwlock.h | 6 + arch/blackfin/include/asm/smp.h | 42 +++ arch/blackfin/include/asm/spinlock.h | 87 +++++- arch/blackfin/include/asm/spinlock_types.h | 22 ++ arch/blackfin/include/asm/system.h | 116 +++++-- arch/blackfin/mach-common/Makefile | 1 + arch/blackfin/mach-common/cache.S | 36 +++ arch/blackfin/mach-common/entry.S | 92 +++--- arch/blackfin/mach-common/head.S | 29 +- arch/blackfin/mach-common/ints-priority.c | 41 ++- arch/blackfin/mach-common/smp.c | 476 +++++++++++++++++++++++++++++ arch/blackfin/oprofile/common.c | 2 +- 25 files changed, 1435 insertions(+), 192 deletions(-) create mode 100644 arch/blackfin/include/asm/cpu.h create mode 100644 arch/blackfin/include/asm/mutex-dec.h create mode 100644 arch/blackfin/include/asm/pda.h create mode 100644 arch/blackfin/include/asm/rwlock.h create mode 100644 arch/blackfin/include/asm/smp.h create mode 100644 arch/blackfin/include/asm/spinlock_types.h create mode 100644 arch/blackfin/mach-common/smp.c (limited to 'arch/blackfin/include/asm/atomic.h') diff --git a/arch/blackfin/include/asm/atomic.h b/arch/blackfin/include/asm/atomic.h index 25776c19064b..d76275e5638c 100644 --- a/arch/blackfin/include/asm/atomic.h +++ b/arch/blackfin/include/asm/atomic.h @@ -15,11 +15,80 @@ */ #define ATOMIC_INIT(i) { (i) } - -#define atomic_read(v) ((v)->counter) #define atomic_set(v, i) (((v)->counter) = i) -static __inline__ void atomic_add(int i, atomic_t * v) +#ifdef CONFIG_SMP + +#define atomic_read(v) __raw_uncached_fetch_asm(&(v)->counter) + +asmlinkage int __raw_uncached_fetch_asm(const volatile int *ptr); + +asmlinkage int __raw_atomic_update_asm(volatile int *ptr, int value); + +asmlinkage int __raw_atomic_clear_asm(volatile int *ptr, int value); + +asmlinkage int __raw_atomic_set_asm(volatile int *ptr, int value); + +asmlinkage int __raw_atomic_xor_asm(volatile int *ptr, int value); + +asmlinkage int __raw_atomic_test_asm(const volatile int *ptr, int value); + +static inline void atomic_add(int i, atomic_t *v) +{ + __raw_atomic_update_asm(&v->counter, i); +} + +static inline void atomic_sub(int i, atomic_t *v) +{ + __raw_atomic_update_asm(&v->counter, -i); +} + +static inline int atomic_add_return(int i, atomic_t *v) +{ + return __raw_atomic_update_asm(&v->counter, i); +} + +static inline int atomic_sub_return(int i, atomic_t *v) +{ + return __raw_atomic_update_asm(&v->counter, -i); +} + +static inline void atomic_inc(volatile atomic_t *v) +{ + __raw_atomic_update_asm(&v->counter, 1); +} + +static inline void atomic_dec(volatile atomic_t *v) +{ + __raw_atomic_update_asm(&v->counter, -1); +} + +static inline void atomic_clear_mask(int mask, atomic_t *v) +{ + __raw_atomic_clear_asm(&v->counter, mask); +} + +static inline void atomic_set_mask(int mask, atomic_t *v) +{ + __raw_atomic_set_asm(&v->counter, mask); +} + +static inline int atomic_test_mask(int mask, atomic_t *v) +{ + return __raw_atomic_test_asm(&v->counter, mask); +} + +/* Atomic operations are already serializing */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + +#else /* !CONFIG_SMP */ + +#define atomic_read(v) ((v)->counter) + +static inline void atomic_add(int i, atomic_t *v) { long flags; @@ -28,7 +97,7 @@ static __inline__ void atomic_add(int i, atomic_t * v) local_irq_restore(flags); } -static __inline__ void atomic_sub(int i, atomic_t * v) +static inline void atomic_sub(int i, atomic_t *v) { long flags; @@ -38,7 +107,7 @@ static __inline__ void atomic_sub(int i, atomic_t * v) } -static inline int atomic_add_return(int i, atomic_t * v) +static inline int atomic_add_return(int i, atomic_t *v) { int __temp = 0; long flags; @@ -52,8 +121,7 @@ static inline int atomic_add_return(int i, atomic_t * v) return __temp; } -#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) -static inline int atomic_sub_return(int i, atomic_t * v) +static inline int atomic_sub_return(int i, atomic_t *v) { int __temp = 0; long flags; @@ -66,7 +134,7 @@ static inline int atomic_sub_return(int i, atomic_t * v) return __temp; } -static __inline__ void atomic_inc(volatile atomic_t * v) +static inline void atomic_inc(volatile atomic_t *v) { long flags; @@ -75,20 +143,7 @@ static __inline__ void atomic_inc(volatile atomic_t * v) local_irq_restore(flags); } -#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) -#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) - -#define atomic_add_unless(v, a, u) \ -({ \ - int c, old; \ - c = atomic_read(v); \ - while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \ - c = old; \ - c != (u); \ -}) -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) - -static __inline__ void atomic_dec(volatile atomic_t * v) +static inline void atomic_dec(volatile atomic_t *v) { long flags; @@ -97,7 +152,7 @@ static __inline__ void atomic_dec(volatile atomic_t * v) local_irq_restore(flags); } -static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t * v) +static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) { long flags; @@ -106,7 +161,7 @@ static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t * v) local_irq_restore(flags); } -static __inline__ void atomic_set_mask(unsigned int mask, atomic_t * v) +static inline void atomic_set_mask(unsigned int mask, atomic_t *v) { long flags; @@ -121,9 +176,25 @@ static __inline__ void atomic_set_mask(unsigned int mask, atomic_t * v) #define smp_mb__before_atomic_inc() barrier() #define smp_mb__after_atomic_inc() barrier() +#endif /* !CONFIG_SMP */ + +#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_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n))) +#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) + +#define atomic_add_unless(v, a, u) \ +({ \ + int c, old; \ + c = atomic_read(v); \ + while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \ + c = old; \ + c != (u); \ +}) +#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) + /* * atomic_inc_and_test - increment and test * @v: pointer of type atomic_t diff --git a/arch/blackfin/include/asm/bfin-global.h b/arch/blackfin/include/asm/bfin-global.h index 77295666c34b..1dd08058bc90 100644 --- a/arch/blackfin/include/asm/bfin-global.h +++ b/arch/blackfin/include/asm/bfin-global.h @@ -47,6 +47,9 @@ # define DMA_UNCACHED_REGION (0) #endif +extern void bfin_setup_caches(unsigned int cpu); +extern void bfin_setup_cpudata(unsigned int cpu); + extern unsigned long get_cclk(void); extern unsigned long get_sclk(void); extern unsigned long sclk_to_usecs(unsigned long sclk); @@ -58,8 +61,6 @@ extern void dump_bfin_trace_buffer(void); /* init functions only */ extern int init_arch_irq(void); -extern void bfin_icache_init(void); -extern void bfin_dcache_init(void); extern void init_exception_vectors(void); extern void program_IAR(void); diff --git a/arch/blackfin/include/asm/bitops.h b/arch/blackfin/include/asm/bitops.h index c428e4106f89..9964e17232e9 100644 --- a/arch/blackfin/include/asm/bitops.h +++ b/arch/blackfin/include/asm/bitops.h @@ -7,7 +7,6 @@ #include #include /* swab32 */ -#include /* save_flags */ #ifdef __KERNEL__ @@ -20,36 +19,71 @@ #include #include -static __inline__ void set_bit(int nr, volatile unsigned long *addr) +#ifdef CONFIG_SMP + +#include + +asmlinkage int __raw_bit_set_asm(volatile unsigned long *addr, int nr); + +asmlinkage int __raw_bit_clear_asm(volatile unsigned long *addr, int nr); + +asmlinkage int __raw_bit_toggle_asm(volatile unsigned long *addr, int nr); + +asmlinkage int __raw_bit_test_set_asm(volatile unsigned long *addr, int nr); + +asmlinkage int __raw_bit_test_clear_asm(volatile unsigned long *addr, int nr); + +asmlinkage int __raw_bit_test_toggle_asm(volatile unsigned long *addr, int nr); + +asmlinkage int __raw_bit_test_asm(const volatile unsigned long *addr, int nr); + +static inline void set_bit(int nr, volatile unsigned long *addr) { - int *a = (int *)addr; - int mask; - unsigned long flags; + volatile unsigned long *a = addr + (nr >> 5); + __raw_bit_set_asm(a, nr & 0x1f); +} - a += nr >> 5; - mask = 1 << (nr & 0x1f); - local_irq_save(flags); - *a |= mask; - local_irq_restore(flags); +static inline void clear_bit(int nr, volatile unsigned long *addr) +{ + volatile unsigned long *a = addr + (nr >> 5); + __raw_bit_clear_asm(a, nr & 0x1f); } -static __inline__ void __set_bit(int nr, volatile unsigned long *addr) +static inline void change_bit(int nr, volatile unsigned long *addr) { - int *a = (int *)addr; - int mask; + volatile unsigned long *a = addr + (nr >> 5); + __raw_bit_toggle_asm(a, nr & 0x1f); +} - a += nr >> 5; - mask = 1 << (nr & 0x1f); - *a |= mask; +static inline int test_bit(int nr, const volatile unsigned long *addr) +{ + volatile const unsigned long *a = addr + (nr >> 5); + return __raw_bit_test_asm(a, nr & 0x1f) != 0; } -/* - * clear_bit() doesn't provide any barrier for the compiler. - */ -#define smp_mb__before_clear_bit() barrier() -#define smp_mb__after_clear_bit() barrier() +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +{ + volatile unsigned long *a = addr + (nr >> 5); + return __raw_bit_test_set_asm(a, nr & 0x1f); +} -static __inline__ void clear_bit(int nr, volatile unsigned long *addr) +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +{ + volatile unsigned long *a = addr + (nr >> 5); + return __raw_bit_test_clear_asm(a, nr & 0x1f); +} + +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +{ + volatile unsigned long *a = addr + (nr >> 5); + return __raw_bit_test_toggle_asm(a, nr & 0x1f); +} + +#else /* !CONFIG_SMP */ + +#include /* save_flags */ + +static inline void set_bit(int nr, volatile unsigned long *addr) { int *a = (int *)addr; int mask; @@ -57,21 +91,23 @@ static __inline__ void clear_bit(int nr, volatile unsigned long *addr) a += nr >> 5; mask = 1 << (nr & 0x1f); local_irq_save(flags); - *a &= ~mask; + *a |= mask; local_irq_restore(flags); } -static __inline__ void __clear_bit(int nr, volatile unsigned long *addr) +static inline void clear_bit(int nr, volatile unsigned long *addr) { int *a = (int *)addr; int mask; - + unsigned long flags; a += nr >> 5; mask = 1 << (nr & 0x1f); + local_irq_save(flags); *a &= ~mask; + local_irq_restore(flags); } -static __inline__ void change_bit(int nr, volatile unsigned long *addr) +static inline void change_bit(int nr, volatile unsigned long *addr) { int mask, flags; unsigned long *ADDR = (unsigned long *)addr; @@ -83,17 +119,7 @@ static __inline__ void change_bit(int nr, volatile unsigned long *addr) local_irq_restore(flags); } -static __inline__ void __change_bit(int nr, volatile unsigned long *addr) -{ - int mask; - unsigned long *ADDR = (unsigned long *)addr; - - ADDR += nr >> 5; - mask = 1 << (nr & 31); - *ADDR ^= mask; -} - -static __inline__ int test_and_set_bit(int nr, void *addr) +static inline int test_and_set_bit(int nr, volatile unsigned long *addr) { int mask, retval; volatile unsigned int *a = (volatile unsigned int *)addr; @@ -109,19 +135,23 @@ static __inline__ int test_and_set_bit(int nr, void *addr) return retval; } -static __inline__ int __test_and_set_bit(int nr, volatile unsigned long *addr) +static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) { int mask, retval; volatile unsigned int *a = (volatile unsigned int *)addr; + unsigned long flags; a += nr >> 5; mask = 1 << (nr & 0x1f); + local_irq_save(flags); retval = (mask & *a) != 0; - *a |= mask; + *a &= ~mask; + local_irq_restore(flags); + return retval; } -static __inline__ int test_and_clear_bit(int nr, volatile unsigned long *addr) +static inline int test_and_change_bit(int nr, volatile unsigned long *addr) { int mask, retval; volatile unsigned int *a = (volatile unsigned int *)addr; @@ -131,13 +161,50 @@ static __inline__ int test_and_clear_bit(int nr, volatile unsigned long *addr) mask = 1 << (nr & 0x1f); local_irq_save(flags); retval = (mask & *a) != 0; - *a &= ~mask; + *a ^= mask; local_irq_restore(flags); - return retval; } -static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long *addr) +#endif /* CONFIG_SMP */ + +/* + * clear_bit() doesn't provide any barrier for the compiler. + */ +#define smp_mb__before_clear_bit() barrier() +#define smp_mb__after_clear_bit() barrier() + +static inline void __set_bit(int nr, volatile unsigned long *addr) +{ + int *a = (int *)addr; + int mask; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a |= mask; +} + +static inline void __clear_bit(int nr, volatile unsigned long *addr) +{ + int *a = (int *)addr; + int mask; + + a += nr >> 5; + mask = 1 << (nr & 0x1f); + *a &= ~mask; +} + +static inline void __change_bit(int nr, volatile unsigned long *addr) +{ + int mask; + unsigned long *ADDR = (unsigned long *)addr; + + ADDR += nr >> 5; + mask = 1 << (nr & 31); + *ADDR ^= mask; +} + +static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) { int mask, retval; volatile unsigned int *a = (volatile unsigned int *)addr; @@ -145,26 +212,23 @@ static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long *addr) a += nr >> 5; mask = 1 << (nr & 0x1f); retval = (mask & *a) != 0; - *a &= ~mask; + *a |= mask; return retval; } -static __inline__ int test_and_change_bit(int nr, volatile unsigned long *addr) +static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) { int mask, retval; volatile unsigned int *a = (volatile unsigned int *)addr; - unsigned long flags; a += nr >> 5; mask = 1 << (nr & 0x1f); - local_irq_save(flags); retval = (mask & *a) != 0; - *a ^= mask; - local_irq_restore(flags); + *a &= ~mask; return retval; } -static __inline__ int __test_and_change_bit(int nr, +static inline int __test_and_change_bit(int nr, volatile unsigned long *addr) { int mask, retval; @@ -177,16 +241,7 @@ static __inline__ int __test_and_change_bit(int nr, return retval; } -/* - * This routine doesn't need to be atomic. - */ -static __inline__ int __constant_test_bit(int nr, const void *addr) -{ - return ((1UL << (nr & 31)) & - (((const volatile unsigned int *)addr)[nr >> 5])) != 0; -} - -static __inline__ int __test_bit(int nr, const void *addr) +static inline int __test_bit(int nr, const void *addr) { int *a = (int *)addr; int mask; @@ -196,10 +251,16 @@ static __inline__ int __test_bit(int nr, const void *addr) return ((mask & *a) != 0); } -#define test_bit(nr,addr) \ -(__builtin_constant_p(nr) ? \ - __constant_test_bit((nr),(addr)) : \ - __test_bit((nr),(addr))) +#ifndef CONFIG_SMP +/* + * This routine doesn't need irq save and restore ops in UP + * context. + */ +static inline int test_bit(int nr, const void *addr) +{ + return __test_bit(nr, addr); +} +#endif #include #include diff --git a/arch/blackfin/include/asm/cache.h b/arch/blackfin/include/asm/cache.h index 023d72133b5a..86637814cf25 100644 --- a/arch/blackfin/include/asm/cache.h +++ b/arch/blackfin/include/asm/cache.h @@ -12,6 +12,11 @@ #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) #define SMP_CACHE_BYTES L1_CACHE_BYTES +#ifdef CONFIG_SMP +#define __cacheline_aligned +#else +#define ____cacheline_aligned + /* * Put cacheline_aliged data to L1 data memory */ @@ -21,9 +26,33 @@ __section__(".data_l1.cacheline_aligned"))) #endif +#endif + /* * largest L1 which this arch supports */ #define L1_CACHE_SHIFT_MAX 5 +#if defined(CONFIG_SMP) && \ + !defined(CONFIG_BFIN_CACHE_COHERENT) && \ + defined(CONFIG_BFIN_DCACHE) +#define __ARCH_SYNC_CORE_DCACHE +#ifndef __ASSEMBLY__ +asmlinkage void __raw_smp_mark_barrier_asm(void); +asmlinkage void __raw_smp_check_barrier_asm(void); + +static inline void smp_mark_barrier(void) +{ + __raw_smp_mark_barrier_asm(); +} +static inline void smp_check_barrier(void) +{ + __raw_smp_check_barrier_asm(); +} + +void resync_core_dcache(void); +#endif +#endif + + #endif diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h index 4403415583fa..1b040f5b4feb 100644 --- a/arch/blackfin/include/asm/cacheflush.h +++ b/arch/blackfin/include/asm/cacheflush.h @@ -35,6 +35,7 @@ extern void blackfin_icache_flush_range(unsigned long start_address, unsigned lo extern void blackfin_dcache_flush_range(unsigned long start_address, unsigned long end_address); extern void blackfin_dcache_invalidate_range(unsigned long start_address, unsigned long end_address); extern void blackfin_dflush_page(void *page); +extern void blackfin_invalidate_entire_dcache(void); #define flush_dcache_mmap_lock(mapping) do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) @@ -44,12 +45,20 @@ extern void blackfin_dflush_page(void *page); #define flush_cache_vmap(start, end) do { } while (0) #define flush_cache_vunmap(start, end) do { } while (0) +#ifdef CONFIG_SMP +#define flush_icache_range_others(start, end) \ + smp_icache_flush_range_others((start), (end)) +#else +#define flush_icache_range_others(start, end) do { } while (0) +#endif + static inline void flush_icache_range(unsigned start, unsigned end) { #if defined(CONFIG_BFIN_DCACHE) && defined(CONFIG_BFIN_ICACHE) # if defined(CONFIG_BFIN_WT) blackfin_icache_flush_range((start), (end)); + flush_icache_range_others(start, end); # else blackfin_icache_dcache_flush_range((start), (end)); # endif @@ -58,6 +67,7 @@ static inline void flush_icache_range(unsigned start, unsigned end) # if defined(CONFIG_BFIN_ICACHE) blackfin_icache_flush_range((start), (end)); + flush_icache_range_others(start, end); # endif # if defined(CONFIG_BFIN_DCACHE) blackfin_dcache_flush_range((start), (end)); @@ -66,10 +76,12 @@ static inline void flush_icache_range(unsigned start, unsigned end) #endif } -#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ -do { memcpy(dst, src, len); \ - flush_icache_range ((unsigned) (dst), (unsigned) (dst) + (len)); \ +#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ +do { memcpy(dst, src, len); \ + flush_icache_range((unsigned) (dst), (unsigned) (dst) + (len)); \ + flush_icache_range_others((unsigned long) (dst), (unsigned long) (dst) + (len));\ } while (0) + #define copy_from_user_page(vma, page, vaddr, dst, src, len) memcpy(dst, src, len) #if defined(CONFIG_BFIN_DCACHE) @@ -82,7 +94,7 @@ do { memcpy(dst, src, len); \ # define flush_dcache_page(page) blackfin_dflush_page(page_address(page)) #else # define flush_dcache_range(start,end) do { } while (0) -# define flush_dcache_page(page) do { } while (0) +# define flush_dcache_page(page) do { } while (0) #endif extern unsigned long reserved_mem_dcache_on; diff --git a/arch/blackfin/include/asm/context.S b/arch/blackfin/include/asm/context.S index c0e630edfb9a..40d20b4a9b1f 100644 --- a/arch/blackfin/include/asm/context.S +++ b/arch/blackfin/include/asm/context.S @@ -303,9 +303,14 @@ RETI = [sp++]; RETS = [sp++]; +#ifdef CONFIG_SMP + GET_PDA(p0, r0); + r0 = [p0 + PDA_IRQFLAGS]; +#else p0.h = _irq_flags; p0.l = _irq_flags; r0 = [p0]; +#endif sti r0; sp += 4; /* Skip Reserved */ @@ -352,4 +357,3 @@ SYSCFG = [sp++]; csync; .endm - diff --git a/arch/blackfin/include/asm/cpu.h b/arch/blackfin/include/asm/cpu.h new file mode 100644 index 000000000000..9b7aefe7eb2d --- /dev/null +++ b/arch/blackfin/include/asm/cpu.h @@ -0,0 +1,42 @@ +/* + * File: arch/blackfin/include/asm/cpu.h. + * Author: Philippe Gerum + * + * Copyright 2007 Analog Devices Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __ASM_BLACKFIN_CPU_H +#define __ASM_BLACKFIN_CPU_H + +#include + +struct task_struct; + +struct blackfin_cpudata { + struct cpu cpu; + struct task_struct *idle; + unsigned long cclk; + unsigned int imemctl; + unsigned int dmemctl; + unsigned long loops_per_jiffy; + unsigned long dcache_invld_count; +}; + +DECLARE_PER_CPU(struct blackfin_cpudata, cpu_data); + +#endif diff --git a/arch/blackfin/include/asm/l1layout.h b/arch/blackfin/include/asm/l1layout.h index c13ded777828..06bb37f6c788 100644 --- a/arch/blackfin/include/asm/l1layout.h +++ b/arch/blackfin/include/asm/l1layout.h @@ -24,7 +24,8 @@ struct l1_scratch_task_info }; /* A pointer to the structure in memory. */ -#define L1_SCRATCH_TASK_INFO ((struct l1_scratch_task_info *)L1_SCRATCH_START) +#define L1_SCRATCH_TASK_INFO ((struct l1_scratch_task_info *)\ + get_l1_scratch_start()) #endif diff --git a/arch/blackfin/include/asm/mutex-dec.h b/arch/blackfin/include/asm/mutex-dec.h new file mode 100644 index 000000000000..0134151656af --- /dev/null +++ b/arch/blackfin/include/asm/mutex-dec.h @@ -0,0 +1,112 @@ +/* + * include/asm-generic/mutex-dec.h + * + * Generic implementation of the mutex fastpath, based on atomic + * decrement/increment. + */ +#ifndef _ASM_GENERIC_MUTEX_DEC_H +#define _ASM_GENERIC_MUTEX_DEC_H + +/** + * __mutex_fastpath_lock - try to take the lock by moving the count + * from 1 to a 0 value + * @count: pointer of type atomic_t + * @fail_fn: function to call if the original value was not 1 + * + * Change the count from 1 to a value lower than 1, and call if + * it wasn't 1 originally. This function MUST leave the value lower than + * 1 even when the "1" assertion wasn't true. + */ +static inline void +__mutex_fastpath_lock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *)) +{ + if (unlikely(atomic_dec_return(count) < 0)) + fail_fn(count); + else + smp_mb(); +} + +/** + * __mutex_fastpath_lock_retval - try to take the lock by moving the count + * from 1 to a 0 value + * @count: pointer of type atomic_t + * @fail_fn: function to call if the original value was not 1 + * + * Change the count from 1 to a value lower than 1, and call if + * it wasn't 1 originally. This function returns 0 if the fastpath succeeds, + * or anything the slow path function returns. + */ +static inline int +__mutex_fastpath_lock_retval(atomic_t *count, fastcall int (*fail_fn)(atomic_t *)) +{ + if (unlikely(atomic_dec_return(count) < 0)) + return fail_fn(count); + else { + smp_mb(); + return 0; + } +} + +/** + * __mutex_fastpath_unlock - try to promote the count from 0 to 1 + * @count: pointer of type atomic_t + * @fail_fn: function to call if the original value was not 0 + * + * Try to promote the count from 0 to 1. If it wasn't 0, call . + * In the failure case, this function is allowed to either set the value to + * 1, or to set it to a value lower than 1. + * + * If the implementation sets it to a value of lower than 1, then the + * __mutex_slowpath_needs_to_unlock() macro needs to return 1, it needs + * to return 0 otherwise. + */ +static inline void +__mutex_fastpath_unlock(atomic_t *count, fastcall void (*fail_fn)(atomic_t *)) +{ + smp_mb(); + if (unlikely(atomic_inc_return(count) <= 0)) + fail_fn(count); +} + +#define __mutex_slowpath_needs_to_unlock() 1 + +/** + * __mutex_fastpath_trylock - try to acquire the mutex, without waiting + * + * @count: pointer of type atomic_t + * @fail_fn: fallback function + * + * Change the count from 1 to a value lower than 1, and return 0 (failure) + * if it wasn't 1 originally, or return 1 (success) otherwise. This function + * MUST leave the value lower than 1 even when the "1" assertion wasn't true. + * Additionally, if the value was < 0 originally, this function must not leave + * it to 0 on failure. + * + * If the architecture has no effective trylock variant, it should call the + * spinlock-based trylock variant unconditionally. + */ +static inline int +__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) +{ + /* + * We have two variants here. The cmpxchg based one is the best one + * because it never induce a false contention state. It is included + * here because architectures using the inc/dec algorithms over the + * xchg ones are much more likely to support cmpxchg natively. + * + * If not we fall back to the spinlock based variant - that is + * just as efficient (and simpler) as a 'destructive' probing of + * the mutex state would be. + */ +#ifdef __HAVE_ARCH_CMPXCHG + if (likely(atomic_cmpxchg(count, 1, 0) == 1)) { + smp_mb(); + return 1; + } + return 0; +#else + return fail_fn(count); +#endif +} + +#endif diff --git a/arch/blackfin/include/asm/mutex.h b/arch/blackfin/include/asm/mutex.h index 458c1f7fbc18..5d399256bf06 100644 --- a/arch/blackfin/include/asm/mutex.h +++ b/arch/blackfin/include/asm/mutex.h @@ -6,4 +6,67 @@ * implementation. (see asm-generic/mutex-xchg.h for details) */ +#ifndef _ASM_MUTEX_H +#define _ASM_MUTEX_H + +#ifndef CONFIG_SMP #include +#else + +static inline void +__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *)) +{ + if (unlikely(atomic_dec_return(count) < 0)) + fail_fn(count); + else + smp_mb(); +} + +static inline int +__mutex_fastpath_lock_retval(atomic_t *count, int (*fail_fn)(atomic_t *)) +{ + if (unlikely(atomic_dec_return(count) < 0)) + return fail_fn(count); + else { + smp_mb(); + return 0; + } +} + +static inline void +__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) +{ + smp_mb(); + if (unlikely(atomic_inc_return(count) <= 0)) + fail_fn(count); +} + +#define __mutex_slowpath_needs_to_unlock() 1 + +static inline int +__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) +{ + /* + * We have two variants here. The cmpxchg based one is the best one + * because it never induce a false contention state. It is included + * here because architectures using the inc/dec algorithms over the + * xchg ones are much more likely to support cmpxchg natively. + * + * If not we fall back to the spinlock based variant - that is + * just as efficient (and simpler) as a 'destructive' probing of + * the mutex state would be. + */ +#ifdef __HAVE_ARCH_CMPXCHG + if (likely(atomic_cmpxchg(count, 1, 0) == 1)) { + smp_mb(); + return 1; + } + return 0; +#else + return fail_fn(count); +#endif +} + +#endif + +#endif diff --git a/arch/blackfin/include/asm/pda.h b/arch/blackfin/include/asm/pda.h new file mode 100644 index 000000000000..a24d130c30f0 --- /dev/null +++ b/arch/blackfin/include/asm/pda.h @@ -0,0 +1,70 @@ +/* + * File: arch/blackfin/include/asm/pda.h + * Author: Philippe Gerum + * + * Copyright 2007 Analog Devices Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ASM_BLACKFIN_PDA_H +#define _ASM_BLACKFIN_PDA_H + +#include + +#ifndef __ASSEMBLY__ + +struct blackfin_pda { /* Per-processor Data Area */ + struct blackfin_pda *next; + + unsigned long syscfg; +#ifdef CONFIG_SMP + unsigned long imask; /* Current IMASK value */ +#endif + + unsigned long *ipdt; /* Start of switchable I-CPLB table */ + unsigned long *ipdt_swapcount; /* Number of swaps in ipdt */ + unsigned long *dpdt; /* Start of switchable D-CPLB table */ + unsigned long *dpdt_swapcount; /* Number of swaps in dpdt */ + + /* + * Single instructions can have multiple faults, which + * need to be handled by traps.c, in irq5. We store + * the exception cause to ensure we don't miss a + * double fault condition + */ + unsigned long ex_iptr; + unsigned long ex_optr; + unsigned long ex_buf[4]; + unsigned long ex_imask; /* Saved imask from exception */ + unsigned long *ex_stack; /* Exception stack space */ + +#ifdef ANOMALY_05000261 + unsigned long last_cplb_fault_retx; +#endif + unsigned long dcplb_fault_addr; + unsigned long icplb_fault_addr; + unsigned long retx; + unsigned long seqstat; +}; + +extern struct blackfin_pda cpu_pda[]; + +void reserve_pda(void); + +#endif /* __ASSEMBLY__ */ + +#endif /* _ASM_BLACKFIN_PDA_H */ diff --git a/arch/blackfin/include/asm/percpu.h b/arch/blackfin/include/asm/percpu.h index 78dd61f6b39f..797c0c165069 100644 --- a/arch/blackfin/include/asm/percpu.h +++ b/arch/blackfin/include/asm/percpu.h @@ -3,4 +3,14 @@ #include -#endif /* __ARCH_BLACKFIN_PERCPU__ */ +#ifdef CONFIG_MODULES +#define PERCPU_MODULE_RESERVE 8192 +#else +#define PERCPU_MODULE_RESERVE 0 +#endif + +#define PERCPU_ENOUGH_ROOM \ + (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) + \ + PERCPU_MODULE_RESERVE) + +#endif /* __ARCH_BLACKFIN_PERCPU__ */ diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h index e3e9b41fa8db..30703c75030c 100644 --- a/arch/blackfin/include/asm/processor.h +++ b/arch/blackfin/include/asm/processor.h @@ -106,7 +106,8 @@ unsigned long get_wchan(struct task_struct *p); eip; }) #define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->thread.usp) -#define cpu_relax() barrier() +#define cpu_relax() smp_mb() + /* Get the Silicon Revision of the chip */ static inline uint32_t __pure bfin_revid(void) @@ -137,7 +138,11 @@ static inline uint32_t __pure bfin_revid(void) static inline uint16_t __pure bfin_cpuid(void) { return (bfin_read_CHIPID() & CHIPID_FAMILY) >> 12; +} +static inline uint32_t __pure bfin_dspid(void) +{ + return bfin_read_DSPID(); } static inline uint32_t __pure bfin_compiled_revid(void) diff --git a/arch/blackfin/include/asm/rwlock.h b/arch/blackfin/include/asm/rwlock.h new file mode 100644 index 000000000000..4a724b378971 --- /dev/null +++ b/arch/blackfin/include/asm/rwlock.h @@ -0,0 +1,6 @@ +#ifndef _ASM_BLACKFIN_RWLOCK_H +#define _ASM_BLACKFIN_RWLOCK_H + +#define RW_LOCK_BIAS 0x01000000 + +#endif diff --git a/arch/blackfin/include/asm/smp.h b/arch/blackfin/include/asm/smp.h new file mode 100644 index 000000000000..233cb8c3cfb7 --- /dev/null +++ b/arch/blackfin/include/asm/smp.h @@ -0,0 +1,42 @@ +/* + * File: arch/blackfin/include/asm/smp.h + * Author: Philippe Gerum + * + * Copyright 2007 Analog Devices Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __ASM_BLACKFIN_SMP_H +#define __ASM_BLACKFIN_SMP_H + +#include +#include +#include +#include +#include +#include + +#define raw_smp_processor_id() blackfin_core_id() + +struct corelock_slot { + int lock; +}; + +void smp_icache_flush_range_others(unsigned long start, + unsigned long end); + +#endif /* !__ASM_BLACKFIN_SMP_H */ diff --git a/arch/blackfin/include/asm/spinlock.h b/arch/blackfin/include/asm/spinlock.h index 64e908a50646..0249ac319476 100644 --- a/arch/blackfin/include/asm/spinlock.h +++ b/arch/blackfin/include/asm/spinlock.h @@ -1,6 +1,89 @@ #ifndef __BFIN_SPINLOCK_H #define __BFIN_SPINLOCK_H -#error blackfin architecture does not support SMP spin lock yet +#include -#endif +asmlinkage int __raw_spin_is_locked_asm(volatile int *ptr); +asmlinkage void __raw_spin_lock_asm(volatile int *ptr); +asmlinkage int __raw_spin_trylock_asm(volatile int *ptr); +asmlinkage void __raw_spin_unlock_asm(volatile int *ptr); +asmlinkage void __raw_read_lock_asm(volatile int *ptr); +asmlinkage int __raw_read_trylock_asm(volatile int *ptr); +asmlinkage void __raw_read_unlock_asm(volatile int *ptr); +asmlinkage void __raw_write_lock_asm(volatile int *ptr); +asmlinkage int __raw_write_trylock_asm(volatile int *ptr); +asmlinkage void __raw_write_unlock_asm(volatile int *ptr); + +static inline int __raw_spin_is_locked(raw_spinlock_t *lock) +{ + return __raw_spin_is_locked_asm(&lock->lock); +} + +static inline void __raw_spin_lock(raw_spinlock_t *lock) +{ + __raw_spin_lock_asm(&lock->lock); +} + +#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) + +static inline int __raw_spin_trylock(raw_spinlock_t *lock) +{ + return __raw_spin_trylock_asm(&lock->lock); +} + +static inline void __raw_spin_unlock(raw_spinlock_t *lock) +{ + __raw_spin_unlock_asm(&lock->lock); +} + +static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock) +{ + while (__raw_spin_is_locked(lock)) + cpu_relax(); +} + +static inline int __raw_read_can_lock(raw_rwlock_t *rw) +{ + return __raw_uncached_fetch_asm(&rw->lock) > 0; +} + +static inline int __raw_write_can_lock(raw_rwlock_t *rw) +{ + return __raw_uncached_fetch_asm(&rw->lock) == RW_LOCK_BIAS; +} + +static inline void __raw_read_lock(raw_rwlock_t *rw) +{ + __raw_read_lock_asm(&rw->lock); +} + +static inline int __raw_read_trylock(raw_rwlock_t *rw) +{ + return __raw_read_trylock_asm(&rw->lock); +} + +static inline void __raw_read_unlock(raw_rwlock_t *rw) +{ + __raw_read_unlock_asm(&rw->lock); +} + +static inline void __raw_write_lock(raw_rwlock_t *rw) +{ + __raw_write_lock_asm(&rw->lock); +} + +static inline int __raw_write_trylock(raw_rwlock_t *rw) +{ + return __raw_write_trylock_asm(&rw->lock); +} + +static inline void __raw_write_unlock(raw_rwlock_t *rw) +{ + __raw_write_unlock_asm(&rw->lock); +} + +#define _raw_spin_relax(lock) cpu_relax() +#define _raw_read_relax(lock) cpu_relax() +#define _raw_write_relax(lock) cpu_relax() + +#endif /* !__BFIN_SPINLOCK_H */ diff --git a/arch/blackfin/include/asm/spinlock_types.h b/arch/blackfin/include/asm/spinlock_types.h new file mode 100644 index 000000000000..b1e3c4c7b382 --- /dev/null +++ b/arch/blackfin/include/asm/spinlock_types.h @@ -0,0 +1,22 @@ +#ifndef __ASM_SPINLOCK_TYPES_H +#define __ASM_SPINLOCK_TYPES_H + +#ifndef __LINUX_SPINLOCK_TYPES_H +# error "please don't include this file directly" +#endif + +#include + +typedef struct { + volatile unsigned int lock; +} raw_spinlock_t; + +#define __RAW_SPIN_LOCK_UNLOCKED { 0 } + +typedef struct { + volatile unsigned int lock; +} raw_rwlock_t; + +#define __RAW_RW_LOCK_UNLOCKED { RW_LOCK_BIAS } + +#endif diff --git a/arch/blackfin/include/asm/system.h b/arch/blackfin/include/asm/system.h index 8f1627d8bf09..6b368faf30c3 100644 --- a/arch/blackfin/include/asm/system.h +++ b/arch/blackfin/include/asm/system.h @@ -37,20 +37,16 @@ #include #include #include +#include +#include + +/* Forward decl needed due to cdef inter dependencies */ +static inline uint32_t __pure bfin_dspid(void); +#define blackfin_core_id() (bfin_dspid() & 0xff) /* * Interrupt configuring macros. */ - -extern unsigned long irq_flags; - -#define local_irq_enable() \ - __asm__ __volatile__( \ - "sti %0;" \ - : \ - : "d" (irq_flags) \ - ) - #define local_irq_disable() \ do { \ int __tmp_dummy; \ @@ -66,6 +62,18 @@ extern unsigned long irq_flags; # define NOP_PAD_ANOMALY_05000244 #endif +#ifdef CONFIG_SMP +# define irq_flags cpu_pda[blackfin_core_id()].imask +#else +extern unsigned long irq_flags; +#endif + +#define local_irq_enable() \ + __asm__ __volatile__( \ + "sti %0;" \ + : \ + : "d" (irq_flags) \ + ) #define idle_with_irq_disabled() \ __asm__ __volatile__( \ NOP_PAD_ANOMALY_05000244 \ @@ -129,22 +137,85 @@ extern unsigned long irq_flags; #define rmb() asm volatile ("" : : :"memory") #define wmb() asm volatile ("" : : :"memory") #define set_mb(var, value) do { (void) xchg(&var, value); } while (0) - #define read_barrier_depends() do { } while(0) #ifdef CONFIG_SMP -#define smp_mb() mb() -#define smp_rmb() rmb() -#define smp_wmb() wmb() -#define smp_read_barrier_depends() read_barrier_depends() +asmlinkage unsigned long __raw_xchg_1_asm(volatile void *ptr, unsigned long value); +asmlinkage unsigned long __raw_xchg_2_asm(volatile void *ptr, unsigned long value); +asmlinkage unsigned long __raw_xchg_4_asm(volatile void *ptr, unsigned long value); +asmlinkage unsigned long __raw_cmpxchg_1_asm(volatile void *ptr, + unsigned long new, unsigned long old); +asmlinkage unsigned long __raw_cmpxchg_2_asm(volatile void *ptr, + unsigned long new, unsigned long old); +asmlinkage unsigned long __raw_cmpxchg_4_asm(volatile void *ptr, + unsigned long new, unsigned long old); + +#ifdef __ARCH_SYNC_CORE_DCACHE +# define smp_mb() do { barrier(); smp_check_barrier(); smp_mark_barrier(); } while (0) +# define smp_rmb() do { barrier(); smp_check_barrier(); } while (0) +# define smp_wmb() do { barrier(); smp_mark_barrier(); } while (0) #else +# define smp_mb() barrier() +# define smp_rmb() barrier() +# define smp_wmb() barrier() +#endif + +static inline unsigned long __xchg(unsigned long x, volatile void *ptr, + int size) +{ + unsigned long tmp; + + switch (size) { + case 1: + tmp = __raw_xchg_1_asm(ptr, x); + break; + case 2: + tmp = __raw_xchg_2_asm(ptr, x); + break; + case 4: + tmp = __raw_xchg_4_asm(ptr, x); + break; + } + + return tmp; +} + +/* + * Atomic compare and exchange. Compare OLD with MEM, if identical, + * store NEW in MEM. Return the initial value in MEM. Success is + * indicated by comparing RETURN with OLD. + */ +static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, + unsigned long new, int size) +{ + unsigned long tmp; + + switch (size) { + case 1: + tmp = __raw_cmpxchg_1_asm(ptr, new, old); + break; + case 2: + tmp = __raw_cmpxchg_2_asm(ptr, new, old); + break; + case 4: + tmp = __raw_cmpxchg_4_asm(ptr, new, old); + break; + } + + return tmp; +} +#define cmpxchg(ptr, o, n) \ + ((__typeof__(*(ptr)))__cmpxchg((ptr), (unsigned long)(o), \ + (unsigned long)(n), sizeof(*(ptr)))) + +#define smp_read_barrier_depends() smp_check_barrier() + +#else /* !CONFIG_SMP */ + #define smp_mb() barrier() #define smp_rmb() barrier() #define smp_wmb() barrier() #define smp_read_barrier_depends() do { } while(0) -#endif - -#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) struct __xchg_dummy { unsigned long a[100]; @@ -194,9 +265,12 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, (unsigned long)(n), sizeof(*(ptr)))) #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) -#ifndef CONFIG_SMP #include -#endif + +#endif /* !CONFIG_SMP */ + +#define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) +#define tas(ptr) ((void)xchg((ptr), 1)) #define prepare_to_switch() do { } while(0) @@ -218,4 +292,4 @@ do { \ (last) = resume (prev, next); \ } while (0) -#endif /* _BLACKFIN_SYSTEM_H */ +#endif /* _BLACKFIN_SYSTEM_H */ diff --git a/arch/blackfin/mach-common/Makefile b/arch/blackfin/mach-common/Makefile index e6ed57c56d4b..9388b4ab7349 100644 --- a/arch/blackfin/mach-common/Makefile +++ b/arch/blackfin/mach-common/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_BFIN_ICACHE_LOCK) += lock.o obj-$(CONFIG_PM) += pm.o dpmc_modes.o obj-$(CONFIG_CPU_FREQ) += cpufreq.o obj-$(CONFIG_CPU_VOLTAGE) += dpmc.o +obj-$(CONFIG_SMP) += smp.o diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S index 3c98dacbf289..118751287437 100644 --- a/arch/blackfin/mach-common/cache.S +++ b/arch/blackfin/mach-common/cache.S @@ -97,3 +97,39 @@ ENTRY(_blackfin_dflush_page) P1 = 1 << (PAGE_SHIFT - L1_CACHE_SHIFT); jump .Ldfr; ENDPROC(_blackfin_dflush_page) + +/* Invalidate the Entire Data cache by + * clearing DMC[1:0] bits + */ +ENTRY(_blackfin_invalidate_entire_dcache) + [--SP] = ( R7:5); + + P0.L = LO(DMEM_CONTROL); + P0.H = HI(DMEM_CONTROL); + R7 = [P0]; + R5 = R7; /* Save DMEM_CNTR */ + + /* Clear the DMC[1:0] bits, All valid bits in the data + * cache are set to the invalid state + */ + BITCLR(R7,DMC0_P); + BITCLR(R7,DMC1_P); + CLI R6; + SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ + .align 8; + [P0] = R7; + SSYNC; + STI R6; + + /* Configures the data cache again */ + + CLI R6; + SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */ + .align 8; + [P0] = R5; + SSYNC; + STI R6; + + ( R7:5) = [SP++]; + RTS; +ENDPROC(_blackfin_invalidate_entire_dcache) diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index c6ae8442fc4e..5531f49c84e6 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -75,11 +76,11 @@ ENTRY(_ex_workaround_261) * handle it. */ P4 = R7; /* Store EXCAUSE */ - p5.l = _last_cplb_fault_retx; - p5.h = _last_cplb_fault_retx; - r7 = [p5]; + + GET_PDA(p5, r7); + r7 = [p5 + PDA_LFRETX]; r6 = retx; - [p5] = r6; + [p5 + PDA_LFRETX] = r6; cc = r6 == r7; if !cc jump _bfin_return_from_exception; /* fall through */ @@ -324,7 +325,9 @@ ENTRY(_ex_trap_c) [p4] = p5; csync; + GET_PDA(p5, r6); #ifndef CONFIG_DEBUG_DOUBLEFAULT + /* * Save these registers, as they are only valid in exception context * (where we are now - as soon as we defer to IRQ5, they can change) @@ -335,29 +338,25 @@ ENTRY(_ex_trap_c) p4.l = lo(DCPLB_FAULT_ADDR); p4.h = hi(DCPLB_FAULT_ADDR); r7 = [p4]; - p5.h = _saved_dcplb_fault_addr; - p5.l = _saved_dcplb_fault_addr; - [p5] = r7; + [p5 + PDA_DCPLB] = r7; - r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)]; - p5.h = _saved_icplb_fault_addr; - p5.l = _saved_icplb_fault_addr; - [p5] = r7; + p4.l = lo(ICPLB_FAULT_ADDR); + p4.h = hi(ICPLB_FAULT_ADDR); + r6 = [p4]; + [p5 + PDA_ICPLB] = r6; r6 = retx; - p4.l = _saved_retx; - p4.h = _saved_retx; - [p4] = r6; + [p5 + PDA_RETX] = r6; #endif r6 = SYSCFG; - [p4 + 4] = r6; + [p5 + PDA_SYSCFG] = r6; BITCLR(r6, 0); SYSCFG = r6; /* Disable all interrupts, but make sure level 5 is enabled so * we can switch to that level. Save the old mask. */ cli r6; - [p4 + 8] = r6; + [p5 + PDA_EXIMASK] = r6; p4.l = lo(SAFE_USER_INSTRUCTION); p4.h = hi(SAFE_USER_INSTRUCTION); @@ -424,17 +423,16 @@ ENDPROC(_double_fault) ENTRY(_exception_to_level5) SAVE_ALL_SYS - p4.l = _saved_retx; - p4.h = _saved_retx; - r6 = [p4]; + GET_PDA(p4, r7); /* Fetch current PDA */ + r6 = [p4 + PDA_RETX]; [sp + PT_PC] = r6; - r6 = [p4 + 4]; + r6 = [p4 + PDA_SYSCFG]; [sp + PT_SYSCFG] = r6; /* Restore interrupt mask. We haven't pushed RETI, so this * doesn't enable interrupts until we return from this handler. */ - r6 = [p4 + 8]; + r6 = [p4 + PDA_EXIMASK]; sti r6; /* Restore the hardware error vector. */ @@ -478,8 +476,8 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/ * scratch register (for want of a better option). */ EX_SCRATCH_REG = sp; - sp.l = _exception_stack_top; - sp.h = _exception_stack_top; + GET_PDA_SAFE(sp); + sp = [sp + PDA_EXSTACK] /* Try to deal with syscalls quickly. */ [--sp] = ASTAT; [--sp] = (R7:6,P5:4); @@ -501,27 +499,22 @@ ENTRY(_trap) /* Exception: 4th entry into system event table(supervisor mode)*/ * but they are not very interesting, so don't save them */ + GET_PDA(p5, r7); p4.l = lo(DCPLB_FAULT_ADDR); p4.h = hi(DCPLB_FAULT_ADDR); r7 = [p4]; - p5.h = _saved_dcplb_fault_addr; - p5.l = _saved_dcplb_fault_addr; - [p5] = r7; + [p5 + PDA_DCPLB] = r7; - r7 = [p4 + (ICPLB_FAULT_ADDR - DCPLB_FAULT_ADDR)]; - p5.h = _saved_icplb_fault_addr; - p5.l = _saved_icplb_fault_addr; - [p5] = r7; + p4.l = lo(ICPLB_FAULT_ADDR); + p4.h = hi(ICPLB_FAULT_ADDR); + r7 = [p4]; + [p5 + PDA_ICPLB] = r7; - p4.l = _saved_retx; - p4.h = _saved_retx; r6 = retx; - [p4] = r6; + [p5 + PDA_RETX] = r6; r7 = SEQSTAT; /* reason code is in bit 5:0 */ - p4.l = _saved_seqstat; - p4.h = _saved_seqstat; - [p4] = r7; + [p5 + PDA_SEQSTAT] = r7; #else r7 = SEQSTAT; /* reason code is in bit 5:0 */ #endif @@ -546,11 +539,11 @@ ENTRY(_kernel_execve) p0 = sp; r3 = SIZEOF_PTREGS / 4; r4 = 0(x); -0: +.Lclear_regs: [p0++] = r4; r3 += -1; cc = r3 == 0; - if !cc jump 0b (bp); + if !cc jump .Lclear_regs (bp); p0 = sp; sp += -16; @@ -558,7 +551,7 @@ ENTRY(_kernel_execve) call _do_execve; SP += 16; cc = r0 == 0; - if ! cc jump 1f; + if ! cc jump .Lexecve_failed; /* Success. Copy our temporary pt_regs to the top of the kernel * stack and do a normal exception return. */ @@ -574,12 +567,12 @@ ENTRY(_kernel_execve) p0 = fp; r4 = [p0--]; r3 = SIZEOF_PTREGS / 4; -0: +.Lcopy_regs: r4 = [p0--]; [p1--] = r4; r3 += -1; cc = r3 == 0; - if ! cc jump 0b (bp); + if ! cc jump .Lcopy_regs (bp); r0 = (KERNEL_STACK_SIZE - SIZEOF_PTREGS) (z); p1 = r0; @@ -591,7 +584,7 @@ ENTRY(_kernel_execve) RESTORE_CONTEXT; rti; -1: +.Lexecve_failed: unlink; rts; ENDPROC(_kernel_execve) @@ -925,9 +918,14 @@ _schedule_and_signal_from_int: p1 = rets; [sp + PT_RESERVED] = p1; +#ifdef CONFIG_SMP + GET_PDA(p0, r0); /* Fetch current PDA (can't migrate to other CPU here) */ + r0 = [p0 + PDA_IRQFLAGS]; +#else p0.l = _irq_flags; p0.h = _irq_flags; r0 = [p0]; +#endif sti r0; r0 = sp; @@ -1539,12 +1537,6 @@ ENTRY(_sys_call_table) .endr END(_sys_call_table) -#if ANOMALY_05000261 -/* Used by the assembly entry point to work around an anomaly. */ -_last_cplb_fault_retx: - .long 0; -#endif - #ifdef CONFIG_EXCEPTION_L1_SCRATCH /* .section .l1.bss.scratch */ .set _exception_stack_top, L1_SCRATCH_START + L1_SCRATCH_LENGTH @@ -1554,8 +1546,8 @@ _last_cplb_fault_retx: #else .bss #endif -_exception_stack: - .rept 1024 +ENTRY(_exception_stack) + .rept 1024 * NR_CPUS .long 0 .endr _exception_stack_top: diff --git a/arch/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S index c1dcaebbd3a9..a621ae444810 100644 --- a/arch/blackfin/mach-common/head.S +++ b/arch/blackfin/mach-common/head.S @@ -13,6 +13,7 @@ #include #include #include +#include __INIT @@ -111,33 +112,26 @@ ENTRY(__start) * This happens here, since L1 gets clobbered * below */ - p0.l = _saved_retx; - p0.h = _saved_retx; + GET_PDA(p0, r0); + r7 = [p0 + PDA_RETX]; p1.l = _init_saved_retx; p1.h = _init_saved_retx; - r0 = [p0]; - [p1] = r0; + [p1] = r7; - p0.l = _saved_dcplb_fault_addr; - p0.h = _saved_dcplb_fault_addr; + r7 = [p0 + PDA_DCPLB]; p1.l = _init_saved_dcplb_fault_addr; p1.h = _init_saved_dcplb_fault_addr; - r0 = [p0]; - [p1] = r0; + [p1] = r7; - p0.l = _saved_icplb_fault_addr; - p0.h = _saved_icplb_fault_addr; + r7 = [p0 + PDA_ICPLB]; p1.l = _init_saved_icplb_fault_addr; p1.h = _init_saved_icplb_fault_addr; - r0 = [p0]; - [p1] = r0; + [p1] = r7; - p0.l = _saved_seqstat; - p0.h = _saved_seqstat; + r7 = [p0 + PDA_SEQSTAT]; p1.l = _init_saved_seqstat; p1.h = _init_saved_seqstat; - r0 = [p0]; - [p1] = r0; + [p1] = r7; #endif /* Initialize stack pointer */ @@ -255,6 +249,9 @@ ENTRY(_real_start) sp = sp + p1; usp = sp; fp = sp; + sp += -12; + call _init_pda + sp += 12; jump.l _start_kernel; ENDPROC(_real_start) diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index d45d0c59fac7..eb8dfcfc3544 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -55,6 +55,7 @@ * - */ +#ifndef CONFIG_SMP /* Initialize this to an actual value to force it into the .data * section so that we know it is properly initialized at entry into * the kernel but before bss is initialized to zero (which is where @@ -63,6 +64,7 @@ */ unsigned long irq_flags = 0x1f; EXPORT_SYMBOL(irq_flags); +#endif /* The number of spurious interrupts */ atomic_t num_spurious; @@ -163,6 +165,10 @@ static void bfin_internal_mask_irq(unsigned int irq) mask_bit = SIC_SYSIRQ(irq) % 32; bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) & ~(1 << mask_bit)); +#ifdef CONFIG_SMP + bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) & + ~(1 << mask_bit)); +#endif #endif } @@ -177,6 +183,10 @@ static void bfin_internal_unmask_irq(unsigned int irq) mask_bit = SIC_SYSIRQ(irq) % 32; bfin_write_SIC_IMASK(mask_bank, bfin_read_SIC_IMASK(mask_bank) | (1 << mask_bit)); +#ifdef CONFIG_SMP + bfin_write_SICB_IMASK(mask_bank, bfin_read_SICB_IMASK(mask_bank) | + (1 << mask_bit)); +#endif #endif } @@ -896,7 +906,7 @@ static struct irq_chip bfin_gpio_irqchip = { #endif }; -void __init init_exception_vectors(void) +void __cpuinit init_exception_vectors(void) { /* cannot program in software: * evt0 - emulation (jtag) @@ -935,6 +945,10 @@ int __init init_arch_irq(void) # ifdef CONFIG_BF54x bfin_write_SIC_IMASK2(SIC_UNMASK_ALL); # endif +# ifdef CONFIG_SMP + bfin_write_SICB_IMASK0(SIC_UNMASK_ALL); + bfin_write_SICB_IMASK1(SIC_UNMASK_ALL); +# endif #else bfin_write_SIC_IMASK(SIC_UNMASK_ALL); #endif @@ -995,6 +1009,17 @@ int __init init_arch_irq(void) break; #endif +#ifdef CONFIG_TICK_SOURCE_SYSTMR0 + case IRQ_TIMER0: + set_irq_handler(irq, handle_percpu_irq); + break; +#endif +#ifdef CONFIG_SMP + case IRQ_SUPPLE_0: + case IRQ_SUPPLE_1: + set_irq_handler(irq, handle_percpu_irq); + break; +#endif default: set_irq_handler(irq, handle_simple_irq); break; @@ -1029,7 +1054,7 @@ int __init init_arch_irq(void) search_IAR(); /* Enable interrupts IVG7-15 */ - irq_flags = irq_flags | IMASK_IVG15 | + irq_flags |= IMASK_IVG15 | IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; @@ -1070,8 +1095,16 @@ void do_irq(int vec, struct pt_regs *fp) || defined(BF538_FAMILY) || defined(CONFIG_BF51x) unsigned long sic_status[3]; - sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0(); - sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1(); + if (smp_processor_id()) { +#ifdef CONFIG_SMP + /* This will be optimized out in UP mode. */ + sic_status[0] = bfin_read_SICB_ISR0() & bfin_read_SICB_IMASK0(); + sic_status[1] = bfin_read_SICB_ISR1() & bfin_read_SICB_IMASK1(); +#endif + } else { + sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0(); + sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1(); + } #ifdef CONFIG_BF54x sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2(); #endif diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c new file mode 100644 index 000000000000..7aeecedd3147 --- /dev/null +++ b/arch/blackfin/mach-common/smp.c @@ -0,0 +1,476 @@ +/* + * File: arch/blackfin/kernel/smp.c + * Author: Philippe Gerum + * IPI management based on arch/arm/kernel/smp.c. + * + * Copyright 2007 Analog Devices Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see the file COPYING, or write + * to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct corelock_slot corelock __attribute__ ((__section__(".l2.bss"))); + +void __cpuinitdata *init_retx_coreb, *init_saved_retx_coreb, + *init_saved_seqstat_coreb, *init_saved_icplb_fault_addr_coreb, + *init_saved_dcplb_fault_addr_coreb; + +cpumask_t cpu_possible_map; +EXPORT_SYMBOL(cpu_possible_map); + +cpumask_t cpu_online_map; +EXPORT_SYMBOL(cpu_online_map); + +#define BFIN_IPI_RESCHEDULE 0 +#define BFIN_IPI_CALL_FUNC 1 +#define BFIN_IPI_CPU_STOP 2 + +struct blackfin_flush_data { + unsigned long start; + unsigned long end; +}; + +void *secondary_stack; + + +struct smp_call_struct { + void (*func)(void *info); + void *info; + int wait; + cpumask_t pending; + cpumask_t waitmask; +}; + +static struct blackfin_flush_data smp_flush_data; + +static DEFINE_SPINLOCK(stop_lock); + +struct ipi_message { + struct list_head list; + unsigned long type; + struct smp_call_struct call_struct; +}; + +struct ipi_message_queue { + struct list_head head; + spinlock_t lock; + unsigned long count; +}; + +static DEFINE_PER_CPU(struct ipi_message_queue, ipi_msg_queue); + +static void ipi_cpu_stop(unsigned int cpu) +{ + spin_lock(&stop_lock); + printk(KERN_CRIT "CPU%u: stopping\n", cpu); + dump_stack(); + spin_unlock(&stop_lock); + + cpu_clear(cpu, cpu_online_map); + + local_irq_disable(); + + while (1) + SSYNC(); +} + +static void ipi_flush_icache(void *info) +{ + struct blackfin_flush_data *fdata = info; + + /* Invalidate the memory holding the bounds of the flushed region. */ + blackfin_dcache_invalidate_range((unsigned long)fdata, + (unsigned long)fdata + sizeof(*fdata)); + + blackfin_icache_flush_range(fdata->start, fdata->end); +} + +static void ipi_call_function(unsigned int cpu, struct ipi_message *msg) +{ + int wait; + void (*func)(void *info); + void *info; + func = msg->call_struct.func; + info = msg->call_struct.info; + wait = msg->call_struct.wait; + cpu_clear(cpu, msg->call_struct.pending); + func(info); + if (wait) + cpu_clear(cpu, msg->call_struct.waitmask); + else + kfree(msg); +} + +static irqreturn_t ipi_handler(int irq, void *dev_instance) +{ + struct ipi_message *msg, *mg; + struct ipi_message_queue *msg_queue; + unsigned int cpu = smp_processor_id(); + + platform_clear_ipi(cpu); + + msg_queue = &__get_cpu_var(ipi_msg_queue); + msg_queue->count++; + + spin_lock(&msg_queue->lock); + list_for_each_entry_safe(msg, mg, &msg_queue->head, list) { + list_del(&msg->list); + switch (msg->type) { + case BFIN_IPI_RESCHEDULE: + /* That's the easiest one; leave it to + * return_from_int. */ + kfree(msg); + break; + case BFIN_IPI_CALL_FUNC: + ipi_call_function(cpu, msg); + break; + case BFIN_IPI_CPU_STOP: + ipi_cpu_stop(cpu); + kfree(msg); + break; + default: + printk(KERN_CRIT "CPU%u: Unknown IPI message \ + 0x%lx\n", cpu, msg->type); + kfree(msg); + break; + } + } + spin_unlock(&msg_queue->lock); + return IRQ_HANDLED; +} + +static void ipi_queue_init(void) +{ + unsigned int cpu; + struct ipi_message_queue *msg_queue; + for_each_possible_cpu(cpu) { + msg_queue = &per_cpu(ipi_msg_queue, cpu); + INIT_LIST_HEAD(&msg_queue->head); + spin_lock_init(&msg_queue->lock); + msg_queue->count = 0; + } +} + +int smp_call_function(void (*func)(void *info), void *info, int wait) +{ + unsigned int cpu; + cpumask_t callmap; + unsigned long flags; + struct ipi_message_queue *msg_queue; + struct ipi_message *msg; + + callmap = cpu_online_map; + cpu_clear(smp_processor_id(), callmap); + if (cpus_empty(callmap)) + return 0; + + msg = kmalloc(sizeof(*msg), GFP_ATOMIC); + INIT_LIST_HEAD(&msg->list); + msg->call_struct.func = func; + msg->call_struct.info = info; + msg->call_struct.wait = wait; + msg->call_struct.pending = callmap; + msg->call_struct.waitmask = callmap; + msg->type = BFIN_IPI_CALL_FUNC; + + for_each_cpu_mask(cpu, callmap) { + msg_queue = &per_cpu(ipi_msg_queue, cpu); + spin_lock_irqsave(&msg_queue->lock, flags); + list_add(&msg->list, &msg_queue->head); + spin_unlock_irqrestore(&msg_queue->lock, flags); + platform_send_ipi_cpu(cpu); + } + if (wait) { + while (!cpus_empty(msg->call_struct.waitmask)) + blackfin_dcache_invalidate_range( + (unsigned long)(&msg->call_struct.waitmask), + (unsigned long)(&msg->call_struct.waitmask)); + kfree(msg); + } + return 0; +} +EXPORT_SYMBOL_GPL(smp_call_function); + +int smp_call_function_single(int cpuid, void (*func) (void *info), void *info, + int wait) +{ + unsigned int cpu = cpuid; + cpumask_t callmap; + unsigned long flags; + struct ipi_message_queue *msg_queue; + struct ipi_message *msg; + + if (cpu_is_offline(cpu)) + return 0; + cpus_clear(callmap); + cpu_set(cpu, callmap); + + msg = kmalloc(sizeof(*msg), GFP_ATOMIC); + INIT_LIST_HEAD(&msg->list); + msg->call_struct.func = func; + msg->call_struct.info = info; + msg->call_struct.wait = wait; + msg->call_struct.pending = callmap; + msg->call_struct.waitmask = callmap; + msg->type = BFIN_IPI_CALL_FUNC; + + msg_queue = &per_cpu(ipi_msg_queue, cpu); + spin_lock_irqsave(&msg_queue->lock, flags); + list_add(&msg->list, &msg_queue->head); + spin_unlock_irqrestore(&msg_queue->lock, flags); + platform_send_ipi_cpu(cpu); + + if (wait) { + while (!cpus_empty(msg->call_struct.waitmask)) + blackfin_dcache_invalidate_range( + (unsigned long)(&msg->call_struct.waitmask), + (unsigned long)(&msg->call_struct.waitmask)); + kfree(msg); + } + return 0; +} +EXPORT_SYMBOL_GPL(smp_call_function_single); + +void smp_send_reschedule(int cpu) +{ + unsigned long flags; + struct ipi_message_queue *msg_queue; + struct ipi_message *msg; + + if (cpu_is_offline(cpu)) + return; + + msg = kmalloc(sizeof(*msg), GFP_ATOMIC); + memset(msg, 0, sizeof(msg)); + INIT_LIST_HEAD(&msg->list); + msg->type = BFIN_IPI_RESCHEDULE; + + msg_queue = &per_cpu(ipi_msg_queue, cpu); + spin_lock_irqsave(&msg_queue->lock, flags); + list_add(&msg->list, &msg_queue->head); + spin_unlock_irqrestore(&msg_queue->lock, flags); + platform_send_ipi_cpu(cpu); + + return; +} + +void smp_send_stop(void) +{ + unsigned int cpu; + cpumask_t callmap; + unsigned long flags; + struct ipi_message_queue *msg_queue; + struct ipi_message *msg; + + callmap = cpu_online_map; + cpu_clear(smp_processor_id(), callmap); + if (cpus_empty(callmap)) + return; + + msg = kmalloc(sizeof(*msg), GFP_ATOMIC); + memset(msg, 0, sizeof(msg)); + INIT_LIST_HEAD(&msg->list); + msg->type = BFIN_IPI_CPU_STOP; + + for_each_cpu_mask(cpu, callmap) { + msg_queue = &per_cpu(ipi_msg_queue, cpu); + spin_lock_irqsave(&msg_queue->lock, flags); + list_add(&msg->list, &msg_queue->head); + spin_unlock_irqrestore(&msg_queue->lock, flags); + platform_send_ipi_cpu(cpu); + } + return; +} + +int __cpuinit __cpu_up(unsigned int cpu) +{ + struct task_struct *idle; + int ret; + + idle = fork_idle(cpu); + if (IS_ERR(idle)) { + printk(KERN_ERR "CPU%u: fork() failed\n", cpu); + return PTR_ERR(idle); + } + + secondary_stack = task_stack_page(idle) + THREAD_SIZE; + smp_wmb(); + + ret = platform_boot_secondary(cpu, idle); + + if (ret) { + cpu_clear(cpu, cpu_present_map); + printk(KERN_CRIT "CPU%u: processor failed to boot (%d)\n", cpu, ret); + free_task(idle); + } else + cpu_set(cpu, cpu_online_map); + + secondary_stack = NULL; + + return ret; +} + +static void __cpuinit setup_secondary(unsigned int cpu) +{ +#ifndef CONFIG_TICK_SOURCE_SYSTMR0 + struct irq_desc *timer_desc; +#endif + unsigned long ilat; + + bfin_write_IMASK(0); + CSYNC(); + ilat = bfin_read_ILAT(); + CSYNC(); + bfin_write_ILAT(ilat); + CSYNC(); + + /* Reserve the PDA space for the secondary CPU. */ + reserve_pda(); + + /* Enable interrupt levels IVG7-15. IARs have been already + * programmed by the boot CPU. */ + irq_flags |= IMASK_IVG15 | + IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | + IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; + +#ifdef CONFIG_TICK_SOURCE_SYSTMR0 + /* Power down the core timer, just to play safe. */ + bfin_write_TCNTL(0); + + /* system timer0 has been setup by CoreA. */ +#else + timer_desc = irq_desc + IRQ_CORETMR; + setup_core_timer(); + timer_desc->chip->enable(IRQ_CORETMR); +#endif +} + +void __cpuinit secondary_start_kernel(void) +{ + unsigned int cpu = smp_processor_id(); + struct mm_struct *mm = &init_mm; + + if (_bfin_swrst & SWRST_DBL_FAULT_B) { + printk(KERN_EMERG "CoreB Recovering from DOUBLE FAULT event\n"); +#ifdef CONFIG_DEBUG_DOUBLEFAULT + printk(KERN_EMERG " While handling exception (EXCAUSE = 0x%x) at %pF\n", + (int)init_saved_seqstat_coreb & SEQSTAT_EXCAUSE, init_saved_retx_coreb); + printk(KERN_NOTICE " DCPLB_FAULT_ADDR: %pF\n", init_saved_dcplb_fault_addr_coreb); + printk(KERN_NOTICE " ICPLB_FAULT_ADDR: %pF\n", init_saved_icplb_fault_addr_coreb); +#endif + printk(KERN_NOTICE " The instruction at %pF caused a double exception\n", + init_retx_coreb); + } + + /* + * We want the D-cache to be enabled early, in case the atomic + * support code emulates cache coherence (see + * __ARCH_SYNC_CORE_DCACHE). + */ + init_exception_vectors(); + + bfin_setup_caches(cpu); + + local_irq_disable(); + + /* Attach the new idle task to the global mm. */ + atomic_inc(&mm->mm_users); + atomic_inc(&mm->mm_count); + current->active_mm = mm; + BUG_ON(current->mm); /* Can't be, but better be safe than sorry. */ + + preempt_disable(); + + setup_secondary(cpu); + + local_irq_enable(); + + platform_secondary_init(cpu); + + cpu_idle(); +} + +void __init smp_prepare_boot_cpu(void) +{ +} + +void __init smp_prepare_cpus(unsigned int max_cpus) +{ + platform_prepare_cpus(max_cpus); + ipi_queue_init(); + platform_request_ipi(&ipi_handler); +} + +void __init smp_cpus_done(unsigned int max_cpus) +{ + unsigned long bogosum = 0; + unsigned int cpu; + + for_each_online_cpu(cpu) + bogosum += per_cpu(cpu_data, cpu).loops_per_jiffy; + + printk(KERN_INFO "SMP: Total of %d processors activated " + "(%lu.%02lu BogoMIPS).\n", + num_online_cpus(), + bogosum / (500000/HZ), + (bogosum / (5000/HZ)) % 100); +} + +void smp_icache_flush_range_others(unsigned long start, unsigned long end) +{ + smp_flush_data.start = start; + smp_flush_data.end = end; + + if (smp_call_function(&ipi_flush_icache, &smp_flush_data, 1)) + printk(KERN_WARNING "SMP: failed to run I-cache flush request on other CPUs\n"); +} +EXPORT_SYMBOL_GPL(smp_icache_flush_range_others); + +#ifdef __ARCH_SYNC_CORE_DCACHE +unsigned long barrier_mask __attribute__ ((__section__(".l2.bss"))); + +void resync_core_dcache(void) +{ + unsigned int cpu = get_cpu(); + blackfin_invalidate_entire_dcache(); + ++per_cpu(cpu_data, cpu).dcache_invld_count; + put_cpu(); +} +EXPORT_SYMBOL(resync_core_dcache); +#endif diff --git a/arch/blackfin/oprofile/common.c b/arch/blackfin/oprofile/common.c index 0f6d303a8891..f34795a2e481 100644 --- a/arch/blackfin/oprofile/common.c +++ b/arch/blackfin/oprofile/common.c @@ -130,7 +130,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) mutex_init(&pfmon_lock); - dspid = bfin_read_DSPID(); + dspid = bfin_dspid(); printk(KERN_INFO "Oprofile got the cpu id is 0x%x. \n", dspid); -- cgit v1.2.3 From 6a01f230339321292cf065551f8cf55361052461 Mon Sep 17 00:00:00 2001 From: Yi Li Date: Wed, 7 Jan 2009 23:14:39 +0800 Subject: Blackfin arch: merge adeos blackfin part to arch/blackfin/ [Mike Frysinger : - handle bf531/bf532/bf534/bf536 variants in ipipe.h - cleanup IPIPE logic for bfin_set_irq_handler() - cleanup ipipe asm code a bit and add missing ENDPROC() - simplify IPIPE code in trap_c - unify some of the IPIPE code and fix style - simplify DO_IRQ_L1 handling with ipipe code - revert IRQ_SW_INT# addition from ipipe merge - remove duplicate get_{c,s}clk() prototypes ] Signed-off-by: Yi Li Signed-off-by: Mike Frysinger Signed-off-by: Bryan Wu --- arch/blackfin/configs/BF518F-EZBRD_defconfig | 16 +- arch/blackfin/configs/BF526-EZBRD_defconfig | 16 +- arch/blackfin/configs/BF527-EZKIT_defconfig | 16 +- arch/blackfin/configs/BF537-STAMP_defconfig | 16 +- arch/blackfin/configs/BF538-EZKIT_defconfig | 6 +- arch/blackfin/configs/CM-BF527_defconfig | 16 +- arch/blackfin/configs/CM-BF537E_defconfig | 16 +- arch/blackfin/configs/CM-BF537U_defconfig | 16 +- arch/blackfin/configs/PNAV-10_defconfig | 16 +- arch/blackfin/configs/SRV1_defconfig | 16 +- arch/blackfin/configs/TCM-BF537_defconfig | 16 +- arch/blackfin/include/asm/atomic.h | 32 +- arch/blackfin/include/asm/bitops.h | 24 +- arch/blackfin/include/asm/entry.h | 9 + arch/blackfin/include/asm/ipipe.h | 278 +++++++++++++ arch/blackfin/include/asm/ipipe_base.h | 80 ++++ arch/blackfin/include/asm/irq.h | 223 +++++++++-- arch/blackfin/include/asm/system.h | 4 +- arch/blackfin/kernel/Makefile | 2 + arch/blackfin/kernel/bfin_gpio.c | 100 ++--- arch/blackfin/kernel/cplb-mpu/cplbmgr.c | 8 +- arch/blackfin/kernel/entry.S | 4 + arch/blackfin/kernel/ipipe.c | 428 +++++++++++++++++++++ arch/blackfin/kernel/irqchip.c | 5 +- arch/blackfin/kernel/mcount.S | 70 ++++ arch/blackfin/kernel/process.c | 7 +- arch/blackfin/kernel/time.c | 15 +- arch/blackfin/kernel/traps.c | 13 +- arch/blackfin/lib/ins.S | 163 +++++++- arch/blackfin/mach-bf518/Kconfig | 34 +- .../mach-bf518/include/mach/cdefBF51x_base.h | 8 +- arch/blackfin/mach-bf518/include/mach/irq.h | 32 +- arch/blackfin/mach-bf518/ints-priority.c | 16 +- arch/blackfin/mach-bf527/Kconfig | 34 +- .../mach-bf527/include/mach/cdefBF52x_base.h | 8 +- arch/blackfin/mach-bf527/include/mach/irq.h | 32 +- arch/blackfin/mach-bf527/ints-priority.c | 16 +- arch/blackfin/mach-bf533/Kconfig | 2 +- arch/blackfin/mach-bf533/include/mach/cdefBF532.h | 16 +- arch/blackfin/mach-bf533/include/mach/irq.h | 6 +- arch/blackfin/mach-bf537/Kconfig | 34 +- arch/blackfin/mach-bf537/include/mach/cdefBF534.h | 8 +- arch/blackfin/mach-bf537/include/mach/irq.h | 32 +- arch/blackfin/mach-bf537/ints-priority.c | 16 +- arch/blackfin/mach-bf538/Kconfig | 14 +- arch/blackfin/mach-bf538/include/mach/cdefBF538.h | 8 +- arch/blackfin/mach-bf538/include/mach/irq.h | 12 +- arch/blackfin/mach-bf538/ints-priority.c | 6 +- arch/blackfin/mach-bf548/Kconfig | 2 +- .../mach-bf548/include/mach/cdefBF54x_base.h | 8 +- arch/blackfin/mach-bf548/include/mach/irq.h | 2 +- arch/blackfin/mach-bf561/Kconfig | 2 +- arch/blackfin/mach-bf561/include/mach/cdefBF561.h | 8 +- arch/blackfin/mach-common/cpufreq.c | 4 +- arch/blackfin/mach-common/interrupt.S | 60 +++ arch/blackfin/mach-common/ints-priority.c | 235 +++++++++-- arch/blackfin/mach-common/pm.c | 10 +- arch/blackfin/mach-common/smp.c | 4 +- 58 files changed, 1881 insertions(+), 419 deletions(-) create mode 100644 arch/blackfin/include/asm/ipipe.h create mode 100644 arch/blackfin/include/asm/ipipe_base.h create mode 100644 arch/blackfin/kernel/ipipe.c create mode 100644 arch/blackfin/kernel/mcount.S (limited to 'arch/blackfin/include/asm/atomic.h') diff --git a/arch/blackfin/configs/BF518F-EZBRD_defconfig b/arch/blackfin/configs/BF518F-EZBRD_defconfig index 98cf7c3cfef9..699781c4a4cf 100644 --- a/arch/blackfin/configs/BF518F-EZBRD_defconfig +++ b/arch/blackfin/configs/BF518F-EZBRD_defconfig @@ -204,14 +204,14 @@ CONFIG_IRQ_MAC_RX=11 CONFIG_IRQ_PORTH_INTA=11 CONFIG_IRQ_MAC_TX=11 CONFIG_IRQ_PORTH_INTB=11 -CONFIG_IRQ_TMR0=12 -CONFIG_IRQ_TMR1=12 -CONFIG_IRQ_TMR2=12 -CONFIG_IRQ_TMR3=12 -CONFIG_IRQ_TMR4=12 -CONFIG_IRQ_TMR5=12 -CONFIG_IRQ_TMR6=12 -CONFIG_IRQ_TMR7=12 +CONFIG_IRQ_TIMER0=12 +CONFIG_IRQ_TIMER1=12 +CONFIG_IRQ_TIMER2=12 +CONFIG_IRQ_TIMER3=12 +CONFIG_IRQ_TIMER4=12 +CONFIG_IRQ_TIMER5=12 +CONFIG_IRQ_TIMER6=12 +CONFIG_IRQ_TIMER7=12 CONFIG_IRQ_PORTG_INTA=12 CONFIG_IRQ_PORTG_INTB=12 CONFIG_IRQ_MEM_DMA0=13 diff --git a/arch/blackfin/configs/BF526-EZBRD_defconfig b/arch/blackfin/configs/BF526-EZBRD_defconfig index 667af6bb0c46..6dfcd2705133 100644 --- a/arch/blackfin/configs/BF526-EZBRD_defconfig +++ b/arch/blackfin/configs/BF526-EZBRD_defconfig @@ -199,14 +199,14 @@ CONFIG_IRQ_MAC_RX=11 CONFIG_IRQ_PORTH_INTA=11 CONFIG_IRQ_MAC_TX=11 CONFIG_IRQ_PORTH_INTB=11 -CONFIG_IRQ_TMR0=12 -CONFIG_IRQ_TMR1=12 -CONFIG_IRQ_TMR2=12 -CONFIG_IRQ_TMR3=12 -CONFIG_IRQ_TMR4=12 -CONFIG_IRQ_TMR5=12 -CONFIG_IRQ_TMR6=12 -CONFIG_IRQ_TMR7=12 +CONFIG_IRQ_TIMER0=12 +CONFIG_IRQ_TIMER1=12 +CONFIG_IRQ_TIMER2=12 +CONFIG_IRQ_TIMER3=12 +CONFIG_IRQ_TIMER4=12 +CONFIG_IRQ_TIMER5=12 +CONFIG_IRQ_TIMER6=12 +CONFIG_IRQ_TIMER7=12 CONFIG_IRQ_PORTG_INTA=12 CONFIG_IRQ_PORTG_INTB=12 CONFIG_IRQ_MEM_DMA0=13 diff --git a/arch/blackfin/configs/BF527-EZKIT_defconfig b/arch/blackfin/configs/BF527-EZKIT_defconfig index 70b50d010471..2947dcba5ff3 100644 --- a/arch/blackfin/configs/BF527-EZKIT_defconfig +++ b/arch/blackfin/configs/BF527-EZKIT_defconfig @@ -188,14 +188,14 @@ CONFIG_IRQ_MAC_RX=11 CONFIG_IRQ_PORTH_INTA=11 CONFIG_IRQ_MAC_TX=11 CONFIG_IRQ_PORTH_INTB=11 -CONFIG_IRQ_TMR0=12 -CONFIG_IRQ_TMR1=12 -CONFIG_IRQ_TMR2=12 -CONFIG_IRQ_TMR3=12 -CONFIG_IRQ_TMR4=12 -CONFIG_IRQ_TMR5=12 -CONFIG_IRQ_TMR6=12 -CONFIG_IRQ_TMR7=12 +CONFIG_IRQ_TIMER0=8 +CONFIG_IRQ_TIMER1=12 +CONFIG_IRQ_TIMER2=12 +CONFIG_IRQ_TIMER3=12 +CONFIG_IRQ_TIMER4=12 +CONFIG_IRQ_TIMER5=12 +CONFIG_IRQ_TIMER6=12 +CONFIG_IRQ_TIMER7=12 CONFIG_IRQ_PORTG_INTA=12 CONFIG_IRQ_PORTG_INTB=12 CONFIG_IRQ_MEM_DMA0=13 diff --git a/arch/blackfin/configs/BF537-STAMP_defconfig b/arch/blackfin/configs/BF537-STAMP_defconfig index ed84c620d03b..4aa668723032 100644 --- a/arch/blackfin/configs/BF537-STAMP_defconfig +++ b/arch/blackfin/configs/BF537-STAMP_defconfig @@ -148,14 +148,14 @@ CONFIG_IRQ_UART1_RX=10 CONFIG_IRQ_UART1_TX=10 CONFIG_IRQ_MAC_RX=11 CONFIG_IRQ_MAC_TX=11 -CONFIG_IRQ_TMR0=12 -CONFIG_IRQ_TMR1=12 -CONFIG_IRQ_TMR2=12 -CONFIG_IRQ_TMR3=12 -CONFIG_IRQ_TMR4=12 -CONFIG_IRQ_TMR5=12 -CONFIG_IRQ_TMR6=12 -CONFIG_IRQ_TMR7=12 +CONFIG_IRQ_TIMER0=8 +CONFIG_IRQ_TIMER1=12 +CONFIG_IRQ_TIMER2=12 +CONFIG_IRQ_TIMER3=12 +CONFIG_IRQ_TIMER4=12 +CONFIG_IRQ_TIMER5=12 +CONFIG_IRQ_TIMER6=12 +CONFIG_IRQ_TIMER7=12 CONFIG_IRQ_PORTG_INTB=12 CONFIG_IRQ_MEM_DMA0=13 CONFIG_IRQ_MEM_DMA1=13 diff --git a/arch/blackfin/configs/BF538-EZKIT_defconfig b/arch/blackfin/configs/BF538-EZKIT_defconfig index f1d2b3669940..baf33e662096 100644 --- a/arch/blackfin/configs/BF538-EZKIT_defconfig +++ b/arch/blackfin/configs/BF538-EZKIT_defconfig @@ -163,9 +163,9 @@ CONFIG_IRQ_UART0_RX=10 CONFIG_IRQ_UART0_TX=10 CONFIG_IRQ_UART1_RX=10 CONFIG_IRQ_UART1_TX=10 -CONFIG_IRQ_TMR0=12 -CONFIG_IRQ_TMR1=12 -CONFIG_IRQ_TMR2=12 +CONFIG_IRQ_TIMER0=12 +CONFIG_IRQ_TIMER1=12 +CONFIG_IRQ_TIMER2=12 CONFIG_IRQ_WATCH=13 CONFIG_IRQ_PORTF_INTA=12 CONFIG_IRQ_PORTF_INTB=12 diff --git a/arch/blackfin/configs/CM-BF527_defconfig b/arch/blackfin/configs/CM-BF527_defconfig index 0043da5f4938..719538571a5c 100644 --- a/arch/blackfin/configs/CM-BF527_defconfig +++ b/arch/blackfin/configs/CM-BF527_defconfig @@ -190,14 +190,14 @@ CONFIG_IRQ_MAC_RX=11 CONFIG_IRQ_PORTH_INTA=11 CONFIG_IRQ_MAC_TX=11 CONFIG_IRQ_PORTH_INTB=11 -CONFIG_IRQ_TMR0=12 -CONFIG_IRQ_TMR1=12 -CONFIG_IRQ_TMR2=12 -CONFIG_IRQ_TMR3=12 -CONFIG_IRQ_TMR4=12 -CONFIG_IRQ_TMR5=12 -CONFIG_IRQ_TMR6=12 -CONFIG_IRQ_TMR7=12 +CONFIG_IRQ_TIMER0=12 +CONFIG_IRQ_TIMER1=12 +CONFIG_IRQ_TIMER2=12 +CONFIG_IRQ_TIMER3=12 +CONFIG_IRQ_TIMER4=12 +CONFIG_IRQ_TIMER5=12 +CONFIG_IRQ_TIMER6=12 +CONFIG_IRQ_TIMER7=12 CONFIG_IRQ_PORTG_INTA=12 CONFIG_IRQ_PORTG_INTB=12 CONFIG_IRQ_MEM_DMA0=13 diff --git a/arch/blackfin/configs/CM-BF537E_defconfig b/arch/blackfin/configs/CM-BF537E_defconfig index 1b50d382f6e9..cbf4803b448c 100644 --- a/arch/blackfin/configs/CM-BF537E_defconfig +++ b/arch/blackfin/configs/CM-BF537E_defconfig @@ -157,14 +157,14 @@ CONFIG_IRQ_UART1_RX=10 CONFIG_IRQ_UART1_TX=10 CONFIG_IRQ_MAC_RX=11 CONFIG_IRQ_MAC_TX=11 -CONFIG_IRQ_TMR0=12 -CONFIG_IRQ_TMR1=12 -CONFIG_IRQ_TMR2=12 -CONFIG_IRQ_TMR3=12 -CONFIG_IRQ_TMR4=12 -CONFIG_IRQ_TMR5=12 -CONFIG_IRQ_TMR6=12 -CONFIG_IRQ_TMR7=12 +CONFIG_IRQ_TIMER0=12 +CONFIG_IRQ_TIMER1=12 +CONFIG_IRQ_TIMER2=12 +CONFIG_IRQ_TIMER3=12 +CONFIG_IRQ_TIMER4=12 +CONFIG_IRQ_TIMER5=12 +CONFIG_IRQ_TIMER6=12 +CONFIG_IRQ_TIMER7=12 CONFIG_IRQ_PORTG_INTB=12 CONFIG_IRQ_MEM_DMA0=13 CONFIG_IRQ_MEM_DMA1=13 diff --git a/arch/blackfin/configs/CM-BF537U_defconfig b/arch/blackfin/configs/CM-BF537U_defconfig index 2ca768d15b56..f2ac0cc37bf1 100644 --- a/arch/blackfin/configs/CM-BF537U_defconfig +++ b/arch/blackfin/configs/CM-BF537U_defconfig @@ -157,14 +157,14 @@ CONFIG_IRQ_UART1_RX=10 CONFIG_IRQ_UART1_TX=10 CONFIG_IRQ_MAC_RX=11 CONFIG_IRQ_MAC_TX=11 -CONFIG_IRQ_TMR0=12 -CONFIG_IRQ_TMR1=12 -CONFIG_IRQ_TMR2=12 -CONFIG_IRQ_TMR3=12 -CONFIG_IRQ_TMR4=12 -CONFIG_IRQ_TMR5=12 -CONFIG_IRQ_TMR6=12 -CONFIG_IRQ_TMR7=12 +CONFIG_IRQ_TIMER0=12 +CONFIG_IRQ_TIMER1=12 +CONFIG_IRQ_TIMER2=12 +CONFIG_IRQ_TIMER3=12 +CONFIG_IRQ_TIMER4=12 +CONFIG_IRQ_TIMER5=12 +CONFIG_IRQ_TIMER6=12 +CONFIG_IRQ_TIMER7=12 CONFIG_IRQ_PORTG_INTB=12 CONFIG_IRQ_MEM_DMA0=13 CONFIG_IRQ_MEM_DMA1=13 diff --git a/arch/blackfin/configs/PNAV-10_defconfig b/arch/blackfin/configs/PNAV-10_defconfig index 648edd99a94e..834fb8c9eefb 100644 --- a/arch/blackfin/configs/PNAV-10_defconfig +++ b/arch/blackfin/configs/PNAV-10_defconfig @@ -153,14 +153,14 @@ CONFIG_IRQ_UART1_RX=10 CONFIG_IRQ_UART1_TX=10 CONFIG_IRQ_MAC_RX=11 CONFIG_IRQ_MAC_TX=11 -CONFIG_IRQ_TMR0=12 -CONFIG_IRQ_TMR1=12 -CONFIG_IRQ_TMR2=12 -CONFIG_IRQ_TMR3=12 -CONFIG_IRQ_TMR4=12 -CONFIG_IRQ_TMR5=12 -CONFIG_IRQ_TMR6=12 -CONFIG_IRQ_TMR7=12 +CONFIG_IRQ_TIMER0=12 +CONFIG_IRQ_TIMER1=12 +CONFIG_IRQ_TIMER2=12 +CONFIG_IRQ_TIMER3=12 +CONFIG_IRQ_TIMER4=12 +CONFIG_IRQ_TIMER5=12 +CONFIG_IRQ_TIMER6=12 +CONFIG_IRQ_TIMER7=12 CONFIG_IRQ_PORTG_INTB=12 CONFIG_IRQ_MEM_DMA0=13 CONFIG_IRQ_MEM_DMA1=13 diff --git a/arch/blackfin/configs/SRV1_defconfig b/arch/blackfin/configs/SRV1_defconfig index ffa2396e6121..010f0aa7e4cb 100644 --- a/arch/blackfin/configs/SRV1_defconfig +++ b/arch/blackfin/configs/SRV1_defconfig @@ -172,14 +172,14 @@ CONFIG_IRQ_UART1_RX=10 CONFIG_IRQ_UART1_TX=10 CONFIG_IRQ_MAC_RX=11 CONFIG_IRQ_MAC_TX=11 -CONFIG_IRQ_TMR0=12 -CONFIG_IRQ_TMR1=12 -CONFIG_IRQ_TMR2=12 -CONFIG_IRQ_TMR3=12 -CONFIG_IRQ_TMR4=12 -CONFIG_IRQ_TMR5=12 -CONFIG_IRQ_TMR6=12 -CONFIG_IRQ_TMR7=12 +CONFIG_IRQ_TIMER0=12 +CONFIG_IRQ_TIMER1=12 +CONFIG_IRQ_TIMER2=12 +CONFIG_IRQ_TIMER3=12 +CONFIG_IRQ_TIMER4=12 +CONFIG_IRQ_TIMER5=12 +CONFIG_IRQ_TIMER6=12 +CONFIG_IRQ_TIMER7=12 CONFIG_IRQ_PORTG_INTB=12 CONFIG_IRQ_MEM_DMA0=13 CONFIG_IRQ_MEM_DMA1=13 diff --git a/arch/blackfin/configs/TCM-BF537_defconfig b/arch/blackfin/configs/TCM-BF537_defconfig index 6431192073c6..0ba4aa892139 100644 --- a/arch/blackfin/configs/TCM-BF537_defconfig +++ b/arch/blackfin/configs/TCM-BF537_defconfig @@ -144,14 +144,14 @@ CONFIG_IRQ_UART1_RX=10 CONFIG_IRQ_UART1_TX=10 CONFIG_IRQ_MAC_RX=11 CONFIG_IRQ_MAC_TX=11 -CONFIG_IRQ_TMR0=12 -CONFIG_IRQ_TMR1=12 -CONFIG_IRQ_TMR2=12 -CONFIG_IRQ_TMR3=12 -CONFIG_IRQ_TMR4=12 -CONFIG_IRQ_TMR5=12 -CONFIG_IRQ_TMR6=12 -CONFIG_IRQ_TMR7=12 +CONFIG_IRQ_TIMER0=12 +CONFIG_IRQ_TIMER1=12 +CONFIG_IRQ_TIMER2=12 +CONFIG_IRQ_TIMER3=12 +CONFIG_IRQ_TIMER4=12 +CONFIG_IRQ_TIMER5=12 +CONFIG_IRQ_TIMER6=12 +CONFIG_IRQ_TIMER7=12 CONFIG_IRQ_PORTG_INTB=12 CONFIG_IRQ_MEM_DMA0=13 CONFIG_IRQ_MEM_DMA1=13 diff --git a/arch/blackfin/include/asm/atomic.h b/arch/blackfin/include/asm/atomic.h index d76275e5638c..94b2a9b19451 100644 --- a/arch/blackfin/include/asm/atomic.h +++ b/arch/blackfin/include/asm/atomic.h @@ -92,18 +92,18 @@ static inline void atomic_add(int i, atomic_t *v) { long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter += i; - local_irq_restore(flags); + local_irq_restore_hw(flags); } static inline void atomic_sub(int i, atomic_t *v) { long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter -= i; - local_irq_restore(flags); + local_irq_restore_hw(flags); } @@ -112,10 +112,10 @@ static inline int atomic_add_return(int i, atomic_t *v) int __temp = 0; long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter += i; __temp = v->counter; - local_irq_restore(flags); + local_irq_restore_hw(flags); return __temp; @@ -126,10 +126,10 @@ static inline int atomic_sub_return(int i, atomic_t *v) int __temp = 0; long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter -= i; __temp = v->counter; - local_irq_restore(flags); + local_irq_restore_hw(flags); return __temp; } @@ -138,36 +138,36 @@ static inline void atomic_inc(volatile atomic_t *v) { long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter++; - local_irq_restore(flags); + local_irq_restore_hw(flags); } static inline void atomic_dec(volatile atomic_t *v) { long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter--; - local_irq_restore(flags); + local_irq_restore_hw(flags); } static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) { long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter &= ~mask; - local_irq_restore(flags); + local_irq_restore_hw(flags); } static inline void atomic_set_mask(unsigned int mask, atomic_t *v) { long flags; - local_irq_save(flags); + local_irq_save_hw(flags); v->counter |= mask; - local_irq_restore(flags); + local_irq_restore_hw(flags); } /* Atomic operations are already serializing */ diff --git a/arch/blackfin/include/asm/bitops.h b/arch/blackfin/include/asm/bitops.h index 9964e17232e9..21b036eadab1 100644 --- a/arch/blackfin/include/asm/bitops.h +++ b/arch/blackfin/include/asm/bitops.h @@ -90,9 +90,9 @@ static inline void set_bit(int nr, volatile unsigned long *addr) unsigned long flags; a += nr >> 5; mask = 1 << (nr & 0x1f); - local_irq_save(flags); + local_irq_save_hw(flags); *a |= mask; - local_irq_restore(flags); + local_irq_restore_hw(flags); } static inline void clear_bit(int nr, volatile unsigned long *addr) @@ -102,9 +102,9 @@ static inline void clear_bit(int nr, volatile unsigned long *addr) unsigned long flags; a += nr >> 5; mask = 1 << (nr & 0x1f); - local_irq_save(flags); + local_irq_save_hw(flags); *a &= ~mask; - local_irq_restore(flags); + local_irq_restore_hw(flags); } static inline void change_bit(int nr, volatile unsigned long *addr) @@ -114,9 +114,9 @@ static inline void change_bit(int nr, volatile unsigned long *addr) ADDR += nr >> 5; mask = 1 << (nr & 31); - local_irq_save(flags); + local_irq_save_hw(flags); *ADDR ^= mask; - local_irq_restore(flags); + local_irq_restore_hw(flags); } static inline int test_and_set_bit(int nr, volatile unsigned long *addr) @@ -127,10 +127,10 @@ static inline int test_and_set_bit(int nr, volatile unsigned long *addr) a += nr >> 5; mask = 1 << (nr & 0x1f); - local_irq_save(flags); + local_irq_save_hw(flags); retval = (mask & *a) != 0; *a |= mask; - local_irq_restore(flags); + local_irq_restore_hw(flags); return retval; } @@ -143,10 +143,10 @@ static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) a += nr >> 5; mask = 1 << (nr & 0x1f); - local_irq_save(flags); + local_irq_save_hw(flags); retval = (mask & *a) != 0; *a &= ~mask; - local_irq_restore(flags); + local_irq_restore_hw(flags); return retval; } @@ -159,10 +159,10 @@ static inline int test_and_change_bit(int nr, volatile unsigned long *addr) a += nr >> 5; mask = 1 << (nr & 0x1f); - local_irq_save(flags); + local_irq_save_hw(flags); retval = (mask & *a) != 0; *a ^= mask; - local_irq_restore(flags); + local_irq_restore_hw(flags); return retval; } diff --git a/arch/blackfin/include/asm/entry.h b/arch/blackfin/include/asm/entry.h index d94e4f5139d2..b30a2968e274 100644 --- a/arch/blackfin/include/asm/entry.h +++ b/arch/blackfin/include/asm/entry.h @@ -27,6 +27,14 @@ #define SAVE_ALL_SYS save_context_no_interrupts /* This is used for all normal interrupts. It saves a minimum of registers to the stack, loads the IRQ number, and jumps to common code. */ +#ifdef CONFIG_IPIPE +# define LOAD_IPIPE_IPEND \ + P0.l = lo(IPEND); \ + P0.h = hi(IPEND); \ + R1 = [P0]; +#else +# define LOAD_IPIPE_IPEND +#endif #define INTERRUPT_ENTRY(N) \ [--sp] = SYSCFG; \ \ @@ -34,6 +42,7 @@ [--sp] = R0; /*orig_r0*/ \ [--sp] = (R7:0,P5:0); \ R0 = (N); \ + LOAD_IPIPE_IPEND \ jump __common_int_entry; /* For timer interrupts, we need to save IPEND, since the user_mode diff --git a/arch/blackfin/include/asm/ipipe.h b/arch/blackfin/include/asm/ipipe.h new file mode 100644 index 000000000000..76f53d8b9a0d --- /dev/null +++ b/arch/blackfin/include/asm/ipipe.h @@ -0,0 +1,278 @@ +/* -*- linux-c -*- + * include/asm-blackfin/ipipe.h + * + * Copyright (C) 2002-2007 Philippe Gerum. + * + * 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, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ASM_BLACKFIN_IPIPE_H +#define __ASM_BLACKFIN_IPIPE_H + +#ifdef CONFIG_IPIPE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IPIPE_ARCH_STRING "1.8-00" +#define IPIPE_MAJOR_NUMBER 1 +#define IPIPE_MINOR_NUMBER 8 +#define IPIPE_PATCH_NUMBER 0 + +#ifdef CONFIG_SMP +#error "I-pipe/blackfin: SMP not implemented" +#else /* !CONFIG_SMP */ +#define ipipe_processor_id() 0 +#endif /* CONFIG_SMP */ + +#define prepare_arch_switch(next) \ +do { \ + ipipe_schedule_notify(current, next); \ + local_irq_disable_hw(); \ +} while (0) + +#define task_hijacked(p) \ + ({ \ + int __x__ = ipipe_current_domain != ipipe_root_domain; \ + /* We would need to clear the SYNC flag for the root domain */ \ + /* over the current processor in SMP mode. */ \ + local_irq_enable_hw(); __x__; \ + }) + +struct ipipe_domain; + +struct ipipe_sysinfo { + + int ncpus; /* Number of CPUs on board */ + u64 cpufreq; /* CPU frequency (in Hz) */ + + /* Arch-dependent block */ + + struct { + unsigned tmirq; /* Timer tick IRQ */ + u64 tmfreq; /* Timer frequency */ + } archdep; +}; + +#define ipipe_read_tsc(t) \ + ({ \ + unsigned long __cy2; \ + __asm__ __volatile__ ("1: %0 = CYCLES2\n" \ + "%1 = CYCLES\n" \ + "%2 = CYCLES2\n" \ + "CC = %2 == %0\n" \ + "if ! CC jump 1b\n" \ + : "=r" (((unsigned long *)&t)[1]), \ + "=r" (((unsigned long *)&t)[0]), \ + "=r" (__cy2) \ + : /*no input*/ : "CC"); \ + t; \ + }) + +#define ipipe_cpu_freq() __ipipe_core_clock +#define ipipe_tsc2ns(_t) (((unsigned long)(_t)) * __ipipe_freq_scale) +#define ipipe_tsc2us(_t) (ipipe_tsc2ns(_t) / 1000 + 1) + +/* Private interface -- Internal use only */ + +#define __ipipe_check_platform() do { } while (0) + +#define __ipipe_init_platform() do { } while (0) + +extern atomic_t __ipipe_irq_lvdepth[IVG15 + 1]; + +extern unsigned long __ipipe_irq_lvmask; + +extern struct ipipe_domain ipipe_root; + +/* enable/disable_irqdesc _must_ be used in pairs. */ + +void __ipipe_enable_irqdesc(struct ipipe_domain *ipd, + unsigned irq); + +void __ipipe_disable_irqdesc(struct ipipe_domain *ipd, + unsigned irq); + +#define __ipipe_enable_irq(irq) (irq_desc[irq].chip->unmask(irq)) + +#define __ipipe_disable_irq(irq) (irq_desc[irq].chip->mask(irq)) + +#define __ipipe_lock_root() \ + set_bit(IPIPE_ROOTLOCK_FLAG, &ipipe_root_domain->flags) + +#define __ipipe_unlock_root() \ + clear_bit(IPIPE_ROOTLOCK_FLAG, &ipipe_root_domain->flags) + +void __ipipe_enable_pipeline(void); + +#define __ipipe_hook_critical_ipi(ipd) do { } while (0) + +#define __ipipe_sync_pipeline(syncmask) \ + do { \ + struct ipipe_domain *ipd = ipipe_current_domain; \ + if (likely(ipd != ipipe_root_domain || !test_bit(IPIPE_ROOTLOCK_FLAG, &ipd->flags))) \ + __ipipe_sync_stage(syncmask); \ + } while (0) + +void __ipipe_handle_irq(unsigned irq, struct pt_regs *regs); + +int __ipipe_get_irq_priority(unsigned irq); + +int __ipipe_get_irqthread_priority(unsigned irq); + +void __ipipe_stall_root_raw(void); + +void __ipipe_unstall_root_raw(void); + +void __ipipe_serial_debug(const char *fmt, ...); + +DECLARE_PER_CPU(struct pt_regs, __ipipe_tick_regs); + +extern unsigned long __ipipe_core_clock; + +extern unsigned long __ipipe_freq_scale; + +extern unsigned long __ipipe_irq_tail_hook; + +static inline unsigned long __ipipe_ffnz(unsigned long ul) +{ + return ffs(ul) - 1; +} + +#define __ipipe_run_irqtail() /* Must be a macro */ \ + do { \ + asmlinkage void __ipipe_call_irqtail(void); \ + unsigned long __pending; \ + CSYNC(); \ + __pending = bfin_read_IPEND(); \ + if (__pending & 0x8000) { \ + __pending &= ~0x8010; \ + if (__pending && (__pending & (__pending - 1)) == 0) \ + __ipipe_call_irqtail(); \ + } \ + } while (0) + +#define __ipipe_run_isr(ipd, irq) \ + do { \ + if (ipd == ipipe_root_domain) { \ + /* \ + * Note: the I-pipe implements a threaded interrupt model on \ + * this arch for Linux external IRQs. The interrupt handler we \ + * call here only wakes up the associated IRQ thread. \ + */ \ + if (ipipe_virtual_irq_p(irq)) { \ + /* No irqtail here; virtual interrupts have no effect \ + on IPEND so there is no need for processing \ + deferral. */ \ + local_irq_enable_nohead(ipd); \ + ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \ + local_irq_disable_nohead(ipd); \ + } else \ + /* \ + * No need to run the irqtail here either; \ + * we can't be preempted by hw IRQs, so \ + * non-Linux IRQs cannot stack over the short \ + * thread wakeup code. Which in turn means \ + * that no irqtail condition could be pending \ + * for domains above Linux in the pipeline. \ + */ \ + ipd->irqs[irq].handler(irq, &__raw_get_cpu_var(__ipipe_tick_regs)); \ + } else { \ + __clear_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \ + local_irq_enable_nohead(ipd); \ + ipd->irqs[irq].handler(irq, ipd->irqs[irq].cookie); \ + /* Attempt to exit the outer interrupt level before \ + * starting the deferred IRQ processing. */ \ + local_irq_disable_nohead(ipd); \ + __ipipe_run_irqtail(); \ + __set_bit(IPIPE_SYNC_FLAG, &ipipe_cpudom_var(ipd, status)); \ + } \ + } while (0) + +#define __ipipe_syscall_watched_p(p, sc) \ + (((p)->flags & PF_EVNOTIFY) || (unsigned long)sc >= NR_syscalls) + +void ipipe_init_irq_threads(void); + +int ipipe_start_irq_thread(unsigned irq, struct irq_desc *desc); + +#define IS_SYSIRQ(irq) ((irq) > IRQ_CORETMR && (irq) <= SYS_IRQS) +#define IS_GPIOIRQ(irq) ((irq) >= GPIO_IRQ_BASE && (irq) < NR_IRQS) + +#define IRQ_SYSTMR IRQ_TIMER0 +#define IRQ_PRIOTMR CONFIG_IRQ_TIMER0 + +#if defined(CONFIG_BF531) || defined(CONFIG_BF532) || defined(CONFIG_BF533) +#define PRIO_GPIODEMUX(irq) CONFIG_PFA +#elif defined(CONFIG_BF534) || defined(CONFIG_BF536) || defined(CONFIG_BF537) +#define PRIO_GPIODEMUX(irq) CONFIG_IRQ_PROG_INTA +#elif defined(CONFIG_BF52x) +#define PRIO_GPIODEMUX(irq) ((irq) == IRQ_PORTF_INTA ? CONFIG_IRQ_PORTF_INTA : \ + (irq) == IRQ_PORTG_INTA ? CONFIG_IRQ_PORTG_INTA : \ + (irq) == IRQ_PORTH_INTA ? CONFIG_IRQ_PORTH_INTA : \ + -1) +#elif defined(CONFIG_BF561) +#define PRIO_GPIODEMUX(irq) ((irq) == IRQ_PROG0_INTA ? CONFIG_IRQ_PROG0_INTA : \ + (irq) == IRQ_PROG1_INTA ? CONFIG_IRQ_PROG1_INTA : \ + (irq) == IRQ_PROG2_INTA ? CONFIG_IRQ_PROG2_INTA : \ + -1) +#define bfin_write_TIMER_DISABLE(val) bfin_write_TMRS8_DISABLE(val) +#define bfin_write_TIMER_ENABLE(val) bfin_write_TMRS8_ENABLE(val) +#define bfin_write_TIMER_STATUS(val) bfin_write_TMRS8_STATUS(val) +#define bfin_read_TIMER_STATUS() bfin_read_TMRS8_STATUS() +#elif defined(CONFIG_BF54x) +#define PRIO_GPIODEMUX(irq) ((irq) == IRQ_PINT0 ? CONFIG_IRQ_PINT0 : \ + (irq) == IRQ_PINT1 ? CONFIG_IRQ_PINT1 : \ + (irq) == IRQ_PINT2 ? CONFIG_IRQ_PINT2 : \ + (irq) == IRQ_PINT3 ? CONFIG_IRQ_PINT3 : \ + -1) +#define bfin_write_TIMER_DISABLE(val) bfin_write_TIMER_DISABLE0(val) +#define bfin_write_TIMER_ENABLE(val) bfin_write_TIMER_ENABLE0(val) +#define bfin_write_TIMER_STATUS(val) bfin_write_TIMER_STATUS0(val) +#define bfin_read_TIMER_STATUS(val) bfin_read_TIMER_STATUS0(val) +#else +# error "no PRIO_GPIODEMUX() for this part" +#endif + +#define __ipipe_root_tick_p(regs) ((regs->ipend & 0x10) != 0) + +#else /* !CONFIG_IPIPE */ + +#define task_hijacked(p) 0 +#define ipipe_trap_notify(t, r) 0 + +#define __ipipe_stall_root_raw() do { } while (0) +#define __ipipe_unstall_root_raw() do { } while (0) + +#define ipipe_init_irq_threads() do { } while (0) +#define ipipe_start_irq_thread(irq, desc) 0 + +#define IRQ_SYSTMR IRQ_CORETMR +#define IRQ_PRIOTMR IRQ_CORETMR + +#define __ipipe_root_tick_p(regs) 1 + +#endif /* !CONFIG_IPIPE */ + +#endif /* !__ASM_BLACKFIN_IPIPE_H */ diff --git a/arch/blackfin/include/asm/ipipe_base.h b/arch/blackfin/include/asm/ipipe_base.h new file mode 100644 index 000000000000..cb1025aeabcf --- /dev/null +++ b/arch/blackfin/include/asm/ipipe_base.h @@ -0,0 +1,80 @@ +/* -*- linux-c -*- + * include/asm-blackfin/_baseipipe.h + * + * Copyright (C) 2007 Philippe Gerum. + * + * 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, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __ASM_BLACKFIN_IPIPE_BASE_H +#define __ASM_BLACKFIN_IPIPE_BASE_H + +#ifdef CONFIG_IPIPE + +#define IPIPE_NR_XIRQS NR_IRQS +#define IPIPE_IRQ_ISHIFT 5 /* 2^5 for 32bits arch. */ + +/* Blackfin-specific, global domain flags */ +#define IPIPE_ROOTLOCK_FLAG 1 /* Lock pipeline for root */ + + /* Blackfin traps -- i.e. exception vector numbers */ +#define IPIPE_NR_FAULTS 52 /* We leave a gap after VEC_ILL_RES. */ +/* Pseudo-vectors used for kernel events */ +#define IPIPE_FIRST_EVENT IPIPE_NR_FAULTS +#define IPIPE_EVENT_SYSCALL (IPIPE_FIRST_EVENT) +#define IPIPE_EVENT_SCHEDULE (IPIPE_FIRST_EVENT + 1) +#define IPIPE_EVENT_SIGWAKE (IPIPE_FIRST_EVENT + 2) +#define IPIPE_EVENT_SETSCHED (IPIPE_FIRST_EVENT + 3) +#define IPIPE_EVENT_INIT (IPIPE_FIRST_EVENT + 4) +#define IPIPE_EVENT_EXIT (IPIPE_FIRST_EVENT + 5) +#define IPIPE_EVENT_CLEANUP (IPIPE_FIRST_EVENT + 6) +#define IPIPE_LAST_EVENT IPIPE_EVENT_CLEANUP +#define IPIPE_NR_EVENTS (IPIPE_LAST_EVENT + 1) + +#define IPIPE_TIMER_IRQ IRQ_CORETMR + +#ifndef __ASSEMBLY__ + +#include + +extern int test_bit(int nr, const void *addr); + + +extern unsigned long __ipipe_root_status; /* Alias to ipipe_root_cpudom_var(status) */ + +static inline void __ipipe_stall_root(void) +{ + volatile unsigned long *p = &__ipipe_root_status; + set_bit(0, p); +} + +static inline unsigned long __ipipe_test_and_stall_root(void) +{ + volatile unsigned long *p = &__ipipe_root_status; + return test_and_set_bit(0, p); +} + +static inline unsigned long __ipipe_test_root(void) +{ + const unsigned long *p = &__ipipe_root_status; + return test_bit(0, p); +} + +#endif /* !__ASSEMBLY__ */ + +#endif /* CONFIG_IPIPE */ + +#endif /* !__ASM_BLACKFIN_IPIPE_BASE_H */ diff --git a/arch/blackfin/include/asm/irq.h b/arch/blackfin/include/asm/irq.h index 21e25f778a63..3d977909ce7d 100644 --- a/arch/blackfin/include/asm/irq.h +++ b/arch/blackfin/include/asm/irq.h @@ -22,11 +22,176 @@ #include #include -static __inline__ int irq_canonicalize(int irq) +#ifdef CONFIG_SMP +/* Forward decl needed due to cdef inter dependencies */ +static inline uint32_t __pure bfin_dspid(void); +# define blackfin_core_id() (bfin_dspid() & 0xff) +# define bfin_irq_flags cpu_pda[blackfin_core_id()].imask +#else +extern unsigned long bfin_irq_flags; +#endif + +#ifdef CONFIG_IPIPE + +#include + +void __ipipe_unstall_root(void); + +void __ipipe_restore_root(unsigned long flags); + +#ifdef CONFIG_DEBUG_HWERR +# define __all_masked_irq_flags 0x3f +# define __save_and_cli_hw(x) \ + __asm__ __volatile__( \ + "cli %0;" \ + "sti %1;" \ + : "=&d"(x) \ + : "d" (0x3F) \ + ) +#else +# define __all_masked_irq_flags 0x1f +# define __save_and_cli_hw(x) \ + __asm__ __volatile__( \ + "cli %0;" \ + : "=&d"(x) \ + ) +#endif + +#define irqs_enabled_from_flags_hw(x) ((x) != __all_masked_irq_flags) +#define raw_irqs_disabled_flags(flags) (!irqs_enabled_from_flags_hw(flags)) +#define local_test_iflag_hw(x) irqs_enabled_from_flags_hw(x) + +#define local_save_flags(x) \ + do { \ + (x) = __ipipe_test_root() ? \ + __all_masked_irq_flags : bfin_irq_flags; \ + } while (0) + +#define local_irq_save(x) \ + do { \ + (x) = __ipipe_test_and_stall_root(); \ + } while (0) + +#define local_irq_restore(x) __ipipe_restore_root(x) +#define local_irq_disable() __ipipe_stall_root() +#define local_irq_enable() __ipipe_unstall_root() +#define irqs_disabled() __ipipe_test_root() + +#define local_save_flags_hw(x) \ + __asm__ __volatile__( \ + "cli %0;" \ + "sti %0;" \ + : "=d"(x) \ + ) + +#define irqs_disabled_hw() \ + ({ \ + unsigned long flags; \ + local_save_flags_hw(flags); \ + !irqs_enabled_from_flags_hw(flags); \ + }) + +static inline unsigned long raw_mangle_irq_bits(int virt, unsigned long real) { - return irq; + /* Merge virtual and real interrupt mask bits into a single + 32bit word. */ + return (real & ~(1 << 31)) | ((virt != 0) << 31); } +static inline int raw_demangle_irq_bits(unsigned long *x) +{ + int virt = (*x & (1 << 31)) != 0; + *x &= ~(1L << 31); + return virt; +} + +#ifdef CONFIG_IPIPE_TRACE_IRQSOFF + +#define local_irq_disable_hw() \ + do { \ + int _tmp_dummy; \ + if (!irqs_disabled_hw()) \ + ipipe_trace_begin(0x80000000); \ + __asm__ __volatile__ ("cli %0;" : "=d" (_tmp_dummy) : ); \ + } while (0) + +#define local_irq_enable_hw() \ + do { \ + if (irqs_disabled_hw()) \ + ipipe_trace_end(0x80000000); \ + __asm__ __volatile__ ("sti %0;" : : "d"(bfin_irq_flags)); \ + } while (0) + +#define local_irq_save_hw(x) \ + do { \ + __save_and_cli_hw(x); \ + if (local_test_iflag_hw(x)) \ + ipipe_trace_begin(0x80000001); \ + } while (0) + +#define local_irq_restore_hw(x) \ + do { \ + if (local_test_iflag_hw(x)) { \ + ipipe_trace_end(0x80000001); \ + local_irq_enable_hw_notrace(); \ + } \ + } while (0) + +#define local_irq_disable_hw_notrace() \ + do { \ + int _tmp_dummy; \ + __asm__ __volatile__ ("cli %0;" : "=d" (_tmp_dummy) : ); \ + } while (0) + +#define local_irq_enable_hw_notrace() \ + __asm__ __volatile__( \ + "sti %0;" \ + : \ + : "d"(bfin_irq_flags) \ + ) + +#define local_irq_save_hw_notrace(x) __save_and_cli_hw(x) + +#define local_irq_restore_hw_notrace(x) \ + do { \ + if (local_test_iflag_hw(x)) \ + local_irq_enable_hw_notrace(); \ + } while (0) + +#else /* CONFIG_IPIPE_TRACE_IRQSOFF */ + +#define local_irq_enable_hw() \ + __asm__ __volatile__( \ + "sti %0;" \ + : \ + : "d"(bfin_irq_flags) \ + ) + +#define local_irq_disable_hw() \ + do { \ + int _tmp_dummy; \ + __asm__ __volatile__ ( \ + "cli %0;" \ + : "=d" (_tmp_dummy)); \ + } while (0) + +#define local_irq_restore_hw(x) \ + do { \ + if (irqs_enabled_from_flags_hw(x)) \ + local_irq_enable_hw(); \ + } while (0) + +#define local_irq_save_hw(x) __save_and_cli_hw(x) + +#define local_irq_disable_hw_notrace() local_irq_disable_hw() +#define local_irq_enable_hw_notrace() local_irq_enable_hw() +#define local_irq_save_hw_notrace(x) local_irq_save_hw(x) +#define local_irq_restore_hw_notrace(x) local_irq_restore_hw(x) + +#endif /* CONFIG_IPIPE_TRACE_IRQSOFF */ + +#else /* !CONFIG_IPIPE */ + /* * Interrupt configuring macros. */ @@ -39,21 +204,6 @@ static __inline__ int irq_canonicalize(int irq) ); \ } while (0) -#if ANOMALY_05000244 && defined(CONFIG_BFIN_ICACHE) -# define NOP_PAD_ANOMALY_05000244 "nop; nop;" -#else -# define NOP_PAD_ANOMALY_05000244 -#endif - -#ifdef CONFIG_SMP -/* Forward decl needed due to cdef inter dependencies */ -static inline uint32_t __pure bfin_dspid(void); -# define blackfin_core_id() (bfin_dspid() & 0xff) -# define bfin_irq_flags cpu_pda[blackfin_core_id()].imask -#else -extern unsigned long bfin_irq_flags; -#endif - #define local_irq_enable() \ __asm__ __volatile__( \ "sti %0;" \ @@ -61,16 +211,6 @@ extern unsigned long bfin_irq_flags; : "d" (bfin_irq_flags) \ ) -#define idle_with_irq_disabled() \ - __asm__ __volatile__( \ - NOP_PAD_ANOMALY_05000244 \ - ".align 8;" \ - "sti %0;" \ - "idle;" \ - : \ - : "d" (bfin_irq_flags) \ - ) - #ifdef CONFIG_DEBUG_HWERR # define __save_and_cli(x) \ __asm__ __volatile__( \ @@ -116,4 +256,33 @@ extern unsigned long bfin_irq_flags; !irqs_enabled_from_flags(flags); \ }) +#define local_irq_save_hw(x) local_irq_save(x) +#define local_irq_restore_hw(x) local_irq_restore(x) +#define local_irq_enable_hw() local_irq_enable() +#define local_irq_disable_hw() local_irq_disable() +#define irqs_disabled_hw() irqs_disabled() + +#endif /* !CONFIG_IPIPE */ + +#if ANOMALY_05000244 && defined(CONFIG_BFIN_ICACHE) +# define NOP_PAD_ANOMALY_05000244 "nop; nop;" +#else +# define NOP_PAD_ANOMALY_05000244 +#endif + +#define idle_with_irq_disabled() \ + __asm__ __volatile__( \ + NOP_PAD_ANOMALY_05000244 \ + ".align 8;" \ + "sti %0;" \ + "idle;" \ + : \ + : "d" (bfin_irq_flags) \ + ) + +static inline int irq_canonicalize(int irq) +{ + return irq; +} + #endif /* _BFIN_IRQ_H_ */ diff --git a/arch/blackfin/include/asm/system.h b/arch/blackfin/include/asm/system.h index 812e6e6e2cee..a4c8254bec55 100644 --- a/arch/blackfin/include/asm/system.h +++ b/arch/blackfin/include/asm/system.h @@ -141,7 +141,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, unsigned long tmp = 0; unsigned long flags = 0; - local_irq_save(flags); + local_irq_save_hw(flags); switch (size) { case 1: @@ -163,7 +163,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, : "=&d" (tmp) : "d" (x), "m" (*__xg(ptr)) : "memory"); break; } - local_irq_restore(flags); + local_irq_restore_hw(flags); return tmp; } diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index f0902c120dc2..38a233374f07 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile @@ -15,6 +15,8 @@ else obj-y += time.o endif +obj-$(CONFIG_IPIPE) += ipipe.o +obj-$(CONFIG_IPIPE_TRACE_MCOUNT) += mcount.o obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o obj-$(CONFIG_CPLB_INFO) += cplbinfo.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index 2c72b15b71b0..4c14331978f6 100644 --- a/arch/blackfin/kernel/bfin_gpio.c +++ b/arch/blackfin/kernel/bfin_gpio.c @@ -422,13 +422,13 @@ arch_initcall(bfin_gpio_init); void set_gpio_ ## name(unsigned gpio, unsigned short arg) \ { \ unsigned long flags; \ - local_irq_save(flags); \ + local_irq_save_hw(flags); \ if (arg) \ gpio_bankb[gpio_bank(gpio)]->name |= gpio_bit(gpio); \ else \ gpio_bankb[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \ AWA_DUMMY_READ(name); \ - local_irq_restore(flags); \ + local_irq_restore_hw(flags); \ } \ EXPORT_SYMBOL(set_gpio_ ## name); @@ -444,13 +444,13 @@ SET_GPIO(both) void set_gpio_ ## name(unsigned gpio, unsigned short arg) \ { \ unsigned long flags; \ - local_irq_save(flags); \ + local_irq_save_hw(flags); \ if (arg) \ gpio_bankb[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \ else \ gpio_bankb[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \ AWA_DUMMY_READ(name); \ - local_irq_restore(flags); \ + local_irq_restore_hw(flags); \ } \ EXPORT_SYMBOL(set_gpio_ ## name); #else @@ -473,10 +473,10 @@ SET_GPIO_SC(data) void set_gpio_toggle(unsigned gpio) { unsigned long flags; - local_irq_save(flags); + local_irq_save_hw(flags); gpio_bankb[gpio_bank(gpio)]->toggle = gpio_bit(gpio); AWA_DUMMY_READ(toggle); - local_irq_restore(flags); + local_irq_restore_hw(flags); } #else void set_gpio_toggle(unsigned gpio) @@ -494,10 +494,10 @@ EXPORT_SYMBOL(set_gpio_toggle); void set_gpiop_ ## name(unsigned gpio, unsigned short arg) \ { \ unsigned long flags; \ - local_irq_save(flags); \ + local_irq_save_hw(flags); \ gpio_bankb[gpio_bank(gpio)]->name = arg; \ AWA_DUMMY_READ(name); \ - local_irq_restore(flags); \ + local_irq_restore_hw(flags); \ } \ EXPORT_SYMBOL(set_gpiop_ ## name); #else @@ -525,10 +525,10 @@ unsigned short get_gpio_ ## name(unsigned gpio) \ { \ unsigned long flags; \ unsigned short ret; \ - local_irq_save(flags); \ + local_irq_save_hw(flags); \ ret = 0x01 & (gpio_bankb[gpio_bank(gpio)]->name >> gpio_sub_n(gpio)); \ AWA_DUMMY_READ(name); \ - local_irq_restore(flags); \ + local_irq_restore_hw(flags); \ return ret; \ } \ EXPORT_SYMBOL(get_gpio_ ## name); @@ -558,10 +558,10 @@ unsigned short get_gpiop_ ## name(unsigned gpio) \ { \ unsigned long flags; \ unsigned short ret; \ - local_irq_save(flags); \ + local_irq_save_hw(flags); \ ret = (gpio_bankb[gpio_bank(gpio)]->name); \ AWA_DUMMY_READ(name); \ - local_irq_restore(flags); \ + local_irq_restore_hw(flags); \ return ret; \ } \ EXPORT_SYMBOL(get_gpiop_ ## name); @@ -611,10 +611,10 @@ int gpio_pm_wakeup_request(unsigned gpio, unsigned char type) if ((check_gpio(gpio) < 0) || !type) return -EINVAL; - local_irq_save(flags); + local_irq_save_hw(flags); wakeup_map[gpio_bank(gpio)] |= gpio_bit(gpio); wakeup_flags_map[gpio] = type; - local_irq_restore(flags); + local_irq_restore_hw(flags); return 0; } @@ -627,11 +627,11 @@ void gpio_pm_wakeup_free(unsigned gpio) if (check_gpio(gpio) < 0) return; - local_irq_save(flags); + local_irq_save_hw(flags); wakeup_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); - local_irq_restore(flags); + local_irq_restore_hw(flags); } EXPORT_SYMBOL(gpio_pm_wakeup_free); @@ -882,7 +882,7 @@ int peripheral_request(unsigned short per, const char *label) if (!(per & P_DEFINED)) return -ENODEV; - local_irq_save(flags); + local_irq_save_hw(flags); /* If a pin can be muxed as either GPIO or peripheral, make * sure it is not already a GPIO pin when we request it. @@ -893,7 +893,7 @@ int peripheral_request(unsigned short per, const char *label) printk(KERN_ERR "%s: Peripheral %d is already reserved as GPIO by %s !\n", __func__, ident, get_label(ident)); - local_irq_restore(flags); + local_irq_restore_hw(flags); return -EBUSY; } @@ -923,7 +923,7 @@ int peripheral_request(unsigned short per, const char *label) printk(KERN_ERR "%s: Peripheral %d function %d is already reserved by %s !\n", __func__, ident, P_FUNCT2MUX(per), get_label(ident)); - local_irq_restore(flags); + local_irq_restore_hw(flags); return -EBUSY; } } @@ -938,7 +938,7 @@ int peripheral_request(unsigned short per, const char *label) #endif port_setup(ident, PERIPHERAL_USAGE); - local_irq_restore(flags); + local_irq_restore_hw(flags); set_label(ident, label); return 0; @@ -980,10 +980,10 @@ void peripheral_free(unsigned short per) if (check_gpio(ident) < 0) return; - local_irq_save(flags); + local_irq_save_hw(flags); if (unlikely(!(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident)))) { - local_irq_restore(flags); + local_irq_restore_hw(flags); return; } @@ -994,7 +994,7 @@ void peripheral_free(unsigned short per) set_label(ident, "free"); - local_irq_restore(flags); + local_irq_restore_hw(flags); } EXPORT_SYMBOL(peripheral_free); @@ -1028,7 +1028,7 @@ int bfin_gpio_request(unsigned gpio, const char *label) if (check_gpio(gpio) < 0) return -EINVAL; - local_irq_save(flags); + local_irq_save_hw(flags); /* * Allow that the identical GPIO can @@ -1037,7 +1037,7 @@ int bfin_gpio_request(unsigned gpio, const char *label) */ if (cmp_label(gpio, label) == 0) { - local_irq_restore(flags); + local_irq_restore_hw(flags); return 0; } @@ -1045,7 +1045,7 @@ int bfin_gpio_request(unsigned gpio, const char *label) dump_stack(); printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", gpio, get_label(gpio)); - local_irq_restore(flags); + local_irq_restore_hw(flags); return -EBUSY; } if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { @@ -1053,7 +1053,7 @@ int bfin_gpio_request(unsigned gpio, const char *label) printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", gpio, get_label(gpio)); - local_irq_restore(flags); + local_irq_restore_hw(flags); return -EBUSY; } if (unlikely(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio))) @@ -1063,7 +1063,7 @@ int bfin_gpio_request(unsigned gpio, const char *label) reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio); set_label(gpio, label); - local_irq_restore(flags); + local_irq_restore_hw(flags); port_setup(gpio, GPIO_USAGE); @@ -1078,12 +1078,12 @@ void bfin_gpio_free(unsigned gpio) if (check_gpio(gpio) < 0) return; - local_irq_save(flags); + local_irq_save_hw(flags); if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) { dump_stack(); gpio_error(gpio); - local_irq_restore(flags); + local_irq_restore_hw(flags); return; } @@ -1091,7 +1091,7 @@ void bfin_gpio_free(unsigned gpio) set_label(gpio, "free"); - local_irq_restore(flags); + local_irq_restore_hw(flags); } EXPORT_SYMBOL(bfin_gpio_free); @@ -1102,14 +1102,14 @@ int bfin_gpio_irq_request(unsigned gpio, const char *label) if (check_gpio(gpio) < 0) return -EINVAL; - local_irq_save(flags); + local_irq_save_hw(flags); if (unlikely(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio))) { dump_stack(); printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved as gpio-irq !\n", gpio); - local_irq_restore(flags); + local_irq_restore_hw(flags); return -EBUSY; } if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { @@ -1117,7 +1117,7 @@ int bfin_gpio_irq_request(unsigned gpio, const char *label) printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", gpio, get_label(gpio)); - local_irq_restore(flags); + local_irq_restore_hw(flags); return -EBUSY; } if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) @@ -1128,7 +1128,7 @@ int bfin_gpio_irq_request(unsigned gpio, const char *label) reserved_gpio_irq_map[gpio_bank(gpio)] |= gpio_bit(gpio); set_label(gpio, label); - local_irq_restore(flags); + local_irq_restore_hw(flags); port_setup(gpio, GPIO_USAGE); @@ -1142,12 +1142,12 @@ void bfin_gpio_irq_free(unsigned gpio) if (check_gpio(gpio) < 0) return; - local_irq_save(flags); + local_irq_save_hw(flags); if (unlikely(!(reserved_gpio_irq_map[gpio_bank(gpio)] & gpio_bit(gpio)))) { dump_stack(); gpio_error(gpio); - local_irq_restore(flags); + local_irq_restore_hw(flags); return; } @@ -1155,7 +1155,7 @@ void bfin_gpio_irq_free(unsigned gpio) set_label(gpio, "free"); - local_irq_restore(flags); + local_irq_restore_hw(flags); } @@ -1169,10 +1169,10 @@ int bfin_gpio_direction_input(unsigned gpio) return -EINVAL; } - local_irq_save(flags); + local_irq_save_hw(flags); gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio); gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio); - local_irq_restore(flags); + local_irq_restore_hw(flags); return 0; } @@ -1187,11 +1187,11 @@ int bfin_gpio_direction_output(unsigned gpio, int value) return -EINVAL; } - local_irq_save(flags); + local_irq_save_hw(flags); gpio_array[gpio_bank(gpio)]->port_inen &= ~gpio_bit(gpio); gpio_set_value(gpio, value); gpio_array[gpio_bank(gpio)]->port_dir_set = gpio_bit(gpio); - local_irq_restore(flags); + local_irq_restore_hw(flags); return 0; } @@ -1218,10 +1218,10 @@ void bfin_gpio_irq_prepare(unsigned gpio) port_setup(gpio, GPIO_USAGE); - local_irq_save(flags); + local_irq_save_hw(flags); gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio); gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio); - local_irq_restore(flags); + local_irq_restore_hw(flags); } #else @@ -1232,11 +1232,11 @@ int bfin_gpio_get_value(unsigned gpio) int ret; if (unlikely(get_gpio_edge(gpio))) { - local_irq_save(flags); + local_irq_save_hw(flags); set_gpio_edge(gpio, 0); ret = get_gpio_data(gpio); set_gpio_edge(gpio, 1); - local_irq_restore(flags); + local_irq_restore_hw(flags); return ret; } else @@ -1254,11 +1254,11 @@ int bfin_gpio_direction_input(unsigned gpio) return -EINVAL; } - local_irq_save(flags); + local_irq_save_hw(flags); gpio_bankb[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio); gpio_bankb[gpio_bank(gpio)]->inen |= gpio_bit(gpio); AWA_DUMMY_READ(inen); - local_irq_restore(flags); + local_irq_restore_hw(flags); return 0; } @@ -1273,7 +1273,7 @@ int bfin_gpio_direction_output(unsigned gpio, int value) return -EINVAL; } - local_irq_save(flags); + local_irq_save_hw(flags); gpio_bankb[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio); if (value) @@ -1283,7 +1283,7 @@ int bfin_gpio_direction_output(unsigned gpio, int value) gpio_bankb[gpio_bank(gpio)]->dir |= gpio_bit(gpio); AWA_DUMMY_READ(dir); - local_irq_restore(flags); + local_irq_restore_hw(flags); return 0; } diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c index 5ef5d1a787fc..87463ce87f5a 100644 --- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c +++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c @@ -332,7 +332,7 @@ void flush_switched_cplbs(unsigned int cpu) nr_cplb_flush[cpu]++; - local_irq_save(flags); + local_irq_save_hw(flags); disable_icplb(); for (i = first_switched_icplb; i < MAX_CPLBS; i++) { icplb_tbl[cpu][i].data = 0; @@ -346,7 +346,7 @@ void flush_switched_cplbs(unsigned int cpu) bfin_write32(DCPLB_DATA0 + i * 4, 0); } enable_dcplb(); - local_irq_restore(flags); + local_irq_restore_hw(flags); } @@ -362,7 +362,7 @@ void set_mask_dcplbs(unsigned long *masks, unsigned int cpu) return; } - local_irq_save(flags); + local_irq_save_hw(flags); current_rwx_mask[cpu] = masks; d_data = CPLB_SUPV_WR | CPLB_VALID | CPLB_DIRTY | PAGE_SIZE_4KB; @@ -382,5 +382,5 @@ void set_mask_dcplbs(unsigned long *masks, unsigned int cpu) addr += PAGE_SIZE; } enable_dcplb(); - local_irq_restore(flags); + local_irq_restore_hw(flags); } diff --git a/arch/blackfin/kernel/entry.S b/arch/blackfin/kernel/entry.S index c0c3fe811228..a9cfba9946b5 100644 --- a/arch/blackfin/kernel/entry.S +++ b/arch/blackfin/kernel/entry.S @@ -42,6 +42,10 @@ #endif ENTRY(_ret_from_fork) +#ifdef CONFIG_IPIPE + [--sp] = reti; /* IRQs on. */ + SP += 4; +#endif /* CONFIG_IPIPE */ SP += -12; call _schedule_tail; SP += 12; diff --git a/arch/blackfin/kernel/ipipe.c b/arch/blackfin/kernel/ipipe.c new file mode 100644 index 000000000000..339be5a3ae6a --- /dev/null +++ b/arch/blackfin/kernel/ipipe.c @@ -0,0 +1,428 @@ +/* -*- linux-c -*- + * linux/arch/blackfin/kernel/ipipe.c + * + * Copyright (C) 2005-2007 Philippe Gerum. + * + * 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, Inc., 675 Mass Ave, Cambridge MA 02139, + * USA; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * Architecture-dependent I-pipe support for the Blackfin. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int create_irq_threads; + +DEFINE_PER_CPU(struct pt_regs, __ipipe_tick_regs); + +static DEFINE_PER_CPU(unsigned long, pending_irqthread_mask); + +static DEFINE_PER_CPU(int [IVG13 + 1], pending_irq_count); + +asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs); + +static void __ipipe_no_irqtail(void); + +unsigned long __ipipe_irq_tail_hook = (unsigned long)&__ipipe_no_irqtail; +EXPORT_SYMBOL(__ipipe_irq_tail_hook); + +unsigned long __ipipe_core_clock; +EXPORT_SYMBOL(__ipipe_core_clock); + +unsigned long __ipipe_freq_scale; +EXPORT_SYMBOL(__ipipe_freq_scale); + +atomic_t __ipipe_irq_lvdepth[IVG15 + 1]; + +unsigned long __ipipe_irq_lvmask = __all_masked_irq_flags; +EXPORT_SYMBOL(__ipipe_irq_lvmask); + +static void __ipipe_ack_irq(unsigned irq, struct irq_desc *desc) +{ + desc->ipipe_ack(irq, desc); +} + +/* + * __ipipe_enable_pipeline() -- We are running on the boot CPU, hw + * interrupts are off, and secondary CPUs are still lost in space. + */ +void __ipipe_enable_pipeline(void) +{ + unsigned irq; + + __ipipe_core_clock = get_cclk(); /* Fetch this once. */ + __ipipe_freq_scale = 1000000000UL / __ipipe_core_clock; + + for (irq = 0; irq < NR_IRQS; ++irq) + ipipe_virtualize_irq(ipipe_root_domain, + irq, + (ipipe_irq_handler_t)&asm_do_IRQ, + NULL, + &__ipipe_ack_irq, + IPIPE_HANDLE_MASK | IPIPE_PASS_MASK); +} + +/* + * __ipipe_handle_irq() -- IPIPE's generic IRQ handler. An optimistic + * interrupt protection log is maintained here for each domain. Hw + * interrupts are masked on entry. + */ +void __ipipe_handle_irq(unsigned irq, struct pt_regs *regs) +{ + struct ipipe_domain *this_domain, *next_domain; + struct list_head *head, *pos; + int m_ack, s = -1; + + /* + * Software-triggered IRQs do not need any ack. The contents + * of the register frame should only be used when processing + * the timer interrupt, but not for handling any other + * interrupt. + */ + m_ack = (regs == NULL || irq == IRQ_SYSTMR || irq == IRQ_CORETMR); + + this_domain = ipipe_current_domain; + + if (unlikely(test_bit(IPIPE_STICKY_FLAG, &this_domain->irqs[irq].control))) + head = &this_domain->p_link; + else { + head = __ipipe_pipeline.next; + next_domain = list_entry(head, struct ipipe_domain, p_link); + if (likely(test_bit(IPIPE_WIRED_FLAG, &next_domain->irqs[irq].control))) { + if (!m_ack && next_domain->irqs[irq].acknowledge != NULL) + next_domain->irqs[irq].acknowledge(irq, irq_desc + irq); + if (test_bit(IPIPE_ROOTLOCK_FLAG, &ipipe_root_domain->flags)) + s = __test_and_set_bit(IPIPE_STALL_FLAG, + &ipipe_root_cpudom_var(status)); + __ipipe_dispatch_wired(next_domain, irq); + goto finalize; + return; + } + } + + /* Ack the interrupt. */ + + pos = head; + + while (pos != &__ipipe_pipeline) { + next_domain = list_entry(pos, struct ipipe_domain, p_link); + /* + * For each domain handling the incoming IRQ, mark it + * as pending in its log. + */ + if (test_bit(IPIPE_HANDLE_FLAG, &next_domain->irqs[irq].control)) { + /* + * Domains that handle this IRQ are polled for + * acknowledging it by decreasing priority + * order. The interrupt must be made pending + * _first_ in the domain's status flags before + * the PIC is unlocked. + */ + __ipipe_set_irq_pending(next_domain, irq); + + if (!m_ack && next_domain->irqs[irq].acknowledge != NULL) { + next_domain->irqs[irq].acknowledge(irq, irq_desc + irq); + m_ack = 1; + } + } + + /* + * If the domain does not want the IRQ to be passed + * down the interrupt pipe, exit the loop now. + */ + if (!test_bit(IPIPE_PASS_FLAG, &next_domain->irqs[irq].control)) + break; + + pos = next_domain->p_link.next; + } + + /* + * Now walk the pipeline, yielding control to the highest + * priority domain that has pending interrupt(s) or + * immediately to the current domain if the interrupt has been + * marked as 'sticky'. This search does not go beyond the + * current domain in the pipeline. We also enforce the + * additional root stage lock (blackfin-specific). */ + + if (test_bit(IPIPE_ROOTLOCK_FLAG, &ipipe_root_domain->flags)) + s = __test_and_set_bit(IPIPE_STALL_FLAG, + &ipipe_root_cpudom_var(status)); +finalize: + + __ipipe_walk_pipeline(head); + + if (!s) + __clear_bit(IPIPE_STALL_FLAG, + &ipipe_root_cpudom_var(status)); +} + +int __ipipe_check_root(void) +{ + return ipipe_root_domain_p; +} + +void __ipipe_enable_irqdesc(struct ipipe_domain *ipd, unsigned irq) +{ + struct irq_desc *desc = irq_desc + irq; + int prio = desc->ic_prio; + + desc->depth = 0; + if (ipd != &ipipe_root && + atomic_inc_return(&__ipipe_irq_lvdepth[prio]) == 1) + __set_bit(prio, &__ipipe_irq_lvmask); +} +EXPORT_SYMBOL(__ipipe_enable_irqdesc); + +void __ipipe_disable_irqdesc(struct ipipe_domain *ipd, unsigned irq) +{ + struct irq_desc *desc = irq_desc + irq; + int prio = desc->ic_prio; + + if (ipd != &ipipe_root && + atomic_dec_and_test(&__ipipe_irq_lvdepth[prio])) + __clear_bit(prio, &__ipipe_irq_lvmask); +} +EXPORT_SYMBOL(__ipipe_disable_irqdesc); + +void __ipipe_stall_root_raw(void) +{ + /* + * This code is called by the ins{bwl} routines (see + * arch/blackfin/lib/ins.S), which are heavily used by the + * network stack. It masks all interrupts but those handled by + * non-root domains, so that we keep decent network transfer + * rates for Linux without inducing pathological jitter for + * the real-time domain. + */ + __asm__ __volatile__ ("sti %0;" : : "d"(__ipipe_irq_lvmask)); + + __set_bit(IPIPE_STALL_FLAG, + &ipipe_root_cpudom_var(status)); +} + +void __ipipe_unstall_root_raw(void) +{ + __clear_bit(IPIPE_STALL_FLAG, + &ipipe_root_cpudom_var(status)); + + __asm__ __volatile__ ("sti %0;" : : "d"(bfin_irq_flags)); +} + +int __ipipe_syscall_root(struct pt_regs *regs) +{ + unsigned long flags; + + /* We need to run the IRQ tail hook whenever we don't + * propagate a syscall to higher domains, because we know that + * important operations might be pending there (e.g. Xenomai + * deferred rescheduling). */ + + if (!__ipipe_syscall_watched_p(current, regs->orig_p0)) { + void (*hook)(void) = (void (*)(void))__ipipe_irq_tail_hook; + hook(); + return 0; + } + + /* + * This routine either returns: + * 0 -- if the syscall is to be passed to Linux; + * 1 -- if the syscall should not be passed to Linux, and no + * tail work should be performed; + * -1 -- if the syscall should not be passed to Linux but the + * tail work has to be performed (for handling signals etc). + */ + + if (__ipipe_event_monitored_p(IPIPE_EVENT_SYSCALL) && + __ipipe_dispatch_event(IPIPE_EVENT_SYSCALL, regs) > 0) { + if (ipipe_root_domain_p && !in_atomic()) { + /* + * Sync pending VIRQs before _TIF_NEED_RESCHED + * is tested. + */ + local_irq_save_hw(flags); + if ((ipipe_root_cpudom_var(irqpend_himask) & IPIPE_IRQMASK_VIRT) != 0) + __ipipe_sync_pipeline(IPIPE_IRQMASK_VIRT); + local_irq_restore_hw(flags); + return -1; + } + return 1; + } + + return 0; +} + +unsigned long ipipe_critical_enter(void (*syncfn) (void)) +{ + unsigned long flags; + + local_irq_save_hw(flags); + + return flags; +} + +void ipipe_critical_exit(unsigned long flags) +{ + local_irq_restore_hw(flags); +} + +static void __ipipe_no_irqtail(void) +{ +} + +int ipipe_get_sysinfo(struct ipipe_sysinfo *info) +{ + info->ncpus = num_online_cpus(); + info->cpufreq = ipipe_cpu_freq(); + info->archdep.tmirq = IPIPE_TIMER_IRQ; + info->archdep.tmfreq = info->cpufreq; + + return 0; +} + +/* + * ipipe_trigger_irq() -- Push the interrupt at front of the pipeline + * just like if it has been actually received from a hw source. Also + * works for virtual interrupts. + */ +int ipipe_trigger_irq(unsigned irq) +{ + unsigned long flags; + + if (irq >= IPIPE_NR_IRQS || + (ipipe_virtual_irq_p(irq) + && !test_bit(irq - IPIPE_VIRQ_BASE, &__ipipe_virtual_irq_map))) + return -EINVAL; + + local_irq_save_hw(flags); + + __ipipe_handle_irq(irq, NULL); + + local_irq_restore_hw(flags); + + return 1; +} + +/* Move Linux IRQ to threads. */ + +static int do_irqd(void *__desc) +{ + struct irq_desc *desc = __desc; + unsigned irq = desc - irq_desc; + int thrprio = desc->thr_prio; + int thrmask = 1 << thrprio; + int cpu = smp_processor_id(); + cpumask_t cpumask; + + sigfillset(¤t->blocked); + current->flags |= PF_NOFREEZE; + cpumask = cpumask_of_cpu(cpu); + set_cpus_allowed(current, cpumask); + ipipe_setscheduler_root(current, SCHED_FIFO, 50 + thrprio); + + while (!kthread_should_stop()) { + local_irq_disable(); + if (!(desc->status & IRQ_SCHEDULED)) { + set_current_state(TASK_INTERRUPTIBLE); +resched: + local_irq_enable(); + schedule(); + local_irq_disable(); + } + __set_current_state(TASK_RUNNING); + /* + * If higher priority interrupt servers are ready to + * run, reschedule immediately. We need this for the + * GPIO demux IRQ handler to unmask the interrupt line + * _last_, after all GPIO IRQs have run. + */ + if (per_cpu(pending_irqthread_mask, cpu) & ~(thrmask|(thrmask-1))) + goto resched; + if (--per_cpu(pending_irq_count[thrprio], cpu) == 0) + per_cpu(pending_irqthread_mask, cpu) &= ~thrmask; + desc->status &= ~IRQ_SCHEDULED; + desc->thr_handler(irq, &__raw_get_cpu_var(__ipipe_tick_regs)); + local_irq_enable(); + } + __set_current_state(TASK_RUNNING); + return 0; +} + +static void kick_irqd(unsigned irq, void *cookie) +{ + struct irq_desc *desc = irq_desc + irq; + int thrprio = desc->thr_prio; + int thrmask = 1 << thrprio; + int cpu = smp_processor_id(); + + if (!(desc->status & IRQ_SCHEDULED)) { + desc->status |= IRQ_SCHEDULED; + per_cpu(pending_irqthread_mask, cpu) |= thrmask; + ++per_cpu(pending_irq_count[thrprio], cpu); + wake_up_process(desc->thread); + } +} + +int ipipe_start_irq_thread(unsigned irq, struct irq_desc *desc) +{ + if (desc->thread || !create_irq_threads) + return 0; + + desc->thread = kthread_create(do_irqd, desc, "IRQ %d", irq); + if (desc->thread == NULL) { + printk(KERN_ERR "irqd: could not create IRQ thread %d!\n", irq); + return -ENOMEM; + } + + wake_up_process(desc->thread); + + desc->thr_handler = ipipe_root_domain->irqs[irq].handler; + ipipe_root_domain->irqs[irq].handler = &kick_irqd; + + return 0; +} + +void __init ipipe_init_irq_threads(void) +{ + unsigned irq; + struct irq_desc *desc; + + create_irq_threads = 1; + + for (irq = 0; irq < NR_IRQS; irq++) { + desc = irq_desc + irq; + if (desc->action != NULL || + (desc->status & IRQ_NOREQUEST) != 0) + ipipe_start_irq_thread(irq, desc); + } +} + +EXPORT_SYMBOL(show_stack); + +#ifdef CONFIG_IPIPE_TRACE_MCOUNT +void notrace _mcount(void); +EXPORT_SYMBOL(_mcount); +#endif /* CONFIG_IPIPE_TRACE_MCOUNT */ diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c index 1624e1129681..ab8209cbbad0 100644 --- a/arch/blackfin/kernel/irqchip.c +++ b/arch/blackfin/kernel/irqchip.c @@ -108,8 +108,9 @@ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) { struct pt_regs *old_regs; struct irq_desc *desc = irq_desc + irq; +#ifndef CONFIG_IPIPE unsigned short pending, other_ints; - +#endif old_regs = set_irq_regs(regs); /* @@ -137,6 +138,7 @@ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) #endif generic_handle_irq(irq); +#ifndef CONFIG_IPIPE /* Useless and bugous over the I-pipe: IRQs are threaded. */ /* If we're the only interrupt running (ignoring IRQ15 which is for syscalls), lower our priority to IRQ14 so that softirqs run at that level. If there's another, lower-level interrupt, irq_exit @@ -146,6 +148,7 @@ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs) other_ints = pending & (pending - 1); if (other_ints == 0) lower_to_irq14(); +#endif /* !CONFIG_IPIPE */ irq_exit(); set_irq_regs(old_regs); diff --git a/arch/blackfin/kernel/mcount.S b/arch/blackfin/kernel/mcount.S new file mode 100644 index 000000000000..edcfb3865f46 --- /dev/null +++ b/arch/blackfin/kernel/mcount.S @@ -0,0 +1,70 @@ +/* + * linux/arch/blackfin/mcount.S + * + * Copyright (C) 2006 Analog Devices Inc. + * + * 2007/04/12 Save index, length, modify and base registers. --rpm + */ + +#include +#include + +.text + +.align 4 /* just in case */ + +ENTRY(__mcount) + [--sp] = i0; + [--sp] = i1; + [--sp] = i2; + [--sp] = i3; + [--sp] = l0; + [--sp] = l1; + [--sp] = l2; + [--sp] = l3; + [--sp] = m0; + [--sp] = m1; + [--sp] = m2; + [--sp] = m3; + [--sp] = b0; + [--sp] = b1; + [--sp] = b2; + [--sp] = b3; + [--sp] = ( r7:0, p5:0 ); + [--sp] = ASTAT; + + p1.L = _ipipe_trace_enable; + p1.H = _ipipe_trace_enable; + r7 = [p1]; + CC = r7 == 0; + if CC jump out; + link 0x10; + r0 = 0x0; + [sp + 0xc] = r0; /* v */ + r0 = 0x0; /* type: IPIPE_TRACE_FN */ + r1 = rets; + p0 = [fp]; /* p0: Prior FP */ + r2 = [p0 + 4]; /* r2: Prior RETS */ + call ___ipipe_trace; + unlink; +out: + ASTAT = [sp++]; + ( r7:0, p5:0 ) = [sp++]; + b3 = [sp++]; + b2 = [sp++]; + b1 = [sp++]; + b0 = [sp++]; + m3 = [sp++]; + m2 = [sp++]; + m1 = [sp++]; + m0 = [sp++]; + l3 = [sp++]; + l2 = [sp++]; + l1 = [sp++]; + l0 = [sp++]; + i3 = [sp++]; + i2 = [sp++]; + i1 = [sp++]; + i0 = [sp++]; + rts; +ENDPROC(__mcount) diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c index 1ec0faa8c68d..33e2e8993f7f 100644 --- a/arch/blackfin/kernel/process.c +++ b/arch/blackfin/kernel/process.c @@ -82,11 +82,14 @@ void cpu_idle(void)__attribute__((l1_text)); */ static void default_idle(void) { - local_irq_disable(); +#ifdef CONFIG_IPIPE + ipipe_suspend_domain(); +#endif + local_irq_disable_hw(); if (!need_resched()) idle_with_irq_disabled(); - local_irq_enable(); + local_irq_enable_hw(); } /* diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c index ec4dfa38eb0a..172b4c588467 100644 --- a/arch/blackfin/kernel/time.c +++ b/arch/blackfin/kernel/time.c @@ -31,7 +31,7 @@ static struct irqaction bfin_timer_irq = { #endif }; -#ifdef CONFIG_TICK_SOURCE_SYSTMR0 +#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE) void __init setup_system_timer0(void) { /* Power down the core timer, just to play safe. */ @@ -74,7 +74,7 @@ void __init setup_core_timer(void) static void __init time_sched_init(irqreturn_t(*timer_routine) (int, void *)) { -#ifdef CONFIG_TICK_SOURCE_SYSTMR0 +#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE) setup_system_timer0(); bfin_timer_irq.handler = timer_routine; setup_irq(IRQ_TIMER0, &bfin_timer_irq); @@ -94,7 +94,7 @@ static unsigned long gettimeoffset(void) unsigned long offset; unsigned long clocks_per_jiffy; -#ifdef CONFIG_TICK_SOURCE_SYSTMR0 +#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE) clocks_per_jiffy = bfin_read_TIMER0_PERIOD(); offset = bfin_read_TIMER0_COUNTER() / \ (((clocks_per_jiffy + 1) * HZ) / USEC_PER_SEC); @@ -133,7 +133,8 @@ irqreturn_t timer_interrupt(int irq, void *dummy) static long last_rtc_update; write_seqlock(&xtime_lock); -#ifdef CONFIG_TICK_SOURCE_SYSTMR0 +#if defined(CONFIG_TICK_SOURCE_SYSTMR0) && !defined(CONFIG_IPIPE) +/* FIXME: Here TIMIL0 is not set when IPIPE enabled, why? */ if (get_gptimer_status(0) & TIMER_STATUS_TIMIL0) { #endif do_timer(1); @@ -155,13 +156,17 @@ irqreturn_t timer_interrupt(int irq, void *dummy) /* Do it again in 60s. */ last_rtc_update = xtime.tv_sec - 600; } -#ifdef CONFIG_TICK_SOURCE_SYSTMR0 +#if defined(CONFIG_TICK_SOURCE_SYSTMR0) && !defined(CONFIG_IPIPE) set_gptimer_status(0, TIMER_STATUS_TIMIL0); } #endif write_sequnlock(&xtime_lock); +#ifdef CONFIG_IPIPE + update_root_process_times(get_irq_regs()); +#else update_process_times(user_mode(get_irq_regs())); +#endif profile_tick(CPU_PROFILING); return IRQ_HANDLED; diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c index 950cc822fb75..956aefb84687 100644 --- a/arch/blackfin/kernel/traps.c +++ b/arch/blackfin/kernel/traps.c @@ -577,10 +577,15 @@ asmlinkage void trap_c(struct pt_regs *fp) } } - info.si_signo = sig; - info.si_errno = 0; - info.si_addr = (void __user *)fp->pc; - force_sig_info(sig, &info, current); +#ifdef CONFIG_IPIPE + if (!ipipe_trap_notify(fp->seqstat & 0x3f, fp)) +#endif + { + info.si_signo = sig; + info.si_errno = 0; + info.si_addr = (void __user *)fp->pc; + force_sig_info(sig, &info, current); + } trace_buffer_restore(j); return; diff --git a/arch/blackfin/lib/ins.S b/arch/blackfin/lib/ins.S index d60554dce87b..1b84b21ca7d1 100644 --- a/arch/blackfin/lib/ins.S +++ b/arch/blackfin/lib/ins.S @@ -56,7 +56,16 @@ ENTRY(_insl) #ifdef CONFIG_BFIN_INS_LOWOVERHEAD P0 = R0; /* P0 = port */ +#ifdef CONFIG_IPIPE + [--sp] = rets + [--sp] = (P5:0); + sp += -12 + call ___ipipe_stall_root_raw + sp += 12 + (P5:0) = [sp++]; +#else cli R3; +#endif P1 = R1; /* P1 = address */ P2 = R2; /* P2 = count */ SSYNC; @@ -65,7 +74,14 @@ ENTRY(_insl) [P1++] = R0; NOP; .Llong_loop_e: NOP; +#ifdef CONFIG_IPIPE + sp += -12 + call ___ipipe_unstall_root_raw + sp += 12 + rets = [sp++] +#else sti R3; +#endif RTS; #else P0 = R0; /* P0 = port */ @@ -74,13 +90,28 @@ ENTRY(_insl) SSYNC; LSETUP( .Llong_loop_s, .Llong_loop_e) LC0 = P2; .Llong_loop_s: +#ifdef CONFIG_IPIPE + [--sp] = rets + [--sp] = (P5:0); + sp += -12 + call ___ipipe_stall_root_raw + sp += 12 + (P5:0) = [sp++]; +#else CLI R3; +#endif NOP; NOP; NOP; R0 = [P0]; [P1++] = R0; .Llong_loop_e: +#ifdef CONFIG_IPIPE + sp += -12 + call ___ipipe_unstall_root_raw + sp += 12 + rets = [sp++] +#else STI R3; - +#endif RTS; #endif ENDPROC(_insl) @@ -88,7 +119,16 @@ ENDPROC(_insl) ENTRY(_insw) #ifdef CONFIG_BFIN_INS_LOWOVERHEAD P0 = R0; /* P0 = port */ +#ifdef CONFIG_IPIPE + [--sp] = rets + [--sp] = (P5:0); + sp += -12 + call ___ipipe_stall_root_raw + sp += 12 + (P5:0) = [sp++]; +#else cli R3; +#endif P1 = R1; /* P1 = address */ P2 = R2; /* P2 = count */ SSYNC; @@ -97,7 +137,14 @@ ENTRY(_insw) W[P1++] = R0; NOP; .Lword_loop_e: NOP; +#ifdef CONFIG_IPIPE + sp += -12 + call ___ipipe_unstall_root_raw + sp += 12 + rets = [sp++] +#else sti R3; +#endif RTS; #else P0 = R0; /* P0 = port */ @@ -106,12 +153,28 @@ ENTRY(_insw) SSYNC; LSETUP( .Lword_loop_s, .Lword_loop_e) LC0 = P2; .Lword_loop_s: +#ifdef CONFIG_IPIPE + [--sp] = rets + [--sp] = (P5:0); + sp += -12 + call ___ipipe_stall_root_raw + sp += 12 + (P5:0) = [sp++]; +#else CLI R3; +#endif NOP; NOP; NOP; R0 = W[P0]; W[P1++] = R0; .Lword_loop_e: +#ifdef CONFIG_IPIPE + sp += -12 + call ___ipipe_unstall_root_raw + sp += 12 + rets = [sp++] +#else STI R3; +#endif RTS; #endif @@ -120,7 +183,16 @@ ENDPROC(_insw) ENTRY(_insw_8) #ifdef CONFIG_BFIN_INS_LOWOVERHEAD P0 = R0; /* P0 = port */ +#ifdef CONFIG_IPIPE + [--sp] = rets + [--sp] = (P5:0); + sp += -12 + call ___ipipe_stall_root_raw + sp += 12 + (P5:0) = [sp++]; +#else cli R3; +#endif P1 = R1; /* P1 = address */ P2 = R2; /* P2 = count */ SSYNC; @@ -131,7 +203,14 @@ ENTRY(_insw_8) B[P1++] = R0; NOP; .Lword8_loop_e: NOP; +#ifdef CONFIG_IPIPE + sp += -12 + call ___ipipe_unstall_root_raw + sp += 12 + rets = [sp++] +#else sti R3; +#endif RTS; #else P0 = R0; /* P0 = port */ @@ -140,7 +219,16 @@ ENTRY(_insw_8) SSYNC; LSETUP( .Lword8_loop_s, .Lword8_loop_e) LC0 = P2; .Lword8_loop_s: +#ifdef CONFIG_IPIPE + [--sp] = rets + [--sp] = (P5:0); + sp += -12 + call ___ipipe_stall_root_raw + sp += 12 + (P5:0) = [sp++]; +#else CLI R3; +#endif NOP; NOP; NOP; R0 = W[P0]; B[P1++] = R0; @@ -148,8 +236,14 @@ ENTRY(_insw_8) B[P1++] = R0; NOP; .Lword8_loop_e: +#ifdef CONFIG_IPIPE + sp += -12 + call ___ipipe_unstall_root_raw + sp += 12 + rets = [sp++] +#else STI R3; - +#endif RTS; #endif ENDPROC(_insw_8) @@ -157,7 +251,16 @@ ENDPROC(_insw_8) ENTRY(_insb) #ifdef CONFIG_BFIN_INS_LOWOVERHEAD P0 = R0; /* P0 = port */ +#ifdef CONFIG_IPIPE + [--sp] = rets + [--sp] = (P5:0); + sp += -12 + call ___ipipe_stall_root_raw + sp += 12 + (P5:0) = [sp++]; +#else cli R3; +#endif P1 = R1; /* P1 = address */ P2 = R2; /* P2 = count */ SSYNC; @@ -166,7 +269,14 @@ ENTRY(_insb) B[P1++] = R0; NOP; .Lbyte_loop_e: NOP; +#ifdef CONFIG_IPIPE + sp += -12 + call ___ipipe_unstall_root_raw + sp += 12 + rets = [sp++] +#else sti R3; +#endif RTS; #else P0 = R0; /* P0 = port */ @@ -175,13 +285,28 @@ ENTRY(_insb) SSYNC; LSETUP( .Lbyte_loop_s, .Lbyte_loop_e) LC0 = P2; .Lbyte_loop_s: +#ifdef CONFIG_IPIPE + [--sp] = rets + [--sp] = (P5:0); + sp += -12 + call ___ipipe_stall_root_raw + sp += 12 + (P5:0) = [sp++]; +#else CLI R3; +#endif NOP; NOP; NOP; R0 = B[P0]; B[P1++] = R0; .Lbyte_loop_e: +#ifdef CONFIG_IPIPE + sp += -12 + call ___ipipe_unstall_root_raw + sp += 12 + rets = [sp++] +#else STI R3; - +#endif RTS; #endif ENDPROC(_insb) @@ -189,7 +314,16 @@ ENDPROC(_insb) ENTRY(_insl_16) #ifdef CONFIG_BFIN_INS_LOWOVERHEAD P0 = R0; /* P0 = port */ +#ifdef CONFIG_IPIPE + [--sp] = rets + [--sp] = (P5:0); + sp += -12 + call ___ipipe_stall_root_raw + sp += 12 + (P5:0) = [sp++]; +#else cli R3; +#endif P1 = R1; /* P1 = address */ P2 = R2; /* P2 = count */ SSYNC; @@ -200,7 +334,14 @@ ENTRY(_insl_16) W[P1++] = R0; NOP; .Llong16_loop_e: NOP; +#ifdef CONFIG_IPIPE + sp += -12 + call ___ipipe_unstall_root_raw + sp += 12 + rets = [sp++] +#else sti R3; +#endif RTS; #else P0 = R0; /* P0 = port */ @@ -209,14 +350,30 @@ ENTRY(_insl_16) SSYNC; LSETUP( .Llong16_loop_s, .Llong16_loop_e) LC0 = P2; .Llong16_loop_s: +#ifdef CONFIG_IPIPE + [--sp] = rets + [--sp] = (P5:0); + sp += -12 + call ___ipipe_stall_root_raw + sp += 12 + (P5:0) = [sp++]; +#else CLI R3; +#endif NOP; NOP; NOP; R0 = [P0]; W[P1++] = R0; R0 = R0 >> 16; W[P1++] = R0; .Llong16_loop_e: +#ifdef CONFIG_IPIPE + sp += -12 + call ___ipipe_unstall_root_raw + sp += 12 + rets = [sp++] +#else STI R3; +#endif RTS; #endif ENDPROC(_insl_16) diff --git a/arch/blackfin/mach-bf518/Kconfig b/arch/blackfin/mach-bf518/Kconfig index 00f2d3700637..f397ede006bf 100644 --- a/arch/blackfin/mach-bf518/Kconfig +++ b/arch/blackfin/mach-bf518/Kconfig @@ -154,29 +154,29 @@ config IRQ_MAC_TX config IRQ_PORTH_INTB int "IRQ_PORTH_INTB" default 11 -config IRQ_TMR0 - int "IRQ_TMR0" - default 12 -config IRQ_TMR1 - int "IRQ_TMR1" +config IRQ_TIMER0 + int "IRQ_TIMER0" + default 8 +config IRQ_TIMER1 + int "IRQ_TIMER1" default 12 -config IRQ_TMR2 - int "IRQ_TMR2" +config IRQ_TIMER2 + int "IRQ_TIMER2" default 12 -config IRQ_TMR3 - int "IRQ_TMR3" +config IRQ_TIMER3 + int "IRQ_TIMER3" default 12 -config IRQ_TMR4 - int "IRQ_TMR4" +config IRQ_TIMER4 + int "IRQ_TIMER4" default 12 -config IRQ_TMR5 - int "IRQ_TMR5" +config IRQ_TIMER5 + int "IRQ_TIMER5" default 12 -config IRQ_TMR6 - int "IRQ_TMR6" +config IRQ_TIMER6 + int "IRQ_TIMER6" default 12 -config IRQ_TMR7 - int "IRQ_TMR7" +config IRQ_TIMER7 + int "IRQ_TIMER7" default 12 config IRQ_PORTG_INTA int "IRQ_PORTG_INTA" diff --git a/arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h b/arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h index 9fbcd2221986..ee3d4733369c 100644 --- a/arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h +++ b/arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h @@ -1163,7 +1163,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) if (val == bfin_read_PLL_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr0 = bfin_read32(SIC_IWR0); iwr1 = bfin_read32(SIC_IWR1); @@ -1177,7 +1177,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) bfin_write32(SIC_IWR0, iwr0); bfin_write32(SIC_IWR1, iwr1); - local_irq_restore(flags); + local_irq_restore_hw(flags); } /* Writing to VR_CTL initiates a PLL relock sequence. */ @@ -1188,7 +1188,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) if (val == bfin_read_VR_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr0 = bfin_read32(SIC_IWR0); iwr1 = bfin_read32(SIC_IWR1); @@ -1202,7 +1202,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) bfin_write32(SIC_IWR0, iwr0); bfin_write32(SIC_IWR1, iwr1); - local_irq_restore(flags); + local_irq_restore_hw(flags); } #endif /* _CDEF_BF52X_H */ diff --git a/arch/blackfin/mach-bf518/include/mach/irq.h b/arch/blackfin/mach-bf518/include/mach/irq.h index e5062f107ae2..3ff0f093313d 100644 --- a/arch/blackfin/mach-bf518/include/mach/irq.h +++ b/arch/blackfin/mach-bf518/include/mach/irq.h @@ -98,14 +98,14 @@ #define IRQ_PORTH_INTA BFIN_IRQ(29) /* Port H Interrupt A */ #define IRQ_MAC_TX BFIN_IRQ(30) /* DMA2 Channel (MAC TX) */ #define IRQ_PORTH_INTB BFIN_IRQ(31) /* Port H Interrupt B */ -#define IRQ_TMR0 BFIN_IRQ(32) /* Timer 0 */ -#define IRQ_TMR1 BFIN_IRQ(33) /* Timer 1 */ -#define IRQ_TMR2 BFIN_IRQ(34) /* Timer 2 */ -#define IRQ_TMR3 BFIN_IRQ(35) /* Timer 3 */ -#define IRQ_TMR4 BFIN_IRQ(36) /* Timer 4 */ -#define IRQ_TMR5 BFIN_IRQ(37) /* Timer 5 */ -#define IRQ_TMR6 BFIN_IRQ(38) /* Timer 6 */ -#define IRQ_TMR7 BFIN_IRQ(39) /* Timer 7 */ +#define IRQ_TIMER0 BFIN_IRQ(32) /* Timer 0 */ +#define IRQ_TIMER1 BFIN_IRQ(33) /* Timer 1 */ +#define IRQ_TIMER2 BFIN_IRQ(34) /* Timer 2 */ +#define IRQ_TIMER3 BFIN_IRQ(35) /* Timer 3 */ +#define IRQ_TIMER4 BFIN_IRQ(36) /* Timer 4 */ +#define IRQ_TIMER5 BFIN_IRQ(37) /* Timer 5 */ +#define IRQ_TIMER6 BFIN_IRQ(38) /* Timer 6 */ +#define IRQ_TIMER7 BFIN_IRQ(39) /* Timer 7 */ #define IRQ_PORTG_INTA BFIN_IRQ(40) /* Port G Interrupt A */ #define IRQ_PORTG_INTB BFIN_IRQ(41) /* Port G Interrupt B */ #define IRQ_MEM_DMA0 BFIN_IRQ(42) /* MDMA Stream 0 */ @@ -230,14 +230,14 @@ #define IRQ_PORTH_INTB_POS 28 /* IAR4 BIT FIELDS */ -#define IRQ_TMR0_POS 0 -#define IRQ_TMR1_POS 4 -#define IRQ_TMR2_POS 8 -#define IRQ_TMR3_POS 12 -#define IRQ_TMR4_POS 16 -#define IRQ_TMR5_POS 20 -#define IRQ_TMR6_POS 24 -#define IRQ_TMR7_POS 28 +#define IRQ_TIMER0_POS 0 +#define IRQ_TIMER1_POS 4 +#define IRQ_TIMER2_POS 8 +#define IRQ_TIMER3_POS 12 +#define IRQ_TIMER4_POS 16 +#define IRQ_TIMER5_POS 20 +#define IRQ_TIMER6_POS 24 +#define IRQ_TIMER7_POS 28 /* IAR5 BIT FIELDS */ #define IRQ_PORTG_INTA_POS 0 diff --git a/arch/blackfin/mach-bf518/ints-priority.c b/arch/blackfin/mach-bf518/ints-priority.c index c490c79194c0..3151fd5501ca 100644 --- a/arch/blackfin/mach-bf518/ints-priority.c +++ b/arch/blackfin/mach-bf518/ints-priority.c @@ -70,14 +70,14 @@ void __init program_IAR(void) ((CONFIG_IRQ_MAC_TX - 7) << IRQ_MAC_TX_POS) | ((CONFIG_IRQ_PORTH_INTB - 7) << IRQ_PORTH_INTB_POS)); - bfin_write_SIC_IAR4(((CONFIG_IRQ_TMR0 - 7) << IRQ_TMR0_POS) | - ((CONFIG_IRQ_TMR1 - 7) << IRQ_TMR1_POS) | - ((CONFIG_IRQ_TMR2 - 7) << IRQ_TMR2_POS) | - ((CONFIG_IRQ_TMR3 - 7) << IRQ_TMR3_POS) | - ((CONFIG_IRQ_TMR4 - 7) << IRQ_TMR4_POS) | - ((CONFIG_IRQ_TMR5 - 7) << IRQ_TMR5_POS) | - ((CONFIG_IRQ_TMR6 - 7) << IRQ_TMR6_POS) | - ((CONFIG_IRQ_TMR7 - 7) << IRQ_TMR7_POS)); + bfin_write_SIC_IAR4(((CONFIG_IRQ_TIMER0 - 7) << IRQ_TIMER0_POS) | + ((CONFIG_IRQ_TIMER1 - 7) << IRQ_TIMER1_POS) | + ((CONFIG_IRQ_TIMER2 - 7) << IRQ_TIMER2_POS) | + ((CONFIG_IRQ_TIMER3 - 7) << IRQ_TIMER3_POS) | + ((CONFIG_IRQ_TIMER4 - 7) << IRQ_TIMER4_POS) | + ((CONFIG_IRQ_TIMER5 - 7) << IRQ_TIMER5_POS) | + ((CONFIG_IRQ_TIMER6 - 7) << IRQ_TIMER6_POS) | + ((CONFIG_IRQ_TIMER7 - 7) << IRQ_TIMER7_POS)); bfin_write_SIC_IAR5(((CONFIG_IRQ_PORTG_INTA - 7) << IRQ_PORTG_INTA_POS) | ((CONFIG_IRQ_PORTG_INTB - 7) << IRQ_PORTG_INTB_POS) | diff --git a/arch/blackfin/mach-bf527/Kconfig b/arch/blackfin/mach-bf527/Kconfig index 3cde4beeb214..8438ec6d6679 100644 --- a/arch/blackfin/mach-bf527/Kconfig +++ b/arch/blackfin/mach-bf527/Kconfig @@ -168,29 +168,29 @@ config IRQ_MAC_TX config IRQ_PORTH_INTB int "IRQ_PORTH_INTB" default 11 -config IRQ_TMR0 - int "IRQ_TMR0" - default 12 -config IRQ_TMR1 - int "IRQ_TMR1" +config IRQ_TIMER0 + int "IRQ_TIMER0" + default 8 +config IRQ_TIMER1 + int "IRQ_TIMER1" default 12 -config IRQ_TMR2 - int "IRQ_TMR2" +config IRQ_TIMER2 + int "IRQ_TIMER2" default 12 -config IRQ_TMR3 - int "IRQ_TMR3" +config IRQ_TIMER3 + int "IRQ_TIMER3" default 12 -config IRQ_TMR4 - int "IRQ_TMR4" +config IRQ_TIMER4 + int "IRQ_TIMER4" default 12 -config IRQ_TMR5 - int "IRQ_TMR5" +config IRQ_TIMER5 + int "IRQ_TIMER5" default 12 -config IRQ_TMR6 - int "IRQ_TMR6" +config IRQ_TIMER6 + int "IRQ_TIMER6" default 12 -config IRQ_TMR7 - int "IRQ_TMR7" +config IRQ_TIMER7 + int "IRQ_TIMER7" default 12 config IRQ_PORTG_INTA int "IRQ_PORTG_INTA" diff --git a/arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h b/arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h index 8a374c358edf..1fe76d8e0403 100644 --- a/arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h +++ b/arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h @@ -1163,7 +1163,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) if (val == bfin_read_PLL_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr0 = bfin_read32(SIC_IWR0); iwr1 = bfin_read32(SIC_IWR1); @@ -1177,7 +1177,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) bfin_write32(SIC_IWR0, iwr0); bfin_write32(SIC_IWR1, iwr1); - local_irq_restore(flags); + local_irq_restore_hw(flags); } /* Writing to VR_CTL initiates a PLL relock sequence. */ @@ -1188,7 +1188,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) if (val == bfin_read_VR_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr0 = bfin_read32(SIC_IWR0); iwr1 = bfin_read32(SIC_IWR1); @@ -1202,7 +1202,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) bfin_write32(SIC_IWR0, iwr0); bfin_write32(SIC_IWR1, iwr1); - local_irq_restore(flags); + local_irq_restore_hw(flags); } #endif /* _CDEF_BF52X_H */ diff --git a/arch/blackfin/mach-bf527/include/mach/irq.h b/arch/blackfin/mach-bf527/include/mach/irq.h index 4e2b3f2020e5..8ea660d8151f 100644 --- a/arch/blackfin/mach-bf527/include/mach/irq.h +++ b/arch/blackfin/mach-bf527/include/mach/irq.h @@ -96,14 +96,14 @@ #define IRQ_MAC_TX BFIN_IRQ(30) /* DMA2 Channel (MAC TX/NAND) */ #define IRQ_NFC BFIN_IRQ(30) /* DMA2 Channel (MAC TX/NAND) */ #define IRQ_PORTH_INTB BFIN_IRQ(31) /* Port H Interrupt B */ -#define IRQ_TMR0 BFIN_IRQ(32) /* Timer 0 */ -#define IRQ_TMR1 BFIN_IRQ(33) /* Timer 1 */ -#define IRQ_TMR2 BFIN_IRQ(34) /* Timer 2 */ -#define IRQ_TMR3 BFIN_IRQ(35) /* Timer 3 */ -#define IRQ_TMR4 BFIN_IRQ(36) /* Timer 4 */ -#define IRQ_TMR5 BFIN_IRQ(37) /* Timer 5 */ -#define IRQ_TMR6 BFIN_IRQ(38) /* Timer 6 */ -#define IRQ_TMR7 BFIN_IRQ(39) /* Timer 7 */ +#define IRQ_TIMER0 BFIN_IRQ(32) /* Timer 0 */ +#define IRQ_TIMER1 BFIN_IRQ(33) /* Timer 1 */ +#define IRQ_TIMER2 BFIN_IRQ(34) /* Timer 2 */ +#define IRQ_TIMER3 BFIN_IRQ(35) /* Timer 3 */ +#define IRQ_TIMER4 BFIN_IRQ(36) /* Timer 4 */ +#define IRQ_TIMER5 BFIN_IRQ(37) /* Timer 5 */ +#define IRQ_TIMER6 BFIN_IRQ(38) /* Timer 6 */ +#define IRQ_TIMER7 BFIN_IRQ(39) /* Timer 7 */ #define IRQ_PORTG_INTA BFIN_IRQ(40) /* Port G Interrupt A */ #define IRQ_PORTG_INTB BFIN_IRQ(41) /* Port G Interrupt B */ #define IRQ_MEM_DMA0 BFIN_IRQ(42) /* MDMA Stream 0 */ @@ -227,14 +227,14 @@ #define IRQ_PORTH_INTB_POS 28 /* IAR4 BIT FIELDS */ -#define IRQ_TMR0_POS 0 -#define IRQ_TMR1_POS 4 -#define IRQ_TMR2_POS 8 -#define IRQ_TMR3_POS 12 -#define IRQ_TMR4_POS 16 -#define IRQ_TMR5_POS 20 -#define IRQ_TMR6_POS 24 -#define IRQ_TMR7_POS 28 +#define IRQ_TIMER0_POS 0 +#define IRQ_TIMER1_POS 4 +#define IRQ_TIMER2_POS 8 +#define IRQ_TIMER3_POS 12 +#define IRQ_TIMER4_POS 16 +#define IRQ_TIMER5_POS 20 +#define IRQ_TIMER6_POS 24 +#define IRQ_TIMER7_POS 28 /* IAR5 BIT FIELDS */ #define IRQ_PORTG_INTA_POS 0 diff --git a/arch/blackfin/mach-bf527/ints-priority.c b/arch/blackfin/mach-bf527/ints-priority.c index 8a2367403d2b..f8c8acd73e30 100644 --- a/arch/blackfin/mach-bf527/ints-priority.c +++ b/arch/blackfin/mach-bf527/ints-priority.c @@ -69,14 +69,14 @@ void __init program_IAR(void) ((CONFIG_IRQ_MAC_TX - 7) << IRQ_MAC_TX_POS) | ((CONFIG_IRQ_PORTH_INTB - 7) << IRQ_PORTH_INTB_POS)); - bfin_write_SIC_IAR4(((CONFIG_IRQ_TMR0 - 7) << IRQ_TMR0_POS) | - ((CONFIG_IRQ_TMR1 - 7) << IRQ_TMR1_POS) | - ((CONFIG_IRQ_TMR2 - 7) << IRQ_TMR2_POS) | - ((CONFIG_IRQ_TMR3 - 7) << IRQ_TMR3_POS) | - ((CONFIG_IRQ_TMR4 - 7) << IRQ_TMR4_POS) | - ((CONFIG_IRQ_TMR5 - 7) << IRQ_TMR5_POS) | - ((CONFIG_IRQ_TMR6 - 7) << IRQ_TMR6_POS) | - ((CONFIG_IRQ_TMR7 - 7) << IRQ_TMR7_POS)); + bfin_write_SIC_IAR4(((CONFIG_IRQ_TIMER0 - 7) << IRQ_TIMER0_POS) | + ((CONFIG_IRQ_TIMER1 - 7) << IRQ_TIMER1_POS) | + ((CONFIG_IRQ_TIMER2 - 7) << IRQ_TIMER2_POS) | + ((CONFIG_IRQ_TIMER3 - 7) << IRQ_TIMER3_POS) | + ((CONFIG_IRQ_TIMER4 - 7) << IRQ_TIMER4_POS) | + ((CONFIG_IRQ_TIMER5 - 7) << IRQ_TIMER5_POS) | + ((CONFIG_IRQ_TIMER6 - 7) << IRQ_TIMER6_POS) | + ((CONFIG_IRQ_TIMER7 - 7) << IRQ_TIMER7_POS)); bfin_write_SIC_IAR5(((CONFIG_IRQ_PORTG_INTA - 7) << IRQ_PORTG_INTA_POS) | ((CONFIG_IRQ_PORTG_INTB - 7) << IRQ_PORTG_INTB_POS) | diff --git a/arch/blackfin/mach-bf533/Kconfig b/arch/blackfin/mach-bf533/Kconfig index 76beb75f12da..14427de7d77f 100644 --- a/arch/blackfin/mach-bf533/Kconfig +++ b/arch/blackfin/mach-bf533/Kconfig @@ -59,7 +59,7 @@ config DMA7_UARTTX default 10 config TIMER0 int "TIMER0" - default 11 + default 8 config TIMER1 int "TIMER1" default 11 diff --git a/arch/blackfin/mach-bf533/include/mach/cdefBF532.h b/arch/blackfin/mach-bf533/include/mach/cdefBF532.h index d7b08f638ea4..bbc3c8386d48 100644 --- a/arch/blackfin/mach-bf533/include/mach/cdefBF532.h +++ b/arch/blackfin/mach-bf533/include/mach/cdefBF532.h @@ -684,10 +684,10 @@ static inline void bfin_write_FIO_FLAG_##name(unsigned short val) \ { \ unsigned long flags; \ - local_irq_save(flags); \ + local_irq_save_hw(flags); \ bfin_write16(FIO_FLAG_##name, val); \ bfin_read_CHIPID(); \ - local_irq_restore(flags); \ + local_irq_restore_hw(flags); \ } BFIN_WRITE_FIO_FLAG(D) BFIN_WRITE_FIO_FLAG(C) @@ -699,10 +699,10 @@ static inline u16 bfin_read_FIO_FLAG_##name(void) \ { \ unsigned long flags; \ u16 ret; \ - local_irq_save(flags); \ + local_irq_save_hw(flags); \ ret = bfin_read16(FIO_FLAG_##name); \ bfin_read_CHIPID(); \ - local_irq_restore(flags); \ + local_irq_restore_hw(flags); \ return ret; \ } BFIN_READ_FIO_FLAG(D) @@ -729,7 +729,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) if (val == bfin_read_PLL_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr = bfin_read32(SIC_IWR); /* Only allow PPL Wakeup) */ @@ -740,7 +740,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) asm("IDLE;"); bfin_write32(SIC_IWR, iwr); - local_irq_restore(flags); + local_irq_restore_hw(flags); } /* Writing to VR_CTL initiates a PLL relock sequence. */ @@ -751,7 +751,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) if (val == bfin_read_VR_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr = bfin_read32(SIC_IWR); /* Only allow PPL Wakeup) */ @@ -762,7 +762,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) asm("IDLE;"); bfin_write32(SIC_IWR, iwr); - local_irq_restore(flags); + local_irq_restore_hw(flags); } #endif /* _CDEF_BF532_H */ diff --git a/arch/blackfin/mach-bf533/include/mach/irq.h b/arch/blackfin/mach-bf533/include/mach/irq.h index e7dd315159df..db1e346cd1aa 100644 --- a/arch/blackfin/mach-bf533/include/mach/irq.h +++ b/arch/blackfin/mach-bf533/include/mach/irq.h @@ -100,9 +100,9 @@ Core Emulation ** #define IRQ_SPI 20 /*DMA5 Interrupt (SPI) */ #define IRQ_UART0_RX 21 /*DMA6 Interrupt (UART RX) */ #define IRQ_UART0_TX 22 /*DMA7 Interrupt (UART TX) */ -#define IRQ_TMR0 23 /*Timer 0 */ -#define IRQ_TMR1 24 /*Timer 1 */ -#define IRQ_TMR2 25 /*Timer 2 */ +#define IRQ_TIMER0 23 /*Timer 0 */ +#define IRQ_TIMER1 24 /*Timer 1 */ +#define IRQ_TIMER2 25 /*Timer 2 */ #define IRQ_PROG_INTA 26 /*Programmable Flags A (8) */ #define IRQ_PROG_INTB 27 /*Programmable Flags B (8) */ #define IRQ_MEM_DMA0 28 /*DMA8/9 Interrupt (Memory DMA Stream 0) */ diff --git a/arch/blackfin/mach-bf537/Kconfig b/arch/blackfin/mach-bf537/Kconfig index 8255374c04aa..bbc08fd4f122 100644 --- a/arch/blackfin/mach-bf537/Kconfig +++ b/arch/blackfin/mach-bf537/Kconfig @@ -64,29 +64,29 @@ config IRQ_MAC_RX config IRQ_MAC_TX int "IRQ_MAC_TX" default 11 -config IRQ_TMR0 - int "IRQ_TMR0" - default 12 -config IRQ_TMR1 - int "IRQ_TMR1" +config IRQ_TIMER0 + int "IRQ_TIMER0" + default 8 +config IRQ_TIMER1 + int "IRQ_TIMER1" default 12 -config IRQ_TMR2 - int "IRQ_TMR2" +config IRQ_TIMER2 + int "IRQ_TIMER2" default 12 -config IRQ_TMR3 - int "IRQ_TMR3" +config IRQ_TIMER3 + int "IRQ_TIMER3" default 12 -config IRQ_TMR4 - int "IRQ_TMR4" +config IRQ_TIMER4 + int "IRQ_TIMER4" default 12 -config IRQ_TMR5 - int "IRQ_TMR5" +config IRQ_TIMER5 + int "IRQ_TIMER5" default 12 -config IRQ_TMR6 - int "IRQ_TMR6" +config IRQ_TIMER6 + int "IRQ_TIMER6" default 12 -config IRQ_TMR7 - int "IRQ_TMR7" +config IRQ_TIMER7 + int "IRQ_TIMER7" default 12 config IRQ_PROG_INTA int "IRQ_PROG_INTA" diff --git a/arch/blackfin/mach-bf537/include/mach/cdefBF534.h b/arch/blackfin/mach-bf537/include/mach/cdefBF534.h index f3416923be69..5f8b5f845be6 100644 --- a/arch/blackfin/mach-bf537/include/mach/cdefBF534.h +++ b/arch/blackfin/mach-bf537/include/mach/cdefBF534.h @@ -1783,7 +1783,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) if (val == bfin_read_PLL_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr = bfin_read32(SIC_IWR); /* Only allow PPL Wakeup) */ @@ -1794,7 +1794,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) asm("IDLE;"); bfin_write32(SIC_IWR, iwr); - local_irq_restore(flags); + local_irq_restore_hw(flags); } /* Writing to VR_CTL initiates a PLL relock sequence. */ @@ -1805,7 +1805,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) if (val == bfin_read_VR_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr = bfin_read32(SIC_IWR); /* Only allow PPL Wakeup) */ @@ -1816,7 +1816,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) asm("IDLE;"); bfin_write32(SIC_IWR, iwr); - local_irq_restore(flags); + local_irq_restore_hw(flags); } #endif /* _CDEF_BF534_H */ diff --git a/arch/blackfin/mach-bf537/include/mach/irq.h b/arch/blackfin/mach-bf537/include/mach/irq.h index 2e68a8a1e730..b2a71d5d4e5f 100644 --- a/arch/blackfin/mach-bf537/include/mach/irq.h +++ b/arch/blackfin/mach-bf537/include/mach/irq.h @@ -82,14 +82,14 @@ #define IRQ_CAN_TX 23 /*CAN Transmit Interrupt */ #define IRQ_MAC_RX 24 /*DMA1 (Ethernet RX) Interrupt */ #define IRQ_MAC_TX 25 /*DMA2 (Ethernet TX) Interrupt */ -#define IRQ_TMR0 26 /*Timer 0 */ -#define IRQ_TMR1 27 /*Timer 1 */ -#define IRQ_TMR2 28 /*Timer 2 */ -#define IRQ_TMR3 29 /*Timer 3 */ -#define IRQ_TMR4 30 /*Timer 4 */ -#define IRQ_TMR5 31 /*Timer 5 */ -#define IRQ_TMR6 32 /*Timer 6 */ -#define IRQ_TMR7 33 /*Timer 7 */ +#define IRQ_TIMER0 26 /*Timer 0 */ +#define IRQ_TIMER1 27 /*Timer 1 */ +#define IRQ_TIMER2 28 /*Timer 2 */ +#define IRQ_TIMER3 29 /*Timer 3 */ +#define IRQ_TIMER4 30 /*Timer 4 */ +#define IRQ_TIMER5 31 /*Timer 5 */ +#define IRQ_TIMER6 32 /*Timer 6 */ +#define IRQ_TIMER7 33 /*Timer 7 */ #define IRQ_PROG_INTA 34 /* PF Ports F&G (PF15:0) Interrupt A */ #define IRQ_PORTG_INTB 35 /* PF Port G (PF15:0) Interrupt B */ #define IRQ_MEM_DMA0 36 /*(Memory DMA Stream 0) */ @@ -195,16 +195,16 @@ #define IRQ_CAN_TX_POS 0 #define IRQ_MAC_RX_POS 4 #define IRQ_MAC_TX_POS 8 -#define IRQ_TMR0_POS 12 -#define IRQ_TMR1_POS 16 -#define IRQ_TMR2_POS 20 -#define IRQ_TMR3_POS 24 -#define IRQ_TMR4_POS 28 +#define IRQ_TIMER0_POS 12 +#define IRQ_TIMER1_POS 16 +#define IRQ_TIMER2_POS 20 +#define IRQ_TIMER3_POS 24 +#define IRQ_TIMER4_POS 28 /* IAR3 BIT FIELDS*/ -#define IRQ_TMR5_POS 0 -#define IRQ_TMR6_POS 4 -#define IRQ_TMR7_POS 8 +#define IRQ_TIMER5_POS 0 +#define IRQ_TIMER6_POS 4 +#define IRQ_TIMER7_POS 8 #define IRQ_PROG_INTA_POS 12 #define IRQ_PORTG_INTB_POS 16 #define IRQ_MEM_DMA0_POS 20 diff --git a/arch/blackfin/mach-bf537/ints-priority.c b/arch/blackfin/mach-bf537/ints-priority.c index b1300b3f1812..51c48087e03b 100644 --- a/arch/blackfin/mach-bf537/ints-priority.c +++ b/arch/blackfin/mach-bf537/ints-priority.c @@ -55,15 +55,15 @@ void __init program_IAR(void) bfin_write_SIC_IAR2(((CONFIG_IRQ_CAN_TX - 7) << IRQ_CAN_TX_POS) | ((CONFIG_IRQ_MAC_RX - 7) << IRQ_MAC_RX_POS) | ((CONFIG_IRQ_MAC_TX - 7) << IRQ_MAC_TX_POS) | - ((CONFIG_IRQ_TMR0 - 7) << IRQ_TMR0_POS) | - ((CONFIG_IRQ_TMR1 - 7) << IRQ_TMR1_POS) | - ((CONFIG_IRQ_TMR2 - 7) << IRQ_TMR2_POS) | - ((CONFIG_IRQ_TMR3 - 7) << IRQ_TMR3_POS) | - ((CONFIG_IRQ_TMR4 - 7) << IRQ_TMR4_POS)); + ((CONFIG_IRQ_TIMER0 - 7) << IRQ_TIMER0_POS) | + ((CONFIG_IRQ_TIMER1 - 7) << IRQ_TIMER1_POS) | + ((CONFIG_IRQ_TIMER2 - 7) << IRQ_TIMER2_POS) | + ((CONFIG_IRQ_TIMER3 - 7) << IRQ_TIMER3_POS) | + ((CONFIG_IRQ_TIMER4 - 7) << IRQ_TIMER4_POS)); - bfin_write_SIC_IAR3(((CONFIG_IRQ_TMR5 - 7) << IRQ_TMR5_POS) | - ((CONFIG_IRQ_TMR6 - 7) << IRQ_TMR6_POS) | - ((CONFIG_IRQ_TMR7 - 7) << IRQ_TMR7_POS) | + bfin_write_SIC_IAR3(((CONFIG_IRQ_TIMER5 - 7) << IRQ_TIMER5_POS) | + ((CONFIG_IRQ_TIMER6 - 7) << IRQ_TIMER6_POS) | + ((CONFIG_IRQ_TIMER7 - 7) << IRQ_TIMER7_POS) | ((CONFIG_IRQ_PROG_INTA - 7) << IRQ_PROG_INTA_POS) | ((CONFIG_IRQ_PORTG_INTB - 7) << IRQ_PORTG_INTB_POS) | ((CONFIG_IRQ_MEM_DMA0 - 7) << IRQ_MEM_DMA0_POS) | diff --git a/arch/blackfin/mach-bf538/Kconfig b/arch/blackfin/mach-bf538/Kconfig index a6f3307758c0..f068c3523cdc 100644 --- a/arch/blackfin/mach-bf538/Kconfig +++ b/arch/blackfin/mach-bf538/Kconfig @@ -55,14 +55,14 @@ config IRQ_UART0_RX config IRQ_UART0_TX int "IRQ_UART0_TX" default 10 -config IRQ_TMR0 - int "IRQ_TMR0" - default 11 -config IRQ_TMR1 - int "IRQ_TMR1" +config IRQ_TIMER0 + int "IRQ_TIMER0" + default 8 +config IRQ_TIMER1 + int "IRQ_TIMER1" default 11 -config IRQ_TMR2 - int "IRQ_TMR2" +config IRQ_TIMER2 + int "IRQ_TIMER2" default 11 config IRQ_PORTF_INTA int "IRQ_PORTF_INTA" diff --git a/arch/blackfin/mach-bf538/include/mach/cdefBF538.h b/arch/blackfin/mach-bf538/include/mach/cdefBF538.h index 7e469b8d939c..241725bc6988 100644 --- a/arch/blackfin/mach-bf538/include/mach/cdefBF538.h +++ b/arch/blackfin/mach-bf538/include/mach/cdefBF538.h @@ -2063,7 +2063,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) if (val == bfin_read_PLL_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr0 = bfin_read32(SIC_IWR0); iwr1 = bfin_read32(SIC_IWR1); @@ -2077,7 +2077,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) bfin_write32(SIC_IWR0, iwr0); bfin_write32(SIC_IWR1, iwr1); - local_irq_restore(flags); + local_irq_restore_hw(flags); } /* Writing to VR_CTL initiates a PLL relock sequence. */ @@ -2088,7 +2088,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) if (val == bfin_read_VR_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr0 = bfin_read32(SIC_IWR0); iwr1 = bfin_read32(SIC_IWR1); @@ -2102,7 +2102,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) bfin_write32(SIC_IWR0, iwr0); bfin_write32(SIC_IWR1, iwr1); - local_irq_restore(flags); + local_irq_restore_hw(flags); } #endif diff --git a/arch/blackfin/mach-bf538/include/mach/irq.h b/arch/blackfin/mach-bf538/include/mach/irq.h index 60bdac4cb6a4..fdc87fe2c174 100644 --- a/arch/blackfin/mach-bf538/include/mach/irq.h +++ b/arch/blackfin/mach-bf538/include/mach/irq.h @@ -81,9 +81,9 @@ #define IRQ_SPI0 BFIN_IRQ(13) /* DMA 5 Channel (SPI0) */ #define IRQ_UART0_RX BFIN_IRQ(14) /* DMA 6 Channel (UART0 RX) */ #define IRQ_UART0_TX BFIN_IRQ(15) /* DMA 7 Channel (UART0 TX) */ -#define IRQ_TMR0 BFIN_IRQ(16) /* Timer 0 */ -#define IRQ_TMR1 BFIN_IRQ(17) /* Timer 1 */ -#define IRQ_TMR2 BFIN_IRQ(18) /* Timer 2 */ +#define IRQ_TIMER0 BFIN_IRQ(16) /* Timer 0 */ +#define IRQ_TIMER1 BFIN_IRQ(17) /* Timer 1 */ +#define IRQ_TIMER2 BFIN_IRQ(18) /* Timer 2 */ #define IRQ_PORTF_INTA BFIN_IRQ(19) /* Port F Interrupt A */ #define IRQ_PORTF_INTB BFIN_IRQ(20) /* Port F Interrupt B */ #define IRQ_MEM0_DMA0 BFIN_IRQ(21) /* MDMA0 Stream 0 */ @@ -168,9 +168,9 @@ #define IRQ_UART0_TX_POS 28 /* IAR2 BIT FIELDS */ -#define IRQ_TMR0_POS 0 -#define IRQ_TMR1_POS 4 -#define IRQ_TMR2_POS 8 +#define IRQ_TIMER0_POS 0 +#define IRQ_TIMER1_POS 4 +#define IRQ_TIMER2_POS 8 #define IRQ_PORTF_INTA_POS 12 #define IRQ_PORTF_INTB_POS 16 #define IRQ_MEM0_DMA0_POS 20 diff --git a/arch/blackfin/mach-bf538/ints-priority.c b/arch/blackfin/mach-bf538/ints-priority.c index f81f2ac91840..70d17e550e05 100644 --- a/arch/blackfin/mach-bf538/ints-priority.c +++ b/arch/blackfin/mach-bf538/ints-priority.c @@ -53,9 +53,9 @@ void __init program_IAR(void) ((CONFIG_IRQ_UART0_RX - 7) << IRQ_UART0_RX_POS) | ((CONFIG_IRQ_UART0_TX - 7) << IRQ_UART0_TX_POS)); - bfin_write_SIC_IAR2(((CONFIG_IRQ_TMR0 - 7) << IRQ_TMR0_POS) | - ((CONFIG_IRQ_TMR1 - 7) << IRQ_TMR1_POS) | - ((CONFIG_IRQ_TMR2 - 7) << IRQ_TMR2_POS) | + bfin_write_SIC_IAR2(((CONFIG_IRQ_TIMER0 - 7) << IRQ_TIMER0_POS) | + ((CONFIG_IRQ_TIMER1 - 7) << IRQ_TIMER1_POS) | + ((CONFIG_IRQ_TIMER2 - 7) << IRQ_TIMER2_POS) | ((CONFIG_IRQ_PORTF_INTA - 7) << IRQ_PORTF_INTA_POS) | ((CONFIG_IRQ_PORTF_INTB - 7) << IRQ_PORTF_INTB_POS) | ((CONFIG_IRQ_MEM0_DMA0 - 7) << IRQ_MEM0_DMA0_POS) | diff --git a/arch/blackfin/mach-bf548/Kconfig b/arch/blackfin/mach-bf548/Kconfig index 1bfcd8f646ab..dcf657159051 100644 --- a/arch/blackfin/mach-bf548/Kconfig +++ b/arch/blackfin/mach-bf548/Kconfig @@ -250,7 +250,7 @@ config IRQ_OTPSEC default 11 config IRQ_TIMER0 int "IRQ_TIMER0" - default 11 + default 8 config IRQ_TIMER1 int "IRQ_TIMER1" default 11 diff --git a/arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h b/arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h index 0a3b210daadf..6e636c418cb0 100644 --- a/arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h +++ b/arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h @@ -2702,7 +2702,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) if (val == bfin_read_PLL_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr0 = bfin_read32(SIC_IWR0); iwr1 = bfin_read32(SIC_IWR1); @@ -2719,7 +2719,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) bfin_write32(SIC_IWR0, iwr0); bfin_write32(SIC_IWR1, iwr1); bfin_write32(SIC_IWR2, iwr2); - local_irq_restore(flags); + local_irq_restore_hw(flags); } /* Writing to VR_CTL initiates a PLL relock sequence. */ @@ -2730,7 +2730,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) if (val == bfin_read_VR_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr0 = bfin_read32(SIC_IWR0); iwr1 = bfin_read32(SIC_IWR1); @@ -2747,7 +2747,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) bfin_write32(SIC_IWR0, iwr0); bfin_write32(SIC_IWR1, iwr1); bfin_write32(SIC_IWR2, iwr2); - local_irq_restore(flags); + local_irq_restore_hw(flags); } #endif /* _CDEF_BF54X_H */ diff --git a/arch/blackfin/mach-bf548/include/mach/irq.h b/arch/blackfin/mach-bf548/include/mach/irq.h index ad380d1f5872..60299a71e090 100644 --- a/arch/blackfin/mach-bf548/include/mach/irq.h +++ b/arch/blackfin/mach-bf548/include/mach/irq.h @@ -158,7 +158,7 @@ Events (highest priority) EMU 0 #define IRQ_PINT2 BFIN_IRQ(94) /* PINT2 Interrupt */ #define IRQ_PINT3 BFIN_IRQ(95) /* PINT3 Interrupt */ -#define SYS_IRQS IRQ_PINT3 +#define SYS_IRQS IRQ_PINT3 #define BFIN_PA_IRQ(x) ((x) + SYS_IRQS + 1) #define IRQ_PA0 BFIN_PA_IRQ(0) diff --git a/arch/blackfin/mach-bf561/Kconfig b/arch/blackfin/mach-bf561/Kconfig index 5d56438cad2f..638ec38ca470 100644 --- a/arch/blackfin/mach-bf561/Kconfig +++ b/arch/blackfin/mach-bf561/Kconfig @@ -138,7 +138,7 @@ config IRQ_DMA2_11 default 9 config IRQ_TIMER0 int "TIMER 0 Interrupt" - default 10 + default 8 config IRQ_TIMER1 int "TIMER 1 Interrupt" default 10 diff --git a/arch/blackfin/mach-bf561/include/mach/cdefBF561.h b/arch/blackfin/mach-bf561/include/mach/cdefBF561.h index b16875d735b3..95d609f11c97 100644 --- a/arch/blackfin/mach-bf561/include/mach/cdefBF561.h +++ b/arch/blackfin/mach-bf561/include/mach/cdefBF561.h @@ -1537,7 +1537,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) if (val == bfin_read_PLL_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr0 = bfin_read32(SICA_IWR0); iwr1 = bfin_read32(SICA_IWR1); @@ -1551,7 +1551,7 @@ static __inline__ void bfin_write_PLL_CTL(unsigned int val) bfin_write32(SICA_IWR0, iwr0); bfin_write32(SICA_IWR1, iwr1); - local_irq_restore(flags); + local_irq_restore_hw(flags); } /* Writing to VR_CTL initiates a PLL relock sequence. */ @@ -1562,7 +1562,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) if (val == bfin_read_VR_CTL()) return; - local_irq_save(flags); + local_irq_save_hw(flags); /* Enable the PLL Wakeup bit in SIC IWR */ iwr0 = bfin_read32(SICA_IWR0); iwr1 = bfin_read32(SICA_IWR1); @@ -1576,7 +1576,7 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) bfin_write32(SICA_IWR0, iwr0); bfin_write32(SICA_IWR1, iwr1); - local_irq_restore(flags); + local_irq_restore_hw(flags); } #endif /* _CDEF_BF561_H */ diff --git a/arch/blackfin/mach-common/cpufreq.c b/arch/blackfin/mach-common/cpufreq.c index 56f68d879b33..72e16605ca09 100644 --- a/arch/blackfin/mach-common/cpufreq.c +++ b/arch/blackfin/mach-common/cpufreq.c @@ -104,7 +104,7 @@ static int bfin_target(struct cpufreq_policy *policy, cclk_hz, target_freq, freqs.old); cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - local_irq_save(flags); + local_irq_save_hw(flags); plldiv = (bfin_read_PLL_DIV() & SSEL) | dpm_state_table[index].csel; tscale = dpm_state_table[index].tscale; bfin_write_PLL_DIV(plldiv); @@ -115,7 +115,7 @@ static int bfin_target(struct cpufreq_policy *policy, cycles += 10; /* ~10 cycles we lose after get_cycles() */ __bfin_cycles_off += (cycles << __bfin_cycles_mod) - (cycles << index); __bfin_cycles_mod = index; - local_irq_restore(flags); + local_irq_restore_hw(flags); /* TODO: just test case for cycles clock source, remove later */ pr_debug("cpufreq: done\n"); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S index 2604b532897c..c1bdd1edc8eb 100644 --- a/arch/blackfin/mach-common/interrupt.S +++ b/arch/blackfin/mach-common/interrupt.S @@ -129,8 +129,15 @@ __common_int_entry: #endif r1 = sp; SP += -12; +#ifdef CONFIG_IPIPE + call ___ipipe_grab_irq + SP += 12; + cc = r0 == 0; + if cc jump .Lcommon_restore_context; +#else /* CONFIG_IPIPE */ call _do_irq; SP += 12; +#endif /* CONFIG_IPIPE */ call _return_from_int; .Lcommon_restore_context: RESTORE_CONTEXT @@ -247,3 +254,56 @@ ENTRY(_evt_system_call) call _system_call; jump .Lcommon_restore_context; ENDPROC(_evt_system_call) + +#ifdef CONFIG_IPIPE +ENTRY(___ipipe_call_irqtail) + r0.l = 1f; + r0.h = 1f; + reti = r0; + rti; +1: + [--sp] = rets; + [--sp] = ( r7:4, p5:3 ); + p0.l = ___ipipe_irq_tail_hook; + p0.h = ___ipipe_irq_tail_hook; + p0 = [p0]; + sp += -12; + call (p0); + sp += 12; + ( r7:4, p5:3 ) = [sp++]; + rets = [sp++]; + + [--sp] = reti; + reti = [sp++]; /* IRQs are off. */ + r0.h = 3f; + r0.l = 3f; + p0.l = lo(EVT14); + p0.h = hi(EVT14); + [p0] = r0; + csync; + r0 = 0x401f; + sti r0; + raise 14; + [--sp] = reti; /* IRQs on. */ +2: + jump 2b; /* Likely paranoid. */ +3: + sp += 4; /* Discard saved RETI */ + r0.h = _evt14_softirq; + r0.l = _evt14_softirq; + p0.l = lo(EVT14); + p0.h = hi(EVT14); + [p0] = r0; + csync; + p0.l = _bfin_irq_flags; + p0.h = _bfin_irq_flags; + r0 = [p0]; + sti r0; +#if 0 /* FIXME: this actually raises scheduling latencies */ + /* Reenable interrupts */ + [--sp] = reti; + r0 = [sp++]; +#endif + rts; +ENDPROC(___ipipe_call_irqtail) +#endif /* CONFIG_IPIPE */ diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c index 7c1db775751b..1bba6030dce9 100644 --- a/arch/blackfin/mach-common/ints-priority.c +++ b/arch/blackfin/mach-common/ints-priority.c @@ -34,6 +34,9 @@ #include #include #include +#ifdef CONFIG_IPIPE +#include +#endif #ifdef CONFIG_KGDB #include #endif @@ -135,8 +138,8 @@ static void bfin_ack_noop(unsigned int irq) static void bfin_core_mask_irq(unsigned int irq) { bfin_irq_flags &= ~(1 << irq); - if (!irqs_disabled()) - local_irq_enable(); + if (!irqs_disabled_hw()) + local_irq_enable_hw(); } static void bfin_core_unmask_irq(unsigned int irq) @@ -151,8 +154,8 @@ static void bfin_core_unmask_irq(unsigned int irq) * local_irq_enable just does "STI bfin_irq_flags", so it's exactly * what we need. */ - if (!irqs_disabled()) - local_irq_enable(); + if (!irqs_disabled_hw()) + local_irq_enable_hw(); return; } @@ -235,7 +238,7 @@ int bfin_internal_set_wake(unsigned int irq, unsigned int state) break; } - local_irq_save(flags); + local_irq_save_hw(flags); if (state) { bfin_sic_iwr[bank] |= (1 << bit); @@ -246,7 +249,7 @@ int bfin_internal_set_wake(unsigned int irq, unsigned int state) vr_wakeup &= ~wakeup; } - local_irq_restore(flags); + local_irq_restore_hw(flags); return 0; } @@ -272,6 +275,19 @@ static struct irq_chip bfin_internal_irqchip = { #endif }; +static void bfin_handle_irq(unsigned irq) +{ +#ifdef CONFIG_IPIPE + struct pt_regs regs; /* Contents not used. */ + ipipe_trace_irq_entry(irq); + __ipipe_handle_irq(irq, ®s); + ipipe_trace_irq_exit(irq); +#else /* !CONFIG_IPIPE */ + struct irq_desc *desc = irq_desc + irq; + desc->handle_irq(irq, desc); +#endif /* !CONFIG_IPIPE */ +} + #ifdef BF537_GENERIC_ERROR_INT_DEMUX static int error_int_mask; @@ -325,10 +341,9 @@ static void bfin_demux_error_irq(unsigned int int_err_irq, irq = IRQ_UART1_ERROR; if (irq) { - if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR))) { - struct irq_desc *desc = irq_desc + irq; - desc->handle_irq(irq, desc); - } else { + if (error_int_mask & (1L << (irq - IRQ_PPI_ERROR))) + bfin_handle_irq(irq); + else { switch (irq) { case IRQ_PPI_ERROR: @@ -374,10 +389,14 @@ static void bfin_demux_error_irq(unsigned int int_err_irq, static inline void bfin_set_irq_handler(unsigned irq, irq_flow_handler_t handle) { +#ifdef CONFIG_IPIPE + _set_irq_handler(irq, handle_edge_irq); +#else struct irq_desc *desc = irq_desc + irq; /* May not call generic set_irq_handler() due to spinlock recursion. */ desc->handle_irq = handle; +#endif } static DECLARE_BITMAP(gpio_enabled, MAX_BLACKFIN_GPIOS); @@ -563,10 +582,8 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq, mask = get_gpiop_data(i) & get_gpiop_maska(i); while (mask) { - if (mask & 1) { - desc = irq_desc + irq; - desc->handle_irq(irq, desc); - } + if (mask & 1) + bfin_handle_irq(irq); irq++; mask >>= 1; } @@ -576,10 +593,8 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq, mask = get_gpiop_data(gpio) & get_gpiop_maska(gpio); do { - if (mask & 1) { - desc = irq_desc + irq; - desc->handle_irq(irq, desc); - } + if (mask & 1) + bfin_handle_irq(irq); irq++; mask >>= 1; } while (mask); @@ -900,8 +915,7 @@ static void bfin_demux_gpio_irq(unsigned int inta_irq, while (request) { if (request & 1) { irq = pint2irq_lut[pint_val] + SYS_IRQS; - desc = irq_desc + irq; - desc->handle_irq(irq, desc); + bfin_handle_irq(irq); } pint_val++; request >>= 1; @@ -1025,11 +1039,10 @@ int __init init_arch_irq(void) break; #ifdef BF537_GENERIC_ERROR_INT_DEMUX case IRQ_GENERIC_ERROR: - set_irq_handler(irq, bfin_demux_error_irq); - + set_irq_chained_handler(irq, bfin_demux_error_irq); break; #endif -#ifdef CONFIG_TICK_SOURCE_SYSTMR0 +#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE) case IRQ_TIMER0: set_irq_handler(irq, handle_percpu_irq); break; @@ -1041,7 +1054,17 @@ int __init init_arch_irq(void) break; #endif default: +#ifdef CONFIG_IPIPE + /* + * We want internal interrupt sources to be masked, because + * ISRs may trigger interrupts recursively (e.g. DMA), but + * interrupts are _not_ masked at CPU level. So let's handle + * them as level interrupts. + */ + set_irq_handler(irq, handle_level_irq); +#else /* !CONFIG_IPIPE */ set_irq_handler(irq, handle_simple_irq); +#endif /* !CONFIG_IPIPE */ break; } } @@ -1101,6 +1124,14 @@ int __init init_arch_irq(void) bfin_write_SIC_IWR(IWR_DISABLE_ALL); #endif +#ifdef CONFIG_IPIPE + for (irq = 0; irq < NR_IRQS; irq++) { + struct irq_desc *desc = irq_desc + irq; + desc->ic_prio = __ipipe_get_irq_priority(irq); + desc->thr_prio = __ipipe_get_irqthread_priority(irq); + } +#endif /* CONFIG_IPIPE */ + return 0; } @@ -1156,3 +1187,161 @@ void do_irq(int vec, struct pt_regs *fp) } asm_do_IRQ(vec, fp); } + +#ifdef CONFIG_IPIPE + +int __ipipe_get_irq_priority(unsigned irq) +{ + int ient, prio; + + if (irq <= IRQ_CORETMR) + return irq; + + for (ient = 0; ient < NR_PERI_INTS; ient++) { + struct ivgx *ivg = ivg_table + ient; + if (ivg->irqno == irq) { + for (prio = 0; prio <= IVG13-IVG7; prio++) { + if (ivg7_13[prio].ifirst <= ivg && + ivg7_13[prio].istop > ivg) + return IVG7 + prio; + } + } + } + + return IVG15; +} + +int __ipipe_get_irqthread_priority(unsigned irq) +{ + int ient, prio; + int demux_irq; + + /* The returned priority value is rescaled to [0..IVG13+1] + * with 0 being the lowest effective priority level. */ + + if (irq <= IRQ_CORETMR) + return IVG13 - irq + 1; + + /* GPIO IRQs are given the priority of the demux + * interrupt. */ + if (IS_GPIOIRQ(irq)) { +#if defined(CONFIG_BF54x) + u32 bank = PINT_2_BANK(irq2pint_lut[irq - SYS_IRQS]); + demux_irq = (bank == 0 ? IRQ_PINT0 : + bank == 1 ? IRQ_PINT1 : + bank == 2 ? IRQ_PINT2 : + IRQ_PINT3); +#elif defined(CONFIG_BF561) + demux_irq = (irq >= IRQ_PF32 ? IRQ_PROG2_INTA : + irq >= IRQ_PF16 ? IRQ_PROG1_INTA : + IRQ_PROG0_INTA); +#elif defined(CONFIG_BF52x) + demux_irq = (irq >= IRQ_PH0 ? IRQ_PORTH_INTA : + irq >= IRQ_PG0 ? IRQ_PORTG_INTA : + IRQ_PORTF_INTA); +#else + demux_irq = irq; +#endif + return IVG13 - PRIO_GPIODEMUX(demux_irq) + 1; + } + + /* The GPIO demux interrupt is given a lower priority + * than the GPIO IRQs, so that its threaded handler + * unmasks the interrupt line after the decoded IRQs + * have been processed. */ + prio = PRIO_GPIODEMUX(irq); + /* demux irq? */ + if (prio != -1) + return IVG13 - prio; + + for (ient = 0; ient < NR_PERI_INTS; ient++) { + struct ivgx *ivg = ivg_table + ient; + if (ivg->irqno == irq) { + for (prio = 0; prio <= IVG13-IVG7; prio++) { + if (ivg7_13[prio].ifirst <= ivg && + ivg7_13[prio].istop > ivg) + return IVG7 - prio; + } + } + } + + return 0; +} + +/* Hw interrupts are disabled on entry (check SAVE_CONTEXT). */ +#ifdef CONFIG_DO_IRQ_L1 +__attribute__((l1_text)) +#endif +asmlinkage int __ipipe_grab_irq(int vec, struct pt_regs *regs) +{ + struct ivgx *ivg_stop = ivg7_13[vec-IVG7].istop; + struct ivgx *ivg = ivg7_13[vec-IVG7].ifirst; + int irq; + + if (likely(vec == EVT_IVTMR_P)) { + irq = IRQ_CORETMR; + goto handle_irq; + } + + SSYNC(); + +#if defined(CONFIG_BF54x) || defined(CONFIG_BF52x) || defined(CONFIG_BF561) + { + unsigned long sic_status[3]; + + sic_status[0] = bfin_read_SIC_ISR0() & bfin_read_SIC_IMASK0(); + sic_status[1] = bfin_read_SIC_ISR1() & bfin_read_SIC_IMASK1(); +#ifdef CONFIG_BF54x + sic_status[2] = bfin_read_SIC_ISR2() & bfin_read_SIC_IMASK2(); +#endif + for (;; ivg++) { + if (ivg >= ivg_stop) { + atomic_inc(&num_spurious); + return 0; + } + if (sic_status[(ivg->irqno - IVG7) / 32] & ivg->isrflag) + break; + } + } +#else + { + unsigned long sic_status; + + sic_status = bfin_read_SIC_IMASK() & bfin_read_SIC_ISR(); + + for (;; ivg++) { + if (ivg >= ivg_stop) { + atomic_inc(&num_spurious); + return 0; + } else if (sic_status & ivg->isrflag) + break; + } + } +#endif + + irq = ivg->irqno; + + if (irq == IRQ_SYSTMR) { + bfin_write_TIMER_STATUS(1); /* Latch TIMIL0 */ + /* This is basically what we need from the register frame. */ + __raw_get_cpu_var(__ipipe_tick_regs).ipend = regs->ipend; + __raw_get_cpu_var(__ipipe_tick_regs).pc = regs->pc; + if (!ipipe_root_domain_p) + __raw_get_cpu_var(__ipipe_tick_regs).ipend |= 0x10; + else + __raw_get_cpu_var(__ipipe_tick_regs).ipend &= ~0x10; + } + +handle_irq: + + ipipe_trace_irq_entry(irq); + __ipipe_handle_irq(irq, regs); + ipipe_trace_irq_exit(irq); + + if (ipipe_root_domain_p) + return !test_bit(IPIPE_STALL_FLAG, &ipipe_root_cpudom_var(status)); + + return 0; +} + +#endif /* CONFIG_IPIPE */ diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c index 96600b8cb6ad..d3d70fd67c16 100644 --- a/arch/blackfin/mach-common/pm.c +++ b/arch/blackfin/mach-common/pm.c @@ -71,7 +71,7 @@ void bfin_pm_suspend_standby_enter(void) gpio_pm_wakeup_request(CONFIG_PM_WAKEUP_GPIO_NUMBER, WAKEUP_TYPE); #endif - local_irq_save(flags); + local_irq_save_hw(flags); bfin_pm_standby_setup(); #ifdef CONFIG_PM_BFIN_SLEEP_DEEPER @@ -105,7 +105,7 @@ void bfin_pm_suspend_standby_enter(void) bfin_write_SIC_IWR(IWR_DISABLE_ALL); #endif - local_irq_restore(flags); + local_irq_restore_hw(flags); } int bf53x_suspend_l1_mem(unsigned char *memptr) @@ -249,12 +249,12 @@ int bfin_pm_suspend_mem_enter(void) wakeup |= GPWE; #endif - local_irq_save(flags); + local_irq_save_hw(flags); ret = blackfin_dma_suspend(); if (ret) { - local_irq_restore(flags); + local_irq_restore_hw(flags); kfree(memptr); return ret; } @@ -275,7 +275,7 @@ int bfin_pm_suspend_mem_enter(void) bfin_gpio_pm_hibernate_restore(); blackfin_dma_resume(); - local_irq_restore(flags); + local_irq_restore_hw(flags); kfree(memptr); return 0; diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c index 66c47a702da4..77c992847094 100644 --- a/arch/blackfin/mach-common/smp.c +++ b/arch/blackfin/mach-common/smp.c @@ -348,7 +348,7 @@ int __cpuinit __cpu_up(unsigned int cpu) static void __cpuinit setup_secondary(unsigned int cpu) { -#ifndef CONFIG_TICK_SOURCE_SYSTMR0 +#if !(defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE)) struct irq_desc *timer_desc; #endif unsigned long ilat; @@ -369,7 +369,7 @@ static void __cpuinit setup_secondary(unsigned int cpu) IMASK_IVG14 | IMASK_IVG13 | IMASK_IVG12 | IMASK_IVG11 | IMASK_IVG10 | IMASK_IVG9 | IMASK_IVG8 | IMASK_IVG7 | IMASK_IVGHW; -#ifdef CONFIG_TICK_SOURCE_SYSTMR0 +#if defined(CONFIG_TICK_SOURCE_SYSTMR0) || defined(CONFIG_IPIPE) /* Power down the core timer, just to play safe. */ bfin_write_TCNTL(0); -- cgit v1.2.3