summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/microblaze/Kconfig19
-rw-r--r--arch/microblaze/Kconfig.debug3
-rw-r--r--arch/microblaze/Makefile2
-rw-r--r--arch/microblaze/boot/Makefile15
-rw-r--r--arch/microblaze/include/asm/cache.h16
-rw-r--r--arch/microblaze/include/asm/cacheflush.h123
-rw-r--r--arch/microblaze/include/asm/cpuinfo.h5
-rw-r--r--arch/microblaze/include/asm/device.h12
-rw-r--r--arch/microblaze/include/asm/ftrace.h25
-rw-r--r--arch/microblaze/include/asm/futex.h127
-rw-r--r--arch/microblaze/include/asm/irqflags.h112
-rw-r--r--arch/microblaze/include/asm/page.h3
-rw-r--r--arch/microblaze/include/asm/pgalloc.h9
-rw-r--r--arch/microblaze/include/asm/pvr.h30
-rw-r--r--arch/microblaze/include/asm/setup.h2
-rw-r--r--arch/microblaze/include/asm/system.h2
-rw-r--r--arch/microblaze/include/asm/uaccess.h12
-rw-r--r--arch/microblaze/kernel/Makefile14
-rw-r--r--arch/microblaze/kernel/cpu/Makefile4
-rw-r--r--arch/microblaze/kernel/cpu/cache.c663
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c15
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo-static.c17
-rw-r--r--arch/microblaze/kernel/cpu/cpuinfo.c7
-rw-r--r--arch/microblaze/kernel/cpu/mb.c8
-rw-r--r--arch/microblaze/kernel/cpu/pvr.c2
-rw-r--r--arch/microblaze/kernel/entry-nommu.S2
-rw-r--r--arch/microblaze/kernel/entry.S19
-rw-r--r--arch/microblaze/kernel/ftrace.c237
-rw-r--r--arch/microblaze/kernel/heartbeat.c15
-rw-r--r--arch/microblaze/kernel/intc.c10
-rw-r--r--arch/microblaze/kernel/mcount.S170
-rw-r--r--arch/microblaze/kernel/microblaze_ksyms.c5
-rw-r--r--arch/microblaze/kernel/process.c1
-rw-r--r--arch/microblaze/kernel/reset.c140
-rw-r--r--arch/microblaze/kernel/setup.c40
-rw-r--r--arch/microblaze/kernel/signal.c35
-rw-r--r--arch/microblaze/kernel/stacktrace.c65
-rw-r--r--arch/microblaze/kernel/syscall_table.S4
-rw-r--r--arch/microblaze/kernel/timer.c28
-rw-r--r--arch/microblaze/kernel/vmlinux.lds.S6
-rw-r--r--arch/microblaze/lib/uaccess.c7
-rw-r--r--arch/microblaze/mm/init.c1
-rw-r--r--arch/microblaze/mm/pgtable.c10
-rw-r--r--arch/microblaze/oprofile/Makefile13
-rw-r--r--arch/microblaze/oprofile/microblaze_oprofile.c22
-rw-r--r--arch/microblaze/platform/Kconfig.platform21
-rw-r--r--arch/microblaze/platform/generic/Kconfig.auto29
-rw-r--r--arch/microblaze/platform/generic/system.dts38
-rw-r--r--arch/microblaze/platform/platform.c2
49 files changed, 1683 insertions, 484 deletions
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig
index bbd8327f189..fd53e500be6 100644
--- a/arch/microblaze/Kconfig
+++ b/arch/microblaze/Kconfig
@@ -6,8 +6,15 @@ mainmenu "Linux/Microblaze Kernel Configuration"
config MICROBLAZE
def_bool y
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 ARCH_WANT_OPTIONAL_GPIOLIB
+ select HAVE_OPROFILE
+ select TRACING_SUPPORT
config SWAP
def_bool n
@@ -57,12 +64,24 @@ config GENERIC_GPIO
config GENERIC_CSUM
def_bool y
+config STACKTRACE_SUPPORT
+ def_bool y
+
+config LOCKDEP_SUPPORT
+ def_bool y
+
+config HAVE_LATENCYTOP_SUPPORT
+ def_bool y
+
config PCI
def_bool n
config NO_DMA
def_bool y
+config DTC
+ def_bool y
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
diff --git a/arch/microblaze/Kconfig.debug b/arch/microblaze/Kconfig.debug
index 242cd35bdb4..9dc708a7f70 100644
--- a/arch/microblaze/Kconfig.debug
+++ b/arch/microblaze/Kconfig.debug
@@ -3,6 +3,9 @@
menu "Kernel hacking"
+config TRACE_IRQFLAGS_SUPPORT
+ def_bool y
+
source "lib/Kconfig.debug"
config EARLY_PRINTK
diff --git a/arch/microblaze/Makefile b/arch/microblaze/Makefile
index 34187354304..d2d6cfcb1a3 100644
--- a/arch/microblaze/Makefile
+++ b/arch/microblaze/Makefile
@@ -51,6 +51,8 @@ core-y += arch/microblaze/kernel/
core-y += arch/microblaze/mm/
core-y += arch/microblaze/platform/
+drivers-$(CONFIG_OPROFILE) += arch/microblaze/oprofile/
+
boot := arch/microblaze/boot
# Are we making a simpleImage.<boardname> target? If so, crack out the boardname
diff --git a/arch/microblaze/boot/Makefile b/arch/microblaze/boot/Makefile
index 21f13322a4c..902cf9846c3 100644
--- a/arch/microblaze/boot/Makefile
+++ b/arch/microblaze/boot/Makefile
@@ -2,11 +2,13 @@
# arch/microblaze/boot/Makefile
#
+MKIMAGE := $(srctree)/scripts/mkuboot.sh
+
obj-y += linked_dtb.o
targets := linux.bin linux.bin.gz simpleImage.%
-OBJCOPYFLAGS_linux.bin := -O binary
+OBJCOPYFLAGS := -O binary
# Where the DTS files live
dtstree := $(srctree)/$(src)/dts
@@ -24,6 +26,7 @@ $(obj)/linux.bin: vmlinux FORCE
[ -n $(CONFIG_INITRAMFS_SOURCE) ] && [ ! -e $(CONFIG_INITRAMFS_SOURCE) ] && \
touch $(CONFIG_INITRAMFS_SOURCE) || echo "No CPIO image"
$(call if_changed,objcopy)
+ $(call if_changed,uimage)
@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
$(obj)/linux.bin.gz: $(obj)/linux.bin FORCE
@@ -36,8 +39,16 @@ quiet_cmd_cp = CP $< $@$2
quiet_cmd_strip = STRIP $@
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
$(call if_changed,cp,.unstrip)
+ $(call if_changed,objcopy)
+ $(call if_changed,uimage)
$(call if_changed,strip)
@echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
@@ -53,4 +64,4 @@ $(obj)/%.dtb: $(dtstree)/%.dts FORCE
clean-kernel += linux.bin linux.bin.gz simpleImage.*
-clean-files += *.dtb
+clean-files += *.dtb simpleImage.*.unstrip
diff --git a/arch/microblaze/include/asm/cache.h b/arch/microblaze/include/asm/cache.h
index c209c47509d..e52210891d7 100644
--- a/arch/microblaze/include/asm/cache.h
+++ b/arch/microblaze/include/asm/cache.h
@@ -21,20 +21,4 @@
#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 */
diff --git a/arch/microblaze/include/asm/cacheflush.h b/arch/microblaze/include/asm/cacheflush.h
index 088076e657b..a6edd356cd0 100644
--- a/arch/microblaze/include/asm/cacheflush.h
+++ b/arch/microblaze/include/asm/cacheflush.h
@@ -18,6 +18,8 @@
/* Somebody depends on this; sigh... */
#include <linux/mm.h>
+/* Look at Documentation/cachetlb.txt */
+
/*
* Cache handling functions.
* 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.
*/
+/* 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 */
-#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
+/* D-cache aliasing problem can't happen - cache is between MMU and ram */
#define flush_dcache_page(page) do { } while (0)
#define flush_dcache_mmap_lock(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
-#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)
-#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 */
diff --git a/arch/microblaze/include/asm/cpuinfo.h b/arch/microblaze/include/asm/cpuinfo.h
index 52f28f6dc4e..b4f5ca33aeb 100644
--- a/arch/microblaze/include/asm/cpuinfo.h
+++ b/arch/microblaze/include/asm/cpuinfo.h
@@ -43,7 +43,7 @@ struct cpuinfo {
u32 use_icache;
u32 icache_tagbits;
u32 icache_write;
- u32 icache_line;
+ u32 icache_line_length;
u32 icache_size;
unsigned long icache_base;
unsigned long icache_high;
@@ -51,8 +51,9 @@ struct cpuinfo {
u32 use_dcache;
u32 dcache_tagbits;
u32 dcache_write;
- u32 dcache_line;
+ u32 dcache_line_length;
u32 dcache_size;
+ u32 dcache_wb;
unsigned long dcache_base;
unsigned long dcache_high;
diff --git a/arch/microblaze/include/asm/device.h b/arch/microblaze/include/asm/device.h
index 30286db27c1..78a038452c0 100644
--- a/arch/microblaze/include/asm/device.h
+++ b/arch/microblaze/include/asm/device.h
@@ -19,6 +19,18 @@ struct dev_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 */
diff --git a/arch/microblaze/include/asm/ftrace.h b/arch/microblaze/include/asm/ftrace.h
index 8b137891791..fd2fa2eca62 100644
--- a/arch/microblaze/include/asm/ftrace.h
+++ b/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 */
diff --git a/arch/microblaze/include/asm/futex.h b/arch/microblaze/include/asm/futex.h
index 0b745828f42..8dbb6e7a03a 100644
--- a/arch/microblaze/include/asm/futex.h
+++ b/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
diff --git a/arch/microblaze/include/asm/irqflags.h b/arch/microblaze/include/asm/irqflags.h
index dea65645a4f..2c38c6d8017 100644
--- a/arch/microblaze/include/asm/irqflags.h
+++ b/arch/microblaze/include/asm/irqflags.h
@@ -10,78 +10,73 @@
#define _ASM_MICROBLAZE_IRQFLAGS_H
#include <linux/irqflags.h>
+#include <asm/registers.h>
# if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
-# define local_irq_save(flags) \
+# define raw_local_irq_save(flags) \
do { \
- asm volatile ("# local_irq_save \n\t" \
- "msrclr %0, %1 \n\t" \
- "nop \n\t" \
+ asm volatile (" msrclr %0, %1; \
+ nop;" \
: "=r"(flags) \
: "i"(MSR_IE) \
: "memory"); \
} 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)
-# 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)
# else /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR == 0 */
-# define local_irq_save(flags) \
+# define raw_local_irq_save(flags) \
do { \
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) \
: "i"(~MSR_IE) \
: "memory"); \
} while (0)
-# define local_irq_disable() \
+# define raw_local_irq_disable() \
do { \
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) \
: "i"(~MSR_IE) \
: "memory"); \
} while (0)
-# define local_irq_enable() \
+# define raw_local_irq_enable() \
do { \
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) \
: "i"(MSR_IE) \
: "memory"); \
@@ -89,35 +84,28 @@
# endif /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */
-#define local_save_flags(flags) \
+#define raw_local_irq_restore(flags) \
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"); \
} 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;
-
- 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 */
diff --git a/arch/microblaze/include/asm/page.h b/arch/microblaze/include/asm/page.h
index 880c988c223..9b66c0fa9a3 100644
--- a/arch/microblaze/include/asm/page.h
+++ b/arch/microblaze/include/asm/page.h
@@ -164,7 +164,8 @@ extern int page_is_ram(unsigned long pfn);
# endif /* 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)
# else /* CONFIG_MMU */
# define ARCH_PFN_OFFSET (memory_start >> PAGE_SHIFT)
diff --git a/arch/microblaze/include/asm/pgalloc.h b/arch/microblaze/include/asm/pgalloc.h
index b0131da1387..7547f506456 100644
--- a/arch/microblaze/include/asm/pgalloc.h
+++ b/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(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,
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..
*/
#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()
extern int do_check_pgt_cache(int, int);
#endif /* CONFIG_MMU */
-#define check_pgt_cache() do {} while (0)
+#define check_pgt_cache() do { } while (0)
#endif /* _ASM_MICROBLAZE_PGALLOC_H */
diff --git a/arch/microblaze/include/asm/pvr.h b/arch/microblaze/include/asm/pvr.h
index 66f1b30dd09..e38abc7714b 100644
--- a/arch/microblaze/include/asm/pvr.h
+++ b/arch/microblaze/include/asm/pvr.h
@@ -76,20 +76,23 @@ struct pvr_s {
#define PVR3_FSL_LINKS_MASK 0x00000380
/* 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 */
-#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 */
#define PVR6_ICACHE_BASEADDR_MASK 0xFFFFFFFF
@@ -178,11 +181,14 @@ struct pvr_s {
((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_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) \
(1 << ((pvr.pvr[5] & PVR5_DCACHE_LINE_LEN_MASK) >> 21))
#define PVR_DCACHE_BYTE_SIZE(pvr) \
(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_HIGHADDR(pvr) (pvr.pvr[7] & PVR7_ICACHE_HIGHADDR_MASK)
diff --git a/arch/microblaze/include/asm/setup.h b/arch/microblaze/include/asm/setup.h
index ed67c9ed15b..7f31394985e 100644
--- a/arch/microblaze/include/asm/setup.h
+++ b/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);
# endif /* CONFIG_MMU */
+extern void of_platform_reset_gpio_probe(void);
+
void time_init(void);
void init_IRQ(void);
void machine_early_init(const char *cmdline, unsigned int ram,
diff --git a/arch/microblaze/include/asm/system.h b/arch/microblaze/include/asm/system.h
index b1ed6159066..157970688b2 100644
--- a/arch/microblaze/include/asm/system.h
+++ b/arch/microblaze/include/asm/system.h
@@ -16,6 +16,8 @@
#include <asm-generic/cmpxchg.h>
#include <asm-generic/cmpxchg-local.h>
+#define __ARCH_WANT_INTERRUPTS_ON_CTXSW
+
struct task_struct;
struct thread_info;
diff --git a/arch/microblaze/include/asm/uaccess.h b/arch/microblaze/include/asm/uaccess.h
index 5431b4631a7..371bd6e56d9 100644
--- a/arch/microblaze/include/asm/uaccess.h
+++ b/arch/microblaze/include/asm/uaccess.h
@@ -272,8 +272,9 @@ static inline int clear_user(char *to, int 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) \
(access_ok(VERIFY_WRITE, (to), (n)) ? \
@@ -290,10 +291,6 @@ extern unsigned long __copy_tofrom_user(void __user *to,
(void __user *)(from), (n)) \
: -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 __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 */
+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
* address of an instruction that is allowed to fault, and the second is
diff --git a/arch/microblaze/kernel/Makefile b/arch/microblaze/kernel/Makefile
index d487729683d..b07594eccf9 100644
--- a/arch/microblaze/kernel/Makefile
+++ b/arch/microblaze/kernel/Makefile
@@ -2,12 +2,22 @@
# 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
obj-y += exceptions.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 \
- 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/
@@ -16,5 +26,7 @@ obj-$(CONFIG_SELFMOD) += selfmod.o
obj-$(CONFIG_HEART_BEAT) += heartbeat.o
obj-$(CONFIG_MODULES) += microblaze_ksyms.o module.o
obj-$(CONFIG_MMU) += misc.o
+obj-$(CONFIG_STACKTRACE) += stacktrace.o
+obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount.o
obj-y += entry$(MMU).o
diff --git a/arch/microblaze/kernel/cpu/Makefile b/arch/microblaze/kernel/cpu/Makefile
index 20646e54927..59cc7bceaf8 100644
--- a/arch/microblaze/kernel/cpu/Makefile
+++ b/arch/microblaze/kernel/cpu/Makefile
@@ -2,6 +2,10 @@
# 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) \
-DCPU_REV=$(CPU_REV)
diff --git a/arch/microblaze/kernel/cpu/cache.c b/arch/microblaze/kernel/cpu/cache.c
index af866a45012..d9d63831cc2 100644
--- a/arch/microblaze/kernel/cpu/cache.c
+++ b/arch/microblaze/kernel/cpu/cache.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
* 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
* Public License. See the file COPYING in the main directory of this
@@ -13,243 +13,534 @@
#include <asm/cacheflush.h>
#include <linux/cache.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");
-#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");
-#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");
-#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");
-#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");
-#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 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;
+ }
+ }
+ }
}
diff --git a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
index c259786e7fa..f72dbd66c84 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
+++ b/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
@@ -21,8 +21,14 @@
*/
#define CI(c, p) { ci->c = PVR_##p(pvr); }
+
+#if defined(CONFIG_EARLY_PRINTK) && defined(CONFIG_SERIAL_UARTLITE_CONSOLE)
#define err_printk(x) \
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)
{
@@ -70,7 +76,7 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
CI(use_icache, USE_ICACHE);
CI(icache_tagbits, ICACHE_ADDR_TAG_BITS);
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_base, ICACHE_BASEADDR);
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(dcache_tagbits, DCACHE_ADDR_TAG_BITS);
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_base, DCACHE_BASEADDR);
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_iopb, I_OPB);
CI(use_dlmb, D_LMB);
diff --git a/arch/microblaze/kernel/cpu/cpuinfo-static.c b/arch/microblaze/kernel/cpu/cpuinfo-static.c
index adb448f93d5..6095aa6b5c8 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo-static.c
+++ b/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->icache_tagbits = fcpu(cpu, "xlnx,addr-tag-bits");
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"))
- ci->icache_line = 4 << 2;
+ ci->icache_line_length = 4 << 2;
else
- ci->icache_line = 1 << 2;
+ ci->icache_line_length = 1 << 2;
}
ci->icache_size = fcpu(cpu, "i-cache-size");
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->dcache_tagbits = fcpu(cpu, "xlnx,dcache-addr-tag");
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"))
- ci->dcache_line = 4 << 2;
+ ci->dcache_line_length = 4 << 2;
else
- ci->dcache_line = 1 << 2;
+ ci->dcache_line_length = 1 << 2;
}
ci->dcache_size = fcpu(cpu, "d-cache-size");
ci->dcache_base = fcpu(cpu, "d-cache-baseaddr");
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_iopb = fcpu(cpu, "xlnx,i-opb");
diff --git a/arch/microblaze/kernel/cpu/cpuinfo.c b/arch/microblaze/kernel/cpu/cpuinfo.c
index 3539babc1c1..991d71311b0 100644
--- a/arch/microblaze/kernel/cpu/cpuinfo.c
+++ b/arch/microblaze/kernel/cpu/cpuinfo.c
@@ -29,11 +29,8 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
{"7.20.a", 0x0c},
{"7.20.b", 0x0d},
{"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},
};
diff --git a/arch/microblaze/kernel/cpu/mb.c b/arch/microblaze/kernel/cpu/mb.c
index 4dcfccdbc36..0c912b2a8e0 100644
--- a/arch/microblaze/kernel/cpu/mb.c
+++ b/arch/microblaze/kernel/cpu/mb.c
@@ -103,11 +103,15 @@ static int show_cpuinfo(struct seq_file *m, void *v)
else
count += seq_printf(m, "Icache:\t\tno\n");
- if (cpuinfo.use_dcache)
+ if (cpuinfo.use_dcache) {
count += seq_printf(m,
"Dcache:\t\t%ukB\n",
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,
diff --git a/arch/microblaze/kernel/cpu/pvr.c b/arch/microblaze/kernel/cpu/pvr.c
index c9a4340ddd5..9bee9382bf7 100644
--- a/arch/microblaze/kernel/cpu/pvr.c
+++ b/arch/microblaze/kernel/cpu/pvr.c
@@ -45,7 +45,7 @@
int cpu_has_pvr(void)
{
- unsigned flags;
+ unsigned long flags;
unsigned pvr0;
local_save_flags(flags);
diff --git a/arch/microblaze/kernel/entry-nommu.S b/arch/microblaze/kernel/entry-nommu.S
index 9083d85376a..95b0855802d 100644
--- a/arch/microblaze/kernel/entry-nommu.S
+++ b/arch/microblaze/kernel/entry-nommu.S
@@ -208,8 +208,6 @@ ENTRY(_user_exception)
lwi r1, r1, TS_THREAD_INFO /* get the thread info */
/* calculate kernel stack pointer */
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:
swi r11, r1, PT_MODE /* store the mode */
lwi r11, r0, PER_CPU(R11_SAVE) /* reload r11 */
diff --git a/arch/microblaze/kernel/entry.S b/arch/microblaze/kernel/entry.S
index e3ecb36dd55..3bad4ff4947 100644
--- a/arch/microblaze/kernel/entry.S
+++ b/arch/microblaze/kernel/entry.S
@@ -31,6 +31,8 @@
#include <linux/errno.h>
#include <asm/signal.h>
+#undef DEBUG
+
/* The size of a state save frame. */
#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;
+#ifdef DEBUG
/* Trac syscalls and stored them to r0_ram */
lwi r3, r12, 0x400 + r0_ram
addi r3, r3, 1
swi r3, r12, 0x400 + r0_ram
+#endif
# Find and jump into the syscall handler.
lwi r12, r12, sys_call_table
@@ -496,17 +500,6 @@ C_ENTRY(sys_execve):
brid microblaze_execve; /* Do real work (tail-call).*/
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):
swi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
swi r4, r1, PTO+PT_R4;
@@ -711,15 +704,11 @@ C_ENTRY(ret_from_exc):
* (in a possibly modified form) after do_signal returns.
* store return registers separately because this macros is use
* 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 */
add r6, r0, r0; /* Arg 2: sigset_t *oldset */
addi r7, r0, 0; /* Arg 3: int in_syscall */
bralid r15, do_signal; /* Handle any signals */
nop;
- lwi r3, r1, PTO+PT_R3; /* restore saved r3, r4 registers */
- lwi r4, r1, PTO+PT_R4;
/* Finally, return to user state. */
1: swi r0, r0, PER_CPU(KM); /* Now officially in user state. */
diff --git a/arch/microblaze/kernel/ftrace.c b/arch/microblaze/kernel/ftrace.c
new file mode 100644
index 00000000000..388b31ca65a
--- /dev/null
+++ b/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 */
diff --git a/arch/microblaze/kernel/heartbeat.c b/arch/microblaze/kernel/heartbeat.c
index 1bdf20222b9..522751737cf 100644
--- a/arch/microblaze/kernel/heartbeat.c
+++ b/arch/microblaze/kernel/heartbeat.c
@@ -45,6 +45,7 @@ void heartbeat(void)
void setup_heartbeat(void)
{
struct device_node *gpio = NULL;
+ int *prop;
int j;
char *gpio_list[] = {
"xlnx,xps-gpio-1.00.a",
@@ -58,10 +59,14 @@ void setup_heartbeat(void)
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);
+ }
}
diff --git a/arch/microblaze/kernel/intc.c b/arch/microblaze/kernel/intc.c
index 6eea6f92b84..03172c1da77 100644
--- a/arch/microblaze/kernel/intc.c
+++ b/arch/microblaze/kernel/intc.c
@@ -42,8 +42,16 @@ unsigned int nr_irq;
static void intc_enable_or_unmask(unsigned int irq)
{
+ unsigned long mask = 1 << 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)
diff --git a/arch/microblaze/kernel/mcount.S b/arch/microblaze/kernel/mcount.S
new file mode 100644
index 00000000000..e7eaa7a8cbd
--- /dev/null
+++ b/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 */
diff --git a/arch/microblaze/kernel/microblaze_ksyms.c b/arch/microblaze/kernel/microblaze_ksyms.c
index 59ff20e33e0..bc4dcb7d386 100644
--- a/arch/microblaze/kernel/microblaze_ksyms.c
+++ b/arch/microblaze/kernel/microblaze_ksyms.c
@@ -18,6 +18,7 @@
#include <linux/io.h>
#include <asm/page.h>
#include <asm/system.h>
+#include <linux/ftrace.h>
#include <linux/uaccess.h>
/*
@@ -47,3 +48,7 @@ extern void __umodsi3(void);
EXPORT_SYMBOL(__umodsi3);
extern char *_ebss;
EXPORT_SYMBOL_GPL(_ebss);
+#ifdef CONFIG_FUNCTION_TRACER
+extern void _mcount(void);
+EXPORT_SYMBOL(_mcount);
+#endif
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index c592d475b3d..812f1bf06c9 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -15,6 +15,7 @@
#include <linux/bitops.h>
#include <asm/system.h>
#include <asm/pgalloc.h>
+#include <asm/cacheflush.h>
void show_regs(struct pt_regs *regs)
{
diff --git a/arch/microblaze/kernel/reset.c b/arch/microblaze/kernel/reset.c
new file mode 100644
index 00000000000..a1721a33042
--- /dev/null
+++ b/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)
+ ;
+}
diff --git a/arch/microblaze/kernel/setup.c b/arch/microblaze/kernel/setup.c
index 8c1e0f4dcf1..5372b24ad04 100644
--- a/arch/microblaze/kernel/setup.c
+++ b/arch/microblaze/kernel/setup.c
@@ -52,13 +52,12 @@ void __init setup_arch(char **cmdline_p)
/* irq_early_init(); */
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();
@@ -131,6 +130,8 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
strlcpy(cmd_line, cmdline, COMMAND_LINE_SIZE);
#endif
+ lockdep_init();
+
/* initialize device tree for usage in early_printk */
early_init_devtree((void *)_fdt_start);
@@ -186,32 +187,3 @@ static int microblaze_debugfs_init(void)
}
arch_initcall(microblaze_debugfs_init);
#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)
- ;
-}
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c
index 1c80e4fc40c..d8d3bb396cd 100644
--- a/arch/microblaze/kernel/signal.c
+++ b/arch/microblaze/kernel/signal.c
@@ -44,7 +44,6 @@
asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_sycall);
-
asmlinkage long
sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
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;
int err = 0;
int signal;
+ unsigned long address = 0;
+#ifdef CONFIG_MMU
+ pmd_t *pmdp;
+ pte_t *ptep;
+#endif
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 */
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)
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);
+ /* the tracer may want to single-step inside the handler */
+ if (test_thread_flag(TIF_SINGLESTEP))
+ ptrace_notify(SIGTRAP);
+
#ifdef DEBUG_SIG
printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n",
current->comm, current->pid, frame, regs->pc);
diff --git a/arch/microblaze/kernel/stacktrace.c b/arch/microblaze/kernel/stacktrace.c
new file mode 100644
index 00000000000..123692f2264
--- /dev/null
+++ b/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);
diff --git a/arch/microblaze/kernel/syscall_table.S b/arch/microblaze/kernel/syscall_table.S
index b96f365ea6b..4088be7d4e2 100644
--- a/arch/microblaze/kernel/syscall_table.S
+++ b/arch/microblaze/kernel/syscall_table.S
@@ -183,7 +183,7 @@ ENTRY(sys_call_table)
.long sys_rt_sigpending
.long sys_rt_sigtimedwait
.long sys_rt_sigqueueinfo
- .long sys_rt_sigsuspend_wrapper
+ .long sys_rt_sigsuspend
.long sys_pread64 /* 180 */
.long sys_pwrite64
.long sys_chown
@@ -303,7 +303,7 @@ ENTRY(sys_call_table)
.long sys_mkdirat
.long sys_mknodat
.long sys_fchownat
- .long sys_ni_syscall
+ .long sys_futimesat
.long sys_fstatat64 /* 300 */
.long sys_unlinkat
.long sys_renameat
diff --git a/arch/microblaze/kernel/timer.c b/arch/microblaze/kernel/timer.c
index 5499deae7fa..ed61b2f1771 100644
--- a/arch/microblaze/kernel/timer.c
+++ b/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));
}
+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 = {
.name = "microblaze_clocksource",
.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);
/* start timer1 - up counting without interrupt */
out_be32(TIMER_BASE + TCSR1, TCSR_TINT|TCSR_ENT|TCSR_ARHT);
+
+ /* register timecounter - for ftrace support */
+ init_microblaze_timecounter();
return 0;
}
diff --git a/arch/microblaze/kernel/vmlinux.lds.S b/arch/microblaze/kernel/vmlinux.lds.S
index e704188d785..5ef619aad63 100644
--- a/arch/microblaze/kernel/vmlinux.lds.S
+++ b/arch/microblaze/kernel/vmlinux.lds.S
@@ -26,11 +26,12 @@ SECTIONS {
_stext = . ;
*(.text .text.*)
*(.fixup)
- EXIT_TEXT
- EXIT_CALL
+ EXIT_TEXT
+ EXIT_CALL
SCHED_TEXT
LOCK_TEXT
KPROBES_TEXT
+ IRQENTRY_TEXT
. = ALIGN (4) ;
_etext = . ;
}
@@ -86,6 +87,7 @@ SECTIONS {
_KERNEL_SDA_BASE_ = _ssro + (_ssro_size / 2) ;
}
+ . = ALIGN(PAGE_SIZE);
__init_begin = .;
INIT_TEXT_SECTION(PAGE_SIZE)
diff --git a/arch/microblaze/lib/uaccess.c b/arch/microblaze/lib/uaccess.c
index 8eb9df5a26c..a853fe089c4 100644
--- a/arch/microblaze/lib/uaccess.c
+++ b/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);
return res;
}
+
+unsigned long __copy_tofrom_user(void __user *to,
+ const void __user *from, unsigned long size)
+{
+ memcpy(to, from, size);
+ return 0;
+}
diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c
index a44892e7cd5..a57cedf3671 100644
--- a/arch/microblaze/mm/init.c
+++ b/arch/microblaze/mm/init.c
@@ -41,6 +41,7 @@ char *klimit = _end;
* have available.
*/
unsigned long memory_start;
+EXPORT_SYMBOL(memory_start);
unsigned long memory_end; /* due to mm/nommu.c */
unsigned long memory_size;
diff --git a/arch/microblaze/mm/pgtable.c b/arch/microblaze/mm/pgtable.c
index 46c4ca5d15c..2820081b21a 100644
--- a/arch/microblaze/mm/pgtable.c
+++ b/arch/microblaze/mm/pgtable.c
@@ -144,7 +144,6 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
pmd_t *pd;
pte_t *pg;
int err = -ENOMEM;
- /* spin_lock(&init_mm.page_table_lock); */
/* Use upper 10 bits of VA to index the first level map */
pd = pmd_offset(pgd_offset_k(va), va);
/* 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)
flush_HPTE(0, va, pmd_val(*pd));
/* flush_HPTE(0, va, pg); */
-
}
- /* spin_unlock(&init_mm.page_table_lock); */
return err;
}
@@ -182,12 +179,6 @@ void __init adjust_total_lowmem(void)
#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.
*/
@@ -197,7 +188,6 @@ void __init mapin_ram(void)
v = CONFIG_KERNEL_START;
p = memory_start;
- show_tmem(memory_size);
for (s = 0; s < memory_size; s += PAGE_SIZE) {
f = _PAGE_PRESENT | _PAGE_ACCESSED |
_PAGE_SHARED | _PAGE_HWEXEC;
diff --git a/arch/microblaze/oprofile/Makefile b/arch/microblaze/oprofile/Makefile
new file mode 100644
index 00000000000..0d0348c8af9
--- /dev/null
+++ b/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
diff --git a/arch/microblaze/oprofile/microblaze_oprofile.c b/arch/microblaze/oprofile/microblaze_oprofile.c
new file mode 100644
index 00000000000..def17e59888
--- /dev/null
+++ b/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)
+{
+}
diff --git a/arch/microblaze/platform/Kconfig.platform b/arch/microblaze/platform/Kconfig.platform
index 8e9b4752d3f..669c7eec293 100644
--- a/arch/microblaze/platform/Kconfig.platform
+++ b/arch/microblaze/platform/Kconfig.platform
@@ -53,31 +53,12 @@ config OPT_LIB_FUNCTION
config OPT_LIB_ASM
bool "Optimalized lib function ASM"
- depends on OPT_LIB_FUNCTION
+ depends on OPT_LIB_FUNCTION && (XILINX_MICROBLAZE0_USE_BARREL = 1)
default n
help
Allows turn on optimalized library function (memcpy and memmove).
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
source "arch/microblaze/platform/generic/Kconfig.auto"
endif
diff --git a/arch/microblaze/platform/generic/Kconfig.auto b/arch/microblaze/platform/generic/Kconfig.auto
index fbca22d9c8b..5d86fc19029 100644
--- a/arch/microblaze/platform/generic/Kconfig.auto
+++ b/arch/microblaze/platform/generic/Kconfig.auto
@@ -21,7 +21,6 @@
# Definitions for MICROBLAZE0
comment "Definitions for MICROBLAZE0"
- depends on ALLOW_EDIT_AUTO
config KERNEL_BASE_ADDR
hex "Physical address where Linux Kernel is"
@@ -30,33 +29,33 @@ config KERNEL_BASE_ADDR
BASE Address for kernel
config XILINX_MICROBLAZE0_FAMILY
- string "Targetted FPGA family" if ALLOW_EDIT_AUTO
+ string "Targetted FPGA family"
default "virtex5"
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
- 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
- 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
- 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
- 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
- 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
- string "Core version number" if ALLOW_EDIT_AUTO
+ string "Core version number"
default 7.10.d
diff --git a/arch/microblaze/platform/generic/system.dts b/arch/microblaze/platform/generic/system.dts
index 29993f62b30..2d5c41767cd 100644
--- a/arch/microblaze/platform/generic/system.dts
+++ b/arch/microblaze/platform/generic/system.dts
@@ -32,11 +32,16 @@
#address-cells = <1>;
#size-cells = <1>;
compatible = "xlnx,microblaze";
+ hard-reset-gpios = <&LEDs_8Bit 2 1>;
model = "testing";
DDR2_SDRAM: memory@90000000 {
device_type = "memory";
reg = < 0x90000000 0x10000000 >;
} ;
+ aliases {
+ ethernet0 = &Hard_Ethernet_MAC;
+ serial0 = &RS232_Uart_1;
+ } ;
chosen {
bootargs = "console=ttyUL0,115200 highres=on";
linux,stdout-path = "/plb@0/serial@84000000";
@@ -127,7 +132,7 @@
mb_plb: plb@0 {
#address-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 ;
FLASH: flash@a0000000 {
bank-width = <2>;
@@ -214,12 +219,12 @@
#size-cells = <1>;
compatible = "xlnx,compound";
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";
interrupt-parent = <&xps_intc_0>;
interrupts = < 5 2 >;
llink-connected = <&PIM3>;
- local-mac-address = [ 02 00 00 00 00 00 ];
+ local-mac-address = [ 00 0a 35 00 00 00 ];
reg = < 0x81c00000 0x40 >;
xlnx,bus2core-clk-ratio = <0x1>;
xlnx,phy-type = <0x1>;
@@ -261,6 +266,33 @@
xlnx,is-dual = <0x0>;
xlnx,tri-default = <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 {
clock-frequency = <125000000>;
diff --git a/arch/microblaze/platform/platform.c b/arch/microblaze/platform/platform.c
index 56e0234fa34..5b89b58c5ae 100644
--- a/arch/microblaze/platform/platform.c
+++ b/arch/microblaze/platform/platform.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/of_platform.h>
#include <asm/prom.h>
+#include <asm/setup.h>
static struct of_device_id xilinx_of_bus_ids[] __initdata = {
{ .compatible = "simple-bus", },
@@ -26,6 +27,7 @@ static struct of_device_id xilinx_of_bus_ids[] __initdata = {
static int __init microblaze_device_probe(void)
{
of_platform_bus_probe(NULL, xilinx_of_bus_ids, NULL);
+ of_platform_reset_gpio_probe();
return 0;
}
device_initcall(microblaze_device_probe);