Browse Source

Merge branch 'for-linus' of git://git.monstr.eu/linux-2.6-microblaze

* 'for-linus' of git://git.monstr.eu/linux-2.6-microblaze: (46 commits)
  microblaze: Remove rt_sigsuspend wrapper
  microblaze: nommu: Don't clobber R11 on syscalls
  microblaze: Remove show_tmem function
  microblaze: Support for WB cache
  microblaze: Add PVR for Microblaze v7.30.a
  microblaze: Remove ancient and fake microblaze version from cpu_ver table
  microblaze: Remove panic_timeout init value
  microblaze: Do not count system calls in default
  microblaze: Enable DTC compilation
  microblaze: Core oprofile configs and hooks
  microblaze: Fix level interrupt ACKing
  microblaze: Enable futimesat syscall
  microblaze: Checking DTS against PVR for write-back cache
  microblaze: Remove duplicity from pgalloc.h
  microblaze: Futex support
  microblaze: Adding dev_arch_data functions
  microblaze: Fix the heartbeat gpio to be more robust
  microblaze: Simple __copy_tofrom_user for noMMU
  microblaze: Export memory_start for modules
  microblaze: Use lowest-common-denominator default CPU settings
  ...
Linus Torvalds 15 years ago
parent
commit
464480f72e
50 changed files with 1686 additions and 484 deletions
  1. 19 0
      arch/microblaze/Kconfig
  2. 3 0
      arch/microblaze/Kconfig.debug
  3. 2 0
      arch/microblaze/Makefile
  4. 13 2
      arch/microblaze/boot/Makefile
  5. 0 16
      arch/microblaze/include/asm/cache.h
  6. 64 59
      arch/microblaze/include/asm/cacheflush.h
  7. 3 2
      arch/microblaze/include/asm/cpuinfo.h
  8. 12 0
      arch/microblaze/include/asm/device.h
  9. 25 0
      arch/microblaze/include/asm/ftrace.h
  10. 126 1
      arch/microblaze/include/asm/futex.h
  11. 50 62
      arch/microblaze/include/asm/irqflags.h
  12. 2 1
      arch/microblaze/include/asm/page.h
  13. 3 6
      arch/microblaze/include/asm/pgalloc.h
  14. 18 12
      arch/microblaze/include/asm/pvr.h
  15. 2 0
      arch/microblaze/include/asm/setup.h
  16. 2 0
      arch/microblaze/include/asm/system.h
  17. 6 6
      arch/microblaze/include/asm/uaccess.h
  18. 13 1
      arch/microblaze/kernel/Makefile
  19. 4 0
      arch/microblaze/kernel/cpu/Makefile
  20. 477 186
      arch/microblaze/kernel/cpu/cache.c
  21. 13 2
      arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
  22. 9 8
      arch/microblaze/kernel/cpu/cpuinfo-static.c
  23. 2 5
      arch/microblaze/kernel/cpu/cpuinfo.c
  24. 6 2
      arch/microblaze/kernel/cpu/mb.c
  25. 1 1
      arch/microblaze/kernel/cpu/pvr.c
  26. 0 2
      arch/microblaze/kernel/entry-nommu.S
  27. 4 15
      arch/microblaze/kernel/entry.S
  28. 237 0
      arch/microblaze/kernel/ftrace.c
  29. 10 5
      arch/microblaze/kernel/heartbeat.c
  30. 9 1
      arch/microblaze/kernel/intc.c
  31. 170 0
      arch/microblaze/kernel/mcount.S
  32. 5 0
      arch/microblaze/kernel/microblaze_ksyms.c
  33. 1 0
      arch/microblaze/kernel/process.c
  34. 140 0
      arch/microblaze/kernel/reset.c
  35. 6 34
      arch/microblaze/kernel/setup.c
  36. 32 3
      arch/microblaze/kernel/signal.c
  37. 65 0
      arch/microblaze/kernel/stacktrace.c
  38. 2 2
      arch/microblaze/kernel/syscall_table.S
  39. 28 0
      arch/microblaze/kernel/timer.c
  40. 4 2
      arch/microblaze/kernel/vmlinux.lds.S
  41. 7 0
      arch/microblaze/lib/uaccess.c
  42. 1 0
      arch/microblaze/mm/init.c
  43. 0 10
      arch/microblaze/mm/pgtable.c
  44. 13 0
      arch/microblaze/oprofile/Makefile
  45. 22 0
      arch/microblaze/oprofile/microblaze_oprofile.c
  46. 1 20
      arch/microblaze/platform/Kconfig.platform
  47. 14 15
      arch/microblaze/platform/generic/Kconfig.auto
  48. 35 3
      arch/microblaze/platform/generic/system.dts
  49. 2 0
      arch/microblaze/platform/platform.c
  50. 3 0
      scripts/recordmcount.pl

+ 19 - 0
arch/microblaze/Kconfig

@@ -6,8 +6,15 @@ mainmenu "Linux/Microblaze Kernel Configuration"
 config MICROBLAZE
 config MICROBLAZE
 	def_bool y
 	def_bool y
 	select HAVE_LMB
 	select HAVE_LMB
+	select HAVE_FUNCTION_TRACER
+	select HAVE_FUNCTION_TRACE_MCOUNT_TEST
+	select HAVE_FUNCTION_GRAPH_TRACER
+	select HAVE_DYNAMIC_FTRACE
+	select HAVE_FTRACE_MCOUNT_RECORD
 	select USB_ARCH_HAS_EHCI
 	select USB_ARCH_HAS_EHCI
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARCH_WANT_OPTIONAL_GPIOLIB
+	select HAVE_OPROFILE
+	select TRACING_SUPPORT
 
 
 config SWAP
 config SWAP
 	def_bool n
 	def_bool n
@@ -57,12 +64,24 @@ config GENERIC_GPIO
 config GENERIC_CSUM
 config GENERIC_CSUM
 	def_bool y
 	def_bool y
 
 
+config STACKTRACE_SUPPORT
+	def_bool y
+
+config LOCKDEP_SUPPORT
+	def_bool y
+
+config HAVE_LATENCYTOP_SUPPORT
+	def_bool y
+
 config PCI
 config PCI
 	def_bool n
 	def_bool n
 
 
 config NO_DMA
 config NO_DMA
 	def_bool y
 	def_bool y
 
 
+config DTC
+	def_bool y
+
 source "init/Kconfig"
 source "init/Kconfig"
 
 
 source "kernel/Kconfig.freezer"
 source "kernel/Kconfig.freezer"

+ 3 - 0
arch/microblaze/Kconfig.debug

@@ -3,6 +3,9 @@
 
 
 menu "Kernel hacking"
 menu "Kernel hacking"
 
 
+config TRACE_IRQFLAGS_SUPPORT
+	def_bool y
+
 source "lib/Kconfig.debug"
 source "lib/Kconfig.debug"
 
 
 config EARLY_PRINTK
 config EARLY_PRINTK

+ 2 - 0
arch/microblaze/Makefile

@@ -51,6 +51,8 @@ core-y += arch/microblaze/kernel/
 core-y += arch/microblaze/mm/
 core-y += arch/microblaze/mm/
 core-y += arch/microblaze/platform/
 core-y += arch/microblaze/platform/
 
 
+drivers-$(CONFIG_OPROFILE) += arch/microblaze/oprofile/
+
 boot := arch/microblaze/boot
 boot := arch/microblaze/boot
 
 
 # Are we making a simpleImage.<boardname> target? If so, crack out the boardname
 # Are we making a simpleImage.<boardname> target? If so, crack out the boardname

+ 13 - 2
arch/microblaze/boot/Makefile

@@ -2,11 +2,13 @@
 # arch/microblaze/boot/Makefile
 # arch/microblaze/boot/Makefile
 #
 #
 
 
+MKIMAGE := $(srctree)/scripts/mkuboot.sh
+
 obj-y += linked_dtb.o
 obj-y += linked_dtb.o
 
 
 targets := linux.bin linux.bin.gz simpleImage.%
 targets := linux.bin linux.bin.gz simpleImage.%
 
 
-OBJCOPYFLAGS_linux.bin  := -O binary
+OBJCOPYFLAGS := -O binary
 
 
 # Where the DTS files live
 # Where the DTS files live
 dtstree         := $(srctree)/$(src)/dts
 dtstree         := $(srctree)/$(src)/dts
@@ -24,6 +26,7 @@ $(obj)/linux.bin: vmlinux FORCE
 	[ -n $(CONFIG_INITRAMFS_SOURCE) ] && [ ! -e $(CONFIG_INITRAMFS_SOURCE) ] && \
 	[ -n $(CONFIG_INITRAMFS_SOURCE) ] && [ ! -e $(CONFIG_INITRAMFS_SOURCE) ] && \
 	touch $(CONFIG_INITRAMFS_SOURCE) || echo "No CPIO image"
 	touch $(CONFIG_INITRAMFS_SOURCE) || echo "No CPIO image"
 	$(call if_changed,objcopy)
 	$(call if_changed,objcopy)
+	$(call if_changed,uimage)
 	@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 	@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
 
 $(obj)/linux.bin.gz: $(obj)/linux.bin FORCE
 $(obj)/linux.bin.gz: $(obj)/linux.bin FORCE
@@ -36,8 +39,16 @@ quiet_cmd_cp = CP      $< $@$2
 quiet_cmd_strip = STRIP   $@
 quiet_cmd_strip = STRIP   $@
       cmd_strip = $(STRIP) -K _start -K _end -K __log_buf -K _fdt_start vmlinux -o $@
       cmd_strip = $(STRIP) -K _start -K _end -K __log_buf -K _fdt_start vmlinux -o $@
 
 
+quiet_cmd_uimage = UIMAGE  $@.ub
+      cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A microblaze -O linux -T kernel \
+                   -C none -n 'Linux-$(KERNELRELEASE)' \
+                   -a $(CONFIG_KERNEL_BASE_ADDR) -e $(CONFIG_KERNEL_BASE_ADDR) \
+                   -d $@ $@.ub
+
 $(obj)/simpleImage.%: vmlinux FORCE
 $(obj)/simpleImage.%: vmlinux FORCE
 	$(call if_changed,cp,.unstrip)
 	$(call if_changed,cp,.unstrip)
+	$(call if_changed,objcopy)
+	$(call if_changed,uimage)
 	$(call if_changed,strip)
 	$(call if_changed,strip)
 	@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 	@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
 
 
@@ -53,4 +64,4 @@ $(obj)/%.dtb: $(dtstree)/%.dts FORCE
 
 
 clean-kernel += linux.bin linux.bin.gz simpleImage.*
 clean-kernel += linux.bin linux.bin.gz simpleImage.*
 
 
-clean-files += *.dtb
+clean-files += *.dtb simpleImage.*.unstrip

+ 0 - 16
arch/microblaze/include/asm/cache.h

@@ -21,20 +21,4 @@
 
 
 #define SMP_CACHE_BYTES	L1_CACHE_BYTES
 #define SMP_CACHE_BYTES	L1_CACHE_BYTES
 
 
-void _enable_icache(void);
-void _disable_icache(void);
-void _invalidate_icache(unsigned int addr);
-
-#define __enable_icache()		_enable_icache()
-#define __disable_icache()		_disable_icache()
-#define __invalidate_icache(addr)	_invalidate_icache(addr)
-
-void _enable_dcache(void);
-void _disable_dcache(void);
-void _invalidate_dcache(unsigned int addr);
-
-#define __enable_dcache()		_enable_dcache()
-#define __disable_dcache()		_disable_dcache()
-#define __invalidate_dcache(addr)	_invalidate_dcache(addr)
-
 #endif /* _ASM_MICROBLAZE_CACHE_H */
 #endif /* _ASM_MICROBLAZE_CACHE_H */

+ 64 - 59
arch/microblaze/include/asm/cacheflush.h

@@ -18,6 +18,8 @@
 /* Somebody depends on this; sigh... */
 /* Somebody depends on this; sigh... */
 #include <linux/mm.h>
 #include <linux/mm.h>
 
 
+/* Look at Documentation/cachetlb.txt */
+
 /*
 /*
  * Cache handling functions.
  * Cache handling functions.
  * Microblaze has a write-through data cache, meaning that the data cache
  * Microblaze has a write-through data cache, meaning that the data cache
@@ -27,78 +29,81 @@
  * instruction cache to make sure we don't fetch old, bad code.
  * instruction cache to make sure we don't fetch old, bad code.
  */
  */
 
 
+/* struct cache, d=dcache, i=icache, fl = flush, iv = invalidate,
+ * suffix r = range */
+struct scache {
+	/* icache */
+	void (*ie)(void); /* enable */
+	void (*id)(void); /* disable */
+	void (*ifl)(void); /* flush */
+	void (*iflr)(unsigned long a, unsigned long b);
+	void (*iin)(void); /* invalidate */
+	void (*iinr)(unsigned long a, unsigned long b);
+	/* dcache */
+	void (*de)(void); /* enable */
+	void (*dd)(void); /* disable */
+	void (*dfl)(void); /* flush */
+	void (*dflr)(unsigned long a, unsigned long b);
+	void (*din)(void); /* invalidate */
+	void (*dinr)(unsigned long a, unsigned long b);
+};
+
+/* microblaze cache */
+extern struct scache *mbc;
+
+void microblaze_cache_init(void);
+
+#define enable_icache()					mbc->ie();
+#define disable_icache()				mbc->id();
+#define flush_icache()					mbc->ifl();
+#define flush_icache_range(start, end)			mbc->iflr(start, end);
+#define invalidate_icache()				mbc->iin();
+#define invalidate_icache_range(start, end)		mbc->iinr(start, end);
+
+
+#define flush_icache_user_range(vma, pg, adr, len)	flush_icache();
+#define flush_icache_page(vma, pg)			do { } while (0)
+
+#define enable_dcache()					mbc->de();
+#define disable_dcache()				mbc->dd();
 /* FIXME for LL-temac driver */
 /* FIXME for LL-temac driver */
-#define invalidate_dcache_range(start, end) \
-			__invalidate_dcache_range(start, end)
-
-#define flush_cache_all()			__invalidate_cache_all()
-#define flush_cache_mm(mm)			do { } while (0)
-#define flush_cache_range(vma, start, end)	__invalidate_cache_all()
-#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
+#define invalidate_dcache()				mbc->din();
+#define invalidate_dcache_range(start, end)		mbc->dinr(start, end);
+#define flush_dcache()					mbc->dfl();
+#define flush_dcache_range(start, end)			mbc->dflr(start, end);
 
 
-#define flush_dcache_range(start, end)	__invalidate_dcache_range(start, end)
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
 #define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0
+/* D-cache aliasing problem can't happen - cache is between MMU and ram */
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_page(page)			do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_lock(mapping)		do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
 #define flush_dcache_mmap_unlock(mapping)	do { } while (0)
 
 
-#define flush_icache_range(start, len)	__invalidate_icache_range(start, len)
-#define flush_icache_page(vma, pg)		do { } while (0)
-
-#ifndef CONFIG_MMU
-# define flush_icache_user_range(start, len)	do { } while (0)
-#else
-# define flush_icache_user_range(vma, pg, adr, len) __invalidate_icache_all()
-
-# define flush_page_to_ram(page)		do { } while (0)
 
 
-# define flush_icache()			__invalidate_icache_all()
-# define flush_cache_sigtramp(vaddr) \
-			__invalidate_icache_range(vaddr, vaddr + 8)
-
-# define flush_dcache_mmap_lock(mapping)	do { } while (0)
-# define flush_dcache_mmap_unlock(mapping)	do { } while (0)
+#define flush_cache_dup_mm(mm)				do { } while (0)
+#define flush_cache_vmap(start, end)			do { } while (0)
+#define flush_cache_vunmap(start, end)			do { } while (0)
+#define flush_cache_mm(mm)			do { } while (0)
+#define flush_cache_page(vma, vmaddr, pfn)	do { } while (0)
 
 
-# define flush_cache_dup_mm(mm)			do { } while (0)
+/* MS: kgdb code use this macro, wrong len with FLASH */
+#if 0
+#define flush_cache_range(vma, start, len)	{	\
+	flush_icache_range((unsigned) (start), (unsigned) (start) + (len)); \
+	flush_dcache_range((unsigned) (start), (unsigned) (start) + (len)); \
+}
 #endif
 #endif
 
 
