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
  ...
This commit is contained in:
Linus Torvalds 2009-12-14 10:04:04 -08:00
commit 464480f72e
50 changed files with 1712 additions and 510 deletions

View File

@ -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"

View File

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

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 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_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 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_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_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)
/* 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)
#define flush_cache_range(vma, start, len) 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 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 */

View File

@ -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;

View File

@ -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 */

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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)

View File

@ -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 */

View File

@ -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)

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 */
void _enable_icache(void)
static inline void __invalidate_flush_icache(unsigned int addr)
{
if (cpuinfo.use_icache) {
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
__asm__ __volatile__ (" \
msrset r0, %0; \
nop; " \
: \
: "i" (MSR_ICE) \
: "memory");
#else
__asm__ __volatile__ (" \
mfs r12, rmsr; \
nop; \
ori r12, r12, %0; \
mts rmsr, r12; \
nop; " \
: \
: "i" (MSR_ICE) \
: "memory", "r12");
#endif
}
__asm__ __volatile__ ("wic %0, r0;" \
: : "r" (addr));
}
void _disable_icache(void)
static inline void __flush_dcache(unsigned int addr)
{
if (cpuinfo.use_icache) {
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
__asm__ __volatile__ (" \
msrclr r0, %0; \
nop; " \
: \
: "i" (MSR_ICE) \
: "memory");
#else
__asm__ __volatile__ (" \
mfs r12, rmsr; \
nop; \
andi r12, r12, ~%0; \
mts rmsr, r12; \
nop; " \
: \
: "i" (MSR_ICE) \
: "memory", "r12");
#endif
}
__asm__ __volatile__ ("wdc.flush %0, r0;" \
: : "r" (addr));
}
void _invalidate_icache(unsigned int addr)
static inline void __invalidate_dcache(unsigned int baseaddr,
unsigned int offset)
{
if (cpuinfo.use_icache) {
__asm__ __volatile__ (" \
wic %0, r0" \
: \
: "r" (addr));
}
__asm__ __volatile__ ("wdc.clear %0, %1;" \
: : "r" (baseaddr), "r" (offset));
}
void _enable_dcache(void)
static inline void __enable_icache_msr(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) \
: "memory", "r12");
#endif
}
__asm__ __volatile__ (" msrset r0, %0; \
nop; " \
: : "i" (MSR_ICE) : "memory");
}
void _disable_dcache(void)
static inline void __disable_icache_msr(void)
{
#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
__asm__ __volatile__ (" \
msrclr r0, %0; \
nop; " \
: \
: "i" (MSR_DCE) \
__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; \
andi r12, r12, ~%0; \
mts rmsr, r12; \
nop; " \
: \
: "i" (MSR_DCE) \
}
static inline void __disable_dcache_msr(void)
{
__asm__ __volatile__ (" msrclr r0, %0; \
nop; " \
: \
: "i" (MSR_DCE) \
: "memory");
}
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");
}
static inline void __disable_icache_nomsr(void)
{
__asm__ __volatile__ (" mfs r12, rmsr; \
nop; \
andi r12, r12, ~%0; \
mts rmsr, r12; \
nop; " \
: \
: "i" (MSR_ICE) \
: "memory", "r12");
}
static inline void __enable_dcache_nomsr(void)
{
__asm__ __volatile__ (" mfs r12, rmsr; \
nop; \
ori r12, r12, %0; \
mts rmsr, r12; \
nop; " \
: \
: "i" (MSR_DCE) \
: "memory", "r12");
}
static inline void __disable_dcache_nomsr(void)
{
__asm__ __volatile__ (" mfs r12, rmsr; \
nop; \
andi r12, r12, ~%0; \
mts rmsr, r12; \
nop; " \
: \
: "i" (MSR_DCE) \
: "memory", "r12");
}
/* 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)
{
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);
}
static void __flush_icache_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.icache_line_length, cpuinfo.icache_size);
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);
}
static void __flush_icache_range_noirq(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.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);
}
static void __flush_icache_all_noirq(void)
{
pr_debug("%s\n", __func__);
CACHE_ALL_LOOP(cpuinfo.icache_size, cpuinfo.icache_line_length, wic);
}
static void __invalidate_dcache_all_msr_irq(void)
{
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);
}
static void __invalidate_dcache_all_nomsr_irq(void)
{
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);
}
static void __invalidate_dcache_all_noirq_wt(void)
{
pr_debug("%s\n", __func__);
CACHE_ALL_LOOP(cpuinfo.dcache_size, cpuinfo.dcache_line_length, wdc)
}
/* 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;
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
}
void _invalidate_dcache(unsigned int addr)
static void __invalidate_dcache_range_wb(unsigned long start,
unsigned long end)
{
__asm__ __volatile__ (" \
wdc %0, r0" \
: \
: "r" (addr));
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);
}
void __invalidate_icache_all(void)
static void __invalidate_dcache_range_nomsr_wt(unsigned long start,
unsigned long end)
{
unsigned int i;
unsigned 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);
if (cpuinfo.use_icache) {
local_irq_save(flags);
__disable_icache();
CACHE_RANGE_LOOP_1(start, end, cpuinfo.dcache_line_length, wdc);
}
/* 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);
static void __invalidate_dcache_range_msr_irq_wt(unsigned long start,
unsigned long end)
{
unsigned long flags;
__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.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);
}
static void __flush_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.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;
}
}
}
}
void __invalidate_icache_range(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);
}
}
void __invalidate_icache_page(struct vm_area_struct *vma, struct page *page)
{
__invalidate_icache_all();
}
void __invalidate_icache_user_range(struct vm_area_struct *vma,
struct page *page, unsigned long adr,
int len)
{
__invalidate_icache_all();
}
void __invalidate_cache_sigtramp(unsigned long addr)
{
__invalidate_icache_range(addr, addr + 8);
}
void __invalidate_dcache_all(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);
}
}
void __invalidate_dcache_range(unsigned long start, unsigned long end)
{
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);
}
}
void __invalidate_dcache_page(struct vm_area_struct *vma, struct page *page)
{
__invalidate_dcache_all();
}
void __invalidate_dcache_user_range(struct vm_area_struct *vma,
struct page *page, unsigned long adr,
int len)
{
__invalidate_dcache_all();
}

View File

@ -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);

View File

@ -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");

View File

@ -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},
};

View File

@ -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,

View File

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

View File

@ -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 */

View File

@ -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. */

View File

@ -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 */

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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 */

View File

@ -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

View File

@ -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)
{

View File

@ -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)
;
}

View File

@ -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)
;
}

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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)
{
}

View File

@ -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

View File

@ -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

View File

@ -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>;

View File

@ -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);

View File

@ -295,6 +295,9 @@ if ($arch eq "x86_64") {
$ld .= " -m elf64_sparc";
$cc .= " -m64";
$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 {
die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD";
}