-#define flush_cache_vmap(start, end)		do { } while (0)
-#define flush_cache_vunmap(start, end)		do { } while (0)
-
-struct page;
-struct mm_struct;
-struct vm_area_struct;
-
-/* see arch/microblaze/kernel/cache.c */
-extern void __invalidate_icache_all(void);
-extern void __invalidate_icache_range(unsigned long start, unsigned long end);
-extern void __invalidate_icache_page(struct vm_area_struct *vma,
-				struct page *page);
-extern void __invalidate_icache_user_range(struct vm_area_struct *vma,
-				struct page *page,
-				unsigned long adr, int len);
-extern void __invalidate_cache_sigtramp(unsigned long addr);
-
-extern void __invalidate_dcache_all(void);
-extern void __invalidate_dcache_range(unsigned long start, unsigned long end);
-extern void __invalidate_dcache_page(struct vm_area_struct *vma,
-				struct page *page);
-extern void __invalidate_dcache_user_range(struct vm_area_struct *vma,
-				struct page *page,
-				unsigned long adr, int len);
-
-extern inline void __invalidate_cache_all(void)
-{
-	__invalidate_icache_all();
-	__invalidate_dcache_all();
-}
+#define flush_cache_range(vma, start, len) do { } while (0)
 
 
-#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));	\
 } while (0)
 } while (0)
 
 
-#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
-	memcpy((dst), (src), (len))
+#define copy_from_user_page(vma, page, vaddr, dst, src, len)		\
+do {									\
+	memcpy((dst), (src), (len));					\
+} while (0)
 
 
 #endif /* _ASM_MICROBLAZE_CACHEFLUSH_H */
 #endif /* _ASM_MICROBLAZE_CACHEFLUSH_H */

+ 3 - 2
arch/microblaze/include/asm/cpuinfo.h

@@ -43,7 +43,7 @@ struct cpuinfo {
 	u32 use_icache;
 	u32 use_icache;
 	u32 icache_tagbits;
 	u32 icache_tagbits;
 	u32 icache_write;
 	u32 icache_write;
-	u32 icache_line;
+	u32 icache_line_length;
 	u32 icache_size;
 	u32 icache_size;
 	unsigned long icache_base;
 	unsigned long icache_base;
 	unsigned long icache_high;
 	unsigned long icache_high;
@@ -51,8 +51,9 @@ struct cpuinfo {
 	u32 use_dcache;
 	u32 use_dcache;
 	u32 dcache_tagbits;
 	u32 dcache_tagbits;
 	u32 dcache_write;
 	u32 dcache_write;
-	u32 dcache_line;
+	u32 dcache_line_length;
 	u32 dcache_size;
 	u32 dcache_size;
+	u32 dcache_wb;
 	unsigned long dcache_base;
 	unsigned long dcache_base;
 	unsigned long dcache_high;
 	unsigned long dcache_high;
 
 

+ 12 - 0
arch/microblaze/include/asm/device.h

@@ -19,6 +19,18 @@ struct dev_archdata {
 struct pdev_archdata {
 struct pdev_archdata {
 };
 };
 
 
+static inline void dev_archdata_set_node(struct dev_archdata *ad,
+					 struct device_node *np)
+{
+	ad->of_node = np;
+}
+
+static inline struct device_node *
+dev_archdata_get_node(const struct dev_archdata *ad)
+{
+	return ad->of_node;
+}
+
 #endif /* _ASM_MICROBLAZE_DEVICE_H */
 #endif /* _ASM_MICROBLAZE_DEVICE_H */
 
 
 
 

+ 25 - 0
arch/microblaze/include/asm/ftrace.h

@@ -1 +1,26 @@
+#ifndef _ASM_MICROBLAZE_FTRACE
+#define _ASM_MICROBLAZE_FTRACE
 
 
+#ifdef CONFIG_FUNCTION_TRACER
+
+#define MCOUNT_ADDR		((long)(_mcount))
+#define MCOUNT_INSN_SIZE	8 /* sizeof mcount call */
+
+#ifndef __ASSEMBLY__
+extern void _mcount(void);
+extern void ftrace_call_graph(void);
+#endif
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+/* reloction of mcount call site is the same as the address */
+static inline unsigned long ftrace_call_adjust(unsigned long addr)
+{
+	return addr;
+}
+
+struct dyn_arch_ftrace {
+};
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#endif /* CONFIG_FUNCTION_TRACER */
+#endif /* _ASM_MICROBLAZE_FTRACE */

+ 126 - 1
arch/microblaze/include/asm/futex.h

@@ -1 +1,126 @@
-#include <asm-generic/futex.h>
+#ifndef _ASM_MICROBLAZE_FUTEX_H
+#define _ASM_MICROBLAZE_FUTEX_H
+
+#ifdef __KERNEL__
+
+#include <linux/futex.h>
+#include <linux/uaccess.h>
+#include <asm/errno.h>
+
+#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
+({									\
+	__asm__ __volatile__ (						\
+			"1:	lwx	%0, %2, r0; "			\
+				insn					\
+			"2:	swx	%1, %2, r0;			\
+				addic	%1, r0, 0;			\
+				bnei	%1, 1b;				\
+			3:						\
+			.section .fixup,\"ax\";				\
+			4:	brid	3b;				\
+				addik	%1, r0, %3;			\
+			.previous;					\
+			.section __ex_table,\"a\";			\
+			.word	1b,4b,2b,4b;				\
+			.previous;"					\
+	: "=&r" (oldval), "=&r" (ret)					\
+	: "b" (uaddr), "i" (-EFAULT), "r" (oparg)			\
+	);								\
+})
+
+static inline int
+futex_atomic_op_inuser(int encoded_op, int __user *uaddr)
+{
+	int op = (encoded_op >> 28) & 7;
+	int cmp = (encoded_op >> 24) & 15;
+	int oparg = (encoded_op << 8) >> 20;
+	int cmparg = (encoded_op << 20) >> 20;
+	int oldval = 0, ret;
+	if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+		oparg = 1 << oparg;
+
+	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+		return -EFAULT;
+
+	pagefault_disable();
+
+	switch (op) {
+	case FUTEX_OP_SET:
+		__futex_atomic_op("or %1,%4,%4;", ret, oldval, uaddr, oparg);
+		break;
+	case FUTEX_OP_ADD:
+		__futex_atomic_op("add %1,%0,%4;", ret, oldval, uaddr, oparg);
+		break;
+	case FUTEX_OP_OR:
+		__futex_atomic_op("or %1,%0,%4;", ret, oldval, uaddr, oparg);
+		break;
+	case FUTEX_OP_ANDN:
+		__futex_atomic_op("and %1,%0,%4;", ret, oldval, uaddr, oparg);
+		break;
+	case FUTEX_OP_XOR:
+		__futex_atomic_op("xor %1,%0,%4;", ret, oldval, uaddr, oparg);
+		break;
+	default:
+		ret = -ENOSYS;
+	}
+
+	pagefault_enable();
+
+	if (!ret) {
+		switch (cmp) {
+		case FUTEX_OP_CMP_EQ:
+			ret = (oldval == cmparg);
+			break;
+		case FUTEX_OP_CMP_NE:
+			ret = (oldval != cmparg);
+			break;
+		case FUTEX_OP_CMP_LT:
+			ret = (oldval < cmparg);
+			break;
+		case FUTEX_OP_CMP_GE:
+			ret = (oldval >= cmparg);
+			break;
+		case FUTEX_OP_CMP_LE:
+			ret = (oldval <= cmparg);
+			break;
+		case FUTEX_OP_CMP_GT:
+			ret = (oldval > cmparg);
+			break;
+		default:
+			ret = -ENOSYS;
+		}
+	}
+	return ret;
+}
+
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+	int prev, cmp;
+
+	if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+		return -EFAULT;
+
+	__asm__ __volatile__ ("1:	lwx	%0, %2, r0;		\
+					cmp	%1, %0, %3;		\
+					beqi	%1, 3f;			\
+				2:	swx	%4, %2, r0;		\
+					addic	%1, r0, 0;		\
+					bnei	%1, 1b;			\
+				3:					\
+				.section .fixup,\"ax\";			\
+				4:	brid	3b;			\
+					addik	%0, r0, %5;		\
+				.previous;				\
+				.section __ex_table,\"a\";		\
+				.word	1b,4b,2b,4b;			\
+				.previous;"				\
+		: "=&r" (prev), "=&r"(cmp)				\
+		: "r" (uaddr), "r" (oldval), "r" (newval), "i" (-EFAULT));
+
+	return prev;
+}
+
+#endif /* __KERNEL__ */
+
+#endif

+ 50 - 62
arch/microblaze/include/asm/irqflags.h

@@ -10,78 +10,73 @@
 #define _ASM_MICROBLAZE_IRQFLAGS_H
 #define _ASM_MICROBLAZE_IRQFLAGS_H
 
 
 #include <linux/irqflags.h>
 #include <linux/irqflags.h>
+#include <asm/registers.h>
 
 
 # if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
 # if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
 
 
-# define local_irq_save(flags)				\
+# define raw_local_irq_save(flags)			\
 	do {						\
 	do {						\
-		asm volatile ("# local_irq_save	\n\t"	\
-				"msrclr %0, %1	\n\t"	\
-				"nop	\n\t"		\
+		asm volatile ("	msrclr %0, %1;		\
+				nop;"			\
 				: "=r"(flags)		\
 				: "=r"(flags)		\
 				: "i"(MSR_IE)		\
 				: "i"(MSR_IE)		\
 				: "memory");		\
 				: "memory");		\
 	} while (0)
 	} while (0)
 
 
-# define local_irq_disable()					\
-	do {							\
-		asm volatile ("# local_irq_disable \n\t"	\
-				"msrclr r0, %0 \n\t"		\
-				"nop	\n\t"			\
-				:				\
-				: "i"(MSR_IE)			\
-				: "memory");			\
+# define raw_local_irq_disable()			\
+	do {						\
+		asm volatile ("	msrclr r0, %0;		\
+				nop;"			\
+				:			\
+				: "i"(MSR_IE)		\
+				: "memory");		\
 	} while (0)
 	} while (0)
 
 
-# define local_irq_enable()					\
-	do {							\
-		asm volatile ("# local_irq_enable \n\t"		\
-				"msrset	r0, %0 \n\t"		\
-				"nop	\n\t"			\
-				:				\
-				: "i"(MSR_IE)			\
-				: "memory");			\
+# define raw_local_irq_enable()				\
+	do {						\
+		asm volatile ("	msrset	r0, %0;		\
+				nop;"			\
+				:			\
+				: "i"(MSR_IE)		\
+				: "memory");		\
 	} while (0)
 	} while (0)
 
 
 # else /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR == 0 */
 # else /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR == 0 */
 
 
-# define local_irq_save(flags)					\
+# define raw_local_irq_save(flags)				\
 	do {							\
 	do {							\
 		register unsigned tmp;				\
 		register unsigned tmp;				\
-		asm volatile ("# local_irq_save	\n\t"		\
-				"mfs	%0, rmsr \n\t"		\
-				"nop \n\t"			\
-				"andi	%1, %0, %2 \n\t"	\
-				"mts	rmsr, %1 \n\t"		\
-				"nop \n\t"			\
+		asm volatile ("	mfs	%0, rmsr;		\
+				nop;				\
+				andi	%1, %0, %2;		\
+				mts	rmsr, %1;		\
+				nop;"				\
 				: "=r"(flags), "=r" (tmp)	\
 				: "=r"(flags), "=r" (tmp)	\
 				: "i"(~MSR_IE)			\
 				: "i"(~MSR_IE)			\
 				: "memory");			\
 				: "memory");			\
 	} while (0)
 	} while (0)
 
 
-# define local_irq_disable()					\
+# define raw_local_irq_disable()				\
 	do {							\
 	do {							\
 		register unsigned tmp;				\
 		register unsigned tmp;				\
-		asm volatile ("# local_irq_disable \n\t"	\
-				"mfs	%0, rmsr \n\t"		\
-				"nop \n\t"			\
-				"andi	%0, %0, %1 \n\t"	\
-				"mts	rmsr, %0 \n\t"		\
-				"nop \n\t"			\
+		asm volatile ("	mfs	%0, rmsr;		\
+				nop;				\
+				andi	%0, %0, %1;		\
+				mts	rmsr, %0;		\
+				nop;"			\
 				: "=r"(tmp)			\
 				: "=r"(tmp)			\
 				: "i"(~MSR_IE)			\
 				: "i"(~MSR_IE)			\
 				: "memory");			\
 				: "memory");			\
 	} while (0)
 	} while (0)
 
 
-# define local_irq_enable()					\
+# define raw_local_irq_enable()					\
 	do {							\
 	do {							\
 		register unsigned tmp;				\
 		register unsigned tmp;				\
-		asm volatile ("# local_irq_enable \n\t"		\
-				"mfs	%0, rmsr \n\t"		\
-				"nop \n\t"			\
-				"ori	%0, %0, %1 \n\t"	\
-				"mts	rmsr, %0 \n\t"		\
-				"nop \n\t"			\
+		asm volatile ("	mfs	%0, rmsr;		\
+				nop;				\
+				ori	%0, %0, %1;		\
+				mts	rmsr, %0;		\
+				nop;"				\
 				: "=r"(tmp)			\
 				: "=r"(tmp)			\
 				: "i"(MSR_IE)			\
 				: "i"(MSR_IE)			\
 				: "memory");			\
 				: "memory");			\
@@ -89,35 +84,28 @@
 
 
 # endif /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */
 # endif /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */
 
 
-#define local_save_flags(flags)					\
+#define raw_local_irq_restore(flags)				\
 	do {							\
 	do {							\
-		asm volatile ("# local_save_flags \n\t"		\
-				"mfs	%0, rmsr \n\t"		\
-				"nop	\n\t"			\
-				: "=r"(flags)			\
+		asm volatile ("	mts	rmsr, %0;		\
+				nop;"				\
 				:				\
 				:				\
+				: "r"(flags)			\
 				: "memory");			\
 				: "memory");			\
 	} while (0)
 	} while (0)
 
 
-#define local_irq_restore(flags)			\
-	do {						\
-		asm volatile ("# local_irq_restore \n\t"\
-				"mts	rmsr, %0 \n\t"	\
-				"nop	\n\t"		\
-				:			\
-				: "r"(flags)		\
-				: "memory");		\
-	} while (0)
-
-static inline int irqs_disabled(void)
+static inline unsigned long get_msr(void)
 {
 {
 	unsigned long flags;
 	unsigned long flags;
-
-	local_save_flags(flags);
-	return ((flags & MSR_IE) == 0);
+	asm volatile ("	mfs	%0, rmsr;	\
+			nop;"			\
+			: "=r"(flags)		\
+			:			\
+			: "memory");		\
+	return flags;
 }
 }
 
 
-#define raw_irqs_disabled irqs_disabled
-#define raw_irqs_disabled_flags(flags)	((flags) == 0)
+#define raw_local_save_flags(flags)	((flags) = get_msr())
+#define raw_irqs_disabled()		((get_msr() & MSR_IE) == 0)
+#define raw_irqs_disabled_flags(flags)	((flags & MSR_IE) == 0)
 
 
 #endif /* _ASM_MICROBLAZE_IRQFLAGS_H */
 #endif /* _ASM_MICROBLAZE_IRQFLAGS_H */

+ 2 - 1
arch/microblaze/include/asm/page.h

@@ -164,7 +164,8 @@ extern int page_is_ram(unsigned long pfn);
 #  endif /* CONFIG_MMU */
 #  endif /* CONFIG_MMU */
 
 
 #  ifndef CONFIG_MMU
 #  ifndef CONFIG_MMU
-#  define pfn_valid(pfn)	((pfn) >= min_low_pfn && (pfn) <= max_mapnr)
+#  define pfn_valid(pfn)	(((pfn) >= min_low_pfn) && \
+				((pfn) <= (min_low_pfn + max_mapnr)))
 #  define ARCH_PFN_OFFSET	(PAGE_OFFSET >> PAGE_SHIFT)
 #  define ARCH_PFN_OFFSET	(PAGE_OFFSET >> PAGE_SHIFT)
 #  else /* CONFIG_MMU */
 #  else /* CONFIG_MMU */
 #  define ARCH_PFN_OFFSET	(memory_start >> PAGE_SHIFT)
 #  define ARCH_PFN_OFFSET	(memory_start >> PAGE_SHIFT)

+ 3 - 6
arch/microblaze/include/asm/pgalloc.h

@@ -106,9 +106,6 @@ extern inline void free_pgd_slow(pgd_t *pgd)
  */
  */
 #define pmd_alloc_one_fast(mm, address)	({ BUG(); ((pmd_t *)1); })
 #define pmd_alloc_one_fast(mm, address)	({ BUG(); ((pmd_t *)1); })
 #define pmd_alloc_one(mm, address)	({ BUG(); ((pmd_t *)2); })
 #define pmd_alloc_one(mm, address)	({ BUG(); ((pmd_t *)2); })
-/* FIXME two definition - look below */
-#define pmd_free(mm, x)			do { } while (0)
-#define pgd_populate(mm, pmd, pte)	BUG()
 
 
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
 		unsigned long address)
 		unsigned long address)
@@ -192,14 +189,14 @@ extern inline void pte_free(struct mm_struct *mm, struct page *ptepage)
  * the pgd will always be present..
  * the pgd will always be present..
  */
  */
 #define pmd_alloc_one(mm, address)	({ BUG(); ((pmd_t *)2); })
 #define pmd_alloc_one(mm, address)	({ BUG(); ((pmd_t *)2); })
-/*#define pmd_free(mm, x)			do { } while (0)*/
-#define __pmd_free_tlb(tlb, x, addr)	do { } while (0)
+#define pmd_free(mm, x)			do { } while (0)
+#define __pmd_free_tlb(tlb, x, addr)	pmd_free((tlb)->mm, x)
 #define pgd_populate(mm, pmd, pte)	BUG()
 #define pgd_populate(mm, pmd, pte)	BUG()
 
 
 extern int do_check_pgt_cache(int, int);
 extern int do_check_pgt_cache(int, int);
 
 
 #endif /* CONFIG_MMU */
 #endif /* CONFIG_MMU */
 
 
-#define check_pgt_cache()	do {} while (0)
+#define check_pgt_cache()		do { } while (0)
 
 
 #endif /* _ASM_MICROBLAZE_PGALLOC_H */
 #endif /* _ASM_MICROBLAZE_PGALLOC_H */

+ 18 - 12
arch/microblaze/include/asm/pvr.h

@@ -76,20 +76,23 @@ struct pvr_s {
 #define PVR3_FSL_LINKS_MASK		0x00000380
 #define PVR3_FSL_LINKS_MASK		0x00000380
 
 
 /* ICache config PVR masks */
 /* ICache config PVR masks */
-#define PVR4_USE_ICACHE_MASK		0x80000000
-#define PVR4_ICACHE_ADDR_TAG_BITS_MASK	0x7C000000
-#define PVR4_ICACHE_USE_FSL_MASK	0x02000000
-#define PVR4_ICACHE_ALLOW_WR_MASK	0x01000000
-#define PVR4_ICACHE_LINE_LEN_MASK	0x00E00000
-#define PVR4_ICACHE_BYTE_SIZE_MASK	0x001F0000
+#define PVR4_USE_ICACHE_MASK		0x80000000 /* ICU */
+#define PVR4_ICACHE_ADDR_TAG_BITS_MASK	0x7C000000 /* ICTS */
+#define PVR4_ICACHE_ALLOW_WR_MASK	0x01000000 /* ICW */
+#define PVR4_ICACHE_LINE_LEN_MASK	0x00E00000 /* ICLL */
+#define PVR4_ICACHE_BYTE_SIZE_MASK	0x001F0000 /* ICBS */
+#define PVR4_ICACHE_ALWAYS_USED		0x00008000 /* IAU */
+#define PVR4_ICACHE_INTERFACE		0x00002000 /* ICI */
 
 
 /* DCache config PVR masks */
 /* DCache config PVR masks */
-#define PVR5_USE_DCACHE_MASK		0x80000000
-#define PVR5_DCACHE_ADDR_TAG_BITS_MASK	0x7C000000
-#define PVR5_DCACHE_USE_FSL_MASK	0x02000000
-#define PVR5_DCACHE_ALLOW_WR_MASK	0x01000000
-#define PVR5_DCACHE_LINE_LEN_MASK	0x00E00000
-#define PVR5_DCACHE_BYTE_SIZE_MASK	0x001F0000
+#define PVR5_USE_DCACHE_MASK		0x80000000 /* DCU */
+#define PVR5_DCACHE_ADDR_TAG_BITS_MASK	0x7C000000 /* DCTS */
+#define PVR5_DCACHE_ALLOW_WR_MASK	0x01000000 /* DCW */
+#define PVR5_DCACHE_LINE_LEN_MASK	0x00E00000 /* DCLL */
+#define PVR5_DCACHE_BYTE_SIZE_MASK	0x001F0000 /* DCBS */
+#define PVR5_DCACHE_ALWAYS_USED		0x00008000 /* DAU */
+#define PVR5_DCACHE_USE_WRITEBACK	0x00004000 /* DWB */
+#define PVR5_DCACHE_INTERFACE		0x00002000 /* DCI */
 
 
 /* ICache base address PVR mask */
 /* ICache base address PVR mask */
 #define PVR6_ICACHE_BASEADDR_MASK	0xFFFFFFFF
 #define PVR6_ICACHE_BASEADDR_MASK	0xFFFFFFFF
@@ -178,11 +181,14 @@ struct pvr_s {
 			((pvr.pvr[5] & PVR5_DCACHE_ADDR_TAG_BITS_MASK) >> 26)
 			((pvr.pvr[5] & PVR5_DCACHE_ADDR_TAG_BITS_MASK) >> 26)
 #define PVR_DCACHE_USE_FSL(pvr)		(pvr.pvr[5] & PVR5_DCACHE_USE_FSL_MASK)
 #define PVR_DCACHE_USE_FSL(pvr)		(pvr.pvr[5] & PVR5_DCACHE_USE_FSL_MASK)
 #define PVR_DCACHE_ALLOW_WR(pvr)	(pvr.pvr[5] & PVR5_DCACHE_ALLOW_WR_MASK)
 #define PVR_DCACHE_ALLOW_WR(pvr)	(pvr.pvr[5] & PVR5_DCACHE_ALLOW_WR_MASK)
+/* FIXME two shifts on one line needs any comment */
 #define PVR_DCACHE_LINE_LEN(pvr) \
 #define PVR_DCACHE_LINE_LEN(pvr) \
 			(1 << ((pvr.pvr[5] & PVR5_DCACHE_LINE_LEN_MASK) >> 21))
 			(1 << ((pvr.pvr[5] & PVR5_DCACHE_LINE_LEN_MASK) >> 21))
 #define PVR_DCACHE_BYTE_SIZE(pvr) \
 #define PVR_DCACHE_BYTE_SIZE(pvr) \
 			(1 << ((pvr.pvr[5] & PVR5_DCACHE_BYTE_SIZE_MASK) >> 16))
 			(1 << ((pvr.pvr[5] & PVR5_DCACHE_BYTE_SIZE_MASK) >> 16))
 
 
+#define PVR_DCACHE_USE_WRITEBACK(pvr) \
+			((pvr.pvr[5] & PVR5_DCACHE_USE_WRITEBACK) >> 14)
 
 
 #define PVR_ICACHE_BASEADDR(pvr)	(pvr.pvr[6] & PVR6_ICACHE_BASEADDR_MASK)
 #define PVR_ICACHE_BASEADDR(pvr)	(pvr.pvr[6] & PVR6_ICACHE_BASEADDR_MASK)
 #define PVR_ICACHE_HIGHADDR(pvr)	(pvr.pvr[7] & PVR7_ICACHE_HIGHADDR_MASK)
 #define PVR_ICACHE_HIGHADDR(pvr)	(pvr.pvr[7] & PVR7_ICACHE_HIGHADDR_MASK)

+ 2 - 0
arch/microblaze/include/asm/setup.h

@@ -35,6 +35,8 @@ extern void mmu_reset(void);
 extern void early_console_reg_tlb_alloc(unsigned int addr);
 extern void early_console_reg_tlb_alloc(unsigned int addr);
 #   endif /* CONFIG_MMU */
 #   endif /* CONFIG_MMU */
 
 
+extern void of_platform_reset_gpio_probe(void);
+
 void time_init(void);
 void time_init(void);
 void init_IRQ(void);
 void init_IRQ(void);
 void machine_early_init(const char *cmdline, unsigned int ram,
 void machine_early_init(const char *cmdline, unsigned int ram,

+ 2 - 0
arch/microblaze/include/asm/system.h

@@ -16,6 +16,8 @@
 #include <asm-generic/cmpxchg.h>
 #include <asm-generic/cmpxchg.h>
 #include <asm-generic/cmpxchg-local.h>
 #include <asm-generic/cmpxchg-local.h>
 
 
+#define __ARCH_WANT_INTERRUPTS_ON_CTXSW
+
 struct task_struct;
 struct task_struct;
 struct thread_info;
 struct thread_info;
 
 

+ 6 - 6
arch/microblaze/include/asm/uaccess.h

@@ -272,8 +272,9 @@ static inline int clear_user(char *to, int size)
 	return size;
 	return size;
 }
 }
 
 
-extern unsigned long __copy_tofrom_user(void __user *to,
-		const void __user *from, unsigned long size);
+#define __copy_from_user(to, from, n)	copy_from_user((to), (from), (n))
+#define __copy_from_user_inatomic(to, from, n) \
+		copy_from_user((to), (from), (n))
 
 
 #define copy_to_user(to, from, n)					\
 #define copy_to_user(to, from, n)					\
 	(access_ok(VERIFY_WRITE, (to), (n)) ?				\
 	(access_ok(VERIFY_WRITE, (to), (n)) ?				\
@@ -290,10 +291,6 @@ extern unsigned long __copy_tofrom_user(void __user *to,
 			(void __user *)(from), (n))			\
 			(void __user *)(from), (n))			\
 		: -EFAULT)
 		: -EFAULT)
 
 
-#define __copy_from_user(to, from, n)	copy_from_user((to), (from), (n))
-#define __copy_from_user_inatomic(to, from, n) \
-		copy_from_user((to), (from), (n))
-
 extern int __strncpy_user(char *to, const char __user *from, int len);
 extern int __strncpy_user(char *to, const char __user *from, int len);
 extern int __strnlen_user(const char __user *sstr, int len);
 extern int __strnlen_user(const char __user *sstr, int len);
 
 
@@ -305,6 +302,9 @@ extern int __strnlen_user(const char __user *sstr, int len);
 
 
 #endif /* CONFIG_MMU */
 #endif /* CONFIG_MMU */
 
 
+extern unsigned long __copy_tofrom_user(void __user *to,
+		const void __user *from, unsigned long size);
+
 /*
 /*
  * The exception table consists of pairs of addresses: the first is the
  * The exception table consists of pairs of addresses: the first is the
  * address of an instruction that is allowed to fault, and the second is
  * address of an instruction that is allowed to fault, and the second is

+ 13 - 1
arch/microblaze/kernel/Makefile

@@ -2,12 +2,22 @@
 # Makefile
 # Makefile
 #
 #
 
 
+ifdef CONFIG_FUNCTION_TRACER
+# Do not trace early boot code and low level code
+CFLAGS_REMOVE_timer.o = -pg
+CFLAGS_REMOVE_intc.o = -pg
+CFLAGS_REMOVE_early_printk.o = -pg
+CFLAGS_REMOVE_selfmod.o = -pg
+CFLAGS_REMOVE_heartbeat.o = -pg
+CFLAGS_REMOVE_ftrace.o = -pg
+endif
+
 extra-y := head.o vmlinux.lds
 extra-y := head.o vmlinux.lds
 
 
 obj-y += exceptions.o \
 obj-y += exceptions.o \
 	hw_exception_handler.o init_task.o intc.o irq.o of_device.o \
 	hw_exception_handler.o init_task.o intc.o irq.o of_device.o \
 	of_platform.o process.o prom.o prom_parse.o ptrace.o \
 	of_platform.o process.o prom.o prom_parse.o ptrace.o \
-	setup.o signal.o sys_microblaze.o timer.o traps.o
+	setup.o signal.o sys_microblaze.o timer.o traps.o reset.o
 
 
 obj-y += cpu/
 obj-y += cpu/
 
 
@@ -16,5 +26,7 @@ obj-$(CONFIG_SELFMOD)		+= selfmod.o
 obj-$(CONFIG_HEART_BEAT)	+= heartbeat.o
 obj-$(CONFIG_HEART_BEAT)	+= heartbeat.o
 obj-$(CONFIG_MODULES)		+= microblaze_ksyms.o module.o
 obj-$(CONFIG_MODULES)		+= microblaze_ksyms.o module.o
 obj-$(CONFIG_MMU)		+= misc.o
 obj-$(CONFIG_MMU)		+= misc.o
+obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
+obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o mcount.o
 
 
 obj-y	+= entry$(MMU).o
 obj-y	+= entry$(MMU).o

+ 4 - 0
arch/microblaze/kernel/cpu/Makefile

@@ -2,6 +2,10 @@
 # Build the appropriate CPU version support
 # Build the appropriate CPU version support
 #
 #
 
 
+ifdef CONFIG_FUNCTION_TRACER
+CFLAGS_REMOVE_cache.o = -pg
+endif
+
 EXTRA_CFLAGS += -DCPU_MAJOR=$(CPU_MAJOR) -DCPU_MINOR=$(CPU_MINOR) \
 EXTRA_CFLAGS += -DCPU_MAJOR=$(CPU_MAJOR) -DCPU_MINOR=$(CPU_MINOR) \
 		-DCPU_REV=$(CPU_REV)
 		-DCPU_REV=$(CPU_REV)
 
 

+ 477 - 186
arch/microblaze/kernel/cpu/cache.c

@@ -3,7 +3,7 @@
  *
  *
  * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
  * Copyright (C) 2007-2009 PetaLogix
  * Copyright (C) 2007-2009 PetaLogix
- * Copyright (C) 2007 John Williams <john.williams@petalogix.com>
+ * Copyright (C) 2007-2009 John Williams <john.williams@petalogix.com>
  *
  *
  * This file is subject to the terms and conditions of the GNU General
  * This file is subject to the terms and conditions of the GNU General
  * Public License. See the file COPYING in the main directory of this
  * Public License. See the file COPYING in the main directory of this
@@ -13,243 +13,534 @@
 #include <asm/cacheflush.h>
 #include <asm/cacheflush.h>
 #include <linux/cache.h>
 #include <linux/cache.h>
 #include <asm/cpuinfo.h>
 #include <asm/cpuinfo.h>
+#include <asm/pvr.h>
 
 
-/* Exported functions */
+static inline void __invalidate_flush_icache(unsigned int addr)
+{
+	__asm__ __volatile__ ("wic	%0, r0;"	\
+					: : "r" (addr));
+}
+
+static inline void __flush_dcache(unsigned int addr)
+{
+	__asm__ __volatile__ ("wdc.flush	%0, r0;"	\
+					: : "r" (addr));
+}
+
+static inline void __invalidate_dcache(unsigned int baseaddr,
+						unsigned int offset)
+{
+	__asm__ __volatile__ ("wdc.clear	%0, %1;"	\
+					: : "r" (baseaddr), "r" (offset));
+}
 
 
-void _enable_icache(void)
+static inline void __enable_icache_msr(void)
 {
 {
-	if (cpuinfo.use_icache) {
-#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
-		__asm__ __volatile__ ("					\
-				msrset	r0, %0;				\
-				nop; "					\
-				:					\
-				: "i" (MSR_ICE)				\
+	__asm__ __volatile__ ("	msrset	r0, %0;		\
+				nop; "			\
+			: : "i" (MSR_ICE) : "memory");
+}
+
+static inline void __disable_icache_msr(void)
+{
+	__asm__ __volatile__ ("	msrclr	r0, %0;		\
+				nop; "			\
+			: : "i" (MSR_ICE) : "memory");
+}
+
+static inline void __enable_dcache_msr(void)
+{
+	__asm__ __volatile__ ("	msrset	r0, %0;		\
+				nop; "			\
+				:			\
+				: "i" (MSR_DCE)		\
 				: "memory");
 				: "memory");
-#else
-		__asm__ __volatile__ ("					\
-				mfs	r12, rmsr;			\
-				nop;					\
-				ori	r12, r12, %0;			\
-				mts	rmsr, r12;			\
-				nop; "					\
-				:					\
-				: "i" (MSR_ICE)				\
-				: "memory", "r12");
-#endif
-	}
 }
 }
 
 
-void _disable_icache(void)
+static inline void __disable_dcache_msr(void)
 {
 {
-	if (cpuinfo.use_icache) {
-#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
-		__asm__ __volatile__ ("					\
-				msrclr r0, %0;				\
-				nop; "					\
-				:					\
-				: "i" (MSR_ICE)				\
+	__asm__ __volatile__ ("	msrclr	r0, %0;		\
+				nop; "			\
+				:			\
+				: "i" (MSR_DCE)		\
 				: "memory");
 				: "memory");
-#else
-		__asm__ __volatile__ ("					\
-				mfs	r12, rmsr;			\
-				nop;					\
-				andi	r12, r12, ~%0;			\
-				mts	rmsr, r12;			\
-				nop; "					\
-				:					\
-				: "i" (MSR_ICE)				\
+}
+
+static inline void __enable_icache_nomsr(void)
+{
+	__asm__ __volatile__ ("	mfs	r12, rmsr;	\
+				nop;			\
+				ori	r12, r12, %0;	\
+				mts	rmsr, r12;	\
+				nop; "			\
+				:			\
+				: "i" (MSR_ICE)		\
 				: "memory", "r12");
 				: "memory", "r12");
-#endif
-	}
 }
 }
 
 
-void _invalidate_icache(unsigned int addr)
+static inline void __disable_icache_nomsr(void)
 {
 {
-	if (cpuinfo.use_icache) {
-		__asm__ __volatile__ ("					\
-				wic	%0, r0"				\
-				:					\
-				: "r" (addr));
-	}
+	__asm__ __volatile__ ("	mfs	r12, rmsr;	\
+				nop;			\
+				andi	r12, r12, ~%0;	\
+				mts	rmsr, r12;	\
+				nop; "			\
+				:			\
+				: "i" (MSR_ICE)		\
+				: "memory", "r12");
 }
 }
 
 
-void _enable_dcache(void)
+static inline void __enable_dcache_nomsr(void)
 {
 {
-	if (cpuinfo.use_dcache) {
-#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
-		__asm__ __volatile__ ("					\
-				msrset	r0, %0;				\
-				nop; "					\
-				:					\
-				: "i" (MSR_DCE)				\
-				: "memory");
-#else
-		__asm__ __volatile__ ("					\
-				mfs	r12, rmsr;			\
-				nop;					\
-				ori	r12, r12, %0;			\
-				mts	rmsr, r12;			\
-				nop; "					\
-				:					\
-				: "i" (MSR_DCE)			\
+	__asm__ __volatile__ ("	mfs	r12, rmsr;	\
+				nop;			\
+				ori	r12, r12, %0;	\
+				mts	rmsr, r12;	\
+				nop; "			\
+				:			\
+				: "i" (MSR_DCE)		\
 				: "memory", "r12");
 				: "memory", "r12");
-#endif
-	}
 }
 }
 
 
-void _disable_dcache(void)
+static inline void __disable_dcache_nomsr(void)
 {
 {
-#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
-		__asm__ __volatile__ ("					\
-				msrclr	r0, %0;				\
-				nop; "					\
-				:					\
-				: "i" (MSR_DCE)			\
-				: "memory");
-#else
-		__asm__ __volatile__ ("					\
-				mfs	r12, rmsr;			\
-				nop;					\
-				andi	r12, r12, ~%0;			\
-				mts	rmsr, r12;			\
-				nop; "					\
-				:					\
-				: "i" (MSR_DCE)			\
+	__asm__ __volatile__ ("	mfs	r12, rmsr;	\
+				nop;			\
+				andi	r12, r12, ~%0;	\
+				mts	rmsr, r12;	\
+				nop; "			\
+				:			\
+				: "i" (MSR_DCE)		\
 				: "memory", "r12");
 				: "memory", "r12");
-#endif
 }
 }
 
 
-void _invalidate_dcache(unsigned int addr)
+
+/* Helper macro for computing the limits of cache range loops */
+#define CACHE_LOOP_LIMITS(start, end, cache_line_length, cache_size)	\
+do {									\
+	int align = ~(cache_line_length - 1);				\
+	end = min(start + cache_size, end);				\
+	start &= align;							\
+	end = ((end & align) + cache_line_length);			\
+} while (0);
+
+/*
+ * Helper macro to loop over the specified cache_size/line_length and
+ * execute 'op' on that cacheline
+ */
+#define CACHE_ALL_LOOP(cache_size, line_length, op)			\
+do {									\
+	unsigned int len = cache_size;					\
+	int step = -line_length;					\
+	BUG_ON(step >= 0);						\
+									\
+	__asm__ __volatile__ (" 1:      " #op " %0, r0;			\
+					bgtid   %0, 1b;			\
+					addk    %0, %0, %1;		\
+					" : : "r" (len), "r" (step)	\
+					: "memory");			\
+} while (0);
+
+
+#define CACHE_ALL_LOOP2(cache_size, line_length, op)			\
+do {									\
+	unsigned int len = cache_size;					\
+	int step = -line_length;					\
+	BUG_ON(step >= 0);						\
+									\
+	__asm__ __volatile__ (" 1:      " #op " r0, %0;			\
+					bgtid   %0, 1b;			\
+					addk    %0, %0, %1;		\
+					" : : "r" (len), "r" (step)	\
+					: "memory");			\
+} while (0);
+
+/* for wdc.flush/clear */
+#define CACHE_RANGE_LOOP_2(start, end, line_length, op)			\
+do {									\
+	int step = -line_length;					\
+	int count = end - start;					\
+	BUG_ON(count <= 0);						\
+									\
+	__asm__ __volatile__ (" 1:	" #op " %0, %1;			\
+					bgtid   %1, 1b;			\
+					addk    %1, %1, %2;		\
+					" : : "r" (start), "r" (count),	\
+					"r" (step) : "memory");		\
+} while (0);
+
+/* It is used only first parameter for OP - for wic, wdc */
+#define CACHE_RANGE_LOOP_1(start, end, line_length, op)			\
+do {									\
+	int step = -line_length;					\
+	int count = end - start;					\
+	BUG_ON(count <= 0);						\
+									\
+	__asm__ __volatile__ (" 1:	addk	%0, %0, %1;		\
+					" #op " %0, r0;			\
+					bgtid   %1, 1b;			\
+					addk    %1, %1, %2;		\
+					" : : "r" (start), "r" (count),	\
+					"r" (step) : "memory");		\
+} while (0);
+
+static void __flush_icache_range_msr_irq(unsigned long start, unsigned long end)
 {
 {
-		__asm__ __volatile__ ("					\
-				wdc	%0, r0"				\
-				:					\
-				: "r" (addr));
+	unsigned long flags;
+
+	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+				(unsigned int)start, (unsigned int) end);
+
+	CACHE_LOOP_LIMITS(start, end,
+			cpuinfo.icache_line_length, cpuinfo.icache_size);
+
+	local_irq_save(flags);
+	__disable_icache_msr();
+
+	CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
+
+	__enable_icache_msr();
+	local_irq_restore(flags);
 }
 }
 
 
-void __invalidate_icache_all(void)
+static void __flush_icache_range_nomsr_irq(unsigned long start,
+				unsigned long end)
 {
 {
-	unsigned int i;
-	unsigned flags;
+	unsigned long flags;
 
 
-	if (cpuinfo.use_icache) {
-		local_irq_save(flags);
-		__disable_icache();
+	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+				(unsigned int)start, (unsigned int) end);
 
 
-		/* Just loop through cache size and invalidate, no need to add
-			CACHE_BASE address */
-		for (i = 0; i < cpuinfo.icache_size;
-			i += cpuinfo.icache_line)
-				__invalidate_icache(i);
+	CACHE_LOOP_LIMITS(start, end,
+			cpuinfo.icache_line_length, cpuinfo.icache_size);
 
 
-		__enable_icache();
-		local_irq_restore(flags);
-	}
+	local_irq_save(flags);
+	__disable_icache_nomsr();
+
+	CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
+
+	__enable_icache_nomsr();
+	local_irq_restore(flags);
 }
 }
 
 
-void __invalidate_icache_range(unsigned long start, unsigned long end)
+static void __flush_icache_range_noirq(unsigned long start,
+				unsigned long end)
 {
 {
-	unsigned int i;
-	unsigned flags;
-	unsigned int align;
-
-	if (cpuinfo.use_icache) {
-		/*
-		 * No need to cover entire cache range,
-		 * just cover cache footprint
-		 */
-		end = min(start + cpuinfo.icache_size, end);
-		align = ~(cpuinfo.icache_line - 1);
-		start &= align; /* Make sure we are aligned */
-		/* Push end up to the next cache line */
-		end = ((end & align) + cpuinfo.icache_line);
-
-		local_irq_save(flags);
-		__disable_icache();
-
-		for (i = start; i < end; i += cpuinfo.icache_line)
-			__invalidate_icache(i);
-
-		__enable_icache();
-		local_irq_restore(flags);
-	}
+	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+				(unsigned int)start, (unsigned int) end);
+
+	CACHE_LOOP_LIMITS(start, end,
+			cpuinfo.icache_line_length, cpuinfo.icache_size);
+	CACHE_RANGE_LOOP_1(start, end, cpuinfo.icache_line_length, wic);
+}
+
+static void __flush_icache_all_msr_irq(void)
+{
+	unsigned long flags;
+
+	pr_debug("%s\n", __func__);
+
+	local_irq_save(flags);
+	__disable_icache_msr();
+
+	CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
+
+	__enable_icache_msr();
+	local_irq_restore(flags);
+}
+
+static void __flush_icache_all_nomsr_irq(void)
+{
+	unsigned long flags;
+
+	pr_debug("%s\n", __func__);
+
+	local_irq_save(flags);
+	__disable_icache_nomsr();
+
+	CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
+
+	__enable_icache_nomsr();
+	local_irq_restore(flags);
 }
 }
 
 
-void __invalidate_icache_page(struct vm_area_struct *vma, struct page *page)
+static void __flush_icache_all_noirq(void)
 {
 {
-	__invalidate_icache_all();
+	pr_debug("%s\n", __func__);
+	CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
 }
 }
 
 
-void __invalidate_icache_user_range(struct vm_area_struct *vma,
-				struct page *page, unsigned long adr,
-				int len)
+static void __invalidate_dcache_all_msr_irq(void)
 {
 {
-	__invalidate_icache_all();
+	unsigned long flags;
+
+	pr_debug("%s\n", __func__);
+
+	local_irq_save(flags);
+	__disable_dcache_msr();
+
+	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
+
+	__enable_dcache_msr();
+	local_irq_restore(flags);
 }
 }
 
 
-void __invalidate_cache_sigtramp(unsigned long addr)
+static void __invalidate_dcache_all_nomsr_irq(void)
 {
 {
-	__invalidate_icache_range(addr, addr + 8);
+	unsigned long flags;
+
+	pr_debug("%s\n", __func__);
+
+	local_irq_save(flags);
+	__disable_dcache_nomsr();
+
+	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc);
+
+	__enable_dcache_nomsr();
+	local_irq_restore(flags);
 }
 }
 
 
-void __invalidate_dcache_all(void)
+static void __invalidate_dcache_all_noirq_wt(void)
 {
 {
-	unsigned int i;
-	unsigned flags;
-
-	if (cpuinfo.use_dcache) {
-		local_irq_save(flags);
-		__disable_dcache();
-
-		/*
-		 * Just loop through cache size and invalidate,
-		 * no need to add CACHE_BASE address
-		 */
-		for (i = 0; i < cpuinfo.dcache_size;
-			i += cpuinfo.dcache_line)
-				__invalidate_dcache(i);
-
-		__enable_dcache();
-		local_irq_restore(flags);
-	}
+	pr_debug("%s\n", __func__);
+	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc)
 }
 }
 
 
-void __invalidate_dcache_range(unsigned long start, unsigned long end)
+/* FIXME this is weird - should be only wdc but not work
+ * MS: I am getting bus errors and other weird things */
+static void __invalidate_dcache_all_wb(void)
 {
 {
+	pr_debug("%s\n", __func__);
+	CACHE_ALL_LOOP2(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
+					wdc.clear)
+
+#if 0
 	unsigned int i;
 	unsigned int i;
-	unsigned flags;
-	unsigned int align;
-
-	if (cpuinfo.use_dcache) {
-		/*
-		 * No need to cover entire cache range,
-		 * just cover cache footprint
-		 */
-		end = min(start + cpuinfo.dcache_size, end);
-		align = ~(cpuinfo.dcache_line - 1);
-		start &= align; /* Make sure we are aligned */
-		/* Push end up to the next cache line */
-		end = ((end & align) + cpuinfo.dcache_line);
-		local_irq_save(flags);
-		__disable_dcache();
-
-		for (i = start; i < end; i += cpuinfo.dcache_line)
-			__invalidate_dcache(i);
-
-		__enable_dcache();
-		local_irq_restore(flags);
-	}
+
+	pr_debug("%s\n", __func__);
+
+	/* Just loop through cache size and invalidate it */
+	for (i = 0; i < cpuinfo.dcache_size; i += cpuinfo.dcache_line_length)
+			__invalidate_dcache(0, i);
+#endif
+}
+
+static void __invalidate_dcache_range_wb(unsigned long start,
+						unsigned long end)
+{
+	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+				(unsigned int)start, (unsigned int) end);
+
+	CACHE_LOOP_LIMITS(start, end,
+			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
+	CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.clear);
+}
+
+static void __invalidate_dcache_range_nomsr_wt(unsigned long start,
+							unsigned long end)
+{
+	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+				(unsigned int)start, (unsigned int) end);
+	CACHE_LOOP_LIMITS(start, end,
+			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
+
+	CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
 }
 }
 
 
-void __invalidate_dcache_page(struct vm_area_struct *vma, struct page *page)
+static void __invalidate_dcache_range_msr_irq_wt(unsigned long start,
+							unsigned long end)
 {
 {
-	__invalidate_dcache_all();
+	unsigned long flags;
+
+	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+				(unsigned int)start, (unsigned int) end);
+	CACHE_LOOP_LIMITS(start, end,
+			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
+
+	local_irq_save(flags);
+	__disable_dcache_msr();
+
+	CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
+
+	__enable_dcache_msr();
+	local_irq_restore(flags);
+}
+
+static void __invalidate_dcache_range_nomsr_irq(unsigned long start,
+							unsigned long end)
+{
+	unsigned long flags;
+
+	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+				(unsigned int)start, (unsigned int) end);
+
+	CACHE_LOOP_LIMITS(start, end,
+			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
+
+	local_irq_save(flags);
+	__disable_dcache_nomsr();
+
+	CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
+
+	__enable_dcache_nomsr();
+	local_irq_restore(flags);
+}
+
+static void __flush_dcache_all_wb(void)
+{
+	pr_debug("%s\n", __func__);
+	CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length,
+				wdc.flush);
 }
 }
 
 
-void __invalidate_dcache_user_range(struct vm_area_struct *vma,
-				struct page *page, unsigned long adr,
-				int len)
+static void __flush_dcache_range_wb(unsigned long start, unsigned long end)
 {
 {
-	__invalidate_dcache_all();
+	pr_debug("%s: start 0x%x, end 0x%x\n", __func__,
+				(unsigned int)start, (unsigned int) end);
+
+	CACHE_LOOP_LIMITS(start, end,
+			cpuinfo.dcache_line_length, cpuinfo.dcache_size);
+	CACHE_RANGE_LOOP_2(start, end, cpuinfo.dcache_line_length, wdc.flush);
+}
+
+/* struct for wb caches and for wt caches */
+struct scache *mbc;
+
+/* new wb cache model */
+const struct scache wb_msr = {
+	.ie = __enable_icache_msr,
+	.id = __disable_icache_msr,
+	.ifl = __flush_icache_all_noirq,
+	.iflr = __flush_icache_range_noirq,
+	.iin = __flush_icache_all_noirq,
+	.iinr = __flush_icache_range_noirq,
+	.de = __enable_dcache_msr,
+	.dd = __disable_dcache_msr,
+	.dfl = __flush_dcache_all_wb,
+	.dflr = __flush_dcache_range_wb,
+	.din = __invalidate_dcache_all_wb,
+	.dinr = __invalidate_dcache_range_wb,
+};
+
+/* There is only difference in ie, id, de, dd functions */
+const struct scache wb_nomsr = {
+	.ie = __enable_icache_nomsr,
+	.id = __disable_icache_nomsr,
+	.ifl = __flush_icache_all_noirq,
+	.iflr = __flush_icache_range_noirq,
+	.iin = __flush_icache_all_noirq,
+	.iinr = __flush_icache_range_noirq,
+	.de = __enable_dcache_nomsr,
+	.dd = __disable_dcache_nomsr,
+	.dfl = __flush_dcache_all_wb,
+	.dflr = __flush_dcache_range_wb,
+	.din = __invalidate_dcache_all_wb,
+	.dinr = __invalidate_dcache_range_wb,
+};
+
+/* Old wt cache model with disabling irq and turn off cache */
+const struct scache wt_msr = {
+	.ie = __enable_icache_msr,
+	.id = __disable_icache_msr,
+	.ifl = __flush_icache_all_msr_irq,
+	.iflr = __flush_icache_range_msr_irq,
+	.iin = __flush_icache_all_msr_irq,
+	.iinr = __flush_icache_range_msr_irq,
+	.de = __enable_dcache_msr,
+	.dd = __disable_dcache_msr,
+	.dfl = __invalidate_dcache_all_msr_irq,
+	.dflr = __invalidate_dcache_range_msr_irq_wt,
+	.din = __invalidate_dcache_all_msr_irq,
+	.dinr = __invalidate_dcache_range_msr_irq_wt,
+};
+
+const struct scache wt_nomsr = {
+	.ie = __enable_icache_nomsr,
+	.id = __disable_icache_nomsr,
+	.ifl = __flush_icache_all_nomsr_irq,
+	.iflr = __flush_icache_range_nomsr_irq,
+	.iin = __flush_icache_all_nomsr_irq,
+	.iinr = __flush_icache_range_nomsr_irq,
+	.de = __enable_dcache_nomsr,
+	.dd = __disable_dcache_nomsr,
+	.dfl = __invalidate_dcache_all_nomsr_irq,
+	.dflr = __invalidate_dcache_range_nomsr_irq,
+	.din = __invalidate_dcache_all_nomsr_irq,
+	.dinr = __invalidate_dcache_range_nomsr_irq,
+};
+
+/* New wt cache model for newer Microblaze versions */
+const struct scache wt_msr_noirq = {
+	.ie = __enable_icache_msr,
+	.id = __disable_icache_msr,
+	.ifl = __flush_icache_all_noirq,
+	.iflr = __flush_icache_range_noirq,
+	.iin = __flush_icache_all_noirq,
+	.iinr = __flush_icache_range_noirq,
+	.de = __enable_dcache_msr,
+	.dd = __disable_dcache_msr,
+	.dfl = __invalidate_dcache_all_noirq_wt,
+	.dflr = __invalidate_dcache_range_nomsr_wt,
+	.din = __invalidate_dcache_all_noirq_wt,
+	.dinr = __invalidate_dcache_range_nomsr_wt,
+};
+
+const struct scache wt_nomsr_noirq = {
+	.ie = __enable_icache_nomsr,
+	.id = __disable_icache_nomsr,
+	.ifl = __flush_icache_all_noirq,
+	.iflr = __flush_icache_range_noirq,
+	.iin = __flush_icache_all_noirq,
+	.iinr = __flush_icache_range_noirq,
+	.de = __enable_dcache_nomsr,
+	.dd = __disable_dcache_nomsr,
+	.dfl = __invalidate_dcache_all_noirq_wt,
+	.dflr = __invalidate_dcache_range_nomsr_wt,
+	.din = __invalidate_dcache_all_noirq_wt,
+	.dinr = __invalidate_dcache_range_nomsr_wt,
+};
+
+/* CPU version code for 7.20.c - see arch/microblaze/kernel/cpu/cpuinfo.c */
+#define CPUVER_7_20_A	0x0c
+#define CPUVER_7_20_D	0x0f
+
+#define INFO(s)	printk(KERN_INFO "cache: " s " \n");
+
+void microblaze_cache_init(void)
+{
+	if (cpuinfo.use_instr & PVR2_USE_MSR_INSTR) {
+		if (cpuinfo.dcache_wb) {
+			INFO("wb_msr");
+			mbc = (struct scache *)&wb_msr;
+			if (cpuinfo.ver_code < CPUVER_7_20_D) {
+				/* MS: problem with signal handling - hw bug */
+				INFO("WB won't work properly");
+			}
+		} else {
+			if (cpuinfo.ver_code >= CPUVER_7_20_A) {
+				INFO("wt_msr_noirq");
+				mbc = (struct scache *)&wt_msr_noirq;
+			} else {
+				INFO("wt_msr");
+				mbc = (struct scache *)&wt_msr;
+			}
+		}
+	} else {
+		if (cpuinfo.dcache_wb) {
+			INFO("wb_nomsr");
+			mbc = (struct scache *)&wb_nomsr;
+			if (cpuinfo.ver_code < CPUVER_7_20_D) {
+				/* MS: problem with signal handling - hw bug */
+				INFO("WB won't work properly");
+			}
+		} else {
+			if (cpuinfo.ver_code >= CPUVER_7_20_A) {
+				INFO("wt_nomsr_noirq");
+				mbc = (struct scache *)&wt_nomsr_noirq;
+			} else {
+				INFO("wt_nomsr");
+				mbc = (struct scache *)&wt_nomsr;
+			}
+		}
+	}
 }
 }

+ 13 - 2
arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c

@@ -21,8 +21,14 @@
  */
  */
 
 
 #define CI(c, p) { ci->c = PVR_##p(pvr); }
 #define CI(c, p) { ci->c = PVR_##p(pvr); }
+
+#if defined(CONFIG_EARLY_PRINTK) && defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
 #define err_printk(x) \
 #define err_printk(x) \
 	early_printk("ERROR: Microblaze " x "-different for PVR and DTS\n");
 	early_printk("ERROR: Microblaze " x "-different for PVR and DTS\n");
+#else
+#define err_printk(x) \
+	printk(KERN_INFO "ERROR: Microblaze " x "-different for PVR and DTS\n");
+#endif
 
 
 void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
 void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
 {
 {
@@ -70,7 +76,7 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
 	CI(use_icache, USE_ICACHE);
 	CI(use_icache, USE_ICACHE);
 	CI(icache_tagbits, ICACHE_ADDR_TAG_BITS);
 	CI(icache_tagbits, ICACHE_ADDR_TAG_BITS);
 	CI(icache_write, ICACHE_ALLOW_WR);
 	CI(icache_write, ICACHE_ALLOW_WR);
-	CI(icache_line, ICACHE_LINE_LEN);
+	ci->icache_line_length = PVR_ICACHE_LINE_LEN(pvr) << 2;
 	CI(icache_size, ICACHE_BYTE_SIZE);
 	CI(icache_size, ICACHE_BYTE_SIZE);
 	CI(icache_base, ICACHE_BASEADDR);
 	CI(icache_base, ICACHE_BASEADDR);
 	CI(icache_high, ICACHE_HIGHADDR);
 	CI(icache_high, ICACHE_HIGHADDR);
@@ -78,11 +84,16 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
 	CI(use_dcache, USE_DCACHE);
 	CI(use_dcache, USE_DCACHE);
 	CI(dcache_tagbits, DCACHE_ADDR_TAG_BITS);
 	CI(dcache_tagbits, DCACHE_ADDR_TAG_BITS);
 	CI(dcache_write, DCACHE_ALLOW_WR);
 	CI(dcache_write, DCACHE_ALLOW_WR);
-	CI(dcache_line, DCACHE_LINE_LEN);
+	ci->dcache_line_length = PVR_DCACHE_LINE_LEN(pvr) << 2;
 	CI(dcache_size, DCACHE_BYTE_SIZE);
 	CI(dcache_size, DCACHE_BYTE_SIZE);
 	CI(dcache_base, DCACHE_BASEADDR);
 	CI(dcache_base, DCACHE_BASEADDR);
 	CI(dcache_high, DCACHE_HIGHADDR);
 	CI(dcache_high, DCACHE_HIGHADDR);
 
 
+	temp = PVR_DCACHE_USE_WRITEBACK(pvr);
+	if (ci->dcache_wb != temp)
+		err_printk("DCACHE WB");
+	ci->dcache_wb = temp;
+
 	CI(use_dopb, D_OPB);
 	CI(use_dopb, D_OPB);
 	CI(use_iopb, I_OPB);
 	CI(use_iopb, I_OPB);
 	CI(use_dlmb, D_LMB);
 	CI(use_dlmb, D_LMB);

+ 9 - 8
arch/microblaze/kernel/cpu/cpuinfo-static.c

@@ -72,12 +72,12 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
 	ci->use_icache = fcpu(cpu, "xlnx,use-icache");
 	ci->use_icache = fcpu(cpu, "xlnx,use-icache");
 	ci->icache_tagbits = fcpu(cpu, "xlnx,addr-tag-bits");
 	ci->icache_tagbits = fcpu(cpu, "xlnx,addr-tag-bits");
 	ci->icache_write = fcpu(cpu, "xlnx,allow-icache-wr");
 	ci->icache_write = fcpu(cpu, "xlnx,allow-icache-wr");
-	ci->icache_line = fcpu(cpu, "xlnx,icache-line-len") << 2;
-	if (!ci->icache_line) {
+	ci->icache_line_length = fcpu(cpu, "xlnx,icache-line-len") << 2;
+	if (!ci->icache_line_length) {
 		if (fcpu(cpu, "xlnx,icache-use-fsl"))
 		if (fcpu(cpu, "xlnx,icache-use-fsl"))
-			ci->icache_line = 4 << 2;
+			ci->icache_line_length = 4 << 2;
 		else
 		else
-			ci->icache_line = 1 << 2;
+			ci->icache_line_length = 1 << 2;
 	}
 	}
 	ci->icache_size = fcpu(cpu, "i-cache-size");
 	ci->icache_size = fcpu(cpu, "i-cache-size");
 	ci->icache_base = fcpu(cpu, "i-cache-baseaddr");
 	ci->icache_base = fcpu(cpu, "i-cache-baseaddr");
@@ -86,16 +86,17 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
 	ci->use_dcache = fcpu(cpu, "xlnx,use-dcache");
 	ci->use_dcache = fcpu(cpu, "xlnx,use-dcache");
 	ci->dcache_tagbits = fcpu(cpu, "xlnx,dcache-addr-tag");
 	ci->dcache_tagbits = fcpu(cpu, "xlnx,dcache-addr-tag");
 	ci->dcache_write = fcpu(cpu, "xlnx,allow-dcache-wr");
 	ci->dcache_write = fcpu(cpu, "xlnx,allow-dcache-wr");
-	ci->dcache_line = fcpu(cpu, "xlnx,dcache-line-len") << 2;
-	if (!ci->dcache_line) {
+	ci->dcache_line_length = fcpu(cpu, "xlnx,dcache-line-len") << 2;
+	if (!ci->dcache_line_length) {
 		if (fcpu(cpu, "xlnx,dcache-use-fsl"))
 		if (fcpu(cpu, "xlnx,dcache-use-fsl"))
-			ci->dcache_line = 4 << 2;
+			ci->dcache_line_length = 4 << 2;
 		else
 		else
-			ci->dcache_line = 1 << 2;
+			ci->dcache_line_length = 1 << 2;
 	}
 	}
 	ci->dcache_size = fcpu(cpu, "d-cache-size");
 	ci->dcache_size = fcpu(cpu, "d-cache-size");
 	ci->dcache_base = fcpu(cpu, "d-cache-baseaddr");
 	ci->dcache_base = fcpu(cpu, "d-cache-baseaddr");
 	ci->dcache_high = fcpu(cpu, "d-cache-highaddr");
 	ci->dcache_high = fcpu(cpu, "d-cache-highaddr");
+	ci->dcache_wb = fcpu(cpu, "xlnx,dcache-use-writeback");
 
 
 	ci->use_dopb = fcpu(cpu, "xlnx,d-opb");
 	ci->use_dopb = fcpu(cpu, "xlnx,d-opb");
 	ci->use_iopb = fcpu(cpu, "xlnx,i-opb");
 	ci->use_iopb = fcpu(cpu, "xlnx,i-opb");

+ 2 - 5
arch/microblaze/kernel/cpu/cpuinfo.c

@@ -29,11 +29,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
 	{"7.20.a", 0x0c},
 	{"7.20.a", 0x0c},
 	{"7.20.b", 0x0d},
 	{"7.20.b", 0x0d},
 	{"7.20.c", 0x0e},
 	{"7.20.c", 0x0e},
-	/* FIXME There is no keycode defined in MBV for these versions */
-	{"2.10.a", 0x10},
-	{"3.00.a", 0x20},
-	{"4.00.a", 0x30},
-	{"4.00.b", 0x40},
+	{"7.20.d", 0x0f},
+	{"7.30.a", 0x10},
 	{NULL, 0},
 	{NULL, 0},
 };
 };
 
 

+ 6 - 2
arch/microblaze/kernel/cpu/mb.c

@@ -103,11 +103,15 @@ static int show_cpuinfo(struct seq_file *m, void *v)
 	else
 	else
 		count += seq_printf(m, "Icache:\t\tno\n");
 		count += seq_printf(m, "Icache:\t\tno\n");
 
 
-	if (cpuinfo.use_dcache)
+	if (cpuinfo.use_dcache) {
 		count += seq_printf(m,
 		count += seq_printf(m,
 				"Dcache:\t\t%ukB\n",
 				"Dcache:\t\t%ukB\n",
 				cpuinfo.dcache_size >> 10);
 				cpuinfo.dcache_size >> 10);
-	else
+		if (cpuinfo.dcache_wb)
+			count += seq_printf(m, "\t\twrite-back\n");
+		else
+			count += seq_printf(m, "\t\twrite-through\n");
+	} else
 		count += seq_printf(m, "Dcache:\t\tno\n");
 		count += seq_printf(m, "Dcache:\t\tno\n");
 
 
 	count += seq_printf(m,
 	count += seq_printf(m,

+ 1 - 1
arch/microblaze/kernel/cpu/pvr.c

@@ -45,7 +45,7 @@
 
 
 int cpu_has_pvr(void)
 int cpu_has_pvr(void)
 {
 {
-	unsigned flags;
+	unsigned long flags;
 	unsigned pvr0;
 	unsigned pvr0;
 
 
 	local_save_flags(flags);
 	local_save_flags(flags);

+ 0 - 2
arch/microblaze/kernel/entry-nommu.S

@@ -208,8 +208,6 @@ ENTRY(_user_exception)
 	lwi	r1, r1, TS_THREAD_INFO		/* get the thread info */
 	lwi	r1, r1, TS_THREAD_INFO		/* get the thread info */
 	/* calculate kernel stack pointer */
 	/* calculate kernel stack pointer */
 	addik	r1, r1, THREAD_SIZE - PT_SIZE
 	addik	r1, r1, THREAD_SIZE - PT_SIZE
-	swi	r11, r0, PER_CPU(R11_SAVE)	/* temporarily save r11 */
-	lwi	r11, r0, PER_CPU(KM)		/* load mode indicator */
 2:
 2:
 	swi	r11, r1, PT_MODE		/* store the mode */
 	swi	r11, r1, PT_MODE		/* store the mode */
 	lwi	r11, r0, PER_CPU(R11_SAVE)	/* reload r11 */
 	lwi	r11, r0, PER_CPU(R11_SAVE)	/* reload r11 */

+ 4 - 15
arch/microblaze/kernel/entry.S

@@ -31,6 +31,8 @@
 #include <linux/errno.h>
 #include <linux/errno.h>
 #include <asm/signal.h>
 #include <asm/signal.h>
 
 
+#undef DEBUG
+
 /* The size of a state save frame. */
 /* The size of a state save frame. */
 #define STATE_SAVE_SIZE		(PT_SIZE + STATE_SAVE_ARG_SPACE)
 #define STATE_SAVE_SIZE		(PT_SIZE + STATE_SAVE_ARG_SPACE)
 
 
@@ -352,10 +354,12 @@ C_ENTRY(_user_exception):
 	add	r12, r12, r12;			/* convert num -> ptr */
 	add	r12, r12, r12;			/* convert num -> ptr */
 	add	r12, r12, r12;
 	add	r12, r12, r12;
 
 
+#ifdef DEBUG
 	/* Trac syscalls and stored them to r0_ram */
 	/* Trac syscalls and stored them to r0_ram */
 	lwi	r3, r12, 0x400 + r0_ram
 	lwi	r3, r12, 0x400 + r0_ram
 	addi	r3, r3, 1
 	addi	r3, r3, 1
 	swi	r3, r12, 0x400 + r0_ram
 	swi	r3, r12, 0x400 + r0_ram
+#endif
 
 
 	# Find and jump into the syscall handler.
 	# Find and jump into the syscall handler.
 	lwi	r12, r12, sys_call_table
 	lwi	r12, r12, sys_call_table
@@ -496,17 +500,6 @@ C_ENTRY(sys_execve):
 	brid	microblaze_execve;	/* Do real work (tail-call).*/
 	brid	microblaze_execve;	/* Do real work (tail-call).*/
 	nop;
 	nop;
 
 
-C_ENTRY(sys_rt_sigsuspend_wrapper):
-	swi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-	swi	r4, r1, PTO+PT_R4;
-	la	r7, r1, PTO;		/* add user context as 3rd arg */
-	brlid	r15, sys_rt_sigsuspend;	/* Do real work.*/
-	nop;
-	lwi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-	lwi	r4, r1, PTO+PT_R4;
-	bri ret_from_trap /* fall through will not work here due to align */
-	nop;
-
 C_ENTRY(sys_rt_sigreturn_wrapper):
 C_ENTRY(sys_rt_sigreturn_wrapper):
 	swi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
 	swi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
 	swi	r4, r1, PTO+PT_R4;
 	swi	r4, r1, PTO+PT_R4;
@@ -711,15 +704,11 @@ C_ENTRY(ret_from_exc):
 	 * (in a possibly modified form) after do_signal returns.
 	 * (in a possibly modified form) after do_signal returns.
 	 * store return registers separately because this macros is use
 	 * store return registers separately because this macros is use
 	 * for others exceptions */
 	 * for others exceptions */
-	swi	r3, r1, PTO + PT_R3;
-	swi	r4, r1, PTO + PT_R4;
 	la	r5, r1, PTO;		/* Arg 1: struct pt_regs *regs */
 	la	r5, r1, PTO;		/* Arg 1: struct pt_regs *regs */
 	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */
 	add	r6, r0, r0;		/* Arg 2: sigset_t *oldset */
 	addi	r7, r0, 0;		/* Arg 3: int in_syscall */
 	addi	r7, r0, 0;		/* Arg 3: int in_syscall */
 	bralid	r15, do_signal;	/* Handle any signals */
 	bralid	r15, do_signal;	/* Handle any signals */
 	nop;
 	nop;
-	lwi	r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
-	lwi	r4, r1, PTO+PT_R4;
 
 
 /* Finally, return to user state.  */
 /* Finally, return to user state.  */
 1:	swi	r0, r0, PER_CPU(KM);	/* Now officially in user state. */
 1:	swi	r0, r0, PER_CPU(KM);	/* Now officially in user state. */

+ 237 - 0
arch/microblaze/kernel/ftrace.c

@@ -0,0 +1,237 @@
+/*
+ * Ftrace support for Microblaze.
+ *
+ * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2009 PetaLogix
+ *
+ * Based on MIPS and PowerPC ftrace code
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <asm/cacheflush.h>
+#include <linux/ftrace.h>
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+/*
+ * Hook the return address and push it in the stack of return addrs
+ * in current thread info.
+ */
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
+{
+	unsigned long old;
+	int faulted, err;
+	struct ftrace_graph_ent trace;
+	unsigned long return_hooker = (unsigned long)
+				&return_to_handler;
+
+	if (unlikely(atomic_read(&current->tracing_graph_pause)))
+		return;
+
+	/*
+	 * Protect against fault, even if it shouldn't
+	 * happen. This tool is too much intrusive to
+	 * ignore such a protection.
+	 */
+	asm volatile("	1:	lwi	%0, %2, 0;		\
+			2:	swi	%3, %2, 0;		\
+				addik	%1, r0, 0;		\
+			3:					\
+				.section .fixup, \"ax\";	\
+			4:	brid	3b;			\
+				addik	%1, r0, 1;		\
+				.previous;			\
+				.section __ex_table,\"a\";	\
+				.word	1b,4b;			\
+				.word	2b,4b;			\
+				.previous;"			\
+			: "=&r" (old), "=r" (faulted)
+			: "r" (parent), "r" (return_hooker)
+	);
+
+	if (unlikely(faulted)) {
+		ftrace_graph_stop();
+		WARN_ON(1);
+		return;
+	}
+
+	err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0);
+	if (err == -EBUSY) {
+		*parent = old;
+		return;
+	}
+
+	trace.func = self_addr;
+	/* Only trace if the calling function expects to */
+	if (!ftrace_graph_entry(&trace)) {
+		current->curr_ret_stack--;
+		*parent = old;
+	}
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+/* save value to addr - it is save to do it in asm */
+static int ftrace_modify_code(unsigned long addr, unsigned int value)
+{
+	int faulted = 0;
+
+	__asm__ __volatile__("	1:	swi	%2, %1, 0;		\
+					addik	%0, r0, 0;		\
+				2:					\
+					.section .fixup, \"ax\";	\
+				3:	brid	2b;			\
+					addik	%0, r0, 1;		\
+					.previous;			\
+					.section __ex_table,\"a\";	\
+					.word	1b,3b;			\
+					.previous;"			\
+				: "=r" (faulted)
+				: "r" (addr), "r" (value)
+	);
+
+	if (unlikely(faulted))
+		return -EFAULT;
+
+	return 0;
+}
+
+#define MICROBLAZE_NOP 0x80000000
+#define MICROBLAZE_BRI 0xb800000C
+
+static unsigned int recorded; /* if save was or not */
+static unsigned int imm; /* saving whole imm instruction */
+
+/* There are two approaches howto solve ftrace_make nop function - look below */
+#undef USE_FTRACE_NOP
+
+#ifdef USE_FTRACE_NOP
+static unsigned int bralid; /* saving whole bralid instruction */
+#endif
+
+int ftrace_make_nop(struct module *mod,
+			struct dyn_ftrace *rec, unsigned long addr)
+{
+	/* we have this part of code which we are working with
+	 * b000c000        imm     -16384
+	 * b9fc8e30        bralid  r15, -29136     // c0008e30 <_mcount>
+	 * 80000000        or      r0, r0, r0
+	 *
+	 * The first solution (!USE_FTRACE_NOP-could be called branch solution)
+	 * b000c000        bri	12 (0xC - jump to any other instruction)
+	 * b9fc8e30        bralid  r15, -29136     // c0008e30 <_mcount>
+	 * 80000000        or      r0, r0, r0
+	 * any other instruction
+	 *
+	 * The second solution (USE_FTRACE_NOP) - no jump just nops
+	 * 80000000        or      r0, r0, r0
+	 * 80000000        or      r0, r0, r0
+	 * 80000000        or      r0, r0, r0
+	 */
+	int ret = 0;
+
+	if (recorded == 0) {
+		recorded = 1;
+		imm = *(unsigned int *)rec->ip;
+		pr_debug("%s: imm:0x%x\n", __func__, imm);
+#ifdef USE_FTRACE_NOP
+		bralid = *(unsigned int *)(rec->ip + 4);
+		pr_debug("%s: bralid 0x%x\n", __func__, bralid);
+#endif /* USE_FTRACE_NOP */
+	}
+
+#ifdef USE_FTRACE_NOP
+	ret = ftrace_modify_code(rec->ip, MICROBLAZE_NOP);
+	ret += ftrace_modify_code(rec->ip + 4, MICROBLAZE_NOP);
+#else /* USE_FTRACE_NOP */
+	ret = ftrace_modify_code(rec->ip, MICROBLAZE_BRI);
+#endif /* USE_FTRACE_NOP */
+	return ret;
+}
+
+static int ret_addr; /* initialized as 0 by default */
+
+/* I believe that first is called ftrace_make_nop before this function */
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+	int ret;
+	ret_addr = addr; /* saving where the barrier jump is */
+	pr_debug("%s: addr:0x%x, rec->ip: 0x%x, imm:0x%x\n",
+		__func__, (unsigned int)addr, (unsigned int)rec->ip, imm);
+	ret = ftrace_modify_code(rec->ip, imm);
+#ifdef USE_FTRACE_NOP
+	pr_debug("%s: bralid:0x%x\n", __func__, bralid);
+	ret += ftrace_modify_code(rec->ip + 4, bralid);
+#endif /* USE_FTRACE_NOP */
+	return ret;
+}
+
+int __init ftrace_dyn_arch_init(void *data)
+{
+	/* The return code is retured via data */
+	*(unsigned long *)data = 0;
+
+	return 0;
+}
+
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+	unsigned long ip = (unsigned long)(&ftrace_call);
+	unsigned int upper = (unsigned int)func;
+	unsigned int lower = (unsigned int)func;
+	int ret = 0;
+
+	/* create proper saving to ftrace_call poll */
+	upper = 0xb0000000 + (upper >> 16); /* imm func_upper */
+	lower = 0x32800000 + (lower & 0xFFFF); /* addik r20, r0, func_lower */
+
+	pr_debug("%s: func=0x%x, ip=0x%x, upper=0x%x, lower=0x%x\n",
+		__func__, (unsigned int)func, (unsigned int)ip, upper, lower);
+
+	/* save upper and lower code */
+	ret = ftrace_modify_code(ip, upper);
+	ret += ftrace_modify_code(ip + 4, lower);
+
+	/* We just need to remove the rtsd r15, 8 by NOP */
+	BUG_ON(!ret_addr);
+	if (ret_addr)
+		ret += ftrace_modify_code(ret_addr, MICROBLAZE_NOP);
+	else
+		ret = 1; /* fault */
+
+	/* All changes are done - lets do caches consistent */
+	flush_icache();
+	return ret;
+}
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+unsigned int old_jump; /* saving place for jump instruction */
+
+int ftrace_enable_ftrace_graph_caller(void)
+{
+	unsigned int ret;
+	unsigned long ip = (unsigned long)(&ftrace_call_graph);
+
+	old_jump = *(unsigned int *)ip; /* save jump over instruction */
+	ret = ftrace_modify_code(ip, MICROBLAZE_NOP);
+	flush_icache();
+
+	pr_debug("%s: Replace instruction: 0x%x\n", __func__, old_jump);
+	return ret;
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+	unsigned int ret;
+	unsigned long ip = (unsigned long)(&ftrace_call_graph);
+
+	ret = ftrace_modify_code(ip, old_jump);
+	flush_icache();
+
+	pr_debug("%s\n", __func__);
+	return ret;
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+#endif /* CONFIG_DYNAMIC_FTRACE */

+ 10 - 5
arch/microblaze/kernel/heartbeat.c

@@ -45,6 +45,7 @@ void heartbeat(void)
 void setup_heartbeat(void)
 void setup_heartbeat(void)
 {
 {
 	struct device_node *gpio = NULL;
 	struct device_node *gpio = NULL;
+	int *prop;
 	int j;
 	int j;
 	char *gpio_list[] = {
 	char *gpio_list[] = {
 				"xlnx,xps-gpio-1.00.a",
 				"xlnx,xps-gpio-1.00.a",
@@ -58,10 +59,14 @@ void setup_heartbeat(void)
 			break;
 			break;
 	}
 	}
 
 
-	base_addr = *(int *) of_get_property(gpio, "reg", NULL);
-	base_addr = (unsigned long) ioremap(base_addr, PAGE_SIZE);
-	printk(KERN_NOTICE "Heartbeat GPIO at 0x%x\n", base_addr);
+	if (gpio) {
+		base_addr = *(int *) of_get_property(gpio, "reg", NULL);
+		base_addr = (unsigned long) ioremap(base_addr, PAGE_SIZE);
+		printk(KERN_NOTICE "Heartbeat GPIO at 0x%x\n", base_addr);
 
 
-	if (*(int *) of_get_property(gpio, "xlnx,is-bidir", NULL))
-		out_be32(base_addr + 4, 0); /* GPIO is configured as output */
+		/* GPIO is configured as output */
+		prop = (int *) of_get_property(gpio, "xlnx,is-bidir", NULL);
+		if (prop)
+			out_be32(base_addr + 4, 0);
+	}
 }
 }

+ 9 - 1
arch/microblaze/kernel/intc.c

@@ -42,8 +42,16 @@ unsigned int nr_irq;
 
 
 static void intc_enable_or_unmask(unsigned int irq)
 static void intc_enable_or_unmask(unsigned int irq)
 {
 {
+	unsigned long mask = 1 << irq;
 	pr_debug("enable_or_unmask: %d\n", irq);
 	pr_debug("enable_or_unmask: %d\n", irq);
-	out_be32(INTC_BASE + SIE, 1 << irq);
+	out_be32(INTC_BASE + SIE, mask);
+
+	/* ack level irqs because they can't be acked during
+	 * ack function since the handle_level_irq function
+	 * acks the irq before calling the interrupt handler
+	 */
+	if (irq_desc[irq].status & IRQ_LEVEL)
+		out_be32(INTC_BASE + IAR, mask);
 }
 }
 
 
 static void intc_disable_or_mask(unsigned int irq)
 static void intc_disable_or_mask(unsigned int irq)

+ 170 - 0
arch/microblaze/kernel/mcount.S

@@ -0,0 +1,170 @@
+/*
+ * Low-level ftrace handling
+ *
+ * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2009 PetaLogix
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#include <linux/linkage.h>
+
+#define NOALIGN_ENTRY(name)	.globl name; name:
+
+/* FIXME MS: I think that I don't need to save all regs */
+#define SAVE_REGS		\
+	addik	r1, r1, -120;	\
+	swi	r2, r1, 4;	\
+	swi	r3, r1, 8;	\
+	swi	r4, r1, 12;	\
+	swi	r5, r1, 116;	\
+	swi	r6, r1, 16;	\
+	swi	r7, r1, 20;	\
+	swi	r8, r1, 24;	\
+	swi	r9, r1, 28;	\
+	swi	r10, r1, 32;	\
+	swi	r11, r1, 36;	\
+	swi	r12, r1, 40;	\
+	swi	r13, r1, 44;	\
+	swi	r14, r1, 48;	\
+	swi	r16, r1, 52;	\
+	swi	r17, r1, 56;	\
+	swi	r18, r1, 60;	\
+	swi	r19, r1, 64;	\
+	swi	r20, r1, 68;	\
+	swi	r21, r1, 72;	\
+	swi	r22, r1, 76;	\
+	swi	r23, r1, 80;	\
+	swi	r24, r1, 84;	\
+	swi	r25, r1, 88;	\
+	swi	r26, r1, 92;	\
+	swi	r27, r1, 96;	\
+	swi	r28, r1, 100;	\
+	swi	r29, r1, 104;	\
+	swi	r30, r1, 108;	\
+	swi	r31, r1, 112;
+
+#define RESTORE_REGS		\
+	lwi	r2, r1, 4;	\
+	lwi	r3, r1, 8;	\
+	lwi	r4, r1, 12;	\
+	lwi	r5, r1, 116;	\
+	lwi	r6, r1, 16;	\
+	lwi	r7, r1, 20;	\
+	lwi	r8, r1, 24;	\
+	lwi	r9, r1, 28;	\
+	lwi	r10, r1, 32;	\
+	lwi	r11, r1, 36;	\
+	lwi	r12, r1, 40;	\
+	lwi	r13, r1, 44;	\
+	lwi	r14, r1, 48;	\
+	lwi	r16, r1, 52;	\
+	lwi	r17, r1, 56;	\
+	lwi	r18, r1, 60;	\
+	lwi	r19, r1, 64;	\
+	lwi	r20, r1, 68;	\
+	lwi	r21, r1, 72;	\
+	lwi	r22, r1, 76;	\
+	lwi	r23, r1, 80;	\
+	lwi	r24, r1, 84;	\
+	lwi	r25, r1, 88;	\
+	lwi	r26, r1, 92;	\
+	lwi	r27, r1, 96;	\
+	lwi	r28, r1, 100;	\
+	lwi	r29, r1, 104;	\
+	lwi	r30, r1, 108;	\
+	lwi	r31, r1, 112;	\
+	addik	r1, r1, 120;
+
+ENTRY(ftrace_stub)
+	rtsd	r15, 8;
+	nop;
+
+ENTRY(_mcount)
+#ifdef CONFIG_DYNAMIC_FTRACE
+ENTRY(ftrace_caller)
+	/* MS: It is just barrier which is removed from C code */
+	rtsd	r15, 8
+	nop
+#endif /* CONFIG_DYNAMIC_FTRACE */
+	SAVE_REGS
+	swi	r15, r1, 0;
+	/* MS: HAVE_FUNCTION_TRACE_MCOUNT_TEST begin of checking */
+	lwi	r5, r0, function_trace_stop;
+	bneid	r5, end;
+	nop;
+	/* MS: HAVE_FUNCTION_TRACE_MCOUNT_TEST end of checking */
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+#ifndef CONFIG_DYNAMIC_FTRACE
+	lwi	r5, r0, ftrace_graph_return;
+	addik	r6, r0, ftrace_stub; /* asm implementation */
+	cmpu	r5, r5, r6; /* ftrace_graph_return != ftrace_stub */
+	beqid	r5, end_graph_tracer;
+	nop;
+
+	lwi	r6, r0, ftrace_graph_entry;
+	addik	r5, r0, ftrace_graph_entry_stub; /* implemented in C */
+	cmpu	r5, r5, r6; /* ftrace_graph_entry != ftrace_graph_entry_stub */
+	beqid	r5, end_graph_tracer;
+	nop;
+#else /* CONFIG_DYNAMIC_FTRACE */
+NOALIGN_ENTRY(ftrace_call_graph)
+	/* MS: jump over graph function - replaced from C code */
+	bri	end_graph_tracer
+#endif /* CONFIG_DYNAMIC_FTRACE */
+	addik	r5, r1, 120; /* MS: load parent addr */
+	addik	r6, r15, 0; /* MS: load current function addr */
+	bralid	r15, prepare_ftrace_return;
+	nop;
+	/* MS: graph was taken that's why - can jump over function trace */
+	brid	end;
+	nop;
+end_graph_tracer:
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+#ifndef CONFIG_DYNAMIC_FTRACE
+	/* MS: test function trace if is taken or not */
+	lwi	r20, r0, ftrace_trace_function;
+	addik	r6, r0, ftrace_stub;
+	cmpu	r5, r20, r6; /* ftrace_trace_function != ftrace_stub */
+	beqid	r5, end; /* MS: not taken -> jump over */
+	nop;
+#else /* CONFIG_DYNAMIC_FTRACE */
+NOALIGN_ENTRY(ftrace_call)
+/* instruction for setup imm FUNC_part1, addik r20, r0, FUNC_part2 */
+	nop
+	nop
+#endif /* CONFIG_DYNAMIC_FTRACE */
+/* static normal trace */
+	lwi	r6, r1, 120; /* MS: load parent addr */
+	addik	r5, r15, 0; /* MS: load current function addr */
+	/* MS: here is dependency on previous code */
+	brald	r15, r20; /* MS: jump to ftrace handler */
+	nop;
+end:
+	lwi	r15, r1, 0;
+	RESTORE_REGS
+
+	rtsd	r15, 8; /* MS: jump back */
+	nop;
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ENTRY(return_to_handler)
+	nop; /* MS: just barrier for rtsd r15, 8 */
+	nop;
+	SAVE_REGS
+	swi	r15, r1, 0;
+
+	/* MS: find out returning address */
+	bralid	r15, ftrace_return_to_handler;
+	nop;
+
+	/* MS: return value from ftrace_return_to_handler is my returning addr
+	 * must be before restore regs because I have to restore r3 content */
+	addik	r15, r3, 0;
+	RESTORE_REGS
+
+	rtsd	r15, 8; /* MS: jump back */
+	nop;
+#endif	/* CONFIG_FUNCTION_TRACER */

+ 5 - 0
arch/microblaze/kernel/microblaze_ksyms.c

@@ -18,6 +18,7 @@
 #include <linux/io.h>
 #include <linux/io.h>
 #include <asm/page.h>
 #include <asm/page.h>
 #include <asm/system.h>
 #include <asm/system.h>
+#include <linux/ftrace.h>
 #include <linux/uaccess.h>
 #include <linux/uaccess.h>
 
 
 /*
 /*
@@ -47,3 +48,7 @@ extern void __umodsi3(void);
 EXPORT_SYMBOL(__umodsi3);
 EXPORT_SYMBOL(__umodsi3);
 extern char *_ebss;
 extern char *_ebss;
 EXPORT_SYMBOL_GPL(_ebss);
 EXPORT_SYMBOL_GPL(_ebss);
+#ifdef CONFIG_FUNCTION_TRACER
+extern void _mcount(void);
+EXPORT_SYMBOL(_mcount);
+#endif

+ 1 - 0
arch/microblaze/kernel/process.c

@@ -15,6 +15,7 @@
 #include <linux/bitops.h>
 #include <linux/bitops.h>
 #include <asm/system.h>
 #include <asm/system.h>
 #include <asm/pgalloc.h>
 #include <asm/pgalloc.h>
+#include <asm/cacheflush.h>
 
 
 void show_regs(struct pt_regs *regs)
 void show_regs(struct pt_regs *regs)
 {
 {

+ 140 - 0
arch/microblaze/kernel/reset.c

@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2009 PetaLogix
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <asm/prom.h>
+
+/* Trigger specific functions */
+#ifdef CONFIG_GPIOLIB
+
+#include <linux/of_gpio.h>
+
+static int handle; /* reset pin handle */
+static unsigned int reset_val;
+
+static int of_reset_gpio_handle(void)
+{
+	int ret; /* variable which stored handle reset gpio pin */
+	struct device_node *root; /* root node */
+	struct device_node *gpio; /* gpio node */
+	struct of_gpio_chip *of_gc = NULL;
+	enum of_gpio_flags flags ;
+	const void *gpio_spec;
+
+	/* find out root node */
+	root = of_find_node_by_path("/");
+
+	/* give me handle for gpio node to be possible allocate pin */
+	ret = of_parse_phandles_with_args(root, "hard-reset-gpios",
+				"#gpio-cells", 0, &gpio, &gpio_spec);
+	if (ret) {
+		pr_debug("%s: can't parse gpios property\n", __func__);
+		goto err0;
+	}
+
+	of_gc = gpio->data;
+	if (!of_gc) {
+		pr_debug("%s: gpio controller %s isn't registered\n",
+			 root->full_name, gpio->full_name);
+		ret = -ENODEV;
+		goto err1;
+	}
+
+	ret = of_gc->xlate(of_gc, root, gpio_spec, &flags);
+	if (ret < 0)
+		goto err1;
+
+	ret += of_gc->gc.base;
+err1:
+	of_node_put(gpio);
+err0:
+	pr_debug("%s exited with status %d\n", __func__, ret);
+	return ret;
+}
+
+void of_platform_reset_gpio_probe(void)
+{
+	int ret;
+	handle = of_reset_gpio_handle();
+
+	if (!gpio_is_valid(handle)) {
+		printk(KERN_INFO "Skipping unavailable RESET gpio %d (%s)\n",
+				handle, "reset");
+	}
+
+	ret = gpio_request(handle, "reset");
+	if (ret < 0) {
+		printk(KERN_INFO "GPIO pin is already allocated\n");
+		return;
+	}
+
+	/* get current setup value */
+	reset_val = gpio_get_value(handle);
+	/* FIXME maybe worth to perform any action */
+	pr_debug("Reset: Gpio output state: 0x%x\n", reset_val);
+
+	/* Setup GPIO as output */
+	ret = gpio_direction_output(handle, 0);
+	if (ret < 0)
+		goto err;
+
+	/* Setup output direction */
+	gpio_set_value(handle, 0);
+
+	printk(KERN_INFO "RESET: Registered gpio device: %d, current val: %d\n",
+							handle, reset_val);
+	return;
+err:
+	gpio_free(handle);
+	return;
+}
+
+
+static void gpio_system_reset(void)
+{
+	gpio_set_value(handle, 1 - reset_val);
+}
+#else
+#define gpio_system_reset() do {} while (0)
+void of_platform_reset_gpio_probe(void)
+{
+	return;
+}
+#endif
+
+void machine_restart(char *cmd)
+{
+	printk(KERN_NOTICE "Machine restart...\n");
+	gpio_system_reset();
+	dump_stack();
+	while (1)
+		;
+}
+
+void machine_shutdown(void)
+{
+	printk(KERN_NOTICE "Machine shutdown...\n");
+	while (1)
+		;
+}
+
+void machine_halt(void)
+{
+	printk(KERN_NOTICE "Machine halt...\n");
+	while (1)
+		;
+}
+
+void machine_power_off(void)
+{
+	printk(KERN_NOTICE "Machine power off...\n");
+	while (1)
+		;
+}

+ 6 - 34
arch/microblaze/kernel/setup.c

@@ -52,13 +52,12 @@ void __init setup_arch(char **cmdline_p)
 	/* irq_early_init(); */
 	/* irq_early_init(); */
 	setup_cpuinfo();
 	setup_cpuinfo();
 
 
-	__invalidate_icache_all();
-	__enable_icache();
+	microblaze_cache_init();
 
 
-	__invalidate_dcache_all();
-	__enable_dcache();
+	enable_dcache();
 
 
-	panic_timeout = 120;
+	invalidate_icache();
+	enable_icache();
 
 
 	setup_memory();
 	setup_memory();
 
 
@@ -131,6 +130,8 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
 		strlcpy(cmd_line, cmdline, COMMAND_LINE_SIZE);
 		strlcpy(cmd_line, cmdline, COMMAND_LINE_SIZE);
 #endif
 #endif
 
 
+	lockdep_init();
+
 /* initialize device tree for usage in early_printk */
 /* initialize device tree for usage in early_printk */
 	early_init_devtree((void *)_fdt_start);
 	early_init_devtree((void *)_fdt_start);
 
 
@@ -186,32 +187,3 @@ static int microblaze_debugfs_init(void)
 }
 }
 arch_initcall(microblaze_debugfs_init);
 arch_initcall(microblaze_debugfs_init);
 #endif
 #endif
-
-void machine_restart(char *cmd)
-{
-	printk(KERN_NOTICE "Machine restart...\n");
-	dump_stack();
-	while (1)
-		;
-}
-
-void machine_shutdown(void)
-{
-	printk(KERN_NOTICE "Machine shutdown...\n");
-	while (1)
-		;
-}
-
-void machine_halt(void)
-{
-	printk(KERN_NOTICE "Machine halt...\n");
-	while (1)
-		;
-}
-
-void machine_power_off(void)
-{
-	printk(KERN_NOTICE "Machine power off...\n");
-	while (1)
-		;
-}

+ 32 - 3
arch/microblaze/kernel/signal.c

@@ -44,7 +44,6 @@
 
 
 asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall);
 asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall);
 
 
-
 asmlinkage long
 asmlinkage long
 sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
 sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
 		struct pt_regs *regs)
 		struct pt_regs *regs)
@@ -176,6 +175,11 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	struct rt_sigframe __user *frame;
 	struct rt_sigframe __user *frame;
 	int err = 0;
 	int err = 0;
 	int signal;
 	int signal;
+	unsigned long address = 0;
+#ifdef CONFIG_MMU
+	pmd_t *pmdp;
+	pte_t *ptep;
+#endif
 
 
 	frame = get_sigframe(ka, regs, sizeof(*frame));
 	frame = get_sigframe(ka, regs, sizeof(*frame));
 
 
@@ -216,8 +220,29 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 	 Negative 8 offset because return is rtsd r15, 8 */
 	 Negative 8 offset because return is rtsd r15, 8 */
 	regs->r15 = ((unsigned long)frame->tramp)-8;
 	regs->r15 = ((unsigned long)frame->tramp)-8;
 
 
-	__invalidate_cache_sigtramp((unsigned long)frame->tramp);
-
+	address = ((unsigned long)frame->tramp);
+#ifdef CONFIG_MMU
+	pmdp = pmd_offset(pud_offset(
+			pgd_offset(current->mm, address),
+					address), address);
+
+	preempt_disable();
+	ptep = pte_offset_map(pmdp, address);
+	if (pte_present(*ptep)) {
+		address = (unsigned long) page_address(pte_page(*ptep));
+		/* MS: I need add offset in page */
+		address += ((unsigned long)frame->tramp) & ~PAGE_MASK;
+		/* MS address is virtual */
+		address = virt_to_phys(address);
+		invalidate_icache_range(address, address + 8);
+		flush_dcache_range(address, address + 8);
+	}
+	pte_unmap(ptep);
+	preempt_enable();
+#else
+	flush_icache_range(address, address + 8);
+	flush_dcache_range(address, address + 8);
+#endif
 	if (err)
 	if (err)
 		goto give_sigsegv;
 		goto give_sigsegv;
 
 
@@ -233,6 +258,10 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
 
 
 	set_fs(USER_DS);
 	set_fs(USER_DS);
 
 
+	/* the tracer may want to single-step inside the handler */
+	if (test_thread_flag(TIF_SINGLESTEP))
+		ptrace_notify(SIGTRAP);
+
 #ifdef DEBUG_SIG
 #ifdef DEBUG_SIG
 	printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
 	printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
 		current->comm, current->pid, frame, regs->pc);
 		current->comm, current->pid, frame, regs->pc);

+ 65 - 0
arch/microblaze/kernel/stacktrace.c

@@ -0,0 +1,65 @@
+/*
+ * Stack trace support for Microblaze.
+ *
+ * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2009 PetaLogix
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <linux/thread_info.h>
+#include <linux/ptrace.h>
+#include <linux/module.h>
+
+/* FIXME initial support */
+void save_stack_trace(struct stack_trace *trace)
+{
+	unsigned long *sp;
+	unsigned long addr;
+	asm("addik %0, r1, 0" : "=r" (sp));
+
+	while (!kstack_end(sp)) {
+		addr = *sp++;
+		if (__kernel_text_address(addr)) {
+			if (trace->skip > 0)
+				trace->skip--;
+			else
+				trace->entries[trace->nr_entries++] = addr;
+
+			if (trace->nr_entries >= trace->max_entries)
+				break;
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(save_stack_trace);
+
+void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
+{
+	unsigned int *sp;
+	unsigned long addr;
+
+	struct thread_info *ti = task_thread_info(tsk);
+
+	if (tsk == current)
+		asm("addik %0, r1, 0" : "=r" (sp));
+	else
+		sp = (unsigned int *)ti->cpu_context.r1;
+
+	while (!kstack_end(sp)) {
+		addr = *sp++;
+		if (__kernel_text_address(addr)) {
+			if (trace->skip > 0)
+				trace->skip--;
+			else
+				trace->entries[trace->nr_entries++] = addr;
+
+			if (trace->nr_entries >= trace->max_entries)
+				break;
+		}
+	}
+}
+EXPORT_SYMBOL_GPL(save_stack_trace_tsk);

+ 2 - 2
arch/microblaze/kernel/syscall_table.S

@@ -183,7 +183,7 @@ ENTRY(sys_call_table)
 	.long sys_rt_sigpending
 	.long sys_rt_sigpending
 	.long sys_rt_sigtimedwait
 	.long sys_rt_sigtimedwait
 	.long sys_rt_sigqueueinfo
 	.long sys_rt_sigqueueinfo
-	.long sys_rt_sigsuspend_wrapper
+	.long sys_rt_sigsuspend
 	.long sys_pread64		/* 180 */
 	.long sys_pread64		/* 180 */
 	.long sys_pwrite64
 	.long sys_pwrite64
 	.long sys_chown
 	.long sys_chown
@@ -303,7 +303,7 @@ ENTRY(sys_call_table)
 	.long sys_mkdirat
 	.long sys_mkdirat
 	.long sys_mknodat
 	.long sys_mknodat
 	.long sys_fchownat
 	.long sys_fchownat
-	.long sys_ni_syscall
+	.long sys_futimesat
 	.long sys_fstatat64		/* 300 */
 	.long sys_fstatat64		/* 300 */
 	.long sys_unlinkat
 	.long sys_unlinkat
 	.long sys_renameat
 	.long sys_renameat

+ 28 - 0
arch/microblaze/kernel/timer.c

@@ -183,6 +183,31 @@ static cycle_t microblaze_read(struct clocksource *cs)
 	return (cycle_t) (in_be32(TIMER_BASE + TCR1));
 	return (cycle_t) (in_be32(TIMER_BASE + TCR1));
 }
 }
 
 
+static struct timecounter microblaze_tc = {
+	.cc = NULL,
+};
+
+static cycle_t microblaze_cc_read(const struct cyclecounter *cc)
+{
+	return microblaze_read(NULL);
+}
+
+static struct cyclecounter microblaze_cc = {
+	.read = microblaze_cc_read,
+	.mask = CLOCKSOURCE_MASK(32),
+	.shift = 24,
+};
+
+int __init init_microblaze_timecounter(void)
+{
+	microblaze_cc.mult = div_sc(cpuinfo.cpu_clock_freq, NSEC_PER_SEC,
+				microblaze_cc.shift);
+
+	timecounter_init(&microblaze_tc, &microblaze_cc, sched_clock());
+
+	return 0;
+}
+
 static struct clocksource clocksource_microblaze = {
 static struct clocksource clocksource_microblaze = {
 	.name		= "microblaze_clocksource",
 	.name		= "microblaze_clocksource",
 	.rating		= 300,
 	.rating		= 300,
@@ -204,6 +229,9 @@ static int __init microblaze_clocksource_init(void)
 	out_be32(TIMER_BASE + TCSR1, in_be32(TIMER_BASE + TCSR1) & ~TCSR_ENT);
 	out_be32(TIMER_BASE + TCSR1, in_be32(TIMER_BASE + TCSR1) & ~TCSR_ENT);
 	/* start timer1 - up counting without interrupt */
 	/* start timer1 - up counting without interrupt */
 	out_be32(TIMER_BASE + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT);
 	out_be32(TIMER_BASE + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT);
+
+	/* register timecounter - for ftrace support */
+	init_microblaze_timecounter();
 	return 0;
 	return 0;
 }
 }
 
 

+ 4 - 2
arch/microblaze/kernel/vmlinux.lds.S

@@ -26,11 +26,12 @@ SECTIONS {
 		_stext = . ;
 		_stext = . ;
 		*(.text .text.*)
 		*(.text .text.*)
 		*(.fixup)
 		*(.fixup)
-               EXIT_TEXT
-               EXIT_CALL
+		EXIT_TEXT
+		EXIT_CALL
 		SCHED_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
 		LOCK_TEXT
 		KPROBES_TEXT
 		KPROBES_TEXT
+		IRQENTRY_TEXT
 		. = ALIGN (4) ;
 		. = ALIGN (4) ;
 		_etext = . ;
 		_etext = . ;
 	}
 	}
@@ -86,6 +87,7 @@ SECTIONS {
 		_KERNEL_SDA_BASE_ = _ssro + (_ssro_size / 2) ;
 		_KERNEL_SDA_BASE_ = _ssro + (_ssro_size / 2) ;
 	}
 	}
 
 
+	. = ALIGN(PAGE_SIZE);
 	__init_begin = .;
 	__init_begin = .;
 
 
 	INIT_TEXT_SECTION(PAGE_SIZE)
 	INIT_TEXT_SECTION(PAGE_SIZE)

+ 7 - 0
arch/microblaze/lib/uaccess.c

@@ -39,3 +39,10 @@ long strncpy_from_user(char *dst, const char __user *src, long count)
 		__do_strncpy_from_user(dst, src, count, res);
 		__do_strncpy_from_user(dst, src, count, res);
 	return res;
 	return res;
 }
 }
+
+unsigned long __copy_tofrom_user(void __user *to,
+		const void __user *from, unsigned long size)
+{
+	memcpy(to, from, size);
+	return 0;
+}

+ 1 - 0
arch/microblaze/mm/init.c

@@ -41,6 +41,7 @@ char *klimit = _end;
  * have available.
  * have available.
  */
  */
 unsigned long memory_start;
 unsigned long memory_start;
+EXPORT_SYMBOL(memory_start);
 unsigned long memory_end; /* due to mm/nommu.c */
 unsigned long memory_end; /* due to mm/nommu.c */
 unsigned long memory_size;
 unsigned long memory_size;
 
 

+ 0 - 10
arch/microblaze/mm/pgtable.c

@@ -144,7 +144,6 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
 	pmd_t *pd;
 	pmd_t *pd;
 	pte_t *pg;
 	pte_t *pg;
 	int err = -ENOMEM;
 	int err = -ENOMEM;
-	/* spin_lock(&init_mm.page_table_lock); */
 	/* Use upper 10 bits of VA to index the first level map */
 	/* Use upper 10 bits of VA to index the first level map */
 	pd = pmd_offset(pgd_offset_k(va), va);
 	pd = pmd_offset(pgd_offset_k(va), va);
 	/* Use middle 10 bits of VA to index the second-level map */
 	/* Use middle 10 bits of VA to index the second-level map */
@@ -158,9 +157,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
 		if (mem_init_done)
 		if (mem_init_done)
 			flush_HPTE(0, va, pmd_val(*pd));
 			flush_HPTE(0, va, pmd_val(*pd));
 			/* flush_HPTE(0, va, pg); */
 			/* flush_HPTE(0, va, pg); */
-
 	}
 	}
-	/* spin_unlock(&init_mm.page_table_lock); */
 	return err;
 	return err;
 }
 }
 
 
@@ -182,12 +179,6 @@ void __init adjust_total_lowmem(void)
 #endif
 #endif
 }
 }
 
 
-static void show_tmem(unsigned long tmem)
-{
-	volatile unsigned long a;
-	a = a + tmem;
-}
-
 /*
 /*
  * Map in all of physical memory starting at CONFIG_KERNEL_START.
  * Map in all of physical memory starting at CONFIG_KERNEL_START.
  */
  */
@@ -197,7 +188,6 @@ void __init mapin_ram(void)
 
 
 	v = CONFIG_KERNEL_START;
 	v = CONFIG_KERNEL_START;
 	p = memory_start;
 	p = memory_start;
-	show_tmem(memory_size);
 	for (s = 0; s < memory_size; s += PAGE_SIZE) {
 	for (s = 0; s < memory_size; s += PAGE_SIZE) {
 		f = _PAGE_PRESENT | _PAGE_ACCESSED |
 		f = _PAGE_PRESENT | _PAGE_ACCESSED |
 				_PAGE_SHARED | _PAGE_HWEXEC;
 				_PAGE_SHARED | _PAGE_HWEXEC;

+ 13 - 0
arch/microblaze/oprofile/Makefile

@@ -0,0 +1,13 @@
+#
+# arch/microblaze/oprofile/Makefile
+#
+
+obj-$(CONFIG_OPROFILE) += oprofile.o
+
+DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
+		oprof.o cpu_buffer.o buffer_sync.o \
+		event_buffer.o oprofile_files.o \
+		oprofilefs.o oprofile_stats.o \
+		timer_int.o )
+
+oprofile-y := $(DRIVER_OBJS) microblaze_oprofile.o

+ 22 - 0
arch/microblaze/oprofile/microblaze_oprofile.c

@@ -0,0 +1,22 @@
+/*
+ * Microblaze oprofile code
+ *
+ * Copyright (C) 2009 Michal Simek <monstr@monstr.eu>
+ * Copyright (C) 2009 PetaLogix
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/oprofile.h>
+#include <linux/init.h>
+
+int __init oprofile_arch_init(struct oprofile_operations *ops)
+{
+	return -1;
+}
+
+void oprofile_arch_exit(void)
+{
+}

+ 1 - 20
arch/microblaze/platform/Kconfig.platform

@@ -53,31 +53,12 @@ config OPT_LIB_FUNCTION
 
 
 config OPT_LIB_ASM
 config OPT_LIB_ASM
 	bool "Optimalized lib function ASM"
 	bool "Optimalized lib function ASM"
-	depends on OPT_LIB_FUNCTION
+	depends on OPT_LIB_FUNCTION && (XILINX_MICROBLAZE0_USE_BARREL = 1)
 	default n
 	default n
 	help
 	help
 	  Allows turn on optimalized library function (memcpy and memmove).
 	  Allows turn on optimalized library function (memcpy and memmove).
 	  Function are written in asm code.
 	  Function are written in asm code.
 
 
-# This is still a bit broken - disabling for now JW 20070504
-config ALLOW_EDIT_AUTO
-	bool "Permit Display/edit of Kconfig.auto platform settings"
-	default n
-	help
-	  Allows the editing of auto-generated platform settings from
-	  the Kconfig.auto file. Obviously this does not change the
-	  underlying hardware, so be very careful if you go editing
-	  these settings.
-
-	  Also, if you enable this, and edit various Kconfig.auto
-	  settings, YOUR CHANGES WILL BE LOST if you then disable it
-	  again. You have been warned!
-
-	  If unsure, say no.
-
-comment "Automatic platform settings from Kconfig.auto"
-	depends on ALLOW_EDIT_AUTO
-
 if PLATFORM_GENERIC=y
 if PLATFORM_GENERIC=y
 	source "arch/microblaze/platform/generic/Kconfig.auto"
 	source "arch/microblaze/platform/generic/Kconfig.auto"
 endif
 endif

+ 14 - 15
arch/microblaze/platform/generic/Kconfig.auto

@@ -21,7 +21,6 @@
 
 
 # Definitions for MICROBLAZE0
 # Definitions for MICROBLAZE0
 comment "Definitions for MICROBLAZE0"
 comment "Definitions for MICROBLAZE0"
-	depends on ALLOW_EDIT_AUTO
 
 
 config KERNEL_BASE_ADDR
 config KERNEL_BASE_ADDR
 	hex "Physical address where Linux Kernel is"
 	hex "Physical address where Linux Kernel is"
@@ -30,33 +29,33 @@ config KERNEL_BASE_ADDR
 	  BASE Address for kernel
 	  BASE Address for kernel
 
 
 config XILINX_MICROBLAZE0_FAMILY
 config XILINX_MICROBLAZE0_FAMILY
-	string "Targetted FPGA family" if ALLOW_EDIT_AUTO
+	string "Targetted FPGA family"
 	default "virtex5"
 	default "virtex5"
 
 
 config XILINX_MICROBLAZE0_USE_MSR_INSTR
 config XILINX_MICROBLAZE0_USE_MSR_INSTR
-	int "USE_MSR_INSTR range (0:1)" if ALLOW_EDIT_AUTO
-	default 1
+	int "USE_MSR_INSTR range (0:1)"
+	default 0
 
 
 config XILINX_MICROBLAZE0_USE_PCMP_INSTR
 config XILINX_MICROBLAZE0_USE_PCMP_INSTR
-	int "USE_PCMP_INSTR range (0:1)" if ALLOW_EDIT_AUTO
-	default 1
+	int "USE_PCMP_INSTR range (0:1)"
+	default 0
 
 
 config XILINX_MICROBLAZE0_USE_BARREL
 config XILINX_MICROBLAZE0_USE_BARREL
-	int "USE_BARREL range (0:1)" if ALLOW_EDIT_AUTO
-	default 1
+	int "USE_BARREL range (0:1)"
+	default 0
 
 
 config XILINX_MICROBLAZE0_USE_DIV
 config XILINX_MICROBLAZE0_USE_DIV
-	int "USE_DIV range (0:1)" if ALLOW_EDIT_AUTO
-	default 1
+	int "USE_DIV range (0:1)"
+	default 0
 
 
 config XILINX_MICROBLAZE0_USE_HW_MUL
 config XILINX_MICROBLAZE0_USE_HW_MUL
-	int "USE_HW_MUL values (0=NONE, 1=MUL32, 2=MUL64)" if ALLOW_EDIT_AUTO
-	default 2
+	int "USE_HW_MUL values (0=NONE, 1=MUL32, 2=MUL64)"
+	default 0
 
 
 config XILINX_MICROBLAZE0_USE_FPU
 config XILINX_MICROBLAZE0_USE_FPU
-	int "USE_FPU values (0=NONE, 1=BASIC, 2=EXTENDED)" if ALLOW_EDIT_AUTO
-	default 2
+	int "USE_FPU values (0=NONE, 1=BASIC, 2=EXTENDED)"
+	default 0
 
 
 config XILINX_MICROBLAZE0_HW_VER
 config XILINX_MICROBLAZE0_HW_VER
-	string "Core version number" if ALLOW_EDIT_AUTO
+	string "Core version number"
 	default 7.10.d
 	default 7.10.d

+ 35 - 3
arch/microblaze/platform/generic/system.dts

@@ -32,11 +32,16 @@
 	#address-cells = <1>;
 	#address-cells = <1>;
 	#size-cells = <1>;
 	#size-cells = <1>;
 	compatible = "xlnx,microblaze";
 	compatible = "xlnx,microblaze";
+	hard-reset-gpios = <&LEDs_8Bit 2 1>;
 	model = "testing";
 	model = "testing";
 	DDR2_SDRAM: memory@90000000 {
 	DDR2_SDRAM: memory@90000000 {
 		device_type = "memory";
 		device_type = "memory";
 		reg = < 0x90000000 0x10000000 >;
 		reg = < 0x90000000 0x10000000 >;
 	} ;
 	} ;
+	aliases {
+		ethernet0 = &Hard_Ethernet_MAC;
+		serial0 = &RS232_Uart_1;
+	} ;
 	chosen {
 	chosen {
 		bootargs = "console=ttyUL0,115200 highres=on";
 		bootargs = "console=ttyUL0,115200 highres=on";
 		linux,stdout-path = "/plb@0/serial@84000000";
 		linux,stdout-path = "/plb@0/serial@84000000";
@@ -127,7 +132,7 @@
 	mb_plb: plb@0 {
 	mb_plb: plb@0 {
 		#address-cells = <1>;
 		#address-cells = <1>;
 		#size-cells = <1>;
 		#size-cells = <1>;
-		compatible = "xlnx,plb-v46-1.03.a", "simple-bus";
+		compatible = "xlnx,plb-v46-1.03.a", "xlnx,plb-v46-1.00.a", "simple-bus";
 		ranges ;
 		ranges ;
 		FLASH: flash@a0000000 {
 		FLASH: flash@a0000000 {
 			bank-width = <2>;
 			bank-width = <2>;
@@ -214,12 +219,12 @@
 			#size-cells = <1>;
 			#size-cells = <1>;
 			compatible = "xlnx,compound";
 			compatible = "xlnx,compound";
 			ethernet@81c00000 {
 			ethernet@81c00000 {
-				compatible = "xlnx,xps-ll-temac-1.01.b";
+				compatible = "xlnx,xps-ll-temac-1.01.b", "xlnx,xps-ll-temac-1.00.a";
 				device_type = "network";
 				device_type = "network";
 				interrupt-parent = <&xps_intc_0>;
 				interrupt-parent = <&xps_intc_0>;
 				interrupts = < 5 2 >;
 				interrupts = < 5 2 >;
 				llink-connected = <&PIM3>;
 				llink-connected = <&PIM3>;
-				local-mac-address = [ 02 00 00 00 00 00 ];
+				local-mac-address = [ 00 0a 35 00 00 00 ];
 				reg = < 0x81c00000 0x40 >;
 				reg = < 0x81c00000 0x40 >;
 				xlnx,bus2core-clk-ratio = <0x1>;
 				xlnx,bus2core-clk-ratio = <0x1>;
 				xlnx,phy-type = <0x1>;
 				xlnx,phy-type = <0x1>;
@@ -261,6 +266,33 @@
 			xlnx,is-dual = <0x0>;
 			xlnx,is-dual = <0x0>;
 			xlnx,tri-default = <0xffffffff>;
 			xlnx,tri-default = <0xffffffff>;
 			xlnx,tri-default-2 = <0xffffffff>;
 			xlnx,tri-default-2 = <0xffffffff>;
+			#gpio-cells = <2>;
+			gpio-controller;
+		} ;
+
+		gpio-leds {
+			compatible = "gpio-leds";
+
+			heartbeat {
+				label = "Heartbeat";
+				gpios = <&LEDs_8Bit 4 1>;
+				linux,default-trigger = "heartbeat";
+			};
+
+			yellow {
+				label = "Yellow";
+				gpios = <&LEDs_8Bit 5 1>;
+			};
+
+			red {
+				label = "Red";
+				gpios = <&LEDs_8Bit 6 1>;
+			};
+
+			green {
+				label = "Green";
+				gpios = <&LEDs_8Bit 7 1>;
+			};
 		} ;
 		} ;
 		RS232_Uart_1: serial@84000000 {
 		RS232_Uart_1: serial@84000000 {
 			clock-frequency = <125000000>;
 			clock-frequency = <125000000>;

+ 2 - 0
arch/microblaze/platform/platform.c

@@ -13,6 +13,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/of_platform.h>
 #include <linux/of_platform.h>
 #include <asm/prom.h>
 #include <asm/prom.h>
+#include <asm/setup.h>
 
 
 static struct of_device_id xilinx_of_bus_ids[] __initdata = {
 static struct of_device_id xilinx_of_bus_ids[] __initdata = {
 	{ .compatible = "simple-bus", },
 	{ .compatible = "simple-bus", },
@@ -26,6 +27,7 @@ static struct of_device_id xilinx_of_bus_ids[] __initdata = {
 static int __init microblaze_device_probe(void)
 static int __init microblaze_device_probe(void)
 {
 {
 	of_platform_bus_probe(NULL, xilinx_of_bus_ids, NULL);
 	of_platform_bus_probe(NULL, xilinx_of_bus_ids, NULL);
+	of_platform_reset_gpio_probe();
 	return 0;
 	return 0;
 }
 }
 device_initcall(microblaze_device_probe);
 device_initcall(microblaze_device_probe);

+ 3 - 0
scripts/recordmcount.pl

@@ -295,6 +295,9 @@ if ($arch eq "x86_64") {
     $ld .= " -m elf64_sparc";
     $ld .= " -m elf64_sparc";
     $cc .= " -m64";
     $cc .= " -m64";
     $objcopy .= " -O elf64-sparc";
     $objcopy .= " -O elf64-sparc";
+} elsif ($arch eq "microblaze") {
+    # Microblaze calls '_mcount' instead of plain 'mcount'.
+    $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$";
 } else {
 } else {
     die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
     die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
 }
 }